/** * @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 "llvertexbuffer.h" #include "llgl.h" #include "llglheaders.h" LLCylinder gCylinder; LLCone gCone; GLUquadricObj* gQuadObj = NULL; static const GLint SLICES[] = { 30, 20, 12, 6 }; // same as sphere slices static const GLint STACKS = 2; static const GLfloat RADIUS = 0.5f; // 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::drawSide(S32 detail) { draw_cylinder_side(SLICES[detail], STACKS, RADIUS, RADIUS); } void LLCylinder::drawTop(S32 detail) { draw_cylinder_cap(SLICES[detail], RADIUS, TOP); } void LLCylinder::drawBottom(S32 detail) { draw_cylinder_cap(SLICES[detail], RADIUS, BOTTOM); } void LLCylinder::prerender() { } void LLCylinder::cleanupGL() { 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; } LLVertexBuffer::unbind(); switch(face) { case 0: glTranslatef(0.f, 0.f, -0.5f); drawSide(level_of_detail); break; case 1: glTranslatef(0.0f, 0.f, 0.5f); drawTop(level_of_detail); break; case 2: glTranslatef(0.0f, 0.f, -0.5f); drawBottom(level_of_detail); break; default: llerror("LLCylinder::renderface() fell out of switch", 0); break; } glMatrixMode(GL_MODELVIEW); glPopMatrix(); } // // Cones // void LLCone::prerender() { } void LLCone::cleanupGL() { if (gQuadObj) { gluDeleteQuadric(gQuadObj); gQuadObj = NULL; } } void LLCone::drawSide(S32 detail) { draw_cylinder_side( SLICES[detail], STACKS, RADIUS, 0.f ); } void LLCone::drawBottom(S32 detail) { draw_cylinder_cap( SLICES[detail], RADIUS, BOTTOM ); } 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); LLVertexBuffer::unbind(); drawSide(level_of_detail); drawBottom(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(); LLVertexBuffer::unbind(); switch(face) { case 0: glTranslatef(0.f, 0.f, -0.5f); drawSide(level_of_detail); break; case 1: glTranslatef(0.f, 0.f, -0.5f); drawBottom(level_of_detail); break; default: llerror("LLCylinder::renderface() fell out of switch", 0); break; } glMatrixMode(GL_MODELVIEW); glPopMatrix(); }