r_sphere.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 1997-2001 Id Software, Inc.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "r_local.h"
00027 #include "r_sphere.h"
00028 #include "r_error.h"
00029 
00030 static cvar_t *r_sphereDetails;
00031 
00032 sphere_t r_globeEarth;
00033 sphere_t r_globeMoon;
00034 sphere_t r_globeEarthAtmosphere;
00035 
00036 static inline float rhoSpiral (const int index, const float deltaRho,const float thetaAngle)
00037 {
00038     const float rhoAngle = (index == 0) ? 0.0f : (float) ((index - 1) * deltaRho + thetaAngle * deltaRho / (2.0f * M_PI));
00039     return rhoAngle > M_PI ? M_PI : rhoAngle;
00040 }
00041 
00050 void R_SphereGenerate (sphere_t *sphere, const int tris, const float radius)
00051 {
00052     const float drho = M_PI / tris; 
00053     /* must multiply pi by 2, rather than do integer division of tris by two,
00054      * otherwise it goes wrong when tris is an odd number */
00055     const float dtheta = 2.0f * M_PI / tris; 
00057     int i, j;
00058 
00059     int vertspos = 0;
00060     int texespos = 0;
00061 
00062     sphere->glslProgram = NULL;
00063 
00064     sphere->verts = (float*)Mem_PoolAlloc(sizeof(float) * ((tris + 1) * (tris + 2) * 6), vid_genericPool, 0);
00065     sphere->texes = (float*)Mem_PoolAlloc(sizeof(float) * ((tris + 1) * (tris + 2) * 4), vid_genericPool, 0);
00066     sphere->normals = (float*)Mem_PoolAlloc(sizeof(float) * ((tris + 1) * (tris + 2) * 6), vid_genericPool, 0);
00067 
00068     /* must be i <= tris, as one loop is wasted, because of the spiral */
00069     for (i = 0; i <= tris; i++) { /* loop through rho, from pole to pole */
00070         /* must be j <= tris, so it meets up again */
00071         for (j = 0; j <= tris ; j++) { /* loop through theta, around equator */
00072             const float theta = j * dtheta;
00073             const float stheta = (float) (-sin(theta));
00074             const float ctheta = (float) (cos(theta));
00075 
00076             /* second term in rho adds a spiral */
00077             const float rho = rhoSpiral(i, drho, theta);
00078             const float rhodrho = rhoSpiral(i + 1, drho, theta); /* rho plus drho, minding boundary conditions */
00079             const float srho = (float) (sin(rho));
00080             const float crho = (float) (cos(rho));
00081             const float srhodrho = (float) (sin(rhodrho));
00082             const float crhodrho = (float) (cos(rhodrho));
00083 
00084             const float st   = 1 - rho     / M_PI;
00085             const float stdt = 1 - rhodrho / M_PI;
00086 
00087             const float s = theta / (4.0f * M_PI);
00088 
00089             Vector2Set((&sphere->texes[texespos]), s, stdt);
00090             texespos += 2;
00091 
00092             VectorSet((&sphere->verts[vertspos]),
00093                 stheta * srhodrho * radius,
00094                 ctheta * srhodrho * radius,
00095                 crhodrho * radius);
00096             VectorNormalize2((&sphere->verts[vertspos]), (&sphere->normals[vertspos]));
00097             vertspos += 3;
00098 
00099             Vector2Set((&sphere->texes[texespos]), s, st);
00100             texespos += 2;
00101 
00102             VectorSet((&sphere->verts[vertspos]),
00103                 stheta * srho * radius,
00104                 ctheta * srho * radius,
00105                 crho * radius);
00106             VectorNormalize2((&sphere->verts[vertspos]), (&sphere->normals[vertspos]));
00107             vertspos += 3;
00108         }
00109     }
00110     sphere->num_tris = (tris + 1) * (tris + 2) * 2;
00111 }
00112 
00120 void R_SphereInit (void)
00121 {
00122     r_sphereDetails = Cvar_Get("r_sphereDetails", "1.0", CVAR_ARCHIVE, "Factor to increase or decrease the sphere tris");
00123     if (r_sphereDetails->integer <= 0)
00124         Cvar_SetValue("r_sphereDetails", 1.0);
00125 
00126     R_SphereGenerate(&r_globeEarth, 60 * r_sphereDetails->value, EARTH_RADIUS);
00127     R_SphereGenerate(&r_globeEarthAtmosphere, 60 * r_sphereDetails->value, EARTH_RADIUS * 1.03);
00128     /* the earth has more details than the moon */
00129     R_SphereGenerate(&r_globeMoon, 20 * r_sphereDetails->value, MOON_RADIUS);
00130 }
00131 
00132 static inline void R_SphereActivateTextureUnit (gltexunit_t *texunit, void *texCoordBuffer)
00133 {
00134     R_SelectTexture(texunit);
00135     R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, texCoordBuffer);
00136     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00137 }
00138 
00139 static inline void R_SphereDeactivateTextureUnit (gltexunit_t *texunit)
00140 {
00141     R_SelectTexture(texunit);
00142     R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
00143     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
00144 }
00145 
00146 static void R_SphereRenderTris (const sphere_t *sphere)
00147 {
00148     glEnable(GL_CULL_FACE);
00149     glEnable(GL_NORMALIZE);
00150 
00151     glDrawArrays(GL_TRIANGLE_STRIP, 0, sphere->num_tris);
00152 
00153     glDisable(GL_NORMALIZE);
00154     glDisable(GL_CULL_FACE);
00155 }
00156 
00161 static inline qboolean R_SphereCheckGLSL (const sphere_t *sphere)
00162 {
00163     return sphere->glslProgram && qglUseProgram && r_programs->integer;
00164 }
00165 
00174 void R_SphereRender (const sphere_t *sphere, const vec3_t pos, const vec3_t rotate, const float scale, const vec4_t lightPos)
00175 {
00176 
00177     /* go to a new matrix */
00178     glPushMatrix();
00179 
00180     glMatrixMode(GL_MODELVIEW);
00181     glTranslatef(pos[0], pos[1], pos[2]);
00182 
00183     /* flatten the sphere */
00184     glScalef(scale * viddef.rx, scale * viddef.ry, scale);
00185     R_CheckError();
00186 
00187     /* rotate the globe as given in ccs.angles */
00188     glRotatef(rotate[YAW], 1, 0, 0);
00189     glRotatef(rotate[ROLL], 0, 1, 0);
00190     glRotatef(rotate[PITCH], 0, 0, 1);
00191 
00192     if (lightPos && VectorNotEmpty(lightPos))
00193         glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
00194 
00195     R_CheckError();
00196 
00197     if (!sphere->overlay  && R_SphereCheckGLSL(sphere))
00198         R_SphereShadeGLSL(sphere); /* render globe with bump mapping, specularity, etc. */
00199     else
00200         R_SphereShade(sphere); /* otherwise, use basic OpenGL rendering */
00201 
00202     /* cleanup common to both GLSL and normal rendering */
00203     R_CheckError();
00204 
00205     /* restore the previous matrix */
00206     glPopMatrix();
00207 
00208     refdef.aliasCount += sphere->num_tris * sphere->num_tris;
00209 
00210     R_BindDefaultArray(GL_VERTEX_ARRAY);
00211     R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
00212     R_BindDefaultArray(GL_NORMAL_ARRAY);
00213 }
00214 
00218 void R_SphereShade (const sphere_t *sphere)
00219 {
00220     if (sphere->overlay)
00221         R_BindTexture(sphere->overlay->texnum);
00222     else
00223         R_BindTexture(sphere->texture->texnum);
00224 
00225     if (sphere->overlayAlphaMask) {
00226         R_EnableTexture(&texunit_lightmap, qtrue);
00227         R_SelectTexture(&texunit_lightmap);
00228         R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, sphere->texes);
00229         R_BindLightmapTexture(sphere->overlayAlphaMask->texnum);
00230     }
00231 
00232     R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, sphere->verts);
00233     R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, sphere->texes);
00234     R_BindArray(GL_NORMAL_ARRAY, GL_FLOAT, sphere->normals);
00235 
00236     glEnableClientState(GL_NORMAL_ARRAY);
00237 
00238     R_SphereRenderTris(sphere);
00239 
00240     glDisableClientState(GL_NORMAL_ARRAY);
00241 
00242     if (sphere->overlayAlphaMask)
00243         R_EnableTexture(&texunit_lightmap, qfalse);
00244 }
00245 
00249 void R_SphereShadeGLSL (const sphere_t *sphere)
00250 {
00251     if (Vector4NotEmpty(sphere->nightLightPos))
00252         glLightfv(GL_LIGHT1, GL_POSITION, sphere->nightLightPos);
00253 
00254     /* configure openGL to use our shader program */
00255     R_EnableLighting(sphere->glslProgram, qtrue);
00256 
00257     R_BindTexture(sphere->texture->texnum);
00258     if (sphere->blendTexture)
00259         R_BindTextureForTexUnit(sphere->blendTexture->texnum, &texunit_1);
00260     if (sphere->normalMap)
00261         R_BindTextureForTexUnit(sphere->normalMap->texnum, &texunit_2);
00262 
00263     if (r_lights->integer) {
00264         if (sphere->blendScale >= 0)
00265             R_ProgramParameter1f("BLENDSCALE", sphere->blendScale);
00266         if (r_postprocess->integer && sphere->glowScale >= 0)
00267             R_ProgramParameter1f("GLOWSCALE", sphere->glowScale);
00268     }
00269 
00270     /* set up pointers */
00271     R_SphereActivateTextureUnit(&texunit_1, sphere->texes);
00272     R_SphereActivateTextureUnit(&texunit_2, sphere->texes);
00273 
00274     R_SelectTexture(&texunit_diffuse);
00275     R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, sphere->verts);
00276     R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, sphere->texes);
00277     R_BindArray(GL_NORMAL_ARRAY, GL_FLOAT, sphere->normals);
00278 
00279     R_SphereRenderTris(sphere);
00280 
00281     R_SphereDeactivateTextureUnit(&texunit_1);
00282     R_SphereDeactivateTextureUnit(&texunit_2);
00283 
00284     /* deactivate the shader program */
00285     R_EnableLighting(NULL, qfalse);
00286     R_SelectTexture(&texunit_diffuse);
00287 }
00288 

Generated by  doxygen 1.6.2