00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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) {
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
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
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) {
00200 VectorSubtract(v, refdef.viewOrigin, tmp);
00201 VectorNormalize(tmp);
00202 Vector2Copy(tmp, out);
00203 } else {
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)
00223 VectorCopy(stage->color, color);
00224 else
00225 VectorSet(color, 1.0, 1.0, 1.0);
00226
00227
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
00252 const int index = (int)VectorLength(v) % lengthof(dirtmap);
00253
00254 if (stage->flags & STAGE_COLOR)
00255 VectorCopy(stage->color, color);
00256 else
00257 VectorSet(color, 1.0, 1.0, 1.0);
00258 color[3] = dirtmap[index] * stage->dirt.intensity;
00259 } else {
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
00273 R_BindTexture(stage->image->texnum);
00274
00275
00276 R_StageLighting(surf, stage);
00277
00278 R_StageGlow(stage);
00279
00280
00281 R_StageTextureMatrix(surf, stage);
00282
00283
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
00290 if (stage->flags & (STAGE_TAPE | STAGE_TERRAIN | STAGE_DIRTMAP))
00291 R_EnableColorArray(qtrue);
00292 else
00293 R_EnableColorArray(qfalse);
00294
00295
00296 if (!r_state.color_array_enabled) {
00297 if (stage->flags & STAGE_COLOR)
00298 VectorCopy(stage->color, color);
00299
00300 else if (stage->flags & STAGE_ENVMAP)
00301 VectorCopy(surf->color, color);
00302
00303 else
00304 VectorSet(color, 1.0, 1.0, 1.0);
00305
00306
00307 if (stage->flags & STAGE_PULSE) {
00308
00309 R_EnableFog(qfalse);
00310 color[3] = stage->pulse.dhz;
00311 } else {
00312
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
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);
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
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
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
00520
00521
00522 s->anim.images[0] = s->image;
00523 name[j - 1] = 0;
00524
00525
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
00742 c = Com_Parse(buffer);
00743 s->tape.floor = atof(c);
00744
00745
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
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
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
00902 R_ImageClearMaterials();
00903
00904 if (map[0] == '+' || map[0] == '-')
00905 map++;
00906 else if (map[0] == '-')
00907 return;
00908
00909
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
01020 if (s->flags & STAGE_ANIM) {
01021 if (R_LoadAnimImages(s) == -1) {
01022 Mem_Free(s);
01023 continue;
01024 }
01025 }
01026
01027
01028
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
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 }