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=&sectorloops[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=&sectorloops[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