1 // blah
2 
3 #if defined USE_OPENGL && defined POLYMER
4 
5 #include "compat.h"
6 
7 #define POLYMER_C
8 #include "polymer.h"
9 #include "engine_priv.h"
10 #include "xxhash.h"
11 #include "texcache.h"
12 
13 // CVARS
14 int32_t         pr_lighting = 1;
15 int32_t         pr_normalmapping = 1;
16 int32_t         pr_specularmapping = 1;
17 int32_t         pr_shadows = 1;
18 int32_t         pr_shadowcount = 5;
19 int32_t         pr_shadowdetail = 4;
20 int32_t         pr_shadowfiltering = 1;
21 int32_t         pr_maxlightpasses = 10;
22 int32_t         pr_maxlightpriority = PR_MAXLIGHTPRIORITY;
23 int32_t         pr_fov = 512;
24 double          pr_customaspect = 0.0f;
25 int32_t         pr_billboardingmode = 1;
26 int32_t         pr_verbosity = 1;       // 0: silent, 1: errors and one-times, 2: multiple-times, 3: flood
27 int32_t         pr_wireframe = 0;
28 int32_t         pr_vbos = 2;
29 int32_t         pr_buckets = 0;
30 int32_t         pr_gpusmoothing = 1;
31 int32_t         pr_overrideparallax = 0;
32 float           pr_parallaxscale = 0.1f;
33 float           pr_parallaxbias = 0.0f;
34 int32_t         pr_overridespecular = 0;
35 float           pr_specularpower = 15.0f;
36 float           pr_specularfactor = 1.0f;
37 int32_t         pr_highpalookups = 1;
38 int32_t         pr_artmapping = 1;
39 int32_t         pr_overridehud = 0;
40 float           pr_hudxadd = 0.0f;
41 float           pr_hudyadd = 0.0f;
42 float           pr_hudzadd = 0.0f;
43 int32_t         pr_hudangadd = 0;
44 int32_t         pr_hudfov = 512;
45 float           pr_overridemodelscale = 0.0f;
46 int32_t         pr_ati_fboworkaround = 0;
47 int32_t         pr_ati_nodepthoffset = 0;
48 #ifdef __APPLE__
49 int32_t         pr_ati_textureformat_one = 0;
50 #endif
51 int32_t         pr_nullrender = 0; // 1: no draw, 2: no draw or updates
52 
53 int32_t         r_pr_maxlightpasses = 5; // value of the cvar (not live value), used to detect changes
54 
55 GLenum          mapvbousage = GL_STREAM_DRAW;
56 GLenum          modelvbousage = GL_STATIC_DRAW;
57 
58 // BUILD DATA
59 _prsector       *prsectors[MAXSECTORS];
60 _prwall         *prwalls[MAXWALLS];
61 _prsprite       *prsprites[MAXSPRITES];
62 _prmaterial     mdspritematerial;
63 _prhighpalookup prhighpalookups[MAXBASEPALS][MAXPALOOKUPS];
64 
65 // One U8 texture per tile
66 GLuint          prartmaps[MAXTILES];
67 // 256 U8U8U8 values per basepal
68 GLuint          prbasepalmaps[MAXBASEPALS];
69 // numshades full indirections (32*256) per lookup
70 GLuint          prlookups[MAXPALOOKUPS];
71 
72 GLuint          prmapvbo;
73 const GLsizeiptr proneplanesize = sizeof(_prvert) * 4;
74 const GLintptr prwalldatasize = sizeof(_prvert)* 4 * 3; // wall, over and mask planes for every wall
75 GLintptr prwalldataoffset;
76 
77 GLuint          prindexringvbo;
78 GLuint          *prindexring;
79 const GLsizeiptr prindexringsize = 65535;
80 GLintptr prindexringoffset;
81 
82 const GLbitfield prindexringmapflags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
83 
84 _prbucket       *prbuckethead;
85 int32_t         prcanbucket;
86 
87 static const _prvert  vertsprite[4] =
88 {
89     {
90         -0.5f, 0.0f, 0.0f,
91         0.0f, 1.0f,
92         0xff, 0xff, 0xff, 0xff,
93     },
94     {
95         0.5f, 0.0f, 0.0f,
96         1.0f, 1.0f,
97         0xff, 0xff, 0xff, 0xff,
98     },
99     {
100         0.5f, 1.0f, 0.0f,
101         1.0f, 0.0f,
102         0xff, 0xff, 0xff, 0xff,
103     },
104     {
105         -0.5f, 1.0f, 0.0f,
106         0.0f, 0.0f,
107         0xff, 0xff, 0xff, 0xff,
108     },
109 };
110 
111 static const _prvert  horizsprite[4] =
112 {
113     {
114         -0.5f, 0.0f, 0.5f,
115         0.0f, 0.0f,
116         0xff, 0xff, 0xff, 0xff,
117     },
118     {
119         0.5f, 0.0f, 0.5f,
120         1.0f, 0.0f,
121         0xff, 0xff, 0xff, 0xff,
122     },
123     {
124         0.5f, 0.0f, -0.5f,
125         1.0f, 1.0f,
126         0xff, 0xff, 0xff, 0xff,
127     },
128     {
129         -0.5f, 0.0f, -0.5f,
130         0.0f, 1.0f,
131         0xff, 0xff, 0xff, 0xff,
132     },
133 };
134 
135 static const GLfloat  skyboxdata[4 * 5 * 6] =
136 {
137     // -ZY
138     -0.5f, -0.5f, 0.5f,
139     0.0f, 1.0f,
140     -0.5f, -0.5f, -0.5f,
141     1.0f, 1.0f,
142     -0.5f, 0.5f, -0.5f,
143     1.0f, 0.0f,
144     -0.5f, 0.5f, 0.5f,
145     0.0f, 0.0f,
146 
147     // XY
148     -0.5f, -0.5f, -0.5f,
149     0.0f, 1.0f,
150     0.5f, -0.5f, -0.5f,
151     1.0f, 1.0f,
152     0.5f, 0.5f, -0.5f,
153     1.0f, 0.0f,
154     -0.5f, 0.5f, -0.5f,
155     0.0f, 0.0f,
156 
157     // ZY
158     0.5f, -0.5f, -0.5f,
159     0.0f, 1.0f,
160     0.5f, -0.5f, 0.5f,
161     1.0f, 1.0f,
162     0.5f, 0.5f, 0.5f,
163     1.0f, 0.0f,
164     0.5f, 0.5f, -0.5f,
165     0.0f, 0.0f,
166 
167     // -XY
168     0.5f, -0.5f, 0.5f,
169     0.0f, 1.0f,
170     -0.5f, -0.5f, 0.5f,
171     1.0f, 1.0f,
172     -0.5f, 0.5f, 0.5f,
173     1.0f, 0.0f,
174     0.5f, 0.5f, 0.5f,
175     0.0f, 0.0f,
176 
177     // XZ
178     -0.5f, 0.5f, -0.5f,
179     1.0f, 1.0f,
180     0.5f, 0.5f, -0.5f,
181     1.0f, 0.0f,
182     0.5f, 0.5f, 0.5f,
183     0.0f, 0.0f,
184     -0.5f, 0.5f, 0.5f,
185     0.0f, 1.0f,
186 
187     // X-Z
188     -0.5f, -0.5f, 0.5f,
189     0.0f, 0.0f,
190     0.5f, -0.5f, 0.5f,
191     0.0f, 1.0f,
192     0.5f, -0.5f, -0.5f,
193     1.0f, 1.0f,
194     -0.5f, -0.5f, -0.5f,
195     1.0f, 0.0f,
196 };
197 
198 GLuint          skyboxdatavbo;
199 
200 GLfloat         artskydata[PSKYOFF_MAX*2];
201 
202 // LIGHTS
203 static _prplanelist *plpool;
204 #pragma pack(push,1)
205 _prlight        prlights[PR_MAXLIGHTS];
206 int32_t         lightcount;
207 int32_t         curlight;
208 #pragma pack(pop)
209 
210 static const GLfloat  shadowBias[] =
211 {
212     0.5, 0.0, 0.0, 0.0,
213     0.0, 0.5, 0.0, 0.0,
214     0.0, 0.0, 0.5, 0.0,
215     0.5, 0.5, 0.5, 1.0
216 };
217 
218 // MATERIALS
219 static const _prprogrambit   prprogrambits[PR_BIT_COUNT] = {
220     {
221         1 << PR_BIT_HEADER,
222         // vert_def
223         "#version 120\n"
224         "#extension GL_ARB_texture_rectangle : enable\n"
225         "\n",
226         // vert_prog
227         "",
228         // frag_def
229         "#version 120\n"
230         "#extension GL_ARB_texture_rectangle : enable\n"
231         "\n",
232         // frag_prog
233         "",
234     },
235     {
236         1 << PR_BIT_ANIM_INTERPOLATION,
237         // vert_def
238         "attribute vec4 nextFrameData;\n"
239         "attribute vec4 nextFrameNormal;\n"
240         "uniform float frameProgress;\n"
241         "\n",
242         // vert_prog
243         "  vec4 currentFramePosition;\n"
244         "  vec4 nextFramePosition;\n"
245         "\n"
246         "  currentFramePosition = curVertex * (1.0 - frameProgress);\n"
247         "  nextFramePosition = nextFrameData * frameProgress;\n"
248         "  curVertex = currentFramePosition + nextFramePosition;\n"
249         "\n"
250         "  currentFramePosition = vec4(curNormal, 1.0) * (1.0 - frameProgress);\n"
251         "  nextFramePosition = nextFrameNormal * frameProgress;\n"
252         "  curNormal = vec3(currentFramePosition + nextFramePosition);\n"
253         "\n",
254         // frag_def
255         "",
256         // frag_prog
257         "",
258     },
259     {
260         1 << PR_BIT_LIGHTING_PASS,
261         // vert_def
262         "",
263         // vert_prog
264         "",
265         // frag_def
266         "",
267         // frag_prog
268         "  isLightingPass = 1;\n"
269         "  result = vec4(0.0, 0.0, 0.0, 1.0);\n"
270         "\n",
271     },
272     {
273         1 << PR_BIT_NORMAL_MAP,
274         // vert_def
275         "attribute vec3 T;\n"
276         "attribute vec3 B;\n"
277         "attribute vec3 N;\n"
278         "uniform vec3 eyePosition;\n"
279         "varying vec3 tangentSpaceEyeVec;\n"
280         "\n",
281         // vert_prog
282         "  TBN = mat3(T, B, N);\n"
283         "  tangentSpaceEyeVec = eyePosition - vec3(curVertex);\n"
284         "  tangentSpaceEyeVec = TBN * tangentSpaceEyeVec;\n"
285         "\n"
286         "  isNormalMapped = 1;\n"
287         "\n",
288         // frag_def
289         "uniform sampler2D normalMap;\n"
290         "uniform vec2 normalBias;\n"
291         "varying vec3 tangentSpaceEyeVec;\n"
292         "\n",
293         // frag_prog
294         "  vec4 normalStep;\n"
295         "  float biasedHeight;\n"
296         "\n"
297         "  eyeVec = normalize(tangentSpaceEyeVec);\n"
298         "\n"
299         "  for (int i = 0; i < 4; i++) {\n"
300         "    normalStep = texture2D(normalMap, commonTexCoord.st);\n"
301         "    biasedHeight = normalStep.a * normalBias.x - normalBias.y;\n"
302         "    commonTexCoord += (biasedHeight - commonTexCoord.z) * normalStep.z * eyeVec;\n"
303         "  }\n"
304         "\n"
305         "  normalTexel = texture2D(normalMap, commonTexCoord.st);\n"
306         "\n"
307         "  isNormalMapped = 1;\n"
308         "\n",
309     },
310     {
311         1 << PR_BIT_ART_MAP,
312         // vert_def
313         "varying vec3 horizDistance;\n"
314         "\n",
315         // vert_prog
316         "  gl_TexCoord[0] = gl_MultiTexCoord0;\n"
317         "  horizDistance = vec3(gl_ModelViewMatrix * curVertex);\n"
318         "\n",
319         // frag_def
320         "uniform sampler2D artMap;\n"
321         "uniform sampler2D basePalMap;\n"
322         "uniform sampler2DRect lookupMap;\n"
323         "uniform float shadeOffset;\n"
324         "uniform float visibility;\n"
325         "varying vec3 horizDistance;\n"
326         "\n",
327         // frag_prog
328 
329         "  float shadeLookup = length(horizDistance) / 1.024 * visibility;\n"
330         "  shadeLookup = shadeLookup + shadeOffset;\n"
331         "\n"
332         "  float colorIndex = texture2D(artMap, commonTexCoord.st).r * 256.0;\n"
333         "  float colorIndexNear = texture2DRect(lookupMap, vec2(colorIndex, floor(shadeLookup))).r;\n"
334         "  float colorIndexFar = texture2DRect(lookupMap, vec2(colorIndex, floor(shadeLookup + 1.0))).r;\n"
335         "  float colorIndexFullbright = texture2DRect(lookupMap, vec2(colorIndex, 0.0)).r;\n"
336         "\n"
337         "  vec3 texelNear = texture2D(basePalMap, vec2(colorIndexNear, 0.5)).rgb;\n"
338         "  vec3 texelFar = texture2D(basePalMap, vec2(colorIndexFar, 0.5)).rgb;\n"
339         "  diffuseTexel.rgb = texture2D(basePalMap, vec2(colorIndexFullbright, 0.5)).rgb;\n"
340         "\n"
341         "  if (isLightingPass == 0) {\n"
342         "    result.rgb = mix(texelNear, texelFar, fract(shadeLookup));\n"
343         "    result.a = 1.0;\n"
344         "    if (colorIndex == 256.0)\n"
345         "      result.a = 0.0;\n"
346         "  }\n"
347         "\n",
348     },
349     {
350         1 << PR_BIT_DIFFUSE_MAP,
351         // vert_def
352         "uniform vec2 diffuseScale;\n"
353         "\n",
354         // vert_prog
355         "  gl_TexCoord[0] = vec4(diffuseScale, 1.0, 1.0) * gl_MultiTexCoord0;\n"
356         "\n",
357         // frag_def
358         "uniform sampler2D diffuseMap;\n"
359         "\n",
360         // frag_prog
361         "  diffuseTexel = texture2D(diffuseMap, commonTexCoord.st);\n"
362         "\n",
363     },
364     {
365         1 << PR_BIT_DIFFUSE_DETAIL_MAP,
366         // vert_def
367         "uniform vec2 detailScale;\n"
368         "varying vec2 fragDetailScale;\n"
369         "\n",
370         // vert_prog
371         "  fragDetailScale = detailScale;\n"
372         "  if (isNormalMapped == 0)\n"
373         "    gl_TexCoord[1] = vec4(detailScale, 1.0, 1.0) * gl_MultiTexCoord0;\n"
374         "\n",
375         // frag_def
376         "uniform sampler2D detailMap;\n"
377         "varying vec2 fragDetailScale;\n"
378         "\n",
379         // frag_prog
380         "  if (isNormalMapped == 0)\n"
381         "    diffuseTexel *= texture2D(detailMap, gl_TexCoord[1].st);\n"
382         "  else\n"
383         "    diffuseTexel *= texture2D(detailMap, commonTexCoord.st * fragDetailScale);\n"
384         "  diffuseTexel.rgb *= 2.0;\n"
385         "\n",
386     },
387     {
388         1 << PR_BIT_DIFFUSE_MODULATION,
389         // vert_def
390         "",
391         // vert_prog
392         "  gl_FrontColor = gl_Color;\n"
393         "\n",
394         // frag_def
395         "",
396         // frag_prog
397         "  if (isLightingPass == 0)\n"
398         "    result *= vec4(gl_Color);\n"
399         "\n",
400     },
401     {
402         1 << PR_BIT_DIFFUSE_MAP2,
403         // vert_def
404         "",
405         // vert_prog
406         "",
407         // frag_def
408         "",
409         // frag_prog
410         "  if (isLightingPass == 0)\n"
411         "    result *= diffuseTexel;\n"
412         "\n",
413     },
414     {
415         1 << PR_BIT_HIGHPALOOKUP_MAP,
416         // vert_def
417         "",
418         // vert_prog
419         "",
420         // frag_def
421         "uniform sampler3D highPalookupMap;\n"
422         "\n",
423         // frag_prog
424         "  float highPalScale = 0.9921875; // for 6 bits\n"
425         "  float highPalBias = 0.00390625;\n"
426         "\n"
427         "  if (isLightingPass == 0)\n"
428         "    result.rgb = texture3D(highPalookupMap, result.rgb * highPalScale + highPalBias).rgb;\n"
429         "  diffuseTexel.rgb = texture3D(highPalookupMap, diffuseTexel.rgb * highPalScale + highPalBias).rgb;\n"
430         "\n",
431     },
432     {
433         1 << PR_BIT_SPECULAR_MAP,
434         // vert_def
435         "",
436         // vert_prog
437         "",
438         // frag_def
439         "uniform sampler2D specMap;\n"
440         "\n",
441         // frag_prog
442         "  specTexel = texture2D(specMap, commonTexCoord.st);\n"
443         "\n"
444         "  isSpecularMapped = 1;\n"
445         "\n",
446     },
447     {
448         1 << PR_BIT_SPECULAR_MATERIAL,
449         // vert_def
450         "",
451         // vert_prog
452         "",
453         // frag_def
454         "uniform vec2 specMaterial;\n"
455         "\n",
456         // frag_prog
457         "  specularMaterial = specMaterial;\n"
458         "\n",
459     },
460     {
461         1 << PR_BIT_MIRROR_MAP,
462         // vert_def
463         "",
464         // vert_prog
465         "",
466         // frag_def
467         "uniform sampler2DRect mirrorMap;\n"
468         "\n",
469         // frag_prog
470         "  vec4 mirrorTexel;\n"
471         "  vec2 mirrorCoords;\n"
472         "\n"
473         "  mirrorCoords = gl_FragCoord.st;\n"
474         "  if (isNormalMapped == 1) {\n"
475         "    mirrorCoords += 100.0 * (normalTexel.rg - 0.5);\n"
476         "  }\n"
477         "  mirrorTexel = texture2DRect(mirrorMap, mirrorCoords);\n"
478         "  result = vec4((result.rgb * (1.0 - specTexel.a)) + (mirrorTexel.rgb * specTexel.rgb * specTexel.a), result.a);\n"
479         "\n",
480     },
481     {
482         1 << PR_BIT_FOG,
483         // vert_def
484         "",
485         // vert_prog
486         "",
487         // frag_def
488 #ifdef PR_LINEAR_FOG
489         "uniform bool linearFog;\n"
490 #endif
491         "",
492         // frag_prog
493         "  float fragDepth;\n"
494         "  float fogFactor;\n"
495         "\n"
496         "  fragDepth = gl_FragCoord.z / gl_FragCoord.w;\n"
497 #ifdef PR_LINEAR_FOG
498         "  if (!linearFog) {\n"
499 #endif
500         "    fragDepth *= fragDepth;\n"
501         "    fogFactor = exp2(-gl_Fog.density * gl_Fog.density * fragDepth * 1.442695);\n"
502 #ifdef PR_LINEAR_FOG
503         "  } else {\n"
504         "    fogFactor = gl_Fog.scale * (gl_Fog.end - fragDepth);\n"
505         "    fogFactor = clamp(fogFactor, 0.0, 1.0);"
506         "  }\n"
507 #endif
508         "  result.rgb = mix(gl_Fog.color.rgb, result.rgb, fogFactor);\n"
509         "\n",
510     },
511     {
512         1 << PR_BIT_GLOW_MAP,
513         // vert_def
514         "",
515         // vert_prog
516         "",
517         // frag_def
518         "uniform sampler2D glowMap;\n"
519         "\n",
520         // frag_prog
521         "  vec4 glowTexel;\n"
522         "\n"
523         "  glowTexel = texture2D(glowMap, commonTexCoord.st);\n"
524         "  result = vec4((result.rgb * (1.0 - glowTexel.a)) + (glowTexel.rgb * glowTexel.a), result.a);\n"
525         "\n",
526     },
527     {
528         1 << PR_BIT_PROJECTION_MAP,
529         // vert_def
530         "uniform mat4 shadowProjMatrix;\n"
531         "\n",
532         // vert_prog
533         "  gl_TexCoord[2] = shadowProjMatrix * curVertex;\n"
534         "\n",
535         // frag_def
536         "",
537         // frag_prog
538         "",
539     },
540     {
541         1 << PR_BIT_SHADOW_MAP,
542         // vert_def
543         "",
544         // vert_prog
545         "",
546         // frag_def
547         "uniform sampler2DShadow shadowMap;\n"
548         "\n",
549         // frag_prog
550         "  shadowResult = shadow2DProj(shadowMap, gl_TexCoord[2]).a;\n"
551         "\n",
552     },
553     {
554         1 << PR_BIT_LIGHT_MAP,
555         // vert_def
556         "",
557         // vert_prog
558         "",
559         // frag_def
560         "uniform sampler2D lightMap;\n"
561         "\n",
562         // frag_prog
563         "  lightTexel = texture2D(lightMap, vec2(gl_TexCoord[2].s, -gl_TexCoord[2].t) / gl_TexCoord[2].q).rgb;\n"
564         "\n",
565     },
566     {
567         1 << PR_BIT_SPOT_LIGHT,
568         // vert_def
569         "",
570         // vert_prog
571         "",
572         // frag_def
573         "uniform vec3 spotDir;\n"
574         "uniform vec2 spotRadius;\n"
575         "\n",
576         // frag_prog
577         "  spotVector = spotDir;\n"
578         "  spotCosRadius = spotRadius;\n"
579         "  isSpotLight = 1;\n"
580         "\n",
581     },
582     {
583         1 << PR_BIT_POINT_LIGHT,
584         // vert_def
585         "varying vec3 vertexNormal;\n"
586         "varying vec3 eyeVector;\n"
587         "varying vec3 lightVector;\n"
588         "varying vec3 tangentSpaceLightVector;\n"
589         "\n",
590         // vert_prog
591         "  vec3 vertexPos;\n"
592         "\n"
593         "  vertexPos = vec3(gl_ModelViewMatrix * curVertex);\n"
594         "  eyeVector = -vertexPos;\n"
595         "  lightVector = gl_LightSource[0].ambient.rgb - vertexPos;\n"
596         "\n"
597         "  if (isNormalMapped == 1) {\n"
598         "    tangentSpaceLightVector = gl_LightSource[0].specular.rgb - vec3(curVertex);\n"
599         "    tangentSpaceLightVector = TBN * tangentSpaceLightVector;\n"
600         "  } else\n"
601         "    vertexNormal = normalize(gl_NormalMatrix * curNormal);\n"
602         "\n",
603         // frag_def
604         "varying vec3 vertexNormal;\n"
605         "varying vec3 eyeVector;\n"
606         "varying vec3 lightVector;\n"
607         "varying vec3 tangentSpaceLightVector;\n"
608         "\n",
609         // frag_prog
610         "  float pointLightDistance;\n"
611         "  float lightAttenuation;\n"
612         "  float spotAttenuation;\n"
613         "  vec3 N, L, E, R, D;\n"
614         "  vec3 lightDiffuse;\n"
615         "  float lightSpecular;\n"
616         "  float NdotL;\n"
617         "  float spotCosAngle;\n"
618         "\n"
619         "  L = normalize(lightVector);\n"
620         "\n"
621         "  pointLightDistance = dot(lightVector,lightVector);\n"
622         "  lightAttenuation = clamp(1.0 - pointLightDistance * gl_LightSource[0].linearAttenuation, 0.0, 1.0);\n"
623         "  spotAttenuation = 1.0;\n"
624         "\n"
625         "  if (isSpotLight == 1) {\n"
626         "    D = normalize(spotVector);\n"
627         "    spotCosAngle = dot(-L, D);\n"
628         "    spotAttenuation = clamp((spotCosAngle - spotCosRadius.x) * spotCosRadius.y, 0.0, 1.0);\n"
629         "  }\n"
630         "\n"
631         "  if (isNormalMapped == 1) {\n"
632         "    E = eyeVec;\n"
633         "    N = normalize(2.0 * (normalTexel.rgb - 0.5));\n"
634         "    L = normalize(tangentSpaceLightVector);\n"
635         "  } else {\n"
636         "    E = normalize(eyeVector);\n"
637         "    N = normalize(vertexNormal);\n"
638         "  }\n"
639         "  NdotL = max(dot(N, L), 0.0);\n"
640         "\n"
641         "  R = reflect(-L, N);\n"
642         "\n"
643         "  lightDiffuse = gl_Color.a * shadowResult * lightTexel *\n"
644         "                 gl_LightSource[0].diffuse.rgb * lightAttenuation * spotAttenuation;\n"
645         "  result += vec4(lightDiffuse * diffuseTexel.a * diffuseTexel.rgb * NdotL, 0.0);\n"
646         "\n"
647         "  if (isSpecularMapped == 0)\n"
648         "    specTexel.rgb = diffuseTexel.rgb * diffuseTexel.a;\n"
649         "\n"
650         "  lightSpecular = pow( max(dot(R, E), 0.0), specularMaterial.x * specTexel.a) * specularMaterial.y;\n"
651         "  result += vec4(lightDiffuse * specTexel.rgb * lightSpecular, 0.0);\n"
652         "\n",
653     },
654     {
655         1 << PR_BIT_FOOTER,
656         // vert_def
657         "void main(void)\n"
658         "{\n"
659         "  vec4 curVertex = gl_Vertex;\n"
660         "  vec3 curNormal = gl_Normal;\n"
661         "  int isNormalMapped = 0;\n"
662         "  mat3 TBN;\n"
663         "\n"
664         "  gl_TexCoord[0] = gl_MultiTexCoord0;\n"
665         "\n",
666         // vert_prog
667         "  gl_Position = gl_ModelViewProjectionMatrix * curVertex;\n"
668         "}\n",
669         // frag_def
670         "void main(void)\n"
671         "{\n"
672         "  vec3 commonTexCoord = vec3(gl_TexCoord[0].st, 0.0);\n"
673         "  vec4 result = vec4(1.0, 1.0, 1.0, 1.0);\n"
674         "  vec4 diffuseTexel = vec4(1.0, 1.0, 1.0, 1.0);\n"
675         "  vec4 specTexel = vec4(1.0, 1.0, 1.0, 1.0);\n"
676         "  vec4 normalTexel;\n"
677         "  int isLightingPass = 0;\n"
678         "  int isNormalMapped = 0;\n"
679         "  int isSpecularMapped = 0;\n"
680         "  vec3 eyeVec;\n"
681         "  int isSpotLight = 0;\n"
682         "  vec3 spotVector;\n"
683         "  vec2 spotCosRadius;\n"
684         "  float shadowResult = 1.0;\n"
685         "  vec2 specularMaterial = vec2(15.0, 1.0);\n"
686         "  vec3 lightTexel = vec3(1.0, 1.0, 1.0);\n"
687         "\n",
688         // frag_prog
689         "  gl_FragColor = result;\n"
690         "}\n",
691     }
692 };
693 
694 _prprograminfo  prprograms[1 << PR_BIT_COUNT];
695 
696 int32_t         overridematerial;
697 int32_t         globaloldoverridematerial;
698 
699 int32_t         rotatespritematerialbits;
700 
701 // RENDER TARGETS
702 _prrt           *prrts;
703 
704 // CONTROL
705 GLfloat         spritemodelview[16];
706 GLfloat         mdspritespace[4][4];
707 GLfloat         rootmodelviewmatrix[16];
708 GLfloat         *curmodelviewmatrix;
709 GLfloat         rootskymodelviewmatrix[16];
710 GLfloat         *curskymodelviewmatrix;
711 
712 static int16_t  sectorqueue[MAXSECTORS];
713 static int16_t  querydelay[MAXSECTORS];
714 static GLuint   queryid[MAXWALLS];
715 static int16_t  drawingstate[MAXSECTORS];
716 
717 int16_t         *cursectormasks;
718 int16_t         *cursectormaskcount;
719 
720 float           horizang;
721 fix16_t         viewangle;
722 
723 int32_t         depth;
724 _prmirror       mirrors[10];
725 
726 #if defined __clang__ && defined __APPLE__
727 // XXX: OS X 10.9 deprecated GLUtesselator.
728 #pragma clang diagnostic push
729 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
730 #endif
731 GLUtesselator*  prtess;
732 #if defined __clang__ && defined __APPLE__
733 #pragma clang diagnostic pop
734 #endif
735 
736 static int16_t  cursky;
737 static char     curskypal;
738 static int8_t   curskyshade;
739 static float    curskyangmul = 1;
740 
741 _pranimatespritesinfo asi;
742 
743 rorcallback     prorcallback;
744 
745 int32_t         polymersearching;
746 
747 int32_t         culledface;
748 
749 static char     transluctable[2] = { 0x55, 0xAA };
750 
751 // EXTERNAL FUNCTIONS
polymer_init(void)752 int32_t             polymer_init(void)
753 {
754     int32_t         i, j, t = timerGetTicks();
755 
756     if (pr_verbosity >= 1) OSD_Printf("Initializing Polymer subsystem...\n");
757 
758     if (!glinfo.texnpot ||
759         !glinfo.depthtex ||
760         !glinfo.shadow ||
761         !glinfo.fbos ||
762         !glinfo.rect ||
763         !glinfo.multitex ||
764         !glinfo.vbos ||
765         !glinfo.occlusionqueries ||
766         !glinfo.glsl)
767     {
768         OSD_Printf("PR : Your video card driver/combo doesn't support the necessary features!\n");
769         OSD_Printf("PR : Disabling Polymer...\n");
770         return 0;
771     }
772 
773     // clean up existing stuff since it will be initialized again if we're re-entering here
774     polymer_uninit();
775 
776     Bmemset(&prsectors[0], 0, sizeof(prsectors[0]) * MAXSECTORS);
777     Bmemset(&prwalls[0], 0, sizeof(prwalls[0]) * MAXWALLS);
778 
779     prtess = bgluNewTess();
780     if (prtess == 0)
781     {
782         OSD_Printf("PR : Tessellation object initialization failed!\n");
783         return 0;
784     }
785 
786     polymer_loadboard();
787 
788     polymer_initartsky();
789     skyboxdatavbo = 0;
790 
791     i = 0;
792     while (i < nextmodelid)
793     {
794         if (models[i])
795         {
796             md3model_t* m;
797 
798             m = (md3model_t*)models[i];
799             m->indices = NULL;
800         }
801         i++;
802     }
803 
804     i = 0;
805     while (i < (1 << PR_BIT_COUNT))
806     {
807         prprograms[i].handle = 0;
808         i++;
809     }
810 
811     overridematerial = 0xFFFFFFFF;
812 
813     polymersearching = FALSE;
814 
815     polymer_initrendertargets(pr_shadowcount + 1);
816 
817     // Prime highpalookup maps
818     i = 0;
819     while (i < MAXBASEPALS)
820     {
821         j = 0;
822         while (j < MAXPALOOKUPS)
823         {
824             if (prhighpalookups[i][j].data)
825             {
826                 glGenTextures(1, &prhighpalookups[i][j].map);
827                 glBindTexture(GL_TEXTURE_3D, prhighpalookups[i][j].map);
828                 glTexImage3D(GL_TEXTURE_3D,                // target
829                               0,                            // mip level
830                               GL_RGBA,                      // internalFormat
831                               PR_HIGHPALOOKUP_DIM,          // width
832                               PR_HIGHPALOOKUP_DIM,          // height
833                               PR_HIGHPALOOKUP_DIM,          // depth
834                               0,                            // border
835                               GL_BGRA,                      // upload format
836                               GL_UNSIGNED_BYTE,             // upload component type
837                               prhighpalookups[i][j].data);     // data pointer
838                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
839                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
840                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
841                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
842                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
843                 glBindTexture(GL_TEXTURE_3D, 0);
844             }
845             j++;
846         }
847         i++;
848     }
849 
850     if (bloodhack)
851     {
852         transluctable[0] = 0xAA;
853         transluctable[1] = 0x55;
854     }
855 
856 #ifndef __APPLE__
857     if (glinfo.debugoutput) {
858         // Enable everything.
859         glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
860         glDebugMessageCallbackARB((GLDEBUGPROCARB)polymer_debugoutputcallback, NULL);
861         glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
862     }
863 #endif
864 
865     if (pr_verbosity >= 1) OSD_Printf("PR : Initialization complete in %d ms.\n", timerGetTicks()-t);
866 
867     return 1;
868 }
869 
polymer_uninit(void)870 void                polymer_uninit(void)
871 {
872     int32_t         i, j;
873 
874     if (prtess)
875     {
876         bgluDeleteTess(prtess);
877         prtess = NULL;
878     }
879 
880     polymer_freeboard();
881 
882     polymer_initrendertargets(0);
883 
884     i = 0;
885     while (i < MAXBASEPALS)
886     {
887         j = 0;
888         while (j < MAXPALOOKUPS)
889         {
890 //            if (prhighpalookups[i][j].data) {
891 //                DO_FREE_AND_NULL(prhighpalookups[i][j].data);
892 //            }
893             if (prhighpalookups[i][j].map) {
894                 glDeleteTextures(1, &prhighpalookups[i][j].map);
895                 prhighpalookups[i][j].map = 0;
896             }
897             j++;
898         }
899         i++;
900     }
901 
902     i = 0;
903     while (plpool)
904     {
905         _prplanelist*   next = plpool->n;
906 
907         Xfree(plpool);
908         plpool = next;
909         i++;
910     }
911 
912     if (pr_verbosity >= 3)
913         OSD_Printf("PR: freed %d planelists\n", i);
914 }
915 
polymer_setaspect(int32_t ang)916 void                polymer_setaspect(int32_t ang)
917 {
918     float           aspect;
919     float fang = (float)ang * atanf(fviewingrange*(1.f/65536.f)) * (4.f/fPI);
920 
921     // use horizontal fov instead of vertical
922     fang = atanf(tanf(fang * (fPI / 2048.f)) * float(windowxy2.y - windowxy1.y + 1) / float(windowxy2.x - windowxy1.x + 1) *
923                       float(xdim) / float(ydim) * (3.f / 4.f)) * (2048.f / fPI);
924 
925     if (pr_customaspect != 0.0f)
926         aspect = pr_customaspect;
927     else
928         aspect = (float)(windowxy2.x-windowxy1.x+1) /
929                  (float)(windowxy2.y-windowxy1.y+1);
930 
931     glMatrixMode(GL_PROJECTION);
932     glLoadIdentity();
933     bgluPerspective(fang * (360.f/2048.f), aspect, 0.01f, 100.0f);
934 }
935 
polymer_glinit(void)936 void                polymer_glinit(void)
937 {
938     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
939     glClearStencil(0);
940     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
941     glViewport(windowxy1.x, ydim-(windowxy2.y+1),windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
942 
943     glEnable(GL_DEPTH_TEST);
944     glDepthFunc(GL_LEQUAL);
945 
946     glDisable(GL_BLEND);
947     glDisable(GL_ALPHA_TEST);
948 
949     if (pr_wireframe)
950         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
951     else
952         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
953 
954     polymer_setaspect(pr_fov);
955 
956     glMatrixMode(GL_MODELVIEW);
957     glLoadIdentity();
958 
959     glEnableClientState(GL_VERTEX_ARRAY);
960     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
961 
962     glDisable(GL_FOG);
963 
964     culledface = GL_BACK;
965     glCullFace(GL_BACK);
966     glFrontFace(GL_CCW);
967 
968     glEnable(GL_CULL_FACE);
969 }
970 
polymer_resetlights(void)971 void                polymer_resetlights(void)
972 {
973     int32_t         i;
974     _prsector       *s;
975     _prwall         *w;
976 
977     i = 0;
978     while (i < numsectors)
979     {
980         s = prsectors[i];
981 
982         if (!s) {
983             i++;
984             continue;
985         }
986 
987         polymer_resetplanelights(&s->floor);
988         polymer_resetplanelights(&s->ceil);
989 
990         i++;
991     }
992 
993     i = 0;
994     while (i < numwalls)
995     {
996         w = prwalls[i];
997 
998         if (!w) {
999             i++;
1000             continue;
1001         }
1002 
1003         polymer_resetplanelights(&w->wall);
1004         polymer_resetplanelights(&w->over);
1005         polymer_resetplanelights(&w->mask);
1006 
1007         i++;
1008     }
1009 
1010     i = 0;
1011     while (i < PR_MAXLIGHTS)
1012     {
1013         prlights[i].flags.active = 0;
1014         i++;
1015     }
1016 
1017     lightcount = 0;
1018 
1019     if (!engineLoadMHK(NULL))
1020         OSD_Printf("polymer_resetlights: reloaded maphack\n");
1021 }
1022 
polymer_loadboard(void)1023 void                polymer_loadboard(void)
1024 {
1025     int32_t         i;
1026 
1027     polymer_freeboard();
1028 
1029     // in the big map buffer, sectors have floor and ceiling vertices for each wall first, then walls
1030     prwalldataoffset = numwalls * 2 * sizeof(_prvert);
1031 
1032     glGenBuffers(1, &prmapvbo);
1033     glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
1034     glBufferData(GL_ARRAY_BUFFER, prwalldataoffset + (numwalls * prwalldatasize), NULL, mapvbousage);
1035     glBindBuffer(GL_ARRAY_BUFFER, 0);
1036 
1037     glGenBuffers(1, &prindexringvbo);
1038     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prindexringvbo);
1039 
1040     if (pr_buckets)
1041     {
1042         glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, prindexringsize * sizeof(GLuint), NULL, prindexringmapflags | GL_DYNAMIC_STORAGE_BIT);
1043         prindexring = (GLuint*)glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, prindexringsize * sizeof(GLuint), prindexringmapflags);
1044     }
1045 
1046     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1047 
1048     i = 0;
1049     while (i < numsectors)
1050     {
1051         polymer_initsector(i);
1052         polymer_updatesector(i);
1053         i++;
1054     }
1055 
1056     i = 0;
1057     while (i < numwalls)
1058     {
1059         polymer_initwall(i);
1060         polymer_updatewall(i);
1061         i++;
1062     }
1063 
1064     polymer_getsky();
1065 
1066     polymer_resetlights();
1067 
1068     if (pr_verbosity >= 1 && numsectors) OSD_Printf("PR : Board loaded.\n");
1069 }
1070 
polymer_printtext256(int32_t xpos,int32_t ypos,int16_t col,int16_t backcol,const char * name,char fontsize)1071 int32_t polymer_printtext256(int32_t xpos, int32_t ypos, int16_t col, int16_t backcol, const char *name, char fontsize)
1072 {
1073     //POGOTODO: Polymer should implement this so it's no longer coupled with Polymost & reliant on the fixed-function pipeline
1074     glEnable(GL_TEXTURE_2D);
1075     int32_t returnVal = polymost_printtext256(xpos, ypos, col, backcol, name, fontsize);
1076     glDisable(GL_TEXTURE_2D);
1077     return returnVal;
1078 }
1079 
polymer_fillpolygon(int32_t npoints)1080 void polymer_fillpolygon(int32_t npoints)
1081 {
1082     //POGOTODO: Polymer should implement this so it's no longer coupled with Polymost & reliant on the fixed-function pipeline
1083     glEnable(GL_TEXTURE_2D);
1084     polymost_fillpolygon(npoints);
1085     glDisable(GL_TEXTURE_2D);
1086 }
1087 
1088 // The parallaxed ART sky angle divisor corresponding to a horizfrac of 32768.
1089 #define DEFAULT_ARTSKY_ANGDIV 4.3027f
1090 
polymer_drawrooms(int32_t daposx,int32_t daposy,int32_t daposz,fix16_t daang,fix16_t dahoriz,int16_t dacursectnum)1091 void polymer_drawrooms(int32_t daposx, int32_t daposy, int32_t daposz, fix16_t daang, fix16_t dahoriz, int16_t dacursectnum)
1092 {
1093     int16_t         cursectnum;
1094     int32_t         i, cursectflorz, cursectceilz;
1095     float           skyhoriz, ang, tiltang;
1096     float           pos[3];
1097     pthtyp*         pth;
1098 
1099     if (videoGetRenderMode() == REND_CLASSIC) return;
1100 
1101     videoBeginDrawing();
1102 
1103     // TODO: support for screen resizing
1104     // frameoffset = frameplace + windowxy1.y*bytesperline + windowxy1.x;
1105 
1106     if (pr_verbosity >= 3) OSD_Printf("PR : Drawing rooms...\n");
1107 
1108     // fogcalc_old needs this
1109     gvisibility = ((float)globalvisibility)*FOGSCALE;
1110 
1111     ang = fix16_to_float(daang) * (360.f/2048.f);
1112     horizang = -(float)atan2f(fix16_to_float(dahoriz) - 100.f, 128.f) * (180.f * (float)M_1_PI);
1113     tiltang = (gtang * 90.0f);
1114 
1115     pos[0] = (float)daposy;
1116     pos[1] = -(float)(daposz) / 16.0f;
1117     pos[2] = -(float)daposx;
1118 
1119     polymer_updatelights();
1120 
1121 //     polymer_resetlights();
1122 //     if (pr_lighting)
1123 //         polymer_applylights();
1124 
1125     depth = 0;
1126 
1127     if (pr_shadows && lightcount && (pr_shadowcount > 0))
1128         polymer_prepareshadows();
1129 
1130     // hack for parallax skies
1131     skyhoriz = horizang;
1132     if (skyhoriz < -180.0f)
1133         skyhoriz += 360.0f;
1134 
1135     drawingskybox = 1;
1136     pth = texcache_fetch(cursky, 0, 0, DAMETH_NOMASK);
1137     drawingskybox = 0;
1138 
1139     // if it's not a skybox, make the sky parallax
1140     // DEFAULT_ARTSKY_ANGDIV is computed from eyeballed values
1141     // need to recompute it if we ever change the max horiz amplitude
1142     if (!pth || !(pth->flags & PTH_SKYBOX))
1143         skyhoriz *= curskyangmul;
1144 
1145     glMatrixMode(GL_MODELVIEW);
1146     glLoadIdentity();
1147 
1148     glRotatef(tiltang, 0.0f, 0.0f, -1.0f);
1149     glRotatef(skyhoriz, 1.0f, 0.0f, 0.0f);
1150     glRotatef(ang, 0.0f, 1.0f, 0.0f);
1151 
1152     glScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
1153     glTranslatef(-pos[0], -pos[1], -pos[2]);
1154 
1155     glGetFloatv(GL_MODELVIEW_MATRIX, rootskymodelviewmatrix);
1156 
1157     curskymodelviewmatrix = rootskymodelviewmatrix;
1158 
1159     glMatrixMode(GL_MODELVIEW);
1160     glLoadIdentity();
1161 
1162     glRotatef(tiltang, 0.0f, 0.0f, -1.0f);
1163     glRotatef(horizang, 1.0f, 0.0f, 0.0f);
1164     glRotatef(ang, 0.0f, 1.0f, 0.0f);
1165 
1166     glScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
1167     glTranslatef(-pos[0], -pos[1], -pos[2]);
1168 
1169     glGetFloatv(GL_MODELVIEW_MATRIX, rootmodelviewmatrix);
1170 
1171     cursectnum = dacursectnum;
1172     updatesector(daposx, daposy, &cursectnum);
1173 
1174     if (cursectnum >= 0 && cursectnum < numsectors)
1175         dacursectnum = cursectnum;
1176     else if (pr_verbosity>=2)
1177         OSD_Printf("PR : got sector %d after update!\n", cursectnum);
1178 
1179     // unflag all sectors
1180     i = numsectors-1;
1181     while (i >= 0)
1182     {
1183         prsectors[i]->flags.uptodate = 0;
1184         prsectors[i]->wallsproffset = 0.0f;
1185         prsectors[i]->floorsproffset = 0.0f;
1186         i--;
1187     }
1188     i = numwalls-1;
1189     while (i >= 0)
1190     {
1191         prwalls[i]->flags.uptodate = 0;
1192         i--;
1193     }
1194 
1195     if (searchit == 2 && !polymersearching)
1196     {
1197         globaloldoverridematerial = overridematerial;
1198         overridematerial = prprogrambits[PR_BIT_DIFFUSE_MODULATION].bit;
1199         overridematerial |= prprogrambits[PR_BIT_DIFFUSE_MAP2].bit;
1200         polymersearching = TRUE;
1201     }
1202     if (!searchit && polymersearching) {
1203         overridematerial = globaloldoverridematerial;
1204         polymersearching = FALSE;
1205     }
1206 
1207     if (dacursectnum > -1 && dacursectnum < numsectors)
1208         getzsofslope(dacursectnum, daposx, daposy, &cursectceilz, &cursectflorz);
1209 
1210     // external view (editor)
1211     if ((dacursectnum < 0) || (dacursectnum >= numsectors) ||
1212             (daposz > cursectflorz) ||
1213             (daposz < cursectceilz))
1214     {
1215         prcanbucket = 1;
1216 
1217         if (!editstatus && pr_verbosity>=1)
1218         {
1219             if ((unsigned)dacursectnum < (unsigned)numsectors)
1220                 OSD_Printf("PR : EXT sec=%d  z=%d (%d, %d)\n", dacursectnum, daposz, cursectflorz, cursectceilz);
1221             else
1222                 OSD_Printf("PR : EXT sec=%d  z=%d\n", dacursectnum, daposz);
1223         }
1224 
1225         curmodelviewmatrix = rootmodelviewmatrix;
1226         i = numsectors-1;
1227         while (i >= 0)
1228         {
1229             polymer_updatesector(i);
1230             polymer_drawsector(i, FALSE);
1231             polymer_scansprites(i, tsprite, &spritesortcnt);
1232             i--;
1233         }
1234 
1235         i = numwalls-1;
1236         while (i >= 0)
1237         {
1238             polymer_updatewall(i);
1239             polymer_drawwall(sectorofwall(i), i);
1240             i--;
1241         }
1242 
1243         polymer_emptybuckets();
1244 
1245         viewangle = daang;
1246         videoEndDrawing();
1247         return;
1248     }
1249 
1250     // GO!
1251     polymer_displayrooms(dacursectnum);
1252 
1253     curmodelviewmatrix = rootmodelviewmatrix;
1254 
1255     // build globals used by rotatesprite
1256     viewangle = daang;
1257     set_globalang(daang);
1258 
1259     // polymost globals used by polymost_dorotatesprite
1260     gcosang = fcosglobalang*(1./262144.f);
1261     gsinang = fsinglobalang*(1./262144.f);
1262     gcosang2 = gcosang*fviewingrange*(1./65536.f);
1263     gsinang2 = gsinang*fviewingrange*(1./65536.f);
1264 
1265     if (pr_verbosity >= 3) OSD_Printf("PR : Rooms drawn.\n");
1266     videoEndDrawing();
1267 }
1268 
polymer_drawmasks(void)1269 void                polymer_drawmasks(void)
1270 {
1271     glEnable(GL_ALPHA_TEST);
1272     glEnable(GL_BLEND);
1273 //     glEnable(GL_POLYGON_OFFSET_FILL);
1274 
1275 //     while (--spritesortcnt)
1276 //     {
1277 //         tspriteptr[spritesortcnt] = &tsprite[spritesortcnt];
1278 //         polymer_drawsprite(spritesortcnt);
1279 //     }
1280 
1281     glEnable(GL_CULL_FACE);
1282 
1283     if (cursectormaskcount) {
1284         // We (kind of) queue sector masks near to far, so drawing them in reverse
1285         // order is the sane approach here. Of course impossible cases will arise.
1286         while (*cursectormaskcount) {
1287             polymer_drawsector(cursectormasks[--(*cursectormaskcount)], TRUE);
1288         }
1289 
1290         // This should _always_ be called after a corresponding pr_displayrooms()
1291         // unless we're in "external view" mode, which was checked above.
1292         // Both the top-level game drawrooms and the recursive internal passes
1293         // should be accounted for here. If these free cause corruption, there's
1294         // an accounting bug somewhere.
1295         DO_FREE_AND_NULL(cursectormaskcount);
1296         DO_FREE_AND_NULL(cursectormasks);
1297     }
1298 
1299     glDisable(GL_CULL_FACE);
1300 
1301 //     glDisable(GL_POLYGON_OFFSET_FILL);
1302     glDisable(GL_BLEND);
1303     glDisable(GL_ALPHA_TEST);
1304 }
1305 
polymer_editorpick(void)1306 void                polymer_editorpick(void)
1307 {
1308     GLubyte         picked[3];
1309     int16_t         num;
1310 
1311     glReadPixels(searchx, ydim - searchy, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, picked);
1312 
1313     num = B_UNBUF16(&picked[1]);
1314 
1315     searchstat = picked[0];
1316 
1317     switch (searchstat) {
1318     case 0: // wall
1319     case 5: // botomwall
1320     case 4: // 1-way/masked wall
1321         searchsector = sectorofwall(num);
1322         searchbottomwall = searchwall = num;
1323         searchisbottom = (searchstat==5);
1324         if (searchstat == 5) {
1325             searchstat = 0;
1326             if (wall[num].nextwall >= 0 && (wall[num].cstat & 2)) {
1327                 searchbottomwall = wall[num].nextwall;
1328             }
1329         }
1330         break;
1331     case 1: // floor
1332     case 2: // ceiling
1333         searchsector = num;
1334 
1335         // Apologies to Plagman for littering here, but this feature is quite essential
1336         {
1337             GLdouble model[16];
1338             GLdouble proj[16];
1339             GLint view[4];
1340 
1341             GLdouble x,y,z;
1342             GLfloat scr[3], scrv[3];
1343             GLdouble scrx,scry,scrz;
1344             GLfloat dadepth;
1345 
1346             int16_t k, bestk=0;
1347             GLfloat bestwdistsq = (GLfloat)3.4e38, wdistsq;
1348             GLfloat w1[2], w2[2], w21[2], pw1[2], pw2[2];
1349             GLfloat ptonline[2];
1350             GLfloat scrvxz[2];
1351             GLfloat scrvxznorm, scrvxzn[2], scrpxz[2];
1352             GLfloat w1d, w2d;
1353             walltype *wal = &wall[sector[searchsector].wallptr];
1354 
1355             GLfloat t, svcoeff, p[2];
1356             GLfloat *pl;
1357 
1358             glGetDoublev(GL_MODELVIEW_MATRIX, model);
1359             glGetDoublev(GL_PROJECTION_MATRIX, proj);
1360             glGetIntegerv(GL_VIEWPORT, view);
1361 
1362             glReadPixels(searchx, ydim-searchy, 1,1, GL_DEPTH_COMPONENT, GL_FLOAT, &dadepth);
1363             bgluUnProject(searchx, ydim-searchy, dadepth,  model, proj, view,  &x, &y, &z);
1364             bgluUnProject(searchx, ydim-searchy, 0.0,  model, proj, view,  &scrx, &scry, &scrz);
1365 
1366             scr[0]=scrx, scr[1]=scry, scr[2]=scrz;
1367 
1368             scrv[0] = x-scrx;
1369             scrv[1] = y-scry;
1370             scrv[2] = z-scrz;
1371 
1372             scrvxz[0] = x-scrx;
1373             scrvxz[1] = z-scrz;
1374 
1375             if (prsectors[searchsector]==NULL)
1376             {
1377                 //OSD_Printf("polymer_editorpick: prsectors[searchsector]==NULL !!!\n");
1378                 searchwall = sector[num].wallptr;
1379             }
1380             else
1381             {
1382                 if (searchstat==1)
1383                     pl = prsectors[searchsector]->ceil.plane;
1384                 else
1385                     pl = prsectors[searchsector]->floor.plane;
1386 
1387                 if (pl == NULL)
1388                 {
1389                     searchwall = sector[num].wallptr;
1390                     return;
1391                 }
1392 
1393                 t = dot3f(pl,scrv);
1394                 svcoeff = -(dot3f(pl,scr)+pl[3])/t;
1395 
1396                 // point on plane (x and z)
1397                 p[0] = scrx + svcoeff*scrv[0];
1398                 p[1] = scrz + svcoeff*scrv[2];
1399 
1400                 for (k=0; k<sector[searchsector].wallnum; k++)
1401                 {
1402                     w1[1] = -(float)wal[k].x;
1403                     w1[0] = (float)wal[k].y;
1404                     w2[1] = -(float)wall[wal[k].point2].x;
1405                     w2[0] = (float)wall[wal[k].point2].y;
1406 
1407                     scrvxznorm = sqrt(dot2f(scrvxz,scrvxz));
1408                     scrvxzn[0] = scrvxz[1]/scrvxznorm;
1409                     scrvxzn[1] = -scrvxz[0]/scrvxznorm;
1410 
1411                     relvec2f(p,w1, pw1);
1412                     relvec2f(p,w2, pw2);
1413                     relvec2f(w2,w1, w21);
1414 
1415                     w1d = dot2f(scrvxzn,pw1);
1416                     w2d = dot2f(scrvxzn,pw2);
1417                     w2d = -w2d;
1418                     if (w1d <= 0 || w2d <= 0)
1419                         continue;
1420 
1421                     ptonline[0] = w2[0]+(w2d/(w1d+w2d))*w21[0];
1422                     ptonline[1] = w2[1]+(w2d/(w1d+w2d))*w21[1];
1423                     relvec2f(p,ptonline, scrpxz);
1424                     if (dot2f(scrvxz,scrpxz)<0)
1425                         continue;
1426 
1427                     wdistsq = dot2f(scrpxz,scrpxz);
1428                     if (wdistsq < bestwdistsq)
1429                     {
1430                         bestk = k;
1431                         bestwdistsq = wdistsq;
1432                     }
1433                 }
1434 
1435                 searchwall = sector[searchsector].wallptr + bestk;
1436             }
1437         }
1438         // :P
1439 
1440 //        searchwall = sector[num].wallptr;
1441         break;
1442     case 3:
1443         // sprite
1444         searchsector = sprite[num].sectnum;
1445         searchwall = num;
1446         break;
1447     }
1448 
1449     searchit = 0;
1450 }
1451 
polymer_inb4rotatesprite(int16_t tilenum,char pal,int8_t shade,int32_t method)1452 void                polymer_inb4rotatesprite(int16_t tilenum, char pal, int8_t shade, int32_t method)
1453 {
1454     _prmaterial     rotatespritematerial;
1455 
1456     polymer_getbuildmaterial(&rotatespritematerial, tilenum, pal, shade, 0, method);
1457 
1458     rotatespritematerialbits = polymer_bindmaterial(&rotatespritematerial, NULL, 0);
1459 }
1460 
polymer_postrotatesprite(void)1461 void                polymer_postrotatesprite(void)
1462 {
1463     polymer_unbindmaterial(rotatespritematerialbits);
1464 }
1465 
polymer_setupdiffusemodulation(_prplane * plane,GLubyte modulation,const GLubyte * data)1466 static void         polymer_setupdiffusemodulation(_prplane *plane, GLubyte modulation, const GLubyte *data)
1467 {
1468     plane->material.diffusemodulation[0] = modulation;
1469     plane->material.diffusemodulation[1] = ((GLubyte const *) data)[0];
1470     plane->material.diffusemodulation[2] = ((GLubyte const *) data)[1];
1471     plane->material.diffusemodulation[3] = 0xFF;
1472 }
1473 
polymer_drawsearchplane(_prplane * plane,GLubyte * oldcolor,GLubyte modulation,GLubyte * data)1474 static void         polymer_drawsearchplane(_prplane *plane, GLubyte *oldcolor, GLubyte modulation, GLubyte *data)
1475 {
1476     Bmemcpy(oldcolor, plane->material.diffusemodulation, sizeof(GLubyte) * 4);
1477 
1478     polymer_setupdiffusemodulation(plane, modulation, data);
1479 
1480     polymer_drawplane(plane);
1481 
1482     Bmemcpy(plane->material.diffusemodulation, oldcolor, sizeof(GLubyte) * 4);
1483 }
1484 
polymer_drawmaskwall(int32_t damaskwallcnt)1485 void                polymer_drawmaskwall(int32_t damaskwallcnt)
1486 {
1487     usectorptr_t      sec;
1488     walltype        *wal;
1489     _prwall         *w;
1490     GLubyte         oldcolor[4];
1491 
1492     if (pr_verbosity >= 3) OSD_Printf("PR : Masked wall %i...\n", damaskwallcnt);
1493 
1494     sec = (usectorptr_t)&sector[sectorofwall(maskwall[damaskwallcnt])];
1495     wal = &wall[maskwall[damaskwallcnt]];
1496     w = prwalls[maskwall[damaskwallcnt]];
1497 
1498     glEnable(GL_CULL_FACE);
1499 
1500     if (searchit == 2) {
1501         polymer_drawsearchplane(&w->mask, oldcolor, 0x04, (GLubyte *)&maskwall[damaskwallcnt]);
1502     } else {
1503         calc_and_apply_fog(fogshade(wal->shade, wal->pal), sec->visibility, get_floor_fogpal(sec));
1504         polymer_drawplane(&w->mask);
1505     }
1506 
1507     glDisable(GL_CULL_FACE);
1508 }
1509 
polymer_drawsprite(int32_t snum)1510 void                polymer_drawsprite(int32_t snum)
1511 {
1512     int32_t         i, j, cs;
1513     _prsprite       *s;
1514 
1515     auto const tspr = tspriteptr[snum];
1516     usectorptr_t sec;
1517 
1518     if (pr_verbosity >= 3) OSD_Printf("PR : Sprite %i...\n", snum);
1519 
1520     if (bad_tspr(tspr))
1521         return;
1522 
1523     if ((tspr->clipdist & TSPR_FLAGS_NO_SHADOW) && (depth && !mirrors[depth-1].plane))
1524         return;
1525 
1526     if ((tspr->clipdist & TSPR_FLAGS_INVISIBLE_WITH_SHADOW) && (!depth || mirrors[depth-1].plane))
1527         return;
1528 
1529     int const spritenum = tspr->owner;
1530     Bassert(spritenum < MAXSPRITES+MAXUNIQHUDID);
1531 
1532     tileUpdatePicnum(&tspr->picnum, (unsigned)spritenum < MAXSPRITES ? spritenum+32768 : 0);
1533 
1534     sec = (usectorptr_t)&sector[tspr->sectnum];
1535     calc_and_apply_fog(fogshade(tspr->shade, tspr->pal), sec->visibility, get_floor_fogpal((usectorptr_t)&sector[tspr->sectnum]));
1536 
1537     if (usemodels && tile2model[Ptile2tile(tspr->picnum,tspr->pal)].modelid >= 0 &&
1538         tile2model[Ptile2tile(tspr->picnum,tspr->pal)].framenum >= 0 &&
1539         !(spriteext[spritenum].flags & SPREXT_NOTMD))
1540     {
1541         glEnable(GL_CULL_FACE);
1542         SWITCH_CULL_DIRECTION;
1543         polymer_drawmdsprite(tspr);
1544         SWITCH_CULL_DIRECTION;
1545         glDisable(GL_CULL_FACE);
1546         return;
1547     }
1548 
1549     cs = tspr->cstat;
1550 
1551     // I think messing with the tspr is safe at this point?
1552     // If not, change that to modify a temp position in updatesprite itself.
1553     // I don't think this flags are meant to change on the fly so it'd possibly
1554     // be safe to cache a plane that has them applied.
1555     if (spriteext[spritenum].flags & SPREXT_AWAY1)
1556     {
1557         tspr->x += sintable[(tspr->ang + 512) & 2047] >> 13;
1558         tspr->y += sintable[tspr->ang & 2047] >> 13;
1559     }
1560     else if (spriteext[spritenum].flags & SPREXT_AWAY2)
1561     {
1562         tspr->x -= sintable[(tspr->ang + 512) & 2047] >> 13;
1563         tspr->y -= sintable[tspr->ang & 2047] >> 13;
1564     }
1565 
1566     polymer_updatesprite(snum);
1567 
1568     Bassert(spritenum < MAXSPRITES);
1569     s = prsprites[spritenum];
1570 
1571     if (s == NULL)
1572         return;
1573 
1574     switch ((tspr->cstat>>4) & 3)
1575     {
1576     case 1:
1577         prsectors[tspr->sectnum]->wallsproffset += 0.5f;
1578         if (!depth || mirrors[depth-1].plane)
1579             glPolygonOffset(-1.0f, -1.0f);
1580         break;
1581     case 2:
1582         prsectors[tspr->sectnum]->floorsproffset += 0.5f;
1583         if (!depth || mirrors[depth-1].plane)
1584             glPolygonOffset(-1.0f, -1.0f);
1585         break;
1586     }
1587 
1588     if ((cs & 48) == 0)
1589     {
1590         int32_t curpriority = 0;
1591 
1592         s->plane.lightcount = 0;
1593 
1594         while ((curpriority < pr_maxlightpriority) && (!depth || mirrors[depth-1].plane))
1595         {
1596             i = j = 0;
1597             while (j < lightcount)
1598             {
1599                 while (!prlights[i].flags.active)
1600                     i++;
1601 
1602                 if (prlights[i].priority != curpriority)
1603                 {
1604                     i++;
1605                     j++;
1606                     continue;
1607                 }
1608 
1609                 if (polymer_planeinlight(&s->plane, &prlights[i]))
1610                     s->plane.lights[s->plane.lightcount++] = i;
1611 
1612                 i++;
1613                 j++;
1614             }
1615             curpriority++;
1616         }
1617     }
1618 
1619     if (automapping == 1)
1620         show2dsprite[spritenum>>3] |= pow2char[spritenum&7];
1621 
1622     if ((tspr->cstat & 64) && (tspr->cstat & SPR_ALIGN_MASK))
1623     {
1624         if ((tspr->cstat & SPR_ALIGN_MASK)==SPR_FLOOR && (tspr->cstat & SPR_YFLIP))
1625             SWITCH_CULL_DIRECTION;
1626         glEnable(GL_CULL_FACE);
1627     }
1628 
1629     if ((!depth || mirrors[depth-1].plane) && !pr_ati_nodepthoffset)
1630         glEnable(GL_POLYGON_OFFSET_FILL);
1631 
1632     polymer_drawplane(&s->plane);
1633 
1634     if ((!depth || mirrors[depth-1].plane) && !pr_ati_nodepthoffset)
1635         glDisable(GL_POLYGON_OFFSET_FILL);
1636 
1637     if ((tspr->cstat & 64) && (tspr->cstat & SPR_ALIGN_MASK))
1638     {
1639         if ((tspr->cstat & SPR_ALIGN_MASK)==SPR_FLOOR && (tspr->cstat & SPR_YFLIP))
1640             SWITCH_CULL_DIRECTION;
1641         glDisable(GL_CULL_FACE);
1642     }
1643 }
1644 
polymer_setanimatesprites(animatespritesptr animatesprites,int32_t x,int32_t y,int32_t z,int32_t a,int32_t smoothratio)1645 void                polymer_setanimatesprites(animatespritesptr animatesprites, int32_t x, int32_t y, int32_t z, int32_t a, int32_t smoothratio)
1646 {
1647     asi.animatesprites = animatesprites;
1648     asi.x = x;
1649     asi.y = y;
1650     asi.z = z;
1651     asi.a = a;
1652     asi.smoothratio = smoothratio;
1653 }
1654 
polymer_addlight(_prlight * light)1655 int16_t             polymer_addlight(_prlight* light)
1656 {
1657     int32_t         lighti;
1658 
1659     if (lightcount >= PR_MAXLIGHTS || light->priority > pr_maxlightpriority || !pr_lighting)
1660         return -1;
1661 
1662     if ((light->sector == -1) || (light->sector >= numsectors))
1663         return -1;
1664 
1665     lighti = 0;
1666     while ((lighti < PR_MAXLIGHTS) && (prlights[lighti].flags.active))
1667         lighti++;
1668 
1669     if (lighti == PR_MAXLIGHTS)
1670         return -1;
1671 #if 0
1672     // Spot lights disabled on ATI cards because they cause crashes with
1673     // Catalyst 12.8 drivers.
1674     // See: http://forums.duke4.net/topic/5723-hrp-polymer-crash/
1675     if (pr_ati_fboworkaround && light->radius)
1676         return -1;
1677 #endif
1678     Bmemcpy(&prlights[lighti], light, sizeof(_prlight));
1679 
1680     if (light->radius) {
1681         polymer_processspotlight(&prlights[lighti]);
1682 
1683         // get the texture handle for the lightmap
1684         if (light->tilenum > 0) {
1685             int16_t     picnum = light->tilenum;
1686             pthtyp*     pth;
1687 
1688             tileUpdatePicnum(&picnum, 0);
1689 
1690             if (!waloff[picnum])
1691                 tileLoad(picnum);
1692 
1693             pth = NULL;
1694             pth = texcache_fetch(picnum, 0, 0, DAMETH_NOMASK);
1695 
1696             if (pth)
1697                 light->lightmap = pth->glpic;
1698         }
1699     }
1700 
1701     prlights[lighti].flags.isinview = 0;
1702     prlights[lighti].flags.active = 1;
1703 
1704     prlights[lighti].flags.invalidate = 0;
1705 
1706     prlights[lighti].planecount = 0;
1707     prlights[lighti].planelist = NULL;
1708 
1709     polymer_culllight(lighti);
1710 
1711     lightcount++;
1712 
1713     return lighti;
1714 }
1715 
polymer_deletelight(int16_t lighti)1716 void                polymer_deletelight(int16_t lighti)
1717 {
1718     if (!prlights[lighti].flags.active)
1719     {
1720 #ifdef DEBUGGINGAIDS
1721         if (pr_verbosity >= 2)
1722             OSD_Printf("PR : Called polymer_deletelight on inactive light\n");
1723         // currently known cases: when reloading maphack lights (didn't set maphacklightcnt=0
1724         // but did loadmaphack()->delete_maphack_lights() after polymer_resetlights())
1725 #endif
1726         return;
1727     }
1728 
1729     polymer_removelight(lighti);
1730 
1731     prlights[lighti].flags.active = 0;
1732 
1733     lightcount--;
1734 }
1735 
polymer_invalidatelights(void)1736 void                polymer_invalidatelights(void)
1737 {
1738     int32_t         i = PR_MAXLIGHTS-1;
1739 
1740     do
1741         prlights[i].flags.invalidate = prlights[i].flags.active;
1742     while (i--);
1743 }
1744 
polymer_texinvalidate(void)1745 void                polymer_texinvalidate(void)
1746 {
1747     int32_t         i;
1748 
1749     i = 0;
1750 
1751     while (i < MAXSPRITES) {
1752         polymer_invalidatesprite(i);
1753         i++;
1754     }
1755 
1756     i = numsectors - 1;
1757 
1758     if (!numsectors || !prsectors[i])
1759         return;
1760 
1761     do
1762         prsectors[i--]->flags.invalidtex = 1;
1763     while (i >= 0);
1764 
1765     i = numwalls - 1;
1766     do
1767         prwalls[i--]->flags.invalidtex = 1;
1768     while (i >= 0);
1769 }
1770 
polymer_definehighpalookup(char basepalnum,char palnum,char * data)1771 void                polymer_definehighpalookup(char basepalnum, char palnum, char *data)
1772 {
1773     prhighpalookups[basepalnum][palnum].data = (char *)Xmalloc(PR_HIGHPALOOKUP_DATA_SIZE);
1774 
1775     Bmemcpy(prhighpalookups[basepalnum][palnum].data, data, PR_HIGHPALOOKUP_DATA_SIZE);
1776 }
1777 
polymer_havehighpalookup(int32_t basepalnum,int32_t palnum)1778 int32_t             polymer_havehighpalookup(int32_t basepalnum, int32_t palnum)
1779 {
1780     if ((uint32_t)basepalnum >= MAXBASEPALS || (uint32_t)palnum >= MAXPALOOKUPS)
1781         return 0;
1782 
1783     return (prhighpalookups[basepalnum][palnum].data != NULL);
1784 }
1785 
polymer_setrorcallback(rorcallback callback)1786 void                polymer_setrorcallback(rorcallback callback)
1787 {
1788     prorcallback = callback;
1789 }
1790 
1791 // CORE
polymer_displayrooms(const int16_t dacursectnum)1792 static void         polymer_displayrooms(const int16_t dacursectnum)
1793 {
1794     usectorptr_t      sec;
1795     int32_t         i;
1796     int16_t         bunchnum;
1797     int16_t         ns;
1798     GLint           result;
1799     int16_t         doquery;
1800     int32_t         front;
1801     int32_t         back;
1802     GLfloat         localskymodelviewmatrix[16];
1803     GLfloat         localmodelviewmatrix[16];
1804     GLfloat         localprojectionmatrix[16];
1805     float           frustum[5 * 4];
1806     int32_t         localspritesortcnt;
1807     tspritetype     localtsprite[MAXSPRITESONSCREEN];
1808     int16_t         localmaskwall[MAXWALLSB];
1809     int16_t         localmaskwallcnt;
1810     _prmirror       mirrorlist[10];
1811     int             mirrorcount;
1812     int16_t         mirrorsect;
1813     int16_t         *localsectormasks;
1814     int16_t         *localsectormaskcount;
1815     int32_t         gx, gy, gz, px, py, pz;
1816     GLdouble        plane[4];
1817     float           coeff;
1818     float           pos[3];
1819 
1820     curmodelviewmatrix = localmodelviewmatrix;
1821     glGetFloatv(GL_MODELVIEW_MATRIX, localmodelviewmatrix);
1822     glGetFloatv(GL_PROJECTION_MATRIX, localprojectionmatrix);
1823 
1824     polymer_extractfrustum(localmodelviewmatrix, localprojectionmatrix, frustum);
1825 
1826     Bmemset(querydelay, 0, sizeof(int16_t) * numsectors);
1827     Bmemset(queryid, 0, sizeof(GLuint) * numwalls);
1828     Bmemset(drawingstate, 0, sizeof(int16_t) * numsectors);
1829 
1830     front = 0;
1831     back = 1;
1832     sectorqueue[0] = dacursectnum;
1833     drawingstate[dacursectnum] = 1;
1834 
1835     localspritesortcnt = localmaskwallcnt = 0;
1836 
1837     mirrorcount = 0;
1838 
1839     localsectormasks = (int16_t *)Xmalloc(sizeof(int16_t) * numsectors);
1840     localsectormaskcount = (int16_t *)Xcalloc(sizeof(int16_t), 1);
1841     cursectormasks = localsectormasks;
1842     cursectormaskcount = localsectormaskcount;
1843 
1844     glDisable(GL_DEPTH_TEST);
1845     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1846     polymer_drawsky(cursky, curskypal, curskyshade);
1847     glEnable(GL_DEPTH_TEST);
1848 
1849     // depth-only occlusion testing pass
1850 //     overridematerial = 0;
1851 
1852     prcanbucket = 1;
1853 
1854     while (front != back)
1855     {
1856         sec = (usectorptr_t)&sector[sectorqueue[front]];
1857 
1858         polymer_pokesector(sectorqueue[front]);
1859         polymer_drawsector(sectorqueue[front], FALSE);
1860         polymer_scansprites(sectorqueue[front], localtsprite, &localspritesortcnt);
1861 
1862         if (!depth && sec->ceilingpicnum >= r_rortexture && sec->ceilingpicnum < r_rortexture+r_rortexturerange)
1863         {
1864             mirrorlist[mirrorcount].plane = &prsectors[sectorqueue[front]]->ceil;
1865             mirrorlist[mirrorcount].sectnum = sectorqueue[front];
1866             mirrorlist[mirrorcount].wallnum = -1;
1867             mirrorlist[mirrorcount].rorstat = 1;
1868             mirrorcount++;
1869         }
1870 
1871         if (!depth && sec->floorpicnum >= r_rortexture && sec->floorpicnum < r_rortexture+r_rortexturerange)
1872         {
1873             mirrorlist[mirrorcount].plane = &prsectors[sectorqueue[front]]->floor;
1874             mirrorlist[mirrorcount].sectnum = sectorqueue[front];
1875             mirrorlist[mirrorcount].rorstat = 2;
1876             mirrorcount++;
1877         }
1878 
1879         doquery = 0;
1880 
1881         i = sec->wallnum-1;
1882         do
1883         {
1884             // if we have a level boundary somewhere in the sector,
1885             // consider these walls as visportals
1886             if (wall[sec->wallptr + i].nextsector < 0 && pr_buckets == 0)
1887                 doquery = 1;
1888         }
1889         while (--i >= 0);
1890 
1891         i = sec->wallnum-1;
1892         while (i >= 0)
1893         {
1894             if ((wall[sec->wallptr + i].nextsector >= 0) &&
1895                 (wallvisible(globalposx, globalposy, sec->wallptr + i)) &&
1896                 (polymer_planeinfrustum(&prwalls[sec->wallptr + i]->mask, frustum)))
1897             {
1898                 if ((prwalls[sec->wallptr + i]->mask.vertcount == 4) &&
1899                     !(prwalls[sec->wallptr + i]->underover & 4) &&
1900                     !(prwalls[sec->wallptr + i]->underover & 8))
1901                 {
1902                     // early exit for closed sectors
1903                     _prwall         *w;
1904 
1905                     w = prwalls[sec->wallptr + i];
1906 
1907                     if ((w->mask.buffer[0].y >= w->mask.buffer[3].y) &&
1908                         (w->mask.buffer[1].y >= w->mask.buffer[2].y))
1909                     {
1910                         i--;
1911                         continue;
1912                     }
1913                 }
1914 
1915                 if ((wall[sec->wallptr + i].cstat & 48) == 16)
1916                 {
1917                     int pic = wall[sec->wallptr + i].overpicnum;
1918 
1919                     if (tilesiz[pic].x > 0 && tilesiz[pic].y > 0)
1920                         localmaskwall[localmaskwallcnt++] = sec->wallptr + i;
1921                 }
1922 
1923                 if (!depth && (overridematerial & prprogrambits[PR_BIT_MIRROR_MAP].bit) &&
1924                      wall[sec->wallptr + i].overpicnum == 560 &&
1925                      wall[sec->wallptr + i].cstat & 32)
1926                 {
1927                     mirrorlist[mirrorcount].plane = &prwalls[sec->wallptr + i]->mask;
1928                     mirrorlist[mirrorcount].sectnum = sectorqueue[front];
1929                     mirrorlist[mirrorcount].wallnum = sec->wallptr + i;
1930                     mirrorlist[mirrorcount].rorstat = 0;
1931                     mirrorcount++;
1932                 }
1933 
1934                 if (!depth && (overridematerial & prprogrambits[PR_BIT_MIRROR_MAP].bit) &&
1935                      wall[sec->wallptr + i].picnum >= r_rortexture && wall[sec->wallptr + i].picnum < r_rortexture + r_rortexturerange)
1936                 {
1937                     mirrorlist[mirrorcount].plane = &prwalls[sec->wallptr + i]->wall;
1938                     mirrorlist[mirrorcount].sectnum = sectorqueue[front];
1939                     mirrorlist[mirrorcount].wallnum = sec->wallptr + i;
1940                     mirrorlist[mirrorcount].rorstat = 0;
1941                     mirrorcount++;
1942                 }
1943 
1944                 if (!(wall[sec->wallptr + i].cstat & 32)) {
1945                     if (doquery && (!drawingstate[wall[sec->wallptr + i].nextsector]))
1946                     {
1947                         float pos[3], sqdist;
1948                         int32_t oldoverridematerial;
1949 
1950                         pos[0] = fglobalposy;
1951                         pos[1] = fglobalposz * (-1.f/16.f);
1952                         pos[2] = -fglobalposx;
1953 
1954                         sqdist = prwalls[sec->wallptr + i]->mask.plane[0] * pos[0] +
1955                                  prwalls[sec->wallptr + i]->mask.plane[1] * pos[1] +
1956                                  prwalls[sec->wallptr + i]->mask.plane[2] * pos[2] +
1957                                  prwalls[sec->wallptr + i]->mask.plane[3];
1958 
1959                         // hack to avoid occlusion querying portals that are too close to the viewpoint
1960                         // this is needed because of the near z-clipping plane;
1961                         if (sqdist < 100)
1962                             queryid[sec->wallptr + i] = 0xFFFFFFFF;
1963                         else {
1964                             _prwall         *w;
1965 
1966                             w = prwalls[sec->wallptr + i];
1967 
1968                             glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1969                             glDepthMask(GL_FALSE);
1970 
1971                             glGenQueries(1, &queryid[sec->wallptr + i]);
1972                             glBeginQuery(GL_SAMPLES_PASSED, queryid[sec->wallptr + i]);
1973 
1974                             oldoverridematerial = overridematerial;
1975                             overridematerial = 0;
1976 
1977                             if ((w->underover & 4) && (w->underover & 1))
1978                                 polymer_drawplane(&w->wall);
1979                             polymer_drawplane(&w->mask);
1980                             if ((w->underover & 8) && (w->underover & 2))
1981                                 polymer_drawplane(&w->over);
1982 
1983                             overridematerial = oldoverridematerial;
1984 
1985                             glEndQuery(GL_SAMPLES_PASSED);
1986 
1987                             glDepthMask(GL_TRUE);
1988                             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1989                         }
1990                     } else
1991                         queryid[sec->wallptr + i] = 0xFFFFFFFF;
1992                 }
1993             }
1994 
1995             i--;
1996         }
1997 
1998         // Cram as much CPU or GPU work as we can between queuing the
1999         // occlusion queries and reaping them.
2000         i = sec->wallnum-1;
2001         do
2002         {
2003             if (wallvisible(globalposx, globalposy, sec->wallptr + i))
2004                 polymer_drawwall(sectorqueue[front], sec->wallptr + i);
2005         }
2006         while (--i >= 0);
2007 #ifdef YAX_ENABLE
2008         // queue ROR neighbors
2009         if ((bunchnum = yax_getbunch(sectorqueue[front], YAX_FLOOR)) >= 0) {
2010 
2011             for (SECTORS_OF_BUNCH(bunchnum, YAX_CEILING, ns)) {
2012 
2013                 if (ns >= 0 && !drawingstate[ns] &&
2014                     polymer_planeinfrustum(&prsectors[ns]->ceil, frustum)) {
2015 
2016                     sectorqueue[back++] = ns;
2017                     drawingstate[ns] = 1;
2018                 }
2019             }
2020         }
2021 
2022         if ((bunchnum = yax_getbunch(sectorqueue[front], YAX_CEILING)) >= 0) {
2023 
2024             for (SECTORS_OF_BUNCH(bunchnum, YAX_FLOOR, ns)) {
2025 
2026                 if (ns >= 0 && !drawingstate[ns] &&
2027                     polymer_planeinfrustum(&prsectors[ns]->floor, frustum)) {
2028 
2029                     sectorqueue[back++] = ns;
2030                     drawingstate[ns] = 1;
2031                 }
2032             }
2033         }
2034 #endif
2035         i = sec->wallnum-1;
2036         do
2037         {
2038             if ((queryid[sec->wallptr + i]) &&
2039                 (!drawingstate[wall[sec->wallptr + i].nextsector]))
2040             {
2041                 // REAP
2042                 result = 0;
2043                 if (doquery && (queryid[sec->wallptr + i] != 0xFFFFFFFF))
2044                 {
2045                     glGetQueryObjectiv(queryid[sec->wallptr + i],
2046                                            GL_QUERY_RESULT,
2047                                            &result);
2048                     glDeleteQueries(1, &queryid[sec->wallptr + i]);
2049                 } else if (queryid[sec->wallptr + i] == 0xFFFFFFFF)
2050                     result = 1;
2051 
2052                 queryid[sec->wallptr + i] = 0;
2053 
2054                 if (result || !doquery)
2055                 {
2056                     sectorqueue[back++] = wall[sec->wallptr + i].nextsector;
2057                     drawingstate[wall[sec->wallptr + i].nextsector] = 1;
2058                 }
2059             } else if (queryid[sec->wallptr + i] &&
2060                        queryid[sec->wallptr + i] != 0xFFFFFFFF)
2061             {
2062                 glDeleteQueries(1, &queryid[sec->wallptr + i]);
2063                 queryid[sec->wallptr + i] = 0;
2064             }
2065         }
2066         while (--i >= 0);
2067 
2068         front++;
2069     }
2070 
2071     polymer_emptybuckets();
2072 
2073     // do the actual shaded drawing
2074 //     overridematerial = 0xFFFFFFFF;
2075 
2076     // go through the sector queue again
2077 //     front = 0;
2078 //     while (front < back)
2079 //     {
2080 //         sec = &sector[sectorqueue[front]];
2081 //
2082 //         polymer_drawsector(sectorqueue[front]);
2083 //
2084 //         i = 0;
2085 //         while (i < sec->wallnum)
2086 //         {
2087 //             polymer_drawwall(sectorqueue[front], sec->wallptr + i);
2088 //
2089 //             i++;
2090 //         }
2091 //
2092 //         front++;
2093 //     }
2094 
2095     i = mirrorcount-1;
2096     while (i >= 0)
2097     {
2098         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[0].fbo);
2099         glPushAttrib(GL_VIEWPORT_BIT);
2100         glViewport(windowxy1.x, ydim-(windowxy2.y+1),windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
2101 
2102         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2103 
2104         Bmemcpy(localskymodelviewmatrix, curskymodelviewmatrix, sizeof(GLfloat) * 16);
2105         curskymodelviewmatrix = localskymodelviewmatrix;
2106 
2107         glMatrixMode(GL_MODELVIEW);
2108         glPushMatrix();
2109 
2110         plane[0] = mirrorlist[i].plane->plane[0];
2111         plane[1] = mirrorlist[i].plane->plane[1];
2112         plane[2] = mirrorlist[i].plane->plane[2];
2113         plane[3] = mirrorlist[i].plane->plane[3];
2114 
2115         glClipPlane(GL_CLIP_PLANE0, plane);
2116 
2117         if (mirrorlist[i].rorstat == 0)
2118         {
2119             polymer_inb4mirror(mirrorlist[i].plane->buffer, mirrorlist[i].plane->plane);
2120             SWITCH_CULL_DIRECTION;
2121         }
2122         //glEnable(GL_CLIP_PLANE0);
2123 
2124         if (mirrorlist[i].rorstat == 0 && mirrorlist[i].wallnum >= 0)
2125             renderPrepareMirror(globalposx, globalposy, globalposz, qglobalang, qglobalhoriz,
2126                                 mirrorlist[i].wallnum, &gx, &gy, &viewangle);
2127 
2128         gx = globalposx;
2129         gy = globalposy;
2130         gz = globalposz;
2131 
2132         if (mirrorlist[i].rorstat == 0)
2133         {
2134             // map the player pos from build to polymer
2135             px = globalposy;
2136             py = -globalposz / 16;
2137             pz = -globalposx;
2138 
2139             // calculate new player position on the other side of the mirror
2140             // this way the basic build visibility shit can be used (wallvisible)
2141             coeff = mirrorlist[i].plane->plane[0] * px +
2142                     mirrorlist[i].plane->plane[1] * py +
2143                     mirrorlist[i].plane->plane[2] * pz +
2144                     mirrorlist[i].plane->plane[3];
2145 
2146             coeff /= (float)(mirrorlist[i].plane->plane[0] * mirrorlist[i].plane->plane[0] +
2147                              mirrorlist[i].plane->plane[1] * mirrorlist[i].plane->plane[1] +
2148                              mirrorlist[i].plane->plane[2] * mirrorlist[i].plane->plane[2]);
2149 
2150             px = (int32_t)(-coeff*mirrorlist[i].plane->plane[0]*2 + px);
2151             py = (int32_t)(-coeff*mirrorlist[i].plane->plane[1]*2 + py);
2152             pz = (int32_t)(-coeff*mirrorlist[i].plane->plane[2]*2 + pz);
2153 
2154             // map back from polymer to build
2155             set_globalpos(-pz, px, -py * 16);
2156 
2157             mirrorsect = mirrorlist[i].sectnum;
2158         }
2159         else
2160         {
2161             // map the player pos from build to polymer
2162             px = globalposx;
2163             py = globalposy;
2164             pz = globalposz;
2165 
2166             mirrorsect = mirrorlist[i].sectnum;
2167 
2168             if (prorcallback)
2169                 prorcallback(mirrorlist[i].sectnum, mirrorlist[i].wallnum, mirrorlist[i].rorstat, &mirrorsect, &px, &py, &pz);
2170 
2171             pos[0] = (py-gy);
2172             pos[1] = -(pz-gz)/16.f;
2173             pos[2] = -(px-gx);
2174 
2175             glTranslatef(-pos[0], -pos[1], -pos[2]);
2176 
2177             glPushMatrix();
2178             glLoadMatrixf(curskymodelviewmatrix);
2179             glTranslatef(-pos[0], -pos[1], -pos[2]);
2180             glGetFloatv(GL_MODELVIEW_MATRIX, curskymodelviewmatrix);
2181             glPopMatrix();
2182 
2183             set_globalpos(px, py, pz);
2184         }
2185 
2186         mirrors[depth++] = mirrorlist[i];
2187         polymer_displayrooms(mirrorsect);
2188         depth--;
2189 
2190         cursectormasks = localsectormasks;
2191         cursectormaskcount = localsectormaskcount;
2192 
2193         set_globalpos(gx, gy, gz);
2194 
2195         glDisable(GL_CLIP_PLANE0);
2196         if (mirrorlist[i].rorstat == 0)
2197             SWITCH_CULL_DIRECTION;
2198         glMatrixMode(GL_MODELVIEW);
2199         glPopMatrix();
2200 
2201         glPopAttrib();
2202         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2203 
2204         mirrorlist[i].plane->material.mirrormap = prrts[0].color;
2205         polymer_drawplane(mirrorlist[i].plane);
2206         mirrorlist[i].plane->material.mirrormap = 0;
2207 
2208         i--;
2209     }
2210 
2211     spritesortcnt = localspritesortcnt;
2212     Bmemcpy(tsprite, localtsprite, sizeof(tspritetype) * spritesortcnt);
2213     maskwallcnt = localmaskwallcnt;
2214     Bmemcpy(maskwall, localmaskwall, sizeof(int16_t) * maskwallcnt);
2215 
2216     if (depth)
2217     {
2218         set_globalang(viewangle);
2219 
2220         if (mirrors[depth - 1].plane)
2221             display_mirror = 1;
2222         polymer_animatesprites();
2223         if (mirrors[depth - 1].plane)
2224             display_mirror = 0;
2225 
2226         glDisable(GL_CULL_FACE);
2227         renderDrawMasks();
2228         glEnable(GL_CULL_FACE);
2229     }
2230     }
2231 
polymer_emptybuckets(void)2232 static void         polymer_emptybuckets(void)
2233 {
2234     _prbucket *bucket = prbuckethead;
2235 
2236     if (pr_buckets == 0)
2237         return;
2238 
2239     glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
2240     glVertexPointer(3, GL_FLOAT, sizeof(_prvert), NULL);
2241     glTexCoordPointer(2, GL_FLOAT, sizeof(_prvert), (GLvoid *)(3 * sizeof(GLfloat)));
2242 
2243     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prindexringvbo);
2244 
2245     uint32_t indexcount = 0;
2246     while (bucket != NULL)
2247     {
2248         indexcount += bucket->count;
2249 
2250         bucket = bucket->next;
2251     }
2252 
2253     // ensure space in index ring, wrap otherwise
2254     if (indexcount + prindexringoffset >= (unsigned)prindexringsize)
2255     {
2256         glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
2257         prindexring = (GLuint *)glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, prindexringsize * sizeof(GLuint), GL_MAP_INVALIDATE_BUFFER_BIT | prindexringmapflags);
2258         prindexringoffset = 0;
2259     }
2260 
2261     // put indices in the ring, all at once
2262     bucket = prbuckethead;
2263 
2264     while (bucket != NULL)
2265     {
2266         if (bucket->count == 0)
2267         {
2268             bucket = bucket->next;
2269             continue;
2270         }
2271 
2272         memcpy(&prindexring[prindexringoffset], bucket->indices, bucket->count * sizeof(GLuint));
2273 
2274         bucket->indiceoffset = (GLuint*)(prindexringoffset * sizeof(GLuint));
2275 
2276         prindexringoffset += bucket->count;
2277 
2278         bucket = bucket->next;
2279     }
2280 
2281     bucket = prbuckethead;
2282 
2283     while (bucket != NULL)
2284     {
2285         if (bucket->count == 0)
2286         {
2287             bucket = bucket->next;
2288             continue;
2289         }
2290 
2291         int32_t materialbits = polymer_bindmaterial(&bucket->material, NULL, 0);
2292 
2293         glDrawElements(GL_TRIANGLES, bucket->count, GL_UNSIGNED_INT, bucket->indiceoffset);
2294 
2295         polymer_unbindmaterial(materialbits);
2296 
2297         bucket->count = 0;
2298 
2299         bucket = bucket->next;
2300     }
2301 
2302     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2303     glBindBuffer(GL_ARRAY_BUFFER, 0);
2304 
2305     prcanbucket = 0;
2306 }
2307 
2308 static hashtable_t h_buckets      = { 2048, NULL };
2309 
polymer_findbucket(int16_t tilenum,char pal)2310 static _prbucket*   polymer_findbucket(int16_t tilenum, char pal)
2311 {
2312     char propstr[16];
2313 
2314     Bsprintf(propstr, "%d_%d", tilenum, pal);
2315 
2316     _prbucket *bucketptr = prbuckethead ? (_prbucket *)hash_find(&h_buckets, propstr) : NULL;
2317 
2318     // find bucket
2319 
2320     // no buckets or no bucket found, create one
2321     if (bucketptr == NULL || (intptr_t)bucketptr == -1)
2322     {
2323         bucketptr = (_prbucket *)Xmalloc(sizeof (_prbucket));
2324 
2325         if (h_buckets.items == NULL)
2326             hash_init(&h_buckets);
2327 
2328         // insert, since most likely to use same pattern next frame
2329         // will need to reorder by MRU first every once in a while
2330         // or move to hashing lookup
2331         bucketptr->next = prbuckethead;
2332         prbuckethead = bucketptr;
2333 
2334         bucketptr->tilenum = tilenum;
2335         bucketptr->pal = pal;
2336 
2337         bucketptr->invalidmaterial = 1;
2338 
2339         bucketptr->count = 0;
2340         bucketptr->buffersize = 1024;
2341         bucketptr->indices = (GLuint *)Xmalloc(bucketptr->buffersize * sizeof(GLuint));
2342 
2343         hash_add(&h_buckets, propstr, (intptr_t)bucketptr, 1);
2344     }
2345 
2346     return bucketptr;
2347 }
2348 
polymer_bucketplane(_prplane * plane)2349 static void         polymer_bucketplane(_prplane* plane)
2350 {
2351     _prbucket *bucketptr = plane->bucket;
2352     uint32_t neededindicecount;
2353     int32_t i;
2354 
2355     // we don't keep buffers for quads
2356     neededindicecount = (plane->indicescount == 0) ? 6 : plane->indicescount;
2357 
2358     // ensure size
2359     while (bucketptr->count + neededindicecount >= bucketptr->buffersize)
2360     {
2361         bucketptr->buffersize *= 2;
2362         bucketptr->indices = (GLuint *)Xrealloc(bucketptr->indices, bucketptr->buffersize * sizeof(GLuint));
2363     }
2364 
2365     // queue indices
2366     i = 0;
2367 
2368     if (plane->indicescount > 0)
2369     {
2370         while (i < plane->indicescount)
2371         {
2372             bucketptr->indices[bucketptr->count] = plane->indices[i] + plane->mapvbo_vertoffset;
2373             bucketptr->count++;
2374             i++;
2375         }
2376     }
2377     else
2378     {
2379         static const uint32_t quadindices[6] = { 0, 1, 2, 0, 2, 3 };
2380 
2381         while (i < 6)
2382         {
2383             bucketptr->indices[bucketptr->count] = quadindices[i] + plane->mapvbo_vertoffset;
2384             bucketptr->count++;
2385             i++;
2386         }
2387     }
2388 }
2389 
polymer_drawplane(_prplane * plane)2390 static void         polymer_drawplane(_prplane* plane)
2391 {
2392     int32_t         materialbits;
2393 
2394     if (pr_nullrender >= 1) return;
2395 
2396     // debug code for drawing plane inverse TBN
2397 //     glDisable(GL_TEXTURE_2D);
2398 //     glBegin(GL_LINES);
2399 //     glColor4f(1.0, 0.0, 0.0, 1.0);
2400 //     glVertex3f(plane->buffer[0],
2401 //                 plane->buffer[1],
2402 //                 plane->buffer[2]);
2403 //     glVertex3f(plane->buffer[0] + plane->t[0] * 50,
2404 //                 plane->buffer[1] + plane->t[1] * 50,
2405 //                 plane->buffer[2] + plane->t[2] * 50);
2406 //     glColor4f(0.0, 1.0, 0.0, 1.0);
2407 //     glVertex3f(plane->buffer[0],
2408 //                 plane->buffer[1],
2409 //                 plane->buffer[2]);
2410 //     glVertex3f(plane->buffer[0] + plane->b[0] * 50,
2411 //                 plane->buffer[1] + plane->b[1] * 50,
2412 //                 plane->buffer[2] + plane->b[2] * 50);
2413 //     glColor4f(0.0, 0.0, 1.0, 1.0);
2414 //     glVertex3f(plane->buffer[0],
2415 //                 plane->buffer[1],
2416 //                 plane->buffer[2]);
2417 //     glVertex3f(plane->buffer[0] + plane->n[0] * 50,
2418 //                 plane->buffer[1] + plane->n[1] * 50,
2419 //                 plane->buffer[2] + plane->n[2] * 50);
2420 //     glEnd();
2421 //     glEnable(GL_TEXTURE_2D);
2422 
2423     // debug code for drawing plane normals
2424 //     glDisable(GL_TEXTURE_2D);
2425 //     glBegin(GL_LINES);
2426 //     glColor4f(1.0, 1.0, 1.0, 1.0);
2427 //     glVertex3f(plane->buffer[0],
2428 //                 plane->buffer[1],
2429 //                 plane->buffer[2]);
2430 //     glVertex3f(plane->buffer[0] + plane->plane[0] * 50,
2431 //                 plane->buffer[1] + plane->plane[1] * 50,
2432 //                 plane->buffer[2] + plane->plane[2] * 50);
2433 //     glEnd();
2434 //     glEnable(GL_TEXTURE_2D);
2435 
2436     if (pr_buckets && pr_vbos > 0 && prcanbucket && plane->bucket)
2437     {
2438         polymer_bucketplane(plane);
2439         return;
2440     }
2441 
2442     glNormal3f((float)(plane->plane[0]), (float)(plane->plane[1]), (float)(plane->plane[2]));
2443 
2444     GLuint planevbo;
2445     GLintptr geomfbooffset;
2446 
2447     if (plane->mapvbo_vertoffset != (uint32_t)-1)
2448     {
2449         planevbo = prmapvbo;
2450         geomfbooffset = plane->mapvbo_vertoffset * sizeof(_prvert);
2451     }
2452     else
2453     {
2454         planevbo = plane->vbo;
2455         geomfbooffset = 0;
2456     }
2457 
2458     if (planevbo && (pr_vbos > 0))
2459     {
2460         glBindBuffer(GL_ARRAY_BUFFER, planevbo);
2461         glVertexPointer(3, GL_FLOAT, sizeof(_prvert), (GLvoid *)(geomfbooffset));
2462         glTexCoordPointer(2, GL_FLOAT, sizeof(_prvert), (GLvoid *)(geomfbooffset + (3 * sizeof(GLfloat))));
2463         if (plane->indices)
2464             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane->ivbo);
2465     } else {
2466         glVertexPointer(3, GL_FLOAT, sizeof(_prvert), &plane->buffer->x);
2467         glTexCoordPointer(2, GL_FLOAT, sizeof(_prvert), &plane->buffer->u);
2468     }
2469 
2470     curlight = 0;
2471     do {
2472         materialbits = polymer_bindmaterial(&plane->material, plane->lights, plane->lightcount);
2473 
2474         if (materialbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
2475         {
2476             glVertexAttrib3fv(prprograms[materialbits].attrib_T, &plane->tbn[0][0]);
2477             glVertexAttrib3fv(prprograms[materialbits].attrib_B, &plane->tbn[1][0]);
2478             glVertexAttrib3fv(prprograms[materialbits].attrib_N, &plane->tbn[2][0]);
2479         }
2480 
2481         if (plane->indices)
2482         {
2483             if (planevbo && (pr_vbos > 0))
2484                 glDrawElements(GL_TRIANGLES, plane->indicescount, GL_UNSIGNED_SHORT, NULL);
2485             else
2486                 glDrawElements(GL_TRIANGLES, plane->indicescount, GL_UNSIGNED_SHORT, plane->indices);
2487         } else
2488             glDrawArrays(GL_QUADS, 0, 4);
2489 
2490         polymer_unbindmaterial(materialbits);
2491 
2492         if (plane->lightcount && (!depth || mirrors[depth-1].plane))
2493             prlights[plane->lights[curlight]].flags.isinview = 1;
2494 
2495         curlight++;
2496     } while ((curlight < plane->lightcount) && (curlight < pr_maxlightpasses) && (!depth || mirrors[depth-1].plane));
2497 
2498     if (planevbo && (pr_vbos > 0))
2499     {
2500         glBindBuffer(GL_ARRAY_BUFFER, 0);
2501         if (plane->indices)
2502             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2503     }
2504 }
2505 
polymer_inb4mirror(_prvert * buffer,const GLfloat * plane)2506 static inline void  polymer_inb4mirror(_prvert* buffer, const GLfloat* plane)
2507 {
2508     float           pv;
2509     float           reflectionmatrix[16];
2510 
2511     pv = buffer->x * plane[0] +
2512          buffer->y * plane[1] +
2513          buffer->z * plane[2];
2514 
2515     reflectionmatrix[0] = 1 - (2 * plane[0] * plane[0]);
2516     reflectionmatrix[1] = -2 * plane[0] * plane[1];
2517     reflectionmatrix[2] = -2 * plane[0] * plane[2];
2518     reflectionmatrix[3] = 0;
2519 
2520     reflectionmatrix[4] = -2 * plane[0] * plane[1];
2521     reflectionmatrix[5] = 1 - (2 * plane[1] * plane[1]);
2522     reflectionmatrix[6] = -2 * plane[1] * plane[2];
2523     reflectionmatrix[7] = 0;
2524 
2525     reflectionmatrix[8] = -2 * plane[0] * plane[2];
2526     reflectionmatrix[9] = -2 * plane[1] * plane[2];
2527     reflectionmatrix[10] = 1 - (2 * plane[2] * plane[2]);
2528     reflectionmatrix[11] = 0;
2529 
2530     reflectionmatrix[12] = 2 * pv * plane[0];
2531     reflectionmatrix[13] = 2 * pv * plane[1];
2532     reflectionmatrix[14] = 2 * pv * plane[2];
2533     reflectionmatrix[15] = 1;
2534 
2535     glMultMatrixf(reflectionmatrix);
2536 
2537     glPushMatrix();
2538     glLoadMatrixf(curskymodelviewmatrix);
2539     glMultMatrixf(reflectionmatrix);
2540     glGetFloatv(GL_MODELVIEW_MATRIX, curskymodelviewmatrix);
2541     glPopMatrix();
2542 }
2543 
polymer_animatesprites(void)2544 static void         polymer_animatesprites(void)
2545 {
2546     if (asi.animatesprites)
2547         asi.animatesprites(globalposx, globalposy, globalposz, fix16_to_int(viewangle), asi.smoothratio);
2548 }
2549 
polymer_freeboard(void)2550 static void         polymer_freeboard(void)
2551 {
2552     int32_t         i;
2553 
2554     i = 0;
2555     while (i < MAXSECTORS)
2556     {
2557         if (prsectors[i])
2558         {
2559             Xfree(prsectors[i]->verts);
2560             Xfree(prsectors[i]->floor.buffer);
2561             Xfree(prsectors[i]->ceil.buffer);
2562             Xfree(prsectors[i]->floor.indices);
2563             Xfree(prsectors[i]->ceil.indices);
2564             if (prsectors[i]->ceil.vbo) glDeleteBuffers(1, &prsectors[i]->ceil.vbo);
2565             if (prsectors[i]->ceil.ivbo) glDeleteBuffers(1, &prsectors[i]->ceil.ivbo);
2566             if (prsectors[i]->floor.vbo) glDeleteBuffers(1, &prsectors[i]->floor.vbo);
2567             if (prsectors[i]->floor.ivbo) glDeleteBuffers(1, &prsectors[i]->floor.ivbo);
2568 
2569             DO_FREE_AND_NULL(prsectors[i]);
2570         }
2571 
2572         i++;
2573     }
2574 
2575     i = 0;
2576     while (i < MAXWALLS)
2577     {
2578         if (prwalls[i])
2579         {
2580             Xfree(prwalls[i]->bigportal);
2581             Xfree(prwalls[i]->mask.buffer);
2582             Xfree(prwalls[i]->over.buffer);
2583             // Xfree(prwalls[i]->cap);
2584             Xfree(prwalls[i]->wall.buffer);
2585             if (prwalls[i]->wall.vbo) glDeleteBuffers(1, &prwalls[i]->wall.vbo);
2586             if (prwalls[i]->over.vbo) glDeleteBuffers(1, &prwalls[i]->over.vbo);
2587             if (prwalls[i]->mask.vbo) glDeleteBuffers(1, &prwalls[i]->mask.vbo);
2588             if (prwalls[i]->stuffvbo) glDeleteBuffers(1, &prwalls[i]->stuffvbo);
2589 
2590             DO_FREE_AND_NULL(prwalls[i]);
2591         }
2592 
2593         i++;
2594     }
2595 
2596     i = 0;
2597     while (i < MAXSPRITES)
2598     {
2599         if (prsprites[i])
2600         {
2601             Xfree(prsprites[i]->plane.buffer);
2602             if (prsprites[i]->plane.vbo) glDeleteBuffers(1, &prsprites[i]->plane.vbo);
2603             DO_FREE_AND_NULL(prsprites[i]);
2604         }
2605 
2606         i++;
2607     }
2608 
2609     i = 0;
2610     while (i < MAXTILES)
2611     {
2612         polymer_invalidateartmap(i);
2613         i++;
2614     }
2615 
2616     i = 0;
2617     while (i < MAXBASEPALS)
2618     {
2619         if (prbasepalmaps[i])
2620         {
2621             glDeleteTextures(1, &prbasepalmaps[i]);
2622             prbasepalmaps[i] = 0;
2623         }
2624 
2625         i++;
2626     }
2627 
2628     i = 0;
2629     while (i < MAXPALOOKUPS)
2630     {
2631         if (prlookups[i])
2632         {
2633             glDeleteTextures(1, &prlookups[i]);
2634             prlookups[i] = 0;
2635         }
2636 
2637         i++;
2638     }
2639 }
2640 
2641 // SECTORS
polymer_initsector(int16_t sectnum)2642 static int32_t      polymer_initsector(int16_t sectnum)
2643 {
2644     usectorptr_t sec;
2645     _prsector*      s;
2646 
2647     if (pr_verbosity >= 2) OSD_Printf("PR : Initializing sector %i...\n", sectnum);
2648 
2649     sec = (usectorptr_t)&sector[sectnum];
2650     s = (_prsector *)Xcalloc(1, sizeof(_prsector));
2651 
2652     s->verts = (GLdouble *)Xcalloc(sec->wallnum, sizeof(GLdouble) * 3);
2653     s->floor.buffer = (_prvert *)Xcalloc(sec->wallnum, sizeof(_prvert));
2654     s->floor.vertcount = sec->wallnum;
2655     s->ceil.buffer = (_prvert *)Xcalloc(sec->wallnum, sizeof(_prvert));
2656     s->ceil.vertcount = sec->wallnum;
2657 
2658     glGenBuffers(1, &s->floor.vbo);
2659     glGenBuffers(1, &s->ceil.vbo);
2660     glGenBuffers(1, &s->floor.ivbo);
2661     glGenBuffers(1, &s->ceil.ivbo);
2662 
2663     glBindBuffer(GL_ARRAY_BUFFER, s->floor.vbo);
2664     glBufferData(GL_ARRAY_BUFFER, sec->wallnum * sizeof(GLfloat) * 5, NULL, mapvbousage);
2665 
2666     glBindBuffer(GL_ARRAY_BUFFER, s->ceil.vbo);
2667     glBufferData(GL_ARRAY_BUFFER, sec->wallnum * sizeof(GLfloat) * 5, NULL, mapvbousage);
2668 
2669     glBindBuffer(GL_ARRAY_BUFFER, 0);
2670 
2671     s->flags.empty = 1; // let updatesector know that everything needs to go
2672 
2673     prsectors[sectnum] = s;
2674 
2675     if (pr_verbosity >= 2) OSD_Printf("PR : Initialized sector %i.\n", sectnum);
2676 
2677     return 1;
2678 }
2679 
polymer_updatesector(int16_t sectnum)2680 static int32_t      polymer_updatesector(int16_t sectnum)
2681 {
2682     _prsector*      s;
2683     usectorptr_t sec;
2684     walltype        *wal;
2685     int32_t         i, j;
2686     int32_t         ceilz, florz;
2687     int32_t         tex, tey, heidiff;
2688     float           secangcos, secangsin, scalecoef, xpancoef, ypancoef;
2689     int32_t         ang, needfloor, wallinvalidate;
2690     int16_t         curstat, curpicnum, floorpicnum, ceilingpicnum;
2691     char            curxpanning, curypanning;
2692     _prvert*        curbuffer;
2693 
2694     if (pr_nullrender >= 3) return 0;
2695 
2696     s = prsectors[sectnum];
2697     sec = (usectorptr_t)&sector[sectnum];
2698 
2699     secangcos = secangsin = 2;
2700 
2701     if (s == NULL)
2702     {
2703         if (pr_verbosity >= 1) OSD_Printf("PR : Can't update uninitialized sector %i.\n", sectnum);
2704         return -1;
2705     }
2706 
2707     needfloor = wallinvalidate = 0;
2708 
2709     // geometry
2710     wal = &wall[sec->wallptr];
2711     i = 0;
2712     while (i < sec->wallnum)
2713     {
2714         if ((-wal->x != s->verts[(i*3)+2]))
2715         {
2716             s->verts[(i*3)+2] = s->floor.buffer[i].z = s->ceil.buffer[i].z = -(float)wal->x;
2717             needfloor = wallinvalidate = 1;
2718         }
2719         if ((wal->y != s->verts[i*3]))
2720         {
2721             s->verts[i*3] = s->floor.buffer[i].x = s->ceil.buffer[i].x = (float)wal->y;
2722             needfloor = wallinvalidate = 1;
2723         }
2724 
2725         i++;
2726         wal = &wall[sec->wallptr + i];
2727     }
2728 
2729     if ((s->flags.empty) ||
2730             needfloor ||
2731             (sec->floorz != s->floorz) ||
2732             (sec->ceilingz != s->ceilingz) ||
2733             (sec->floorheinum != s->floorheinum) ||
2734             (sec->ceilingheinum != s->ceilingheinum))
2735     {
2736         wallinvalidate = 1;
2737 
2738         wal = &wall[sec->wallptr];
2739         i = 0;
2740         while (i < sec->wallnum)
2741         {
2742             getzsofslope(sectnum, wal->x, wal->y, &ceilz, &florz);
2743             s->floor.buffer[i].y = -(float)(florz) / 16.0f;
2744             s->ceil.buffer[i].y = -(float)(ceilz) / 16.0f;
2745 
2746             i++;
2747             wal = &wall[sec->wallptr + i];
2748         }
2749 
2750         s->floorz = sec->floorz;
2751         s->ceilingz = sec->ceilingz;
2752         s->floorheinum = sec->floorheinum;
2753         s->ceilingheinum = sec->ceilingheinum;
2754     }
2755     else if (sec->visibility != s->visibility)
2756         wallinvalidate = 1;
2757 
2758     floorpicnum = sec->floorpicnum;
2759     tileUpdatePicnum(&floorpicnum, sectnum);
2760     ceilingpicnum = sec->ceilingpicnum;
2761     tileUpdatePicnum(&ceilingpicnum, sectnum);
2762 
2763     if ((!s->flags.empty) && (!needfloor) &&
2764             (floorpicnum == s->floorpicnum_anim) &&
2765             (ceilingpicnum == s->ceilingpicnum_anim) &&
2766 #ifdef USE_STRUCT_TRACKERS
2767             (s->trackedrev == sectorchanged[sectnum]))
2768 #else
2769             !Bmemcmp(&s->ceilingstat, &sec->ceilingstat, offsetof(sectortype, visibility) - offsetof(sectortype, ceilingstat)))
2770 #endif
2771         goto attributes;
2772 
2773     wal = &wall[sec->wallptr];
2774     i = 0;
2775     while (i < sec->wallnum)
2776     {
2777         j = 2;
2778         curstat = sec->floorstat;
2779         curbuffer = s->floor.buffer;
2780         curpicnum = floorpicnum;
2781         curxpanning = sec->floorxpanning;
2782         curypanning = sec->floorypanning;
2783 
2784         while (j)
2785         {
2786             if (j == 1)
2787             {
2788                 curstat = sec->ceilingstat;
2789                 curbuffer = s->ceil.buffer;
2790                 curpicnum = ceilingpicnum;
2791                 curxpanning = sec->ceilingxpanning;
2792                 curypanning = sec->ceilingypanning;
2793             }
2794 
2795             if (!waloff[curpicnum])
2796                 tileLoad(curpicnum);
2797 
2798             if (((sec->floorstat & 64) || (sec->ceilingstat & 64)) &&
2799                     ((secangcos == 2) && (secangsin == 2)))
2800             {
2801                 ang = (getangle(wall[wal->point2].x - wal->x, wall[wal->point2].y - wal->y) + 512) & 2047;
2802                 secangcos = (float)(sintable[(ang+512)&2047]) / 16383.0f;
2803                 secangsin = (float)(sintable[ang&2047]) / 16383.0f;
2804             }
2805 
2806             // relative texturing
2807             if (curstat & 64)
2808             {
2809                 xpancoef = (float)(wal->x - wall[sec->wallptr].x);
2810                 ypancoef = (float)(wall[sec->wallptr].y - wal->y);
2811 
2812                 tex = (int32_t)(xpancoef * secangsin + ypancoef * secangcos);
2813                 tey = (int32_t)(xpancoef * secangcos - ypancoef * secangsin);
2814             } else {
2815                 tex = wal->x;
2816                 tey = -wal->y;
2817             }
2818 
2819             if ((curstat & (2+64)) == (2+64))
2820             {
2821                 heidiff = (int32_t)(curbuffer[i].y - curbuffer[0].y);
2822                 // don't forget the sign, tey could be negative with concave sectors
2823                 if (tey >= 0)
2824                     tey = (int32_t)sqrt((double)((tey * tey) + (heidiff * heidiff)));
2825                 else
2826                     tey = -(int32_t)sqrt((double)((tey * tey) + (heidiff * heidiff)));
2827             }
2828 
2829             if (curstat & 4)
2830                 swaplong(&tex, &tey);
2831 
2832             if (curstat & 16) tex = -tex;
2833             if (curstat & 32) tey = -tey;
2834 
2835             scalecoef = (curstat & 8) ? 8.0f : 16.0f;
2836 
2837             if (curxpanning)
2838             {
2839                 xpancoef = (float)(pow2long[picsiz[curpicnum] & 15]);
2840                 xpancoef *= (float)(curxpanning) / (256.0f * (float)(tilesiz[curpicnum].x));
2841             }
2842             else
2843                 xpancoef = 0;
2844 
2845             if (curypanning)
2846             {
2847                 ypancoef = (float)(pow2long[picsiz[curpicnum] >> 4]);
2848                 ypancoef *= (float)(curypanning) / (256.0f * (float)(tilesiz[curpicnum].y));
2849             }
2850             else
2851                 ypancoef = 0;
2852 
2853             curbuffer[i].u = ((float)(tex) / (scalecoef * tilesiz[curpicnum].x)) + xpancoef;
2854             curbuffer[i].v = ((float)(tey) / (scalecoef * tilesiz[curpicnum].y)) + ypancoef;
2855 
2856             j--;
2857         }
2858         i++;
2859         wal = &wall[sec->wallptr + i];
2860     }
2861 
2862     s->floorxpanning = sec->floorxpanning;
2863     s->ceilingxpanning = sec->ceilingxpanning;
2864     s->floorypanning = sec->floorypanning;
2865     s->ceilingypanning = sec->ceilingypanning;
2866 #ifdef USE_STRUCT_TRACKERS
2867     s->trackedrev = sectorchanged[sectnum];
2868 #endif
2869 
2870     i = -1;
2871 
2872 attributes:
2873     if ((pr_vbos > 0) && ((i == -1) || (wallinvalidate)))
2874     {
2875         if (pr_vbos > 0)
2876         {
2877             if (pr_nullrender < 2)
2878             {
2879                 /*glBindBuffer(GL_ARRAY_BUFFER, s->floor.vbo);
2880                 glBufferSubData(GL_ARRAY_BUFFER, 0, sec->wallnum * sizeof(GLfloat)* 5, s->floor.buffer);
2881                 glBindBuffer(GL_ARRAY_BUFFER, s->ceil.vbo);
2882                 glBufferSubData(GL_ARRAY_BUFFER, 0, sec->wallnum * sizeof(GLfloat)* 5, s->ceil.buffer);
2883                 */
2884 
2885                 s->floor.mapvbo_vertoffset = sec->wallptr * 2;
2886                 s->ceil.mapvbo_vertoffset = s->floor.mapvbo_vertoffset + sec->wallnum;
2887 
2888                 GLintptr sector_offset = s->floor.mapvbo_vertoffset * sizeof(_prvert);
2889                 GLsizeiptr cur_sector_size = sec->wallnum * sizeof(_prvert);
2890                 glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
2891                 // floor
2892                 glBufferSubData(GL_ARRAY_BUFFER, sector_offset, cur_sector_size, s->floor.buffer);
2893                 // ceiling
2894                 glBufferSubData(GL_ARRAY_BUFFER, sector_offset + cur_sector_size, cur_sector_size, s->ceil.buffer);
2895                 glBindBuffer(GL_ARRAY_BUFFER, 0);
2896             }
2897         }
2898         else
2899         {
2900             s->floor.mapvbo_vertoffset = -1;
2901             s->ceil.mapvbo_vertoffset = -1;
2902         }
2903     }
2904 
2905     if ((!s->flags.empty) && (!s->flags.invalidtex) &&
2906             (floorpicnum == s->floorpicnum_anim) &&
2907             (ceilingpicnum == s->ceilingpicnum_anim) &&
2908             !Bmemcmp(&s->ceilingstat, &sec->ceilingstat, offsetof(sectortype, visibility) - offsetof(sectortype, ceilingstat)))
2909         goto finish;
2910 
2911     s->floor.bucket = polymer_getbuildmaterial(&s->floor.material, floorpicnum, sec->floorpal, sec->floorshade, sec->visibility, (sec->floorstat & 384) ? DAMETH_MASK : DAMETH_NOMASK);
2912 
2913     if (sec->floorstat & 256) {
2914         if (sec->floorstat & 128) {
2915             s->floor.material.diffusemodulation[3] = transluctable[0];
2916         } else {
2917             s->floor.material.diffusemodulation[3] = transluctable[1];
2918         }
2919     }
2920 
2921     s->ceil.bucket = polymer_getbuildmaterial(&s->ceil.material, ceilingpicnum, sec->ceilingpal, sec->ceilingshade, sec->visibility, (sec->ceilingstat & 384) ? DAMETH_MASK : DAMETH_NOMASK);
2922 
2923     if (sec->ceilingstat & 256) {
2924         if (sec->ceilingstat & 128) {
2925             s->ceil.material.diffusemodulation[3] = transluctable[0];
2926         } else {
2927             s->ceil.material.diffusemodulation[3] = transluctable[1];
2928         }
2929     }
2930 
2931     s->flags.invalidtex = 0;
2932 
2933     // copy ceilingstat through visibility members
2934     Bmemcpy(&s->ceilingstat, &sec->ceilingstat, offsetof(sectortype, visibility) - offsetof(sectortype, ceilingstat));
2935     s->floorpicnum_anim = floorpicnum;
2936     s->ceilingpicnum_anim = ceilingpicnum;
2937 
2938 finish:
2939 
2940     if (needfloor)
2941     {
2942         polymer_buildfloor(sectnum);
2943         if ((pr_vbos > 0))
2944         {
2945             if (pr_nullrender < 2)
2946             {
2947                 if (s->oldindicescount < s->indicescount)
2948                 {
2949                     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->floor.ivbo);
2950                     glBufferData(GL_ELEMENT_ARRAY_BUFFER, s->indicescount * sizeof(GLushort), NULL, mapvbousage);
2951                     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->ceil.ivbo);
2952                     glBufferData(GL_ELEMENT_ARRAY_BUFFER, s->indicescount * sizeof(GLushort), NULL, mapvbousage);
2953                     s->oldindicescount = s->indicescount;
2954                 }
2955                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->floor.ivbo);
2956                 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, s->indicescount * sizeof(GLushort), s->floor.indices);
2957                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->ceil.ivbo);
2958                 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, s->indicescount * sizeof(GLushort), s->ceil.indices);
2959                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2960             }
2961         }
2962     }
2963 
2964     if (wallinvalidate)
2965     {
2966         s->invalidid++;
2967         polymer_invalidatesectorlights(sectnum);
2968         polymer_computeplane(&s->floor);
2969         polymer_computeplane(&s->ceil);
2970     }
2971 
2972     s->flags.empty = 0;
2973     s->flags.uptodate = 1;
2974 
2975     if (pr_verbosity >= 3) OSD_Printf("PR : Updated sector %i.\n", sectnum);
2976 
2977     return 0;
2978 }
2979 
polymer_tesserror(GLenum error)2980 void PR_CALLBACK    polymer_tesserror(GLenum error)
2981 {
2982     /* This callback is called by the tesselator whenever it raises an error.
2983        GLU_TESS_ERROR6 is the "no error"/"null" error spam in e1l1 and others. */
2984 
2985     if (pr_verbosity >= 1 && error != GLU_TESS_ERROR6) OSD_Printf("PR : Tesselation error number %i reported : %s.\n", error, bgluErrorString(errno));
2986 }
2987 
polymer_tessedgeflag(GLenum error)2988 void PR_CALLBACK    polymer_tessedgeflag(GLenum error)
2989 {
2990     // Passing an edgeflag callback forces the tesselator to output a triangle list
2991     UNREFERENCED_PARAMETER(error);
2992 }
2993 
polymer_tessvertex(void * vertex,void * sector)2994 void PR_CALLBACK    polymer_tessvertex(void* vertex, void* sector)
2995 {
2996     _prsector*      s;
2997 
2998     s = (_prsector*)sector;
2999 
3000     if (s->curindice >= s->indicescount)
3001     {
3002         if (pr_verbosity >= 2) OSD_Printf("PR : Indice overflow, extending the indices list... !\n");
3003         s->indicescount++;
3004         s->floor.indices = (GLushort *)Xrealloc(s->floor.indices, s->indicescount * sizeof(GLushort));
3005         s->ceil.indices = (GLushort *)Xrealloc(s->ceil.indices, s->indicescount * sizeof(GLushort));
3006     }
3007     s->ceil.indices[s->curindice] = (intptr_t)vertex;
3008     s->curindice++;
3009 }
3010 
polymer_buildfloor(int16_t sectnum)3011 static int32_t      polymer_buildfloor(int16_t sectnum)
3012 {
3013     // This function tesselates the floor/ceiling of a sector and stores the triangles in a display list.
3014     _prsector*      s;
3015     usectorptr_t sec;
3016     intptr_t        i;
3017 
3018     if (pr_verbosity >= 2) OSD_Printf("PR : Tesselating floor of sector %i...\n", sectnum);
3019 
3020     s = prsectors[sectnum];
3021     sec = (usectorptr_t)&sector[sectnum];
3022 
3023     if (s == NULL)
3024         return -1;
3025 
3026     if (s->floor.indices == NULL)
3027     {
3028         s->indicescount = (max<int16_t>(3, sec->wallnum) - 2) * 3;
3029         s->floor.indices = (GLushort *)Xcalloc(s->indicescount, sizeof(GLushort));
3030         s->ceil.indices = (GLushort *)Xcalloc(s->indicescount, sizeof(GLushort));
3031     }
3032 
3033     s->curindice = 0;
3034 
3035     bgluTessCallback(prtess, GLU_TESS_VERTEX_DATA, (void (PR_CALLBACK *)(void))polymer_tessvertex);
3036     bgluTessCallback(prtess, GLU_TESS_EDGE_FLAG, (void (PR_CALLBACK *)(void))polymer_tessedgeflag);
3037     bgluTessCallback(prtess, GLU_TESS_ERROR, (void (PR_CALLBACK *)(void))polymer_tesserror);
3038 
3039     bgluTessProperty(prtess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE);
3040 
3041     bgluTessBeginPolygon(prtess, s);
3042     bgluTessBeginContour(prtess);
3043 
3044     i = 0;
3045     while (i < sec->wallnum)
3046     {
3047         bgluTessVertex(prtess, s->verts + (3 * i), (void *)i);
3048         if ((i != (sec->wallnum - 1)) && ((sec->wallptr + i) > wall[sec->wallptr + i].point2))
3049         {
3050             bgluTessEndContour(prtess);
3051             bgluTessBeginContour(prtess);
3052         }
3053         i++;
3054     }
3055     bgluTessEndContour(prtess);
3056     bgluTessEndPolygon(prtess);
3057 
3058     i = 0;
3059     while (i < s->indicescount)
3060     {
3061         s->floor.indices[s->indicescount - i - 1] = s->ceil.indices[i];
3062 
3063         i++;
3064     }
3065     s->floor.indicescount = s->ceil.indicescount = s->indicescount;
3066 
3067     if (pr_verbosity >= 2) OSD_Printf("PR : Tesselated floor of sector %i.\n", sectnum);
3068 
3069     return 1;
3070 }
3071 
polymer_drawsector(int16_t sectnum,int32_t domasks)3072 static void         polymer_drawsector(int16_t sectnum, int32_t domasks)
3073 {
3074     usectorptr_t sec;
3075     _prsector*      s;
3076     GLubyte         oldcolor[4];
3077     int32_t         draw;
3078     int32_t         queuedmask;
3079 
3080     if (pr_verbosity >= 3) OSD_Printf("PR : Drawing sector %i...\n", sectnum);
3081 
3082     if (automapping)
3083         show2dsector[sectnum>>3] |= pow2char[sectnum&7];
3084 
3085     sec = (usectorptr_t)&sector[sectnum];
3086     s = prsectors[sectnum];
3087 
3088     queuedmask = FALSE;
3089 
3090     // If you're thinking of 'optimizing' the following logic, you'd better
3091     // provide compelling evidence that the generated code is more efficient
3092     // than what GCC can come up with on its own.
3093 
3094     draw = TRUE;
3095     // Draw masks regardless; avoid all non-masks TROR links
3096     if (sec->floorstat & 384) {
3097         draw = domasks;
3098     } else if (yax_getbunch(sectnum, YAX_FLOOR) >= 0) {
3099         draw = FALSE;
3100     }
3101     // Parallaxed
3102     if (sec->floorstat & 1) {
3103         draw = FALSE;
3104     }
3105 
3106     if (draw || (searchit == 2)) {
3107         if (searchit == 2) {
3108             polymer_drawsearchplane(&s->floor, oldcolor, 0x02, (GLubyte *) &sectnum);
3109         }
3110         else {
3111             calc_and_apply_fog(fogshade(sec->floorshade, sec->floorpal), sec->visibility,
3112                 get_floor_fogpal(sec));
3113             polymer_drawplane(&s->floor);
3114         }
3115     } else if (!domasks && cursectormaskcount && sec->floorstat & 384) {
3116         // If we just skipped a mask, queue it for later
3117         cursectormasks[(*cursectormaskcount)++] = sectnum;
3118         // Don't queue it twice if the ceiling is also a mask, though.
3119         queuedmask = TRUE;
3120     }
3121 
3122     draw = TRUE;
3123     // Draw masks regardless; avoid all non-masks TROR links
3124     if (sec->ceilingstat & 384) {
3125         draw = domasks;
3126     } else if (yax_getbunch(sectnum, YAX_CEILING) >= 0) {
3127         draw = FALSE;
3128     }
3129     // Parallaxed
3130     if (sec->ceilingstat & 1) {
3131         draw = FALSE;
3132     }
3133 
3134     if (draw || (searchit == 2)) {
3135         if (searchit == 2) {
3136             polymer_drawsearchplane(&s->ceil, oldcolor, 0x01, (GLubyte *) &sectnum);
3137         }
3138         else {
3139             calc_and_apply_fog(fogshade(sec->ceilingshade, sec->ceilingpal), sec->visibility,
3140                                get_ceiling_fogpal(sec));
3141             polymer_drawplane(&s->ceil);
3142         }
3143     } else if (!domasks && !queuedmask && cursectormaskcount &&
3144                (sec->ceilingstat & 384)) {
3145         // If we just skipped a mask, queue it for later
3146         cursectormasks[(*cursectormaskcount)++] = sectnum;
3147     }
3148 
3149     if (pr_verbosity >= 3) OSD_Printf("PR : Finished drawing sector %i...\n", sectnum);
3150 }
3151 
3152 // WALLS
polymer_initwall(int16_t wallnum)3153 static int32_t      polymer_initwall(int16_t wallnum)
3154 {
3155     _prwall         *w;
3156 
3157     if (pr_verbosity >= 2) OSD_Printf("PR : Initializing wall %i...\n", wallnum);
3158 
3159     w = (_prwall *)Xcalloc(1, sizeof(_prwall));
3160 
3161     if (w->mask.buffer == NULL) {
3162         w->mask.buffer = (_prvert *)Xmalloc(4 * sizeof(_prvert));
3163         w->mask.vertcount = 4;
3164     }
3165     if (w->bigportal == NULL)
3166         w->bigportal = (GLfloat *)Xmalloc(4 * sizeof(GLfloat) * 5);
3167     //if (w->cap == NULL)
3168     //    w->cap = (GLfloat *)Xmalloc(4 * sizeof(GLfloat) * 3);
3169 
3170     glGenBuffers(1, &w->wall.vbo);
3171     glGenBuffers(1, &w->over.vbo);
3172     glGenBuffers(1, &w->mask.vbo);
3173     glGenBuffers(1, &w->stuffvbo);
3174 
3175     glBindBuffer(GL_ARRAY_BUFFER, w->wall.vbo);
3176     glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
3177 
3178     glBindBuffer(GL_ARRAY_BUFFER, w->over.vbo);
3179     glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
3180 
3181     glBindBuffer(GL_ARRAY_BUFFER, w->mask.vbo);
3182     glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
3183 
3184     glBindBuffer(GL_ARRAY_BUFFER, w->stuffvbo);
3185     glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat) * 5, NULL, mapvbousage);
3186 
3187     glBindBuffer(GL_ARRAY_BUFFER, 0);
3188 
3189     w->flags.empty = 1;
3190 
3191     prwalls[wallnum] = w;
3192 
3193     if (pr_verbosity >= 2) OSD_Printf("PR : Initialized wall %i.\n", wallnum);
3194 
3195     return 1;
3196 }
3197 
3198 // TODO: r_npotwallmode. Needs polymost_is_npotmode() handling among others.
3199 #define DAMETH_WALL 0
3200 
calc_ypancoef(char curypanning,int16_t curpicnum,int32_t dopancor)3201 static float calc_ypancoef(char curypanning, int16_t curpicnum, int32_t dopancor)
3202 {
3203 #ifdef NEW_MAP_FORMAT
3204     if (g_loadedMapVersion >= 10)
3205         return curypanning / 256.0f;
3206 #endif
3207     {
3208         float ypancoef = (float)(pow2long[picsiz[curpicnum] >> 4]);
3209 
3210         if (ypancoef < tilesiz[curpicnum].y)
3211             ypancoef *= 2;
3212 
3213         if (dopancor)
3214         {
3215             int32_t yoffs = Blrintf((ypancoef - tilesiz[curpicnum].y) * (255.0f / ypancoef));
3216             if (curypanning > 256 - yoffs)
3217                 curypanning -= yoffs;
3218         }
3219 
3220         ypancoef *= (float)curypanning / (256.0f * (float)tilesiz[curpicnum].y);
3221 
3222         return ypancoef;
3223     }
3224 }
3225 
3226 #define NBYTES_WALL_CSTAT_THROUGH_YPANNING \
3227     (offsetof(walltype, ypanning)+sizeof(wall[0].ypanning) - offsetof(walltype, cstat))
3228 
polymer_updatewall(int16_t wallnum)3229 static void         polymer_updatewall(int16_t wallnum)
3230 {
3231     int16_t         nwallnum, nnwallnum, curpicnum, wallpicnum, walloverpicnum, nwallpicnum;
3232     char            curxpanning, curypanning, underwall, overwall, curpal;
3233     int8_t          curshade;
3234     walltype        *wal;
3235     sectortype      *sec, *nsec;
3236     _prwall         *w;
3237     _prsector       *s, *ns;
3238     int32_t         xref, yref;
3239     float           ypancoef, dist;
3240     int32_t         i;
3241     uint32_t        invalid;
3242     int32_t         sectofwall = sectorofwall(wallnum);
3243 
3244     if (pr_nullrender >= 3) return;
3245 
3246     // yes, this function is messy and unefficient
3247     // it also works, bitches
3248     sec = &sector[sectofwall];
3249 
3250     if (sectofwall < 0 || sectofwall >= numsectors ||
3251         wallnum < 0 || wallnum > numwalls ||
3252         sec->wallptr > wallnum || wallnum >= (sec->wallptr + sec->wallnum))
3253         return; // yay, corrupt map
3254 
3255     wal = &wall[wallnum];
3256     nwallnum = wal->nextwall;
3257 
3258     w = prwalls[wallnum];
3259     s = prsectors[sectofwall];
3260     invalid = s->invalidid;
3261     if (nwallnum >= 0 && nwallnum < numwalls && wal->nextsector >= 0 && wal->nextsector < numsectors)
3262     {
3263         ns = prsectors[wal->nextsector];
3264         invalid += ns->invalidid;
3265         nsec = &sector[wal->nextsector];
3266     }
3267     else
3268     {
3269         ns = NULL;
3270         nsec = NULL;
3271     }
3272 
3273     if (w->wall.buffer == NULL) {
3274         w->wall.buffer = (_prvert *)Xcalloc(4, sizeof(_prvert));  // XXX
3275         w->wall.vertcount = 4;
3276     }
3277 
3278     wallpicnum = wal->picnum;
3279     tileUpdatePicnum(&wallpicnum, wallnum+16384);
3280 
3281     walloverpicnum = wal->overpicnum;
3282     if (walloverpicnum>=0)
3283         tileUpdatePicnum(&walloverpicnum, wallnum+16384);
3284 
3285     if (nwallnum >= 0 && nwallnum < numwalls)
3286     {
3287         nwallpicnum = wall[nwallnum].picnum;
3288         tileUpdatePicnum(&nwallpicnum, wallnum+16384);
3289     }
3290     else
3291         nwallpicnum = 0;
3292 
3293     if ((!w->flags.empty) && (!w->flags.invalidtex) &&
3294             (w->invalidid == invalid) &&
3295             (wallpicnum == w->picnum_anim) &&
3296             (walloverpicnum == w->overpicnum_anim) &&
3297 #ifdef USE_STRUCT_TRACKERS
3298             (w->trackedrev == wallchanged[wallnum]) &&
3299 #else
3300             !Bmemcmp(&wal->cstat, &w->cstat, NBYTES_WALL_CSTAT_THROUGH_YPANNING) &&
3301 #endif
3302             ((nwallnum < 0 || nwallnum > numwalls) ||
3303              ((nwallpicnum == w->nwallpicnum) &&
3304               (wall[nwallnum].xpanning == w->nwallxpanning) &&
3305               (wall[nwallnum].ypanning == w->nwallypanning) &&
3306               (wall[nwallnum].cstat == w->nwallcstat) &&
3307               (wall[nwallnum].shade == w->nwallshade))))
3308     {
3309         w->flags.uptodate = 1;
3310         return; // screw you guys I'm going home
3311     }
3312     else
3313     {
3314         w->invalidid = invalid;
3315 
3316         Bmemcpy(&w->cstat, &wal->cstat, NBYTES_WALL_CSTAT_THROUGH_YPANNING);
3317 
3318         w->picnum_anim = wallpicnum;
3319         w->overpicnum_anim = walloverpicnum;
3320 #ifdef USE_STRUCT_TRACKERS
3321         w->trackedrev = wallchanged[wallnum];
3322 #endif
3323         if (nwallnum >= 0 && nwallnum < numwalls)
3324         {
3325             w->nwallpicnum = nwallpicnum;
3326             w->nwallxpanning = wall[nwallnum].xpanning;
3327             w->nwallypanning = wall[nwallnum].ypanning;
3328             w->nwallcstat = wall[nwallnum].cstat;
3329             w->nwallshade = wall[nwallnum].shade;
3330         }
3331     }
3332 
3333     w->underover = underwall = overwall = 0;
3334 
3335     if (wal->cstat & 8)
3336         xref = 1;
3337     else
3338         xref = 0;
3339 
3340     if ((unsigned)wal->nextsector >= (unsigned)numsectors || !ns)
3341     {
3342         Bmemcpy(w->wall.buffer, &s->floor.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
3343         Bmemcpy(&w->wall.buffer[1], &s->floor.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
3344         Bmemcpy(&w->wall.buffer[2], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
3345         Bmemcpy(&w->wall.buffer[3], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
3346 
3347         if (wal->nextsector < 0)
3348             curpicnum = wallpicnum;
3349         else
3350             curpicnum = walloverpicnum;
3351 
3352         w->wall.bucket = polymer_getbuildmaterial(&w->wall.material, curpicnum, wal->pal, wal->shade, sec->visibility, DAMETH_WALL);
3353 
3354         if (wal->cstat & 4)
3355             yref = sec->floorz;
3356         else
3357             yref = sec->ceilingz;
3358 
3359         if ((wal->cstat & 32) && (wal->nextsector >= 0))
3360         {
3361             if ((!(wal->cstat & 2) && (wal->cstat & 4)) || ((wal->cstat & 2) && (wall[nwallnum].cstat & 4)))
3362                 yref = sec->ceilingz;
3363             else
3364                 yref = nsec->floorz;
3365         }
3366 
3367         if (wal->ypanning)
3368             // white (but not 1-way)
3369             ypancoef = calc_ypancoef(wal->ypanning, curpicnum, !(wal->cstat & 4));
3370         else
3371             ypancoef = 0;
3372 
3373         i = 0;
3374         while (i < 4)
3375         {
3376             if ((i == 0) || (i == 3))
3377                 dist = (float)xref;
3378             else
3379                 dist = (float)(xref == 0);
3380 
3381             w->wall.buffer[i].u = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
3382             w->wall.buffer[i].v = (-(float)(yref + (w->wall.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
3383 
3384             if (wal->cstat & 256) w->wall.buffer[i].v = -w->wall.buffer[i].v;
3385 
3386             i++;
3387         }
3388 
3389         w->underover |= 1;
3390     }
3391     else
3392     {
3393         nnwallnum = wall[nwallnum].point2;
3394 
3395         if ((s->floor.buffer[wallnum - sec->wallptr].y < ns->floor.buffer[nnwallnum - nsec->wallptr].y) ||
3396             (s->floor.buffer[wal->point2 - sec->wallptr].y < ns->floor.buffer[nwallnum - nsec->wallptr].y))
3397             underwall = 1;
3398 
3399         if ((underwall) || (wal->cstat & 16) || (wal->cstat & 32))
3400         {
3401             int32_t refwall;
3402 
3403             if (s->floor.buffer[wallnum - sec->wallptr].y < ns->floor.buffer[nnwallnum - nsec->wallptr].y)
3404                 Bmemcpy(w->wall.buffer, &s->floor.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
3405             else
3406                 Bmemcpy(w->wall.buffer, &ns->floor.buffer[nnwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
3407             Bmemcpy(&w->wall.buffer[1], &s->floor.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
3408             Bmemcpy(&w->wall.buffer[2], &ns->floor.buffer[nwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
3409             Bmemcpy(&w->wall.buffer[3], &ns->floor.buffer[nnwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
3410 
3411             if (wal->cstat & 2)
3412                 refwall = nwallnum;
3413             else
3414                 refwall = wallnum;
3415 
3416             curpicnum = (wal->cstat & 2) ? nwallpicnum : wallpicnum;
3417             curpal = wall[refwall].pal;
3418             curshade = wall[refwall].shade;
3419             curxpanning = wall[refwall].xpanning;
3420             curypanning = wall[refwall].ypanning;
3421 
3422             w->wall.bucket = polymer_getbuildmaterial(&w->wall.material, curpicnum, curpal, curshade, sec->visibility, DAMETH_WALL);
3423 
3424             if (!(wall[refwall].cstat&4))
3425                 yref = nsec->floorz;
3426             else
3427                 yref = sec->ceilingz;
3428 
3429             if (curypanning)
3430                 // under
3431                 ypancoef = calc_ypancoef(curypanning, curpicnum, !(wall[refwall].cstat & 4));
3432             else
3433                 ypancoef = 0;
3434 
3435             i = 0;
3436             while (i < 4)
3437             {
3438                 if ((i == 0) || (i == 3))
3439                     dist = (float)xref;
3440                 else
3441                     dist = (float)(xref == 0);
3442 
3443                 w->wall.buffer[i].u = ((dist * 8.0f * wal->xrepeat) + curxpanning) / (float)(tilesiz[curpicnum].x);
3444                 w->wall.buffer[i].v = (-(float)(yref + (w->wall.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
3445 
3446                 if ((!(wal->cstat & 2) && (wal->cstat & 256)) ||
3447                     ((wal->cstat & 2) && (wall[nwallnum].cstat & 256)))
3448                     w->wall.buffer[i].v = -w->wall.buffer[i].v;
3449 
3450                 i++;
3451             }
3452 
3453             if (underwall)
3454                 w->underover |= 1;
3455 
3456             Bmemcpy(w->mask.buffer, &w->wall.buffer[3], sizeof(GLfloat) * 5);
3457             Bmemcpy(&w->mask.buffer[1], &w->wall.buffer[2], sizeof(GLfloat) * 5);
3458         }
3459         else
3460         {
3461             Bmemcpy(w->mask.buffer, &s->floor.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 5);
3462             Bmemcpy(&w->mask.buffer[1], &s->floor.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 5);
3463         }
3464 
3465         if ((s->ceil.buffer[wallnum - sec->wallptr].y > ns->ceil.buffer[nnwallnum - nsec->wallptr].y) ||
3466             (s->ceil.buffer[wal->point2 - sec->wallptr].y > ns->ceil.buffer[nwallnum - nsec->wallptr].y))
3467             overwall = 1;
3468 
3469         if ((overwall) || (wal->cstat & 48))
3470         {
3471             if (w->over.buffer == NULL) {
3472                 w->over.buffer = (_prvert *)Xmalloc(4 * sizeof(_prvert));
3473                 w->over.vertcount = 4;
3474             }
3475 
3476             Bmemcpy(w->over.buffer, &ns->ceil.buffer[nnwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
3477             Bmemcpy(&w->over.buffer[1], &ns->ceil.buffer[nwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
3478             if (s->ceil.buffer[wal->point2 - sec->wallptr].y > ns->ceil.buffer[nwallnum - nsec->wallptr].y)
3479                 Bmemcpy(&w->over.buffer[2], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
3480             else
3481                 Bmemcpy(&w->over.buffer[2], &ns->ceil.buffer[nwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
3482             Bmemcpy(&w->over.buffer[3], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
3483 
3484             if ((wal->cstat & 16) || (wal->overpicnum == 0))
3485                 curpicnum = wallpicnum;
3486             else
3487                 curpicnum = wallpicnum;
3488 
3489             w->over.bucket = polymer_getbuildmaterial(&w->over.material, curpicnum, wal->pal, wal->shade, sec->visibility, DAMETH_WALL);
3490 
3491             if (wal->cstat & 48)
3492             {
3493                 // mask
3494                 w->mask.bucket = polymer_getbuildmaterial(&w->mask.material, walloverpicnum, wal->pal, wal->shade, sec->visibility, DAMETH_WALL | ((wal->cstat & 48) == 48 ? DAMETH_NOMASK : DAMETH_MASK));
3495 
3496                 if (wal->cstat & 128)
3497                 {
3498                     if (wal->cstat & 512)
3499                         w->mask.material.diffusemodulation[3] = transluctable[0];
3500                     else
3501                         w->mask.material.diffusemodulation[3] = transluctable[1];
3502                 }
3503             }
3504 
3505             if (wal->cstat & 4)
3506                 yref = sec->ceilingz;
3507             else
3508                 yref = nsec->ceilingz;
3509 
3510             if (wal->ypanning)
3511                 // over
3512                 ypancoef = calc_ypancoef(wal->ypanning, curpicnum, wal->cstat & 4);
3513             else
3514                 ypancoef = 0;
3515 
3516             i = 0;
3517             while (i < 4)
3518             {
3519                 if ((i == 0) || (i == 3))
3520                     dist = (float)xref;
3521                 else
3522                     dist = (float)(xref == 0);
3523 
3524                 w->over.buffer[i].u = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
3525                 w->over.buffer[i].v = (-(float)(yref + (w->over.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
3526 
3527                 if (wal->cstat & 256) w->over.buffer[i].v = -w->over.buffer[i].v;
3528 
3529                 i++;
3530             }
3531 
3532             if (overwall)
3533                 w->underover |= 2;
3534 
3535             Bmemcpy(&w->mask.buffer[2], &w->over.buffer[1], sizeof(GLfloat) * 5);
3536             Bmemcpy(&w->mask.buffer[3], &w->over.buffer[0], sizeof(GLfloat) * 5);
3537 
3538             if ((wal->cstat & 16) || (wal->cstat & 32))
3539             {
3540                 const int botSwap = (wal->cstat & 4);
3541 
3542                 if (wal->cstat & 32)
3543                 {
3544                     // 1-sided wall
3545                     if (nsec)
3546                         yref = botSwap ? sec->ceilingz : nsec->ceilingz;
3547                     else
3548                         yref = botSwap ? sec->floorz : sec->ceilingz;
3549                 }
3550                 else
3551                 {
3552                     // masked wall
3553                     if (botSwap)
3554                         yref = min(sec->floorz, nsec->floorz);
3555                     else
3556                         yref = max(sec->ceilingz, nsec->ceilingz);
3557                 }
3558 
3559                 curpicnum = walloverpicnum;
3560 
3561                 if (wal->ypanning)
3562                     // mask / 1-way
3563                     ypancoef = calc_ypancoef(wal->ypanning, curpicnum, 0);
3564                 else
3565                     ypancoef = 0;
3566 
3567                 i = 0;
3568                 while (i < 4)
3569                 {
3570                     if ((i == 0) || (i == 3))
3571                         dist = (float)xref;
3572                     else
3573                         dist = (float)(xref == 0);
3574 
3575                     w->mask.buffer[i].u = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
3576                     w->mask.buffer[i].v = (-(float)(yref + (w->mask.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
3577 
3578                     if (wal->cstat & 256) w->mask.buffer[i].v = -w->mask.buffer[i].v;
3579 
3580                     i++;
3581                 }
3582             }
3583         }
3584         else
3585         {
3586             Bmemcpy(&w->mask.buffer[2], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 5);
3587             Bmemcpy(&w->mask.buffer[3], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 5);
3588         }
3589     }
3590 
3591     // make sure shade color handling is correct below XXX
3592     if (wal->nextsector < 0)
3593         Bmemcpy(w->mask.buffer, w->wall.buffer, sizeof(_prvert) * 4);
3594 
3595     Bmemcpy(w->bigportal, &s->floor.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
3596     Bmemcpy(&w->bigportal[5], &s->floor.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
3597     Bmemcpy(&w->bigportal[10], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
3598     Bmemcpy(&w->bigportal[15], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
3599 
3600     //Bmemcpy(&w->cap[0], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
3601     //Bmemcpy(&w->cap[3], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
3602     //Bmemcpy(&w->cap[6], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
3603     //Bmemcpy(&w->cap[9], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
3604     //w->cap[7] += 1048576; // this number is the result of 1048574 + 2
3605     //w->cap[10] += 1048576; // this one is arbitrary
3606 
3607     if (w->underover & 1)
3608         polymer_computeplane(&w->wall);
3609     if (w->underover & 2)
3610         polymer_computeplane(&w->over);
3611     polymer_computeplane(&w->mask);
3612 
3613     if ((pr_vbos > 0))
3614     {
3615         if (pr_nullrender < 2)
3616         {
3617             const GLintptr thiswalloffset = prwalldataoffset + (prwalldatasize * wallnum);
3618             const GLintptr thisoveroffset = thiswalloffset + proneplanesize;
3619             const GLintptr thismaskoffset = thisoveroffset + proneplanesize;
3620             glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
3621             glBufferSubData(GL_ARRAY_BUFFER, thiswalloffset, proneplanesize, w->wall.buffer);
3622             glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
3623             if (w->over.buffer)
3624                 glBufferSubData(GL_ARRAY_BUFFER, thisoveroffset, proneplanesize, w->over.buffer);
3625             glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
3626             glBufferSubData(GL_ARRAY_BUFFER, thismaskoffset, proneplanesize, w->mask.buffer);
3627             glBindBuffer(GL_ARRAY_BUFFER, w->stuffvbo);
3628             glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(GLfloat)* 5, w->bigportal);
3629             //glBufferSubData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat)* 5, 4 * sizeof(GLfloat)* 3, w->cap);
3630             glBindBuffer(GL_ARRAY_BUFFER, 0);
3631 
3632             w->wall.mapvbo_vertoffset = thiswalloffset / sizeof(_prvert);
3633             w->over.mapvbo_vertoffset = thisoveroffset / sizeof(_prvert);
3634             w->mask.mapvbo_vertoffset = thismaskoffset / sizeof(_prvert);
3635         }
3636     }
3637     else
3638     {
3639         w->wall.mapvbo_vertoffset = -1;
3640         w->over.mapvbo_vertoffset = -1;
3641         w->mask.mapvbo_vertoffset = -1;
3642     }
3643 
3644     w->flags.empty = 0;
3645     w->flags.uptodate = 1;
3646     w->flags.invalidtex = 0;
3647 
3648     if (pr_verbosity >= 3) OSD_Printf("PR : Updated wall %i.\n", wallnum);
3649 }
3650 
polymer_drawwall(int16_t sectnum,int16_t wallnum)3651 static void         polymer_drawwall(int16_t sectnum, int16_t wallnum)
3652 {
3653     usectorptr_t sec;
3654     walltype        *wal;
3655     _prwall         *w;
3656     GLubyte         oldcolor[4];
3657     int32_t         parallaxedfloor = 0, parallaxedceiling = 0;
3658 
3659     if (pr_verbosity >= 3) OSD_Printf("PR : Drawing wall %i...\n", wallnum);
3660 
3661     sec = (usectorptr_t)&sector[sectnum];
3662     wal = &wall[wallnum];
3663     w = prwalls[wallnum];
3664 
3665     if ((sec->floorstat & 1) && (wal->nextsector >= 0) &&
3666         (sector[wal->nextsector].floorstat & 1))
3667         parallaxedfloor = 1;
3668 
3669     if ((sec->ceilingstat & 1) && (wal->nextsector >= 0) &&
3670         (sector[wal->nextsector].ceilingstat & 1))
3671         parallaxedceiling = 1;
3672 
3673     calc_and_apply_fog(fogshade(wal->shade, wal->pal), sec->visibility, get_floor_fogpal(sec));
3674 
3675     if ((w->underover & 1) && (!parallaxedfloor || (searchit == 2)))
3676     {
3677         if (searchit == 2) {
3678             polymer_drawsearchplane(&w->wall, oldcolor, 0x05, (GLubyte *) &wallnum);
3679         }
3680         else
3681             polymer_drawplane(&w->wall);
3682     }
3683 
3684     if ((w->underover & 2) && (!parallaxedceiling || (searchit == 2)))
3685     {
3686         if (searchit == 2) {
3687             polymer_drawsearchplane(&w->over, oldcolor, 0x00, (GLubyte *) &wallnum);
3688         }
3689         else
3690             polymer_drawplane(&w->over);
3691     }
3692 
3693     if ((wall[wallnum].cstat & 32) && (wall[wallnum].nextsector >= 0))
3694     {
3695         if (searchit == 2) {
3696             polymer_drawsearchplane(&w->mask, oldcolor, 0x04, (GLubyte *) &wallnum);
3697         }
3698         else
3699             polymer_drawplane(&w->mask);
3700     }
3701 
3702     //if (!searchit && (sector[sectnum].ceilingstat & 1) &&
3703     //    ((wall[wallnum].nextsector < 0) ||
3704     //    !(sector[wall[wallnum].nextsector].ceilingstat & 1)))
3705     //{
3706     //    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3707 
3708     //    if (pr_vbos)
3709     //    {
3710     //        glBindBuffer(GL_ARRAY_BUFFER, w->stuffvbo);
3711     //        glVertexPointer(3, GL_FLOAT, 0, (const GLvoid*)(4 * sizeof(GLfloat) * 5));
3712     //    }
3713     //    else
3714     //        glVertexPointer(3, GL_FLOAT, 0, w->cap);
3715 
3716     //    glDrawArrays(GL_QUADS, 0, 4);
3717 
3718     //    if (pr_vbos)
3719     //        glBindBuffer(GL_ARRAY_BUFFER, 0);
3720 
3721     //    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3722     //}
3723 
3724     if (automapping)
3725         show2dwall[wallnum>>3] |= pow2char[wallnum&7];
3726 
3727     if (pr_verbosity >= 3) OSD_Printf("PR : Finished drawing wall %i...\n", wallnum);
3728 }
3729 
3730 // HSR
polymer_computeplane(_prplane * p)3731 static void         polymer_computeplane(_prplane* p)
3732 {
3733     GLfloat         vec1[5], vec2[5], norm, r;// BxN[3], NxT[3], TxB[3];
3734     int32_t         i;
3735     _prvert*        buffer;
3736     GLfloat*        plane;
3737 
3738     if (p->indices && (p->indicescount < 3))
3739         return; // corrupt sector (E3L4, I'm looking at you)
3740 
3741     buffer = p->buffer;
3742     plane = p->plane;
3743 
3744     i = 0;
3745     do
3746     {
3747         vec1[0] = buffer[(INDICE(1))].x - buffer[(INDICE(0))].x; //x1
3748         vec1[1] = buffer[(INDICE(1))].y - buffer[(INDICE(0))].y; //y1
3749         vec1[2] = buffer[(INDICE(1))].z - buffer[(INDICE(0))].z; //z1
3750         vec1[3] = buffer[(INDICE(1))].u - buffer[(INDICE(0))].u; //s1
3751         vec1[4] = buffer[(INDICE(1))].v - buffer[(INDICE(0))].v; //t1
3752 
3753         vec2[0] = buffer[(INDICE(2))].x - buffer[(INDICE(1))].x; //x2
3754         vec2[1] = buffer[(INDICE(2))].y - buffer[(INDICE(1))].y; //y2
3755         vec2[2] = buffer[(INDICE(2))].z - buffer[(INDICE(1))].z; //z2
3756         vec2[3] = buffer[(INDICE(2))].u - buffer[(INDICE(1))].u; //s2
3757         vec2[4] = buffer[(INDICE(2))].v - buffer[(INDICE(1))].v; //t2
3758 
3759         polymer_crossproduct(vec2, vec1, plane);
3760 
3761         norm = plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2];
3762 
3763         // hack to work around a precision issue with slopes
3764         if (norm >= 15000)
3765         {
3766             float tangent[3][3];
3767             double det;
3768 
3769             // normalize the normal/plane equation and calculate its plane norm
3770             norm = -sqrt(norm);
3771             norm = 1.0 / norm;
3772             plane[0] *= norm;
3773             plane[1] *= norm;
3774             plane[2] *= norm;
3775             plane[3] = -(plane[0] * buffer->x + plane[1] * buffer->y + plane[2] * buffer->z);
3776 
3777             // calculate T and B
3778             r = 1.0 / (vec1[3] * vec2[4] - vec2[3] * vec1[4]);
3779 
3780             // tangent
3781             tangent[0][0] = (vec2[4] * vec1[0] - vec1[4] * vec2[0]) * r;
3782             tangent[0][1] = (vec2[4] * vec1[1] - vec1[4] * vec2[1]) * r;
3783             tangent[0][2] = (vec2[4] * vec1[2] - vec1[4] * vec2[2]) * r;
3784 
3785             polymer_normalize(&tangent[0][0]);
3786 
3787             // bitangent
3788             tangent[1][0] = (vec1[3] * vec2[0] - vec2[3] * vec1[0]) * r;
3789             tangent[1][1] = (vec1[3] * vec2[1] - vec2[3] * vec1[1]) * r;
3790             tangent[1][2] = (vec1[3] * vec2[2] - vec2[3] * vec1[2]) * r;
3791 
3792             polymer_normalize(&tangent[1][0]);
3793 
3794             // normal
3795             tangent[2][0] = plane[0];
3796             tangent[2][1] = plane[1];
3797             tangent[2][2] = plane[2];
3798 
3799             INVERT_3X3(p->tbn, det, tangent);
3800 
3801             break;
3802         }
3803         i+= (p->indices) ? 3 : 1;
3804     }
3805     while ((p->indices && i < p->indicescount) ||
3806           (!p->indices && i < p->vertcount));
3807 }
3808 
polymer_crossproduct(const GLfloat * in_a,const GLfloat * in_b,GLfloat * out)3809 static inline void  polymer_crossproduct(const GLfloat* in_a, const GLfloat* in_b, GLfloat* out)
3810 {
3811     out[0] = in_a[1] * in_b[2] - in_a[2] * in_b[1];
3812     out[1] = in_a[2] * in_b[0] - in_a[0] * in_b[2];
3813     out[2] = in_a[0] * in_b[1] - in_a[1] * in_b[0];
3814 }
3815 
polymer_transformpoint(const float * inpos,float * pos,const float * matrix)3816 static inline void  polymer_transformpoint(const float* inpos, float* pos, const float* matrix)
3817 {
3818     pos[0] = inpos[0] * matrix[0] +
3819              inpos[1] * matrix[4] +
3820              inpos[2] * matrix[8] +
3821                       + matrix[12];
3822     pos[1] = inpos[0] * matrix[1] +
3823              inpos[1] * matrix[5] +
3824              inpos[2] * matrix[9] +
3825                       + matrix[13];
3826     pos[2] = inpos[0] * matrix[2] +
3827              inpos[1] * matrix[6] +
3828              inpos[2] * matrix[10] +
3829                       + matrix[14];
3830 }
3831 
polymer_normalize(float * vec)3832 static inline void  polymer_normalize(float* vec)
3833 {
3834     double norm;
3835 
3836     norm = vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2];
3837 
3838     norm = sqrt(norm);
3839     norm = 1.0 / norm;
3840     vec[0] *= norm;
3841     vec[1] *= norm;
3842     vec[2] *= norm;
3843 }
3844 
polymer_pokesector(int16_t sectnum)3845 static inline void  polymer_pokesector(int16_t sectnum)
3846 {
3847     sectortype      *sec = &sector[sectnum];
3848     _prsector       *s = prsectors[sectnum];
3849     walltype        *wal = &wall[sec->wallptr];
3850     int32_t         i = 0;
3851 
3852     if (!s->flags.uptodate)
3853         polymer_updatesector(sectnum);
3854 
3855     do
3856     {
3857         if ((wal->nextsector >= 0) && (!prsectors[wal->nextsector]->flags.uptodate))
3858             polymer_updatesector(wal->nextsector);
3859         if (!prwalls[sec->wallptr + i]->flags.uptodate)
3860             polymer_updatewall(sec->wallptr + i);
3861 
3862         i++;
3863         wal = &wall[sec->wallptr + i];
3864     }
3865     while (i < sec->wallnum);
3866 }
3867 
polymer_extractfrustum(GLfloat * modelview,GLfloat * projection,float * frustum)3868 static void         polymer_extractfrustum(GLfloat* modelview, GLfloat* projection, float* frustum)
3869 {
3870     GLfloat         matrix[16];
3871     int32_t         i;
3872 
3873     glMatrixMode(GL_TEXTURE);
3874     glLoadMatrixf(projection);
3875     glMultMatrixf(modelview);
3876     glGetFloatv(GL_TEXTURE_MATRIX, matrix);
3877     glLoadIdentity();
3878     glMatrixMode(GL_MODELVIEW);
3879 
3880     i = 0;
3881     do
3882     {
3883         uint32_t ii = i<<2, iii = (i<<2) + 3;
3884 
3885         frustum[i] = matrix[iii] + matrix[ii];               // left
3886         frustum[i + 4] = matrix[iii] - matrix[ii];           // right
3887         frustum[i + 8] = matrix[iii] - matrix[ii + 1];     // top
3888         frustum[i + 12] = matrix[iii] + matrix[ii + 1];    // bottom
3889         frustum[i + 16] = matrix[iii] - matrix[ii + 2];    // far
3890     }
3891     while (++i < 4);
3892 
3893     if (pr_verbosity >= 3) OSD_Printf("PR : Frustum extracted.\n");
3894 }
3895 
polymer_planeinfrustum(_prplane * plane,const float * frustum)3896 static inline int32_t polymer_planeinfrustum(_prplane *plane, const float* frustum)
3897 {
3898     int32_t         i, j, k = -1;
3899     i = 4;
3900 
3901 
3902     do
3903     {
3904         int32_t ii = i * 4;
3905         j = k = plane->vertcount - 1;
3906 
3907         do
3908         {
3909             k -= ((frustum[ii + 0] * plane->buffer[j].x +
3910                    frustum[ii + 1] * plane->buffer[j].y +
3911                    frustum[ii + 2] * plane->buffer[j].z +
3912                    frustum[ii + 3]) < 0.f);
3913         }
3914         while (j--);
3915 
3916         if (k == -1)
3917             return 0; // OUT !
3918     }
3919     while (i--);
3920 
3921     return 1;
3922 }
3923 
polymer_scansprites(int16_t sectnum,tspriteptr_t localtsprite,int32_t * localspritesortcnt)3924 static inline void  polymer_scansprites(int16_t sectnum, tspriteptr_t localtsprite, int32_t* localspritesortcnt)
3925 {
3926     int32_t         i;
3927     spritetype      *spr;
3928 
3929     for (i = headspritesect[sectnum];i >=0;i = nextspritesect[i])
3930     {
3931         spr = &sprite[i];
3932         if ((((spr->cstat&0x8000) == 0) || (showinvisibility)) &&
3933                 (spr->xrepeat > 0) && (spr->yrepeat > 0) &&
3934                 (*localspritesortcnt < maxspritesonscreen))
3935         {
3936             // this function's localtsprite is either the tsprite global or
3937             // polymer_drawroom's locattsprite, so no aliasing
3938             renderMakeTSpriteFromSprite(&localtsprite[(*localspritesortcnt)++], i);
3939         }
3940     }
3941 }
3942 
polymer_updatesprite(int32_t snum)3943 void                polymer_updatesprite(int32_t snum)
3944 {
3945     int32_t         xsize, ysize, i, j;
3946     int32_t         tilexoff, tileyoff, xoff, yoff, centeryoff=0, heinum;
3947     auto const      tspr = tspriteptr[snum];
3948     float           xratio, yratio, ang;
3949     float           spos[3];
3950     const _prvert   *inbuffer;
3951     uint8_t         flipu, flipv;
3952     _prsprite       *s;
3953 
3954     const uint32_t cs = tspr->cstat;
3955     const uint32_t alignmask = (cs & SPR_ALIGN_MASK);
3956     const uint8_t flooraligned = (alignmask==SPR_FLOOR);
3957 
3958     if (pr_nullrender >= 3) return;
3959 
3960     if (pr_verbosity >= 3) OSD_Printf("PR : Updating sprite %i...\n", snum);
3961 
3962     int32_t const curpicnum = tspr->picnum;
3963 
3964     if (tspr->owner < 0 || curpicnum < 0) return;
3965 
3966     s = prsprites[tspr->owner];
3967 
3968     if (s == NULL)
3969     {
3970         s = prsprites[tspr->owner] = (_prsprite *)Xcalloc(sizeof(_prsprite), 1);
3971 
3972         s->plane.buffer = (_prvert *)Xcalloc(4, sizeof(_prvert));  // XXX
3973         s->plane.vertcount = 4;
3974         s->plane.mapvbo_vertoffset = -1;
3975         s->hash = 0xDEADBEEF;
3976     }
3977 
3978     if ((tspr->cstat & 48) && (pr_vbos > 0) && !s->plane.vbo)
3979     {
3980         if (pr_nullrender < 2)
3981         {
3982             glGenBuffers(1, &s->plane.vbo);
3983             glBindBuffer(GL_ARRAY_BUFFER, s->plane.vbo);
3984             glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(_prvert), NULL, mapvbousage);
3985         }
3986     }
3987 
3988     if (tspr->cstat & 48 && searchit != 2)
3989     {
3990         uint32_t const changed = XXH3_64bits((uint8_t *) tspr, offsetof(spritetype, owner));
3991 
3992         if (changed == s->hash)
3993             return;
3994 
3995         s->hash = changed;
3996     }
3997 
3998     polymer_getbuildmaterial(&s->plane.material, curpicnum, tspr->pal, tspr->shade,
3999                              sector[tspr->sectnum].visibility, DAMETH_MASK | DAMETH_CLAMPED);
4000 
4001     if (tspr->cstat & 2)
4002     {
4003         if (tspr->cstat & 512)
4004             s->plane.material.diffusemodulation[3] = transluctable[0];
4005         else
4006             s->plane.material.diffusemodulation[3] = transluctable[1];
4007     }
4008 
4009     float f = s->plane.material.diffusemodulation[3] * (1.0f - spriteext[tspr->owner].alpha);
4010     s->plane.material.diffusemodulation[3] = (GLubyte)f;
4011 
4012     if (searchit == 2)
4013     {
4014         polymer_setupdiffusemodulation(&s->plane, 0x03, (GLubyte *) &tspr->owner);
4015         s->hash = 0xDEADBEEF;
4016     }
4017 
4018     if (((tspr->cstat>>4) & 3) == 0)
4019         xratio = (float)(tspr->xrepeat) * 0.20f; // 32 / 160
4020     else
4021         xratio = (float)(tspr->xrepeat) * 0.25f;
4022 
4023     yratio = (float)(tspr->yrepeat) * 0.25f;
4024 
4025     xsize = tilesiz[curpicnum].x;
4026     ysize = tilesiz[curpicnum].y;
4027 
4028     if (usehightile && h_xsize[curpicnum])
4029     {
4030         xsize = h_xsize[curpicnum];
4031         ysize = h_ysize[curpicnum];
4032     }
4033 
4034     xsize = (int32_t)(xsize * xratio);
4035     ysize = (int32_t)(ysize * yratio);
4036 
4037     tilexoff = (usehightile && h_xsize[curpicnum]) ? h_xoffs[curpicnum] : picanm[curpicnum].xofs;
4038     tileyoff = (usehightile && h_xsize[curpicnum]) ? h_yoffs[curpicnum] : picanm[curpicnum].yofs;
4039 
4040     heinum = tspriteGetSlope(tspr);
4041 
4042     if (heinum == 0)
4043     {
4044         tilexoff += (int32_t)tspr->xoffset;
4045         tileyoff += (int32_t)tspr->yoffset;
4046     }
4047 
4048     xoff = (int32_t)(tilexoff * xratio);
4049     yoff = (int32_t)(tileyoff * yratio);
4050 
4051     if ((tspr->cstat & 128) && !flooraligned)
4052     {
4053         if (alignmask == 0)
4054             yoff -= ysize / 2;
4055         else
4056             centeryoff = ysize / 2;
4057     }
4058 
4059     spos[0] = (float)tspr->y;
4060     spos[1] = -(float)(tspr->z) / 16.0f;
4061     spos[2] = -(float)tspr->x;
4062 
4063     glMatrixMode(GL_MODELVIEW);
4064     glPushMatrix();
4065     glLoadIdentity();
4066 
4067     inbuffer = vertsprite;
4068 
4069     {
4070         const uint8_t xflip = !!(cs & SPR_XFLIP);
4071         const uint8_t yflip = !!(cs & SPR_YFLIP);
4072 
4073         // Initially set flipu and flipv.
4074         flipu = (xflip ^ flooraligned);
4075         flipv = (yflip && !flooraligned);
4076 
4077         if (pr_billboardingmode && alignmask==0)
4078         {
4079             // do surgery on the face tspr to make it look like a wall sprite
4080             tspr->cstat |= 16;
4081             tspr->ang = (fix16_to_int(viewangle) + 1024) & 2047;
4082         }
4083 
4084         if (flipu)
4085             xoff = -xoff;
4086 
4087         if (yflip && alignmask!=0)
4088             yoff = -yoff;
4089     }
4090 
4091     switch (tspr->cstat & SPR_ALIGN_MASK)
4092     {
4093     case 0:
4094         ang = (float)((fix16_to_int(viewangle)) & 2047) * (360.f/2048.f);
4095 
4096         glTranslatef(spos[0], spos[1], spos[2]);
4097         glRotatef(-ang, 0.0f, 1.0f, 0.0f);
4098         glRotatef(-horizang, 1.0f, 0.0f, 0.0f);
4099         glTranslatef((float)(-xoff), (float)(yoff), 0.0f);
4100         glScalef((float)(xsize), (float)(ysize), 1.0f);
4101         break;
4102     case SPR_WALL:
4103         ang = (float)((tspr->ang + 1024) & 2047) * (360.f/2048.f);
4104 
4105         glTranslatef(spos[0], spos[1], spos[2]);
4106         glRotatef(-ang, 0.0f, 1.0f, 0.0f);
4107         glTranslatef((float)(-xoff), (float)(yoff-centeryoff), 0.0f);
4108         glScalef((float)(xsize), (float)(ysize), 1.0f);
4109         break;
4110     case SPR_FLOOR:
4111     {
4112         float const sang = atan2f(float(heinum), 4096.f) * (180.f * float(M_1_PI));
4113         ang = (float)((tspr->ang + 1024) & 2047) * (360.f/2048.f);
4114 
4115         glTranslatef(spos[0], spos[1], spos[2]);
4116         glRotatef(-ang, 0.0f, 1.0f, 0.0f);
4117         glRotatef(-sang, 1.0f, 0.0f, 0.0f);
4118         glTranslatef((float)(-xoff), 1.0f, (float)(yoff));
4119         glScalef((float)(xsize), 1.0f, (float)(ysize));
4120 
4121         inbuffer = horizsprite;
4122         break;
4123     }
4124     }
4125 
4126     glGetFloatv(GL_MODELVIEW_MATRIX, spritemodelview);
4127     glPopMatrix();
4128 
4129     Bmemcpy(s->plane.buffer, inbuffer, sizeof(_prvert) * 4);
4130 
4131     if (flipu || flipv)
4132     {
4133         i = 0;
4134         do
4135         {
4136             if (flipu)
4137                 s->plane.buffer[i].u =
4138                 (s->plane.buffer[i].u - 1.0f) * -1.0f;
4139             if (flipv)
4140                 s->plane.buffer[i].v =
4141                 (s->plane.buffer[i].v - 1.0f) * -1.0f;
4142         }
4143         while (++i < 4);
4144     }
4145 
4146     i = 0;
4147     do
4148         polymer_transformpoint(&inbuffer[i].x, &s->plane.buffer[i].x, spritemodelview);
4149     while (++i < 4);
4150 
4151     polymer_computeplane(&s->plane);
4152 
4153     if (pr_nullrender < 2)
4154     {
4155         if (alignmask && (pr_vbos > 0))
4156         {
4157             glBindBuffer(GL_ARRAY_BUFFER, s->plane.vbo);
4158             glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(_prvert), s->plane.buffer);
4159             glBindBuffer(GL_ARRAY_BUFFER, 0);
4160         }
4161         else if (s->plane.vbo) // clean up the vbo if a wall/floor sprite becomes a face sprite
4162         {
4163             glDeleteBuffers(1, &s->plane.vbo);
4164             s->plane.vbo = 0;
4165         }
4166     }
4167 
4168     if (alignmask)
4169     {
4170         int32_t curpriority = 0;
4171 
4172         polymer_resetplanelights(&s->plane);
4173 
4174         while (curpriority < pr_maxlightpriority)
4175         {
4176             i = j = 0;
4177             while (j < lightcount)
4178             {
4179                 while (!prlights[i].flags.active)
4180                     i++;
4181 
4182                 if (prlights[i].priority != curpriority)
4183                 {
4184                     i++;
4185                     j++;
4186                     continue;
4187                 }
4188 
4189                 if (polymer_planeinlight(&s->plane, &prlights[i]))
4190                     polymer_addplanelight(&s->plane, i);
4191                 i++;
4192                 j++;
4193             }
4194             curpriority++;
4195         }
4196     }
4197 }
4198 
4199 // SKIES
polymer_getsky(void)4200 static void         polymer_getsky(void)
4201 {
4202     int32_t         i;
4203 
4204     i = 0;
4205     while (i < numsectors)
4206     {
4207         if (sector[i].ceilingstat & 1)
4208         {
4209             int32_t horizfrac;
4210 
4211             cursky = sector[i].ceilingpicnum;
4212             curskypal = sector[i].ceilingpal;
4213             curskyshade = sector[i].ceilingshade;
4214 
4215             getpsky(cursky, &horizfrac, NULL, NULL, NULL);
4216 
4217             switch (horizfrac)
4218             {
4219             case 0:
4220                 // psky always at same level wrt screen
4221                 curskyangmul = 0.f;
4222                 break;
4223             case 65536:
4224                 // psky horiz follows camera horiz
4225                 curskyangmul = 1.f;
4226                 break;
4227             default:
4228                 // sky has hard-coded parallax
4229                 curskyangmul = 1/DEFAULT_ARTSKY_ANGDIV;
4230                 break;
4231             }
4232 
4233             return;
4234         }
4235         i++;
4236     }
4237 }
4238 
polymer_drawsky(int16_t tilenum,char palnum,int8_t shade)4239 void         polymer_drawsky(int16_t tilenum, char palnum, int8_t shade)
4240 {
4241     float           pos[3];
4242     pthtyp*         pth;
4243 
4244     pos[0] = fglobalposy;
4245     pos[1] = fglobalposz * (-1.f/16.f);
4246     pos[2] = -fglobalposx;
4247 
4248     glPushMatrix();
4249     glLoadIdentity();
4250 
4251     glLoadMatrixf(curskymodelviewmatrix);
4252 
4253     glTranslatef(pos[0], pos[1], pos[2]);
4254     glScalef(1000.0f, 1000.0f, 1000.0f);
4255 
4256     drawingskybox = 1;
4257     pth = texcache_fetch(tilenum, 0, 0, DAMETH_NOMASK);
4258     drawingskybox = 0;
4259 
4260     if (pth && (pth->flags & PTH_SKYBOX))
4261         polymer_drawskybox(tilenum, palnum, shade);
4262     else
4263         polymer_drawartsky(tilenum, palnum, shade);
4264 
4265     glPopMatrix();
4266 }
4267 
polymer_initartsky(void)4268 static void         polymer_initartsky(void)
4269 {
4270     constexpr double factor = 2.0 * PI / (double)PSKYOFF_MAX;
4271 
4272     for (int i = 0; i < PSKYOFF_MAX; i++)
4273     {
4274         artskydata[i * 2 + 0] = -cos(i * factor);
4275         artskydata[i * 2 + 1] = sin(i * factor);
4276     }
4277 }
4278 
polymer_drawartsky(int16_t tilenum,char palnum,int8_t shade)4279 static void         polymer_drawartsky(int16_t tilenum, char palnum, int8_t shade)
4280 {
4281     pthtyp*         pth;
4282     GLuint          glpics[PSKYOFF_MAX];
4283     GLfloat         glcolors[PSKYOFF_MAX][3];
4284     int32_t         i, j;
4285     GLfloat         height = 2.45f / 2.0f;
4286 
4287     int32_t dapskybits;
4288     const int8_t *dapskyoff = getpsky(tilenum, NULL, &dapskybits, NULL, NULL);
4289     const int32_t numskytiles = 1<<dapskybits;
4290     const int32_t numskytilesm1 = numskytiles-1;
4291 
4292     i = 0;
4293     while (i < numskytiles)
4294     {
4295         int16_t picnum = tilenum + dapskyoff[i];
4296         // Prevent oob by bad user input:
4297         if (picnum >= MAXTILES)
4298             picnum = MAXTILES-1;
4299 
4300         tileUpdatePicnum(&picnum, 0);
4301         if (!waloff[picnum])
4302             tileLoad(picnum);
4303         pth = texcache_fetch(picnum, palnum, 0, DAMETH_NOMASK);
4304         glpics[i] = pth ? pth->glpic : 0;
4305 
4306         glcolors[i][0] = glcolors[i][1] = glcolors[i][2] = getshadefactor(shade, palnum);
4307 
4308         if (pth)
4309         {
4310             // tinting
4311             polytintflags_t const tintflags = hictinting[palnum].f;
4312             if (!(tintflags & HICTINT_PRECOMPUTED))
4313             {
4314                 if (pth->flags & PTH_HIGHTILE)
4315                 {
4316                     if (pth->palnum != palnum || (pth->effects & HICTINT_IN_MEMORY) || (tintflags & HICTINT_APPLYOVERALTPAL))
4317                         hictinting_apply(glcolors[i], palnum);
4318                 }
4319                 else if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
4320                     hictinting_apply(glcolors[i], palnum);
4321             }
4322 
4323             // global tinting
4324             if ((pth->flags & PTH_HIGHTILE) && have_basepal_tint())
4325                 hictinting_apply(glcolors[i], MAXPALOOKUPS-1);
4326 
4327             globaltinting_apply(glcolors[i]);
4328         }
4329 
4330         i++;
4331     }
4332 
4333     glEnable(GL_TEXTURE_2D);
4334     i = 0;
4335     j = 0;
4336     int32_t const increment = PSKYOFF_MAX>>max(3, dapskybits);  // In Polymer, an ART sky has 8 or 16 sides...
4337     while (i < PSKYOFF_MAX)
4338     {
4339         GLint oldswrap;
4340         // ... but in case a multi-psky specifies less than 8, repeat cyclically:
4341         const int8_t tileofs = j&numskytilesm1;
4342 
4343         glColor4f(glcolors[tileofs][0], glcolors[tileofs][1], glcolors[tileofs][2], 1.0f);
4344         glBindTexture(GL_TEXTURE_2D, glpics[tileofs]);
4345 
4346         glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &oldswrap);
4347         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
4348 
4349         polymer_drawartskyquad(i, (i + increment) & (PSKYOFF_MAX - 1), height);
4350 
4351         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, oldswrap);
4352 
4353         i += increment;
4354         ++j;
4355     }
4356     glDisable(GL_TEXTURE_2D);
4357 }
4358 
polymer_drawartskyquad(int32_t p1,int32_t p2,GLfloat height)4359 static void         polymer_drawartskyquad(int32_t p1, int32_t p2, GLfloat height)
4360 {
4361     glBegin(GL_QUADS);
4362     glTexCoord2f(0.0f, 0.0f);
4363     //OSD_Printf("PR: drawing %f %f %f\n", skybox[(p1 * 2) + 1], height, skybox[p1 * 2]);
4364     glVertex3f(artskydata[(p1 * 2) + 1], height, artskydata[p1 * 2]);
4365     glTexCoord2f(0.0f, 1.0f);
4366     //OSD_Printf("PR: drawing %f %f %f\n", skybox[(p1 * 2) + 1], -height, skybox[p1 * 2]);
4367     glVertex3f(artskydata[(p1 * 2) + 1], -height, artskydata[p1 * 2]);
4368     glTexCoord2f(1.0f, 1.0f);
4369     //OSD_Printf("PR: drawing %f %f %f\n", skybox[(p2 * 2) + 1], -height, skybox[p2 * 2]);
4370     glVertex3f(artskydata[(p2 * 2) + 1], -height, artskydata[p2 * 2]);
4371     glTexCoord2f(1.0f, 0.0f);
4372     //OSD_Printf("PR: drawing %f %f %f\n", skybox[(p2 * 2) + 1], height, skybox[p2 * 2]);
4373     glVertex3f(artskydata[(p2 * 2) + 1], height, artskydata[p2 * 2]);
4374     glEnd();
4375 }
4376 
polymer_drawskybox(int16_t tilenum,char palnum,int8_t shade)4377 static void         polymer_drawskybox(int16_t tilenum, char palnum, int8_t shade)
4378 {
4379     pthtyp*         pth;
4380     int32_t         i;
4381     GLfloat         color[3];
4382 
4383     if ((pr_vbos > 0) && (skyboxdatavbo == 0))
4384     {
4385         glGenBuffers(1, &skyboxdatavbo);
4386 
4387         glBindBuffer(GL_ARRAY_BUFFER, skyboxdatavbo);
4388         glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat) * 5 * 6, skyboxdata, modelvbousage);
4389 
4390         glBindBuffer(GL_ARRAY_BUFFER, 0);
4391     }
4392 
4393     if (pr_vbos > 0)
4394         glBindBuffer(GL_ARRAY_BUFFER, skyboxdatavbo);
4395 
4396     tileUpdatePicnum(&tilenum, 0);
4397 
4398     i = 0;
4399     while (i < 6)
4400     {
4401         drawingskybox = i + 1;
4402         pth = texcache_fetch(tilenum, palnum, 0, DAMETH_CLAMPED);
4403 
4404         color[0] = color[1] = color[2] = getshadefactor(shade, palnum);
4405 
4406         if (pth)
4407         {
4408             // tinting
4409             polytintflags_t const tintflags = hictinting[palnum].f;
4410             if (!(tintflags & HICTINT_PRECOMPUTED))
4411             {
4412                 if (pth->flags & PTH_HIGHTILE)
4413                 {
4414                     if (pth->palnum != palnum || (pth->effects & HICTINT_IN_MEMORY) || (tintflags & HICTINT_APPLYOVERALTPAL))
4415                         hictinting_apply(color, palnum);
4416                 }
4417                 else if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
4418                     hictinting_apply(color, palnum);
4419             }
4420 
4421             // global tinting
4422             if ((pth->flags & PTH_HIGHTILE) && have_basepal_tint())
4423                 hictinting_apply(color, MAXPALOOKUPS-1);
4424 
4425             globaltinting_apply(color);
4426         }
4427 
4428         glColor4f(color[0], color[1], color[2], 1.0);
4429         glEnable(GL_TEXTURE_2D);
4430         glBindTexture(GL_TEXTURE_2D, pth ? pth->glpic : 0);
4431         if (pr_vbos > 0)
4432         {
4433             glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), (GLfloat*)(4 * 5 * i * sizeof(GLfloat)));
4434             glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), (GLfloat*)(((4 * 5 * i) + 3) * sizeof(GLfloat)));
4435         } else {
4436             glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), &skyboxdata[4 * 5 * i]);
4437             glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), &skyboxdata[3 + (4 * 5 * i)]);
4438         }
4439         glDrawArrays(GL_QUADS, 0, 4);
4440         glDisable(GL_TEXTURE_2D);
4441 
4442         i++;
4443     }
4444     drawingskybox = 0;
4445 
4446     if (pr_vbos > 0)
4447         glBindBuffer(GL_ARRAY_BUFFER, 0);
4448 }
4449 
4450 // MDSPRITES
polymer_drawmdsprite(tspriteptr_t tspr)4451 static void         polymer_drawmdsprite(tspriteptr_t tspr)
4452 {
4453     md3model_t*     m;
4454     mdskinmap_t*    sk;
4455     float           *v0, *v1;
4456     md3surf_t       *s;
4457     char            targetpal, usinghighpal, foundpalskin;
4458     float           spos2[3], spos[3], tspos[3], lpos[3], tlpos[3], vec[3], mat[4][4];
4459     float           ang;
4460     float           scale;
4461     double          det;
4462     int32_t         surfi, i, j;
4463     GLubyte*        color;
4464     int32_t         materialbits;
4465     float           sradius, lradius;
4466     int16_t         modellights[PR_MAXLIGHTS];
4467     char            modellightcount;
4468     uint8_t         curpriority;
4469 
4470     uint8_t lpal = (tspr->owner >= MAXSPRITES) ? tspr->pal : sprite[tspr->owner].pal;
4471 
4472     m = (md3model_t*)models[tile2model[Ptile2tile(tspr->picnum,lpal)].modelid];
4473     updateanimation((md2model_t *)m,tspr,lpal);
4474 
4475     if ((pr_vbos > 1) && (m->indices == NULL))
4476         polymer_loadmodelvbos(m);
4477 
4478     // Hackish, but that means it's a model drawn by rotatesprite.
4479     if (tspriteptr[maxspritesonscreen] == tspr) {
4480         float       x, y, z;
4481 
4482         spos[0] = fglobalposy;
4483         spos[1] = fglobalposz * (-1.f/16.f);
4484         spos[2] = -fglobalposx;
4485 
4486         // The coordinates are actually floats disguised as int in this case
4487         memcpy(&x, &tspr->x, sizeof(float));
4488         memcpy(&y, &tspr->y, sizeof(float));
4489         memcpy(&z, &tspr->z, sizeof(float));
4490 
4491         spos2[0] = y - globalposy;
4492         spos2[1] = (z - fglobalposz) * (-1.f/16.f);
4493         spos2[2] = fglobalposx - x;
4494     } else {
4495         spos[0] = (float)tspr->y+spriteext[tspr->owner].mdposition_offset.y;
4496         spos[1] = -(float)(tspr->z+spriteext[tspr->owner].mdposition_offset.z) / 16.0f;
4497         spos[2] = -(float)(tspr->x+spriteext[tspr->owner].mdposition_offset.x);
4498 
4499         spos2[0] = spos2[1] = spos2[2] = 0.0f;
4500     }
4501 
4502     ang = (float)((tspr->ang+spriteext[tspr->owner].mdangoff) & 2047) * (360.f/2048.f);
4503     ang -= 90.0f;
4504     if (((tspr->cstat>>4) & 3) == 2)
4505         ang -= 90.0f;
4506 
4507     glMatrixMode(GL_MODELVIEW);
4508     glPushMatrix();
4509     glLoadIdentity();
4510     scale = (1.0/4.0);
4511     scale *= m->scale;
4512     if (pr_overridemodelscale) {
4513         scale *= pr_overridemodelscale;
4514     } else {
4515         scale *= m->bscale;
4516     }
4517 
4518     if (tspriteptr[maxspritesonscreen] == tspr) {
4519         float playerang, radplayerang, cosminusradplayerang, sinminusradplayerang, hudzoom;
4520 
4521         playerang = (globalang & 2047) * (360.f/2048.f) - 90.0f;
4522         radplayerang = (globalang & 2047) * (2.0f * fPI / 2048.0f);
4523         cosminusradplayerang = cos(-radplayerang);
4524         sinminusradplayerang = sin(-radplayerang);
4525         hudzoom = 65536.0 / spriteext[tspr->owner].mdpivot_offset.z;
4526 
4527         glTranslatef(spos[0], spos[1], spos[2]);
4528         glRotatef(horizang, -cosminusradplayerang, 0.0f, sinminusradplayerang);
4529         glRotatef(spriteext[tspr->owner].mdroll * (360.f/2048.f), sinminusradplayerang, 0.0f, cosminusradplayerang);
4530         glRotatef(-playerang, 0.0f, 1.0f, 0.0f);
4531         glScalef(hudzoom, 1.0f, 1.0f);
4532         glRotatef(playerang, 0.0f, 1.0f, 0.0f);
4533         glTranslatef(spos2[0], spos2[1], spos2[2]);
4534         glRotatef(-ang, 0.0f, 1.0f, 0.0f);
4535     } else {
4536         glTranslatef(spos[0], spos[1], spos[2]);
4537         glRotatef(-ang, 0.0f, 1.0f, 0.0f);
4538     }
4539     if (((tspr->cstat>>4) & 3) == 2)
4540     {
4541         glTranslatef(0.0f, 0.0, -(float)(tilesiz[tspr->picnum].y * tspr->yrepeat) / 8.0f);
4542         glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
4543     }
4544     else
4545         glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
4546 
4547     if ((tspr->cstat & 128) && (((tspr->cstat>>4) & 3) != 2))
4548         glTranslatef(0.0f, 0.0, -(float)(tilesiz[tspr->picnum].y * tspr->yrepeat) / 8.0f);
4549 
4550     // yoffset differs from zadd in that it does not follow cstat&8 y-flipping
4551     glTranslatef(0.0f, 0.0, m->yoffset * 64 * scale * tspr->yrepeat);
4552 
4553     if (tspr->cstat & 8)
4554     {
4555         glTranslatef(0.0f, 0.0, (float)(tilesiz[tspr->picnum].y * tspr->yrepeat) / 4.0f);
4556         glScalef(1.0f, 1.0f, -1.0f);
4557     }
4558 
4559     if (tspr->cstat & 4)
4560         glScalef(1.0f, -1.0f, 1.0f);
4561 
4562     if (!(tspr->cstat & 4) != !(tspr->cstat & 8)) {
4563         // Only inverting one coordinate will reverse the winding order of
4564         // faces, so we need to account for that when culling.
4565         SWITCH_CULL_DIRECTION;
4566     }
4567 
4568     glScalef(scale * tspr->xrepeat, scale * tspr->xrepeat, scale * tspr->yrepeat);
4569     glTranslatef(0.0f, 0.0, m->zadd * 64);
4570 
4571     // scripted model rotation
4572     if (tspr->owner < MAXSPRITES &&
4573         (spriteext[tspr->owner].mdpitch || spriteext[tspr->owner].mdroll))
4574     {
4575         float       pitchang, rollang, offsets[3];
4576 
4577         pitchang = (float)(spriteext[tspr->owner].mdpitch) * (360.f/2048.f);
4578         rollang = (float)(spriteext[tspr->owner].mdroll) * (360.f/2048.f);
4579 
4580         offsets[0] = -spriteext[tspr->owner].mdpivot_offset.x / (scale * tspr->xrepeat);
4581         offsets[1] = -spriteext[tspr->owner].mdpivot_offset.y / (scale * tspr->xrepeat);
4582         offsets[2] = (float)(spriteext[tspr->owner].mdpivot_offset.z) / 16.0f / (scale * tspr->yrepeat);
4583 
4584         glTranslatef(-offsets[0], -offsets[1], -offsets[2]);
4585 
4586         glRotatef(pitchang, 0.0f, 1.0f, 0.0f);
4587         glRotatef(rollang, -1.0f, 0.0f, 0.0f);
4588 
4589         glTranslatef(offsets[0], offsets[1], offsets[2]);
4590     }
4591 
4592     glGetFloatv(GL_MODELVIEW_MATRIX, spritemodelview);
4593 
4594     glPopMatrix();
4595     glPushMatrix();
4596     glMultMatrixf(spritemodelview);
4597 
4598     // invert this matrix to get the polymer -> mdsprite space
4599     memcpy(mat, spritemodelview, sizeof(float) * 16);
4600     INVERT_4X4(mdspritespace, det, mat);
4601 
4602     // debug code for drawing the model bounding sphere
4603 //     glDisable(GL_TEXTURE_2D);
4604 //     glBegin(GL_LINES);
4605 //     glColor4f(1.0, 0.0, 0.0, 1.0);
4606 //     glVertex3f(m->head.frames[m->cframe].cen.x,
4607 //                 m->head.frames[m->cframe].cen.y,
4608 //                 m->head.frames[m->cframe].cen.z);
4609 //     glVertex3f(m->head.frames[m->cframe].cen.x + m->head.frames[m->cframe].r,
4610 //                 m->head.frames[m->cframe].cen.y,
4611 //                 m->head.frames[m->cframe].cen.z);
4612 //     glColor4f(0.0, 1.0, 0.0, 1.0);
4613 //     glVertex3f(m->head.frames[m->cframe].cen.x,
4614 //                 m->head.frames[m->cframe].cen.y,
4615 //                 m->head.frames[m->cframe].cen.z);
4616 //     glVertex3f(m->head.frames[m->cframe].cen.x,
4617 //                 m->head.frames[m->cframe].cen.y + m->head.frames[m->cframe].r,
4618 //                 m->head.frames[m->cframe].cen.z);
4619 //     glColor4f(0.0, 0.0, 1.0, 1.0);
4620 //     glVertex3f(m->head.frames[m->cframe].cen.x,
4621 //                 m->head.frames[m->cframe].cen.y,
4622 //                 m->head.frames[m->cframe].cen.z);
4623 //     glVertex3f(m->head.frames[m->cframe].cen.x,
4624 //                 m->head.frames[m->cframe].cen.y,
4625 //                 m->head.frames[m->cframe].cen.z + m->head.frames[m->cframe].r);
4626 //     glEnd();
4627 //     glEnable(GL_TEXTURE_2D);
4628 
4629     polymer_getscratchmaterial(&mdspritematerial);
4630 
4631     color = mdspritematerial.diffusemodulation;
4632 
4633     color[0] = color[1] = color[2] =
4634         (GLubyte)(((float)(numshades-min(max((tspr->shade * shadescale)+m->shadeoff,0.f),(float)numshades)))/((float)numshades) * 0xFF);
4635 
4636     usinghighpal = (pr_highpalookups &&
4637                     prhighpalookups[curbasepal][tspr->pal].map);
4638 
4639     // tinting
4640     polytintflags_t const tintflags = hictinting[tspr->pal].f;
4641     if (!usinghighpal && !(tintflags & HICTINT_PRECOMPUTED))
4642     {
4643         if (!(m->flags&1))
4644             hictinting_apply_ub(color, tspr->pal);
4645         else globalnoeffect=1; //mdloadskin reads this
4646     }
4647 
4648     // global tinting
4649     if (!usinghighpal && have_basepal_tint())
4650         hictinting_apply_ub(color, MAXPALOOKUPS-1);
4651 
4652     globaltinting_apply_ub(color);
4653 
4654     if (tspr->cstat & 2)
4655     {
4656         if (!(tspr->cstat&512))
4657             color[3] = transluctable[1];
4658         else
4659             color[3] = transluctable[0];
4660     } else
4661         color[3] = 0xFF;
4662 
4663     {
4664         double f = color[3] * (1.0f - spriteext[tspr->owner].alpha);
4665         color[3] = (GLubyte)f;
4666     }
4667 
4668     if (searchit == 2)
4669     {
4670         color[0] = 0x03;
4671         color[1] = ((GLubyte *)(&tspr->owner))[0];
4672         color[2] = ((GLubyte *)(&tspr->owner))[1];
4673         color[3] = 0xFF;
4674     }
4675 
4676     if (pr_gpusmoothing)
4677         mdspritematerial.frameprogress = m->interpol;
4678 
4679     mdspritematerial.mdspritespace = GL_TRUE;
4680 
4681     modellightcount = 0;
4682     curpriority = 0;
4683 
4684     // light culling
4685     if (lightcount && (!depth || mirrors[depth-1].plane))
4686     {
4687         sradius = (m->head.frames[m->cframe].r * (1 - m->interpol)) +
4688                   (m->head.frames[m->nframe].r * m->interpol);
4689 
4690         sradius *= max(scale * tspr->xrepeat, scale * tspr->yrepeat);
4691         sradius /= 1000.0f;
4692 
4693         spos[0] = (m->head.frames[m->cframe].cen.x * (1 - m->interpol)) +
4694                   (m->head.frames[m->nframe].cen.x * m->interpol);
4695         spos[1] = (m->head.frames[m->cframe].cen.y * (1 - m->interpol)) +
4696                   (m->head.frames[m->nframe].cen.y * m->interpol);
4697         spos[2] = (m->head.frames[m->cframe].cen.z * (1 - m->interpol)) +
4698                   (m->head.frames[m->nframe].cen.z * m->interpol);
4699 
4700         polymer_transformpoint(spos, tspos, spritemodelview);
4701         polymer_transformpoint(tspos, spos, rootmodelviewmatrix);
4702 
4703         while (curpriority < pr_maxlightpriority)
4704         {
4705             i = j = 0;
4706             while (j < lightcount)
4707             {
4708                 while (!prlights[i].flags.active)
4709                     i++;
4710 
4711                 if (prlights[i].priority != curpriority)
4712                 {
4713                     i++;
4714                     j++;
4715                     continue;
4716                 }
4717 
4718                 lradius = prlights[i].range / 1000.0f;
4719 
4720                 lpos[0] = (float)prlights[i].y;
4721                 lpos[1] = -(float)prlights[i].z / 16.0f;
4722                 lpos[2] = -(float)prlights[i].x;
4723 
4724                 polymer_transformpoint(lpos, tlpos, rootmodelviewmatrix);
4725 
4726                 vec[0] = tlpos[0] - spos[0];
4727                 vec[0] *= vec[0];
4728                 vec[1] = tlpos[1] - spos[1];
4729                 vec[1] *= vec[1];
4730                 vec[2] = tlpos[2] - spos[2];
4731                 vec[2] *= vec[2];
4732 
4733                 if ((vec[0] + vec[1] + vec[2]) <= ((sradius+lradius) * (sradius+lradius)))
4734                     modellights[modellightcount++] = i;
4735 
4736                 i++;
4737                 j++;
4738             }
4739             curpriority++;
4740         }
4741     }
4742 
4743     for (surfi=0;surfi<m->head.numsurfs;surfi++)
4744     {
4745         s = &m->head.surfs[surfi];
4746         v0 = &s->geometry[m->cframe*s->numverts*15];
4747         v1 = &s->geometry[m->nframe*s->numverts*15];
4748 
4749         // debug code for drawing model normals
4750 //         glDisable(GL_TEXTURE_2D);
4751 //         glBegin(GL_LINES);
4752 //         glColor4f(1.0, 1.0, 1.0, 1.0);
4753 //
4754 //         int i = 0;
4755 //         while (i < s->numverts)
4756 //         {
4757 //             glVertex3f(v0[(i * 6) + 0],
4758 //                         v0[(i * 6) + 1],
4759 //                         v0[(i * 6) + 2]);
4760 //             glVertex3f(v0[(i * 6) + 0] + v0[(i * 6) + 3] * 100,
4761 //                         v0[(i * 6) + 1] + v0[(i * 6) + 4] * 100,
4762 //                         v0[(i * 6) + 2] + v0[(i * 6) + 5] * 100);
4763 //             i++;
4764 //         }
4765 //         glEnd();
4766 //         glEnable(GL_TEXTURE_2D);
4767 
4768 
4769         targetpal = tspr->pal;
4770         foundpalskin = 0;
4771 
4772         for (sk = m->skinmap; sk; sk = sk->next)
4773             if ((int32_t)sk->palette == tspr->pal &&
4774                  sk->skinnum == tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum &&
4775                  sk->surfnum == surfi)
4776         {
4777             if (sk->specpower != 1.0)
4778                 mdspritematerial.specmaterial[0] = sk->specpower;
4779             mdspritematerial.specmaterial[1] = sk->specfactor;
4780             foundpalskin = 1;
4781         }
4782 
4783         // If we have a global palette tint, the palskin won't do us any good
4784         if (curbasepal)
4785             foundpalskin = 0;
4786 
4787         if (!foundpalskin && usinghighpal) {
4788             // We don't have a specific skin defined for this palette
4789             // Use the base skin instead and plug in our highpalookup map
4790             targetpal = 0;
4791             mdspritematerial.highpalookupmap = prhighpalookups[curbasepal][tspr->pal].map;
4792         }
4793 
4794         mdspritematerial.diffusemap =
4795                 mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,targetpal,surfi);
4796         if (!mdspritematerial.diffusemap)
4797             continue;
4798 
4799         if (!(tspr->clipdist & TSPR_FLAGS_MDHACK))
4800         {
4801             mdspritematerial.detailmap =
4802                     mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,DETAILPAL,surfi);
4803 
4804             for (sk = m->skinmap; sk; sk = sk->next)
4805                 if ((int32_t)sk->palette == DETAILPAL &&
4806                     sk->skinnum == tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum &&
4807                     sk->surfnum == surfi)
4808                     mdspritematerial.detailscale[0] = mdspritematerial.detailscale[1] = sk->param;
4809 
4810             mdspritematerial.specmap =
4811                     mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,SPECULARPAL,surfi);
4812 
4813             mdspritematerial.normalmap =
4814                     mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,NORMALPAL,surfi);
4815 
4816             for (sk = m->skinmap; sk; sk = sk->next)
4817                 if ((int32_t)sk->palette == NORMALPAL &&
4818                     sk->skinnum == tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum &&
4819                     sk->surfnum == surfi) {
4820                     mdspritematerial.normalbias[0] = sk->specpower;
4821                     mdspritematerial.normalbias[1] = sk->specfactor;
4822                 }
4823 
4824             mdspritematerial.glowmap =
4825                     mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,GLOWPAL,surfi);
4826         }
4827 
4828         glEnableClientState(GL_NORMAL_ARRAY);
4829 
4830         if (pr_vbos > 1)
4831         {
4832             glBindBuffer(GL_ARRAY_BUFFER, m->texcoords[surfi]);
4833             glTexCoordPointer(2, GL_FLOAT, 0, 0);
4834 
4835             glBindBuffer(GL_ARRAY_BUFFER, m->geometry[surfi]);
4836             glVertexPointer(3, GL_FLOAT, sizeof(float) * 15, (GLfloat*)(m->cframe * s->numverts * sizeof(float) * 15));
4837             glNormalPointer(GL_FLOAT, sizeof(float) * 15, (GLfloat*)(m->cframe * s->numverts * sizeof(float) * 15) + 3);
4838 
4839             mdspritematerial.tbn = (GLfloat*)(m->cframe * s->numverts * sizeof(float) * 15) + 6;
4840 
4841             if (pr_gpusmoothing) {
4842                 mdspritematerial.nextframedata = (GLfloat*)(m->nframe * s->numverts * sizeof(float) * 15);
4843             }
4844 
4845             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->indices[surfi]);
4846 
4847             curlight = 0;
4848             do {
4849                 materialbits = polymer_bindmaterial(&mdspritematerial, modellights, modellightcount);
4850                 glDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_INT, 0);
4851                 polymer_unbindmaterial(materialbits);
4852             } while ((++curlight < modellightcount) && (curlight < pr_maxlightpasses));
4853 
4854             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
4855             glBindBuffer(GL_ARRAY_BUFFER, 0);
4856         }
4857         else
4858         {
4859             glVertexPointer(3, GL_FLOAT, sizeof(float) * 15, v0);
4860             glNormalPointer(GL_FLOAT, sizeof(float) * 15, v0 + 3);
4861             glTexCoordPointer(2, GL_FLOAT, 0, s->uv);
4862 
4863             mdspritematerial.tbn = v0 + 6;
4864 
4865             if (pr_gpusmoothing) {
4866                 mdspritematerial.nextframedata = (GLfloat*)(v1);
4867             }
4868 
4869             curlight = 0;
4870             do {
4871                 materialbits = polymer_bindmaterial(&mdspritematerial, modellights, modellightcount);
4872                 glDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_INT, s->tris);
4873                 polymer_unbindmaterial(materialbits);
4874             } while ((++curlight < modellightcount) && (curlight < pr_maxlightpasses));
4875         }
4876 
4877         glDisableClientState(GL_NORMAL_ARRAY);
4878     }
4879 
4880     glPopMatrix();
4881 
4882     if (!(tspr->cstat & 4) != !(tspr->cstat & 8)) {
4883         SWITCH_CULL_DIRECTION;
4884     }
4885 
4886     globalnoeffect = 0;
4887 }
4888 
polymer_loadmodelvbos(md3model_t * m)4889 static void         polymer_loadmodelvbos(md3model_t* m)
4890 {
4891     int32_t         i;
4892     md3surf_t       *s;
4893 
4894     m->indices = (GLuint *)Xmalloc(m->head.numsurfs * sizeof(GLuint));
4895     m->texcoords = (GLuint *)Xmalloc(m->head.numsurfs * sizeof(GLuint));
4896     m->geometry = (GLuint *)Xmalloc(m->head.numsurfs * sizeof(GLuint));
4897 
4898     glGenBuffers(m->head.numsurfs, m->indices);
4899     glGenBuffers(m->head.numsurfs, m->texcoords);
4900     glGenBuffers(m->head.numsurfs, m->geometry);
4901 
4902     i = 0;
4903     while (i < m->head.numsurfs)
4904     {
4905         s = &m->head.surfs[i];
4906 
4907         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->indices[i]);
4908         glBufferData(GL_ELEMENT_ARRAY_BUFFER, s->numtris * sizeof(md3tri_t), s->tris, modelvbousage);
4909 
4910         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
4911 
4912         glBindBuffer(GL_ARRAY_BUFFER, m->texcoords[i]);
4913         glBufferData(GL_ARRAY_BUFFER, s->numverts * sizeof(md3uv_t), s->uv, modelvbousage);
4914 
4915         glBindBuffer(GL_ARRAY_BUFFER, m->geometry[i]);
4916         glBufferData(GL_ARRAY_BUFFER, s->numframes * s->numverts * sizeof(float) * (15), s->geometry, modelvbousage);
4917 
4918         glBindBuffer(GL_ARRAY_BUFFER, 0);
4919         i++;
4920     }
4921 }
4922 
4923 // MATERIALS
polymer_getscratchmaterial(_prmaterial * material)4924 static void         polymer_getscratchmaterial(_prmaterial* material)
4925 {
4926     // this function returns a material that won't validate any bits
4927     // make sure to keep it up to date with the validation logic in bindmaterial
4928 
4929     // PR_BIT_ANIM_INTERPOLATION
4930     material->frameprogress = 0.0f;
4931     material->nextframedata = (float*)-1;
4932     // PR_BIT_NORMAL_MAP
4933     material->normalmap = 0;
4934     material->normalbias[0] = material->normalbias[1] = 0.0f;
4935     material->tbn = NULL;
4936     // PR_BIT_ART_MAP
4937     material->artmap = 0;
4938     material->basepalmap = 0;
4939     material->lookupmap = 0;
4940     // PR_BIT_DIFFUSE_MAP
4941     material->diffusemap = 0;
4942     material->diffusescale[0] = material->diffusescale[1] = 1.0f;
4943     // PR_BIT_HIGHPALOOKUP_MAP
4944     material->highpalookupmap = 0;
4945     // PR_BIT_DIFFUSE_DETAIL_MAP
4946     material->detailmap = 0;
4947     material->detailscale[0] = material->detailscale[1] = 1.0f;
4948     // PR_BIT_DIFFUSE_MODULATION
4949     material->diffusemodulation[0] =
4950             material->diffusemodulation[1] =
4951             material->diffusemodulation[2] =
4952             material->diffusemodulation[3] = 0xFF;
4953     // PR_BIT_SPECULAR_MAP
4954     material->specmap = 0;
4955     // PR_BIT_SPECULAR_MATERIAL
4956     material->specmaterial[0] = 15.0f;
4957     material->specmaterial[1] = 1.0f;
4958     // PR_BIT_MIRROR_MAP
4959     material->mirrormap = 0;
4960     // PR_BIT_GLOW_MAP
4961     material->glowmap = 0;
4962     // PR_BIT_PROJECTION_MAP
4963     material->mdspritespace = GL_FALSE;
4964 }
4965 
polymer_setupartmap(int16_t tilenum,char pal)4966 static void         polymer_setupartmap(int16_t tilenum, char pal)
4967 {
4968     if (!prartmaps[tilenum]) {
4969         char *tilebuffer = (char *) waloff[tilenum];
4970         char *tempbuffer = (char *) Xmalloc(tilesiz[tilenum].x * tilesiz[tilenum].y);
4971         int i, j, k;
4972 
4973         i = k = 0;
4974         while (i < tilesiz[tilenum].y) {
4975             j = 0;
4976             while (j < tilesiz[tilenum].x) {
4977                 tempbuffer[k] = tilebuffer[(j * tilesiz[tilenum].y) + i];
4978                 k++;
4979                 j++;
4980             }
4981             i++;
4982         }
4983 
4984         glGenTextures(1, &prartmaps[tilenum]);
4985         glBindTexture(GL_TEXTURE_2D, prartmaps[tilenum]);
4986         glTexImage2D(GL_TEXTURE_2D,
4987             0,
4988             GL_RED,
4989             tilesiz[tilenum].x,
4990             tilesiz[tilenum].y,
4991             0,
4992             GL_RED,
4993             GL_UNSIGNED_BYTE,
4994             tempbuffer);
4995         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4996         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4997         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
4998         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
4999         glBindTexture(GL_TEXTURE_2D, 0);
5000         Xfree(tempbuffer);
5001     }
5002 
5003     if (!prbasepalmaps[curbasepal]) {
5004         glGenTextures(1, &prbasepalmaps[curbasepal]);
5005         glBindTexture(GL_TEXTURE_2D, prbasepalmaps[curbasepal]);
5006         glTexImage2D(GL_TEXTURE_2D,
5007             0,
5008             GL_RGB,
5009             256,
5010             1,
5011             0,
5012             GL_RGB,
5013             GL_UNSIGNED_BYTE,
5014             basepaltable[curbasepal]);
5015         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5016         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5017         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP);
5018         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP);
5019         glBindTexture(GL_TEXTURE_2D, 0);
5020     }
5021 
5022     if (!prlookups[pal]) {
5023         glGenTextures(1, &prlookups[pal]);
5024         glBindTexture(GL_TEXTURE_RECTANGLE_ARB, prlookups[pal]);
5025         glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
5026             0,
5027             GL_RED,
5028             256,
5029             numshades,
5030             0,
5031             GL_RED,
5032             GL_UNSIGNED_BYTE,
5033             palookup[pal]);
5034         glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5035         glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5036         glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP);
5037         glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP);
5038         glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
5039     }
5040 }
5041 
polymer_getbuildmaterial(_prmaterial * material,int16_t tilenum,char pal,int8_t shade,int8_t vis,int32_t cmeth)5042 static _prbucket*   polymer_getbuildmaterial(_prmaterial* material, int16_t tilenum, char pal, int8_t shade, int8_t vis, int32_t cmeth)
5043 {
5044     // find corresponding bucket; XXX key that with pr_buckets later, need to be tied to restartvid
5045     _prbucket *bucketptr = polymer_findbucket(tilenum, pal);
5046 
5047     polymer_getscratchmaterial(material);
5048 
5049     if (!waloff[tilenum])
5050         tileLoad(tilenum);
5051 
5052     // PR_BIT_DIFFUSE_MAP
5053     pthtyp *pth = texcache_fetch(tilenum, pal, 0, cmeth);
5054 
5055     if (pth)
5056     {
5057         material->diffusemap = pth->glpic;
5058 
5059         if (pth->hicr)
5060         {
5061             material->diffusescale[0] = pth->hicr->scale.x;
5062             material->diffusescale[1] = pth->hicr->scale.y;
5063         }
5064     }
5065 
5066     int32_t usinghighpal = 0;
5067 
5068     // Lazily fill in all the textures we need, move this to precaching later
5069     if (pr_artmapping && !(globalflags & GLOBAL_NO_GL_TILESHADES) && polymer_eligible_for_artmap(tilenum, pth))
5070     {
5071         polytintflags_t const tintflags = hictinting[pal].f;
5072 
5073         if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
5074         {
5075             if (!(tintflags & HICTINT_APPLYOVERPALSWAP))
5076                 pal = 0;
5077         }
5078 
5079         if (!prartmaps[tilenum] || !prbasepalmaps[curbasepal] || !prlookups[pal])
5080             polymer_setupartmap(tilenum, pal);
5081 
5082         material->artmap = prartmaps[tilenum];
5083         material->basepalmap = prbasepalmaps[curbasepal];
5084         material->lookupmap = prlookups[pal];
5085 
5086         if (!material->basepalmap || !material->lookupmap) {
5087             material->artmap = 0;
5088         }
5089 
5090         material->shadeoffset = shade;
5091         material->visibility = (uint8_t)(vis+16);
5092 
5093         globaltinting_apply_ub(material->diffusemodulation);
5094         // all the stuff below is mutually exclusive with artmapping
5095         goto done;
5096     }
5097 
5098     // PR_BIT_HIGHPALOOKUP_MAP
5099     if (pr_highpalookups && prhighpalookups[curbasepal][pal].map &&
5100         hicfindsubst(tilenum, 0) &&
5101         (curbasepal || (hicfindsubst(tilenum, pal)->palnum != pal)))
5102     {
5103         material->highpalookupmap = prhighpalookups[curbasepal][pal].map;
5104         pal = 0;
5105         usinghighpal = 1;
5106     }
5107 
5108     if (pth)
5109     {
5110         if (pth->hicr)
5111         {
5112             // PR_BIT_SPECULAR_MATERIAL
5113             if (pth->hicr->specpower != 1.0f)
5114                 material->specmaterial[0] = pth->hicr->specpower;
5115             material->specmaterial[1] = pth->hicr->specfactor;
5116         }
5117 
5118         // PR_BIT_DIFFUSE_MODULATION
5119         material->diffusemodulation[0] =
5120             material->diffusemodulation[1] =
5121             material->diffusemodulation[2] =
5122             (GLubyte)(getshadefactor(shade, pal) * 0xFF);
5123 
5124         // tinting
5125         polytintflags_t const tintflags = hictinting[pal].f;
5126         if (!(tintflags & HICTINT_PRECOMPUTED))
5127         {
5128             if (pth->flags & PTH_HIGHTILE)
5129             {
5130                 if (pth->palnum != pal || (pth->effects & HICTINT_IN_MEMORY) || (tintflags & HICTINT_APPLYOVERALTPAL))
5131                     hictinting_apply_ub(material->diffusemodulation, pal);
5132             }
5133             else if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
5134                 hictinting_apply_ub(material->diffusemodulation, pal);
5135         }
5136 
5137         // global tinting
5138         if ((pth->flags & PTH_HIGHTILE) && !usinghighpal && have_basepal_tint())
5139             hictinting_apply_ub(material->diffusemodulation, MAXPALOOKUPS-1);
5140 
5141         globaltinting_apply_ub(material->diffusemodulation);
5142 
5143         // PR_BIT_GLOW_MAP
5144         if (r_fullbrights && pth->flags & PTH_HASFULLBRIGHT)
5145             material->glowmap = pth->ofb->glpic;
5146     }
5147 
5148     // PR_BIT_DIFFUSE_DETAIL_MAP
5149     if (hicfindsubst(tilenum, DETAILPAL, 1) && (pth = texcache_fetch(tilenum, DETAILPAL, 0, DAMETH_NOMASK)) &&
5150         pth->hicr && (pth->hicr->palnum == DETAILPAL))
5151     {
5152         material->detailmap = pth->glpic;
5153         material->detailscale[0] = pth->hicr->scale.x;
5154         material->detailscale[1] = pth->hicr->scale.y;
5155     }
5156 
5157     // PR_BIT_GLOW_MAP
5158     if (hicfindsubst(tilenum, GLOWPAL, 1) && (pth = texcache_fetch(tilenum, GLOWPAL, 0, DAMETH_MASK)) &&
5159         pth->hicr && (pth->hicr->palnum == GLOWPAL))
5160         material->glowmap = pth->glpic;
5161 
5162     // PR_BIT_SPECULAR_MAP
5163     if (hicfindsubst(tilenum, SPECULARPAL, 1) && (pth = texcache_fetch(tilenum, SPECULARPAL, 0, DAMETH_NOMASK)) &&
5164         pth->hicr && (pth->hicr->palnum == SPECULARPAL))
5165         material->specmap = pth->glpic;
5166 
5167     // PR_BIT_NORMAL_MAP
5168     if (hicfindsubst(tilenum, NORMALPAL, 1) && (pth = texcache_fetch(tilenum, NORMALPAL, 0, DAMETH_NOMASK)) &&
5169         pth->hicr && (pth->hicr->palnum == NORMALPAL))
5170     {
5171         material->normalmap = pth->glpic;
5172         material->normalbias[0] = pth->hicr->specpower;
5173         material->normalbias[1] = pth->hicr->specfactor;
5174     }
5175 
5176 done:
5177     if (bucketptr->invalidmaterial != 0)
5178     {
5179         bucketptr->material = *material;
5180         bucketptr->invalidmaterial = 0;
5181     }
5182 
5183     return bucketptr;
5184 }
5185 
polymer_bindmaterial(const _prmaterial * material,const int16_t * lights,int matlightcount)5186 static int32_t      polymer_bindmaterial(const _prmaterial *material, const int16_t* lights, int matlightcount)
5187 {
5188     int32_t         programbits;
5189     int32_t         texunit;
5190 
5191     programbits = 0;
5192 
5193     // --------- bit validation
5194 
5195     // PR_BIT_ANIM_INTERPOLATION
5196     if (material->nextframedata != ((float*)-1))
5197         programbits |= prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit;
5198 
5199     // PR_BIT_LIGHTING_PASS
5200     if (curlight && matlightcount)
5201         programbits |= prprogrambits[PR_BIT_LIGHTING_PASS].bit;
5202 
5203     // PR_BIT_NORMAL_MAP
5204     if (pr_normalmapping && material->normalmap)
5205         programbits |= prprogrambits[PR_BIT_NORMAL_MAP].bit;
5206 
5207     // PR_BIT_ART_MAP
5208     if (pr_artmapping && material->artmap &&
5209         !(globalflags & GLOBAL_NO_GL_TILESHADES) &&
5210         (overridematerial & prprogrambits[PR_BIT_ART_MAP].bit)) {
5211         programbits |= prprogrambits[PR_BIT_ART_MAP].bit;
5212     } else
5213     // PR_BIT_DIFFUSE_MAP
5214     if (material->diffusemap) {
5215         programbits |= prprogrambits[PR_BIT_DIFFUSE_MAP].bit;
5216         programbits |= prprogrambits[PR_BIT_DIFFUSE_MAP2].bit;
5217     }
5218 
5219     // PR_BIT_HIGHPALOOKUP_MAP
5220     if (material->highpalookupmap)
5221         programbits |= prprogrambits[PR_BIT_HIGHPALOOKUP_MAP].bit;
5222 
5223     // PR_BIT_DIFFUSE_DETAIL_MAP
5224     if (r_detailmapping && material->detailmap)
5225         programbits |= prprogrambits[PR_BIT_DIFFUSE_DETAIL_MAP].bit;
5226 
5227     // PR_BIT_DIFFUSE_MODULATION
5228     programbits |= prprogrambits[PR_BIT_DIFFUSE_MODULATION].bit;
5229 
5230     // PR_BIT_SPECULAR_MAP
5231     if (pr_specularmapping && material->specmap)
5232         programbits |= prprogrambits[PR_BIT_SPECULAR_MAP].bit;
5233 
5234     // PR_BIT_SPECULAR_MATERIAL
5235     if ((material->specmaterial[0] != 15.0) || (material->specmaterial[1] != 1.0) || pr_overridespecular)
5236         programbits |= prprogrambits[PR_BIT_SPECULAR_MATERIAL].bit;
5237 
5238     // PR_BIT_MIRROR_MAP
5239     if (!curlight && material->mirrormap)
5240         programbits |= prprogrambits[PR_BIT_MIRROR_MAP].bit;
5241 
5242     // PR_BIT_FOG
5243     if (!material->artmap && !curlight && !material->mirrormap)
5244         programbits |= prprogrambits[PR_BIT_FOG].bit;
5245 
5246     // PR_BIT_GLOW_MAP
5247     if (!curlight && r_glowmapping && material->glowmap)
5248         programbits |= prprogrambits[PR_BIT_GLOW_MAP].bit;
5249 
5250     // PR_BIT_POINT_LIGHT
5251     if (matlightcount) {
5252         programbits |= prprogrambits[PR_BIT_POINT_LIGHT].bit;
5253         // PR_BIT_SPOT_LIGHT
5254         if (prlights[lights[curlight]].radius) {
5255             programbits |= prprogrambits[PR_BIT_SPOT_LIGHT].bit;
5256             // PR_BIT_SHADOW_MAP
5257             if (prlights[lights[curlight]].rtindex != -1) {
5258                 programbits |= prprogrambits[PR_BIT_SHADOW_MAP].bit;
5259                 programbits |= prprogrambits[PR_BIT_PROJECTION_MAP].bit;
5260             }
5261             // PR_BIT_LIGHT_MAP
5262             if (prlights[lights[curlight]].lightmap) {
5263                 programbits |= prprogrambits[PR_BIT_LIGHT_MAP].bit;
5264                 programbits |= prprogrambits[PR_BIT_PROJECTION_MAP].bit;
5265             }
5266         }
5267     }
5268 
5269     // material override
5270     programbits &= overridematerial;
5271 
5272     programbits |= prprogrambits[PR_BIT_HEADER].bit;
5273     programbits |= prprogrambits[PR_BIT_FOOTER].bit;
5274 
5275     // --------- program compiling
5276     if (!prprograms[programbits].handle)
5277         polymer_compileprogram(programbits);
5278 
5279     polymost_useShaderProgram(prprograms[programbits].handle);
5280 
5281     // --------- bit setup
5282 
5283     texunit = 0;
5284 
5285     // PR_BIT_ANIM_INTERPOLATION
5286     if (programbits & prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit)
5287     {
5288         glEnableVertexAttribArray(prprograms[programbits].attrib_nextFrameData);
5289         if (prprograms[programbits].attrib_nextFrameNormal != -1)
5290             glEnableVertexAttribArray(prprograms[programbits].attrib_nextFrameNormal);
5291         glVertexAttribPointer(prprograms[programbits].attrib_nextFrameData,
5292                                3, GL_FLOAT, GL_FALSE,
5293                                sizeof(float) * 15,
5294                                material->nextframedata);
5295         if (prprograms[programbits].attrib_nextFrameNormal != -1)
5296             glVertexAttribPointer(prprograms[programbits].attrib_nextFrameNormal,
5297                                    3, GL_FLOAT, GL_FALSE,
5298                                    sizeof(float) * 15,
5299                                    material->nextframedata + 3);
5300 
5301         glUniform1f(prprograms[programbits].uniform_frameProgress, material->frameprogress);
5302     }
5303 
5304     // PR_BIT_LIGHTING_PASS
5305     if (programbits & prprogrambits[PR_BIT_LIGHTING_PASS].bit)
5306     {
5307         glPushAttrib(GL_COLOR_BUFFER_BIT);
5308         glEnable(GL_BLEND);
5309         glBlendFunc(GL_ONE, GL_ONE);
5310 
5311         if (prlights[lights[curlight]].publicflags.negative) {
5312             glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
5313         }
5314     }
5315 
5316     // PR_BIT_NORMAL_MAP
5317     if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
5318     {
5319         float pos[3], bias[2];
5320 
5321         pos[0] = fglobalposy;
5322         pos[1] = fglobalposz * (-1.f/16.f);
5323         pos[2] = -fglobalposx;
5324 
5325         glActiveTexture(texunit + GL_TEXTURE0);
5326         glBindTexture(GL_TEXTURE_2D, material->normalmap);
5327 
5328         if (material->mdspritespace == GL_TRUE) {
5329             float mdspritespacepos[3];
5330             polymer_transformpoint(pos, mdspritespacepos, (float *)mdspritespace);
5331             glUniform3fv(prprograms[programbits].uniform_eyePosition, 1, mdspritespacepos);
5332         } else
5333             glUniform3fv(prprograms[programbits].uniform_eyePosition, 1, pos);
5334         glUniform1i(prprograms[programbits].uniform_normalMap, texunit);
5335         if (pr_overrideparallax) {
5336             bias[0] = pr_parallaxscale;
5337             bias[1] = pr_parallaxbias;
5338             glUniform2fv(prprograms[programbits].uniform_normalBias, 1, bias);
5339         } else
5340             glUniform2fv(prprograms[programbits].uniform_normalBias, 1, material->normalbias);
5341 
5342         if (material->tbn) {
5343             glEnableVertexAttribArray(prprograms[programbits].attrib_T);
5344             glEnableVertexAttribArray(prprograms[programbits].attrib_B);
5345             glEnableVertexAttribArray(prprograms[programbits].attrib_N);
5346 
5347             glVertexAttribPointer(prprograms[programbits].attrib_T,
5348                                       3, GL_FLOAT, GL_FALSE,
5349                                       sizeof(float) * 15,
5350                                       material->tbn);
5351             glVertexAttribPointer(prprograms[programbits].attrib_B,
5352                                       3, GL_FLOAT, GL_FALSE,
5353                                       sizeof(float) * 15,
5354                                       material->tbn + 3);
5355             glVertexAttribPointer(prprograms[programbits].attrib_N,
5356                                       3, GL_FLOAT, GL_FALSE,
5357                                       sizeof(float) * 15,
5358                                       material->tbn + 6);
5359         }
5360 
5361         texunit++;
5362     }
5363 
5364     // PR_BIT_ART_MAP
5365     if (programbits & prprogrambits[PR_BIT_ART_MAP].bit)
5366     {
5367         glActiveTexture(texunit + GL_TEXTURE0);
5368         glBindTexture(GL_TEXTURE_2D, material->artmap);
5369 
5370         glUniform1i(prprograms[programbits].uniform_artMap, texunit);
5371 
5372         texunit++;
5373 
5374         glActiveTexture(texunit + GL_TEXTURE0);
5375         glBindTexture(GL_TEXTURE_2D, material->basepalmap);
5376 
5377         glUniform1i(prprograms[programbits].uniform_basePalMap, texunit);
5378 
5379         texunit++;
5380 
5381         glActiveTexture(texunit + GL_TEXTURE0);
5382         glBindTexture(GL_TEXTURE_RECTANGLE_ARB, material->lookupmap);
5383 
5384         glUniform1i(prprograms[programbits].uniform_lookupMap, texunit);
5385 
5386         texunit++;
5387 
5388         glUniform1f(prprograms[programbits].uniform_shadeOffset, (GLfloat)material->shadeoffset);
5389         if (r_usenewshading == 4)
5390         {
5391             // the fog in Polymer is a sphere insted of a plane, the furthest visible point should be the same as Polymost
5392             glUniform1f(prprograms[programbits].uniform_visibility, globalvisibility / 262144.f * material->visibility);
5393         }
5394         else
5395         {
5396             static constexpr float material_visibility_divisor = 16.f;
5397 
5398             // NOTE: the denominator was 1.024, but we increase it towards a bit
5399             // farther far clipoff distance to account for the fact that the
5400             // distance to the fragment is the common Euclidean one, as opposed to
5401             // the "ortho" distance of Build.
5402             static constexpr float factor_new = 1.f / ((2048.f * (1.07f / 1.024f) * (150.f / 230.f) / 35.f) * material_visibility_divisor);
5403 
5404             static constexpr float factor_old = 1.f / ((2048.f * (1.07f / 1.024f) / 35.f) * material_visibility_divisor);
5405 
5406             glUniform1f(prprograms[programbits].uniform_visibility, globalvisibility * material->visibility * r_usenewshading > 1 ? factor_new : factor_old);
5407         }
5408     }
5409 
5410     // PR_BIT_DIFFUSE_MAP
5411     if (programbits & prprogrambits[PR_BIT_DIFFUSE_MAP].bit)
5412     {
5413         glActiveTexture(texunit + GL_TEXTURE0);
5414         glBindTexture(GL_TEXTURE_2D, material->diffusemap);
5415 
5416         glUniform1i(prprograms[programbits].uniform_diffuseMap, texunit);
5417         glUniform2fv(prprograms[programbits].uniform_diffuseScale, 1, material->diffusescale);
5418 
5419         texunit++;
5420     }
5421 
5422     // PR_BIT_HIGHPALOOKUP_MAP
5423     if (programbits & prprogrambits[PR_BIT_HIGHPALOOKUP_MAP].bit)
5424     {
5425         glActiveTexture(texunit + GL_TEXTURE0);
5426         glBindTexture(GL_TEXTURE_3D, material->highpalookupmap);
5427 
5428         glUniform1i(prprograms[programbits].uniform_highPalookupMap, texunit);
5429 
5430         texunit++;
5431     }
5432 
5433     // PR_BIT_DIFFUSE_DETAIL_MAP
5434     if (programbits & prprogrambits[PR_BIT_DIFFUSE_DETAIL_MAP].bit)
5435     {
5436         float scale[2];
5437 
5438         // scale by the diffuse map scale if we're not doing normal mapping
5439         if (!(programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit))
5440         {
5441             scale[0] = material->diffusescale[0] * material->detailscale[0];
5442             scale[1] = material->diffusescale[1] * material->detailscale[1];
5443         } else {
5444             scale[0] = material->detailscale[0];
5445             scale[1] = material->detailscale[1];
5446         }
5447 
5448         glActiveTexture(texunit + GL_TEXTURE0);
5449         glBindTexture(GL_TEXTURE_2D, material->detailmap);
5450 
5451         glUniform1i(prprograms[programbits].uniform_detailMap, texunit);
5452         glUniform2fv(prprograms[programbits].uniform_detailScale, 1, scale);
5453 
5454         texunit++;
5455     }
5456 
5457     // PR_BIT_DIFFUSE_MODULATION
5458     if (programbits & prprogrambits[PR_BIT_DIFFUSE_MODULATION].bit)
5459     {
5460             glColor4ub(material->diffusemodulation[0],
5461                         material->diffusemodulation[1],
5462                         material->diffusemodulation[2],
5463                         material->diffusemodulation[3]);
5464     }
5465 
5466     // PR_BIT_SPECULAR_MAP
5467     if (programbits & prprogrambits[PR_BIT_SPECULAR_MAP].bit)
5468     {
5469         glActiveTexture(texunit + GL_TEXTURE0);
5470         glBindTexture(GL_TEXTURE_2D, material->specmap);
5471 
5472         glUniform1i(prprograms[programbits].uniform_specMap, texunit);
5473 
5474         texunit++;
5475     }
5476 
5477     // PR_BIT_SPECULAR_MATERIAL
5478     if (programbits & prprogrambits[PR_BIT_SPECULAR_MATERIAL].bit)
5479     {
5480         float specmaterial[2];
5481 
5482         if (pr_overridespecular) {
5483             specmaterial[0] = pr_specularpower;
5484             specmaterial[1] = pr_specularfactor;
5485             glUniform2fv(prprograms[programbits].uniform_specMaterial, 1, specmaterial);
5486         } else
5487             glUniform2fv(prprograms[programbits].uniform_specMaterial, 1, material->specmaterial);
5488     }
5489 
5490     // PR_BIT_MIRROR_MAP
5491     if (programbits & prprogrambits[PR_BIT_MIRROR_MAP].bit)
5492     {
5493         glActiveTexture(texunit + GL_TEXTURE0);
5494         glBindTexture(GL_TEXTURE_RECTANGLE_ARB, material->mirrormap);
5495 
5496         glUniform1i(prprograms[programbits].uniform_mirrorMap, texunit);
5497 
5498         texunit++;
5499     }
5500 #ifdef PR_LINEAR_FOG
5501     if (programbits & prprogrambits[PR_BIT_FOG].bit)
5502     {
5503         glUniform1i(prprograms[programbits].uniform_linearFog, r_usenewshading >= 2);
5504     }
5505 #endif
5506     // PR_BIT_GLOW_MAP
5507     if (programbits & prprogrambits[PR_BIT_GLOW_MAP].bit)
5508     {
5509         glActiveTexture(texunit + GL_TEXTURE0);
5510         glBindTexture(GL_TEXTURE_2D, material->glowmap);
5511 
5512         glUniform1i(prprograms[programbits].uniform_glowMap, texunit);
5513 
5514         texunit++;
5515     }
5516 
5517     // PR_BIT_POINT_LIGHT
5518     if (programbits & prprogrambits[PR_BIT_POINT_LIGHT].bit)
5519     {
5520         float inpos[4], pos[4];
5521         float range[2];
5522         float color[4];
5523 
5524         inpos[0] = (float)prlights[lights[curlight]].y;
5525         inpos[1] = -(float)prlights[lights[curlight]].z / 16.0f;
5526         inpos[2] = -(float)prlights[lights[curlight]].x;
5527 
5528         polymer_transformpoint(inpos, pos, curmodelviewmatrix);
5529 
5530         // PR_BIT_SPOT_LIGHT
5531         if (programbits & prprogrambits[PR_BIT_SPOT_LIGHT].bit)
5532         {
5533             float sinang, cosang, sinhorizang, coshorizangs;
5534             float indir[3], dir[3];
5535 
5536             cosang = (float)(sintable[(-prlights[lights[curlight]].angle+1024)&2047]) / 16383.0f;
5537             sinang = (float)(sintable[(-prlights[lights[curlight]].angle+512)&2047]) / 16383.0f;
5538             coshorizangs = (float)(sintable[(getangle(128, prlights[lights[curlight]].horiz-100)+1024)&2047]) / 16383.0f;
5539             sinhorizang = (float)(sintable[(getangle(128, prlights[lights[curlight]].horiz-100)+512)&2047]) / 16383.0f;
5540 
5541             indir[0] = inpos[0] + sinhorizang * cosang;
5542             indir[1] = inpos[1] - coshorizangs;
5543             indir[2] = inpos[2] - sinhorizang * sinang;
5544 
5545             polymer_transformpoint(indir, dir, curmodelviewmatrix);
5546 
5547             dir[0] -= pos[0];
5548             dir[1] -= pos[1];
5549             dir[2] -= pos[2];
5550 
5551             indir[0] = (float)(sintable[(prlights[lights[curlight]].radius+512)&2047]) / 16383.0f;
5552             indir[1] = (float)(sintable[(prlights[lights[curlight]].faderadius+512)&2047]) / 16383.0f;
5553             indir[1] = 1.0 / (indir[1] - indir[0]);
5554 
5555             glUniform3fv(prprograms[programbits].uniform_spotDir, 1, dir);
5556             glUniform2fv(prprograms[programbits].uniform_spotRadius, 1, indir);
5557 
5558             // PR_BIT_PROJECTION_MAP
5559             if (programbits & prprogrambits[PR_BIT_PROJECTION_MAP].bit)
5560             {
5561                 GLfloat matrix[16];
5562 
5563                 glMatrixMode(GL_TEXTURE);
5564                 glLoadMatrixf(shadowBias);
5565                 glMultMatrixf(prlights[lights[curlight]].proj);
5566                 glMultMatrixf(prlights[lights[curlight]].transform);
5567                 if (material->mdspritespace == GL_TRUE)
5568                     glMultMatrixf(spritemodelview);
5569                 glGetFloatv(GL_TEXTURE_MATRIX, matrix);
5570                 glLoadIdentity();
5571                 glMatrixMode(GL_MODELVIEW);
5572 
5573                 glUniformMatrix4fv(prprograms[programbits].uniform_shadowProjMatrix, 1, GL_FALSE, matrix);
5574 
5575                 // PR_BIT_SHADOW_MAP
5576                 if (programbits & prprogrambits[PR_BIT_SHADOW_MAP].bit)
5577                 {
5578                     glActiveTexture(texunit + GL_TEXTURE0);
5579                     glBindTexture(prrts[prlights[lights[curlight]].rtindex].target, prrts[prlights[lights[curlight]].rtindex].z);
5580 
5581                     glUniform1i(prprograms[programbits].uniform_shadowMap, texunit);
5582 
5583                     texunit++;
5584                 }
5585 
5586                 // PR_BIT_LIGHT_MAP
5587                 if (programbits & prprogrambits[PR_BIT_LIGHT_MAP].bit)
5588                 {
5589                     glActiveTexture(texunit + GL_TEXTURE0);
5590                     glBindTexture(GL_TEXTURE_2D, prlights[lights[curlight]].lightmap);
5591 
5592                     glUniform1i(prprograms[programbits].uniform_lightMap, texunit);
5593 
5594                     texunit++;
5595                 }
5596             }
5597         }
5598 
5599         range[0] = prlights[lights[curlight]].range  / 1000.0f;
5600         range[1] = 1 / (range[0] * range[0]);
5601 
5602         color[0] = prlights[lights[curlight]].color[0]   / 255.0f;
5603         color[1] = prlights[lights[curlight]].color[1]   / 255.0f;
5604         color[2] = prlights[lights[curlight]].color[2]   / 255.0f;
5605 
5606         // If this isn't a lighting-only pass, just negate the components
5607         if (!curlight && prlights[lights[curlight]].publicflags.negative) {
5608             color[0] = -color[0];
5609             color[1] = -color[1];
5610             color[2] = -color[2];
5611         }
5612 
5613         glLightfv(GL_LIGHT0, GL_AMBIENT, pos);
5614         glLightfv(GL_LIGHT0, GL_DIFFUSE, color);
5615         if (material->mdspritespace == GL_TRUE) {
5616             float mdspritespacepos[3];
5617             polymer_transformpoint(inpos, mdspritespacepos, (float *)mdspritespace);
5618             glLightfv(GL_LIGHT0, GL_SPECULAR, mdspritespacepos);
5619         } else {
5620             glLightfv(GL_LIGHT0, GL_SPECULAR, inpos);
5621         }
5622         glLightfv(GL_LIGHT0, GL_LINEAR_ATTENUATION, &range[1]);
5623     }
5624 
5625     glActiveTexture(GL_TEXTURE0);
5626 
5627     return programbits;
5628 }
5629 
polymer_unbindmaterial(int32_t programbits)5630 static void         polymer_unbindmaterial(int32_t programbits)
5631 {
5632     // repair any dirty GL state here
5633 
5634     // PR_BIT_ANIM_INTERPOLATION
5635     if (programbits & prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit)
5636     {
5637         if (prprograms[programbits].attrib_nextFrameNormal != -1)
5638             glDisableVertexAttribArray(prprograms[programbits].attrib_nextFrameNormal);
5639         glDisableVertexAttribArray(prprograms[programbits].attrib_nextFrameData);
5640     }
5641 
5642     // PR_BIT_LIGHTING_PASS
5643     if (programbits & prprogrambits[PR_BIT_LIGHTING_PASS].bit)
5644     {
5645         glPopAttrib();
5646     }
5647 
5648     // PR_BIT_NORMAL_MAP
5649     if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
5650     {
5651         glDisableVertexAttribArray(prprograms[programbits].attrib_T);
5652         glDisableVertexAttribArray(prprograms[programbits].attrib_B);
5653         glDisableVertexAttribArray(prprograms[programbits].attrib_N);
5654     }
5655 
5656     polymost_useShaderProgram(0);
5657 }
5658 
polymer_compileprogram(int32_t programbits)5659 static void         polymer_compileprogram(int32_t programbits)
5660 {
5661     int32_t         i, enabledbits;
5662     GLuint          vert, frag, program;
5663     const GLchar*      source[PR_BIT_COUNT * 2];
5664     GLchar       infobuffer[PR_INFO_LOG_BUFFER_SIZE];
5665     GLint           linkstatus;
5666 
5667     // --------- VERTEX
5668     vert = glCreateShader(GL_VERTEX_SHADER);
5669 
5670     enabledbits = i = 0;
5671     while (i < PR_BIT_COUNT)
5672     {
5673         if (programbits & prprogrambits[i].bit)
5674             source[enabledbits++] = prprogrambits[i].vert_def;
5675         i++;
5676     }
5677     i = 0;
5678     while (i < PR_BIT_COUNT)
5679     {
5680         if (programbits & prprogrambits[i].bit)
5681             source[enabledbits++] = prprogrambits[i].vert_prog;
5682         i++;
5683     }
5684 
5685     glShaderSource(vert, enabledbits, source, NULL);
5686 
5687     glCompileShader(vert);
5688 
5689     // --------- FRAGMENT
5690     frag = glCreateShader(GL_FRAGMENT_SHADER);
5691 
5692     enabledbits = i = 0;
5693     while (i < PR_BIT_COUNT)
5694     {
5695         if (programbits & prprogrambits[i].bit)
5696             source[enabledbits++] = prprogrambits[i].frag_def;
5697         i++;
5698     }
5699     i = 0;
5700     while (i < PR_BIT_COUNT)
5701     {
5702         if (programbits & prprogrambits[i].bit)
5703             source[enabledbits++] = prprogrambits[i].frag_prog;
5704         i++;
5705     }
5706 
5707     glShaderSource(frag, enabledbits, (const GLchar**)source, NULL);
5708 
5709     glCompileShader(frag);
5710 
5711     // --------- PROGRAM
5712     program = glCreateProgram();
5713 
5714     glAttachShader(program, vert);
5715     glAttachShader(program, frag);
5716 
5717     glLinkProgram(program);
5718 
5719     glGetProgramiv(program, GL_LINK_STATUS, &linkstatus);
5720 
5721     glGetProgramInfoLog(program, PR_INFO_LOG_BUFFER_SIZE, NULL, infobuffer);
5722 
5723     prprograms[programbits].handle = program;
5724 
5725 #ifdef DEBUGGINGAIDS
5726     if (pr_verbosity >= 1)
5727 #else
5728     if (pr_verbosity >= 2)
5729 #endif
5730         OSD_Printf("PR : Compiling GPU program with bits (octal) %o...\n", (unsigned)programbits);
5731     if (!linkstatus) {
5732         OSD_Printf("PR : Failed to compile GPU program with bits (octal) %o!\n", (unsigned)programbits);
5733         if (pr_verbosity >= 1) OSD_Printf("PR : Compilation log:\n%s\n", infobuffer);
5734         glGetShaderSource(vert, PR_INFO_LOG_BUFFER_SIZE, NULL, infobuffer);
5735         if (pr_verbosity >= 1) OSD_Printf("PR : Vertex source dump:\n%s\n", infobuffer);
5736         glGetShaderSource(frag, PR_INFO_LOG_BUFFER_SIZE, NULL, infobuffer);
5737         if (pr_verbosity >= 1) OSD_Printf("PR : Fragment source dump:\n%s\n", infobuffer);
5738     }
5739 
5740     // --------- ATTRIBUTE/UNIFORM LOCATIONS
5741 
5742     // PR_BIT_ANIM_INTERPOLATION
5743     if (programbits & prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit)
5744     {
5745         prprograms[programbits].attrib_nextFrameData = glGetAttribLocation(program, "nextFrameData");
5746         prprograms[programbits].attrib_nextFrameNormal = glGetAttribLocation(program, "nextFrameNormal");
5747         prprograms[programbits].uniform_frameProgress = glGetUniformLocation(program, "frameProgress");
5748     }
5749 
5750     // PR_BIT_NORMAL_MAP
5751     if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
5752     {
5753         prprograms[programbits].attrib_T = glGetAttribLocation(program, "T");
5754         prprograms[programbits].attrib_B = glGetAttribLocation(program, "B");
5755         prprograms[programbits].attrib_N = glGetAttribLocation(program, "N");
5756         prprograms[programbits].uniform_eyePosition = glGetUniformLocation(program, "eyePosition");
5757         prprograms[programbits].uniform_normalMap = glGetUniformLocation(program, "normalMap");
5758         prprograms[programbits].uniform_normalBias = glGetUniformLocation(program, "normalBias");
5759     }
5760 
5761     // PR_BIT_ART_MAP
5762     if (programbits & prprogrambits[PR_BIT_ART_MAP].bit)
5763     {
5764         prprograms[programbits].uniform_artMap = glGetUniformLocation(program, "artMap");
5765         prprograms[programbits].uniform_basePalMap = glGetUniformLocation(program, "basePalMap");
5766         prprograms[programbits].uniform_lookupMap = glGetUniformLocation(program, "lookupMap");
5767         prprograms[programbits].uniform_shadeOffset = glGetUniformLocation(program, "shadeOffset");
5768         prprograms[programbits].uniform_visibility = glGetUniformLocation(program, "visibility");
5769     }
5770 
5771     // PR_BIT_DIFFUSE_MAP
5772     if (programbits & prprogrambits[PR_BIT_DIFFUSE_MAP].bit)
5773     {
5774         prprograms[programbits].uniform_diffuseMap = glGetUniformLocation(program, "diffuseMap");
5775         prprograms[programbits].uniform_diffuseScale = glGetUniformLocation(program, "diffuseScale");
5776     }
5777 
5778     // PR_BIT_HIGHPALOOKUP_MAP
5779     if (programbits & prprogrambits[PR_BIT_HIGHPALOOKUP_MAP].bit)
5780     {
5781         prprograms[programbits].uniform_highPalookupMap = glGetUniformLocation(program, "highPalookupMap");
5782     }
5783 
5784     // PR_BIT_DIFFUSE_DETAIL_MAP
5785     if (programbits & prprogrambits[PR_BIT_DIFFUSE_DETAIL_MAP].bit)
5786     {
5787         prprograms[programbits].uniform_detailMap = glGetUniformLocation(program, "detailMap");
5788         prprograms[programbits].uniform_detailScale = glGetUniformLocation(program, "detailScale");
5789     }
5790 
5791     // PR_BIT_SPECULAR_MAP
5792     if (programbits & prprogrambits[PR_BIT_SPECULAR_MAP].bit)
5793     {
5794         prprograms[programbits].uniform_specMap = glGetUniformLocation(program, "specMap");
5795     }
5796 
5797     // PR_BIT_SPECULAR_MATERIAL
5798     if (programbits & prprogrambits[PR_BIT_SPECULAR_MATERIAL].bit)
5799     {
5800         prprograms[programbits].uniform_specMaterial = glGetUniformLocation(program, "specMaterial");
5801     }
5802 
5803     // PR_BIT_MIRROR_MAP
5804     if (programbits & prprogrambits[PR_BIT_MIRROR_MAP].bit)
5805     {
5806         prprograms[programbits].uniform_mirrorMap = glGetUniformLocation(program, "mirrorMap");
5807     }
5808 #ifdef PR_LINEAR_FOG
5809     if (programbits & prprogrambits[PR_BIT_FOG].bit)
5810     {
5811         prprograms[programbits].uniform_linearFog = glGetUniformLocation(program, "linearFog");
5812     }
5813 #endif
5814     // PR_BIT_GLOW_MAP
5815     if (programbits & prprogrambits[PR_BIT_GLOW_MAP].bit)
5816     {
5817         prprograms[programbits].uniform_glowMap = glGetUniformLocation(program, "glowMap");
5818     }
5819 
5820     // PR_BIT_PROJECTION_MAP
5821     if (programbits & prprogrambits[PR_BIT_PROJECTION_MAP].bit)
5822     {
5823         prprograms[programbits].uniform_shadowProjMatrix = glGetUniformLocation(program, "shadowProjMatrix");
5824     }
5825 
5826     // PR_BIT_SHADOW_MAP
5827     if (programbits & prprogrambits[PR_BIT_SHADOW_MAP].bit)
5828     {
5829         prprograms[programbits].uniform_shadowMap = glGetUniformLocation(program, "shadowMap");
5830     }
5831 
5832     // PR_BIT_LIGHT_MAP
5833     if (programbits & prprogrambits[PR_BIT_LIGHT_MAP].bit)
5834     {
5835         prprograms[programbits].uniform_lightMap = glGetUniformLocation(program, "lightMap");
5836     }
5837 
5838     // PR_BIT_SPOT_LIGHT
5839     if (programbits & prprogrambits[PR_BIT_SPOT_LIGHT].bit)
5840     {
5841         prprograms[programbits].uniform_spotDir = glGetUniformLocation(program, "spotDir");
5842         prprograms[programbits].uniform_spotRadius = glGetUniformLocation(program, "spotRadius");
5843     }
5844 }
5845 
5846 // LIGHTS
polymer_removelight(int16_t lighti)5847 static void         polymer_removelight(int16_t lighti)
5848 {
5849     _prplanelist*   oldhead;
5850 
5851     while (prlights[lighti].planelist)
5852     {
5853         polymer_deleteplanelight(prlights[lighti].planelist->plane, lighti);
5854         oldhead = prlights[lighti].planelist;
5855         prlights[lighti].planelist = prlights[lighti].planelist->n;
5856         oldhead->n = plpool;
5857         plpool = oldhead;
5858         plpool->plane = NULL;
5859     }
5860     prlights[lighti].planecount = 0;
5861     prlights[lighti].planelist = NULL;
5862 }
5863 
polymer_updatelights(void)5864 static void         polymer_updatelights(void)
5865 {
5866     int32_t         i = 0;
5867 
5868     do
5869     {
5870         _prlight* light = &prlights[i];
5871 
5872         if (light->flags.active && light->flags.invalidate) {
5873             // highly suboptimal
5874             polymer_removelight(i);
5875 
5876             if (light->radius)
5877                 polymer_processspotlight(light);
5878 
5879             polymer_culllight(i);
5880 
5881             light->flags.invalidate = 0;
5882         }
5883 
5884         if (light->flags.active) {
5885             // get the texture handle for the lightmap
5886             if (light->radius && light->tilenum > 0)
5887             {
5888                 int16_t     picnum = light->tilenum;
5889                 pthtyp*     pth;
5890 
5891                 tileUpdatePicnum(&picnum, 0);
5892 
5893                 if (!waloff[picnum])
5894                     tileLoad(picnum);
5895 
5896                 pth = NULL;
5897                 pth = texcache_fetch(picnum, 0, 0, DAMETH_NOMASK);
5898 
5899                 if (pth)
5900                     light->lightmap = pth->glpic;
5901             }
5902 
5903             light->rtindex = -1;
5904         }
5905     }
5906     while (++i < PR_MAXLIGHTS);
5907 }
5908 
polymer_resetplanelights(_prplane * plane)5909 static inline void  polymer_resetplanelights(_prplane* plane)
5910 {
5911     Bmemset(&plane->lights[0], -1, sizeof(plane->lights[0]) * plane->lightcount);
5912     plane->lightcount = 0;
5913 }
5914 
polymer_addplanelight(_prplane * plane,int16_t lighti)5915 static void         polymer_addplanelight(_prplane* plane, int16_t lighti)
5916 {
5917     _prplanelist*   oldhead;
5918     int32_t         i = 0;
5919 
5920     if (plane->lightcount)
5921     {
5922         if (plane->lightcount == PR_MAXLIGHTS - 1)
5923             return;
5924 
5925         do
5926         {
5927             if (plane->lights[i++] == lighti)
5928                 goto out;
5929         }
5930         while (i < plane->lightcount);
5931 
5932         i = 0;
5933         while (i < plane->lightcount && prlights[plane->lights[i]].priority < prlights[lighti].priority)
5934             i++;
5935         Bmemmove(&plane->lights[i+1], &plane->lights[i], sizeof(int16_t) * (plane->lightcount - i));
5936     }
5937 
5938     plane->lights[i] = lighti;
5939     plane->lightcount++;
5940 
5941 out:
5942     oldhead = prlights[lighti].planelist;
5943     while (oldhead != NULL)
5944     {
5945         if (oldhead->plane == plane) return;
5946         oldhead = oldhead->n;
5947     }
5948 
5949     oldhead = prlights[lighti].planelist;
5950     if (plpool == NULL)
5951     {
5952         prlights[lighti].planelist = (_prplanelist *) Xmalloc(sizeof(_prplanelist));
5953         prlights[lighti].planelist->n = oldhead;
5954     }
5955     else
5956     {
5957         prlights[lighti].planelist = plpool;
5958         plpool = plpool->n;
5959         prlights[lighti].planelist->n = oldhead;
5960     }
5961 
5962     prlights[lighti].planelist->plane = plane;
5963     prlights[lighti].planecount++;
5964 }
5965 
polymer_deleteplanelight(_prplane * plane,int16_t lighti)5966 static inline void  polymer_deleteplanelight(_prplane* plane, int16_t lighti)
5967 {
5968     int32_t         i = plane->lightcount-1;
5969 
5970     while (i >= 0)
5971     {
5972         if (plane->lights[i] == lighti)
5973         {
5974             Bmemmove(&plane->lights[i], &plane->lights[i+1], sizeof(int16_t) * (plane->lightcount - i));
5975             plane->lightcount--;
5976             return;
5977         }
5978         i--;
5979     }
5980 }
5981 
polymer_planeinlight(_prplane * plane,_prlight * light)5982 static int32_t      polymer_planeinlight(_prplane* plane, _prlight* light)
5983 {
5984     float           lightpos[3];
5985     int32_t         i, j, k, l;
5986 
5987     if (!plane->vertcount)
5988         return 0;
5989 
5990     if (light->radius)
5991         return polymer_planeinfrustum(plane, light->frustum);
5992 
5993     lightpos[0] = (float)light->y;
5994     lightpos[1] = -(float)light->z / 16.0f;
5995     lightpos[2] = -(float)light->x;
5996 
5997     i = 0;
5998 
5999     do
6000     {
6001         j = k = l = 0;
6002 
6003         do
6004         {
6005             if ((&plane->buffer[j].x)[i] > (lightpos[i] + light->range)) k++;
6006             if ((&plane->buffer[j].x)[i] < (lightpos[i] - light->range)) l++;
6007         }
6008         while (++j < plane->vertcount);
6009 
6010         if ((k == plane->vertcount) || (l == plane->vertcount))
6011             return 0;
6012     }
6013     while (++i < 3);
6014 
6015     return 1;
6016 }
6017 
polymer_invalidateplanelights(_prplane * plane)6018 static void         polymer_invalidateplanelights(_prplane* plane)
6019 {
6020     int32_t         i = plane->lightcount;
6021 
6022     while (i--)
6023     {
6024         if (((unsigned)plane->lights[i] < PR_MAXLIGHTS) && (prlights[plane->lights[i]].flags.active))
6025             prlights[plane->lights[i]].flags.invalidate = 1;
6026     }
6027 }
6028 
polymer_invalidatesectorlights(int16_t sectnum)6029 static void         polymer_invalidatesectorlights(int16_t sectnum)
6030 {
6031     int32_t         i;
6032     _prsector       *s = prsectors[sectnum];
6033     sectortype      *sec = &sector[sectnum];
6034 
6035     if (!s)
6036         return;
6037 
6038     polymer_invalidateplanelights(&s->floor);
6039     polymer_invalidateplanelights(&s->ceil);
6040 
6041     i = sec->wallnum;
6042 
6043     while (i--)
6044     {
6045         _prwall         *w;
6046         if (!(w = prwalls[sec->wallptr + i])) continue;
6047 
6048         polymer_invalidateplanelights(&w->wall);
6049         polymer_invalidateplanelights(&w->over);
6050         polymer_invalidateplanelights(&w->mask);
6051     }
6052 }
6053 
polymer_processspotlight(_prlight * light)6054 static void         polymer_processspotlight(_prlight* light)
6055 {
6056     float           radius, ang, horizang, lightpos[3];
6057 
6058     // hack to avoid lights beams perpendicular to walls
6059     if ((light->horiz <= 100) && (light->horiz > 90))
6060         light->horiz = 90;
6061     if ((light->horiz > 100) && (light->horiz < 110))
6062         light->horiz = 110;
6063 
6064     lightpos[0] = (float)light->y;
6065     lightpos[1] = -(float)light->z / 16.0f;
6066     lightpos[2] = -(float)light->x;
6067 
6068     // calculate the spot light transformations and matrices
6069     radius = (float)(light->radius) * (360.f/2048.f);
6070     ang = (float)(light->angle) * (360.f/2048.f);
6071     horizang = (float)(-getangle(128, light->horiz-100)) * (360.f/2048.f);
6072 
6073     glMatrixMode(GL_PROJECTION);
6074     glPushMatrix();
6075     glLoadIdentity();
6076     bgluPerspective(radius * 2, 1, 0.1f, light->range * (1.f/1000.f));
6077     glGetFloatv(GL_PROJECTION_MATRIX, light->proj);
6078     glPopMatrix();
6079 
6080     glMatrixMode(GL_MODELVIEW);
6081     glPushMatrix();
6082     glLoadIdentity();
6083     glRotatef(horizang, 1.0f, 0.0f, 0.0f);
6084     glRotatef(ang, 0.0f, 1.0f, 0.0f);
6085     glScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
6086     glTranslatef(-lightpos[0], -lightpos[1], -lightpos[2]);
6087     glGetFloatv(GL_MODELVIEW_MATRIX, light->transform);
6088     glPopMatrix();
6089 
6090     polymer_extractfrustum(light->transform, light->proj, light->frustum);
6091 
6092     light->rtindex = -1;
6093     light->lightmap = 0;
6094 }
6095 
polymer_culllight(int16_t lighti)6096 static inline void  polymer_culllight(int16_t lighti)
6097 {
6098     _prlight*       light = &prlights[lighti];
6099     int32_t         front = 0;
6100     int32_t         back = 1;
6101     int32_t         i;
6102     int32_t         j;
6103     int32_t         zdiff;
6104     int32_t         checkror;
6105     int16_t         bunchnum;
6106     int16_t         ns;
6107     _prsector       *s;
6108     _prwall         *w;
6109     sectortype      *sec;
6110 
6111     Bmemset(drawingstate, 0, sizeof(int16_t) * numsectors);
6112     drawingstate[light->sector] = 1;
6113 
6114     sectorqueue[0] = light->sector;
6115 
6116     do
6117     {
6118         s = prsectors[sectorqueue[front]];
6119         sec = &sector[sectorqueue[front]];
6120 
6121         polymer_pokesector(sectorqueue[front]);
6122 
6123         checkror = FALSE;
6124 
6125         zdiff = light->z - s->floorz;
6126         if (zdiff < 0)
6127             zdiff = -zdiff;
6128         zdiff >>= 4;
6129 
6130         if (!light->radius && !(sec->floorstat & 1)) {
6131             if (zdiff < light->range) {
6132                 polymer_addplanelight(&s->floor, lighti);
6133                 checkror = TRUE;
6134             }
6135         } else if (polymer_planeinlight(&s->floor, light)) {
6136             polymer_addplanelight(&s->floor, lighti);
6137             checkror = TRUE;
6138         }
6139 
6140 #ifdef YAX_ENABLE
6141         // queue ROR neighbors
6142         if (checkror &&
6143             (bunchnum = yax_getbunch(sectorqueue[front], YAX_FLOOR)) >= 0) {
6144 
6145             for (SECTORS_OF_BUNCH(bunchnum, YAX_CEILING, ns)) {
6146 
6147                 if (ns >= 0 && !drawingstate[ns] &&
6148                     polymer_planeinlight(&prsectors[ns]->ceil, light)) {
6149 
6150                     sectorqueue[back++] = ns;
6151                     drawingstate[ns] = 1;
6152                 }
6153             }
6154         }
6155 #endif
6156         checkror = FALSE;
6157 
6158         zdiff = light->z - s->ceilingz;
6159         if (zdiff < 0)
6160             zdiff = -zdiff;
6161         zdiff >>= 4;
6162 
6163         if (!light->radius && !(sec->ceilingstat & 1)) {
6164             if (zdiff < light->range) {
6165                 polymer_addplanelight(&s->ceil, lighti);
6166                 checkror = TRUE;
6167             }
6168         } else if (polymer_planeinlight(&s->ceil, light)) {
6169             polymer_addplanelight(&s->ceil, lighti);
6170             checkror = TRUE;
6171         }
6172 
6173 #ifdef YAX_ENABLE
6174         // queue ROR neighbors
6175         if (checkror &&
6176             (bunchnum = yax_getbunch(sectorqueue[front], YAX_CEILING)) >= 0) {
6177 
6178             for (SECTORS_OF_BUNCH(bunchnum, YAX_FLOOR, ns)) {
6179 
6180                 if (ns >= 0 && !drawingstate[ns] &&
6181                     polymer_planeinlight(&prsectors[ns]->floor, light)) {
6182 
6183                     sectorqueue[back++] = ns;
6184                     drawingstate[ns] = 1;
6185                 }
6186             }
6187         }
6188 #endif
6189         i = 0;
6190         while (i < sec->wallnum)
6191         {
6192             w = prwalls[sec->wallptr + i];
6193 
6194             j = 0;
6195 
6196             if (polymer_planeinlight(&w->wall, light)) {
6197                 polymer_addplanelight(&w->wall, lighti);
6198                 j++;
6199             }
6200 
6201             if (polymer_planeinlight(&w->over, light)) {
6202                 polymer_addplanelight(&w->over, lighti);
6203                 j++;
6204             }
6205 
6206             // assume the light hits the middle section if it hits the top and bottom
6207             if (wallvisible(light->x, light->y, sec->wallptr + i) &&
6208                 (j == 2 || polymer_planeinlight(&w->mask, light))) {
6209                 if ((w->mask.vertcount == 4) &&
6210                     (w->mask.buffer[0].y >= w->mask.buffer[3].y) &&
6211                     (w->mask.buffer[1].y >= w->mask.buffer[2].y))
6212                 {
6213                     i++;
6214                     continue;
6215                 }
6216 
6217                 polymer_addplanelight(&w->mask, lighti);
6218 
6219                 if ((wall[sec->wallptr + i].nextsector >= 0) &&
6220                     (!drawingstate[wall[sec->wallptr + i].nextsector])) {
6221                     drawingstate[wall[sec->wallptr + i].nextsector] = 1;
6222                     sectorqueue[back] = wall[sec->wallptr + i].nextsector;
6223                     back++;
6224                 }
6225             }
6226 
6227             i++;
6228         }
6229         front++;
6230     }
6231     while (front != back);
6232 
6233     i = MAXSPRITES-1;
6234 
6235     do
6236     {
6237         _prsprite *s = prsprites[i];
6238 
6239         if ((sprite[i].cstat & 48) == 0 || s == NULL || sprite[i].statnum == MAXSTATUS || sprite[i].sectnum == MAXSECTORS)
6240             continue;
6241 
6242         if (polymer_planeinlight(&s->plane, light))
6243             polymer_addplanelight(&s->plane, lighti);
6244     }
6245     while (i--);
6246 }
6247 
polymer_prepareshadows(void)6248 static void         polymer_prepareshadows(void)
6249 {
6250     fix16_t         oviewangle, oglobalang;
6251     int32_t         i, j, k;
6252     int32_t         gx, gy, gz;
6253     int32_t         oldoverridematerial;
6254 
6255     // for wallvisible()
6256     gx = globalposx;
6257     gy = globalposy;
6258     gz = globalposz;
6259     // build globals used by drawmasks
6260     oviewangle = viewangle;
6261     oglobalang = qglobalang;
6262 
6263     i = j = k = 0;
6264 
6265     while ((k < lightcount) && (j < pr_shadowcount))
6266     {
6267         while (!prlights[i].flags.active)
6268             i++;
6269 
6270         if (prlights[i].radius && prlights[i].publicflags.emitshadow &&
6271             prlights[i].flags.isinview)
6272         {
6273             prlights[i].flags.isinview = 0;
6274             prlights[i].rtindex = j + 1;
6275             if (pr_verbosity >= 3) OSD_Printf("PR : Drawing shadow %i...\n", i);
6276 
6277             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[prlights[i].rtindex].fbo);
6278             glPushAttrib(GL_VIEWPORT_BIT);
6279             glViewport(0, 0, prrts[prlights[i].rtindex].xdim, prrts[prlights[i].rtindex].ydim);
6280 
6281             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
6282 
6283             glMatrixMode(GL_PROJECTION);
6284             glPushMatrix();
6285             glLoadMatrixf(prlights[i].proj);
6286             glMatrixMode(GL_MODELVIEW);
6287             glLoadMatrixf(prlights[i].transform);
6288 
6289             glEnable(GL_POLYGON_OFFSET_FILL);
6290             glPolygonOffset(5, SHADOW_DEPTH_OFFSET);
6291 
6292             set_globalpos(prlights[i].x, prlights[i].y, prlights[i].z);
6293 
6294             // build globals used by rotatesprite
6295             viewangle = fix16_from_int(prlights[i].angle);
6296             set_globalang(fix16_from_int(prlights[i].angle));
6297 
6298             oldoverridematerial = overridematerial;
6299             // smooth model shadows
6300             overridematerial = prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit;
6301             // used by alpha-testing for sprite silhouette
6302             overridematerial |= prprogrambits[PR_BIT_DIFFUSE_MAP].bit;
6303             overridematerial |= prprogrambits[PR_BIT_DIFFUSE_MAP2].bit;
6304 
6305             // to force sprite drawing
6306             mirrors[depth++].plane = NULL;
6307             polymer_displayrooms(prlights[i].sector);
6308             depth--;
6309 
6310             overridematerial = oldoverridematerial;
6311 
6312             glDisable(GL_POLYGON_OFFSET_FILL);
6313 
6314             glMatrixMode(GL_PROJECTION);
6315             glPopMatrix();
6316 
6317             glPopAttrib();
6318             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
6319 
6320             j++;
6321         }
6322         i++;
6323         k++;
6324     }
6325 
6326     set_globalpos(gx, gy, gz);
6327 
6328     viewangle = oviewangle;
6329     set_globalang(oglobalang);
6330 }
6331 
6332 // RENDER TARGETS
polymer_initrendertargets(int32_t count)6333 static void         polymer_initrendertargets(int32_t count)
6334 {
6335     int32_t         i;
6336 
6337     static int32_t ocount;
6338 
6339     if (count == 0)  // uninit
6340     {
6341         if (prrts)
6342         {
6343             for (i=0; i<ocount; i++)
6344             {
6345                 if (prrts[i].color)
6346                 {
6347                     glDeleteTextures(1, &prrts[i].color);
6348                     prrts[i].color = 0;
6349                 }
6350                 glDeleteTextures(1, &prrts[i].z);
6351                 prrts[i].z = 0;
6352 
6353                 glDeleteFramebuffersEXT(1, &prrts[i].fbo);
6354                 prrts[i].fbo = 0;
6355             }
6356             DO_FREE_AND_NULL(prrts);
6357         }
6358 
6359         ocount = 0;
6360         return;
6361     }
6362 
6363     ocount = count;
6364     //////////
6365 
6366     prrts = (_prrt *)Xcalloc(count, sizeof(_prrt));
6367 
6368     i = 0;
6369     while (i < count)
6370     {
6371         if (!i) {
6372             prrts[i].target = GL_TEXTURE_RECTANGLE_ARB;
6373             prrts[i].xdim = xdim;
6374             prrts[i].ydim = ydim;
6375 
6376             glGenTextures(1, &prrts[i].color);
6377             glBindTexture(prrts[i].target, prrts[i].color);
6378 
6379             glTexImage2D(prrts[i].target, 0, GL_RGB, prrts[i].xdim, prrts[i].ydim, 0, GL_RGB, GL_SHORT, NULL);
6380             glTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6381             glTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6382             glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
6383             glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
6384         } else {
6385             prrts[i].target = GL_TEXTURE_2D;
6386             prrts[i].xdim = 128 << pr_shadowdetail;
6387             prrts[i].ydim = 128 << pr_shadowdetail;
6388             prrts[i].color = 0;
6389 
6390             if (pr_ati_fboworkaround) {
6391                 glGenTextures(1, &prrts[i].color);
6392                 glBindTexture(prrts[i].target, prrts[i].color);
6393 
6394                 glTexImage2D(prrts[i].target, 0, GL_RGB, prrts[i].xdim, prrts[i].ydim, 0, GL_RGB, GL_SHORT, NULL);
6395                 glTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6396                 glTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6397                 glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
6398                 glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
6399             }
6400         }
6401 
6402         glGenTextures(1, &prrts[i].z);
6403         glBindTexture(prrts[i].target, prrts[i].z);
6404 
6405         glTexImage2D(prrts[i].target, 0, GL_DEPTH_COMPONENT, prrts[i].xdim, prrts[i].ydim, 0, GL_DEPTH_COMPONENT, GL_SHORT, NULL);
6406         glTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, pr_shadowfiltering ? GL_LINEAR : GL_NEAREST);
6407         glTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, pr_shadowfiltering ? GL_LINEAR : GL_NEAREST);
6408         glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
6409         glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
6410         glTexParameteri(prrts[i].target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
6411         glTexParameteri(prrts[i].target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
6412         glTexParameteri(prrts[i].target, GL_DEPTH_TEXTURE_MODE, GL_ALPHA);
6413 
6414         glGenFramebuffersEXT(1, &prrts[i].fbo);
6415         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[i].fbo);
6416 
6417         if (prrts[i].color)
6418             glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
6419                                        prrts[i].target, prrts[i].color, 0);
6420         else {
6421             glDrawBuffer(GL_NONE);
6422             glReadBuffer(GL_NONE);
6423         }
6424         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, prrts[i].target, prrts[i].z, 0);
6425 
6426         if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
6427         {
6428             OSD_Printf("PR : FBO #%d initialization failed.\n", i);
6429         }
6430 
6431         glBindTexture(prrts[i].target, 0);
6432         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
6433 
6434         i++;
6435     }
6436 }
6437 
6438 // DEBUG OUTPUT
polymer_debugoutputcallback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,GLvoid * userParam)6439 void PR_CALLBACK    polymer_debugoutputcallback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam)
6440 {
6441     UNREFERENCED_PARAMETER(source);
6442     UNREFERENCED_PARAMETER(type);
6443     UNREFERENCED_PARAMETER(id);
6444     UNREFERENCED_PARAMETER(severity);
6445     UNREFERENCED_PARAMETER(length);
6446     UNREFERENCED_PARAMETER(userParam);
6447 
6448     if (type == GL_DEBUG_TYPE_ERROR_ARB)
6449     {
6450         OSD_Printf("PR : Received OpenGL debug message: %s\n", message);
6451     }
6452 }
6453 
6454 #endif
6455