llrendersphere.cpp

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

Generated on Fri May 16 08:33:59 2008 for SecondLife by  doxygen 1.5.5