r_material.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_error.h"
00028 #include "r_lightmap.h"
00029 #include "../../shared/parse.h"
00030 
00031 mBspSurfaces_t r_material_surfaces;
00032 
00033 #define UPDATE_THRESHOLD 0.02
00034 
00037 static void R_UpdateMaterial (material_t *m)
00038 {
00039     materialStage_t *s;
00040 
00041     if (refdef.time - m->time < UPDATE_THRESHOLD)
00042         return;
00043 
00044     m->time = refdef.time;
00045 
00046     for (s = m->stages; s; s = s->next) {
00047         if (s->flags & STAGE_PULSE)
00048             s->pulse.dhz = (sin(refdef.time * s->pulse.hz * (2 * M_PI)) + 1.0) / 2.0;
00049 
00050         if (s->flags & STAGE_STRETCH) {
00051             s->stretch.dhz = (sin(refdef.time * s->stretch.hz * (2 * M_PI)) + 1.0) / 2.0;
00052             s->stretch.damp = 1.5 - s->stretch.dhz * s->stretch.amp;
00053         }
00054 
00055         if (s->flags & STAGE_ROTATE)
00056             s->rotate.deg = refdef.time * s->rotate.hz * 360.0;
00057 
00058         if (s->flags & STAGE_SCROLL_S)
00059             s->scroll.ds = s->scroll.s * refdef.time;
00060 
00061         if (s->flags & STAGE_SCROLL_T)
00062             s->scroll.dt = s->scroll.t * refdef.time;
00063 
00064         if (s->flags & STAGE_ANIM) {
00065             if (refdef.time >= s->anim.dtime) {  /* change frames */
00066                 int frame;
00067                 s->anim.dtime = refdef.time + (1.0 / s->anim.fps);
00068                 s->anim.dframe++;
00069                 switch (s->anim.type) {
00070                 case ANIM_NORMAL:
00071                     frame = s->anim.dframe % s->anim.num_frames;
00072                     break;
00073                 case ANIM_ALTERNATE:
00074                     frame = abs(s->anim.dframe % (s->anim.num_frames + 1) - (s->anim.num_frames / 2));
00075                     break;
00076                 case ANIM_BACKWARDS:
00077                     frame = s->anim.num_frames - 1;
00078                     frame -= s->anim.dframe % s->anim.num_frames;
00079                     break;
00080                 case ANIM_RANDOM:
00081                     frame = rand() % s->anim.num_frames;
00082                     break;
00083                 case ANIM_RANDOMFORCE:
00084                     frame = rand() % s->anim.num_frames;
00085                     if (s->image == s->anim.images[frame])
00086                         frame = (frame + 1) % s->anim.num_frames;
00087                     break;
00088                 }
00089                 assert(frame >= 0);
00090                 assert(frame < s->anim.num_frames);
00091                 s->image = s->anim.images[frame];
00092             }
00093         }
00094     }
00095 }
00096 
00097 static void R_StageGlow (const materialStage_t *stage)
00098 {
00099     if (stage->image->glowmap) {
00100         R_EnableGlowMap(stage->image->glowmap, qtrue);
00101         if (r_state.glowmap_enabled)
00102             R_ProgramParameter1f("GLOWSCALE", stage->glowscale);
00103     } else {
00104         R_EnableGlowMap(NULL, qfalse);
00105     }
00106 }
00107 
00111 static void R_StageLighting (const mBspSurface_t *surf, const materialStage_t *stage)
00112 {
00113     /* if the surface has a lightmap, and the stage specifies lighting.. */
00114     if (surf->flags & MSURF_LIGHTMAP &&
00115             (stage->flags & (STAGE_LIGHTMAP | STAGE_LIGHTING))) {
00116         R_EnableTexture(&texunit_lightmap, qtrue);
00117         R_BindLightmapTexture(surf->lightmap_texnum);
00118 
00119         /* hardware lighting */
00120         if ((stage->flags & STAGE_LIGHTING)) {
00121             R_EnableLighting(r_state.world_program, qtrue);
00122             R_SetSurfaceBumpMappingParameters(surf, stage->image->normalmap);
00123         } else {
00124             R_SetSurfaceBumpMappingParameters(surf, NULL);
00125             R_EnableLighting(NULL, qfalse);
00126         }
00127     } else {
00128         R_EnableLighting(NULL, qfalse);
00129 
00130         R_EnableTexture(&texunit_lightmap, qfalse);
00131     }
00132 }
00133 
00138 static inline void R_StageVertex (const mBspSurface_t *surf, const materialStage_t *stage, const vec3_t in, vec3_t out)
00139 {
00140     VectorCopy(in, out);
00141 }
00142 
00147 static inline void R_StageTextureMatrix (const mBspSurface_t *surf, const materialStage_t *stage)
00148 {
00149     static qboolean identity = qtrue;
00150     float s, t;
00151 
00152     if (!(stage->flags & STAGE_TEXTURE_MATRIX)) {
00153         if (!identity)
00154             glLoadIdentity();
00155 
00156         identity = qtrue;
00157         return;
00158     }
00159 
00160     glLoadIdentity();
00161 
00162     s = surf->stcenter[0] / surf->texinfo->image->width;
00163     t = surf->stcenter[1] / surf->texinfo->image->height;
00164 
00165     if (stage->flags & STAGE_STRETCH) {
00166         glTranslatef(-s, -t, 0.0);
00167         glScalef(stage->stretch.damp, stage->stretch.damp, 1.0);
00168         glTranslatef(-s, -t, 0.0);
00169     }
00170 
00171     if (stage->flags & STAGE_ROTATE) {
00172         glTranslatef(-s, -t, 0.0);
00173         glRotatef(stage->rotate.deg, 0.0, 0.0, 1.0);
00174         glTranslatef(-s, -t, 0.0);
00175     }
00176 
00177     if (stage->flags & STAGE_SCALE_S)
00178         glScalef(stage->scale.s, 1.0, 1.0);
00179 
00180     if (stage->flags & STAGE_SCALE_T)
00181         glScalef(1.0, stage->scale.t, 1.0);
00182 
00183     if (stage->flags & STAGE_SCROLL_S)
00184         glTranslatef(stage->scroll.ds, 0.0, 0.0);
00185 
00186     if (stage->flags & STAGE_SCROLL_T)
00187         glTranslatef(0.0, stage->scroll.dt, 0.0);
00188 
00189     identity = qfalse;
00190 }
00191 
00195 static void R_StageTexCoord (const materialStage_t *stage, const vec3_t v, const vec2_t in, vec2_t out)
00196 {
00197     vec3_t tmp;
00198 
00199     if (stage->flags & STAGE_ENVMAP) {  /* generate texcoords */
00200         VectorSubtract(v, refdef.viewOrigin, tmp);
00201         VectorNormalize(tmp);
00202         Vector2Copy(tmp, out);
00203     } else {  /* or use the ones we were given */
00204         Vector2Copy(in, out);
00205     }
00206 }
00207 
00209 static const float dirtmap[] = {
00210         0.6, 0.5, 0.3, 0.4, 0.7, 0.3, 0.0, 0.4,
00211         0.5, 0.2, 0.8, 0.5, 0.3, 0.2, 0.5, 0.3
00212 };
00213 
00217 static void R_StageColor (const materialStage_t *stage, const vec3_t v, vec4_t color)
00218 {
00219     if (stage->flags & (STAGE_TERRAIN | STAGE_TAPE)) {
00220         float a;
00221 
00222         if (stage->flags & STAGE_COLOR)  /* honor stage color */
00223             VectorCopy(stage->color, color);
00224         else  /* or use white */
00225             VectorSet(color, 1.0, 1.0, 1.0);
00226 
00227         /* resolve alpha for vert based on z axis height */
00228         if (stage->flags & STAGE_TERRAIN) {
00229             if (v[2] < stage->terrain.floor)
00230                 a = 0.0;
00231             else if (v[2] > stage->terrain.ceil)
00232                 a = 1.0;
00233             else
00234                 a = (v[2] - stage->terrain.floor) / stage->terrain.height;
00235         } else {
00236             if (v[2] < stage->tape.max && v[2] > stage->tape.min) {
00237                 if (v[2] > stage->tape.center) {
00238                     const float delta = v[2] - stage->tape.center;
00239                     a = 1 - (delta / stage->tape.max);
00240                 } else {
00241                     const float delta = stage->tape.center - v[2];
00242                     a = 1 - (delta / stage->tape.min);
00243                 }
00244             } else {
00245                 a = 0.0;
00246             }
00247         }
00248 
00249         color[3] = a;
00250     } else if (stage->flags & STAGE_DIRTMAP) {
00251         /* resolve dirtmap based on vertex position */
00252         const int index = (int)VectorLength(v) % lengthof(dirtmap);
00253 
00254         if (stage->flags & STAGE_COLOR)  /* honor stage color */
00255             VectorCopy(stage->color, color);
00256         else  /* or use white */
00257             VectorSet(color, 1.0, 1.0, 1.0);
00258         color[3] = dirtmap[index] * stage->dirt.intensity;
00259     } else {  /* simply use white */
00260         Vector4Set(color, 1.0, 1.0, 1.0, 1.0);
00261     }
00262 }
00263 
00268 static void R_SetSurfaceStageState (const mBspSurface_t *surf, const materialStage_t *stage)
00269 {
00270     vec4_t color;
00271 
00272     /* bind the texture */
00273     R_BindTexture(stage->image->texnum);
00274 
00275     /* and optionally the lightmap */
00276     R_StageLighting(surf, stage);
00277 
00278     R_StageGlow(stage);
00279 
00280     /* load the texture matrix for rotations, stretches, etc.. */
00281     R_StageTextureMatrix(surf, stage);
00282 
00283     /* set the blend function, ensuring a good default */
00284     if (stage->flags & STAGE_BLEND)
00285         R_BlendFunc(stage->blend.src, stage->blend.dest);
00286     else
00287         R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00288 
00289     /* for terrain, enable the color array */
00290     if (stage->flags & (STAGE_TAPE | STAGE_TERRAIN | STAGE_DIRTMAP))
00291         R_EnableColorArray(qtrue);
00292     else
00293         R_EnableColorArray(qfalse);
00294 
00295     /* when not using the color array, resolve the shade color */
00296     if (!r_state.color_array_enabled) {
00297         if (stage->flags & STAGE_COLOR)  /* explicit */
00298             VectorCopy(stage->color, color);
00299 
00300         else if (stage->flags & STAGE_ENVMAP)  /* implied */
00301             VectorCopy(surf->color, color);
00302 
00303         else  /* default */
00304             VectorSet(color, 1.0, 1.0, 1.0);
00305 
00306         /* modulate the alpha value for pulses */
00307         if (stage->flags & STAGE_PULSE) {
00308             /* disable fog, since it also sets alpha */
00309             R_EnableFog(qfalse);
00310             color[3] = stage->pulse.dhz;
00311         } else {
00312             /* ensure fog is available */
00313             R_EnableFog(qtrue);
00314             color[3] = 1.0;
00315         }
00316 
00317         R_Color(color);
00318     }
00319 }
00320 
00325 static void R_DrawSurfaceStage (mBspSurface_t *surf, materialStage_t *stage)
00326 {
00327     int i;
00328 
00329     if (surf->numedges >= MAX_GL_ARRAY_LENGTH)
00330         Com_Error(ERR_DROP, "R_DrawMaterialSurface: Exceeded MAX_GL_ARRAY_LENGTH\n");
00331 
00332     for (i = 0; i < surf->numedges; i++) {
00333         const float *v = &r_mapTiles[surf->tile]->bsp.verts[surf->index * 3 + i * 3];
00334         const float *st = &r_mapTiles[surf->tile]->bsp.texcoords[surf->index * 2 + i * 2];
00335 
00336         R_StageVertex(surf, stage, v, &r_state.vertex_array_3d[i * 3]);
00337 
00338         R_StageTexCoord(stage, v, st, &texunit_diffuse.texcoord_array[i * 2]);
00339 
00340         if (texunit_lightmap.enabled) {
00341             st = &r_mapTiles[surf->tile]->bsp.lmtexcoords[surf->index * 2 + i * 2];
00342             texunit_lightmap.texcoord_array[i * 2 + 0] = st[0];
00343             texunit_lightmap.texcoord_array[i * 2 + 1] = st[1];
00344         }
00345 
00346         if (r_state.color_array_enabled)
00347             R_StageColor(stage, v, &r_state.color_array[i * 4]);
00348 
00349         /* normals and tangents */
00350         if (r_state.lighting_enabled) {
00351             const float *n = &r_mapTiles[surf->tile]->bsp.normals[surf->index * 3 + i * 3];
00352             memcpy(&r_state.normal_array[i * 3], n, sizeof(vec3_t));
00353 
00354             if (r_state.bumpmap_enabled) {
00355                 const float *t = &r_mapTiles[surf->tile]->bsp.tangents[surf->index * 4 + i * 4];
00356                 memcpy(&r_state.tangent_array[i * 4], t, sizeof(vec3_t));
00357             }
00358         }
00359     }
00360 
00361     glDrawArrays(GL_POLYGON, 0, i);
00362 
00363     R_CheckError();
00364 }
00365 
00372 void R_DrawMaterialSurfaces (mBspSurfaces_t *surfs)
00373 {
00374     int i;
00375 
00376     if (!r_materials->integer || r_wire->integer)
00377         return;
00378 
00379     if (!surfs->count)
00380         return;
00381 
00382     assert(r_state.blend_enabled);
00383 
00384     R_EnableTexture(&texunit_lightmap, qtrue);
00385 
00386     R_EnableLighting(r_state.world_program, qtrue);
00387 
00389     R_EnableDynamicLights(NULL, qfalse);
00390 
00391     R_EnableColorArray(qtrue);
00392 
00393     R_ResetArrayState();
00394 
00395     R_EnableColorArray(qfalse);
00396 
00397     R_EnableLighting(NULL, qfalse);
00398 
00399     R_EnableTexture(&texunit_lightmap, qfalse);
00400 
00401     glEnable(GL_POLYGON_OFFSET_LINE);
00402     glPolygonOffset(-1.f, -1.f);
00403 
00404     glMatrixMode(GL_TEXTURE);  /* some stages will manipulate texcoords */
00405 
00406     for (i = 0; i < surfs->count; i++) {
00407         materialStage_t *s;
00408         mBspSurface_t *surf = surfs->surfaces[i];
00409         material_t *m = &surf->texinfo->image->material;
00410         int j = -1;
00411 
00412         if (surf->frame != r_locals.frame)
00413             continue;
00414 
00415         R_UpdateMaterial(m);
00416 
00417         for (s = m->stages; s; s = s->next, j--) {
00418             if (!(s->flags & STAGE_RENDER))
00419                 continue;
00420 
00421             R_SetSurfaceStageState(surf, s);
00422 
00423             R_DrawSurfaceStage(surf, s);
00424         }
00425     }
00426 
00427     R_Color(NULL);
00428 
00429     /* polygon offset parameters */
00430     glPolygonOffset(0.0, 0.0);
00431     glDisable(GL_POLYGON_OFFSET_LINE);
00432 
00433     glLoadIdentity();
00434     glMatrixMode(GL_MODELVIEW);
00435 
00436     R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00437 
00438     R_EnableFog(qtrue);
00439 
00440     R_EnableColorArray(qfalse);
00441 
00442     R_EnableTexture(&texunit_lightmap, qfalse);
00443 
00444     R_EnableBumpmap(NULL, qfalse);
00445 
00446     R_EnableGlowMap(NULL, qfalse);
00447 
00448     R_EnableLighting(NULL, qfalse);
00449 
00450     R_Color(NULL);
00451 }
00452 
00456 static GLenum R_ConstByName (const char *c)
00457 {
00458     if (!strcmp(c, "GL_ONE"))
00459         return GL_ONE;
00460     if (!strcmp(c, "GL_ZERO"))
00461         return GL_ZERO;
00462     if (!strcmp(c, "GL_SRC_ALPHA"))
00463         return GL_SRC_ALPHA;
00464     if (!strcmp(c, "GL_ONE_MINUS_SRC_ALPHA"))
00465         return GL_ONE_MINUS_SRC_ALPHA;
00466     if (!strcmp(c, "GL_SRC_COLOR"))
00467         return GL_SRC_COLOR;
00468     if (!strcmp(c, "GL_DST_COLOR"))
00469         return GL_DST_COLOR;
00470     if (!strcmp(c, "GL_ONE_MINUS_SRC_COLOR"))
00471         return GL_ONE_MINUS_SRC_COLOR;
00472     if (!strcmp(c, "GL_ONE_MINUS_DST_COLOR"))
00473         return GL_ONE_MINUS_DST_COLOR;
00474 
00475     Com_Printf("R_ConstByName: Failed to resolve: %s\n", c);
00476     return GL_ZERO;
00477 }
00478 
00479 static void R_CreateMaterialData_ (model_t *mod)
00480 {
00481     int i;
00482 
00483     for (i = 0; i < mod->bsp.numsurfaces; i++) {
00484         mBspSurface_t *surf = &mod->bsp.surfaces[i];
00485         /* create flare */
00486         R_CreateSurfaceFlare(surf);
00487     }
00488 }
00489 
00490 static void R_CreateMaterialData (void)
00491 {
00492     int i;
00493 
00494     for (i = 0; i < r_numMapTiles; i++)
00495         R_CreateMaterialData_(r_mapTiles[i]);
00496 
00497     for (i = 0; i < r_numModelsInline; i++)
00498         R_CreateMaterialData_(&r_modelsInline[i]);
00499 }
00500 
00501 static int R_LoadAnimImages (materialStage_t *s)
00502 {
00503     char name[MAX_QPATH];
00504     int i, j;
00505 
00506     if (!s->image) {
00507         Com_Printf("R_LoadAnimImages: Texture not defined in anim stage.\n");
00508         return -1;
00509     }
00510 
00511     Q_strncpyz(name, s->image->name, sizeof(name));
00512     j = strlen(name);
00513 
00514     if (name[j - 1] != '0') {
00515         Com_Printf("R_LoadAnimImages: Texture name does not end in 0: %s\n", name);
00516         return -1;
00517     }
00518 
00519     /* the first image was already loaded by the stage parse, so just copy
00520      * the pointer into the images array */
00521 
00522     s->anim.images[0] = s->image;
00523     name[j - 1] = 0;
00524 
00525     /* now load the rest */
00526     for (i = 1; i < s->anim.num_frames; i++) {
00527         const char *c = va("%s%d", name, i);
00528         image_t *image = R_FindImage(c, it_material);
00529         s->anim.images[i] = image;
00530         if (image == r_noTexture) {
00531             Com_Printf("R_LoadAnimImages: Failed to resolve texture: %s\n", c);
00532             return -1;
00533         }
00534         if (s->flags & STAGE_GLOWMAPLINK) {
00535             if (image->glowmap)
00536                 Com_Printf("R_LoadAnimImages: overriding already existing glowmap for %s\n", image->name);
00537             image->glowmap = image;
00538         }
00539     }
00540 
00541     return 0;
00542 }
00543 
00548 static int R_ParseStage (materialStage_t *s, const char **buffer)
00549 {
00550     int i;
00551 
00552     while (qtrue) {
00553         const char *c = Com_Parse(buffer);
00554 
00555         if (c[0] == '\0')
00556             break;
00557 
00558         if (!strcmp(c, "glowscale")) {
00559             s->glowscale = atof(Com_Parse(buffer));
00560             if (s->glowscale < 0.0) {
00561                 Com_Printf("R_LoadMaterials: Invalid glowscale value for %s\n", c);
00562                 s->glowscale = DEFAULT_GLOWSCALE;
00563             }
00564             continue;
00565         }
00566 
00567         if (!strcmp(c, "texture")) {
00568             c = Com_Parse(buffer);
00569             s->image = R_FindImage(va("textures/%s", c), it_material);
00570 
00571             if (s->image == r_noTexture) {
00572                 Com_Printf("R_ParseStage: Failed to resolve texture: %s\n", c);
00573                 return -1;
00574             }
00575 
00576             s->flags |= STAGE_TEXTURE;
00577             continue;
00578         }
00579 
00580         if (!strcmp(c, "envmap")) {
00581             c = Com_Parse(buffer);
00582             i = atoi(c);
00583 
00584             if (i > -1 && i < MAX_ENVMAPTEXTURES)
00585                 s->image = r_envmaptextures[i];
00586             else
00587                 s->image = R_FindImage(va("pics/envmaps/%s", c), it_material);
00588 
00589             if (s->image == r_noTexture) {
00590                 Com_Printf("R_ParseStage: Failed to resolve envmap: %s\n", c);
00591                 return -1;
00592             }
00593 
00594             s->flags |= STAGE_ENVMAP;
00595             continue;
00596         }
00597 
00598         if (!strcmp(c, "blend")) {
00599             c = Com_Parse(buffer);
00600             s->blend.src = R_ConstByName(c);
00601 
00602             if (s->blend.src == -1) {
00603                 Com_Printf("R_ParseStage: Failed to resolve blend src: %s\n", c);
00604                 return -1;
00605             }
00606 
00607             c = Com_Parse(buffer);
00608             s->blend.dest = R_ConstByName(c);
00609 
00610             if (s->blend.dest == -1) {
00611                 Com_Printf("R_ParseStage: Failed to resolve blend dest: %s\n", c);
00612                 return -1;
00613             }
00614 
00615             s->flags |= STAGE_BLEND;
00616             continue;
00617         }
00618 
00619         if (!strcmp(c, "color")) {
00620             for (i = 0; i < 3; i++) {
00621                 c = Com_Parse(buffer);
00622                 s->color[i] = atof(c);
00623 
00624                 if (s->color[i] < 0.0 || s->color[i] > 1.0) {
00625                     Com_Printf("R_ParseStage: Failed to resolve color: %s\n", c);
00626                     return -1;
00627                 }
00628             }
00629 
00630             s->flags |= STAGE_COLOR;
00631             continue;
00632         }
00633 
00634         if (!strcmp(c, "pulse")) {
00635             c = Com_Parse(buffer);
00636             s->pulse.hz = atof(c);
00637 
00638             if (s->pulse.hz < 0.0) {
00639                 Com_Printf("R_ParseStage: Failed to resolve frequency: %s\n", c);
00640                 return -1;
00641             }
00642 
00643             s->flags |= STAGE_PULSE;
00644             continue;
00645         }
00646 
00647         if (!strcmp(c, "stretch")) {
00648             c = Com_Parse(buffer);
00649             s->stretch.amp = atof(c);
00650 
00651             if (s->stretch.amp < 0.0) {
00652                 Com_Printf("R_ParseStage: Failed to resolve amplitude: %s\n", c);
00653                 return -1;
00654             }
00655 
00656             c = Com_Parse(buffer);
00657             s->stretch.hz = atof(c);
00658 
00659             if (s->stretch.hz < 0.0) {
00660                 Com_Printf("R_ParseStage: Failed to resolve frequency: %s\n", c);
00661                 return -1;
00662             }
00663 
00664             s->flags |= STAGE_STRETCH;
00665             continue;
00666         }
00667 
00668         if (!strcmp(c, "rotate")) {
00669             c = Com_Parse(buffer);
00670             s->rotate.hz = atof(c);
00671 
00672             if (s->rotate.hz < 0.0) {
00673                 Com_Printf("R_ParseStage: Failed to resolve rotate: %s\n", c);
00674                 return -1;
00675             }
00676 
00677             s->flags |= STAGE_ROTATE;
00678             continue;
00679         }
00680 
00681         if (!strcmp(c, "scroll.s")) {
00682             c = Com_Parse(buffer);
00683             s->scroll.s = atof(c);
00684 
00685             s->flags |= STAGE_SCROLL_S;
00686             continue;
00687         }
00688 
00689         if (!strcmp(c, "scroll.t")) {
00690             c = Com_Parse(buffer);
00691             s->scroll.t = atof(c);
00692 
00693             s->flags |= STAGE_SCROLL_T;
00694             continue;
00695         }
00696 
00697         if (!strcmp(c, "scale.s")) {
00698             c = Com_Parse(buffer);
00699             s->scale.s = atof(c);
00700 
00701             s->flags |= STAGE_SCALE_S;
00702             continue;
00703         }
00704 
00705         if (!strcmp(c, "scale.t")) {
00706             c = Com_Parse(buffer);
00707             s->scale.t = atof(c);
00708 
00709             s->flags |= STAGE_SCALE_T;
00710             continue;
00711         }
00712 
00713         if (!strcmp(c, "terrain")) {
00714             c = Com_Parse(buffer);
00715             s->terrain.floor = atof(c);
00716 
00717             c = Com_Parse(buffer);
00718             s->terrain.ceil = atof(c);
00719             if (s->terrain.ceil < s->terrain.floor) {
00720                 Com_Printf("R_ParseStage: Inverted terrain ceiling and floor "
00721                     "values for %s\n", (s->image ? s->image->name : "NULL"));
00722                 return -1;
00723             }
00724 
00725             s->terrain.height = s->terrain.ceil - s->terrain.floor;
00726 
00727             if (s->terrain.height == 0.0) {
00728                 Com_Printf("R_ParseStage: Zero height terrain specified for %s\n",
00729                     (s->image ? s->image->name : "NULL"));
00730                 return -1;
00731             }
00732 
00733             s->flags |= STAGE_TERRAIN;
00734             continue;
00735         }
00736 
00737         if (!strcmp(c, "tape")) {
00738             c = Com_Parse(buffer);
00739             s->tape.center = atof(c);
00740 
00741             /* how much downwards? */
00742             c = Com_Parse(buffer);
00743             s->tape.floor = atof(c);
00744 
00745             /* how much upwards? */
00746             c = Com_Parse(buffer);
00747             s->tape.ceil = atof(c);
00748 
00749             s->tape.min = s->tape.center - s->tape.floor;
00750             s->tape.max = s->tape.center + s->tape.ceil;
00751             s->tape.height = s->tape.floor + s->tape.ceil;
00752 
00753             if (s->tape.height == 0.0) {
00754                 Com_Printf("R_ParseStage: Zero height tape specified for %s\n",
00755                     (s->image ? s->image->name : "NULL"));
00756                 return -1;
00757             }
00758 
00759             s->flags |= STAGE_TAPE;
00760             continue;
00761         }
00762 
00763         if (!strcmp(c, "dirtmap")) {
00764             c = Com_Parse(buffer);
00765             s->dirt.intensity = atof(c);
00766             if (s->dirt.intensity <= 0.0 || s->dirt.intensity > 1.0) {
00767                 Com_Printf("R_ParseStage: Invalid dirtmap intensity for %s\n",
00768                     (s->image ? s->image->name : "NULL"));
00769                 return -1;
00770             }
00771             s->flags |= STAGE_DIRTMAP;
00772             continue;
00773         }
00774 
00775         if (!strncmp(c, "anim", 4)) {
00776             switch (c[4]) {
00777             case 'a':
00778                 s->anim.type = ANIM_ALTERNATE;
00779                 break;
00780             case 'b':
00781                 s->anim.type = ANIM_BACKWARDS;
00782                 break;
00783             case 'r':
00784                 s->anim.type = ANIM_RANDOM;
00785                 break;
00786             case 'f':
00787                 s->anim.type = ANIM_RANDOMFORCE;
00788                 break;
00789             default:
00790                 s->anim.type = ANIM_NORMAL;
00791                 break;
00792             }
00793             c = Com_Parse(buffer);
00794             s->anim.num_frames = atoi(c);
00795 
00796             if (s->anim.num_frames < 1 || s->anim.num_frames > MAX_ANIM_FRAMES) {
00797                 Com_Printf("R_ParseStage: Invalid number of anim frames for %s (max is %i)\n",
00798                         (s->image ? s->image->name : "NULL"), MAX_ANIM_FRAMES);
00799                 return -1;
00800             }
00801 
00802             c = Com_Parse(buffer);
00803             s->anim.fps = atof(c);
00804 
00805             if (s->anim.fps <= 0) {
00806                 Com_Printf("R_ParseStage: Invalid anim fps for %s\n",
00807                         (s->image ? s->image->name : "NULL"));
00808                 return -1;
00809             }
00810 
00811             /* the frame images are loaded once the stage is parsed completely */
00812 
00813             s->flags |= STAGE_ANIM;
00814             continue;
00815         }
00816 
00817         if (!strcmp(c, "glowmaplink")) {
00818             s->flags |= STAGE_GLOWMAPLINK;
00819             continue;
00820         }
00821 
00822         if (!strcmp(c, "lightmap")) {
00823             s->flags |= STAGE_LIGHTMAP;
00824             continue;
00825         }
00826 
00827         if (!strcmp(c, "flare")) {
00828             c = Com_Parse(buffer);
00829             i = atoi(c);
00830 
00831             if (i > -1 && i < NUM_FLARETEXTURES)
00832                 s->image = r_flaretextures[i];
00833             else
00834                 s->image = R_FindImage(va("pics/flares/%s", c), it_material);
00835 
00836             if (s->image == r_noTexture) {
00837                 Com_Printf("R_ParseStage: Failed to resolve flare: %s\n", c);
00838                 return -1;
00839             }
00840 
00841             s->flags |= STAGE_FLARE;
00842             continue;
00843         }
00844 
00845         if (*c == '}') {
00846             Com_DPrintf(DEBUG_RENDERER, "Parsed stage\n"
00847                     "  flags: %d\n"
00848                     "  image: %s\n"
00849                     "  blend: %d %d\n"
00850                     "  color: %3f %3f %3f\n"
00851                     "  pulse: %3f\n"
00852                     "  stretch: %3f %3f\n"
00853                     "  rotate: %3f\n"
00854                     "  scroll.s: %3f\n"
00855                     "  scroll.t: %3f\n"
00856                     "  scale.s: %3f\n"
00857                     "  scale.t: %3f\n"
00858                     "  terrain.floor: %5f\n"
00859                     "  terrain.ceil: %5f\n"
00860                     "  anim.num_frames: %d\n"
00861                     "  anim.fps: %3f\n",
00862                     s->flags, (s->image ? s->image->name : "NULL"),
00863                     s->blend.src, s->blend.dest,
00864                     s->color[0], s->color[1], s->color[2],
00865                     s->pulse.hz, s->stretch.amp, s->stretch.hz,
00866                     s->rotate.hz, s->scroll.s, s->scroll.t,
00867                     s->scale.s, s->scale.t, s->terrain.floor, s->terrain.ceil,
00868                     s->anim.num_frames, s->anim.fps);
00869 
00870             /* a texture or envmap means render it */
00871             if (s->flags & (STAGE_TEXTURE | STAGE_ENVMAP))
00872                 s->flags |= STAGE_RENDER;
00873 
00874             if (s->flags & (STAGE_TERRAIN | STAGE_DIRTMAP))
00875                 s->flags |= STAGE_LIGHTING;
00876 
00877             return 0;
00878         }
00879 
00880         Com_Printf("Invalid token: '%s'\n", c);
00881     }
00882 
00883     Com_Printf("R_ParseStage: Malformed stage\n");
00884     return -1;
00885 }
00886 
00891 void R_LoadMaterials (const char *map)
00892 {
00893     char path[MAX_QPATH];
00894     byte *fileBuffer;
00895     const char *buffer;
00896     qboolean inmaterial;
00897     image_t *image;
00898     material_t *m;
00899     materialStage_t *s, *ss;
00900 
00901     /* clear previously loaded materials */
00902     R_ImageClearMaterials();
00903 
00904     if (map[0] == '+' || map[0] == '-')
00905         map++;
00906     else if (map[0] == '-')
00907         return;
00908 
00909     /* load the materials file for parsing */
00910     Com_sprintf(path, sizeof(path), "materials/%s.mat", Com_SkipPath(map));
00911 
00912     if (FS_LoadFile(path, &fileBuffer) < 1) {
00913         Com_DPrintf(DEBUG_RENDERER, "Couldn't load %s\n", path);
00914         return;
00915     } else {
00916         Com_Printf("load material file: '%s'\n", path);
00917     }
00918 
00919     buffer = (const char *)fileBuffer;
00920 
00921     inmaterial = qfalse;
00922     image = NULL;
00923     m = NULL;
00924 
00925     while (qtrue) {
00926         const char *c = Com_Parse(&buffer);
00927 
00928         if (c[0] == '\0')
00929             break;
00930 
00931         if (*c == '{' && !inmaterial) {
00932             inmaterial = qtrue;
00933             continue;
00934         }
00935 
00936         if (!strcmp(c, "material")) {
00937             c = Com_Parse(&buffer);
00938             image = R_GetImage(va("textures/%s", c));
00939             if (image == NULL)
00940                 Com_DPrintf(DEBUG_RENDERER, "R_LoadMaterials: skip texture: %s - not used in the map\n", c);
00941 
00942             continue;
00943         }
00944 
00945         if (!image)
00946             continue;
00947 
00948         m = &image->material;
00949 
00950         if (!strcmp(c, "normalmap")){
00951             c = Com_Parse(&buffer);
00952             image->normalmap = R_FindImage(va("textures/%s", c), it_normalmap);
00953 
00954             if (image->normalmap == r_noTexture){
00955                 Com_Printf("R_LoadMaterials: Failed to resolve normalmap: %s\n", c);
00956                 image->normalmap = NULL;
00957             }
00958         }
00959 
00960         if (!strcmp(c, "glowmap")){
00961             c = Com_Parse(&buffer);
00962             image->glowmap = R_FindImage(va("textures/%s", c), it_glowmap);
00963 
00964             if (image->glowmap == r_noTexture){
00965                 Com_Printf("R_LoadMaterials: Failed to resolve glowmap: %s\n", c);
00966                 image->glowmap = NULL;
00967             }
00968         }
00969 
00970         if (!strcmp(c, "bump")) {
00971             m->bump = atof(Com_Parse(&buffer));
00972             if (m->bump < 0.0) {
00973                 Com_Printf("R_LoadMaterials: Invalid bump value for %s\n", image->name);
00974                 m->bump = DEFAULT_BUMP;
00975             }
00976         }
00977 
00978         if (!strcmp(c, "parallax")) {
00979             m->parallax = atof(Com_Parse(&buffer));
00980             if (m->parallax < 0.0) {
00981                 Com_Printf("R_LoadMaterials: Invalid parallax value for %s\n", image->name);
00982                 m->parallax = DEFAULT_PARALLAX;
00983             }
00984         }
00985 
00986         if (!strcmp(c, "hardness")) {
00987             m->hardness = atof(Com_Parse(&buffer));
00988             if (m->hardness < 0.0) {
00989                 Com_Printf("R_LoadMaterials: Invalid hardness value for %s\n", image->name);
00990                 m->hardness = DEFAULT_HARDNESS;
00991             }
00992         }
00993 
00994         if (!strcmp(c, "specular")) {
00995             m->specular = atof(Com_Parse(&buffer));
00996             if (m->specular < 0.0) {
00997                 Com_Printf("R_LoadMaterials: Invalid specular value for %s\n", image->name);
00998                 m->specular = DEFAULT_SPECULAR;
00999             }
01000         }
01001 
01002         if (!strcmp(c, "glowscale")) {
01003             m->glowscale = atof(Com_Parse(&buffer));
01004             if (m->glowscale < 0.0) {
01005                 Com_Printf("R_LoadMaterials: Invalid glowscale value for %s\n", image->name);
01006                 m->glowscale = DEFAULT_GLOWSCALE;
01007             }
01008         }
01009 
01010         if (*c == '{' && inmaterial) {
01011             s = (materialStage_t *)Mem_PoolAlloc(sizeof(*s), vid_imagePool, 0);
01012             s->glowscale = DEFAULT_GLOWSCALE;
01013 
01014             if (R_ParseStage(s, &buffer) == -1) {
01015                 Mem_Free(s);
01016                 continue;
01017             }
01018 
01019             /* load animation frame images */
01020             if (s->flags & STAGE_ANIM) {
01021                 if (R_LoadAnimImages(s) == -1) {
01022                     Mem_Free(s);
01023                     continue;
01024                 }
01025             }
01026 
01027 
01028             /* append the stage to the chain */
01029             if (!m->stages)
01030                 m->stages = s;
01031             else {
01032                 ss = m->stages;
01033                 while (ss->next)
01034                     ss = ss->next;
01035                 ss->next = s;
01036             }
01037 
01038             m->flags |= s->flags;
01039             m->num_stages++;
01040             continue;
01041         }
01042 
01043         if (*c == '}' && inmaterial) {
01044             Com_DPrintf(DEBUG_RENDERER, "Parsed material %s with %d stages\n", image->name, m->num_stages);
01045             inmaterial = qfalse;
01046             image = NULL;
01047             /* multiply stage glowscale values by material glowscale */
01048             ss = m->stages;
01049             while (ss) {
01050                 ss->glowscale *= m->glowscale;
01051                 ss = ss->next;
01052             }
01053         }
01054     }
01055 
01056     FS_FreeFile(fileBuffer);
01057 
01058     R_CreateMaterialData();
01059 }

Generated by  doxygen 1.6.2