UFO: Alien Invasion
Loading...
Searching...
No Matches
r_material.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 1997-2001 Id Software, Inc.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24*/
25
26#include "r_local.h"
27#include "r_error.h"
28#include "r_lightmap.h"
29#include "../../shared/parse.h"
30
32
35
36#define UPDATE_THRESHOLD 0.02
41{
42 if (refdef.time - m->time < UPDATE_THRESHOLD)
43 return;
44
45 m->time = refdef.time;
46
47 for (materialStage_t* s = m->stages; s; s = s->next) {
48 if (s->flags & STAGE_PULSE) {
49 float phase = refdef.time * s->pulse.hz;
50 float moduloPhase = phase - floor(phase); /* extract fractional part of phase */
51
52 if (moduloPhase < s->pulse.dutycycle) {
53 moduloPhase /= s->pulse.dutycycle;
54 s->pulse.dhz = (1.0 - cos(moduloPhase * (2 * M_PI))) / 2.0;
55 } else {
56 s->pulse.dhz = 0;
57 }
58 }
59
60 if (s->flags & STAGE_STRETCH) {
61 s->stretch.dhz = (1.0 - cos(refdef.time * s->stretch.hz * (2 * M_PI)) ) / 2.0;
62 s->stretch.damp = 1.5 - s->stretch.dhz * s->stretch.amp;
63 }
64
65 if (s->flags & STAGE_ROTATE)
66 s->rotate.deg = refdef.time * s->rotate.hz * 360.0;
67
68 if (s->flags & STAGE_SCROLL_S)
69 s->scroll.ds = s->scroll.s * refdef.time;
70
71 if (s->flags & STAGE_SCROLL_T)
72 s->scroll.dt = s->scroll.t * refdef.time;
73
74 if (s->flags & STAGE_ANIM) {
75 if (refdef.time >= s->anim.dtime) { /* change frames */
76 int frame;
77 s->anim.dtime = refdef.time + (1.0 / s->anim.fps);
78 s->anim.dframe++;
79 switch (s->anim.type) {
80 case ANIM_NORMAL:
81 frame = s->anim.dframe % s->anim.num_frames;
82 break;
83 case ANIM_ALTERNATE:
84 frame = abs(s->anim.dframe % (s->anim.num_frames + 1) - (s->anim.num_frames / 2));
85 break;
86 case ANIM_BACKWARDS:
87 frame = s->anim.num_frames - 1;
88 frame -= s->anim.dframe % s->anim.num_frames;
89 break;
90 case ANIM_RANDOM:
91 frame = rand() % s->anim.num_frames;
92 break;
94 frame = rand() % s->anim.num_frames;
95 if (s->image == s->anim.images[frame])
96 frame = (frame + 1) % s->anim.num_frames;
97 break;
98 default:
99 continue;
100 }
101 assert(frame >= 0);
102 assert(frame < s->anim.num_frames);
103 s->image = s->anim.images[frame];
104 }
105 }
106 }
107}
108
109static void R_StageGlow (const materialStage_t* stage)
110{
111 image_t* glowmap;
112
113 if (stage->flags & STAGE_GLOWMAPLINK)
114 glowmap = stage->image;
115 else
116 glowmap = stage->image->glowmap;
117
118 if (glowmap) {
119 R_EnableGlowMap(glowmap);
120 if (r_state.glowmap_enabled)
121 R_ProgramParameter1f("GLOWSCALE", stage->glowscale);
122 } else {
123 R_EnableGlowMap(nullptr);
124 }
125}
126
130static void R_StageLighting (const mBspSurface_t* surf, const materialStage_t* stage)
131{
132 /* if the surface has a lightmap, and the stage specifies lighting.. */
133 if ((surf->flags & MSURF_LIGHTMAP) &&
134 (stage->flags & (STAGE_LIGHTMAP | STAGE_LIGHTING))) {
137
138 /* hardware lighting */
140 if (r_materials->integer > 1) {
141 if ((stage->flags & STAGE_LIGHTING)) {
142 R_EnableLighting(r_state.world_program, true);
143 R_SetSurfaceBumpMappingParameters(surf, stage->image->normalmap, stage->image->specularmap);
144 } else {
145 R_SetSurfaceBumpMappingParameters(surf, nullptr, nullptr);
146 R_EnableLighting(nullptr, false);
147 }
148 }
149 } else {
150 if (!r_state.lighting_enabled)
151 return;
152 R_EnableLighting(nullptr, false);
153
155 }
156}
157
162static inline void R_StageVertex (const mBspSurface_t* surf, const materialStage_t* stage, const vec3_t in, vec3_t out)
163{
164 VectorCopy(in, out);
165}
166
171static inline void R_StageTextureMatrix (const mBspSurface_t* surf, const materialStage_t* stage)
172{
173 static bool identity = true;
174 float s, t;
175
176 if (!(stage->flags & STAGE_TEXTURE_MATRIX)) {
177 if (!identity)
178 glLoadIdentity();
179
180 identity = true;
181 return;
182 }
183
184 glLoadIdentity();
185
186 s = surf->stcenter[0] / surf->texinfo->image->width;
187 t = surf->stcenter[1] / surf->texinfo->image->height;
188
189 if (stage->flags & STAGE_STRETCH) {
190 glTranslatef(-s, -t, 0.0);
191 glScalef(stage->stretch.damp, stage->stretch.damp, 1.0);
192 glTranslatef(-s, -t, 0.0);
193 }
194
195 if (stage->flags & STAGE_ROTATE) {
196 glTranslatef(-s, -t, 0.0);
197 glRotatef(stage->rotate.deg, 0.0, 0.0, 1.0);
198 glTranslatef(-s, -t, 0.0);
199 }
200
201 if (stage->flags & STAGE_SCALE_S)
202 glScalef(stage->scale.s, 1.0, 1.0);
203
204 if (stage->flags & STAGE_SCALE_T)
205 glScalef(1.0, stage->scale.t, 1.0);
206
207 if (stage->flags & STAGE_SCROLL_S)
208 glTranslatef(stage->scroll.ds, 0.0, 0.0);
209
210 if (stage->flags & STAGE_SCROLL_T)
211 glTranslatef(0.0, stage->scroll.dt, 0.0);
212
213 identity = false;
214}
215
219static void R_StageTexCoord (const materialStage_t* stage, const vec3_t v, const vec2_t in, vec2_t out)
220{
221 if (stage->flags & STAGE_ENVMAP) { /* generate texcoords */
222 vec3_t tmp;
223 VectorSubtract(v, refdef.viewOrigin, tmp);
225 Vector2Copy(tmp, out);
226 } else { /* or use the ones we were given */
227 Vector2Copy(in, out);
228 }
229}
230
232static const float dirtmap[] = {
233 0.6, 0.5, 0.3, 0.4, 0.7, 0.3, 0.0, 0.4,
234 0.5, 0.2, 0.8, 0.5, 0.3, 0.2, 0.5, 0.3
235};
236
240static void R_StageColor (const materialStage_t* stage, const vec3_t v, vec4_t color)
241{
242 if (stage->flags & (STAGE_TERRAIN | STAGE_TAPE)) {
243 float a;
244
245 if (stage->flags & STAGE_COLOR) /* honor stage color */
246 VectorCopy(stage->color, color);
247 else /* or use white */
248 VectorSet(color, 1.0, 1.0, 1.0);
249
250 /* resolve alpha for vert based on z axis height */
251 if (stage->flags & STAGE_TERRAIN) {
252 if (v[2] < stage->terrain.floor)
253 a = 0.0;
254 else if (v[2] > stage->terrain.ceil)
255 a = 1.0;
256 else
257 a = (v[2] - stage->terrain.floor) / stage->terrain.height;
258 } else {
259 if (v[2] < stage->tape.max && v[2] > stage->tape.min) {
260 if (v[2] > stage->tape.center) {
261 const float delta = v[2] - stage->tape.center;
262 a = 1 - (delta / stage->tape.max);
263 } else {
264 const float delta = stage->tape.center - v[2];
265 a = 1 - (delta / stage->tape.min);
266 }
267 } else {
268 a = 0.0;
269 }
270 }
271
272 color[3] = a;
273 } else if (stage->flags & STAGE_DIRTMAP) {
274 /* resolve dirtmap based on vertex position */
275 const vec3_t hash_mult = {1.3, 3.1, 7.3};
276 const int index = ((int) DotProduct(v, hash_mult)) % lengthof(dirtmap);
277
278 if (stage->flags & STAGE_COLOR) /* honor stage color */
279 VectorCopy(stage->color, color);
280 else /* or use white */
281 VectorSet(color, 1.0, 1.0, 1.0);
282 color[3] = dirtmap[index] * stage->dirt.intensity;
283 } else { /* simply use white */
284 Vector4Set(color, 1.0, 1.0, 1.0, 1.0);
285 }
286}
287
292static void R_SetSurfaceStageState (const mBspSurface_t* surf, const materialStage_t* stage)
293{
294 /* bind the texture */
295 R_BindTexture(stage->image->texnum);
296
297 /* and optionally the lightmap */
298 R_StageLighting(surf, stage);
299
300 R_StageGlow(stage);
301
302 /* load the texture matrix for rotations, stretches, etc.. */
303 R_StageTextureMatrix(surf, stage);
304
305 /* set the blend function, ensuring a good default */
306 if (stage->flags & STAGE_BLEND)
307 R_BlendFunc(stage->blend.src, stage->blend.dest);
308 else
309 R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
310
311 /* for terrain, enable the color array */
312 if (stage->flags & (STAGE_TAPE | STAGE_TERRAIN | STAGE_DIRTMAP))
313 R_EnableColorArray(true);
314 else
315 R_EnableColorArray(false);
316
317 /* when not using the color array, resolve the shade color */
318 if (!r_state.color_array_enabled) {
319 vec4_t color;
320
321 if (stage->flags & STAGE_COLOR) /* explicit */
322 VectorCopy(stage->color, color);
323
324 else if (stage->flags & STAGE_ENVMAP) /* implied */
325 VectorCopy(surf->lightColor, color);
326
327 else /* default */
328 VectorSet(color, 1.0, 1.0, 1.0);
329
330 /* modulate the alpha value for pulses */
331 if (stage->flags & STAGE_PULSE) {
332 /* disable fog, since it also sets alpha */
333 R_EnableFog(false);
334 color[3] = stage->pulse.dhz;
335 } else {
336 /* ensure fog is available */
337 R_EnableFog(true);
338 color[3] = 1.0;
339 }
340
341 R_Color(color);
342 }
343}
344
350{
351 int i;
352
356
357 for (i = 0; i < surf->numedges; i++) {
358 const float* v = &r_mapTiles[surf->tile]->bsp.verts[surf->index * 3 + i * 3];
359 const float* st = &r_mapTiles[surf->tile]->bsp.texcoords[surf->index * 2 + i * 2];
360
361 R_StageVertex(surf, stage, v, &r_state.vertex_array_3d[i * 3]);
362
363 R_StageTexCoord(stage, v, st, &texunit_diffuse.texcoord_array[i * 2]);
364
365 if (texunit_lightmap.enabled) {
366 st = &r_mapTiles[surf->tile]->bsp.lmtexcoords[surf->index * 2 + i * 2];
367 texunit_lightmap.texcoord_array[i * 2 + 0] = st[0];
368 texunit_lightmap.texcoord_array[i * 2 + 1] = st[1];
369 }
370
371 if (r_state.color_array_enabled)
372 R_StageColor(stage, v, &r_state.color_array[i * 4]);
373
374 /* normals and tangents */
375 if (r_state.lighting_enabled) {
376 const float* n = &r_mapTiles[surf->tile]->bsp.normals[surf->index * 3 + i * 3];
377 memcpy(&r_state.normal_array[i * 3], n, sizeof(vec3_t));
378
379 if (r_state.active_normalmap) {
380 const float* t = &r_mapTiles[surf->tile]->bsp.tangents[surf->index * 4 + i * 4];
381 memcpy(&r_state.tangent_array[i * 4], t, sizeof(vec3_t));
382 }
383 }
384 }
385
386 glDrawArrays(GL_TRIANGLE_FAN, 0, i);
387
388 refdef.batchCount++;
389
390 R_CheckError();
391}
392
400{
401 if (!r_materials->integer || r_wire->integer)
402 return;
403
404 if (!surfs->count)
405 return;
406
407 assert(r_state.blend_enabled);
408
410 R_EnableModelLights(nullptr, 0, false, false);
411
412 R_EnableColorArray(true);
413
415
416 R_EnableColorArray(false);
417
418 R_EnableLighting(nullptr, false);
419
421
422#ifndef GL_VERSION_ES_CM_1_0
423 glEnable(GL_POLYGON_OFFSET_FILL);
424#endif
425 glPolygonOffset(-1.f, -1.f);
426
427 glMatrixMode(GL_TEXTURE); /* some stages will manipulate texcoords */
428
429 for (int i = 0; i < surfs->count; i++) {
430 mBspSurface_t* surf = surfs->surfaces[i];
431 material_t* m = &surf->texinfo->image->material;
432 int j = -1;
433
434 if (surf->frame != r_locals.frame)
435 continue;
436
438
439 for (materialStage_t* s = m->stages; s; s = s->next, j--) {
440 if (!(s->flags & STAGE_RENDER))
441 continue;
442
443 R_SetSurfaceStageState(surf, s);
444
445 R_DrawSurfaceStage(surf, s);
446 }
447 }
448
449 R_Color(nullptr);
450
451 /* polygon offset parameters */
452 glPolygonOffset(0.0, 0.0);
453#ifndef GL_VERSION_ES_CM_1_0
454 glDisable(GL_POLYGON_OFFSET_FILL);
455#endif
456
457 glLoadIdentity();
458 glMatrixMode(GL_MODELVIEW);
459
460 R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
461
462 R_EnableFog(true);
463
464 R_EnableColorArray(false);
465
467
468 R_EnableBumpmap(nullptr);
469
470 R_EnableLighting(nullptr, false);
471
472 R_EnableGlowMap(nullptr);
473
474 R_Color(nullptr);
475}
476
480static GLenum R_ConstByName (const char* c)
481{
482 if (Q_streq(c, "GL_ONE"))
483 return GL_ONE;
484 if (Q_streq(c, "GL_ZERO"))
485 return GL_ZERO;
486 if (Q_streq(c, "GL_SRC_ALPHA"))
487 return GL_SRC_ALPHA;
488 if (Q_streq(c, "GL_ONE_MINUS_SRC_ALPHA"))
489 return GL_ONE_MINUS_SRC_ALPHA;
490 if (Q_streq(c, "GL_SRC_COLOR"))
491 return GL_SRC_COLOR;
492 if (Q_streq(c, "GL_DST_COLOR"))
493 return GL_DST_COLOR;
494 if (Q_streq(c, "GL_ONE_MINUS_SRC_COLOR"))
495 return GL_ONE_MINUS_SRC_COLOR;
496 if (Q_streq(c, "GL_ONE_MINUS_DST_COLOR"))
497 return GL_ONE_MINUS_DST_COLOR;
498
499 Com_Printf("R_ConstByName: Failed to resolve: %s\n", c);
500 return GL_ZERO;
501}
502
504{
505 for (int i = 0; i < mod->bsp.numsurfaces; i++) {
506 mBspSurface_t* surf = &mod->bsp.surfaces[i];
507 /* create flare */
509 }
510}
511
512static void R_CreateMaterialData (void)
513{
514 int i;
515
516 for (i = 0; i < r_numMapTiles; i++)
518
519 for (i = 0; i < r_numModelsInline; i++)
521}
522
524{
525 if (!s->image) {
526 Com_Printf("R_LoadAnimImages: Texture not defined in anim stage.\n");
527 return -1;
528 }
529
530 char name[MAX_QPATH];
531 Q_strncpyz(name, s->image->name, sizeof(name));
532 int j = strlen(name);
533
534 if (name[j - 1] != '0') {
535 Com_Printf("R_LoadAnimImages: Texture name does not end in 0: %s\n", name);
536 return -1;
537 }
538
539 /* the first image was already loaded by the stage parse, so just copy
540 * the pointer into the images array */
541
542 s->anim.images[0] = s->image;
543 name[j - 1] = 0;
544
545 /* now load the rest */
546 for (int i = 0; i < s->anim.num_frames; i++) {
547 const char* c = va("%s%d", name, i);
548 image_t* image = R_FindImage(c, it_material);
549 s->anim.images[i] = image;
550 if (image == r_noTexture) {
551 Com_Printf("R_LoadAnimImages: Failed to resolve texture: %s\n", c);
552 return -1;
553 }
554 }
555
556 return 0;
557}
558
563static int R_ParseStage (materialStage_t* s, const char** buffer)
564{
565 int i;
566
567 while (true) {
568 const char* c = Com_Parse(buffer);
569
570 if (c[0] == '\0')
571 break;
572
573 if (Q_streq(c, "glowscale")) {
574 s->glowscale = atof(Com_Parse(buffer));
575 if (s->glowscale < 0.0) {
576 Com_Printf("R_LoadMaterials: Invalid glowscale value for %s\n", c);
577 s->glowscale = defaultMaterial.glowscale;
578 }
579 continue;
580 }
581
582 if (Q_streq(c, "texture")) {
583 c = Com_Parse(buffer);
584 s->image = R_FindImage(va("textures/%s", c), it_material);
585
586 if (s->image == r_noTexture) {
587 Com_Printf("R_ParseStage: Failed to resolve texture: %s\n", c);
588 return -1;
589 }
590
591 s->flags |= STAGE_TEXTURE;
592 continue;
593 }
594
595 if (Q_streq(c, "envmap")) {
596 c = Com_Parse(buffer);
597 i = atoi(c);
598
599 if (i > -1 && i < MAX_ENVMAPTEXTURES)
601 else
602 s->image = R_FindImage(va("pics/envmaps/%s", c), it_material);
603
604 if (s->image == r_noTexture) {
605 Com_Printf("R_ParseStage: Failed to resolve envmap: %s\n", c);
606 return -1;
607 }
608
609 s->flags |= STAGE_ENVMAP;
610 continue;
611 }
612
613 if (Q_streq(c, "blend")) {
614 c = Com_Parse(buffer);
615 s->blend.src = R_ConstByName(c);
616
617 if (s->blend.src == -1) {
618 Com_Printf("R_ParseStage: Failed to resolve blend src: %s\n", c);
619 return -1;
620 }
621
622 c = Com_Parse(buffer);
623 s->blend.dest = R_ConstByName(c);
624
625 if (s->blend.dest == -1) {
626 Com_Printf("R_ParseStage: Failed to resolve blend dest: %s\n", c);
627 return -1;
628 }
629
630 s->flags |= STAGE_BLEND;
631 continue;
632 }
633
634 if (Q_streq(c, "color")) {
635 for (i = 0; i < 3; i++) {
636 c = Com_Parse(buffer);
637 s->color[i] = atof(c);
638
639 if (s->color[i] < 0.0 || s->color[i] > 1.0) {
640 Com_Printf("R_ParseStage: Failed to resolve color: %s\n", c);
641 return -1;
642 }
643 }
644
645 s->flags |= STAGE_COLOR;
646 continue;
647 }
648
649 if (Q_streq(c, "pulse")) {
650 c = Com_Parse(buffer);
651 s->pulse.hz = atof(c);
652 s->pulse.dutycycle = 1.0;
653
654 if (s->pulse.hz < 0.0) {
655 Com_Printf("R_ParseStage: Failed to resolve frequency: %s\n", c);
656 return -1;
657 }
658
659 s->flags |= STAGE_PULSE;
660 continue;
661 }
662
663 if (Q_streq(c, "dutycycle")) {
664 c = Com_Parse(buffer);
665 s->pulse.dutycycle = atof(c);
666
667 if (s->pulse.dutycycle < 0.0 || s->pulse.dutycycle > 1.0) {
668 Com_Printf("R_ParseStage: Failed to resolve pulse duty cycle: %s\n", c);
669 return -1;
670 }
671
672 continue;
673 }
674
675 if (Q_streq(c, "stretch")) {
676 c = Com_Parse(buffer);
677 s->stretch.amp = atof(c);
678
679 if (s->stretch.amp < 0.0) {
680 Com_Printf("R_ParseStage: Failed to resolve amplitude: %s\n", c);
681 return -1;
682 }
683
684 c = Com_Parse(buffer);
685 s->stretch.hz = atof(c);
686
687 if (s->stretch.hz < 0.0) {
688 Com_Printf("R_ParseStage: Failed to resolve frequency: %s\n", c);
689 return -1;
690 }
691
692 s->flags |= STAGE_STRETCH;
693 continue;
694 }
695
696 if (Q_streq(c, "rotate")) {
697 c = Com_Parse(buffer);
698 s->rotate.hz = atof(c);
699
700 if (s->rotate.hz < 0.0) {
701 Com_Printf("R_ParseStage: Failed to resolve rotate: %s\n", c);
702 return -1;
703 }
704
705 s->flags |= STAGE_ROTATE;
706 continue;
707 }
708
709 if (Q_streq(c, "scroll.s")) {
710 c = Com_Parse(buffer);
711 s->scroll.s = atof(c);
712
713 s->flags |= STAGE_SCROLL_S;
714 continue;
715 }
716
717 if (Q_streq(c, "scroll.t")) {
718 c = Com_Parse(buffer);
719 s->scroll.t = atof(c);
720
721 s->flags |= STAGE_SCROLL_T;
722 continue;
723 }
724
725 if (Q_streq(c, "scale.s")) {
726 c = Com_Parse(buffer);
727 s->scale.s = atof(c);
728
729 s->flags |= STAGE_SCALE_S;
730 continue;
731 }
732
733 if (Q_streq(c, "scale.t")) {
734 c = Com_Parse(buffer);
735 s->scale.t = atof(c);
736
737 s->flags |= STAGE_SCALE_T;
738 continue;
739 }
740
741 if (Q_streq(c, "terrain")) {
742 c = Com_Parse(buffer);
743 s->terrain.floor = atof(c);
744
745 c = Com_Parse(buffer);
746 s->terrain.ceil = atof(c);
747 if (s->terrain.ceil < s->terrain.floor) {
748 Com_Printf("R_ParseStage: Inverted terrain ceiling and floor "
749 "values for %s\n", (s->image ? s->image->name : "nullptr"));
750 return -1;
751 }
752
753 s->terrain.height = s->terrain.ceil - s->terrain.floor;
754
755 if (s->terrain.height == 0.0) {
756 Com_Printf("R_ParseStage: Zero height terrain specified for %s\n",
757 (s->image ? s->image->name : "nullptr"));
758 return -1;
759 }
760
761 s->flags |= STAGE_TERRAIN;
762 continue;
763 }
764
765 if (Q_streq(c, "tape")) {
766 c = Com_Parse(buffer);
767 s->tape.center = atof(c);
768
769 /* how much downwards? */
770 c = Com_Parse(buffer);
771 s->tape.floor = atof(c);
772
773 /* how much upwards? */
774 c = Com_Parse(buffer);
775 s->tape.ceil = atof(c);
776
777 s->tape.min = s->tape.center - s->tape.floor;
778 s->tape.max = s->tape.center + s->tape.ceil;
779 s->tape.height = s->tape.floor + s->tape.ceil;
780
781 if (s->tape.height == 0.0) {
782 Com_Printf("R_ParseStage: Zero height tape specified for %s\n",
783 (s->image ? s->image->name : "nullptr"));
784 return -1;
785 }
786
787 s->flags |= STAGE_TAPE;
788 continue;
789 }
790
791 if (Q_streq(c, "dirtmap")) {
792 c = Com_Parse(buffer);
793 s->dirt.intensity = atof(c);
794 if (s->dirt.intensity <= 0.0 || s->dirt.intensity > 1.0) {
795 Com_Printf("R_ParseStage: Invalid dirtmap intensity for %s\n",
796 (s->image ? s->image->name : "nullptr"));
797 return -1;
798 }
799 s->flags |= STAGE_DIRTMAP;
800 continue;
801 }
802
803 if (char const* const rest = Q_strstart(c, "anim")) {
804 switch (rest[0]) {
805 case 'a':
807 break;
808 case 'b':
810 break;
811 case 'r':
812 s->anim.type = ANIM_RANDOM;
813 break;
814 case 'f':
816 break;
817 default:
818 s->anim.type = ANIM_NORMAL;
819 break;
820 }
821 c = Com_Parse(buffer);
822 s->anim.num_frames = atoi(c);
823
824 if (s->anim.num_frames < 1 || s->anim.num_frames > MAX_ANIM_FRAMES) {
825 Com_Printf("R_ParseStage: Invalid number of anim frames for %s (max is %i)\n",
826 (s->image ? s->image->name : "nullptr"), MAX_ANIM_FRAMES);
827 return -1;
828 }
829
830 c = Com_Parse(buffer);
831 s->anim.fps = atof(c);
832
833 if (s->anim.fps <= 0) {
834 Com_Printf("R_ParseStage: Invalid anim fps for %s\n",
835 (s->image ? s->image->name : "nullptr"));
836 return -1;
837 }
838
839 /* the frame images are loaded once the stage is parsed completely */
840
841 s->flags |= STAGE_ANIM;
842 continue;
843 }
844
845 if (Q_streq(c, "glowmaplink")) {
847 continue;
848 }
849
850 if (Q_streq(c, "lightmap")) {
851 s->flags |= STAGE_LIGHTMAP;
852 continue;
853 }
854
855 if (Q_streq(c, "flare")) {
856 c = Com_Parse(buffer);
857 i = atoi(c);
858
859 if (i > -1 && i < NUM_FLARETEXTURES)
860 s->image = r_flaretextures[i];
861 else
862 s->image = R_FindImage(va("pics/flares/%s", c), it_material);
863
864 if (s->image == r_noTexture) {
865 Com_Printf("R_ParseStage: Failed to resolve flare: %s\n", c);
866 return -1;
867 }
868
869 s->flags |= STAGE_FLARE;
870 continue;
871 }
872
873 if (*c == '}') {
874 Com_DPrintf(DEBUG_RENDERER, "Parsed stage\n"
875 " flags: %d\n"
876 " image: %s\n"
877 " blend: %d %d\n"
878 " color: %3f %3f %3f\n"
879 " pulse: %3f\n"
880 " pulse duty cycle: %1.2f\n"
881 " stretch: %3f %3f\n"
882 " rotate: %3f\n"
883 " scroll.s: %3f\n"
884 " scroll.t: %3f\n"
885 " scale.s: %3f\n"
886 " scale.t: %3f\n"
887 " terrain.floor: %5f\n"
888 " terrain.ceil: %5f\n"
889 " anim.num_frames: %d\n"
890 " anim.fps: %3f\n",
891 s->flags, (s->image ? s->image->name : "nullptr"),
892 s->blend.src, s->blend.dest,
893 s->color[0], s->color[1], s->color[2],
894 s->pulse.hz, s->pulse.dutycycle, s->stretch.amp, s->stretch.hz,
895 s->rotate.hz, s->scroll.s, s->scroll.t,
896 s->scale.s, s->scale.t, s->terrain.floor, s->terrain.ceil,
897 s->anim.num_frames, s->anim.fps);
898
899 /* a texture or envmap means render it */
900 if (s->flags & (STAGE_TEXTURE | STAGE_ENVMAP))
901 s->flags |= STAGE_RENDER;
902
903 if (s->flags & (STAGE_TERRAIN | STAGE_DIRTMAP))
904 s->flags |= STAGE_LIGHTING;
905
906 return 0;
907 }
908
909 Com_Printf("Invalid token: '%s'\n", c);
910 }
911
912 Com_Printf("R_ParseStage: Malformed stage\n");
913 return -1;
914}
915
920void R_LoadMaterials (const char* map)
921{
922 if (Q_strvalid(r_overridematerial->string)) {
923 map = r_overridematerial->string;
924 }
925
926 /* clear previously loaded materials */
928
929 if (map[0] == '+' || map[0] == '-')
930 map++;
931 else if (map[0] == '-')
932 return;
933
934 /* load the materials file for parsing */
935 char path[MAX_QPATH];
936 Com_sprintf(path, sizeof(path), "materials/%s.mat", Com_SkipPath(map));
937
938 byte* fileBuffer;
939 if (FS_LoadFile(path, &fileBuffer) < 1) {
940 Com_DPrintf(DEBUG_RENDERER, "Couldn't load %s\n", path);
941 return;
942 } else {
943 Com_Printf("load material file: '%s'\n", path);
944 if (!r_materials->integer)
945 Com_Printf("...ignore materials (r_materials is deactivated)\n");
946 }
947
948 const char* buffer = (const char*)fileBuffer;
949
950 bool inmaterial = false;
951 image_t* image = nullptr;
952 material_t* m = nullptr;
953
954 while (true) {
955 const char* c = Com_Parse(&buffer);
956
957 if (c[0] == '\0')
958 break;
959
960 if (*c == '{' && !inmaterial) {
961 inmaterial = true;
962 continue;
963 }
964
965 if (Q_streq(c, "material")) {
966 c = Com_Parse(&buffer);
967 image = R_GetImage(va("textures/%s", c));
968 if (image == nullptr)
969 Com_DPrintf(DEBUG_RENDERER, "R_LoadMaterials: skip texture: %s - not used in the map\n", c);
970
971 continue;
972 }
973
974 if (!image)
975 continue;
976
977 m = &image->material;
978
979 if (Q_streq(c, "normalmap")){
980 c = Com_Parse(&buffer);
981 image->normalmap = R_FindImage(va("textures/%s", c), it_normalmap);
982
983 if (image->normalmap == r_noTexture){
984 Com_Printf("R_LoadMaterials: Failed to resolve normalmap: %s\n", c);
985 image->normalmap = nullptr;
986 }
987 }
988
989 if (Q_streq(c, "glowmap")){
990 c = Com_Parse(&buffer);
991 image->glowmap = R_FindImage(va("textures/%s", c), it_glowmap);
992
993 if (image->glowmap == r_noTexture){
994 Com_Printf("R_LoadMaterials: Failed to resolve glowmap: %s\n", c);
995 image->glowmap = nullptr;
996 }
997 }
998
999 if (Q_streq(c, "bump")) {
1000 m->bump = atof(Com_Parse(&buffer));
1001 if (m->bump < 0.0) {
1002 Com_Printf("R_LoadMaterials: Invalid bump value for %s\n", image->name);
1003 m->bump = defaultMaterial.bump;
1004 }
1005 }
1006
1007 if (Q_streq(c, "parallax")) {
1008 m->parallax = atof(Com_Parse(&buffer));
1009 if (m->parallax < 0.0) {
1010 Com_Printf("R_LoadMaterials: Invalid parallax value for %s\n", image->name);
1011 m->parallax = defaultMaterial.parallax;
1012 }
1013 }
1014
1015 if (Q_streq(c, "hardness")) {
1016 m->hardness = atof(Com_Parse(&buffer));
1017 if (m->hardness < 0.0) {
1018 Com_Printf("R_LoadMaterials: Invalid hardness value for %s\n", image->name);
1019 m->hardness = defaultMaterial.hardness;
1020 }
1021 }
1022
1023 if (Q_streq(c, "specular")) {
1024 m->specular = atof(Com_Parse(&buffer));
1025 if (m->specular < 0.0) {
1026 Com_Printf("R_LoadMaterials: Invalid specular value for %s\n", image->name);
1027 m->specular = defaultMaterial.specular;
1028 }
1029 }
1030
1031 if (Q_streq(c, "glowscale")) {
1032 m->glowscale = atof(Com_Parse(&buffer));
1033 if (m->glowscale < 0.0) {
1034 Com_Printf("R_LoadMaterials: Invalid glowscale value for %s\n", image->name);
1035 m->glowscale = defaultMaterial.glowscale;
1036 }
1037 }
1038
1039 if (*c == '{' && inmaterial) {
1041 s->glowscale = defaultMaterial.glowscale;
1042
1043 if (R_ParseStage(s, &buffer) == -1) {
1044 Mem_Free(s);
1045 continue;
1046 }
1047
1048 /* load animation frame images */
1049 if (s->flags & STAGE_ANIM) {
1050 if (R_LoadAnimImages(s) == -1) {
1051 Mem_Free(s);
1052 continue;
1053 }
1054 }
1055
1056 /* append the stage to the chain */
1057 if (!m->stages)
1058 m->stages = s;
1059 else {
1060 materialStage_t* ss = m->stages;
1061 while (ss->next)
1062 ss = ss->next;
1063 ss->next = s;
1064 }
1065
1066 m->flags |= s->flags;
1067 m->num_stages++;
1068 continue;
1069 }
1070
1071 if (*c == '}' && inmaterial) {
1072 Com_DPrintf(DEBUG_RENDERER, "Parsed material %s with %d stages\n", image->name, m->num_stages);
1073 inmaterial = false;
1074 image = nullptr;
1075 /* multiply stage glowscale values by material glowscale */
1076 materialStage_t* ss = m->stages;
1077 while (ss) {
1078 ss->glowscale *= m->glowscale;
1079 ss = ss->next;
1080 }
1081 }
1082 }
1083
1084 FS_FreeFile(fileBuffer);
1085
1087}
1088
1092void R_UpdateDefaultMaterial (const char* cvarName, const char* oldValue, const char* newValue, void* data)
1093{
1094 defaultMaterial.specular = r_default_specular->value;
1095 defaultMaterial.hardness = r_default_hardness->value;
1096}
memPool_t * vid_imagePool
Definition cl_main.cpp:88
rendererData_t refdef
Definition r_main.cpp:45
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition r_state.cpp:1011
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define DEBUG_RENDERER
Definition defines.h:62
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition files.cpp:384
void FS_FreeFile(void *buffer)
Definition files.cpp:411
#define MAX_QPATH
Definition filesys.h:40
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void VectorNormalizeFast(vec3_t v)
fast vector normalize routine that does not check to make sure that length != 0, nor does it return l...
Definition mathlib.cpp:762
#define M_PI
Definition mathlib.h:34
static struct mdfour * m
Definition md4.cpp:35
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_PoolAllocType(type, pool)
Definition mem.h:43
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition parse.cpp:107
Shared parsing functions.
void R_ResetArrayState(void)
Definition r_array.cpp:185
Error checking function.
#define R_CheckError()
Definition r_error.h:30
void R_CreateSurfaceFlare(mBspSurface_t *surf)
Definition r_flare.cpp:24
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLsizei const GLvoid * data
Definition r_gl.h:89
QGL_EXTERN GLuint index
Definition r_gl.h:110
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
GLuint glElementIndex_t
Definition r_gl.h:57
QGL_EXTERN const GLuint *QGL_EXTERN GLuint *QGL_EXTERN GLenum
Definition r_gl.h:127
image_t * R_FindImage(const char *pname, imagetype_t type)
Finds or loads the given image.
Definition r_image.cpp:603
image_t * r_envmaptextures[MAX_ENVMAPTEXTURES]
Definition r_image.cpp:50
void R_ImageClearMaterials(void)
Free previously loaded materials and their stages.
Definition r_image.cpp:61
image_t * r_flaretextures[NUM_FLARETEXTURES]
Definition r_image.cpp:53
image_t * R_GetImage(const char *name)
Definition r_image.cpp:452
#define MAX_ENVMAPTEXTURES
Definition r_image.h:111
#define NUM_FLARETEXTURES
Definition r_image.h:114
image_t * r_noTexture
Definition r_main.cpp:51
@ it_material
Definition r_image.h:57
@ it_normalmap
Definition r_image.h:48
@ it_glowmap
Definition r_image.h:49
void R_EnableModelLights(const light_t **lights, int numLights, bool inShadow, bool enable)
Enable or disable realtime dynamic lighting for models.
Definition r_light.cpp:149
lightmap definitions
local graphics definitions
cvar_t * r_default_hardness
Definition r_main.cpp:83
cvar_t * r_overridematerial
Definition r_main.cpp:81
void R_SetSurfaceBumpMappingParameters(const mBspSurface_t *surf, const image_t *normalMap, const image_t *specularMap)
Definition r_surface.cpp:32
cvar_t * r_wire
Definition r_main.cpp:91
cvar_t * r_default_specular
Definition r_main.cpp:82
cvar_t * r_materials
Definition r_main.cpp:80
rlocals_t r_locals
Definition r_main.cpp:49
rstate_t r_state
Definition r_main.cpp:48
mBspSurfaces_t r_material_surfaces
static void R_DrawSurfaceStage(mBspSurface_t *surf, materialStage_t *stage)
Render the specified stage for the surface. Resolve vertex attributes via helper functions,...
static void R_StageGlow(const materialStage_t *stage)
static void R_StageTexCoord(const materialStage_t *stage, const vec3_t v, const vec2_t in, vec2_t out)
Generates a single texture coordinate for the specified stage and vertex.
static GLenum R_ConstByName(const char *c)
Translate string into glmode.
void R_DrawMaterialSurfaces(const mBspSurfaces_t *surfs, glElementIndex_t *indexPtr)
Iterates the specified surfaces list, updating materials as they are encountered, and rendering all v...
material_t defaultMaterial
static int R_ParseStage(materialStage_t *s, const char **buffer)
Material stage parser.
static void R_CreateMaterialData(void)
static void R_StageVertex(const mBspSurface_t *surf, const materialStage_t *stage, const vec3_t in, vec3_t out)
Vertex deformation.
static void R_StageTextureMatrix(const mBspSurface_t *surf, const materialStage_t *stage)
Manages texture matrix manipulations for stages supporting rotations, scrolls, and stretches (rotate,...
static void R_StageColor(const materialStage_t *stage, const vec3_t v, vec4_t color)
Generates a single color for the specified stage and vertex.
static void R_StageLighting(const mBspSurface_t *surf, const materialStage_t *stage)
Manages state for stages supporting static, dynamic, and per-pixel lighting.
void R_UpdateDefaultMaterial(const char *cvarName, const char *oldValue, const char *newValue, void *data)
Change listener callback for material value cvars.
static void R_CreateMaterialData_(model_t *mod)
#define UPDATE_THRESHOLD
static void R_SetSurfaceStageState(const mBspSurface_t *surf, const materialStage_t *stage)
Manages all state for the specified surface and stage.
static void R_UpdateMaterial(material_t *m)
Materials "think" every few milliseconds to advance animations.
void R_LoadMaterials(const char *map)
Load material definitions for each map that has one.
static int R_LoadAnimImages(materialStage_t *s)
static const float dirtmap[]
Array with 'random' alpha values for the dirtmap.
#define STAGE_BLEND
Definition r_material.h:34
#define STAGE_TERRAIN
Definition r_material.h:43
#define DEFAULT_HARDNESS
Definition r_material.h:153
#define STAGE_SCROLL_S
Definition r_material.h:39
#define STAGE_SCROLL_T
Definition r_material.h:40
#define STAGE_STRETCH
Definition r_material.h:37
#define STAGE_FLARE
Definition r_material.h:48
#define DEFAULT_GLOWSCALE
Definition r_material.h:154
#define STAGE_LIGHTMAP
Definition r_material.h:45
#define STAGE_TEXTURE
Definition r_material.h:32
#define STAGE_ENVMAP
Definition r_material.h:33
#define MAX_ANIM_FRAMES
Definition r_material.h:64
#define STAGE_PULSE
Definition r_material.h:36
#define STAGE_SCALE_T
Definition r_material.h:42
#define STAGE_ANIM
Definition r_material.h:46
#define STAGE_SCALE_S
Definition r_material.h:41
#define STAGE_GLOWMAPLINK
Definition r_material.h:49
#define DEFAULT_PARALLAX
Definition r_material.h:151
#define STAGE_COLOR
Definition r_material.h:35
#define STAGE_ROTATE
Definition r_material.h:38
#define DEFAULT_BUMP
Definition r_material.h:150
#define DEFAULT_SPECULAR
Definition r_material.h:152
#define STAGE_DIRTMAP
Definition r_material.h:47
@ ANIM_BACKWARDS
Definition r_material.h:117
@ ANIM_NORMAL
Definition r_material.h:115
@ ANIM_RANDOM
Definition r_material.h:118
@ ANIM_ALTERNATE
Definition r_material.h:116
@ ANIM_RANDOMFORCE
Definition r_material.h:119
#define STAGE_TEXTURE_MATRIX
Definition r_material.h:58
#define STAGE_LIGHTING
Definition r_material.h:52
#define STAGE_TAPE
Definition r_material.h:44
#define STAGE_RENDER
Definition r_material.h:55
int r_numMapTiles
Definition r_model.cpp:33
int r_numModelsInline
Definition r_model.cpp:37
model_t r_modelsInline[MAX_MOD_KNOWN]
Definition r_model.cpp:36
model_t * r_mapTiles[MAX_MAPTILES]
The world model(s).
Definition r_model.cpp:32
#define MSURF_LIGHTMAP
void R_ProgramParameter1f(const char *name, GLfloat value)
void R_EnableTexture(gltexunit_t *texunit, bool enable)
Definition r_state.cpp:303
void R_EnableGlowMap(const image_t *image)
Definition r_state.cpp:664
void R_BlendFunc(GLenum src, GLenum dest)
Definition r_state.cpp:232
bool R_EnableLighting(r_program_t *program, bool enable)
Enables hardware-accelerated lighting with the specified program. This should be called after any tex...
Definition r_state.cpp:350
void R_BindLightmapTexture(GLuint texnum)
Definition r_state.cpp:90
void R_EnableBumpmap(const image_t *normalmap)
Enables bumpmapping and binds the given normalmap.
Definition r_state.cpp:465
void R_ReallocateTexunitArray(gltexunit_t *texunit, int size)
Reallocate texcoord array of the specified texunit, if needed.
Definition r_state.cpp:1059
void R_EnableColorArray(bool enable)
Definition r_state.cpp:332
void R_EnableFog(bool enable)
Definition r_state.cpp:586
void R_ReallocateStateArrays(int size)
Reallocate arrays of GL primitives if needed.
Definition r_state.cpp:1029
#define texunit_diffuse
Definition r_state.h:68
#define texunit_lightmap
Definition r_state.h:69
#define R_BindTexture(tn)
Definition r_state.h:184
#define Q_strvalid(string)
Definition shared.h:141
#define Q_streq(a, b)
Definition shared.h:136
#define lengthof(x)
Definition shared.h:105
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition shared.cpp:37
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
int num_frames
Definition r_material.h:124
struct image_s * images[MAX_ANIM_FRAMES]
Definition r_material.h:126
animLoop_t type
Definition r_material.h:125
float fps
Definition r_material.h:127
unsigned int dest
Definition r_material.h:77
unsigned int src
Definition r_material.h:77
float intensity
Definition r_material.h:69
char name[MAX_QPATH]
Definition r_image.h:62
int height
Definition r_image.h:64
int width
Definition r_image.h:64
struct image_s * normalmap
Definition r_image.h:69
struct image_s * glowmap
Definition r_image.h:70
material_t material
Definition r_image.h:68
mBspSurface_t * surfaces
mBspTexInfo_t * texinfo
unsigned int index
surfaces are assigned to arrays based on their primary rendering type and then sorted by world textur...
mBspSurface_t ** surfaces
image_t * image
scroll_t scroll
Definition r_material.h:140
struct image_s * image
Definition r_material.h:134
rotate_t rotate
Definition r_material.h:139
stretch_t stretch
Definition r_material.h:138
blendmode_t blend
Definition r_material.h:135
struct materialStage_s * next
Definition r_material.h:147
terrain_t terrain
Definition r_material.h:142
mBspModel_t bsp
Definition r_model.h:60
float dutycycle
Definition r_material.h:82
float dhz
Definition r_material.h:81
float hz
Definition r_material.h:81
float deg
Definition r_material.h:73
float hz
Definition r_material.h:73
float s
Definition r_material.h:96
float t
Definition r_material.h:96
float ds
Definition r_material.h:92
float dt
Definition r_material.h:92
float t
Definition r_material.h:91
float s
Definition r_material.h:91
float hz
Definition r_material.h:86
float amp
Definition r_material.h:87
float damp
Definition r_material.h:87
float height
Definition r_material.h:108
float center
Definition r_material.h:111
float floor
Definition r_material.h:106
float ceil
Definition r_material.h:107
float max
Definition r_material.h:110
float min
Definition r_material.h:109
float floor
Definition r_material.h:100
float ceil
Definition r_material.h:101
float height
Definition r_material.h:102
vec_t vec3_t[3]
Definition ufotypes.h:39
vec_t vec4_t[4]
Definition ufotypes.h:40
vec_t vec2_t[2]
Definition ufotypes.h:38
#define Vector4Set(v, r, g, b, a)
Definition vector.h:62
#define VectorSubtract(a, b, dest)
Definition vector.h:45
#define VectorCopy(src, dest)
Definition vector.h:51
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition vector.h:44
#define VectorSet(v, x, y, z)
Definition vector.h:59
#define Vector2Copy(src, dest)
Definition vector.h:52