1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 *
31 *---------------------------------------------------------------------
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "gl_opengl.h"
39
40 #include "z_zone.h"
41 #include <SDL.h>
42
43 #ifdef HAVE_LIBSDL_IMAGE
44 #include <SDL_image.h>
45 #endif
46
47 #include <math.h>
48
49 #include "v_video.h"
50 #include "r_main.h"
51 #include "gl_intern.h"
52 #include "w_wad.h"
53 #include "lprintf.h"
54 #include "p_spec.h"
55 #include "m_misc.h"
56 #include "sc_man.h"
57 #include "e6y.h"
58 #ifdef USE_CUSTOM_QSORT
59 #include "qsort.h"
60 #endif
61
62 int render_usedetail;
63 int gl_allow_detail_textures;
64 int gl_detail_maxdist;
65 float gl_detail_maxdist_sqrt;
66
67 detail_t *details;
68 int details_count;
69 int details_size;
70 int scene_has_details;
71 int scene_has_wall_details;
72 int scene_has_flat_details;
73
74 typedef enum
75 {
76 TAG_DETAIL_WALL,
77 TAG_DETAIL_FLAT,
78 TAG_DETAIL_MAX,
79 } tag_detail_e;
80
81 static const char *DetailItem_Keywords[TAG_DETAIL_MAX + 1] =
82 {
83 "walls",
84 "flats",
85 NULL
86 };
87
88 static GLuint last_detail_texid = -1;
89
90 float xCamera,yCamera,zCamera;
91 TAnimItemParam *anim_flats = NULL;
92 TAnimItemParam *anim_textures = NULL;
93
94 void gld_ShutdownDetail(void);
95
M_ChangeUseDetail(void)96 void M_ChangeUseDetail(void)
97 {
98 render_usedetail = false;
99
100 if (V_GetMode() == VID_MODEGL)
101 {
102 render_usedetail = gl_allow_detail_textures;
103 gld_EnableDetail(true);
104 gld_EnableDetail(false);
105 gld_FlushTextures();
106 }
107 }
108
distance2piece(float x0,float y0,float x1,float y1,float x2,float y2)109 float distance2piece(float x0, float y0, float x1, float y1, float x2, float y2)
110 {
111 float t, w;
112 float x01 = x0 - x1;
113 float x02 = x0 - x2;
114 float x21 = x2 - x1;
115 float y01 = y0 - y1;
116 float y02 = y0 - y2;
117 float y21 = y2 - y1;
118
119 if((x01 * x21 + y01 * y21) * (x02 * x21 + y02 * y21) > 0.0001f)
120 {
121 t = x01 * x01 + y01 * y01;
122 w = x02 * x02 + y02 * y02;
123 if (w < t) t = w;
124 }
125 else
126 {
127 float i1 = x01 * y21 - y01 * x21;
128 float i2 = x21 * x21 + y21 * y21;
129 t = (i1 * i1) / i2;
130 }
131
132 return t;
133 }
134
gld_IsDetailVisible(float x0,float y0,float x1,float y1,float x2,float y2)135 int gld_IsDetailVisible(float x0, float y0, float x1, float y1, float x2, float y2)
136 {
137 if (gl_detail_maxdist_sqrt == 0)
138 {
139 return true;
140 }
141 else
142 {
143 return (distance2piece(x0, y0, x1, y1, x2, y2) < gl_detail_maxdist_sqrt);
144 }
145 }
146
gld_InitDetail(void)147 void gld_InitDetail(void)
148 {
149 gl_detail_maxdist_sqrt = (float)sqrt((float)gl_detail_maxdist);
150
151 atexit(gld_ShutdownDetail);
152 M_ChangeUseDetail();
153 }
154
gld_ShutdownDetail(void)155 void gld_ShutdownDetail(void)
156 {
157 int i;
158
159 if (details)
160 {
161 for (i = 0; i < details_count; i++)
162 {
163 glDeleteTextures(1, &details[i].texid);
164 }
165
166 free(details);
167 details = NULL;
168 details_count = 0;
169 details_size = 0;
170 }
171 }
172
gld_DrawTriangleStripARB(GLWall * wall,gl_strip_coords_t * c1,gl_strip_coords_t * c2)173 void gld_DrawTriangleStripARB(GLWall *wall, gl_strip_coords_t *c1, gl_strip_coords_t *c2)
174 {
175 glBegin(GL_TRIANGLE_STRIP);
176
177 // lower left corner
178 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,(const GLfloat*)&c1->t[0]);
179 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE1_ARB,(const GLfloat*)&c2->t[0]);
180 glVertex3fv((const GLfloat*)&c1->v[0]);
181
182 // split left edge of wall
183 //if (gl_seamless && !wall->glseg->fracleft)
184 // gld_SplitLeftEdge(wall, true);
185
186 // upper left corner
187 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,(const GLfloat*)&c1->t[1]);
188 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE1_ARB,(const GLfloat*)&c2->t[1]);
189 glVertex3fv((const GLfloat*)&c1->v[1]);
190
191 // upper right corner
192 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,(const GLfloat*)&c1->t[2]);
193 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE1_ARB,(const GLfloat*)&c2->t[2]);
194 glVertex3fv((const GLfloat*)&c1->v[2]);
195
196 // split right edge of wall
197 //if (gl_seamless && !wall->glseg->fracright)
198 // gld_SplitRightEdge(wall, true);
199
200 // lower right corner
201 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,(const GLfloat*)&c1->t[3]);
202 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE1_ARB,(const GLfloat*)&c2->t[3]);
203 glVertex3fv((const GLfloat*)&c1->v[3]);
204
205 glEnd();
206 }
207
gld_PreprocessDetail(void)208 void gld_PreprocessDetail(void)
209 {
210 if (gl_arb_multitexture)
211 {
212 GLEXT_glClientActiveTextureARB(GL_TEXTURE0_ARB);
213 #if defined(USE_VERTEX_ARRAYS) || defined(USE_VBO)
214 glTexCoordPointer(2, GL_FLOAT, sizeof(flats_vbo[0]), flats_vbo_u);
215 #endif
216
217 GLEXT_glClientActiveTextureARB(GL_TEXTURE1_ARB);
218 #if defined(USE_VERTEX_ARRAYS) || defined(USE_VBO)
219 glTexCoordPointer(2, GL_FLOAT, sizeof(flats_vbo[0]), flats_vbo_u);
220 #endif
221 GLEXT_glClientActiveTextureARB(GL_TEXTURE0_ARB);
222
223 GLEXT_glActiveTextureARB(GL_TEXTURE1_ARB);
224 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
225 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);
226 GLEXT_glActiveTextureARB(GL_TEXTURE0_ARB);
227 }
228 }
229
230
gld_EnableDetail(int enable)231 void gld_EnableDetail(int enable)
232 {
233 if (!gl_arb_multitexture || !render_usedetail)
234 return;
235
236 gld_EnableTexture2D(GL_TEXTURE1_ARB, enable);
237 gld_EnableClientCoordArray(GL_TEXTURE1_ARB, enable);
238 }
239
gld_DrawWallWithDetail(GLWall * wall)240 void gld_DrawWallWithDetail(GLWall *wall)
241 {
242 float w, h, dx, dy;
243 dboolean fake = (wall->flag == GLDWF_TOPFLUD) || (wall->flag == GLDWF_BOTFLUD);
244 detail_t *detail = wall->gltexture->detail;
245
246 w = wall->gltexture->detail_width;
247 h = wall->gltexture->detail_height;
248 dx = detail->offsetx;
249 dy = detail->offsety;
250
251 if (fake)
252 {
253 int i;
254 gl_strip_coords_t c1;
255 gl_strip_coords_t c2;
256
257 gld_BindFlat(wall->gltexture, 0);
258
259 gld_SetupFloodStencil(wall);
260 gld_SetupFloodedPlaneLight(wall);
261 gld_SetupFloodedPlaneCoords(wall, &c1);
262 for (i = 0; i < 4; i++)
263 {
264 c2.t[i][0] = c1.t[i][0] * w + dx;
265 c2.t[i][1] = c1.t[i][1] * h + dy;
266 }
267
268 gld_EnableTexture2D(GL_TEXTURE1_ARB, true);
269 gld_DrawTriangleStripARB(wall, &c1, &c2);
270 gld_EnableTexture2D(GL_TEXTURE1_ARB, false);
271
272 gld_ClearFloodStencil(wall);
273 }
274 else
275 {
276 gld_StaticLightAlpha(wall->light, wall->alpha);
277 glBegin(GL_TRIANGLE_FAN);
278
279 // lower left corner
280 GLEXT_glMultiTexCoord2fARB(GL_TEXTURE0_ARB,wall->ul,wall->vb);
281 GLEXT_glMultiTexCoord2fARB(GL_TEXTURE1_ARB,wall->ul*w+dx,wall->vb*h+dy);
282 glVertex3f(wall->glseg->x1,wall->ybottom,wall->glseg->z1);
283
284 // split left edge of wall
285 if (gl_seamless && !wall->glseg->fracleft)
286 gld_SplitLeftEdge(wall, true);
287
288 // upper left corner
289 GLEXT_glMultiTexCoord2fARB(GL_TEXTURE0_ARB,wall->ul,wall->vt);
290 GLEXT_glMultiTexCoord2fARB(GL_TEXTURE1_ARB,wall->ul*w+dx,wall->vt*h+dy);
291 glVertex3f(wall->glseg->x1,wall->ytop,wall->glseg->z1);
292
293 // upper right corner
294 GLEXT_glMultiTexCoord2fARB(GL_TEXTURE0_ARB,wall->ur,wall->vt);
295 GLEXT_glMultiTexCoord2fARB(GL_TEXTURE1_ARB,wall->ur*w+dx,wall->vt*h+dy);
296 glVertex3f(wall->glseg->x2,wall->ytop,wall->glseg->z2);
297
298 // split right edge of wall
299 if (gl_seamless && !wall->glseg->fracright)
300 gld_SplitRightEdge(wall, true);
301
302 // lower right corner
303 GLEXT_glMultiTexCoord2fARB(GL_TEXTURE0_ARB,wall->ur,wall->vb);
304 GLEXT_glMultiTexCoord2fARB(GL_TEXTURE1_ARB,wall->ur*w+dx,wall->vb*h+dy);
305 glVertex3f(wall->glseg->x2,wall->ybottom,wall->glseg->z2);
306
307 glEnd();
308 }
309 }
310
gld_DrawWallDetail_NoARB(GLWall * wall)311 void gld_DrawWallDetail_NoARB(GLWall *wall)
312 {
313 if (!wall->gltexture->detail)
314 return;
315
316 if (wall->flag >= GLDWF_SKY)
317 return;
318
319 if (gld_IsDetailVisible(xCamera, yCamera,
320 wall->glseg->x1, wall->glseg->z1,
321 wall->glseg->x2, wall->glseg->z2))
322 {
323 float w, h, dx, dy;
324 dboolean fake = (wall->flag == GLDWF_TOPFLUD) || (wall->flag == GLDWF_BOTFLUD);
325 detail_t *detail = wall->gltexture->detail;
326
327 w = wall->gltexture->detail_width;
328 h = wall->gltexture->detail_height;
329 dx = detail->offsetx;
330 dy = detail->offsety;
331
332 gld_BindDetail(wall->gltexture, detail->texid);
333
334 if (fake)
335 {
336 int i;
337 gl_strip_coords_t c;
338
339 if (gl_use_fog)
340 {
341 // calculation of fog density for flooded walls
342 if (wall->seg->backsector)
343 {
344 wall->fogdensity = gld_CalcFogDensity(wall->seg->frontsector,
345 wall->seg->backsector->lightlevel, GLDIT_FWALL);
346 }
347 gld_SetFog(wall->fogdensity);
348 }
349
350 gld_SetupFloodStencil(wall);
351 gld_SetupFloodedPlaneLight(wall);
352 gld_SetupFloodedPlaneCoords(wall, &c);
353 for (i = 0; i < 4; i++)
354 {
355 c.t[i][0] = c.t[i][0] * w + dx;
356 c.t[i][1] = c.t[i][1] * h + dy;
357 }
358 gld_DrawTriangleStrip(wall, &c);
359 gld_ClearFloodStencil(wall);
360 }
361 else
362 {
363 gld_StaticLightAlpha(wall->light, wall->alpha);
364 glBegin(GL_TRIANGLE_FAN);
365
366 // lower left corner
367 glTexCoord2f(wall->ul*w+dx,wall->vb*h+dy);
368 glVertex3f(wall->glseg->x1,wall->ybottom,wall->glseg->z1);
369
370 // split left edge of wall
371 if (gl_seamless && !wall->glseg->fracleft)
372 gld_SplitLeftEdge(wall, true);
373
374 // upper left corner
375 glTexCoord2f(wall->ul*w+dx,wall->vt*h+dy);
376 glVertex3f(wall->glseg->x1,wall->ytop,wall->glseg->z1);
377
378 // upper right corner
379 glTexCoord2f(wall->ur*w+dx,wall->vt*h+dy);
380 glVertex3f(wall->glseg->x2,wall->ytop,wall->glseg->z2);
381
382 // split right edge of wall
383 if (gl_seamless && !wall->glseg->fracright)
384 gld_SplitRightEdge(wall, true);
385
386 // lower right corner
387 glTexCoord2f(wall->ur*w+dx,wall->vb*h+dy);
388 glVertex3f(wall->glseg->x2,wall->ybottom,wall->glseg->z2);
389
390 glEnd();
391 }
392 }
393 }
394
gld_DrawFlatDetail_NoARB(GLFlat * flat)395 void gld_DrawFlatDetail_NoARB(GLFlat *flat)
396 {
397 float w, h, dx, dy;
398 int loopnum;
399 GLLoopDef *currentloop;
400 detail_t *detail;
401
402 if (!flat->gltexture->detail)
403 return;
404
405 detail = flat->gltexture->detail;
406 gld_BindDetail(flat->gltexture, detail->texid);
407
408 gld_StaticLightAlpha(flat->light, flat->alpha);
409 glMatrixMode(GL_MODELVIEW);
410 glPushMatrix();
411 glTranslatef(0.0f,flat->z,0.0f);
412 glMatrixMode(GL_TEXTURE);
413 glPushMatrix();
414
415 w = flat->gltexture->detail_width;
416 h = flat->gltexture->detail_height;
417 dx = detail->offsetx;
418 dy = detail->offsety;
419
420 if ((flat->flags & GLFLAT_HAVE_OFFSET) || dx || dy)
421 {
422 glTranslatef(flat->uoffs * w + dx, flat->voffs * h + dy, 0.0f);
423 }
424
425 glScalef(w, h, 1.0f);
426
427 if (flat->sectornum>=0)
428 {
429 // go through all loops of this sector
430 #if defined(USE_VERTEX_ARRAYS) || defined(USE_VBO)
431 if (gl_use_display_lists)
432 {
433 glCallList(flats_display_list + flat->sectornum);
434 }
435 else
436 {
437 for (loopnum=0; loopnum<sectorloops[flat->sectornum].loopcount; loopnum++)
438 {
439 currentloop=§orloops[flat->sectornum].loops[loopnum];
440 glDrawArrays(currentloop->mode,currentloop->vertexindex,currentloop->vertexcount);
441 }
442 }
443 #else
444 for (loopnum=0; loopnum<sectorloops[flat->sectornum].loopcount; loopnum++)
445 {
446 int vertexnum;
447 // set the current loop
448 currentloop=§orloops[flat->sectornum].loops[loopnum];
449 if (!currentloop)
450 continue;
451 // set the mode (GL_TRIANGLES, GL_TRIANGLE_STRIP or GL_TRIANGLE_FAN)
452 glBegin(currentloop->mode);
453 // go through all vertexes of this loop
454 for (vertexnum=currentloop->vertexindex; vertexnum<(currentloop->vertexindex+currentloop->vertexcount); vertexnum++)
455 {
456 // set texture coordinate of this vertex
457 if (true)
458 {
459 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, (GLfloat*)&flats_vbo[vertexnum].u);
460 GLEXT_glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, (GLfloat*)&flats_vbo[vertexnum].u);
461 }
462 else
463 {
464 glTexCoord2fv((GLfloat*)&flats_vbo[vertexnum].u);
465 }
466 // set vertex coordinate
467 glVertex3fv((GLfloat*)&flats_vbo[vertexnum].x);
468 }
469 // end of loop
470 glEnd();
471 }
472 #endif
473 }
474 glPopMatrix();
475 glMatrixMode(GL_MODELVIEW);
476 glPopMatrix();
477 }
478
479 #ifdef USE_CUSTOM_QSORT
qsort_walls_by_detail(GLDrawItem * arr,unsigned int n)480 void qsort_walls_by_detail(GLDrawItem *arr, unsigned int n)
481 {
482 #define cmp_walls_by_detail(a, b) ((a)->item.wall->gltexture->detail > (b)->item.wall->gltexture->detail)
483 QSORT(GLDrawItem, arr, n, cmp_walls_by_detail);
484 }
485
qsort_flats_by_detail(GLDrawItem * arr,unsigned int n)486 void qsort_flats_by_detail(GLDrawItem *arr, unsigned int n)
487 {
488 #define cmp_flats_by_detail(a, b) ((a)->item.flat->gltexture->detail > (b)->item.flat->gltexture->detail)
489 QSORT(GLDrawItem, arr, n, cmp_flats_by_detail);
490 }
491 #else
dicmp_wall_detail(const void * a,const void * b)492 static int C_DECL dicmp_wall_detail(const void *a, const void *b)
493 {
494 detail_t *d1 = ((const GLDrawItem *)a)->item.wall->gltexture->detail;
495 detail_t *d2 = ((const GLDrawItem *)b)->item.wall->gltexture->detail;
496 return d1 - d2;
497 }
498
dicmp_flat_detail(const void * a,const void * b)499 static int C_DECL dicmp_flat_detail(const void *a, const void *b)
500 {
501 detail_t *d1 = ((const GLDrawItem *)a)->item.flat->gltexture->detail;
502 detail_t *d2 = ((const GLDrawItem *)b)->item.flat->gltexture->detail;
503 return d1 - d2;
504 }
505 #endif
506
gld_DrawItemsSortByDetail(GLDrawItemType itemtype)507 void gld_DrawItemsSortByDetail(GLDrawItemType itemtype)
508 {
509 #ifdef USE_CUSTOM_QSORT
510 typedef void(*DICMP_ITEM)(GLDrawItem *arr, unsigned int n);
511
512 static DICMP_ITEM itemfuncs[GLDIT_TYPES] = {
513 0,
514 qsort_walls_by_detail, qsort_walls_by_detail, qsort_walls_by_detail, qsort_walls_by_detail, qsort_walls_by_detail,
515 qsort_walls_by_detail, qsort_walls_by_detail,
516 qsort_flats_by_detail, qsort_flats_by_detail,
517 qsort_flats_by_detail, qsort_flats_by_detail,
518 0, 0, 0,
519 0,
520 };
521
522 if (itemfuncs[itemtype] && gld_drawinfo.num_items[itemtype] > 1)
523 {
524 itemfuncs[itemtype](gld_drawinfo.items[itemtype], gld_drawinfo.num_items[itemtype]);
525 }
526 #else
527 typedef int(C_DECL *DICMP_ITEM)(const void *a, const void *b);
528
529 static DICMP_ITEM itemfuncs[GLDIT_TYPES] = {
530 0,
531 dicmp_wall_detail, dicmp_wall_detail, dicmp_wall_detail, dicmp_wall_detail, dicmp_wall_detail,
532 dicmp_wall_detail, dicmp_wall_detail,
533 dicmp_flat_detail, dicmp_flat_detail,
534 dicmp_flat_detail, dicmp_flat_detail,
535 0, 0, 0,
536 0,
537 };
538
539 if (itemfuncs[itemtype] && gld_drawinfo.num_items[itemtype] > 1)
540 {
541 qsort(gld_drawinfo.items[itemtype], gld_drawinfo.num_items[itemtype],
542 sizeof(gld_drawinfo.items[itemtype]), itemfuncs[itemtype]);
543 }
544 #endif
545 }
546
gld_DrawDetail_NoARB(void)547 void gld_DrawDetail_NoARB(void)
548 {
549 int i;
550
551 if (!scene_has_wall_details && !scene_has_flat_details)
552 return;
553
554 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
555 glBlendFunc (GL_DST_COLOR, GL_SRC_COLOR);
556
557 last_detail_texid = -1;
558
559 // detail flats
560
561 if (scene_has_flat_details)
562 {
563 // enable backside removing
564 glEnable(GL_CULL_FACE);
565
566 // floors
567 glCullFace(GL_FRONT);
568 gld_DrawItemsSortByDetail(GLDIT_FLOOR);
569 for (i = gld_drawinfo.num_items[GLDIT_FLOOR] - 1; i >= 0; i--)
570 {
571 gld_SetFog(gld_drawinfo.items[GLDIT_FLOOR][i].item.flat->fogdensity);
572 gld_DrawFlatDetail_NoARB(gld_drawinfo.items[GLDIT_FLOOR][i].item.flat);
573 }
574 // ceilings
575 glCullFace(GL_BACK);
576 gld_DrawItemsSortByDetail(GLDIT_CEILING);
577 for (i = gld_drawinfo.num_items[GLDIT_CEILING] - 1; i >= 0; i--)
578 {
579 gld_SetFog(gld_drawinfo.items[GLDIT_CEILING][i].item.flat->fogdensity);
580 gld_DrawFlatDetail_NoARB(gld_drawinfo.items[GLDIT_CEILING][i].item.flat);
581 }
582 glDisable(GL_CULL_FACE);
583 }
584
585 // detail walls
586 if (scene_has_wall_details)
587 {
588 gld_DrawItemsSortByDetail(GLDIT_WALL);
589 for (i = gld_drawinfo.num_items[GLDIT_WALL] - 1; i >= 0; i--)
590 {
591 gld_SetFog(gld_drawinfo.items[GLDIT_WALL][i].item.wall->fogdensity);
592 gld_DrawWallDetail_NoARB(gld_drawinfo.items[GLDIT_WALL][i].item.wall);
593 }
594
595 if (!gl_use_stencil)
596 {
597 gld_DrawItemsSortByDetail(GLDIT_MWALL);
598 }
599
600 for (i = gld_drawinfo.num_items[GLDIT_MWALL] - 1; i >= 0; i--)
601 {
602 GLWall *wall = gld_drawinfo.items[GLDIT_MWALL][i].item.wall;
603 if (gl_use_stencil)
604 {
605 if (!(wall->gltexture->flags & GLTEXTURE_HASHOLES))
606 {
607 gld_SetFog(wall->fogdensity);
608 gld_DrawWallDetail_NoARB(wall);
609 }
610 }
611 else
612 {
613 gld_SetFog(wall->fogdensity);
614 gld_DrawWallDetail_NoARB(wall);
615 }
616 }
617
618 if (gld_drawinfo.num_items[GLDIT_FWALL] > 0)
619 {
620 glPolygonOffset(1.0f, 128.0f);
621 glEnable(GL_POLYGON_OFFSET_FILL);
622 glEnable(GL_STENCIL_TEST);
623
624 gld_DrawItemsSortByDetail(GLDIT_FWALL);
625 for (i = gld_drawinfo.num_items[GLDIT_FWALL] - 1; i >= 0; i--)
626 {
627 gld_DrawWallDetail_NoARB(gld_drawinfo.items[GLDIT_FWALL][i].item.wall);
628 }
629
630 glDisable(GL_STENCIL_TEST);
631 glPolygonOffset(0.0f, 0.0f);
632 glDisable(GL_POLYGON_OFFSET_FILL);
633 }
634
635 gld_DrawItemsSortByDetail(GLDIT_TWALL);
636 for (i = gld_drawinfo.num_items[GLDIT_TWALL] - 1; i >= 0; i--)
637 {
638 gld_SetFog(gld_drawinfo.items[GLDIT_TWALL][i].item.wall->fogdensity);
639 gld_DrawWallDetail_NoARB(gld_drawinfo.items[GLDIT_TWALL][i].item.wall);
640 }
641 }
642
643 // restore
644 glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
645 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
646 }
647
gld_InitFrameDetails(void)648 void gld_InitFrameDetails(void)
649 {
650 last_detail_texid = -1;
651
652 scene_has_details =
653 (render_usedetail) &&
654 (scene_has_wall_details || scene_has_flat_details);
655 }
656
gld_BindDetailARB(GLTexture * gltexture,int enable)657 void gld_BindDetailARB(GLTexture *gltexture, int enable)
658 {
659 if (scene_has_details)
660 {
661 gld_EnableTexture2D(GL_TEXTURE1_ARB, enable);
662 gld_EnableClientCoordArray(GL_TEXTURE1_ARB, enable);
663
664 if (enable &&
665 gltexture->detail &&
666 gltexture->detail->texid != last_detail_texid)
667 {
668 last_detail_texid = gltexture->detail->texid;
669
670 GLEXT_glActiveTextureARB(GL_TEXTURE1_ARB);
671 glBindTexture(GL_TEXTURE_2D, gltexture->detail->texid);
672 GLEXT_glActiveTextureARB(GL_TEXTURE0_ARB);
673 }
674 }
675 }
676
gld_BindDetail(GLTexture * gltexture,int enable)677 void gld_BindDetail(GLTexture *gltexture, int enable)
678 {
679 if (scene_has_details)
680 {
681 if (enable &&
682 gltexture->detail &&
683 gltexture->detail->texid != last_detail_texid)
684 {
685 last_detail_texid = gltexture->detail->texid;
686 glBindTexture(GL_TEXTURE_2D, gltexture->detail->texid);
687 }
688 }
689 }
690
gld_SetTexDetail(GLTexture * gltexture)691 void gld_SetTexDetail(GLTexture *gltexture)
692 {
693 int i;
694
695 gltexture->detail = NULL;
696
697 if (details_count > 0)
698 {
699 // linear search
700 for (i = 0; i < details_count; i++)
701 {
702 if (gltexture->index == details[i].texture_num)
703 {
704 gltexture->detail = &details[i];
705 break;
706 }
707 }
708
709 if (!gltexture->detail)
710 {
711 switch (gltexture->textype)
712 {
713 case GLDT_TEXTURE:
714 if (details[TAG_DETAIL_WALL].texid > 0)
715 gltexture->detail = &details[TAG_DETAIL_WALL];
716 break;
717 case GLDT_FLAT:
718 if (details[TAG_DETAIL_FLAT].texid > 0)
719 gltexture->detail = &details[TAG_DETAIL_FLAT];
720 break;
721 }
722 }
723
724 if (gltexture->detail)
725 {
726 gltexture->detail_width = (float)gltexture->realtexwidth / gltexture->detail->width;
727 gltexture->detail_height = (float)gltexture->realtexheight / gltexture->detail->height;
728 }
729 }
730 }
731
gld_LoadDetailName(const char * name)732 GLuint gld_LoadDetailName(const char *name)
733 {
734 GLuint texid = 0;
735 int lump;
736
737 lump = (W_CheckNumForName)(name, ns_hires);
738
739 if (lump != -1)
740 {
741 SDL_PixelFormat fmt;
742 SDL_Surface *surf = NULL;
743 SDL_Surface *surf_raw;
744
745 #ifdef HAVE_LIBSDL_IMAGE
746 surf_raw = IMG_Load_RW(SDL_RWFromConstMem(W_CacheLumpNum(lump), W_LumpLength(lump)), 1);
747 #else
748 surf_raw = SDL_LoadBMP_RW(SDL_RWFromConstMem(W_CacheLumpNum(lump), W_LumpLength(lump)), 1);
749 #endif
750
751 W_UnlockLumpNum(lump);
752
753 if (surf_raw)
754 {
755 fmt = *surf_raw->format;
756 fmt.BitsPerPixel = 24;
757 fmt.BytesPerPixel = 3;
758 surf = SDL_ConvertSurface(surf_raw, &fmt, surf_raw->flags);
759 SDL_FreeSurface(surf_raw);
760 if (surf)
761 {
762 if (gl_arb_multitexture)
763 GLEXT_glActiveTextureARB(GL_TEXTURE1_ARB);
764 glGenTextures(1, &texid);
765 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
766 glBindTexture(GL_TEXTURE_2D, texid);
767
768 gluBuild2DMipmaps(GL_TEXTURE_2D, gl_tex_format,
769 surf->w, surf->h,
770 imageformats[surf->format->BytesPerPixel],
771 GL_UNSIGNED_BYTE, surf->pixels);
772
773 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
774 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
775 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
776 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
777 if (gl_ext_texture_filter_anisotropic)
778 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (GLfloat)(1<<gl_texture_filter_anisotropic));
779
780 if (gl_arb_multitexture)
781 GLEXT_glActiveTextureARB(GL_TEXTURE0_ARB);
782
783 SDL_FreeSurface(surf);
784 }
785 }
786 }
787
788 return texid;
789 }
790
gld_ReadDetailParams(tag_detail_e item,detail_t * detail)791 int gld_ReadDetailParams(tag_detail_e item, detail_t *detail)
792 {
793 int result = false;
794 if (SC_Check())
795 {
796 // get detail texture name
797 SC_GetString();
798
799 if (strlen(sc_String) < 9)
800 {
801 detail->texid = gld_LoadDetailName(sc_String);
802
803 if (detail->texid > 0)
804 {
805 float f;
806
807 if (SC_Check() && SC_GetString() && M_StrToFloat(sc_String, &f))
808 detail->width = f;
809 if (SC_Check() && SC_GetString() && M_StrToFloat(sc_String, &f))
810 detail->height = f;
811
812 if (SC_Check() && SC_GetString() && M_StrToFloat(sc_String, &f))
813 detail->offsetx = f / detail->width;
814 if (SC_Check() && SC_GetString() && M_StrToFloat(sc_String, &f))
815 detail->offsety = f / detail->height;
816
817 result = true;
818 }
819 }
820 // skip the rest of unknown params
821 while (SC_Check())
822 SC_GetString();
823 }
824
825 return result;
826 }
827
gld_ParseDetailItem(tag_detail_e item)828 void gld_ParseDetailItem(tag_detail_e item)
829 {
830 // item's default values
831 details[item].width = 16.0f;
832 details[item].height = 16.0f;
833 details[item].offsetx = 0.0f;
834 details[item].offsety = 0.0f;
835 if (SC_Check() && !SC_Compare("{"))
836 {
837 gld_ReadDetailParams(item, &details[item]);
838 }
839
840 if (SC_GetString() && SC_Compare("{"))
841 {
842 while (SC_GetString() && !SC_Compare("}"))
843 {
844 int result;
845 detail_t detail;
846
847 // reset fields for next iteration
848 detail.texid = 0;
849 detail.width = 16.0f;
850 detail.height = 16.0f;
851 detail.offsetx = 0.0f;
852 detail.offsety = 0.0f;
853
854 if (strlen(sc_String) < 9)
855 {
856 switch (item)
857 {
858 case TAG_DETAIL_WALL:
859 detail.texture_num = R_CheckTextureNumForName(sc_String);
860 break;
861 case TAG_DETAIL_FLAT:
862 detail.texture_num = (W_CheckNumForName)(sc_String, ns_flats);
863 break;
864 }
865
866 result = gld_ReadDetailParams(item, &detail);
867
868 if (result || details[item].texid > 0)
869 {
870 if (details_count + 1 > details_size)
871 {
872 details_size = (details_size == 0 ? 128 : details_size * 2);
873 details = realloc(details, details_size * sizeof(details[0]));
874 }
875 details[details_count] = detail;
876 details_count++;
877 }
878 }
879 }
880 }
881 }
882
gld_ParseDetail(void)883 void gld_ParseDetail(void)
884 {
885 gld_ShutdownDetail();
886
887 details_count = 2; // reserved for default wall and flat
888 details_size = 128;
889 details = calloc(details_size, sizeof(details[0]));
890
891 // skip "Detail" params
892 while (SC_Check() && !SC_Compare("{"))
893 SC_GetString();
894
895 if (SC_GetString() && SC_Compare("{"))
896 {
897 while (SC_GetString() && !SC_Compare("}"))
898 {
899 switch (SC_MatchString(DetailItem_Keywords))
900 {
901 case TAG_DETAIL_WALL:
902 gld_ParseDetailItem(TAG_DETAIL_WALL);
903 break;
904 case TAG_DETAIL_FLAT:
905 gld_ParseDetailItem(TAG_DETAIL_FLAT);
906 break;
907 }
908 }
909 }
910 }
911