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)§or[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)§or[tspr->sectnum];
1535 calc_and_apply_fog(fogshade(tspr->shade, tspr->pal), sec->visibility, get_floor_fogpal((usectorptr_t)§or[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)§or[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 = §or[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)§or[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)§or[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)§or[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)§or[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 *) §num);
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 *) §num);
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 = §or[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 = §or[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)§or[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 = §or[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 = §or[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 = §or[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