/** * @file llcylinder.cpp * @brief Draws a cylinder using display lists for speed. * * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. * $License$ */ #include "llviewerprecompiledheaders.h" #include "llcylinder.h" #include "llerror.h" #include "math.h" #include "llmath.h" #include "noise.h" #include "v3math.h" #include "llgl.h" #include "llglheaders.h" LLCylinder gCylinder; LLCone gCone; GLUquadricObj* gQuadObj = NULL; // draws a cylinder or cone // returns approximate number of triangles required U32 draw_cylinder_side(GLint slices, GLint stacks, GLfloat base_radius, GLfloat top_radius) { U32 triangles = 0; GLfloat height = 1.0f; if (!gQuadObj) { gQuadObj = gluNewQuadric(); if (!gQuadObj) llerror("draw_cylindrical_body couldn't allocated quadric", 0); } gluQuadricDrawStyle(gQuadObj, GLU_FILL); gluQuadricNormals(gQuadObj, GLU_SMOOTH); gluQuadricOrientation(gQuadObj, GLU_OUTSIDE); gluQuadricTexture(gQuadObj, GL_TRUE); gluCylinder(gQuadObj, base_radius, top_radius, height, slices, stacks); triangles += stacks * (slices * 2); return triangles; } // Returns number of triangles required to draw // Need to know if top or not to set lighting normals const BOOL TOP = TRUE; const BOOL BOTTOM = FALSE; U32 draw_cylinder_cap(GLint slices, GLfloat base_radius, BOOL is_top) { U32 triangles = 0; if (!gQuadObj) { gQuadObj = gluNewQuadric(); if (!gQuadObj) llerror("draw_cylinder_base couldn't allocated quadric", 0); } gluQuadricDrawStyle(gQuadObj, GLU_FILL); gluQuadricNormals(gQuadObj, GLU_SMOOTH); gluQuadricOrientation(gQuadObj, GLU_OUTSIDE); gluQuadricTexture(gQuadObj, GL_TRUE); // no hole in the middle of the disk, and just one ring GLdouble inner_radius = 0.0; GLint rings = 1; // normals point in +z for top, -z for base if (is_top) { gluQuadricOrientation(gQuadObj, GLU_OUTSIDE); } else { gluQuadricOrientation(gQuadObj, GLU_INSIDE); } gluDisk(gQuadObj, inner_radius, base_radius, slices, rings); triangles += slices; return triangles; } void LLCylinder::prerender() { GLint stacks = 2; GLfloat radius = 0.5f; GLint slices[CYLINDER_LEVELS_OF_DETAIL] = { 30, 20, 12, 6 }; // same as sphere slices for (S32 detail = 0; detail < CYLINDER_LEVELS_OF_DETAIL; detail++) { mTriangleCount[detail] = 0; mDisplayListSide[detail] = glGenLists(1); glNewList(mDisplayListSide[detail], GL_COMPILE); mTriangleCount[detail] += draw_cylinder_side( slices[detail], stacks, radius, radius ); glEndList(); mDisplayListTop[detail] = glGenLists(1); glNewList( mDisplayListTop[detail], GL_COMPILE); mTriangleCount[detail] += draw_cylinder_cap( slices[detail], radius, TOP ); glEndList(); mDisplayListBottom[detail] = glGenLists(1); glNewList( mDisplayListBottom[detail], GL_COMPILE); mTriangleCount[detail] += draw_cylinder_cap( slices[detail], radius, BOTTOM ); glEndList(); } } void LLCylinder::cleanupGL() { for (S32 detail = 0; detail < CYLINDER_LEVELS_OF_DETAIL; detail++) { glDeleteLists(mDisplayListSide[detail], 1); mDisplayListSide[detail] = 0; glDeleteLists(mDisplayListTop[detail], 1); mDisplayListTop[detail] = 0; glDeleteLists(mDisplayListBottom[detail], 1); mDisplayListBottom[detail] = 0; } if (gQuadObj) { gluDeleteQuadric(gQuadObj); gQuadObj = NULL; } } void LLCylinder::render(F32 pixel_area) { renderface(pixel_area, 0); renderface(pixel_area, 1); renderface(pixel_area, 2); } void LLCylinder::renderface(F32 pixel_area, S32 face) { if (face < 0 || face > 2) { llerror("LLCylinder::renderface() invalid face number", face); return; } glMatrixMode(GL_MODELVIEW); glPushMatrix(); S32 level_of_detail; if (pixel_area > 20000.f) { level_of_detail = 0; } else if (pixel_area > 1600.f) { level_of_detail = 1; } else if (pixel_area > 200.f) { level_of_detail = 2; } else { level_of_detail = 3; } if (level_of_detail < 0 || CYLINDER_LEVELS_OF_DETAIL <= level_of_detail) { llerror("LLCylinder::renderface() invalid level of detail", level_of_detail); return; } switch(face) { case 0: glTranslatef(0.f, 0.f, -0.5f); glCallList(mDisplayListSide[level_of_detail]); break; case 1: glTranslatef(0.0f, 0.f, 0.5f); glCallList(mDisplayListTop[level_of_detail]); break; case 2: glTranslatef(0.0f, 0.f, -0.5f); glCallList(mDisplayListBottom[level_of_detail]); break; default: llerror("LLCylinder::renderface() fell out of switch", 0); break; } glMatrixMode(GL_MODELVIEW); glPopMatrix(); } // // Cones // void LLCone::prerender() { GLint stacks = 2; GLfloat radius = 0.5f; GLint slices[CONE_LEVELS_OF_DETAIL] = { 32, 18, 12, 6 }; for (S32 detail = 0; detail < CONE_LEVELS_OF_DETAIL; detail++) { mTriangleCount[detail] = 0; mDisplayListSide[detail] = glGenLists(1); glNewList(mDisplayListSide[detail], GL_COMPILE); mTriangleCount[detail] += draw_cylinder_side( slices[detail], stacks, radius, 0.f ); glEndList(); mDisplayListBottom[detail] = glGenLists(1); glNewList( mDisplayListBottom[detail], GL_COMPILE); mTriangleCount[detail] += draw_cylinder_cap( slices[detail], radius, BOTTOM ); glEndList(); } } void LLCone::cleanupGL() { for (S32 detail = 0; detail < CYLINDER_LEVELS_OF_DETAIL; detail++) { glDeleteLists(mDisplayListSide[detail], 1); mDisplayListSide[detail] = 0; glDeleteLists(mDisplayListBottom[detail], 1); mDisplayListBottom[detail] = 0; } if (gQuadObj) { gluDeleteQuadric(gQuadObj); gQuadObj = NULL; } } void LLCone::render(S32 level_of_detail) { GLfloat height = 1.0f; if (level_of_detail < 0 || CONE_LEVELS_OF_DETAIL <= level_of_detail) { llerror("LLCone::render() invalid level of detail", level_of_detail); return; } glMatrixMode(GL_MODELVIEW); glPushMatrix(); // center object at 0 glTranslatef(0.f, 0.f, - height / 2.0f); glCallList(mDisplayListSide[level_of_detail]); glCallList(mDisplayListBottom[level_of_detail]); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } void LLCone::renderface(S32 level_of_detail, S32 face) { if (face < 0 || face > 1) { llerror("LLCone::renderface() invalid face number", face); return; } if (level_of_detail < 0 || CONE_LEVELS_OF_DETAIL <= level_of_detail) { llerror("LLCone::renderface() invalid level of detail", level_of_detail); return; } glMatrixMode(GL_MODELVIEW); glPushMatrix(); switch(face) { case 0: glTranslatef(0.f, 0.f, -0.5f); glCallList(mDisplayListSide[level_of_detail]); break; case 1: glTranslatef(0.f, 0.f, -0.5f); glCallList(mDisplayListBottom[level_of_detail]); break; default: llerror("LLCylinder::renderface() fell out of switch", 0); break; } glMatrixMode(GL_MODELVIEW); glPopMatrix(); }