00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <cmath>
00011 #include <cassert>
00012 #include <iostream>
00013 #include <algorithm>
00014 #include <celmath/mathlib.h>
00015 #include <celmath/vecmath.h>
00016 #include "gl.h"
00017 #include "glext.h"
00018 #include "vecgl.h"
00019 #include "lodspheremesh.h"
00020
00021 using namespace std;
00022
00023
00024
00025
00026 static bool trigArraysInitialized = false;
00027 static int maxDivisions = 4096;
00028 static int thetaDivisions = maxDivisions;
00029 static int phiDivisions = maxDivisions / 2;
00030 static int minStep = 128;
00031 static float* sinPhi = NULL;
00032 static float* cosPhi = NULL;
00033 static float* sinTheta = NULL;
00034 static float* cosTheta = NULL;
00035
00036
00037
00038
00039
00040
00041 static int MaxVertexSize = 3 + 3 + 3 + MAX_SPHERE_MESH_TEXTURES * 2;
00042
00043 #ifdef SHOW_PATCH_VISIBILITY
00044 static const int MaxPatchesShown = 4096;
00045 static int visiblePatches[MaxPatchesShown];
00046 #endif
00047
00048
00049 static void InitTrigArrays()
00050 {
00051 sinTheta = new float[thetaDivisions + 1];
00052 cosTheta = new float[thetaDivisions + 1];
00053 sinPhi = new float[phiDivisions + 1];
00054 cosPhi = new float[phiDivisions + 1];
00055
00056 int i;
00057 for (i = 0; i <= thetaDivisions; i++)
00058 {
00059 double theta = (double) i / (double) thetaDivisions * 2.0 * PI;
00060 sinTheta[i] = (float) sin(theta);
00061 cosTheta[i] = (float) cos(theta);
00062 }
00063
00064 for (i = 0; i <= phiDivisions; i++)
00065 {
00066 double phi = ((double) i / (double) phiDivisions - 0.5) * PI;
00067 sinPhi[i] = (float) sin(phi);
00068 cosPhi[i] = (float) cos(phi);
00069 }
00070
00071 trigArraysInitialized = true;
00072 }
00073
00074
00075 static float getSphereLOD(float discSizeInPixels)
00076 {
00077 if (discSizeInPixels < 10)
00078 return -3.0f;
00079 else if (discSizeInPixels < 20)
00080 return -2.0f;
00081 else if (discSizeInPixels < 50)
00082 return -1.0f;
00083 else if (discSizeInPixels < 200)
00084 return 0.0f;
00085 else if (discSizeInPixels < 1200)
00086 return 1.0f;
00087 else if (discSizeInPixels < 7200)
00088 return 2.0f;
00089 else if (discSizeInPixels < 53200)
00090 return 3.0f;
00091 else
00092 return 4.0f;
00093 }
00094
00095
00096 LODSphereMesh::LODSphereMesh() :
00097 vertices(NULL),
00098 vertexBuffersInitialized(false),
00099 useVertexBuffers(false)
00100 {
00101 if (!trigArraysInitialized)
00102 InitTrigArrays();
00103
00104 int maxThetaSteps = thetaDivisions / minStep;
00105 int maxPhiSteps = phiDivisions / minStep;
00106 maxVertices = (maxPhiSteps + 1) * (maxThetaSteps + 1);
00107 vertices = new float[MaxVertexSize * maxVertices];
00108
00109 nIndices = maxPhiSteps * 2 * (maxThetaSteps + 1);
00110 indices = new unsigned short[nIndices];
00111 }
00112
00113
00114 LODSphereMesh::~LODSphereMesh()
00115 {
00116 if (vertices != NULL)
00117 delete[] vertices;
00118 }
00119
00120
00121 static Point3f spherePoint(int theta, int phi)
00122 {
00123 return Point3f(cosPhi[phi] * cosTheta[theta],
00124 sinPhi[phi],
00125 cosPhi[phi] * sinTheta[theta]);
00126 }
00127
00128
00129 void LODSphereMesh::render(const GLContext& context,
00130 const Frustum& frustum,
00131 float pixWidth,
00132 Texture** tex,
00133 int nTextures)
00134 {
00135 render(context,
00136 Normals | TexCoords0, frustum, pixWidth, tex,
00137 nTextures);
00138 }
00139
00140
00141 void LODSphereMesh::render(const GLContext& context,
00142 unsigned int attributes,
00143 const Frustum& frustum,
00144 float pixWidth,
00145 Texture* tex0,
00146 Texture* tex1,
00147 Texture* tex2,
00148 Texture* tex3)
00149 {
00150 Texture* textures[MAX_SPHERE_MESH_TEXTURES];
00151 int nTextures = 0;
00152
00153 if (tex0 != NULL)
00154 textures[nTextures++] = tex0;
00155 if (tex1 != NULL)
00156 textures[nTextures++] = tex1;
00157 if (tex2 != NULL)
00158 textures[nTextures++] = tex2;
00159 if (tex3 != NULL)
00160 textures[nTextures++] = tex3;
00161 render(context, attributes, frustum, pixWidth, textures, nTextures);
00162 }
00163
00164
00165 void LODSphereMesh::render(const GLContext& context,
00166 unsigned int attributes,
00167 const Frustum& frustum,
00168 float pixWidth,
00169 Texture** tex,
00170 int nTextures)
00171 {
00172 int lod = 64;
00173 float lodBias = getSphereLOD(pixWidth);
00174
00175 if (lodBias < 0.0f)
00176 {
00177 if (lodBias < -30)
00178 lodBias = -30;
00179 lod = lod / (1 << (int) (-lodBias));
00180 if (lod < 2)
00181 lod = 2;
00182 }
00183 else if (lodBias > 0.0f)
00184 {
00185 if (lodBias > 30)
00186 lodBias = 30;
00187 lod = lod * (1 << (int) lodBias);
00188 if (lod > maxDivisions)
00189 lod = maxDivisions;
00190 }
00191
00192 int step = maxDivisions / lod;
00193 int thetaExtent = maxDivisions;
00194 int phiExtent = thetaExtent / 2;
00195
00196 int split = 1;
00197 if (step < minStep)
00198 {
00199 split = minStep / step;
00200 thetaExtent /= split;
00201 phiExtent /= split;
00202 }
00203
00204 if (tex == NULL)
00205 nTextures = 0;
00206
00207
00208
00209
00210 if (!context.getVertexProcessor())
00211 attributes &= ~Tangents;
00212
00213 RenderInfo ri(step, attributes, frustum, context);
00214
00215
00216
00217 int i;
00218 int minSplit = 1;
00219 for (i = 0; i < nTextures; i++)
00220 {
00221 float pixelsPerTexel = pixWidth * 2.0f /
00222 ((float) tex[i]->getWidth() / 2.0f);
00223 double l = log(pixelsPerTexel) / log(2.0);
00224
00225 ri.texLOD[i] = max(min(tex[i]->getLODCount() - 1, (int) l), 0);
00226 if (tex[i]->getUTileCount(ri.texLOD[i]) > minSplit)
00227 minSplit = tex[i]->getUTileCount(ri.texLOD[i]);
00228 if (tex[i]->getVTileCount(ri.texLOD[i]) > minSplit)
00229 minSplit = tex[i]->getVTileCount(ri.texLOD[i]);
00230 }
00231
00232 if (split < minSplit)
00233 {
00234 thetaExtent /= (minSplit / split);
00235 phiExtent /= (minSplit / split);
00236 split = minSplit;
00237 if (phiExtent <= ri.step)
00238 ri.step /= ri.step / phiExtent;
00239 }
00240
00241
00242 nTexturesUsed = nTextures;
00243 for (i = 0; i < nTextures; i++)
00244 {
00245 tex[i]->beginUsage();
00246 textures[i] = tex[i];
00247 subtextures[i] = 0;
00248 if (nTextures > 1)
00249 glx::glActiveTextureARB(GL_TEXTURE0_ARB + i);
00250 glEnable(GL_TEXTURE_2D);
00251 }
00252
00253 #ifdef VERTEX_BUFFER_OBJECTS_ENABLED
00254 if (!vertexBuffersInitialized)
00255 {
00256
00257
00258
00259
00260 vertexBuffersInitialized = true;
00261 if (context.extensionSupported("GL_ARB_vertex_buffer_object"))
00262 {
00263 for (int i = 0; i < NUM_SPHERE_VERTEX_BUFFERS; i++)
00264 {
00265 GLuint vbname = 0;
00266 glx::glGenBuffersARB(1, &vbname);
00267 vertexBuffers[i] = (unsigned int) vbname;
00268 glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffers[i]);
00269 glx::glBufferDataARB(GL_ARRAY_BUFFER_ARB,
00270 maxVertices * MaxVertexSize * sizeof(float),
00271 NULL,
00272 GL_STREAM_DRAW_ARB);
00273 }
00274 glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
00275
00276 glx::glGenBuffersARB(1, &indexBuffer);
00277
00278 useVertexBuffers = true;
00279
00280
00281
00282 delete[] vertices;
00283 }
00284 }
00285 #endif
00286
00287 if (useVertexBuffers)
00288 {
00289 currentVB = 0;
00290 glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffers[currentVB]);
00291 }
00292
00293
00294 int nRings = phiExtent / ri.step;
00295 int nSlices = thetaExtent / ri.step;
00296
00297 int n2 = 0;
00298 for (i = 0; i < nRings; i++)
00299 {
00300 for (int j = 0; j <= nSlices; j++)
00301 {
00302 indices[n2 + 0] = i * (nSlices + 1) + j;
00303 indices[n2 + 1] = (i + 1) * (nSlices + 1) + j;
00304 n2 += 2;
00305 }
00306 }
00307
00308 if (useVertexBuffers)
00309 {
00310 glx::glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexBuffer);
00311 glx::glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
00312 nIndices * sizeof(indices[0]),
00313 indices,
00314 GL_DYNAMIC_DRAW_ARB);
00315 }
00316
00317
00318 vertexSize = 3;
00319 if ((attributes & Tangents) != 0)
00320 vertexSize += 3;
00321 for (i = 0; i < nTextures; i++)
00322 vertexSize += 2;
00323
00324 glEnableClientState(GL_VERTEX_ARRAY);
00325 if ((attributes & Normals) != 0)
00326 glEnableClientState(GL_NORMAL_ARRAY);
00327
00328 for (i = 0; i < nTextures; i++)
00329 {
00330 if (nTextures > 1)
00331 glx::glClientActiveTextureARB(GL_TEXTURE0_ARB + i);
00332 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00333 }
00334
00335 glDisableClientState(GL_COLOR_ARRAY);
00336
00337 if ((attributes & Tangents) != 0)
00338 {
00339 VertexProcessor* vproc = context.getVertexProcessor();
00340 vproc->enableAttribArray(6);
00341 }
00342
00343 if (split == 1)
00344 {
00345 renderSection(0, 0, thetaExtent, ri);
00346 }
00347 else
00348 {
00349
00350 int reject = 0;
00351
00352
00353
00354 ri.fp[0] = Planef::intersection(frustum.getPlane(Frustum::Near),
00355 frustum.getPlane(Frustum::Top),
00356 frustum.getPlane(Frustum::Left));
00357 ri.fp[1] = Planef::intersection(frustum.getPlane(Frustum::Near),
00358 frustum.getPlane(Frustum::Top),
00359 frustum.getPlane(Frustum::Right));
00360 ri.fp[2] = Planef::intersection(frustum.getPlane(Frustum::Near),
00361 frustum.getPlane(Frustum::Bottom),
00362 frustum.getPlane(Frustum::Left));
00363 ri.fp[3] = Planef::intersection(frustum.getPlane(Frustum::Near),
00364 frustum.getPlane(Frustum::Bottom),
00365 frustum.getPlane(Frustum::Right));
00366 ri.fp[4] = Planef::intersection(frustum.getPlane(Frustum::Far),
00367 frustum.getPlane(Frustum::Top),
00368 frustum.getPlane(Frustum::Left));
00369 ri.fp[5] = Planef::intersection(frustum.getPlane(Frustum::Far),
00370 frustum.getPlane(Frustum::Top),
00371 frustum.getPlane(Frustum::Right));
00372 ri.fp[6] = Planef::intersection(frustum.getPlane(Frustum::Far),
00373 frustum.getPlane(Frustum::Bottom),
00374 frustum.getPlane(Frustum::Left));
00375 ri.fp[7] = Planef::intersection(frustum.getPlane(Frustum::Far),
00376 frustum.getPlane(Frustum::Bottom),
00377 frustum.getPlane(Frustum::Right));
00378
00379
00380
00381 #ifdef SHOW_PATCH_VISIBILITY
00382 {
00383 for (int i = 0; i < MaxPatchesShown; i++)
00384 visiblePatches[i] = 0;
00385 }
00386 #endif // SHOW_PATCH_VISIBILITY
00387
00388 int nPatches = 0;
00389 {
00390 int extent = maxDivisions / 2;
00391
00392 for (int i = 0; i < 2; i++)
00393 {
00394 for (int j = 0; j < 2; j++)
00395 {
00396 nPatches += renderPatches(i * extent / 2, j * extent,
00397 extent, split / 2, ri);
00398 }
00399 }
00400 }
00401
00402 }
00403
00404 glDisableClientState(GL_VERTEX_ARRAY);
00405 if ((attributes & Normals) != 0)
00406 glDisableClientState(GL_NORMAL_ARRAY);
00407
00408 if ((attributes & Tangents) != 0)
00409 {
00410 VertexProcessor* vproc = context.getVertexProcessor();
00411 vproc->disableAttribArray(6);
00412 }
00413
00414 for (i = 0; i < nTextures; i++)
00415 {
00416 tex[i]->endUsage();
00417
00418 if (nTextures > 1)
00419 {
00420 glx::glClientActiveTextureARB(GL_TEXTURE0_ARB + i);
00421 glx::glActiveTextureARB(GL_TEXTURE0_ARB + i);
00422 }
00423 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
00424 if (i > 0)
00425 glDisable(GL_TEXTURE_2D);
00426 }
00427
00428 if (nTextures > 1)
00429 {
00430 glx::glClientActiveTextureARB(GL_TEXTURE0_ARB);
00431 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
00432 }
00433
00434 if (useVertexBuffers)
00435 {
00436 glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
00437 glx::glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
00438 vertices = NULL;
00439 }
00440
00441 #ifdef SHOW_FRUSTUM
00442
00443 glMatrixMode(GL_PROJECTION);
00444 glPushMatrix();
00445 glLoadIdentity();
00446 gluPerspective(45.0, 1.3333f, 1.0f, 100.0f);
00447 glMatrixMode(GL_MODELVIEW);
00448 glPushMatrix();
00449 glLoadIdentity();
00450 glDisable(GL_TEXTURE_2D);
00451 glDisable(GL_LIGHTING);
00452 glColor4f(1, 0, 0, 1);
00453 glTranslatef(0, 0, -20);
00454 glBegin(GL_LINES);
00455 glVertex(ri.fp[0]); glVertex(ri.fp[1]);
00456 glVertex(ri.fp[0]); glVertex(ri.fp[2]);
00457 glVertex(ri.fp[3]); glVertex(ri.fp[1]);
00458 glVertex(ri.fp[3]); glVertex(ri.fp[2]);
00459 glVertex(ri.fp[4]); glVertex(ri.fp[5]);
00460 glVertex(ri.fp[4]); glVertex(ri.fp[6]);
00461 glVertex(ri.fp[7]); glVertex(ri.fp[5]);
00462 glVertex(ri.fp[7]); glVertex(ri.fp[6]);
00463 glVertex(ri.fp[0]); glVertex(ri.fp[4]);
00464 glVertex(ri.fp[1]); glVertex(ri.fp[5]);
00465 glVertex(ri.fp[2]); glVertex(ri.fp[6]);
00466 glVertex(ri.fp[3]); glVertex(ri.fp[7]);
00467 glEnd();
00468
00469
00470 glColor4f(0, 1, 0, 1);
00471 glBegin(GL_LINES);
00472 glVertex3f(-1, 0, 0); glVertex3f(1, 0, 0);
00473 glVertex3f(0, -1, 0); glVertex3f(0, 1, 0);
00474 glVertex3f(0, 0, -1); glVertex3f(1, 0, 1);
00475 glEnd();
00476 glMatrixMode(GL_PROJECTION);
00477 glPopMatrix();
00478 glMatrixMode(GL_MODELVIEW);
00479 glPopMatrix();
00480 #endif
00481
00482 #ifdef SHOW_PATCH_VISIBILITY
00483
00484 glMatrixMode(GL_PROJECTION);
00485 glPushMatrix();
00486 glLoadIdentity();
00487 glMatrixMode(GL_MODELVIEW);
00488 glPushMatrix();
00489 glLoadIdentity();
00490 glDisable(GL_TEXTURE_2D);
00491 glDisable(GL_LIGHTING);
00492 glColor4f(1, 0, 1, 1);
00493
00494 {
00495 int width = split;
00496 int height = width / 2;
00497 float patchWidth = 1.0f / (float) width;
00498 float patchHeight = 1.0f / (float) height;
00499 if (width * height <= MaxPatchesShown)
00500 {
00501 for (int i = 0; i < height; i++)
00502 {
00503 for (int j = 0; j < width; j++)
00504 {
00505 glPushMatrix();
00506 glTranslatef(-0.5f + j * patchWidth,
00507 1.0f - i * patchHeight,
00508 0.0f);
00509 if (visiblePatches[i * width + j])
00510 glBegin(GL_QUADS);
00511 else
00512 glBegin(GL_LINE_LOOP);
00513 glVertex3f(0.0f, 0.0f, 0.0f);
00514 glVertex3f(0.0f, -patchHeight, 0.0f);
00515 glVertex3f(patchWidth, -patchHeight, 0.0f);
00516 glVertex3f(patchWidth, 0.0f, 0.0f);
00517 glEnd();
00518 glPopMatrix();
00519 }
00520 }
00521 }
00522 }
00523
00524 glMatrixMode(GL_PROJECTION);
00525 glPopMatrix();
00526 glMatrixMode(GL_MODELVIEW);
00527 glPopMatrix();
00528 #endif // SHOW_PATCH_VISIBILITY
00529 }
00530
00531
00532 int LODSphereMesh::renderPatches(int phi0, int theta0,
00533 int extent,
00534 int level,
00535 const RenderInfo& ri)
00536 {
00537 int thetaExtent = extent;
00538 int phiExtent = extent / 2;
00539
00540
00541
00542
00543
00544 Point3f p0 = spherePoint(theta0, phi0);
00545 Point3f p1 = spherePoint(theta0 + thetaExtent, phi0);
00546 Point3f p2 = spherePoint(theta0 + thetaExtent,
00547 phi0 + phiExtent);
00548 Point3f p3 = spherePoint(theta0, phi0 + phiExtent);
00549 Vec3f v0 = p1 - p0;
00550 Vec3f v2 = p3 - p2;
00551 Vec3f normal;
00552 if (v0.lengthSquared() > v2.lengthSquared())
00553 normal = (p0 - p3) ^ v0;
00554 else
00555 normal = (p2 - p1) ^ v2;
00556
00557
00558 assert(normal.length() > 1.0e-6);
00559 normal.normalize();
00560 Planef separatingPlane(normal, p0);
00561
00562 bool outside = true;
00563 #if 1
00564 for (int k = 0; k < 8; k++)
00565 {
00566 if (separatingPlane.distanceTo(ri.fp[k]) > 0.0f)
00567 {
00568 outside = false;
00569 break;
00570 }
00571 }
00572
00573
00574 if (outside)
00575 return 0;
00576 #else
00577 outside = false;
00578 #endif
00579
00580
00581 #if 0
00582
00583 Point3f patchCenter = spherePoint(theta0 + thetaExtent / 2,
00584 phi0 + phiExtent / 2);
00585 #else
00586
00587 Point3f patchCenter = Point3f(p0.x + p1.x + p2.x + p3.x,
00588 p0.y + p1.y + p2.y + p3.y,
00589 p0.z + p1.z + p2.z + p3.z) * 0.25f;
00590 #endif
00591 float boundingRadius = 0.0f;
00592 boundingRadius = max(boundingRadius, patchCenter.distanceTo(p0));
00593 boundingRadius = max(boundingRadius, patchCenter.distanceTo(p1));
00594 boundingRadius = max(boundingRadius, patchCenter.distanceTo(p2));
00595 boundingRadius = max(boundingRadius, patchCenter.distanceTo(p3));
00596 if (ri.frustum.testSphere(patchCenter, boundingRadius) == Frustum::Outside)
00597 outside = true;
00598
00599 if (outside)
00600 {
00601 return 0;
00602 }
00603 else if (level == 1)
00604 {
00605 renderSection(phi0, theta0, thetaExtent, ri);
00606 return 1;
00607 }
00608 else
00609 {
00610 int nRendered = 0;
00611 for (int i = 0; i < 2; i++)
00612 {
00613 for (int j = 0; j < 2; j++)
00614 {
00615 nRendered += renderPatches(phi0 + phiExtent / 2 * i,
00616 theta0 + thetaExtent / 2 * j,
00617 extent / 2,
00618 level / 2,
00619 ri);
00620 }
00621 }
00622 return nRendered;
00623 }
00624 }
00625
00626
00627 void LODSphereMesh::renderSection(int phi0, int theta0, int extent,
00628 const RenderInfo& ri)
00629
00630 {
00631 #ifdef SHOW_PATCH_VISIBILITY
00632 {
00633 int width = thetaDivisions / extent;
00634 int height = phiDivisions / extent;
00635 int x = theta0 / extent;
00636 int y = phi0 / extent;
00637 if (width * height <= MaxPatchesShown)
00638 visiblePatches[y * width + x] = 1;
00639 }
00640 #endif // SHOW_PATCH_VISIBILITY
00641
00642 GLsizei stride = (GLsizei) (vertexSize * sizeof(float));
00643 int tangentOffset = 3;
00644 int texCoordOffset = ((ri.attributes & Tangents) != 0) ? 6 : 3;
00645 float* vertexBase = useVertexBuffers ? (float*) NULL : vertices;
00646
00647 glVertexPointer(3, GL_FLOAT, stride, vertexBase + 0);
00648 if ((ri.attributes & Normals) != 0)
00649 glNormalPointer(GL_FLOAT, stride, vertexBase);
00650
00651 for (int tc = 0; tc < nTexturesUsed; tc++)
00652 {
00653 if (nTexturesUsed > 1)
00654 glx::glClientActiveTextureARB(GL_TEXTURE0_ARB + tc);
00655 glTexCoordPointer(2, GL_FLOAT, stride, vertexBase + (tc * 2) + texCoordOffset);
00656 }
00657
00658 if ((ri.attributes & Tangents) != 0)
00659 {
00660 VertexProcessor* vproc = ri.context.getVertexProcessor();
00661 vproc->attribArray(6, 3, GL_FLOAT, stride, vertexBase + tangentOffset);
00662 }
00663
00664
00665
00666
00667
00668 int thetaExtent = extent;
00669 int phiExtent = extent / 2;
00670 int theta1 = theta0 + thetaExtent;
00671 int phi1 = phi0 + phiExtent;
00672 int n3 = 0;
00673 int n2 = 0;
00674
00675 float du[MAX_SPHERE_MESH_TEXTURES];
00676 float dv[MAX_SPHERE_MESH_TEXTURES];
00677 float u0[MAX_SPHERE_MESH_TEXTURES];
00678 float v0[MAX_SPHERE_MESH_TEXTURES];
00679
00680
00681 if (useVertexBuffers)
00682 {
00683 vertices = reinterpret_cast<float*>(glx::glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
00684 if (vertices == NULL)
00685 return;
00686 }
00687
00688
00689
00690 for (int tex = 0; tex < nTexturesUsed; tex++)
00691 {
00692 du[tex] = (float) 1.0f / thetaDivisions;;
00693 dv[tex] = (float) 1.0f / phiDivisions;;
00694 u0[tex] = 1.0f;
00695 v0[tex] = 1.0f;
00696
00697 if (textures[tex] != NULL)
00698 {
00699 int uTexSplit = textures[tex]->getUTileCount(ri.texLOD[tex]);
00700 int vTexSplit = textures[tex]->getVTileCount(ri.texLOD[tex]);
00701 int patchSplit = maxDivisions / extent;
00702 assert(patchSplit >= uTexSplit && patchSplit >= vTexSplit);
00703
00704 int u = theta0 / thetaExtent;
00705 int v = phi0 / phiExtent;
00706 int patchesPerUSubtex = patchSplit / uTexSplit;
00707 int patchesPerVSubtex = patchSplit / vTexSplit;
00708
00709 du[tex] *= uTexSplit;
00710 dv[tex] *= vTexSplit;
00711 u0[tex] = 1.0f - ((float) (u % patchesPerUSubtex) /
00712 (float) patchesPerUSubtex);
00713 v0[tex] = 1.0f - ((float) (v % patchesPerVSubtex) /
00714 (float) patchesPerVSubtex);
00715 u0[tex] += theta0 * du[tex];
00716 v0[tex] += phi0 * dv[tex];
00717
00718 u /= patchesPerUSubtex;
00719 v /= patchesPerVSubtex;
00720
00721 if (nTexturesUsed > 1)
00722 glx::glActiveTextureARB(GL_TEXTURE0_ARB + tex);
00723 TextureTile tile = textures[tex]->getTile(ri.texLOD[tex],
00724 uTexSplit - u - 1,
00725 vTexSplit - v - 1);
00726 du[tex] *= tile.du;
00727 dv[tex] *= tile.dv;
00728 u0[tex] = u0[tex] * tile.du + tile.u;
00729 v0[tex] = v0[tex] * tile.dv + tile.v;
00730
00731
00732
00733 if (tile.texID != subtextures[tex])
00734 {
00735 glBindTexture(GL_TEXTURE_2D, tile.texID);
00736 subtextures[tex] = tile.texID;
00737 }
00738 }
00739 }
00740
00741 int vindex = 0;
00742 for (int phi = phi0; phi <= phi1; phi += ri.step)
00743 {
00744 float cphi = cosPhi[phi];
00745 float sphi = sinPhi[phi];
00746
00747 if ((ri.attributes & Tangents) != 0)
00748 {
00749 for (int theta = theta0; theta <= theta1; theta += ri.step)
00750 {
00751 float ctheta = cosTheta[theta];
00752 float stheta = sinTheta[theta];
00753
00754 vertices[vindex] = cphi * ctheta;
00755 vertices[vindex + 1] = sphi;
00756 vertices[vindex + 2] = cphi * stheta;
00757
00758
00759 vertices[vindex + 3] = stheta;
00760 vertices[vindex + 4] = 0.0f;
00761 vertices[vindex + 5] = -ctheta;
00762
00763 vindex += 6;
00764
00765 for (int tex = 0; tex < nTexturesUsed; tex++)
00766 {
00767 vertices[vindex] = u0[tex] - theta * du[tex];
00768 vertices[vindex + 1] = v0[tex] - phi * dv[tex];
00769 vindex += 2;
00770 }
00771 }
00772 }
00773 else
00774 {
00775 for (int theta = theta0; theta <= theta1; theta += ri.step)
00776 {
00777 float ctheta = cosTheta[theta];
00778 float stheta = sinTheta[theta];
00779
00780 vertices[vindex] = cphi * ctheta;
00781 vertices[vindex + 1] = sphi;
00782 vertices[vindex + 2] = cphi * stheta;
00783
00784 vindex += 3;
00785
00786 for (int tex = 0; tex < nTexturesUsed; tex++)
00787 {
00788 vertices[vindex] = u0[tex] - theta * du[tex];
00789 vertices[vindex + 1] = v0[tex] - phi * dv[tex];
00790 vindex += 2;
00791 }
00792 }
00793 }
00794 }
00795
00796 if (useVertexBuffers)
00797 {
00798 vertices = NULL;
00799 if (!glx::glUnmapBufferARB(GL_ARRAY_BUFFER_ARB))
00800 return;
00801 }
00802
00803
00804
00805 int nRings = phiExtent / ri.step;
00806 int nSlices = thetaExtent / ri.step;
00807 unsigned short* indexBase = useVertexBuffers ? (unsigned short*) NULL : indices;
00808 for (int i = 0; i < nRings; i++)
00809 {
00810 glDrawElements(GL_QUAD_STRIP,
00811 (nSlices + 1) * 2,
00812 GL_UNSIGNED_SHORT,
00813 indexBase + (nSlices + 1) * 2 * i);
00814 }
00815
00816
00817 if (useVertexBuffers)
00818 {
00819 currentVB++;
00820 if (currentVB == NUM_SPHERE_VERTEX_BUFFERS)
00821 currentVB = 0;
00822 glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffers[currentVB]);
00823 }
00824 }
00825