lodspheremesh.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:26k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // lodspheremesh.cpp
  2. //
  3. // Copyright (C) 2000-2007, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include <cmath>
  10. #include <cassert>
  11. #include <iostream>
  12. #include <algorithm>
  13. #include <celmath/mathlib.h>
  14. #include <celmath/vecmath.h>
  15. #include "gl.h"
  16. #include "glext.h"
  17. #include "vecgl.h"
  18. #include "lodspheremesh.h"
  19. using namespace std;
  20. //#define SHOW_PATCH_VISIBILITY
  21. //#define SHOW_FRUSTUM
  22. //#define VERTEX_BUFFER_OBJECTS_ENABLED
  23. static bool trigArraysInitialized = false;
  24. static int maxDivisions = 16384;
  25. static int thetaDivisions = maxDivisions;
  26. static int phiDivisions = maxDivisions / 2;
  27. static int minStep = 128;
  28. static float* sinPhi = NULL;
  29. static float* cosPhi = NULL;
  30. static float* sinTheta = NULL;
  31. static float* cosTheta = NULL;
  32. // largest vertex:
  33. //     position   - 3 floats,
  34. //     normal     - 3 floats,
  35. //     tangent    - 3 floats,
  36. //     tex coords - 2 floats * MAX_SPHERE_MESH_TEXTURES
  37. static int MaxVertexSize = 3 + 3 + 3 + MAX_SPHERE_MESH_TEXTURES * 2;
  38. #ifdef SHOW_PATCH_VISIBILITY
  39. static const int MaxPatchesShown = 4096;
  40. static int visiblePatches[MaxPatchesShown];
  41. #endif
  42. static void InitTrigArrays()
  43. {
  44.     sinTheta = new float[thetaDivisions + 1];
  45.     cosTheta = new float[thetaDivisions + 1];
  46.     sinPhi = new float[phiDivisions + 1];
  47.     cosPhi = new float[phiDivisions + 1];
  48.     int i;
  49.     for (i = 0; i <= thetaDivisions; i++)
  50.     {
  51.         double theta = (double) i / (double) thetaDivisions * 2.0 * PI;
  52.         sinTheta[i] = (float) sin(theta);
  53.         cosTheta[i] = (float) cos(theta);
  54.     }
  55.     for (i = 0; i <= phiDivisions; i++)
  56.     {
  57.         double phi = ((double) i / (double) phiDivisions - 0.5) * PI;
  58.         sinPhi[i] = (float) sin(phi);
  59.         cosPhi[i] = (float) cos(phi);
  60.     }
  61.     trigArraysInitialized = true;
  62. }
  63. static float getSphereLOD(float discSizeInPixels)
  64. {
  65.     if (discSizeInPixels < 10)
  66.         return -3.0f;
  67.     else if (discSizeInPixels < 20)
  68.         return -2.0f;
  69.     else if (discSizeInPixels < 50)
  70.         return -1.0f;
  71.     else if (discSizeInPixels < 200)
  72.         return 0.0f;
  73.     else if (discSizeInPixels < 1200)
  74.         return 1.0f;
  75.     else if (discSizeInPixels < 7200)
  76.         return 2.0f;
  77.     else if (discSizeInPixels < 53200)
  78.         return 3.0f;
  79.     else
  80.         return 4.0f;
  81. }
  82. LODSphereMesh::LODSphereMesh() :
  83.     vertices(NULL),
  84.     vertexBuffersInitialized(false),
  85.     useVertexBuffers(false)
  86. {
  87.     if (!trigArraysInitialized)
  88.         InitTrigArrays();
  89.     int maxThetaSteps = thetaDivisions / minStep;
  90.     int maxPhiSteps = phiDivisions / minStep;
  91.     maxVertices = (maxPhiSteps + 1) * (maxThetaSteps + 1);
  92.     vertices = new float[MaxVertexSize * maxVertices];
  93.     nIndices = maxPhiSteps * 2 * (maxThetaSteps + 1);
  94.     indices = new unsigned short[nIndices];
  95. }
  96. LODSphereMesh::~LODSphereMesh()
  97. {
  98.     if (vertices != NULL)
  99.         delete[] vertices;
  100. }
  101. static Point3f spherePoint(int theta, int phi)
  102. {
  103.     return Point3f(cosPhi[phi] * cosTheta[theta],
  104.                    sinPhi[phi],
  105.                    cosPhi[phi] * sinTheta[theta]);
  106. }
  107. void LODSphereMesh::render(const GLContext& context,
  108.                            const Frustum& frustum,
  109.                            float pixWidth,
  110.                            Texture** tex,
  111.                            int nTextures)
  112. {
  113.     render(context,
  114.            Normals | TexCoords0, frustum, pixWidth, tex,
  115.            nTextures);
  116. }
  117. void LODSphereMesh::render(const GLContext& context,
  118.                            unsigned int attributes,
  119.                            const Frustum& frustum,
  120.                            float pixWidth,
  121.                            Texture* tex0,
  122.                            Texture* tex1,
  123.                            Texture* tex2,
  124.                            Texture* tex3)
  125. {
  126.     Texture* textures[MAX_SPHERE_MESH_TEXTURES];
  127.     int nTextures = 0;
  128.     if (tex0 != NULL)
  129.         textures[nTextures++] = tex0;
  130.     if (tex1 != NULL)
  131.         textures[nTextures++] = tex1;
  132.     if (tex2 != NULL)
  133.         textures[nTextures++] = tex2;
  134.     if (tex3 != NULL)
  135.         textures[nTextures++] = tex3;
  136.     render(context, attributes, frustum, pixWidth, textures, nTextures);
  137. }
  138. void LODSphereMesh::render(const GLContext& context,
  139.                            unsigned int attributes,
  140.                            const Frustum& frustum,
  141.                            float pixWidth,
  142.                            Texture** tex,
  143.                            int nTextures)
  144. {
  145.     int lod = 64;
  146.     float lodBias = getSphereLOD(pixWidth);
  147.     if (lodBias < 0.0f)
  148.     {
  149.         if (lodBias < -30)
  150.             lodBias = -30;
  151.         lod = lod / (1 << (int) (-lodBias));
  152.         if (lod < 2)
  153.             lod = 2;
  154.     }
  155.     else if (lodBias > 0.0f)
  156.     {
  157.         if (lodBias > 30)
  158.             lodBias = 30;
  159.         lod = lod * (1 << (int) lodBias);
  160.         if (lod > maxDivisions)
  161.             lod = maxDivisions;
  162.     }
  163.     int step = maxDivisions / lod;
  164.     int thetaExtent = maxDivisions;
  165.     int phiExtent = thetaExtent / 2;
  166.     int split = 1;
  167.     if (step < minStep)
  168.     {
  169.         split = minStep / step;
  170.         thetaExtent /= split;
  171.         phiExtent /= split;
  172.     }
  173.     if (tex == NULL)
  174.         nTextures = 0;
  175.     // Need to have vertex programs enabled in order to make
  176.     // use of surface tangents.
  177.     if (!context.getVertexProcessor())
  178.         attributes &= ~Tangents;
  179.     RenderInfo ri(step, attributes, frustum, context);
  180.     // If one of the textures is split into subtextures, we may have to
  181.     // use extra patches, since there can be at most one subtexture per patch.
  182.     int i;
  183.     int minSplit = 1;
  184.     for (i = 0; i < nTextures; i++)
  185.     {
  186.         float pixelsPerTexel = pixWidth * 2.0f /
  187.             ((float) tex[i]->getWidth() / 2.0f);
  188.         double l = log(pixelsPerTexel) / log(2.0);
  189.         ri.texLOD[i] = max(min(tex[i]->getLODCount() - 1, (int) l), 0);
  190.         if (tex[i]->getUTileCount(ri.texLOD[i]) > minSplit)
  191.             minSplit = tex[i]->getUTileCount(ri.texLOD[i]);
  192.         if (tex[i]->getVTileCount(ri.texLOD[i]) > minSplit)
  193.             minSplit = tex[i]->getVTileCount(ri.texLOD[i]);
  194.     }
  195.     if (split < minSplit)
  196.     {
  197.         thetaExtent /= (minSplit / split);
  198.         phiExtent /= (minSplit / split);
  199.         split = minSplit;
  200.         if (phiExtent <= ri.step)
  201.             ri.step /= ri.step / phiExtent;
  202.     }
  203.     // Set the current textures
  204.     nTexturesUsed = nTextures;
  205.     for (i = 0; i < nTextures; i++)
  206.     {
  207.         tex[i]->beginUsage();
  208.         textures[i] = tex[i];
  209.         subtextures[i] = 0;
  210.         if (nTextures > 1)
  211.             glx::glActiveTextureARB(GL_TEXTURE0_ARB + i);
  212.         glEnable(GL_TEXTURE_2D);
  213.     }
  214. #ifdef VERTEX_BUFFER_OBJECTS_ENABLED
  215.     if (!vertexBuffersInitialized)
  216.     {
  217.         // TODO: assumes that the same context is used every time we
  218.         // render.  Valid now, but not necessarily in the future.  Still,
  219.         // would only cause problems if we rendered in two different contexts
  220.         // and only one had vertex buffer objects.
  221.         vertexBuffersInitialized = true;
  222.         if (context.extensionSupported("GL_ARB_vertex_buffer_object"))
  223.         {
  224.             for (int i = 0; i < NUM_SPHERE_VERTEX_BUFFERS; i++)
  225.             {
  226.                 GLuint vbname = 0;
  227.                 glx::glGenBuffersARB(1, &vbname);
  228.                 vertexBuffers[i] = (unsigned int) vbname;
  229.                 glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffers[i]);
  230.                 glx::glBufferDataARB(GL_ARRAY_BUFFER_ARB,
  231.                                      maxVertices * MaxVertexSize * sizeof(float),
  232.                                      NULL,
  233.                                      GL_STREAM_DRAW_ARB);
  234.             }
  235.             glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  236.             glx::glGenBuffersARB(1, &indexBuffer);
  237.             useVertexBuffers = true;
  238.             // HACK: delete the user arrays--we shouldn't need to allocate
  239.             // these at all if we're using vertex buffer objects.
  240.             delete[] vertices;
  241.         }
  242.     }
  243. #endif
  244.     if (useVertexBuffers)
  245.     {
  246.         currentVB = 0;
  247.         glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffers[currentVB]);
  248.     }
  249.     // Set up the mesh vertices
  250.     int nRings = phiExtent / ri.step;
  251.     int nSlices = thetaExtent / ri.step;
  252.     int n2 = 0;
  253.     for (i = 0; i < nRings; i++)
  254.     {
  255.         for (int j = 0; j <= nSlices; j++)
  256.         {
  257.             indices[n2 + 0] = i * (nSlices + 1) + j;
  258.             indices[n2 + 1] = (i + 1) * (nSlices + 1) + j;
  259.             n2 += 2;
  260.         }
  261.     }
  262.     if (useVertexBuffers)
  263.     {
  264.         glx::glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexBuffer);
  265.         glx::glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
  266.                              nIndices * sizeof(indices[0]),
  267.                              indices,
  268.                              GL_DYNAMIC_DRAW_ARB);
  269.     }
  270.     // Compute the size of a vertex
  271.     vertexSize = 3;
  272.     if ((attributes & Tangents) != 0)
  273.         vertexSize += 3;
  274.     for (i = 0; i < nTextures; i++)
  275.         vertexSize += 2;
  276.     glEnableClientState(GL_VERTEX_ARRAY);
  277.     if ((attributes & Normals) != 0)
  278.         glEnableClientState(GL_NORMAL_ARRAY);
  279.     for (i = 0; i < nTextures; i++)
  280.     {
  281.         if (nTextures > 1)
  282.             glx::glClientActiveTextureARB(GL_TEXTURE0_ARB + i);
  283.         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  284.     }
  285.     glDisableClientState(GL_COLOR_ARRAY);
  286.     if ((attributes & Tangents) != 0)
  287.     {
  288.         VertexProcessor* vproc = context.getVertexProcessor();
  289.         vproc->enableAttribArray(6);
  290.     }
  291.     if (split == 1)
  292.     {
  293.         renderSection(0, 0, thetaExtent, ri);
  294.     }
  295.     else
  296.     {
  297.         // Render the sphere section by section.
  298.         /*int reject = 0;   Unused*/
  299.         // Compute the vertices of the view frustum.  These will be used for
  300.         // culling patches.
  301.         ri.fp[0] = Planef::intersection(frustum.getPlane(Frustum::Near),
  302.                                         frustum.getPlane(Frustum::Top),
  303.                                         frustum.getPlane(Frustum::Left));
  304.         ri.fp[1] = Planef::intersection(frustum.getPlane(Frustum::Near),
  305.                                         frustum.getPlane(Frustum::Top),
  306.                                         frustum.getPlane(Frustum::Right));
  307.         ri.fp[2] = Planef::intersection(frustum.getPlane(Frustum::Near),
  308.                                         frustum.getPlane(Frustum::Bottom),
  309.                                         frustum.getPlane(Frustum::Left));
  310.         ri.fp[3] = Planef::intersection(frustum.getPlane(Frustum::Near),
  311.                                         frustum.getPlane(Frustum::Bottom),
  312.                                         frustum.getPlane(Frustum::Right));
  313.         ri.fp[4] = Planef::intersection(frustum.getPlane(Frustum::Far),
  314.                                         frustum.getPlane(Frustum::Top),
  315.                                         frustum.getPlane(Frustum::Left));
  316.         ri.fp[5] = Planef::intersection(frustum.getPlane(Frustum::Far),
  317.                                         frustum.getPlane(Frustum::Top),
  318.                                         frustum.getPlane(Frustum::Right));
  319.         ri.fp[6] = Planef::intersection(frustum.getPlane(Frustum::Far),
  320.                                         frustum.getPlane(Frustum::Bottom),
  321.                                         frustum.getPlane(Frustum::Left));
  322.         ri.fp[7] = Planef::intersection(frustum.getPlane(Frustum::Far),
  323.                                         frustum.getPlane(Frustum::Bottom),
  324.                                         frustum.getPlane(Frustum::Right));
  325. #ifdef SHOW_PATCH_VISIBILITY
  326.         {
  327.             for (int i = 0; i < MaxPatchesShown; i++)
  328.                 visiblePatches[i] = 0;
  329.         }
  330. #endif // SHOW_PATCH_VISIBILITY
  331.         int nPatches = 0;
  332.         {
  333.             int extent = maxDivisions / 2;
  334.             for (int i = 0; i < 2; i++)
  335.             {
  336.                 for (int j = 0; j < 2; j++)
  337.                 {
  338.                     nPatches += renderPatches(i * extent / 2, j * extent,
  339.                                               extent, split / 2, ri);
  340.                 }
  341.             }
  342.         }
  343.         // cout << "Rendered " << nPatches << " of " << square(split) << " patchesn";
  344.     }
  345.     glDisableClientState(GL_VERTEX_ARRAY);
  346.     if ((attributes & Normals) != 0)
  347.         glDisableClientState(GL_NORMAL_ARRAY);
  348.     if ((attributes & Tangents) != 0)
  349.     {
  350.         VertexProcessor* vproc = context.getVertexProcessor();
  351.         vproc->disableAttribArray(6);
  352.     }
  353.     for (i = 0; i < nTextures; i++)
  354.     {
  355.         tex[i]->endUsage();
  356.         if (nTextures > 1)
  357.         {
  358.             glx::glClientActiveTextureARB(GL_TEXTURE0_ARB + i);
  359.             glx::glActiveTextureARB(GL_TEXTURE0_ARB + i);
  360.         }
  361.         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  362.         if (i > 0)
  363.             glDisable(GL_TEXTURE_2D);
  364.     }
  365.     if (nTextures > 1)
  366.     {
  367.         glx::glClientActiveTextureARB(GL_TEXTURE0_ARB);
  368.         glx::glActiveTextureARB(GL_TEXTURE0_ARB);
  369.     }
  370.     if (useVertexBuffers)
  371.     {
  372.         glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  373.         glx::glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
  374.         vertices = NULL;
  375.     }
  376. #ifdef SHOW_FRUSTUM
  377.     // Debugging code for visualizing the frustum.
  378.     glMatrixMode(GL_PROJECTION);
  379.     glPushMatrix();
  380.     glLoadIdentity();
  381.     gluPerspective(45.0, 1.3333f, 1.0f, 100.0f);
  382.     glMatrixMode(GL_MODELVIEW);
  383.     glPushMatrix();
  384.     glLoadIdentity();
  385.     glDisable(GL_TEXTURE_2D);
  386.     glDisable(GL_LIGHTING);
  387.     glColor4f(1, 0, 0, 1);
  388.     glTranslatef(0, 0, -20);
  389.     glBegin(GL_LINES);
  390.     glVertex(ri.fp[0]); glVertex(ri.fp[1]);
  391.     glVertex(ri.fp[0]); glVertex(ri.fp[2]);
  392.     glVertex(ri.fp[3]); glVertex(ri.fp[1]);
  393.     glVertex(ri.fp[3]); glVertex(ri.fp[2]);
  394.     glVertex(ri.fp[4]); glVertex(ri.fp[5]);
  395.     glVertex(ri.fp[4]); glVertex(ri.fp[6]);
  396.     glVertex(ri.fp[7]); glVertex(ri.fp[5]);
  397.     glVertex(ri.fp[7]); glVertex(ri.fp[6]);
  398.     glVertex(ri.fp[0]); glVertex(ri.fp[4]);
  399.     glVertex(ri.fp[1]); glVertex(ri.fp[5]);
  400.     glVertex(ri.fp[2]); glVertex(ri.fp[6]);
  401.     glVertex(ri.fp[3]); glVertex(ri.fp[7]);
  402.     glEnd();
  403.     // Render axes representing the unit sphere.
  404.     glColor4f(0, 1, 0, 1);
  405.     glBegin(GL_LINES);
  406.     glVertex3f(-1, 0, 0); glVertex3f(1, 0, 0);
  407.     glVertex3f(0, -1, 0); glVertex3f(0, 1, 0);
  408.     glVertex3f(0, 0, -1); glVertex3f(1, 0, 1);
  409.     glEnd();
  410.     glMatrixMode(GL_PROJECTION);
  411.     glPopMatrix();
  412.     glMatrixMode(GL_MODELVIEW);
  413.     glPopMatrix();
  414. #endif
  415. #ifdef SHOW_PATCH_VISIBILITY
  416.     // Debugging code for visualizing the frustum.
  417.     glMatrixMode(GL_PROJECTION);
  418.     glPushMatrix();
  419.     glLoadIdentity();
  420.     glMatrixMode(GL_MODELVIEW);
  421.     glPushMatrix();
  422.     glLoadIdentity();
  423.     glDisable(GL_TEXTURE_2D);
  424.     glDisable(GL_LIGHTING);
  425.     glColor4f(1, 0, 1, 1);
  426.     {
  427.         int width = split;
  428.         int height = width / 2;
  429.         float patchWidth = 1.0f / (float) width;
  430.         float patchHeight = 1.0f / (float) height;
  431.         if (width * height <= MaxPatchesShown)
  432.         {
  433.             for (int i = 0; i < height; i++)
  434.             {
  435.                 for (int j = 0; j < width; j++)
  436.                 {
  437.                     glPushMatrix();
  438.                     glTranslatef(-0.5f + j * patchWidth,
  439.                                  1.0f - i * patchHeight,
  440.                                  0.0f);
  441.                     if (visiblePatches[i * width + j])
  442.                         glBegin(GL_QUADS);
  443.                     else
  444.                         glBegin(GL_LINE_LOOP);
  445.                     glVertex3f(0.0f, 0.0f, 0.0f);
  446.                     glVertex3f(0.0f, -patchHeight, 0.0f);
  447.                     glVertex3f(patchWidth, -patchHeight, 0.0f);
  448.                     glVertex3f(patchWidth, 0.0f, 0.0f);
  449.                     glEnd();
  450.                     glPopMatrix();
  451.                 }
  452.             }
  453.         }
  454.     }
  455.     glMatrixMode(GL_PROJECTION);
  456.     glPopMatrix();
  457.     glMatrixMode(GL_MODELVIEW);
  458.     glPopMatrix();
  459. #endif // SHOW_PATCH_VISIBILITY
  460. }
  461. int LODSphereMesh::renderPatches(int phi0, int theta0,
  462.                                  int extent,
  463.                                  int level,
  464.                                  const RenderInfo& ri)
  465. {
  466.     int thetaExtent = extent;
  467.     int phiExtent = extent / 2;
  468.     // Compute the plane separating this section of the sphere from
  469.     // the rest of the sphere.  If the view frustum lies entirely
  470.     // on the side of the plane that does not contain the sphere
  471.     // patch, we cull the patch.
  472.     Point3f p0 = spherePoint(theta0, phi0);
  473.     Point3f p1 = spherePoint(theta0 + thetaExtent, phi0);
  474.     Point3f p2 = spherePoint(theta0 + thetaExtent,
  475.                              phi0 + phiExtent);
  476.     Point3f p3 = spherePoint(theta0, phi0 + phiExtent);
  477.     Vec3f v0 = p1 - p0;
  478.     Vec3f v2 = p3 - p2;
  479.     Vec3f normal;
  480.     if (v0.lengthSquared() > v2.lengthSquared())
  481.         normal = (p0 - p3) ^ v0;
  482.     else
  483.         normal = (p2 - p1) ^ v2;
  484.     // If the normal is near zero length, something's going wrong
  485.     assert(normal.length() != 0.0f);
  486.     normal.normalize();
  487.     Planef separatingPlane(normal, p0);
  488.     bool outside = true;
  489. #if 1
  490.     for (int k = 0; k < 8; k++)
  491.     {
  492.         if (separatingPlane.distanceTo(ri.fp[k]) > 0.0f)
  493.         {
  494.             outside = false;
  495.             break;
  496.         }
  497.     }
  498.     // If this patch is outside the view frustum, so are all of its subpatches
  499.     if (outside)
  500.         return 0;
  501. #else
  502.     outside = false;
  503. #endif
  504.     // Second cull test uses the bounding sphere of the patch
  505. #if 0
  506.     // Is this a better choice for the patch center?
  507.     Point3f patchCenter = spherePoint(theta0 + thetaExtent / 2,
  508.                                       phi0 + phiExtent / 2);
  509. #else
  510.     // . . . or is the average of the points better?
  511.     Point3f patchCenter = Point3f(p0.x + p1.x + p2.x + p3.x,
  512.                                   p0.y + p1.y + p2.y + p3.y,
  513.                                   p0.z + p1.z + p2.z + p3.z) * 0.25f;
  514. #endif
  515.     float boundingRadius = 0.0f;
  516.     boundingRadius = max(boundingRadius, patchCenter.distanceTo(p0));
  517.     boundingRadius = max(boundingRadius, patchCenter.distanceTo(p1));
  518.     boundingRadius = max(boundingRadius, patchCenter.distanceTo(p2));
  519.     boundingRadius = max(boundingRadius, patchCenter.distanceTo(p3));
  520.     if (ri.frustum.testSphere(patchCenter, boundingRadius) == Frustum::Outside)
  521.         outside = true;
  522.     if (outside)
  523.     {
  524.         return 0;
  525.     }
  526.     else if (level == 1)
  527.     {
  528.         renderSection(phi0, theta0, thetaExtent, ri);
  529.         return 1;
  530.     }
  531.     else
  532.     {
  533.         int nRendered = 0;
  534.         for (int i = 0; i < 2; i++)
  535.         {
  536.             for (int j = 0; j < 2; j++)
  537.             {
  538.                 nRendered += renderPatches(phi0 + phiExtent / 2 * i,
  539.                                            theta0 + thetaExtent / 2 * j,
  540.                                            extent / 2,
  541.                                            level / 2,
  542.                                            ri);
  543.             }
  544.         }
  545.         return nRendered;
  546.     }
  547. }
  548. void LODSphereMesh::renderSection(int phi0, int theta0, int extent,
  549.                                   const RenderInfo& ri)
  550. {
  551. #ifdef SHOW_PATCH_VISIBILITY
  552.     {
  553.         int width = thetaDivisions / extent;
  554.         int height = phiDivisions / extent;
  555.         int x = theta0 / extent;
  556.         int y = phi0 / extent;
  557.         if (width * height <= MaxPatchesShown)
  558.             visiblePatches[y * width + x] = 1;
  559.     }
  560. #endif // SHOW_PATCH_VISIBILITY
  561.     GLsizei stride = (GLsizei) (vertexSize * sizeof(float));
  562.     int tangentOffset = 3;
  563.     int texCoordOffset = ((ri.attributes & Tangents) != 0) ? 6 : 3;
  564.     float* vertexBase = useVertexBuffers ? (float*) NULL : vertices;
  565.     glVertexPointer(3, GL_FLOAT, stride, vertexBase + 0);
  566.     if ((ri.attributes & Normals) != 0)
  567.         glNormalPointer(GL_FLOAT, stride, vertexBase);
  568.     for (int tc = 0; tc < nTexturesUsed; tc++)
  569.     {
  570.         if (nTexturesUsed > 1)
  571.             glx::glClientActiveTextureARB(GL_TEXTURE0_ARB + tc);
  572.         glTexCoordPointer(2, GL_FLOAT, stride,  vertexBase + (tc * 2) + texCoordOffset);
  573.     }
  574.     if ((ri.attributes & Tangents) != 0)
  575.     {
  576.         VertexProcessor* vproc = ri.context.getVertexProcessor();
  577.         vproc->attribArray(6, 3, GL_FLOAT, stride, vertexBase + tangentOffset);
  578.     }
  579.     // assert(ri.step >= minStep);
  580.     // assert(phi0 + extent <= maxDivisions);
  581.     // assert(theta0 + extent / 2 < maxDivisions);
  582.     // assert(isPow2(extent));
  583.     int thetaExtent = extent;
  584.     int phiExtent = extent / 2;
  585.     int theta1 = theta0 + thetaExtent;
  586.     int phi1 = phi0 + phiExtent;
  587.     /*int n3 = 0;   Unused*/
  588.     /*int n2 = 0;   Unused*/
  589.     float du[MAX_SPHERE_MESH_TEXTURES];
  590.     float dv[MAX_SPHERE_MESH_TEXTURES];
  591.     float u0[MAX_SPHERE_MESH_TEXTURES];
  592.     float v0[MAX_SPHERE_MESH_TEXTURES];
  593.     if (useVertexBuffers)
  594.     {
  595.         // Calling glBufferDataARB() with NULL before mapping the buffer
  596.         // is a hint to OpenGL that previous contents of vertex buffer will
  597.         // be discarded and overwritten. It enables renaming in the driver,
  598.         // hopefully resulting in performance gains.
  599.         glx::glBufferDataARB(GL_ARRAY_BUFFER_ARB,
  600.                              maxVertices * vertexSize * sizeof(float),
  601.                              NULL,
  602.                              GL_STREAM_DRAW_ARB);
  603.         vertices = reinterpret_cast<float*>(glx::glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
  604.         if (vertices == NULL)
  605.             return;
  606.     }
  607.     // Set the current texture.  This is necessary because the texture
  608.     // may be split into subtextures.
  609.     for (int tex = 0; tex < nTexturesUsed; tex++)
  610.     {
  611.         du[tex] = (float) 1.0f / thetaDivisions;;
  612.         dv[tex] = (float) 1.0f / phiDivisions;;
  613.         u0[tex] = 1.0f;
  614.         v0[tex] = 1.0f;
  615.         if (textures[tex] != NULL)
  616.         {
  617.             int uTexSplit = textures[tex]->getUTileCount(ri.texLOD[tex]);
  618.             int vTexSplit = textures[tex]->getVTileCount(ri.texLOD[tex]);
  619.             int patchSplit = maxDivisions / extent;
  620.             assert(patchSplit >= uTexSplit && patchSplit >= vTexSplit);
  621.             int u = theta0 / thetaExtent;
  622.             int v = phi0 / phiExtent;
  623.             int patchesPerUSubtex = patchSplit / uTexSplit;
  624.             int patchesPerVSubtex = patchSplit / vTexSplit;
  625.             du[tex] *= uTexSplit;
  626.             dv[tex] *= vTexSplit;
  627.             u0[tex] = 1.0f - ((float) (u % patchesPerUSubtex) /
  628.                               (float) patchesPerUSubtex);
  629.             v0[tex] = 1.0f - ((float) (v % patchesPerVSubtex) /
  630.                               (float) patchesPerVSubtex);
  631.             u0[tex] += theta0 * du[tex];
  632.             v0[tex] += phi0 * dv[tex];
  633.             u /= patchesPerUSubtex;
  634.             v /= patchesPerVSubtex;
  635.             if (nTexturesUsed > 1)
  636.                 glx::glActiveTextureARB(GL_TEXTURE0_ARB + tex);
  637.             TextureTile tile = textures[tex]->getTile(ri.texLOD[tex],
  638.                                                       uTexSplit - u - 1,
  639.                                                       vTexSplit - v - 1);
  640.             du[tex] *= tile.du;
  641.             dv[tex] *= tile.dv;
  642.             u0[tex] = u0[tex] * tile.du + tile.u;
  643.             v0[tex] = v0[tex] * tile.dv + tile.v;
  644.             // We track the current texture to avoid unnecessary and costly
  645.             // texture state changes.
  646.             if (tile.texID != subtextures[tex])
  647.             {
  648.                 glBindTexture(GL_TEXTURE_2D, tile.texID);
  649.                 subtextures[tex] = tile.texID;
  650.             }
  651.         }
  652.     }
  653.     int vindex = 0;
  654.     for (int phi = phi0; phi <= phi1; phi += ri.step)
  655.     {
  656.         float cphi = cosPhi[phi];
  657.         float sphi = sinPhi[phi];
  658.         if ((ri.attributes & Tangents) != 0)
  659.         {
  660.             for (int theta = theta0; theta <= theta1; theta += ri.step)
  661.             {
  662.                 float ctheta = cosTheta[theta];
  663.                 float stheta = sinTheta[theta];
  664.                 vertices[vindex]      = cphi * ctheta;
  665.                 vertices[vindex + 1]  = sphi;
  666.                 vertices[vindex + 2]  = cphi * stheta;
  667.                 // Compute the tangent--required for bump mapping
  668.                 vertices[vindex + 3] = stheta;
  669.                 vertices[vindex + 4] = 0.0f;
  670.                 vertices[vindex + 5] = -ctheta;
  671.                 vindex += 6;
  672.                 for (int tex = 0; tex < nTexturesUsed; tex++)
  673.                 {
  674.                     vertices[vindex]     = u0[tex] - theta * du[tex];
  675.                     vertices[vindex + 1] = v0[tex] - phi * dv[tex];
  676.                     vindex += 2;
  677.                 }
  678.             }
  679.         }
  680.         else
  681.         {
  682.             for (int theta = theta0; theta <= theta1; theta += ri.step)
  683.             {
  684.                 float ctheta = cosTheta[theta];
  685.                 float stheta = sinTheta[theta];
  686.                 vertices[vindex]      = cphi * ctheta;
  687.                 vertices[vindex + 1]  = sphi;
  688.                 vertices[vindex + 2]  = cphi * stheta;
  689.                 vindex += 3;
  690.                 for (int tex = 0; tex < nTexturesUsed; tex++)
  691.                 {
  692.                     vertices[vindex]     = u0[tex] - theta * du[tex];
  693.                     vertices[vindex + 1] = v0[tex] - phi * dv[tex];
  694.                     vindex += 2;
  695.                 }
  696.             }
  697.         }
  698.     }
  699.     if (useVertexBuffers)
  700.     {
  701.         vertices = NULL;
  702.         if (!glx::glUnmapBufferARB(GL_ARRAY_BUFFER_ARB))
  703.             return;
  704.     }
  705.     // TODO: Fix this--number of rings can reach zero and cause dropout
  706.     // int nRings = max(phiExtent / ri.step, 1); // buggy
  707.     int nRings = phiExtent / ri.step;
  708.     int nSlices = thetaExtent / ri.step;
  709.     unsigned short* indexBase = useVertexBuffers ? (unsigned short*) NULL : indices;
  710.     for (int i = 0; i < nRings; i++)
  711.     {
  712.         glDrawElements(GL_QUAD_STRIP,
  713.                        (nSlices + 1) * 2,
  714.                        GL_UNSIGNED_SHORT,
  715.                        indexBase + (nSlices + 1) * 2 * i);
  716.     }
  717.     // Cycle through the vertex buffers
  718.     if (useVertexBuffers)
  719.     {
  720.         currentVB++;
  721.         if (currentVB == NUM_SPHERE_VERTEX_BUFFERS)
  722.             currentVB = 0;
  723.         glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffers[currentVB]);
  724.     }
  725. }