llsphere.cpp

Go to the documentation of this file.
00001 
00032 //      Sphere creates a set of display lists that can then be called to create 
00033 //      a lit sphere at different LOD levels.  You only need one instance of sphere 
00034 //      per viewer - then call the appropriate list.  
00035 
00036 #include "llviewerprecompiledheaders.h"
00037 #include "llsphere.h"
00038 #include "llerror.h"
00039 #include "llvertexbuffer.h"
00040 #include "llglheaders.h"
00041 
00042 GLUquadricObj *gQuadObj2 = NULL;
00043 LLSphere gSphere;
00044 
00045 void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks);
00046 
00047 void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks)
00048 {
00049         if (!gQuadObj2)
00050         {
00051                 gQuadObj2 = gluNewQuadric();
00052                 if (!gQuadObj2)
00053                 {
00054                         llwarns << "drawSolidSphere couldn't allocate quadric" << llendl;
00055                         return;
00056                 }
00057         }
00058 
00059         gluQuadricDrawStyle(gQuadObj2, GLU_FILL);
00060         gluQuadricNormals(gQuadObj2, GLU_SMOOTH);
00061         // If we ever changed/used the texture or orientation state
00062         // of quadObj, we'd need to change it to the defaults here
00063         // with gluQuadricTexture and/or gluQuadricOrientation.
00064         gluQuadricTexture(gQuadObj2, GL_TRUE);
00065         gluSphere(gQuadObj2, radius, slices, stacks);
00066 }
00067 
00068 
00069 // lat = 0 is Z-axis
00070 // lon = 0, lat = 90 at X-axis
00071 void lat2xyz(LLVector3 * result, F32 lat, F32 lon)
00072 {
00073         // Convert a latitude and longitude to x,y,z on a normal sphere and return it in result
00074         F32 r;
00075         result->mV[VX] = (F32) (cos(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD));
00076         result->mV[VY] = (F32) (sin(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD));
00077         r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f);
00078         if (r == 1.0f) 
00079         {
00080                 result->mV[VZ] = 0.0f;
00081         }
00082         else
00083         {
00084                 result->mV[VZ] = (F32) pow(1 - r*r, 0.5f);
00085                 if (lat > 90.01)
00086                 {
00087                         result->mV[VZ] *= -1.0;
00088                 }
00089         }
00090 }
00091 
00092 void lat2xyz_rad(LLVector3 * result, F32 lat, F32 lon)
00093 {
00094         // Convert a latitude and longitude to x,y,z on a normal sphere and return it in result
00095         F32 r;
00096         result->mV[VX] = (F32) (cos(lon) * sin(lat));
00097         result->mV[VY] = (F32) (sin(lon) * sin(lat));
00098         r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f);
00099         if (r == 1.0f) 
00100                 result->mV[VZ] = 0.0f;
00101         else
00102         {
00103                 result->mV[VZ] = (F32) pow(1 - r*r, 0.5f);
00104                 if (lat > F_PI_BY_TWO) result->mV[VZ] *= -1.0;
00105         }
00106 }
00107 
00108 // A couple thoughts on sphere drawing:
00109 // 1) You need more slices than stacks, but little less than 2:1
00110 // 2) At low LOD, setting stacks to an odd number avoids a "band" around the equator, making things look smoother
00111 void LLSphere::prerender()
00112 {
00113         //  Create a series of display lists for different LODs
00114         mDList[0] = glGenLists(1);
00115         glNewList(mDList[0], GL_COMPILE);
00116         drawSolidSphere(1.0, 30, 20);
00117         glEndList();
00118 
00119         mDList[1] = glGenLists(1);
00120         glNewList(mDList[1], GL_COMPILE);
00121         drawSolidSphere(1.0, 20, 15);
00122         glEndList();
00123 
00124         mDList[2] = glGenLists(1);
00125         glNewList(mDList[2], GL_COMPILE);
00126         drawSolidSphere(1.0, 12, 8);
00127         glEndList();
00128 
00129         mDList[3] = glGenLists(1);
00130         glNewList(mDList[3], GL_COMPILE);
00131         drawSolidSphere(1.0, 8, 5);
00132         glEndList();
00133 }
00134 
00135 void LLSphere::cleanupGL()
00136 {
00137         for (S32 detail = 0; detail < 4; detail++)
00138         {
00139                 glDeleteLists(mDList[detail], 1);
00140                 mDList[detail] = 0;
00141         }
00142         
00143         if (gQuadObj2)
00144         {
00145                 gluDeleteQuadric(gQuadObj2);
00146                 gQuadObj2 = NULL;
00147         }
00148 }
00149 
00150 // Constants here are empirically derived from my eyeballs, JNC
00151 //
00152 // The toughest adjustment is the cutoff for the lowest LOD
00153 // Maybe we should have more LODs at the low end?
00154 void LLSphere::render(F32 pixel_area)
00155 {
00156         S32 level_of_detail;
00157 
00158         if (pixel_area > 10000.f)
00159         {
00160                 level_of_detail = 0;
00161         }
00162         else if (pixel_area > 800.f)
00163         {
00164                 level_of_detail = 1;
00165         }
00166         else if (pixel_area > 100.f)
00167         {
00168                 level_of_detail = 2;
00169         }
00170         else
00171         {
00172                 level_of_detail = 3;
00173         }
00174         LLVertexBuffer::unbind();
00175         glCallList(mDList[level_of_detail]);
00176 }
00177 
00178 
00179 void LLSphere::render()
00180 {
00181         LLVertexBuffer::unbind();
00182         glCallList(mDList[0]);
00183 }

Generated on Thu Jul 1 06:09:12 2010 for Second Life Viewer by  doxygen 1.4.7