1 /**************************************************************************************************
2 "POLYMOST" code written by Ken Silverman
3 Ken Silverman's official web site: http://www.advsys.net/ken
4
5 Motivation:
6 When 3D Realms released the Duke Nukem 3D source code, I thought somebody would do a OpenGL or
7 Direct3D port. Well, after a few months passed, I saw no sign of somebody working on a true
8 hardware-accelerated port of Build, just people saying it wasn't possible. Eventually, I realized
9 the only way this was going to happen was for me to do it myself. First, I needed to port Build to
10 Windows. I could have done it myself, but instead I thought I'd ask my Australian buddy, Jonathon
11 Fowler, if he would upgrade his Windows port to my favorite compiler (MSVC) - which he did. Once
12 that was done, I was ready to start the "POLYMOST" project.
13
14 About:
15 This source file is basically a complete rewrite of the entire rendering part of the Build engine.
16 There are small pieces in ENGINE.C to activate this code, and other minor hacks in other source
17 files, but most of it is in here. If you're looking for polymost-related code in the other source
18 files, you should find most of them by searching for either "polymost" or "rendmode". Speaking of
19 rendmode, there are now 4 rendering modes in Build:
20
21 rendmode 0: The original code I wrote from 1993-1997
22 rendmode 1: Solid-color rendering: my debug code before I did texture mapping
23 rendmode 2: Software rendering before I started the OpenGL code (Note: this is just a quick
24 hack to make testing easier - it's not optimized to my usual standards!)
25 rendmode 3: The OpenGL code
26
27 The original Build engine did hidden surface removal by using a vertical span buffer on the tops
28 and bottoms of walls. This worked nice back in the day, but it it's not suitable for a polygon
29 engine. So I decided to write a brand new hidden surface removal algorithm - using the same idea
30 as the original Build - but one that worked with vectors instead of already rasterized data.
31
32 Brief history:
33 06/20/2000: I release Build Source code
34 04/01/2003: 3D Realms releases Duke Nukem 3D source code
35 10/04/2003: Jonathon Fowler gets his Windows port working in Visual C
36 10/04/2003: I start writing POLYMOST.BAS, a new hidden surface removal algorithm for Build that
37 works on a polygon level instead of spans.
38 10/16/2003: Ported POLYMOST.BAS to C inside JonoF KenBuild's ENGINE.C; later this code was split
39 out of ENGINE.C and put in this file, POLYMOST.C.
40 12/10/2003: Started OpenGL code for POLYMOST (rendmode 3)
41 12/23/2003: 1st public release
42 01/01/2004: 2nd public release: fixed stray lines, status bar, mirrors, sky, and lots of other bugs.
43
44 ----------------------------------------------------------------------------------------------------
45
46 Todo list (in approximate chronological order):
47
48 High priority:
49 * BOTH: Do accurate software sorting/chopping for sprites: drawing in wrong order is bad :/
50 * BOTH: Fix hall of mirrors near "zenith". Call polymost_drawrooms twice?
51 * OPENGL: drawmapview()
52
53 Low priority:
54 * SOFT6D: Do back-face culling of sprites during up/down/tilt transformation (top of drawpoly)
55 * SOFT6D: Fix depth shading: use saturation&LUT
56 * SOFT6D: Optimize using hyperbolic mapping (similar to KUBE algo)
57 * SOFT6D: Slab6-style voxel sprites. How to accelerate? :/
58 * OPENGL: KENBUILD: Write flipping code for floor mirrors
59 * BOTH: KENBUILD: Parallaxing sky modes 1&2
60 * BOTH: Masked/1-way walls don't clip correctly to sectors of intersecting ceiling/floor slopes
61 * BOTH: Editart x-center is not working correctly with Duke's camera/turret sprites
62 * BOTH: Get rid of horizontal line above Duke full-screen status bar
63 * BOTH: Combine ceilings/floors into a single triangle strip (should lower poly count by 2x)
64 * BOTH: Optimize/clean up texture-map setup equations
65
66 **************************************************************************************************/
67
68 #include "build.h"
69
70 #if USE_POLYMOST
71
72 #include "glbuild.h"
73 #include "pragmas.h"
74 #include "baselayer.h"
75 #include "osd.h"
76 #include "engine_priv.h"
77 #include "polymost_priv.h"
78 #if USE_OPENGL
79 # include "hightile_priv.h"
80 # include "polymosttex_priv.h"
81 # include "polymosttexcache.h"
82 # include "mdsprite_priv.h"
83 #endif
84 extern char textfont[2048], smalltextfont[2048];
85
86 int rendmode = 0;
87 int usemodels=1, usehightile=1, usegoodalpha=0;
88
89 #include <math.h> //<-important!
90 typedef struct { float x, cy[2], fy[2]; int n, p, tag, ctag, ftag; } vsptyp;
91 #define VSPMAX 4096 //<- careful!
92 static vsptyp vsp[VSPMAX];
93 static int vcnt, gtag;
94
95 double dxb1[MAXWALLSB], dxb2[MAXWALLSB];
96
97 #define SCISDIST 1.0 //1.0: Close plane clipping distance
98 #define USEZBUFFER 1 //1:use zbuffer (slow, nice sprite rendering), 0:no zbuffer (fast, bad sprite rendering)
99 #define LINTERPSIZ 4 //log2 of interpolation size. 4:pretty fast&acceptable quality, 0:best quality/slow!
100 #define DEPTHDEBUG 0 //1:render distance instead of texture, for debugging only!, 0:default
101 #define FOGSCALE 0.0000384
102
103 double gxyaspect, grhalfxdown10x;
104 static double gyxscale, gviewxrange, ghalfx, grhalfxdown10, ghoriz;
105 double gcosang, gsinang, gcosang2, gsinang2;
106 double gchang, gshang, gctang, gstang;
107 static double gvisibility;
108 float gtang = 0.0;
109 double guo, gux, guy; //Screen-based texture mapping parameters
110 double gvo, gvx, gvy;
111 double gdo, gdx, gdy;
112
113 #if (USEZBUFFER != 0)
114 intptr_t zbufmem = 0;
115 int zbufysiz = 0, zbufbpl = 0, *zbufoff = 0;
116 #endif
117
118 #if USE_OPENGL
119 int gfogpalnum = 0;
120 float gfogdensity = 0.f;
121
122 int glredbluemode = 0;
123 static int lastglredbluemode = 0, redblueclearcnt = 0;
124
125 struct glfiltermodes glfiltermodes[numglfiltermodes] = {
126 {"GL_NEAREST",GL_NEAREST,GL_NEAREST},
127 {"GL_LINEAR",GL_LINEAR,GL_LINEAR},
128 {"GL_NEAREST_MIPMAP_NEAREST",GL_NEAREST_MIPMAP_NEAREST,GL_NEAREST},
129 {"GL_LINEAR_MIPMAP_NEAREST",GL_LINEAR_MIPMAP_NEAREST,GL_LINEAR},
130 {"GL_NEAREST_MIPMAP_LINEAR",GL_NEAREST_MIPMAP_LINEAR,GL_NEAREST},
131 {"GL_LINEAR_MIPMAP_LINEAR",GL_LINEAR_MIPMAP_LINEAR,GL_LINEAR}
132 };
133
134 int glanisotropy = 0; // 0 = maximum supported by card
135 int glusetexcompr = 1;
136 int gltexcomprquality = 0; // 0 = fast, 1 = slow and pretty, 2 = very slow and pretty
137 int gltexfiltermode = 5; // GL_LINEAR_MIPMAP_LINEAR
138 int glusetexcache = 1;
139 int glmultisample = 0, glnvmultisamplehint = 0;
140 int gltexmaxsize = 0; // 0 means autodetection on first run
141 int gltexmiplevel = 0; // discards this many mipmap levels
142 static int lastglpolygonmode = 0;
143 int glpolygonmode = 0; // 0:GL_FILL,1:GL_LINE,2:GL_POINT,3:clear+GL_FILL
144
145 static GLuint texttexture = 0;
146 static GLuint nulltexture = 0;
147
148 #define SHADERDEV 1
149 static struct {
150 GLuint vao; // Vertex array object.
151 GLuint program; // GLSL program object.
152 GLuint elementbuffer;
153 GLint attrib_vertex; // Vertex (vec3)
154 GLint attrib_texcoord; // Texture coordinate (vec2)
155 GLint uniform_modelview; // Modelview matrix (mat4)
156 GLint uniform_projection; // Projection matrix (mat4)
157 GLint uniform_texture; // Base texture (sampler2D)
158 GLint uniform_glowtexture; // Glow texture (sampler2D)
159 GLint uniform_alphacut; // Alpha test cutoff (float)
160 GLint uniform_colour; // Colour (vec4)
161 GLint uniform_fogcolour; // Fog colour (vec4)
162 GLint uniform_fogdensity; // Fog density (float)
163 } polymostglsl;
164
165 static struct {
166 GLuint vao; // Vertex array object.
167 GLuint program;
168 GLuint elementbuffer;
169 GLuint indexbuffer;
170 GLint attrib_vertex; // Vertex (vec3)
171 GLint attrib_texcoord; // Texture coordinate (vec2)
172 GLint uniform_projection; // Projection matrix (mat4)
173 GLint uniform_texture; // Character bitmap (sampler2D)
174 GLint uniform_colour; // Colour (vec4)
175 GLint uniform_bgcolour; // Background colour (vec4)
176 GLint uniform_mode; // Operation mode (int)
177 // 0 = texture is mask, render vertex colour/bgcolour.
178 // 1 = texture is image, blend with bgcolour.
179 // 2 = draw solid colour.
180 } polymostauxglsl;
181
182 static GLuint elementindexbuffer = 0;
183 static GLuint elementindexbuffersize = 0;
184
185 const GLfloat gidentitymat[4][4] = {
186 {1.f, 0.f, 0.f, 0.f},
187 {0.f, 1.f, 0.f, 0.f},
188 {0.f, 0.f, 1.f, 0.f},
189 {0.f, 0.f, 0.f, 1.f},
190 };
191 GLfloat gdrawroomsprojmat[4][4]; // Proj. matrix for drawrooms() calls.
192 GLfloat grotatespriteprojmat[4][4]; // Proj. matrix for rotatesprite() calls.
193 GLfloat gorthoprojmat[4][4]; // Proj. matrix for 2D (aux) calls.
194
195 static int polymost_preparetext(void);
196 #endif //USE_OPENGL
197
198 #ifdef DEBUGGINGAIDS
199 static int polymostshowcallcounts = 0;
200 struct polymostcallcounts polymostcallcounts;
201 #endif
202
203 #if defined(_MSC_VER) && defined(_M_IX86) && USE_ASM
ftol(float f,int * a)204 static inline void ftol (float f, int *a)
205 {
206 _asm
207 {
208 mov eax, a
209 fld f
210 fistp dword ptr [eax]
211 }
212 }
213
dtol(double d,int * a)214 static inline void dtol (double d, int *a)
215 {
216 _asm
217 {
218 mov eax, a
219 fld d
220 fistp dword ptr [eax]
221 }
222 }
223 #elif defined(__WATCOMC__) && USE_ASM
224
225 #pragma aux ftol =\
226 "fistp dword ptr [eax]",\
227 parm [eax 8087]
228 #pragma aux dtol =\
229 "fistp dword ptr [eax]",\
230 parm [eax 8087]
231
232 #elif defined(__GNUC__) && defined(__i386__) && USE_ASM
233
ftol(float f,int * a)234 static inline void ftol (float f, int *a)
235 {
236 __asm__ __volatile__ (
237 #if 0 //(__GNUC__ >= 3)
238 "flds %1; fistpl %0;"
239 #else
240 "flds %1; fistpl (%0);"
241 #endif
242 : "=r" (a) : "m" (f) : "memory","cc");
243 }
244
dtol(double d,int * a)245 static inline void dtol (double d, int *a)
246 {
247 __asm__ __volatile__ (
248 #if 0 //(__GNUC__ >= 3)
249 "fldl %1; fistpl %0;"
250 #else
251 "fldl %1; fistpl (%0);"
252 #endif
253 : "=r" (a) : "m" (d) : "memory","cc");
254 }
255
256 #else
ftol(float f,int * a)257 static inline void ftol (float f, int *a)
258 {
259 *a = (int)f;
260 }
261
dtol(double d,int * a)262 static inline void dtol (double d, int *a)
263 {
264 *a = (int)d;
265 }
266 #endif
267
imod(int a,int b)268 static inline int imod (int a, int b)
269 {
270 if (a >= 0) return(a%b);
271 return(((a+1)%b)+b-1);
272 }
273
drawline2d(float x0,float y0,float x1,float y1,unsigned char col)274 static void drawline2d (float x0, float y0, float x1, float y1, unsigned char col)
275 {
276 float f, dx, dy, fxres, fyres;
277 int e, inc, x, y;
278 unsigned int up16;
279
280 dx = x1-x0; dy = y1-y0; if ((dx == 0) && (dy == 0)) return;
281 fxres = (float)xdimen; fyres = (float)ydimen;
282 if (x0 >= fxres) { if (x1 >= fxres) return; y0 += (fxres-x0)*dy/dx; x0 = fxres; }
283 else if (x0 < 0) { if (x1 < 0) return; y0 += ( 0-x0)*dy/dx; x0 = 0; }
284 if (x1 >= fxres) { y1 += (fxres-x1)*dy/dx; x1 = fxres; }
285 else if (x1 < 0) { y1 += ( 0-x1)*dy/dx; x1 = 0; }
286 if (y0 >= fyres) { if (y1 >= fyres) return; x0 += (fyres-y0)*dx/dy; y0 = fyres; }
287 else if (y0 < 0) { if (y1 < 0) return; x0 += ( 0-y0)*dx/dy; y0 = 0; }
288 if (y1 >= fyres) { x1 += (fyres-y1)*dx/dy; y1 = fyres; }
289 else if (y1 < 0) { x1 += ( 0-y1)*dx/dy; y1 = 0; }
290
291 if (fabs(dx) > fabs(dy))
292 {
293 if (x0 > x1) { f = x0; x0 = x1; x1 = f; f = y0; y0 = y1; y1 = f; }
294 y = (int)(y0*65536.f)+32768;
295 inc = (int)(dy/dx*65536.f+.5f);
296 x = (int)(x0+.5); if (x < 0) { y -= inc*x; x = 0; } //if for safety
297 e = (int)(x1+.5); if (e > xdimen) e = xdimen; //if for safety
298 up16 = (ydimen<<16);
299 for(;x<e;x++,y+=inc) if ((unsigned int)y < up16) *(unsigned char *)(ylookup[y>>16]+x+frameoffset) = col;
300 }
301 else
302 {
303 if (y0 > y1) { f = x0; x0 = x1; x1 = f; f = y0; y0 = y1; y1 = f; }
304 x = (int)(x0*65536.f)+32768;
305 inc = (int)(dx/dy*65536.f+.5f);
306 y = (int)(y0+.5); if (y < 0) { x -= inc*y; y = 0; } //if for safety
307 e = (int)(y1+.5); if (e > ydimen) e = ydimen; //if for safety
308 up16 = (xdimen<<16);
309 for(;y<e;y++,x+=inc) if ((unsigned int)x < up16) *(unsigned char *)(ylookup[y]+(x>>16)+frameoffset) = col;
310 }
311 }
312
313 #if USE_OPENGL
314
315 static int drawingskybox = 0;
316
polymost_texmayhavealpha(int dapicnum,int dapalnum)317 int polymost_texmayhavealpha (int dapicnum, int dapalnum)
318 {
319 PTHead * pth;
320 int i;
321
322 pth = PT_GetHead(dapicnum, dapalnum, 0, 1);
323 if (!pth) {
324 return 1;
325 }
326
327 if (!pth->pic[PTHPIC_BASE]) {
328 // we haven't got a PTMHead reference yet for the base layer, so we
329 // don't know if the texture actually does have alpha, so err on
330 // the side of caution
331 return 1;
332 }
333
334 return ((pth->pic[PTHPIC_BASE]->flags & PTH_HASALPHA) == PTH_HASALPHA);
335 }
336
polymost_texinvalidate(int dapicnum,int dapalnum,int dameth)337 void polymost_texinvalidate (int dapicnum, int dapalnum, int dameth)
338 {
339 PTIter iter;
340 PTHead * pth;
341
342 iter = PTIterNewMatch(
343 PTITER_PICNUM | PTITER_PALNUM | PTITER_FLAGS,
344 dapicnum, dapalnum, PTH_CLAMPED, (dameth & METH_CLAMPED) ? PTH_CLAMPED : 0
345 );
346 while ((pth = PTIterNext(iter)) != 0) {
347 if (pth->pic[PTHPIC_BASE]) {
348 pth->pic[PTHPIC_BASE]->flags |= PTH_DIRTY;
349 }
350 /*buildprintf("invalidating picnum:%d palnum:%d effects:%d skyface:%d flags:%04X repldef:%p\n",
351 pth->picnum, pth->palnum, pth->effects, pth->skyface,
352 pth->flags, pth->repldef);*/
353 }
354 //buildprintf("done\n");
355 PTIterFree(iter);
356 }
357
358 //Make all textures "dirty" so they reload, but not re-allocate
359 //This should be much faster than polymost_glreset()
360 //Use this for palette effects ... but not ones that change every frame!
polymost_texinvalidateall()361 void polymost_texinvalidateall ()
362 {
363 PTIter iter;
364 PTHead * pth;
365
366 iter = PTIterNew();
367 while ((pth = PTIterNext(iter)) != 0) {
368 if (pth->pic[PTHPIC_BASE]) {
369 pth->pic[PTHPIC_BASE]->flags |= PTH_DIRTY;
370 }
371 }
372 PTIterFree(iter);
373 clearskins();
374 //buildprintf("gltexinvalidateall()\n");
375 }
376
377
gltexapplyprops(void)378 void gltexapplyprops (void)
379 {
380 int i;
381 PTIter iter;
382 PTHead * pth;
383
384 if (glinfo.maxanisotropy > 1.0)
385 {
386 if (glanisotropy <= 0 || glanisotropy > glinfo.maxanisotropy) glanisotropy = (int)glinfo.maxanisotropy;
387 }
388
389 if (gltexfiltermode < 0) gltexfiltermode = 0;
390 else if (gltexfiltermode >= (int)numglfiltermodes) gltexfiltermode = numglfiltermodes-1;
391
392 iter = PTIterNew();
393 while ((pth = PTIterNext(iter)) != 0) {
394 for (i = 0; i < PTHPIC_SIZE; i++) {
395 if (pth->pic[i] == 0 || pth->pic[i]->glpic == 0) {
396 continue;
397 }
398 glfunc.glBindTexture(GL_TEXTURE_2D,pth->pic[i]->glpic);
399 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,glfiltermodes[gltexfiltermode].mag);
400 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,glfiltermodes[gltexfiltermode].min);
401 if (glinfo.maxanisotropy > 1.0) {
402 glfunc.glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,glanisotropy);
403 }
404 }
405 }
406 PTIterFree(iter);
407
408 {
409 int j;
410 mdskinmap_t *sk;
411 md2model *m;
412
413 for (i=0;i<nextmodelid;i++)
414 {
415 m = (md2model *)models[i];
416 if (m->mdnum < 2) continue;
417 for (j=0;j<m->numskins*(HICEFFECTMASK+1);j++)
418 {
419 if (!m->tex[j] || !m->tex[j]->glpic) continue;
420 glfunc.glBindTexture(GL_TEXTURE_2D,m->tex[j]->glpic);
421 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,glfiltermodes[gltexfiltermode].mag);
422 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,glfiltermodes[gltexfiltermode].min);
423 if (glinfo.maxanisotropy > 1.0)
424 glfunc.glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,glanisotropy);
425 }
426
427 for (sk=m->skinmap;sk;sk=sk->next)
428 for (j=0;j<(HICEFFECTMASK+1);j++)
429 {
430 if (!sk->tex[j] || !sk->tex[j]->glpic) continue;
431 glfunc.glBindTexture(GL_TEXTURE_2D,sk->tex[j]->glpic);
432 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,glfiltermodes[gltexfiltermode].mag);
433 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,glfiltermodes[gltexfiltermode].min);
434 if (glinfo.maxanisotropy > 1.0)
435 glfunc.glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,glanisotropy);
436 }
437 }
438 }
439 }
440
441 //--------------------------------------------------------------------------------------------------
442
443 float glox1, gloy1, glox2, gloy2;
444
445 //Use this for both initialization and uninitialization of OpenGL.
446 static int gltexcacnum = -1;
polymost_glreset()447 void polymost_glreset ()
448 {
449 int i;
450
451 //Reset if this is -1 (meaning 1st texture call ever), or > 0 (textures in memory)
452 if (gltexcacnum < 0)
453 {
454 gltexcacnum = 0;
455
456 //Hack for polymost_dorotatesprite calls before 1st polymost_drawrooms()
457 gcosang = gcosang2 = ((double)16384)/262144.0;
458 gsinang = gsinang2 = ((double) 0)/262144.0;
459 }
460 else
461 {
462 PTReset();
463 clearskins();
464 }
465
466 glox1 = -1;
467 lastglpolygonmode = -1;
468 lastglredbluemode = -1;
469
470 if (glfunc.glUseProgram) {
471 glfunc.glUseProgram(0);
472 #if (USE_OPENGL == USE_GL3)
473 glfunc.glBindVertexArray(0);
474 #endif
475 glfunc.glBindBuffer(GL_ARRAY_BUFFER, 0);
476 glfunc.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
477 }
478
479 if (elementindexbuffer) {
480 glfunc.glDeleteBuffers(1, &elementindexbuffer);
481 elementindexbuffersize = 0;
482 elementindexbuffer = 0;
483 }
484
485 #if (USE_OPENGL == USE_GL3)
486 if (polymostglsl.vao) {
487 glfunc.glDeleteVertexArrays(1, &polymostglsl.vao);
488 polymostglsl.vao = 0;
489 }
490 #endif
491 if (polymostglsl.elementbuffer) {
492 glfunc.glDeleteBuffers(1, &polymostglsl.elementbuffer);
493 polymostglsl.elementbuffer = 0;
494 }
495 if (polymostglsl.program) {
496 glfunc.glDeleteProgram(polymostglsl.program);
497 polymostglsl.program = 0;
498 }
499
500 #if (USE_OPENGL == USE_GL3)
501 if (polymostauxglsl.vao) {
502 glfunc.glDeleteVertexArrays(1, &polymostauxglsl.vao);
503 polymostauxglsl.vao = 0;
504 }
505 #endif
506 if (polymostauxglsl.indexbuffer) {
507 glfunc.glDeleteBuffers(1, &polymostauxglsl.indexbuffer);
508 polymostauxglsl.indexbuffer = 0;
509 }
510 if (polymostauxglsl.elementbuffer) {
511 glfunc.glDeleteBuffers(1, &polymostauxglsl.elementbuffer);
512 polymostauxglsl.elementbuffer = 0;
513 }
514 if (polymostauxglsl.program) {
515 glfunc.glDeleteProgram(polymostauxglsl.program);
516 polymostauxglsl.program = 0;
517 }
518
519 if (texttexture) {
520 glfunc.glDeleteTextures(1, &texttexture);
521 texttexture = 0;
522 }
523
524 if (nulltexture) {
525 glfunc.glDeleteTextures(1, &nulltexture);
526 nulltexture = 0;
527 }
528 }
529
polymost_get_attrib(GLuint program,const GLchar * name)530 static GLint polymost_get_attrib(GLuint program, const GLchar *name)
531 {
532 GLint attribloc = glfunc.glGetAttribLocation(program, name);
533 if (attribloc < 0) {
534 buildprintf("polymost_get_attrib: could not get location of attribute \"%s\"\n", name);
535 }
536 return attribloc;
537 }
538
polymost_get_uniform(GLuint program,const GLchar * name)539 static GLint polymost_get_uniform(GLuint program, const GLchar *name)
540 {
541 GLint uniformloc = glfunc.glGetUniformLocation(program, name);
542 if (uniformloc < 0) {
543 buildprintf("polymost_get_uniform: could not get location of uniform \"%s\"\n", name);
544 }
545 return uniformloc;
546 }
547
polymost_load_shader(GLuint shadertype,const char * defaultsrc,const char * filename)548 static GLuint polymost_load_shader(GLuint shadertype, const char *defaultsrc, const char *filename)
549 {
550 const GLchar *shadersrc = defaultsrc;
551 GLuint shader = 0;
552
553 #ifdef SHADERDEV
554 GLchar *fileshadersrc = NULL;
555 int shadersrclen = 0;
556 BFILE *shaderfh = NULL;
557
558 shaderfh = fopen(filename, "rb");
559 if (shaderfh) {
560 fseek(shaderfh, 0, SEEK_END);
561 shadersrclen = (int)ftell(shaderfh);
562 fseek(shaderfh, 0, SEEK_SET);
563
564 fileshadersrc = (GLchar *)calloc(1, shadersrclen + 1);
565 fread(fileshadersrc, shadersrclen, 1, shaderfh);
566
567 fclose(shaderfh);
568 shaderfh = NULL;
569
570 buildprintf("polymost_load_shader: loaded %s (%d bytes)\n", filename, shadersrclen);
571 shadersrc = fileshadersrc;
572 }
573 #endif
574
575 shader = glbuild_compile_shader(shadertype, shadersrc);
576
577 #ifdef SHADERDEV
578 if (fileshadersrc) {
579 free(fileshadersrc);
580 fileshadersrc = NULL;
581 }
582 #endif
583
584 return shader;
585 }
586
checkindexbuffer(unsigned int size)587 static void checkindexbuffer(unsigned int size)
588 {
589 GLushort *indexes, i;
590
591 if (size <= elementindexbuffersize) return;
592
593 indexes = (GLushort *) malloc(sizeof(GLushort)*size);
594 for (i = 0; i < size; i++) indexes[i] = i;
595 glfunc.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementindexbuffer);
596 glfunc.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort)*size, indexes, GL_STATIC_DRAW);
597 free(indexes);
598
599 elementindexbuffersize = size;
600 }
601
polymost_loadshaders(void)602 static void polymost_loadshaders(void)
603 {
604 extern const char default_polymost_fs_glsl[];
605 extern const char default_polymost_vs_glsl[];
606
607 extern const char default_polymostaux_fs_glsl[];
608 extern const char default_polymostaux_vs_glsl[];
609
610 GLuint shader[2] = {0,0};
611
612 // General texture rendering shader.
613 if (polymostglsl.program) {
614 glfunc.glDeleteProgram(polymostglsl.program);
615 polymostglsl.program = 0;
616 }
617
618 shader[0] = polymost_load_shader(GL_VERTEX_SHADER, default_polymost_vs_glsl, "polymost_vs.glsl");
619 shader[1] = polymost_load_shader(GL_FRAGMENT_SHADER, default_polymost_fs_glsl, "polymost_fs.glsl");
620 if (shader[0] && shader[1]) {
621 polymostglsl.program = glbuild_link_program(2, shader);
622 }
623 if (shader[0]) glfunc.glDeleteShader(shader[0]);
624 if (shader[1]) glfunc.glDeleteShader(shader[1]);
625
626 if (polymostglsl.program) {
627 polymostglsl.attrib_vertex = polymost_get_attrib(polymostglsl.program, "a_vertex");
628 polymostglsl.attrib_texcoord = polymost_get_attrib(polymostglsl.program, "a_texcoord");
629 polymostglsl.uniform_modelview = polymost_get_uniform(polymostglsl.program, "u_modelview");
630 polymostglsl.uniform_projection = polymost_get_uniform(polymostglsl.program, "u_projection");
631 polymostglsl.uniform_texture = polymost_get_uniform(polymostglsl.program, "u_texture");
632 polymostglsl.uniform_glowtexture = polymost_get_uniform(polymostglsl.program, "u_glowtexture");
633 polymostglsl.uniform_alphacut = polymost_get_uniform(polymostglsl.program, "u_alphacut");
634 polymostglsl.uniform_colour = polymost_get_uniform(polymostglsl.program, "u_colour");
635 polymostglsl.uniform_fogcolour = polymost_get_uniform(polymostglsl.program, "u_fogcolour");
636 polymostglsl.uniform_fogdensity = polymost_get_uniform(polymostglsl.program, "u_fogdensity");
637
638 #if (USE_OPENGL == USE_GL3)
639 glfunc.glGenVertexArrays(1, &polymostglsl.vao);
640 glfunc.glBindVertexArray(polymostglsl.vao);
641 glfunc.glEnableVertexAttribArray(polymostglsl.attrib_vertex);
642 glfunc.glEnableVertexAttribArray(polymostglsl.attrib_texcoord);
643 #endif
644
645 glfunc.glUseProgram(polymostglsl.program);
646 glfunc.glUniform1i(polymostglsl.uniform_texture, 0); //GL_TEXTURE0
647 glfunc.glUniform1i(polymostglsl.uniform_glowtexture, 1); //GL_TEXTURE1
648
649 // Generate a buffer object for vertex/colour elements.
650 glfunc.glGenBuffers(1, &polymostglsl.elementbuffer);
651 }
652
653 // A fully transparent texture for the case when a glow texture is not needed.
654 if (!nulltexture) {
655 const char pix[4] = {0,0,0,0};
656 glfunc.glGenTextures(1, &nulltexture);
657 glfunc.glBindTexture(GL_TEXTURE_2D, nulltexture);
658 glfunc.glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,1,1,0,GL_RGBA,GL_UNSIGNED_BYTE,(GLvoid*)&pix);
659 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
660 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
661 }
662
663 // Engine auxiliary shader.
664 if (polymostauxglsl.program) {
665 glfunc.glDeleteProgram(polymostauxglsl.program);
666 polymostauxglsl.program = 0;
667 }
668
669 shader[0] = polymost_load_shader(GL_VERTEX_SHADER, default_polymostaux_vs_glsl, "polymostaux_vs.glsl");
670 shader[1] = polymost_load_shader(GL_FRAGMENT_SHADER, default_polymostaux_fs_glsl, "polymostaux_fs.glsl");
671 if (shader[0] && shader[1]) {
672 polymostauxglsl.program = glbuild_link_program(2, shader);
673 }
674 if (shader[0]) glfunc.glDeleteShader(shader[0]);
675 if (shader[1]) glfunc.glDeleteShader(shader[1]);
676
677 if (polymostauxglsl.program) {
678 polymostauxglsl.attrib_vertex = polymost_get_attrib(polymostauxglsl.program, "a_vertex");
679 polymostauxglsl.attrib_texcoord = polymost_get_attrib(polymostauxglsl.program, "a_texcoord");
680 polymostauxglsl.uniform_projection = polymost_get_uniform(polymostauxglsl.program, "u_projection");
681 polymostauxglsl.uniform_texture = polymost_get_uniform(polymostauxglsl.program, "u_texture");
682 polymostauxglsl.uniform_colour = polymost_get_uniform(polymostauxglsl.program, "u_colour");
683 polymostauxglsl.uniform_bgcolour = polymost_get_uniform(polymostauxglsl.program, "u_bgcolour");
684 polymostauxglsl.uniform_mode = polymost_get_uniform(polymostauxglsl.program, "u_mode");
685
686 #if (USE_OPENGL == USE_GL3)
687 glfunc.glGenVertexArrays(1, &polymostauxglsl.vao);
688 glfunc.glBindVertexArray(polymostauxglsl.vao);
689 glfunc.glEnableVertexAttribArray(polymostauxglsl.attrib_vertex);
690 glfunc.glEnableVertexAttribArray(polymostauxglsl.attrib_texcoord);
691 #endif
692
693 glfunc.glUseProgram(polymostauxglsl.program);
694 glfunc.glUniform1i(polymostauxglsl.uniform_texture, 0); //GL_TEXTURE0
695
696 // Generate a buffer object for vertex/colour elements and pre-allocate its memory.
697 glfunc.glGenBuffers(1, &polymostauxglsl.elementbuffer);
698
699 // Generate a buffer object for ad-hoc indexes.
700 glfunc.glGenBuffers(1, &polymostauxglsl.indexbuffer);
701 }
702
703 // Generate a buffer object for element indexes and populate it with an
704 // initial set of ascending indices, the way drawpoly() will generate points.
705 glfunc.glGenBuffers(1, &elementindexbuffer);
706 checkindexbuffer(MINVBOINDEXES);
707 }
708
709 // one-time initialisation of OpenGL for polymost
polymost_glinit()710 void polymost_glinit()
711 {
712 GLfloat col[4];
713
714 glfunc.glClearColor(0,0,0,0.5); //Black Background
715 glfunc.glDisable(GL_DITHER);
716
717 glfunc.glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
718
719 glfunc.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
720
721 if (glmultisample > 0 && glinfo.multisample) {
722 #if (USE_OPENGL != USE_GLES2)
723 if (glinfo.nvmultisamplehint)
724 glfunc.glHint(GL_MULTISAMPLE_FILTER_HINT_NV, glnvmultisamplehint ? GL_NICEST:GL_FASTEST);
725 glfunc.glEnable(GL_MULTISAMPLE_ARB);
726 #endif
727 }
728
729 polymost_loadshaders();
730 }
731
resizeglcheck()732 void resizeglcheck ()
733 {
734 float m[4][4];
735
736 if (glredbluemode < lastglredbluemode) {
737 glox1 = -1;
738 glfunc.glColorMask(1,1,1,1);
739 } else if (glredbluemode != lastglredbluemode) {
740 redblueclearcnt = 0;
741 }
742 lastglredbluemode = glredbluemode;
743
744 #if (USE_OPENGL != USE_GLES2)
745 if (lastglpolygonmode != glpolygonmode)
746 {
747 lastglpolygonmode = glpolygonmode;
748 switch(glpolygonmode)
749 {
750 default:
751 case 0: glfunc.glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); break;
752 case 1: glfunc.glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); break;
753 case 2: glfunc.glPolygonMode(GL_FRONT_AND_BACK,GL_POINT); break;
754 }
755 }
756 #endif
757
758 if ((glox1 != windowx1) || (gloy1 != windowy1) || (glox2 != windowx2) || (gloy2 != windowy2))
759 {
760 glox1 = windowx1; gloy1 = windowy1;
761 glox2 = windowx2; gloy2 = windowy2;
762
763 glfunc.glViewport(windowx1,yres-(windowy2+1),windowx2-windowx1+1,windowy2-windowy1+1);
764 }
765 }
766
polymost_aftershowframe(void)767 void polymost_aftershowframe(void)
768 {
769 #if (USE_OPENGL != USE_GLES2)
770 if (glpolygonmode)
771 {
772 glfunc.glClearColor(1.0,1.0,1.0,0.0);
773 glfunc.glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
774 }
775 #endif
776 }
777
polymost_setview(void)778 void polymost_setview(void)
779 {
780 memset(gdrawroomsprojmat,0,sizeof(gdrawroomsprojmat));
781 gdrawroomsprojmat[0][0] = (float)ydimen; gdrawroomsprojmat[0][2] = 1.0;
782 gdrawroomsprojmat[1][1] = (float)xdimen; gdrawroomsprojmat[1][2] = 1.0;
783 gdrawroomsprojmat[2][2] = 1.0; gdrawroomsprojmat[2][3] = (float)ydimen;
784 gdrawroomsprojmat[3][2] =-1.0;
785
786 memset(grotatespriteprojmat,0,sizeof(grotatespriteprojmat));
787 grotatespriteprojmat[0][0] = grotatespriteprojmat[2][3] = 1.0;
788 grotatespriteprojmat[1][1] = ((float)xdim)/((float)ydim);
789 grotatespriteprojmat[2][2] = 1.0001;
790 grotatespriteprojmat[3][2] = 1-grotatespriteprojmat[2][2];
791
792 memset(gorthoprojmat,0,sizeof(gorthoprojmat));
793 gorthoprojmat[0][0] = 2/(float)xdim;
794 gorthoprojmat[1][1] = -2/(float)ydim;
795 gorthoprojmat[2][2] = -1.0;
796 gorthoprojmat[3][3] = 1.0;
797 gorthoprojmat[3][0] = -1.0;
798 gorthoprojmat[3][1] = 1.0;
799 }
800
polymost_drawpoly_glcall(GLenum mode,struct polymostdrawpolycall * draw)801 void polymost_drawpoly_glcall(GLenum mode, struct polymostdrawpolycall *draw)
802 {
803 #ifdef DEBUGGINGAIDS
804 polymostcallcounts.drawpoly_glcall++;
805 #endif
806
807 glfunc.glUseProgram(polymostglsl.program);
808
809 #if (USE_OPENGL == USE_GL3)
810 glfunc.glBindVertexArray(polymostglsl.vao);
811 #else
812 glfunc.glEnableVertexAttribArray(polymostglsl.attrib_vertex);
813 glfunc.glEnableVertexAttribArray(polymostglsl.attrib_texcoord);
814 #endif
815
816 if (draw->elementbuffer > 0) {
817 glfunc.glBindBuffer(GL_ARRAY_BUFFER, draw->elementbuffer);
818 } else {
819 // Drawing from the passed elementvbo items.
820 glfunc.glBindBuffer(GL_ARRAY_BUFFER, polymostglsl.elementbuffer);
821 glfunc.glBufferData(GL_ARRAY_BUFFER, draw->elementcount * sizeof(struct polymostvboitem), draw->elementvbo, GL_STREAM_DRAW);
822 }
823
824 if (draw->indexbuffer > 0) {
825 glfunc.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, draw->indexbuffer);
826 } else {
827 glfunc.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementindexbuffer);
828 checkindexbuffer(draw->indexcount);
829 }
830
831 glfunc.glVertexAttribPointer(polymostglsl.attrib_vertex, 3, GL_FLOAT, GL_FALSE,
832 sizeof(struct polymostvboitem), (const GLvoid *)offsetof(struct polymostvboitem, v));
833 glfunc.glVertexAttribPointer(polymostglsl.attrib_texcoord, 2, GL_FLOAT, GL_FALSE,
834 sizeof(struct polymostvboitem), (const GLvoid *)offsetof(struct polymostvboitem, t));
835
836 glfunc.glActiveTexture(GL_TEXTURE0);
837 glfunc.glBindTexture(GL_TEXTURE_2D, draw->texture0);
838
839 glfunc.glActiveTexture(GL_TEXTURE1);
840 glfunc.glBindTexture(GL_TEXTURE_2D, draw->texture1 ? draw->texture1 : nulltexture);
841
842 glfunc.glUniform1f(polymostglsl.uniform_alphacut, draw->alphacut);
843
844 glfunc.glUniform4f(
845 polymostglsl.uniform_colour,
846 draw->colour.r, draw->colour.g, draw->colour.b, draw->colour.a
847 );
848 glfunc.glUniform4f(
849 polymostglsl.uniform_fogcolour,
850 draw->fogcolour.r, draw->fogcolour.g, draw->fogcolour.b, draw->fogcolour.a
851 );
852 glfunc.glUniform1f(
853 polymostglsl.uniform_fogdensity,
854 draw->fogdensity
855 );
856
857 glfunc.glUniformMatrix4fv(polymostglsl.uniform_modelview, 1, GL_FALSE, draw->modelview);
858 glfunc.glUniformMatrix4fv(polymostglsl.uniform_projection, 1, GL_FALSE, draw->projection);
859
860 glfunc.glDrawElements(mode, draw->indexcount, GL_UNSIGNED_SHORT, 0);
861
862 #if (USE_OPENGL == USE_GL3)
863 glfunc.glBindVertexArray(0);
864 #else
865 glfunc.glDisableVertexAttribArray(polymostglsl.attrib_vertex);
866 glfunc.glDisableVertexAttribArray(polymostglsl.attrib_texcoord);
867 #endif
868 }
869
polymost_drawaux_glcall(GLenum mode,struct polymostdrawauxcall * draw)870 static void polymost_drawaux_glcall(GLenum mode, struct polymostdrawauxcall *draw)
871 {
872 #ifdef DEBUGGINGAIDS
873 polymostcallcounts.drawaux_glcall++;
874 #endif
875
876 glfunc.glUseProgram(polymostauxglsl.program);
877
878 #if (USE_OPENGL == USE_GL3)
879 glfunc.glBindVertexArray(polymostauxglsl.vao);
880 #else
881 glfunc.glEnableVertexAttribArray(polymostauxglsl.attrib_vertex);
882 glfunc.glEnableVertexAttribArray(polymostauxglsl.attrib_texcoord);
883 #endif
884
885 glfunc.glBindBuffer(GL_ARRAY_BUFFER, polymostauxglsl.elementbuffer);
886 glfunc.glBufferData(GL_ARRAY_BUFFER, draw->elementcount * sizeof(struct polymostvboitem), draw->elementvbo, GL_STREAM_DRAW);
887
888 if (draw->indexes) {
889 glfunc.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, polymostauxglsl.indexbuffer);
890 glfunc.glBufferData(GL_ELEMENT_ARRAY_BUFFER, draw->indexcount * sizeof(GLushort), draw->indexes, GL_STREAM_DRAW);
891 } else {
892 glfunc.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementindexbuffer);
893 checkindexbuffer(draw->indexcount);
894 }
895
896 glfunc.glVertexAttribPointer(polymostauxglsl.attrib_vertex, 3, GL_FLOAT, GL_FALSE,
897 sizeof(struct polymostvboitem), (const GLvoid *)offsetof(struct polymostvboitem, v));
898 glfunc.glVertexAttribPointer(polymostauxglsl.attrib_texcoord, 2, GL_FLOAT, GL_FALSE,
899 sizeof(struct polymostvboitem), (const GLvoid *)offsetof(struct polymostvboitem, t));
900
901 glfunc.glActiveTexture(GL_TEXTURE0);
902 glfunc.glBindTexture(GL_TEXTURE_2D, draw->texture0);
903
904 glfunc.glUniform4f(
905 polymostauxglsl.uniform_colour,
906 draw->colour.r, draw->colour.g, draw->colour.b, draw->colour.a
907 );
908 glfunc.glUniform4f(
909 polymostauxglsl.uniform_bgcolour,
910 draw->bgcolour.r, draw->bgcolour.g, draw->bgcolour.b, draw->bgcolour.a
911 );
912 glfunc.glUniform1i(polymostauxglsl.uniform_mode, draw->mode);
913
914 glfunc.glUniformMatrix4fv(polymostauxglsl.uniform_projection, 1, GL_FALSE, &gorthoprojmat[0][0]);
915
916 glfunc.glDrawElements(mode, draw->indexcount, GL_UNSIGNED_SHORT, 0);
917
918 #if (USE_OPENGL == USE_GL3)
919 glfunc.glBindVertexArray(0);
920 #else
921 glfunc.glDisableVertexAttribArray(polymostauxglsl.attrib_vertex);
922 glfunc.glDisableVertexAttribArray(polymostauxglsl.attrib_texcoord);
923 #endif
924 }
925
polymost_palfade(void)926 static void polymost_palfade(void)
927 {
928 struct polymostdrawauxcall draw;
929 struct polymostvboitem vboitem[4];
930
931 if ((rendmode != 3) || (qsetmode != 200)) return;
932 if (palfadedelta == 0) return;
933
934 draw.mode = 2; // Solid colour.
935
936 draw.colour.r = palfadergb.r / 255.f;
937 draw.colour.g = palfadergb.g / 255.f;
938 draw.colour.b = palfadergb.b / 255.f;
939 draw.colour.a = palfadedelta / 255.f;
940
941 vboitem[0].v.x = 0.f;
942 vboitem[0].v.y = 0.f;
943 vboitem[0].v.z = 0.f;
944
945 vboitem[1].v.x = (float)xdim;
946 vboitem[1].v.y = 0.f;
947 vboitem[1].v.z = 0.f;
948
949 vboitem[2].v.x = (float)xdim;
950 vboitem[2].v.y = (float)ydim;
951 vboitem[2].v.z = 0.f;
952
953 vboitem[3].v.x = 0.f;
954 vboitem[3].v.y = (float)ydim;
955 vboitem[3].v.z = 0.f;
956
957 draw.indexcount = 4;
958 draw.indexes = NULL;
959 draw.elementcount = 4;
960 draw.elementvbo = vboitem;
961
962 glfunc.glDisable(GL_DEPTH_TEST);
963 glfunc.glEnable(GL_BLEND);
964
965 polymost_drawaux_glcall(GL_TRIANGLE_FAN, &draw);
966 }
967
968 #endif //USE_OPENGL
969
polymost_nextpage(void)970 void polymost_nextpage(void)
971 {
972 #if USE_OPENGL
973 polymost_palfade();
974 #endif
975
976 #ifdef DEBUGGINGAIDS
977 if (polymostshowcallcounts) {
978 char buf[1024];
979 sprintf(buf,
980 "drawpoly_gl(%d) drawaux_gl(%d) drawpoly(%d) "
981 "domost(%d) drawalls(%d) drawmaskwall(%d) drawsprite(%d)",
982 polymostcallcounts.drawpoly_glcall,
983 polymostcallcounts.drawaux_glcall,
984 polymostcallcounts.drawpoly,
985 polymostcallcounts.domost,
986 polymostcallcounts.drawalls,
987 polymostcallcounts.drawmaskwall,
988 polymostcallcounts.drawsprite
989 );
990 if (rendmode == 3) {
991 polymost_printext256(0, 8, 31, -1, buf, 0);
992 } else {
993 printext256(0, 8, 31, -1, buf, 0);
994 }
995 }
996 memset(&polymostcallcounts, 0, sizeof(polymostcallcounts));
997 #endif
998 }
999
1000 //(dpx,dpy) specifies an n-sided polygon. The polygon must be a convex clockwise loop.
1001 // n must be <= 8 (assume clipping can double number of vertices)
1002 //method: 0:solid, 1:masked(255 is transparent), 2:transluscent #1, 3:transluscent #2
1003 // +4 means it's a sprite, so wraparound isn't needed
drawpoly(double * dpx,double * dpy,int n,int method)1004 void drawpoly (double *dpx, double *dpy, int n, int method)
1005 {
1006 #define PI 3.14159265358979323
1007 double ngdx = 0.0, ngdy = 0.0, ngdo = 0.0, ngux = 0.0, nguy = 0.0, nguo = 0.0;
1008 double ngvx = 0.0, ngvy = 0.0, ngvo = 0.0, dp, up, vp, rdp, du0 = 0.0, du1 = 0.0, dui, duj;
1009 double ngdx2, ngux2, ngvx2;
1010 double f, r, ox, oy, oz, ox2, oy2, oz2, dd[16], uu[16], vv[16], px[16], py[16], uoffs;
1011 int i, j, k, x, y, z, nn, ix0, ix1, mini, maxi, tsizx, tsizy, tsizxm1 = 0, tsizym1 = 0, ltsizy = 0;
1012 int xx, yy, xi, d0, u0, v0, d1, u1, v1, xmodnice = 0, ymulnice = 0, dorot;
1013 unsigned char dacol = 0, *walptr, *palptr = NULL, *vidp, *vide;
1014
1015 #ifdef DEBUGGINGAIDS
1016 polymostcallcounts.drawpoly++;
1017 #endif
1018
1019 if (method == -1) return;
1020
1021 if (n == 3)
1022 {
1023 if ((dpx[0]-dpx[1])*(dpy[2]-dpy[1]) >= (dpx[2]-dpx[1])*(dpy[0]-dpy[1])) return; //for triangle
1024 }
1025 else
1026 {
1027 f = 0; //f is area of polygon / 2
1028 for(i=n-2,j=n-1,k=0;k<n;i=j,j=k,k++) f += (dpx[i]-dpx[k])*dpy[j];
1029 if (f <= 0) return;
1030 }
1031
1032 //Load texture (globalpicnum)
1033 if ((unsigned int)globalpicnum >= MAXTILES) globalpicnum = 0;
1034 setgotpic(globalpicnum);
1035 tsizx = tilesizx[globalpicnum];
1036 tsizy = tilesizy[globalpicnum];
1037 if (!palookup[globalpal]) globalpal = 0;
1038 if (!waloff[globalpicnum])
1039 {
1040 loadtile(globalpicnum);
1041 if (!waloff[globalpicnum])
1042 {
1043 if (rendmode != 3) return;
1044 tsizx = tsizy = 1; method = METH_MASKED; //Hack to update Z-buffer for invalid mirror textures
1045 }
1046 }
1047 walptr = (unsigned char *)waloff[globalpicnum];
1048
1049 j = 0; dorot = ((gchang != 1.0) || (gctang != 1.0));
1050 if (dorot)
1051 {
1052 for(i=0;i<n;i++)
1053 {
1054 ox = dpx[i]-ghalfx;
1055 oy = dpy[i]-ghoriz;
1056 oz = ghalfx;
1057
1058 //Up/down rotation
1059 ox2 = ox;
1060 oy2 = oy*gchang - oz*gshang;
1061 oz2 = oy*gshang + oz*gchang;
1062
1063 //Tilt rotation
1064 ox = ox2*gctang - oy2*gstang;
1065 oy = ox2*gstang + oy2*gctang;
1066 oz = oz2;
1067
1068 if ((oz < SCISDIST) && (rendmode != 3)) return; //annoying hack to avoid bugs in software rendering
1069
1070 r = ghalfx / oz;
1071
1072 dd[j] = (dpx[i]*gdx + dpy[i]*gdy + gdo)*r;
1073 uu[j] = (dpx[i]*gux + dpy[i]*guy + guo)*r;
1074 vv[j] = (dpx[i]*gvx + dpy[i]*gvy + gvo)*r;
1075
1076 px[j] = ox*r + ghalfx;
1077 py[j] = oy*r + ghoriz;
1078 if ((!j) || (px[j] != px[j-1]) || (py[j] != py[j-1])) j++;
1079 }
1080 }
1081 else
1082 {
1083 for(i=0;i<n;i++)
1084 {
1085 px[j] = dpx[i];
1086 py[j] = dpy[i];
1087 if ((!j) || (px[j] != px[j-1]) || (py[j] != py[j-1])) j++;
1088 }
1089 }
1090 while ((j >= 3) && (px[j-1] == px[0]) && (py[j-1] == py[0])) j--;
1091 if (j < 3) return;
1092 n = j;
1093
1094 #if USE_OPENGL
1095 if (rendmode == 3)
1096 {
1097 float hackscx, hackscy;
1098 unsigned short ptflags = 0;
1099 int picidx = PTHPIC_BASE;
1100 PTHead * pth = 0;
1101 struct polymostdrawpolycall draw;
1102 struct polymostvboitem vboitem[MINVBOINDEXES];
1103
1104 if (usehightile) ptflags |= PTH_HIGHTILE;
1105 if (method & METH_CLAMPED) ptflags |= PTH_CLAMPED;
1106 if (drawingskybox) ptflags |= PTH_SKYBOX;
1107
1108 pth = PT_GetHead(globalpicnum, globalpal, ptflags, 0);
1109
1110 // Base texture.
1111 draw.texture0 = 0;
1112 if (pth) {
1113 if (drawingskybox) {
1114 picidx = drawingskybox - 1;
1115 }
1116 if (pth->pic[picidx]) {
1117 draw.texture0 = pth->pic[picidx]->glpic;
1118 }
1119 }
1120
1121 // Glow texture.
1122 draw.texture1 = nulltexture;
1123 if ((method & METH_LAYERS) && pth && !drawingskybox) {
1124 if (pth->pic[ PTHPIC_GLOW ]) {
1125 draw.texture1 = pth->pic[ PTHPIC_GLOW ]->glpic;
1126 }
1127 }
1128
1129 if (!(method & (METH_MASKED | METH_TRANS))) {
1130 glfunc.glDisable(GL_BLEND);
1131 draw.alphacut = 0.f;
1132 } else {
1133 float alphac = 0.32;
1134 if (pth && pth->repldef && pth->repldef->alphacut >= 0.0) {
1135 alphac = pth->repldef->alphacut;
1136 }
1137 if (usegoodalpha) alphac = 0.0;
1138 if (!waloff[globalpicnum]) alphac = 0.0; // invalid textures ignore the alpha cutoff settings
1139
1140 glfunc.glEnable(GL_BLEND);
1141 draw.alphacut = alphac;
1142 }
1143
1144 draw.fogcolour.r = (float)palookupfog[gfogpalnum].r / 63.f;
1145 draw.fogcolour.g = (float)palookupfog[gfogpalnum].g / 63.f;
1146 draw.fogcolour.b = (float)palookupfog[gfogpalnum].b / 63.f;
1147 draw.fogcolour.a = 1.f;
1148 draw.fogdensity = gfogdensity;
1149
1150 hackscx = pth->scalex;
1151 hackscy = pth->scaley;
1152 tsizx = pth->pic[picidx]->tsizx;
1153 tsizy = pth->pic[picidx]->tsizy;
1154 xx = pth->pic[picidx]->sizx;
1155 yy = pth->pic[picidx]->sizy;
1156 ox2 = (double)1.0/(double)xx;
1157 oy2 = (double)1.0/(double)yy;
1158
1159 if (!dorot)
1160 {
1161 for(i=n-1;i>=0;i--)
1162 {
1163 dd[i] = px[i]*gdx + py[i]*gdy + gdo;
1164 uu[i] = px[i]*gux + py[i]*guy + guo;
1165 vv[i] = px[i]*gvx + py[i]*gvy + gvo;
1166 }
1167 }
1168
1169 draw.colour.r = draw.colour.g = draw.colour.b =
1170 ((float)(numpalookups-min(max(globalshade,0),numpalookups)))/((float)numpalookups);
1171 switch(method & (METH_MASKED | METH_TRANS))
1172 {
1173 case METH_SOLID: draw.colour.a = 1.0; break;
1174 case METH_MASKED: draw.colour.a = 1.0; break;
1175 case METH_TRANS: draw.colour.a = 0.66; break;
1176 case METH_INTRANS: draw.colour.a = 0.33; break;
1177 }
1178 // tinting happens only to hightile textures, and only if the texture we're
1179 // rendering isn't for the same palette as what we asked for
1180 if (pth && (pth->flags & PTH_HIGHTILE) && (globalpal != pth->repldef->palnum)) {
1181 // apply tinting for replaced textures
1182 draw.colour.r *= (float)hictinting[globalpal].r / 255.0;
1183 draw.colour.g *= (float)hictinting[globalpal].g / 255.0;
1184 draw.colour.b *= (float)hictinting[globalpal].b / 255.0;
1185 }
1186
1187 draw.modelview = &gidentitymat[0][0];
1188 if (method & METH_ROTATESPRITE) {
1189 draw.projection = &grotatespriteprojmat[0][0];
1190 } else {
1191 draw.projection = &gdrawroomsprojmat[0][0];
1192 }
1193
1194 draw.indexbuffer = 0;
1195 draw.elementbuffer = 0;
1196 draw.elementvbo = vboitem;
1197
1198 //Hack for walls&masked walls which use textures that are not a power of 2
1199 if ((method & METH_POW2XSPLIT) && (tsizx != xx))
1200 {
1201 if (!dorot)
1202 {
1203 ngdx = gdx; ngdy = gdy; ngdo = gdo+(ngdx+ngdy)*.5;
1204 ngux = gux; nguy = guy; nguo = guo+(ngux+nguy)*.5;
1205 ngvx = gvx; ngvy = gvy; ngvo = gvo+(ngvx+ngvy)*.5;
1206 }
1207 else
1208 {
1209 ox = py[1]-py[2]; oy = py[2]-py[0]; oz = py[0]-py[1];
1210 r = 1.0 / (ox*px[0] + oy*px[1] + oz*px[2]);
1211 ngdx = (ox*dd[0] + oy*dd[1] + oz*dd[2])*r;
1212 ngux = (ox*uu[0] + oy*uu[1] + oz*uu[2])*r;
1213 ngvx = (ox*vv[0] + oy*vv[1] + oz*vv[2])*r;
1214 ox = px[2]-px[1]; oy = px[0]-px[2]; oz = px[1]-px[0];
1215 ngdy = (ox*dd[0] + oy*dd[1] + oz*dd[2])*r;
1216 nguy = (ox*uu[0] + oy*uu[1] + oz*uu[2])*r;
1217 ngvy = (ox*vv[0] + oy*vv[1] + oz*vv[2])*r;
1218 ox = px[0]-.5; oy = py[0]-.5; //.5 centers texture nicely
1219 ngdo = dd[0] - ox*ngdx - oy*ngdy;
1220 nguo = uu[0] - ox*ngux - oy*nguy;
1221 ngvo = vv[0] - ox*ngvx - oy*ngvy;
1222 }
1223
1224 ngux *= hackscx; nguy *= hackscx; nguo *= hackscx;
1225 ngvx *= hackscy; ngvy *= hackscy; ngvo *= hackscy;
1226 uoffs = ((double)(xx-tsizx)*.5);
1227 ngux -= ngdx*uoffs;
1228 nguy -= ngdy*uoffs;
1229 nguo -= ngdo*uoffs;
1230
1231 //Find min&max u coordinates (du0...du1)
1232 for(i=0;i<n;i++)
1233 {
1234 ox = px[i]; oy = py[i];
1235 f = (ox*ngux + oy*nguy + nguo) / (ox*ngdx + oy*ngdy + ngdo);
1236 if (!i) { du0 = du1 = f; continue; }
1237 if (f < du0) du0 = f;
1238 else if (f > du1) du1 = f;
1239 }
1240
1241 f = 1.0/(double)tsizx;
1242 ix0 = (int)floor(du0*f);
1243 ix1 = (int)floor(du1*f);
1244 for(;ix0<=ix1;ix0++)
1245 {
1246 du0 = (double)((ix0 )*tsizx); // + uoffs;
1247 du1 = (double)((ix0+1)*tsizx); // + uoffs;
1248
1249 i = 0; nn = 0;
1250 duj = (px[i]*ngux + py[i]*nguy + nguo) / (px[i]*ngdx + py[i]*ngdy + ngdo);
1251 do
1252 {
1253 j = i+1; if (j == n) j = 0;
1254
1255 dui = duj; duj = (px[j]*ngux + py[j]*nguy + nguo) / (px[j]*ngdx + py[j]*ngdy + ngdo);
1256
1257 if ((du0 <= dui) && (dui <= du1)) { uu[nn] = px[i]; vv[nn] = py[i]; nn++; }
1258 if (duj <= dui)
1259 {
1260 if ((du1 < duj) != (du1 < dui))
1261 {
1262 //ox*(ngux-ngdx*du1) + oy*(nguy-ngdy*du1) + (nguo-ngdo*du1) = 0
1263 //(px[j]-px[i])*f + px[i] = ox
1264 //(py[j]-py[i])*f + py[i] = oy
1265
1266 ///Solve for f
1267 //((px[j]-px[i])*f + px[i])*(ngux-ngdx*du1) +
1268 //((py[j]-py[i])*f + py[i])*(nguy-ngdy*du1) + (nguo-ngdo*du1) = 0
1269
1270 f = -( px[i] *(ngux-ngdx*du1) + py[i] *(nguy-ngdy*du1) + (nguo-ngdo*du1)) /
1271 ((px[j]-px[i])*(ngux-ngdx*du1) + (py[j]-py[i])*(nguy-ngdy*du1));
1272 uu[nn] = (px[j]-px[i])*f + px[i];
1273 vv[nn] = (py[j]-py[i])*f + py[i]; nn++;
1274 }
1275 if ((du0 < duj) != (du0 < dui))
1276 {
1277 f = -( px[i] *(ngux-ngdx*du0) + py[i] *(nguy-ngdy*du0) + (nguo-ngdo*du0)) /
1278 ((px[j]-px[i])*(ngux-ngdx*du0) + (py[j]-py[i])*(nguy-ngdy*du0));
1279 uu[nn] = (px[j]-px[i])*f + px[i];
1280 vv[nn] = (py[j]-py[i])*f + py[i]; nn++;
1281 }
1282 }
1283 else
1284 {
1285 if ((du0 < duj) != (du0 < dui))
1286 {
1287 f = -( px[i] *(ngux-ngdx*du0) + py[i] *(nguy-ngdy*du0) + (nguo-ngdo*du0)) /
1288 ((px[j]-px[i])*(ngux-ngdx*du0) + (py[j]-py[i])*(nguy-ngdy*du0));
1289 uu[nn] = (px[j]-px[i])*f + px[i];
1290 vv[nn] = (py[j]-py[i])*f + py[i]; nn++;
1291 }
1292 if ((du1 < duj) != (du1 < dui))
1293 {
1294 f = -( px[i] *(ngux-ngdx*du1) + py[i] *(nguy-ngdy*du1) + (nguo-ngdo*du1)) /
1295 ((px[j]-px[i])*(ngux-ngdx*du1) + (py[j]-py[i])*(nguy-ngdy*du1));
1296 uu[nn] = (px[j]-px[i])*f + px[i];
1297 vv[nn] = (py[j]-py[i])*f + py[i]; nn++;
1298 }
1299 }
1300 i = j;
1301 } while (i);
1302 if (nn < 3) continue;
1303
1304 for(i=0;i<nn;i++)
1305 {
1306 ox = uu[i]; oy = vv[i];
1307 dp = ox*ngdx + oy*ngdy + ngdo;
1308 up = ox*ngux + oy*nguy + nguo;
1309 vp = ox*ngvx + oy*ngvy + ngvo;
1310 r = 1.0/dp;
1311
1312 vboitem[i].v.x = (ox-ghalfx)*r*grhalfxdown10x;
1313 vboitem[i].v.y = (ghoriz-oy)*r*grhalfxdown10;
1314 vboitem[i].v.z = r*(1.0/1024.0);
1315 vboitem[i].t.s = (up*r-du0+uoffs)*ox2;
1316 vboitem[i].t.t = vp*r*oy2;
1317 }
1318 draw.indexcount = nn;
1319 draw.elementcount = nn;
1320
1321 glfunc.glDepthMask(GL_TRUE);
1322 polymost_drawpoly_glcall(GL_TRIANGLE_FAN, &draw);
1323 }
1324 }
1325 else if (n > 0)
1326 {
1327 ox2 *= hackscx; oy2 *= hackscy;
1328
1329 for(i=0;i<n;i++)
1330 {
1331 r = 1.0/dd[i];
1332
1333 vboitem[i].v.x = (px[i]-ghalfx)*r*grhalfxdown10x;
1334 vboitem[i].v.y = (ghoriz-py[i])*r*grhalfxdown10;
1335 vboitem[i].v.z = r*(1.0/1024.0);
1336 vboitem[i].t.s = uu[i]*r*ox2;
1337 vboitem[i].t.t = vv[i]*r*oy2;
1338 }
1339 draw.indexcount = n;
1340 draw.elementcount = n;
1341
1342 glfunc.glDepthMask(GL_TRUE);
1343 polymost_drawpoly_glcall(GL_TRIANGLE_FAN, &draw);
1344 }
1345
1346 return;
1347 }
1348 #endif
1349
1350 if (rendmode == 2)
1351 {
1352 #if (USEZBUFFER != 0)
1353 if ((!zbufmem) || (zbufbpl != bytesperline) || (zbufysiz != ydim))
1354 {
1355 zbufbpl = bytesperline;
1356 zbufysiz = ydim;
1357 zbufmem = (intptr_t)realloc((void *)zbufmem,zbufbpl*zbufysiz*4);
1358 }
1359 zbufoff = (int *)(zbufmem-(frameplace<<2));
1360 #endif
1361 if ((!transluc)) method = (method & ~(METH_MASKED | METH_TRANS)) + METH_MASKED; //In case translucent table doesn't exist
1362
1363 if (!dorot)
1364 {
1365 ngdx = gdx; ngdy = gdy; ngdo = gdo+(ngdx+ngdy)*.5;
1366 ngux = gux; nguy = guy; nguo = guo+(ngux+nguy)*.5;
1367 ngvx = gvx; ngvy = gvy; ngvo = gvo+(ngvx+ngvy)*.5;
1368 }
1369 else
1370 {
1371 //General equations:
1372 //dd[i] = (px[i]*gdx + py[i]*gdy + gdo)
1373 //uu[i] = (px[i]*gux + py[i]*guy + guo)/dd[i]
1374 //vv[i] = (px[i]*gvx + py[i]*gvy + gvo)/dd[i]
1375 //
1376 //px[0]*gdx + py[0]*gdy + 1*gdo = dd[0]
1377 //px[1]*gdx + py[1]*gdy + 1*gdo = dd[1]
1378 //px[2]*gdx + py[2]*gdy + 1*gdo = dd[2]
1379 //
1380 //px[0]*gux + py[0]*guy + 1*guo = uu[0]*dd[0] (uu[i] premultiplied by dd[i] above)
1381 //px[1]*gux + py[1]*guy + 1*guo = uu[1]*dd[1]
1382 //px[2]*gux + py[2]*guy + 1*guo = uu[2]*dd[2]
1383 //
1384 //px[0]*gvx + py[0]*gvy + 1*gvo = vv[0]*dd[0] (vv[i] premultiplied by dd[i] above)
1385 //px[1]*gvx + py[1]*gvy + 1*gvo = vv[1]*dd[1]
1386 //px[2]*gvx + py[2]*gvy + 1*gvo = vv[2]*dd[2]
1387 ox = py[1]-py[2]; oy = py[2]-py[0]; oz = py[0]-py[1];
1388 r = 1.0 / (ox*px[0] + oy*px[1] + oz*px[2]);
1389 ngdx = (ox*dd[0] + oy*dd[1] + oz*dd[2])*r;
1390 ngux = (ox*uu[0] + oy*uu[1] + oz*uu[2])*r;
1391 ngvx = (ox*vv[0] + oy*vv[1] + oz*vv[2])*r;
1392 ox = px[2]-px[1]; oy = px[0]-px[2]; oz = px[1]-px[0];
1393 ngdy = (ox*dd[0] + oy*dd[1] + oz*dd[2])*r;
1394 nguy = (ox*uu[0] + oy*uu[1] + oz*uu[2])*r;
1395 ngvy = (ox*vv[0] + oy*vv[1] + oz*vv[2])*r;
1396 ox = px[0]-.5; oy = py[0]-.5; //.5 centers texture nicely
1397 ngdo = dd[0] - ox*ngdx - oy*ngdy;
1398 nguo = uu[0] - ox*ngux - oy*nguy;
1399 ngvo = vv[0] - ox*ngvx - oy*ngvy;
1400 }
1401 palptr = &palookup[globalpal][min(max(globalshade,0),numpalookups-1)<<8]; //<-need to make shade not static!
1402
1403 tsizxm1 = tsizx-1; xmodnice = (!(tsizxm1&tsizx));
1404 tsizym1 = tsizy-1; ymulnice = (!(tsizym1&tsizy));
1405 if ((method & METH_CLAMPED) && (!xmodnice)) //Sprites don't need a mod on texture coordinates
1406 { xmodnice = 1; for(tsizxm1=1;tsizxm1<tsizx;tsizxm1=(tsizxm1<<1)+1); }
1407 if (!ymulnice) { for(tsizym1=1;tsizym1+1<tsizy;tsizym1=(tsizym1<<1)+1); }
1408 ltsizy = (picsiz[globalpicnum]>>4);
1409 }
1410 else
1411 {
1412 dacol = palookup[0][(int)(*(unsigned char *)(waloff[globalpicnum]))+(min(max(globalshade,0),numpalookups-1)<<8)];
1413 }
1414
1415 if (grhalfxdown10x < 0) //Hack for mirrors
1416 {
1417 for(i=((n-1)>>1);i>=0;i--)
1418 {
1419 r = px[i]; px[i] = ((double)xdimen)-px[n-1-i]; px[n-1-i] = ((double)xdimen)-r;
1420 r = py[i]; py[i] = py[n-1-i]; py[n-1-i] = r;
1421 }
1422 ngdo += ((double)xdimen)*ngdx; ngdx = -ngdx;
1423 nguo += ((double)xdimen)*ngux; ngux = -ngux;
1424 ngvo += ((double)xdimen)*ngvx; ngvx = -ngvx;
1425 }
1426
1427 ngdx2 = ngdx*(1<<LINTERPSIZ);
1428 ngux2 = ngux*(1<<LINTERPSIZ);
1429 ngvx2 = ngvx*(1<<LINTERPSIZ);
1430
1431 mini = (py[0] >= py[1]); maxi = 1-mini;
1432 for(z=2;z<n;z++)
1433 {
1434 if (py[z] < py[mini]) mini = z;
1435 if (py[z] > py[maxi]) maxi = z;
1436 }
1437
1438 i = maxi; dtol(py[i],&yy); if (yy > ydimen) yy = ydimen;
1439 do
1440 {
1441 j = i+1; if (j == n) j = 0;
1442 dtol(py[j],&y); if (y < 0) y = 0;
1443 if (y < yy)
1444 {
1445 f = (px[j]-px[i])/(py[j]-py[i]); dtol(f*16384.0,&xi);
1446 dtol((((double)yy-.5-py[j])*f + px[j])*16384.0+8192.0,&x);
1447 for(;yy>y;yy--,x-=xi) lastx[yy-1] = (x>>14);
1448 }
1449 i = j;
1450 } while (i != mini);
1451 do
1452 {
1453 j = i+1; if (j == n) j = 0;
1454 dtol(py[j],&yy); if (yy > ydimen) yy = ydimen;
1455 if (y < yy)
1456 {
1457 f = (px[j]-px[i])/(py[j]-py[i]); dtol(f*16384.0,&xi);
1458 dtol((((double)y+.5-py[j])*f + px[j])*16384.0+8192.0,&x);
1459 for(;y<yy;y++,x+=xi)
1460 {
1461 ix0 = lastx[y]; if (ix0 < 0) ix0 = 0;
1462 ix1 = (x>>14); if (ix1 > xdimen) ix1 = xdimen;
1463 if (ix0 < ix1)
1464 {
1465 if (rendmode == 1)
1466 memset((void *)(ylookup[y]+ix0+frameoffset),dacol,ix1-ix0);
1467 else
1468 {
1469 vidp = (unsigned char *)(ylookup[y]+frameoffset+ix0);
1470 dp = ngdx*(double)ix0 + ngdy*(double)y + ngdo;
1471 up = ngux*(double)ix0 + nguy*(double)y + nguo;
1472 vp = ngvx*(double)ix0 + ngvy*(double)y + ngvo;
1473 rdp = 65536.0/dp; dp += ngdx2;
1474 dtol( rdp,&d0);
1475 dtol(up*rdp,&u0); up += ngux2;
1476 dtol(vp*rdp,&v0); vp += ngvx2;
1477 rdp = 65536.0/dp;
1478
1479 switch (method & (METH_MASKED | METH_TRANS))
1480 {
1481 case METH_SOLID:
1482 if (xmodnice&ymulnice) //both u&v texture sizes are powers of 2 :)
1483 {
1484 for(xx=ix0;xx<ix1;xx+=(1<<LINTERPSIZ))
1485 {
1486 dtol( rdp,&d1); dp += ngdx2; d1 = ((d1-d0)>>LINTERPSIZ);
1487 dtol(up*rdp,&u1); up += ngux2; u1 = ((u1-u0)>>LINTERPSIZ);
1488 dtol(vp*rdp,&v1); vp += ngvx2; v1 = ((v1-v0)>>LINTERPSIZ);
1489 rdp = 65536.0/dp; vide = &vidp[min(ix1-xx,1<<LINTERPSIZ)];
1490 while (vidp < vide)
1491 {
1492 #if (DEPTHDEBUG == 0)
1493 #if (USEZBUFFER != 0)
1494 zbufoff[(intptr_t)vidp] = d0+16384; //+ hack so wall&floor sprites don't disappear
1495 #endif
1496 vidp[0] = palptr[walptr[(((u0>>16)&tsizxm1)<<ltsizy) + ((v0>>16)&tsizym1)]]; //+((d0>>13)&0x3f00)];
1497 #else
1498 vidp[0] = ((d0>>16)&255);
1499 #endif
1500 d0 += d1; u0 += u1; v0 += v1; vidp++;
1501 }
1502 }
1503 }
1504 else
1505 {
1506 for(xx=ix0;xx<ix1;xx+=(1<<LINTERPSIZ))
1507 {
1508 dtol( rdp,&d1); dp += ngdx2; d1 = ((d1-d0)>>LINTERPSIZ);
1509 dtol(up*rdp,&u1); up += ngux2; u1 = ((u1-u0)>>LINTERPSIZ);
1510 dtol(vp*rdp,&v1); vp += ngvx2; v1 = ((v1-v0)>>LINTERPSIZ);
1511 rdp = 65536.0/dp; vide = &vidp[min(ix1-xx,1<<LINTERPSIZ)];
1512 while (vidp < vide)
1513 {
1514 #if (DEPTHDEBUG == 0)
1515 #if (USEZBUFFER != 0)
1516 zbufoff[(intptr_t)vidp] = d0;
1517 #endif
1518 vidp[0] = palptr[walptr[imod(u0>>16,tsizx)*tsizy + ((v0>>16)&tsizym1)]]; //+((d0>>13)&0x3f00)];
1519 #else
1520 vidp[0] = ((d0>>16)&255);
1521 #endif
1522 d0 += d1; u0 += u1; v0 += v1; vidp++;
1523 }
1524 }
1525 }
1526 break;
1527 case METH_MASKED:
1528 if (xmodnice) //both u&v texture sizes are powers of 2 :)
1529 {
1530 for(xx=ix0;xx<ix1;xx+=(1<<LINTERPSIZ))
1531 {
1532 dtol( rdp,&d1); dp += ngdx2; d1 = ((d1-d0)>>LINTERPSIZ);
1533 dtol(up*rdp,&u1); up += ngux2; u1 = ((u1-u0)>>LINTERPSIZ);
1534 dtol(vp*rdp,&v1); vp += ngvx2; v1 = ((v1-v0)>>LINTERPSIZ);
1535 rdp = 65536.0/dp; vide = &vidp[min(ix1-xx,1<<LINTERPSIZ)];
1536 while (vidp < vide)
1537 {
1538 dacol = walptr[(((u0>>16)&tsizxm1)*tsizy) + ((v0>>16)&tsizym1)];
1539 #if (DEPTHDEBUG == 0)
1540 #if (USEZBUFFER != 0)
1541 if ((dacol != 255) && (d0 <= zbufoff[(intptr_t)vidp]))
1542 {
1543 zbufoff[(intptr_t)vidp] = d0;
1544 vidp[0] = palptr[((int)dacol)]; //+((d0>>13)&0x3f00)];
1545 }
1546 #else
1547 if (dacol != 255) vidp[0] = palptr[((int)dacol)]; //+((d0>>13)&0x3f00)];
1548 #endif
1549 #else
1550 if ((dacol != 255) && (vidp[0] > (d0>>16))) vidp[0] = ((d0>>16)&255);
1551 #endif
1552 d0 += d1; u0 += u1; v0 += v1; vidp++;
1553 }
1554 }
1555 }
1556 else
1557 {
1558 for(xx=ix0;xx<ix1;xx+=(1<<LINTERPSIZ))
1559 {
1560 dtol( rdp,&d1); dp += ngdx2; d1 = ((d1-d0)>>LINTERPSIZ);
1561 dtol(up*rdp,&u1); up += ngux2; u1 = ((u1-u0)>>LINTERPSIZ);
1562 dtol(vp*rdp,&v1); vp += ngvx2; v1 = ((v1-v0)>>LINTERPSIZ);
1563 rdp = 65536.0/dp; vide = &vidp[min(ix1-xx,1<<LINTERPSIZ)];
1564 while (vidp < vide)
1565 {
1566 dacol = walptr[imod(u0>>16,tsizx)*tsizy + ((v0>>16)&tsizym1)];
1567 #if (DEPTHDEBUG == 0)
1568 #if (USEZBUFFER != 0)
1569 if ((dacol != 255) && (d0 <= zbufoff[(intptr_t)vidp]))
1570 {
1571 zbufoff[(intptr_t)vidp] = d0;
1572 vidp[0] = palptr[((int)dacol)]; //+((d0>>13)&0x3f00)];
1573 }
1574 #else
1575 if (dacol != 255) vidp[0] = palptr[((int)dacol)]; //+((d0>>13)&0x3f00)];
1576 #endif
1577 #else
1578 if ((dacol != 255) && (vidp[0] > (d0>>16))) vidp[0] = ((d0>>16)&255);
1579 #endif
1580 d0 += d1; u0 += u1; v0 += v1; vidp++;
1581 }
1582 }
1583 }
1584 break;
1585 case METH_TRANS: //Transluscence #1
1586 for(xx=ix0;xx<ix1;xx+=(1<<LINTERPSIZ))
1587 {
1588 dtol( rdp,&d1); dp += ngdx2; d1 = ((d1-d0)>>LINTERPSIZ);
1589 dtol(up*rdp,&u1); up += ngux2; u1 = ((u1-u0)>>LINTERPSIZ);
1590 dtol(vp*rdp,&v1); vp += ngvx2; v1 = ((v1-v0)>>LINTERPSIZ);
1591 rdp = 65536.0/dp; vide = &vidp[min(ix1-xx,1<<LINTERPSIZ)];
1592 while (vidp < vide)
1593 {
1594 dacol = walptr[imod(u0>>16,tsizx)*tsizy + ((v0>>16)&tsizym1)];
1595 //dacol = walptr[(((u0>>16)&tsizxm1)<<ltsizy) + ((v0>>16)&tsizym1)];
1596 #if (DEPTHDEBUG == 0)
1597 #if (USEZBUFFER != 0)
1598 if ((dacol != 255) && (d0 <= zbufoff[(intptr_t)vidp]))
1599 {
1600 zbufoff[(intptr_t)vidp] = d0;
1601 vidp[0] = transluc[(((int)vidp[0])<<8)+((int)palptr[((int)dacol)])]; //+((d0>>13)&0x3f00)])];
1602 }
1603 #else
1604 if (dacol != 255)
1605 vidp[0] = transluc[(((int)vidp[0])<<8)+((int)palptr[((int)dacol)])]; //+((d0>>13)&0x3f00)])];
1606 #endif
1607 #else
1608 if ((dacol != 255) && (vidp[0] > (d0>>16))) vidp[0] = ((d0>>16)&255);
1609 #endif
1610 d0 += d1; u0 += u1; v0 += v1; vidp++;
1611 }
1612 }
1613 break;
1614 case METH_INTRANS: //Transluscence #2
1615 for(xx=ix0;xx<ix1;xx+=(1<<LINTERPSIZ))
1616 {
1617 dtol( rdp,&d1); dp += ngdx2; d1 = ((d1-d0)>>LINTERPSIZ);
1618 dtol(up*rdp,&u1); up += ngux2; u1 = ((u1-u0)>>LINTERPSIZ);
1619 dtol(vp*rdp,&v1); vp += ngvx2; v1 = ((v1-v0)>>LINTERPSIZ);
1620 rdp = 65536.0/dp; vide = &vidp[min(ix1-xx,1<<LINTERPSIZ)];
1621 while (vidp < vide)
1622 {
1623 dacol = walptr[imod(u0>>16,tsizx)*tsizy + ((v0>>16)&tsizym1)];
1624 //dacol = walptr[(((u0>>16)&tsizxm1)<<ltsizy) + ((v0>>16)&tsizym1)];
1625 #if (DEPTHDEBUG == 0)
1626 #if (USEZBUFFER != 0)
1627 if ((dacol != 255) && (d0 <= zbufoff[(intptr_t)vidp]))
1628 {
1629 zbufoff[(intptr_t)vidp] = d0;
1630 vidp[0] = transluc[((int)vidp[0])+(((int)palptr[((int)dacol)/*+((d0>>13)&0x3f00)*/])<<8)];
1631 }
1632 #else
1633 if (dacol != 255)
1634 vidp[0] = transluc[((int)vidp[0])+(((int)palptr[((int)dacol)/*+((d0>>13)&0x3f00)*/])<<8)];
1635 #endif
1636 #else
1637 if ((dacol != 255) && (vidp[0] > (d0>>16))) vidp[0] = ((d0>>16)&255);
1638 #endif
1639 d0 += d1; u0 += u1; v0 += v1; vidp++;
1640 }
1641 }
1642 break;
1643 }
1644 }
1645 }
1646 }
1647 }
1648 i = j;
1649 } while (i != maxi);
1650
1651 if (rendmode == 1)
1652 {
1653 if (method & (METH_MASKED | METH_TRANS)) //Only draw border around sprites/maskwalls
1654 {
1655 for(i=0,j=n-1;i<n;j=i,i++) drawline2d(px[i],py[i],px[j],py[j],31); //hopefully color index 31 is white
1656 }
1657
1658 //ox = 0; oy = 0;
1659 //for(i=0;i<n;i++) { ox += px[i]; oy += py[i]; }
1660 //ox /= (double)n; oy /= (double)n;
1661 //for(i=0,j=n-1;i<n;j=i,i++) drawline2d(px[i]+(ox-px[i])*.125,py[i]+(oy-py[i])*.125,px[j]+(ox-px[j])*.125,py[j]+(oy-py[j])*.125,31);
1662 }
1663 }
1664
1665 /*Init viewport boundary (must be 4 point convex loop):
1666 // (px[0],py[0]).----.(px[1],py[1])
1667 // / \
1668 // / \
1669 // (px[3],py[3]).--------------.(px[2],py[2])
1670 */
initmosts(double * px,double * py,int n)1671 static void initmosts (double *px, double *py, int n)
1672 {
1673 int i, j, k, imin;
1674
1675 vcnt = 1; //0 is dummy solid node
1676
1677 if (n < 3) return;
1678 imin = (px[1] < px[0]);
1679 for(i=n-1;i>=2;i--) if (px[i] < px[imin]) imin = i;
1680
1681
1682 vsp[vcnt].x = px[imin];
1683 vsp[vcnt].cy[0] = vsp[vcnt].fy[0] = py[imin];
1684 vcnt++;
1685 i = imin+1; if (i >= n) i = 0;
1686 j = imin-1; if (j < 0) j = n-1;
1687 do
1688 {
1689 if (px[i] < px[j])
1690 {
1691 if ((vcnt > 1) && (px[i] <= vsp[vcnt-1].x)) vcnt--;
1692 vsp[vcnt].x = px[i];
1693 vsp[vcnt].cy[0] = py[i];
1694 k = j+1; if (k >= n) k = 0;
1695 //(px[k],py[k])
1696 //(px[i],?)
1697 //(px[j],py[j])
1698 vsp[vcnt].fy[0] = (px[i]-px[k])*(py[j]-py[k])/(px[j]-px[k]) + py[k];
1699 vcnt++;
1700 i++; if (i >= n) i = 0;
1701 }
1702 else if (px[j] < px[i])
1703 {
1704 if ((vcnt > 1) && (px[j] <= vsp[vcnt-1].x)) vcnt--;
1705 vsp[vcnt].x = px[j];
1706 vsp[vcnt].fy[0] = py[j];
1707 k = i-1; if (k < 0) k = n-1;
1708 //(px[k],py[k])
1709 //(px[j],?)
1710 //(px[i],py[i])
1711 vsp[vcnt].cy[0] = (px[j]-px[k])*(py[i]-py[k])/(px[i]-px[k]) + py[k];
1712 vcnt++;
1713 j--; if (j < 0) j = n-1;
1714 }
1715 else
1716 {
1717 if ((vcnt > 1) && (px[i] <= vsp[vcnt-1].x)) vcnt--;
1718 vsp[vcnt].x = px[i];
1719 vsp[vcnt].cy[0] = py[i];
1720 vsp[vcnt].fy[0] = py[j];
1721 vcnt++;
1722 i++; if (i >= n) i = 0; if (i == j) break;
1723 j--; if (j < 0) j = n-1;
1724 }
1725 } while (i != j);
1726 if (px[i] > vsp[vcnt-1].x)
1727 {
1728 vsp[vcnt].x = px[i];
1729 vsp[vcnt].cy[0] = vsp[vcnt].fy[0] = py[i];
1730 vcnt++;
1731 }
1732
1733
1734 for(i=0;i<vcnt;i++)
1735 {
1736 vsp[i].cy[1] = vsp[i+1].cy[0]; vsp[i].ctag = i;
1737 vsp[i].fy[1] = vsp[i+1].fy[0]; vsp[i].ftag = i;
1738 vsp[i].n = i+1; vsp[i].p = i-1;
1739 }
1740 vsp[vcnt-1].n = 0; vsp[0].p = vcnt-1;
1741 gtag = vcnt;
1742
1743 //VSPMAX-1 is dummy empty node
1744 for(i=vcnt;i<VSPMAX;i++) { vsp[i].n = i+1; vsp[i].p = i-1; }
1745 vsp[VSPMAX-1].n = vcnt; vsp[vcnt].p = VSPMAX-1;
1746 }
1747
vsdel(int i)1748 static void vsdel (int i)
1749 {
1750 int pi, ni;
1751 //Delete i
1752 pi = vsp[i].p;
1753 ni = vsp[i].n;
1754 vsp[ni].p = pi;
1755 vsp[pi].n = ni;
1756
1757 //Add i to empty list
1758 vsp[i].n = vsp[VSPMAX-1].n;
1759 vsp[i].p = VSPMAX-1;
1760 vsp[vsp[VSPMAX-1].n].p = i;
1761 vsp[VSPMAX-1].n = i;
1762 }
1763
vsinsaft(int i)1764 static int vsinsaft (int i)
1765 {
1766 int r;
1767 //i = next element from empty list
1768 r = vsp[VSPMAX-1].n;
1769 vsp[vsp[r].n].p = VSPMAX-1;
1770 vsp[VSPMAX-1].n = vsp[r].n;
1771
1772 vsp[r] = vsp[i]; //copy i to r
1773
1774 //insert r after i
1775 vsp[r].p = i; vsp[r].n = vsp[i].n;
1776 vsp[vsp[i].n].p = r; vsp[i].n = r;
1777
1778 return(r);
1779 }
1780
testvisiblemost(float x0,float x1)1781 static int testvisiblemost (float x0, float x1)
1782 {
1783 int i, newi;
1784
1785 for(i=vsp[0].n;i;i=newi)
1786 {
1787 newi = vsp[i].n;
1788 if ((x0 < vsp[newi].x) && (vsp[i].x < x1) && (vsp[i].ctag >= 0)) return(1);
1789 }
1790 return(0);
1791 }
1792
domost(float x0,float y0,float x1,float y1,int polymethod)1793 static void domost (float x0, float y0, float x1, float y1, int polymethod)
1794 {
1795 double dpx[4], dpy[4];
1796 float d, f, n, t, slop, dx, dx0, dx1, nx, nx0, ny0, nx1, ny1;
1797 float spx[4], spy[4], cy[2], cv[2];
1798 int i, j, k, z, ni, vcnt = 0, scnt, newi, dir, spt[4];
1799
1800 #ifdef DEBUGGINGAIDS
1801 polymostcallcounts.domost++;
1802 #endif
1803 polymethod |= METH_LAYERS;
1804
1805 if (x0 < x1)
1806 {
1807 dir = 1; //clip dmost (floor)
1808 y0 -= .01; y1 -= .01;
1809 }
1810 else
1811 {
1812 if (x0 == x1) return;
1813 f = x0; x0 = x1; x1 = f;
1814 f = y0; y0 = y1; y1 = f;
1815 dir = 0; //clip umost (ceiling)
1816 //y0 += .01; y1 += .01; //necessary?
1817 }
1818
1819 slop = (y1-y0)/(x1-x0);
1820 for(i=vsp[0].n;i;i=newi)
1821 {
1822 newi = vsp[i].n; nx0 = vsp[i].x; nx1 = vsp[newi].x;
1823 if ((x0 >= nx1) || (nx0 >= x1) || (vsp[i].ctag <= 0)) continue;
1824 dx = nx1-nx0;
1825 cy[0] = vsp[i].cy[0]; cv[0] = vsp[i].cy[1]-cy[0];
1826 cy[1] = vsp[i].fy[0]; cv[1] = vsp[i].fy[1]-cy[1];
1827
1828 scnt = 0;
1829
1830 //Test if left edge requires split (x0,y0) (nx0,cy(0)),<dx,cv(0)>
1831 if ((x0 > nx0) && (x0 < nx1))
1832 {
1833 t = (x0-nx0)*cv[dir] - (y0-cy[dir])*dx;
1834 if (((!dir) && (t < 0)) || ((dir) && (t > 0)))
1835 { spx[scnt] = x0; spy[scnt] = y0; spt[scnt] = -1; scnt++; }
1836 }
1837
1838 //Test for intersection on umost (j == 0) and dmost (j == 1)
1839 for(j=0;j<2;j++)
1840 {
1841 d = (y0-y1)*dx - (x0-x1)*cv[j];
1842 n = (y0-cy[j])*dx - (x0-nx0)*cv[j];
1843 if ((fabs(n) <= fabs(d)) && (d*n >= 0) && (d != 0))
1844 {
1845 t = n/d; nx = (x1-x0)*t + x0;
1846 if ((nx > nx0) && (nx < nx1))
1847 {
1848 spx[scnt] = nx; spy[scnt] = (y1-y0)*t + y0;
1849 spt[scnt] = j; scnt++;
1850 }
1851 }
1852 }
1853
1854 //Nice hack to avoid full sort later :)
1855 if ((scnt >= 2) && (spx[scnt-1] < spx[scnt-2]))
1856 {
1857 f = spx[scnt-1]; spx[scnt-1] = spx[scnt-2]; spx[scnt-2] = f;
1858 f = spy[scnt-1]; spy[scnt-1] = spy[scnt-2]; spy[scnt-2] = f;
1859 j = spt[scnt-1]; spt[scnt-1] = spt[scnt-2]; spt[scnt-2] = j;
1860 }
1861
1862 //Test if right edge requires split
1863 if ((x1 > nx0) && (x1 < nx1))
1864 {
1865 t = (x1-nx0)*cv[dir] - (y1-cy[dir])*dx;
1866 if (((!dir) && (t < 0)) || ((dir) && (t > 0)))
1867 { spx[scnt] = x1; spy[scnt] = y1; spt[scnt] = -1; scnt++; }
1868 }
1869
1870 vsp[i].tag = vsp[newi].tag = -1;
1871 for(z=0;z<=scnt;z++,i=vcnt)
1872 {
1873 if (z < scnt)
1874 {
1875 vcnt = vsinsaft(i);
1876 t = (spx[z]-nx0)/dx;
1877 vsp[i].cy[1] = t*cv[0] + cy[0];
1878 vsp[i].fy[1] = t*cv[1] + cy[1];
1879 vsp[vcnt].x = spx[z];
1880 vsp[vcnt].cy[0] = vsp[i].cy[1];
1881 vsp[vcnt].fy[0] = vsp[i].fy[1];
1882 vsp[vcnt].tag = spt[z];
1883 }
1884
1885 ni = vsp[i].n; if (!ni) continue; //this 'if' fixes many bugs!
1886 dx0 = vsp[i].x; if (x0 > dx0) continue;
1887 dx1 = vsp[ni].x; if (x1 < dx1) continue;
1888 ny0 = (dx0-x0)*slop + y0;
1889 ny1 = (dx1-x0)*slop + y0;
1890
1891 // dx0 dx1
1892 // ~ ~
1893 //----------------------------
1894 // t0+=0 t1+=0
1895 // vsp[i].cy[0] vsp[i].cy[1]
1896 //============================
1897 // t0+=1 t1+=3
1898 //============================
1899 // vsp[i].fy[0] vsp[i].fy[1]
1900 // t0+=2 t1+=6
1901 //
1902 // ny0 ? ny1 ?
1903
1904 k = 1+3;
1905 if ((vsp[i].tag == 0) || (ny0 <= vsp[i].cy[0]+.01)) k--;
1906 if ((vsp[i].tag == 1) || (ny0 >= vsp[i].fy[0]-.01)) k++;
1907 if ((vsp[ni].tag == 0) || (ny1 <= vsp[i].cy[1]+.01)) k -= 3;
1908 if ((vsp[ni].tag == 1) || (ny1 >= vsp[i].fy[1]-.01)) k += 3;
1909
1910 if (!dir)
1911 {
1912 switch(k)
1913 {
1914 case 1: case 2:
1915 dpx[0] = dx0; dpy[0] = vsp[i].cy[0];
1916 dpx[1] = dx1; dpy[1] = vsp[i].cy[1];
1917 dpx[2] = dx0; dpy[2] = ny0; drawpoly(dpx,dpy,3,polymethod);
1918 vsp[i].cy[0] = ny0; vsp[i].ctag = gtag; break;
1919 case 3: case 6:
1920 dpx[0] = dx0; dpy[0] = vsp[i].cy[0];
1921 dpx[1] = dx1; dpy[1] = vsp[i].cy[1];
1922 dpx[2] = dx1; dpy[2] = ny1; drawpoly(dpx,dpy,3,polymethod);
1923 vsp[i].cy[1] = ny1; vsp[i].ctag = gtag; break;
1924 case 4: case 5: case 7:
1925 dpx[0] = dx0; dpy[0] = vsp[i].cy[0];
1926 dpx[1] = dx1; dpy[1] = vsp[i].cy[1];
1927 dpx[2] = dx1; dpy[2] = ny1;
1928 dpx[3] = dx0; dpy[3] = ny0; drawpoly(dpx,dpy,4,polymethod);
1929 vsp[i].cy[0] = ny0; vsp[i].cy[1] = ny1; vsp[i].ctag = gtag; break;
1930 case 8:
1931 dpx[0] = dx0; dpy[0] = vsp[i].cy[0];
1932 dpx[1] = dx1; dpy[1] = vsp[i].cy[1];
1933 dpx[2] = dx1; dpy[2] = vsp[i].fy[1];
1934 dpx[3] = dx0; dpy[3] = vsp[i].fy[0]; drawpoly(dpx,dpy,4,polymethod);
1935 vsp[i].ctag = vsp[i].ftag = -1; break;
1936 default: break;
1937 }
1938 }
1939 else
1940 {
1941 switch(k)
1942 {
1943 case 7: case 6:
1944 dpx[0] = dx0; dpy[0] = ny0;
1945 dpx[1] = dx1; dpy[1] = vsp[i].fy[1];
1946 dpx[2] = dx0; dpy[2] = vsp[i].fy[0]; drawpoly(dpx,dpy,3,polymethod);
1947 vsp[i].fy[0] = ny0; vsp[i].ftag = gtag; break;
1948 case 5: case 2:
1949 dpx[0] = dx0; dpy[0] = vsp[i].fy[0];
1950 dpx[1] = dx1; dpy[1] = ny1;
1951 dpx[2] = dx1; dpy[2] = vsp[i].fy[1]; drawpoly(dpx,dpy,3,polymethod);
1952 vsp[i].fy[1] = ny1; vsp[i].ftag = gtag; break;
1953 case 4: case 3: case 1:
1954 dpx[0] = dx0; dpy[0] = ny0;
1955 dpx[1] = dx1; dpy[1] = ny1;
1956 dpx[2] = dx1; dpy[2] = vsp[i].fy[1];
1957 dpx[3] = dx0; dpy[3] = vsp[i].fy[0]; drawpoly(dpx,dpy,4,polymethod);
1958 vsp[i].fy[0] = ny0; vsp[i].fy[1] = ny1; vsp[i].ftag = gtag; break;
1959 case 0:
1960 dpx[0] = dx0; dpy[0] = vsp[i].cy[0];
1961 dpx[1] = dx1; dpy[1] = vsp[i].cy[1];
1962 dpx[2] = dx1; dpy[2] = vsp[i].fy[1];
1963 dpx[3] = dx0; dpy[3] = vsp[i].fy[0]; drawpoly(dpx,dpy,4,polymethod);
1964 vsp[i].ctag = vsp[i].ftag = -1; break;
1965 default: break;
1966 }
1967 }
1968 }
1969 }
1970
1971 gtag++;
1972
1973 //Combine neighboring vertical strips with matching collinear top&bottom edges
1974 //This prevents x-splits from propagating through the entire scan
1975 i = vsp[0].n;
1976 while (i)
1977 {
1978 ni = vsp[i].n;
1979 if ((vsp[i].cy[0] >= vsp[i].fy[0]) && (vsp[i].cy[1] >= vsp[i].fy[1])) { vsp[i].ctag = vsp[i].ftag = -1; }
1980 if ((vsp[i].ctag == vsp[ni].ctag) && (vsp[i].ftag == vsp[ni].ftag))
1981 { vsp[i].cy[1] = vsp[ni].cy[1]; vsp[i].fy[1] = vsp[ni].fy[1]; vsdel(ni); }
1982 else i = ni;
1983 }
1984 }
1985
1986 static void polymost_scansector (int sectnum);
1987
polymost_drawalls(int bunch)1988 static void polymost_drawalls (int bunch)
1989 {
1990 sectortype *sec, *nextsec;
1991 walltype *wal, *wal2, *nwal;
1992 double ox, oy, oz, ox2, oy2, px[3], py[3], dd[3], uu[3], vv[3];
1993 double fx, fy, x0, x1, y0, y1, cy0, cy1, fy0, fy1, xp0, yp0, xp1, yp1, ryp0, ryp1, nx0, ny0, nx1, ny1;
1994 double t, r, t0, t1, ocy0, ocy1, ofy0, ofy1, oxp0, oyp0, ft[4];
1995 double oguo, ogux, oguy;
1996 int i, x, y, z, cz, fz, wallnum, sectnum, nextsectnum, domostmethod;
1997
1998 #ifdef DEBUGGINGAIDS
1999 polymostcallcounts.drawalls++;
2000 #endif
2001
2002 sectnum = thesector[bunchfirst[bunch]]; sec = §or[sectnum];
2003
2004 #if USE_OPENGL
2005 gfogpalnum = sec->floorpal;
2006 gfogdensity = gvisibility*((float)((unsigned char)(sec->visibility+16)) / 255.f);
2007 #endif
2008
2009 //DRAW WALLS SECTION!
2010 for(z=bunchfirst[bunch];z>=0;z=p2[z])
2011 {
2012 wallnum = thewall[z]; wal = &wall[wallnum]; wal2 = &wall[wal->point2];
2013 nextsectnum = wal->nextsector; nextsec = §or[nextsectnum];
2014
2015 //Offset&Rotate 3D coordinates to screen 3D space
2016 x = wal->x-globalposx; y = wal->y-globalposy;
2017 xp0 = (double)y*gcosang - (double)x*gsinang;
2018 yp0 = (double)x*gcosang2 + (double)y*gsinang2;
2019 x = wal2->x-globalposx; y = wal2->y-globalposy;
2020 xp1 = (double)y*gcosang - (double)x*gsinang;
2021 yp1 = (double)x*gcosang2 + (double)y*gsinang2;
2022
2023 oxp0 = xp0; oyp0 = yp0;
2024
2025 //Clip to close parallel-screen plane
2026 if (yp0 < SCISDIST)
2027 {
2028 if (yp1 < SCISDIST) continue;
2029 t0 = (SCISDIST-yp0)/(yp1-yp0); xp0 = (xp1-xp0)*t0+xp0; yp0 = SCISDIST;
2030 nx0 = (wal2->x-wal->x)*t0+wal->x;
2031 ny0 = (wal2->y-wal->y)*t0+wal->y;
2032 }
2033 else { t0 = 0.f; nx0 = wal->x; ny0 = wal->y; }
2034 if (yp1 < SCISDIST)
2035 {
2036 t1 = (SCISDIST-oyp0)/(yp1-oyp0); xp1 = (xp1-oxp0)*t1+oxp0; yp1 = SCISDIST;
2037 nx1 = (wal2->x-wal->x)*t1+wal->x;
2038 ny1 = (wal2->y-wal->y)*t1+wal->y;
2039 }
2040 else { t1 = 1.f; nx1 = wal2->x; ny1 = wal2->y; }
2041
2042 ryp0 = 1.f/yp0; ryp1 = 1.f/yp1;
2043
2044 //Generate screen coordinates for front side of wall
2045 x0 = ghalfx*xp0*ryp0 + ghalfx;
2046 x1 = ghalfx*xp1*ryp1 + ghalfx;
2047 if (x1 <= x0) continue;
2048
2049 ryp0 *= gyxscale; ryp1 *= gyxscale;
2050
2051 getzsofslope(sectnum,(int)nx0,(int)ny0,&cz,&fz);
2052 cy0 = ((float)(cz-globalposz))*ryp0 + ghoriz;
2053 fy0 = ((float)(fz-globalposz))*ryp0 + ghoriz;
2054 getzsofslope(sectnum,(int)nx1,(int)ny1,&cz,&fz);
2055 cy1 = ((float)(cz-globalposz))*ryp1 + ghoriz;
2056 fy1 = ((float)(fz-globalposz))*ryp1 + ghoriz;
2057
2058 domostmethod = 0;
2059 globalpicnum = sec->floorpicnum; globalshade = sec->floorshade; globalpal = (int)((unsigned char)sec->floorpal);
2060 globalorientation = sec->floorstat;
2061 if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,sectnum);
2062 if (!(globalorientation&1))
2063 {
2064 //(singlobalang/-16384*(sx-ghalfx) + 0*(sy-ghoriz) + (cosviewingrangeglobalang/16384)*ghalfx)*d + globalposx = u*16
2065 //(cosglobalang/ 16384*(sx-ghalfx) + 0*(sy-ghoriz) + (sinviewingrangeglobalang/16384)*ghalfx)*d + globalposy = v*16
2066 //( 0*(sx-ghalfx) + 1*(sy-ghoriz) + ( 0)*ghalfx)*d + globalposz/16 = (sec->floorz/16)
2067 if (!(globalorientation&64))
2068 { ft[0] = globalposx; ft[1] = globalposy; ft[2] = cosglobalang; ft[3] = singlobalang; }
2069 else
2070 {
2071 //relative alignment
2072 fx = (double)(wall[wall[sec->wallptr].point2].x-wall[sec->wallptr].x);
2073 fy = (double)(wall[wall[sec->wallptr].point2].y-wall[sec->wallptr].y);
2074 r = 1.0/sqrt(fx*fx+fy*fy); fx *= r; fy *= r;
2075 ft[2] = cosglobalang*fx + singlobalang*fy;
2076 ft[3] = singlobalang*fx - cosglobalang*fy;
2077 ft[0] = ((double)(globalposx-wall[sec->wallptr].x))*fx + ((double)(globalposy-wall[sec->wallptr].y))*fy;
2078 ft[1] = ((double)(globalposy-wall[sec->wallptr].y))*fx - ((double)(globalposx-wall[sec->wallptr].x))*fy;
2079 if (!(globalorientation&4)) globalorientation ^= 32; else globalorientation ^= 16;
2080 }
2081 gdx = 0;
2082 gdy = gxyaspect; if (!(globalorientation&2)) gdy /= (double)(sec->floorz-globalposz);
2083 gdo = -ghoriz*gdy;
2084 if (globalorientation&8) { ft[0] /= 8; ft[1] /= -8; ft[2] /= 2097152; ft[3] /= 2097152; }
2085 else { ft[0] /= 16; ft[1] /= -16; ft[2] /= 4194304; ft[3] /= 4194304; }
2086 gux = (double)ft[3]*((double)viewingrange)/-65536.0;
2087 gvx = (double)ft[2]*((double)viewingrange)/-65536.0;
2088 guy = (double)ft[0]*gdy; gvy = (double)ft[1]*gdy;
2089 guo = (double)ft[0]*gdo; gvo = (double)ft[1]*gdo;
2090 guo += (double)(ft[2]-gux)*ghalfx;
2091 gvo -= (double)(ft[3]+gvx)*ghalfx;
2092
2093 //Texture flipping
2094 if (globalorientation&4)
2095 {
2096 r = gux; gux = gvx; gvx = r;
2097 r = guy; guy = gvy; gvy = r;
2098 r = guo; guo = gvo; gvo = r;
2099 }
2100 if (globalorientation&16) { gux = -gux; guy = -guy; guo = -guo; }
2101 if (globalorientation&32) { gvx = -gvx; gvy = -gvy; gvo = -gvo; }
2102
2103 //Texture panning
2104 fx = (float)sec->floorxpanning*((float)(1<<(picsiz[globalpicnum]&15)))/256.0;
2105 fy = (float)sec->floorypanning*((float)(1<<(picsiz[globalpicnum]>>4)))/256.0;
2106 if ((globalorientation&(2+64)) == (2+64)) //Hack for panning for slopes w/ relative alignment
2107 {
2108 r = (float)sec->floorheinum / 4096.0; r = 1.0/sqrt(r*r+1);
2109 if (!(globalorientation&4)) fy *= r; else fx *= r;
2110 }
2111 guy += gdy*fx; guo += gdo*fx;
2112 gvy += gdy*fy; gvo += gdo*fy;
2113
2114 if (globalorientation&2) //slopes
2115 {
2116 px[0] = x0; py[0] = ryp0 + ghoriz;
2117 px[1] = x1; py[1] = ryp1 + ghoriz;
2118
2119 //Pick some point guaranteed to be not collinear to the 1st two points
2120 ox = nx0 + (ny1-ny0);
2121 oy = ny0 + (nx0-nx1);
2122 ox2 = (double)(oy-globalposy)*gcosang - (double)(ox-globalposx)*gsinang;
2123 oy2 = (double)(ox-globalposx)*gcosang2 + (double)(oy-globalposy)*gsinang2;
2124 oy2 = 1.0/oy2;
2125 px[2] = ghalfx*ox2*oy2 + ghalfx; oy2 *= gyxscale;
2126 py[2] = oy2 + ghoriz;
2127
2128 for(i=0;i<3;i++)
2129 {
2130 dd[i] = px[i]*gdx + py[i]*gdy + gdo;
2131 uu[i] = px[i]*gux + py[i]*guy + guo;
2132 vv[i] = px[i]*gvx + py[i]*gvy + gvo;
2133 }
2134
2135 py[0] = fy0;
2136 py[1] = fy1;
2137 py[2] = (getflorzofslope(sectnum,(int)ox,(int)oy)-globalposz)*oy2 + ghoriz;
2138
2139 ox = py[1]-py[2]; oy = py[2]-py[0]; oz = py[0]-py[1];
2140 r = 1.0 / (ox*px[0] + oy*px[1] + oz*px[2]);
2141 gdx = (ox*dd[0] + oy*dd[1] + oz*dd[2])*r;
2142 gux = (ox*uu[0] + oy*uu[1] + oz*uu[2])*r;
2143 gvx = (ox*vv[0] + oy*vv[1] + oz*vv[2])*r;
2144 ox = px[2]-px[1]; oy = px[0]-px[2]; oz = px[1]-px[0];
2145 gdy = (ox*dd[0] + oy*dd[1] + oz*dd[2])*r;
2146 guy = (ox*uu[0] + oy*uu[1] + oz*uu[2])*r;
2147 gvy = (ox*vv[0] + oy*vv[1] + oz*vv[2])*r;
2148 gdo = dd[0] - px[0]*gdx - py[0]*gdy;
2149 guo = uu[0] - px[0]*gux - py[0]*guy;
2150 gvo = vv[0] - px[0]*gvx - py[0]*gvy;
2151
2152 if (globalorientation&64) //Hack for relative alignment on slopes
2153 {
2154 r = (float)sec->floorheinum / 4096.0;
2155 r = sqrt(r*r+1);
2156 if (!(globalorientation&4)) { gvx *= r; gvy *= r; gvo *= r; }
2157 else { gux *= r; guy *= r; guo *= r; }
2158 }
2159 }
2160 domostmethod = (globalorientation>>7)&3;
2161 if (globalposz >= getflorzofslope(sectnum,globalposx,globalposy)) domostmethod = -1; //Back-face culling
2162 domost(x0,fy0,x1,fy1,domostmethod); //flor
2163 }
2164 else if ((nextsectnum < 0) || (!(sector[nextsectnum].floorstat&1)))
2165 {
2166 //Parallaxing sky... hacked for Ken's mountain texture; paper-sky only :/
2167 #if USE_OPENGL
2168 float tempfogdensity = gfogdensity;
2169 if (rendmode == 3)
2170 {
2171 gfogdensity = 0.f;
2172
2173 //Use clamping for tiled sky textures
2174 for(i=(1<<pskybits)-1;i>0;i--)
2175 if (pskyoff[i] != pskyoff[i-1])
2176 { domostmethod = METH_CLAMPED; break; }
2177 }
2178 if (bpp == 8 || !usehightile || !hicfindsubst(globalpicnum,globalpal,1))
2179 #endif
2180 {
2181 dd[0] = (float)xdimen*.0000001; //Adjust sky depth based on screen size!
2182 t = (double)((1<<(picsiz[globalpicnum]&15))<<pskybits);
2183 vv[1] = dd[0]*((double)xdimscale*(double)viewingrange)/(65536.0*65536.0);
2184 vv[0] = dd[0]*((double)((tilesizy[globalpicnum]>>1)+parallaxyoffs)) - vv[1]*ghoriz;
2185 i = (1<<(picsiz[globalpicnum]>>4)); if (i != tilesizy[globalpicnum]) i += i;
2186 vv[0] += dd[0]*((double)sec->floorypanning)*((double)i)/256.0;
2187
2188
2189 //Hack to draw black rectangle below sky when looking down...
2190 gdx = 0; gdy = gxyaspect / 262144.0; gdo = -ghoriz*gdy;
2191 gux = 0; guy = 0; guo = 0;
2192 gvx = 0; gvy = (double)(tilesizy[globalpicnum]-1)*gdy; gvo = (double)(tilesizy[globalpicnum-1])*gdo;
2193 oy = (((double)tilesizy[globalpicnum])*dd[0]-vv[0])/vv[1];
2194 if ((oy > fy0) && (oy > fy1)) domost(x0,oy,x1,oy,domostmethod);
2195 else if ((oy > fy0) != (oy > fy1))
2196 { // fy0 fy1
2197 // \ /
2198 //oy---------- oy----------
2199 // \ /
2200 // fy1 fy0
2201 ox = (oy-fy0)*(x1-x0)/(fy1-fy0) + x0;
2202 if (oy > fy0) { domost(x0,oy,ox,oy,domostmethod); domost(ox,oy,x1,fy1,domostmethod); }
2203 else { domost(x0,fy0,ox,oy,domostmethod); domost(ox,oy,x1,oy,domostmethod); }
2204 } else domost(x0,fy0,x1,fy1,domostmethod);
2205
2206
2207 gdx = 0; gdy = 0; gdo = dd[0];
2208 gux = gdo*(t*((double)xdimscale)*((double)yxaspect)*((double)viewingrange))/(16384.0*65536.0*65536.0*5.0*1024.0);
2209 guy = 0; //guo calculated later
2210 gvx = 0; gvy = vv[1]; gvo = vv[0];
2211
2212 i = globalpicnum; r = (fy1-fy0)/(x1-x0); //slope of line
2213 oy = ((double)viewingrange)/(ghalfx*256.0); oz = 1/oy;
2214
2215 y = ((((int)((x0-ghalfx)*oy))+globalang)>>(11-pskybits));
2216 fx = x0;
2217 do
2218 {
2219 globalpicnum = pskyoff[y&((1<<pskybits)-1)]+i;
2220 guo = gdo*(t*((double)(globalang-(y<<(11-pskybits))))/2048.0 + (double)sec->floorxpanning) - gux*ghalfx;
2221 y++;
2222 ox = fx; fx = ((double)((y<<(11-pskybits))-globalang))*oz+ghalfx;
2223 if (fx > x1) { fx = x1; i = -1; }
2224
2225 domost(ox,(ox-x0)*r+fy0,fx,(fx-x0)*r+fy0,domostmethod); //flor
2226 } while (i >= 0);
2227
2228 }
2229 #if USE_OPENGL
2230 else //NOTE: code copied from ceiling code... lots of duplicated stuff :/
2231 { //Skybox code for parallax ceiling!
2232 double _xp0, _yp0, _xp1, _yp1, _oxp0, _oyp0, _t0, _t1, _nx0, _ny0, _nx1, _ny1;
2233 double _ryp0, _ryp1, _x0, _x1, _cy0, _fy0, _cy1, _fy1, _ox0, _ox1;
2234 double nfy0, nfy1;
2235 int skywalx[4] = {-512,512,512,-512}, skywaly[4] = {-512,-512,512,512};
2236
2237 domostmethod = METH_CLAMPED;
2238
2239 for(i=0;i<4;i++)
2240 {
2241 x = skywalx[i&3]; y = skywaly[i&3];
2242 _xp0 = (double)y*gcosang - (double)x*gsinang;
2243 _yp0 = (double)x*gcosang2 + (double)y*gsinang2;
2244 x = skywalx[(i+1)&3]; y = skywaly[(i+1)&3];
2245 _xp1 = (double)y*gcosang - (double)x*gsinang;
2246 _yp1 = (double)x*gcosang2 + (double)y*gsinang2;
2247
2248 _oxp0 = _xp0; _oyp0 = _yp0;
2249
2250 //Clip to close parallel-screen plane
2251 if (_yp0 < SCISDIST)
2252 {
2253 if (_yp1 < SCISDIST) continue;
2254 _t0 = (SCISDIST-_yp0)/(_yp1-_yp0); _xp0 = (_xp1-_xp0)*_t0+_xp0; _yp0 = SCISDIST;
2255 _nx0 = (skywalx[(i+1)&3]-skywalx[i&3])*_t0+skywalx[i&3];
2256 _ny0 = (skywaly[(i+1)&3]-skywaly[i&3])*_t0+skywaly[i&3];
2257 }
2258 else { _t0 = 0.f; _nx0 = skywalx[i&3]; _ny0 = skywaly[i&3]; }
2259 if (_yp1 < SCISDIST)
2260 {
2261 _t1 = (SCISDIST-_oyp0)/(_yp1-_oyp0); _xp1 = (_xp1-_oxp0)*_t1+_oxp0; _yp1 = SCISDIST;
2262 _nx1 = (skywalx[(i+1)&3]-skywalx[i&3])*_t1+skywalx[i&3];
2263 _ny1 = (skywaly[(i+1)&3]-skywaly[i&3])*_t1+skywaly[i&3];
2264 }
2265 else { _t1 = 1.f; _nx1 = skywalx[(i+1)&3]; _ny1 = skywaly[(i+1)&3]; }
2266
2267 _ryp0 = 1.f/_yp0; _ryp1 = 1.f/_yp1;
2268
2269 //Generate screen coordinates for front side of wall
2270 _x0 = ghalfx*_xp0*_ryp0 + ghalfx;
2271 _x1 = ghalfx*_xp1*_ryp1 + ghalfx;
2272 if (_x1 <= _x0) continue;
2273 if ((_x0 >= x1) || (x0 >= _x1)) continue;
2274
2275 _ryp0 *= gyxscale; _ryp1 *= gyxscale;
2276
2277 _cy0 = -8192.f*_ryp0 + ghoriz;
2278 _fy0 = 8192.f*_ryp0 + ghoriz;
2279 _cy1 = -8192.f*_ryp1 + ghoriz;
2280 _fy1 = 8192.f*_ryp1 + ghoriz;
2281
2282 _ox0 = _x0; _ox1 = _x1;
2283
2284 //Make sure: x0<=_x0<_x1<=_x1
2285 nfy0 = fy0; nfy1 = fy1;
2286 if (_x0 < x0)
2287 {
2288 t = (x0-_x0)/(_x1-_x0);
2289 _cy0 += (_cy1-_cy0)*t;
2290 _fy0 += (_fy1-_fy0)*t;
2291 _x0 = x0;
2292 }
2293 else if (_x0 > x0) nfy0 += (_x0-x0)*(fy1-fy0)/(x1-x0);
2294 if (_x1 > x1)
2295 {
2296 t = (x1-_x1)/(_x1-_x0);
2297 _cy1 += (_cy1-_cy0)*t;
2298 _fy1 += (_fy1-_fy0)*t;
2299 _x1 = x1;
2300 }
2301 else if (_x1 < x1) nfy1 += (_x1-x1)*(fy1-fy0)/(x1-x0);
2302
2303 // (skybox floor)
2304 //(_x0,_fy0)-(_x1,_fy1)
2305 // (skybox wall)
2306 //(_x0,_cy0)-(_x1,_cy1)
2307 // (skybox ceiling)
2308 //(_x0,nfy0)-(_x1,nfy1)
2309
2310 //ceiling of skybox
2311 ft[0] = 512/16; ft[1] = 512/-16;
2312 ft[2] = ((float)cosglobalang)*(1.f/2147483648.f);
2313 ft[3] = ((float)singlobalang)*(1.f/2147483648.f);
2314 gdx = 0;
2315 gdy = gxyaspect*(1.f/4194304.f);
2316 gdo = -ghoriz*gdy;
2317 gux = (double)ft[3]*((double)viewingrange)/-65536.0;
2318 gvx = (double)ft[2]*((double)viewingrange)/-65536.0;
2319 guy = (double)ft[0]*gdy; gvy = (double)ft[1]*gdy;
2320 guo = (double)ft[0]*gdo; gvo = (double)ft[1]*gdo;
2321 guo += (double)(ft[2]-gux)*ghalfx;
2322 gvo -= (double)(ft[3]+gvx)*ghalfx;
2323 gvx = -gvx; gvy = -gvy; gvo = -gvo; //y-flip skybox floor
2324
2325 drawingskybox = 6; //ceiling/5th texture/index 4 of skybox
2326 if ((_fy0 > nfy0) && (_fy1 > nfy1)) domost(_x0,_fy0,_x1,_fy1,domostmethod);
2327 else if ((_fy0 > nfy0) != (_fy1 > nfy1))
2328 {
2329 //(ox,oy) is intersection of: (_x0,_cy0)-(_x1,_cy1)
2330 // (_x0,nfy0)-(_x1,nfy1)
2331 //ox = _x0 + (_x1-_x0)*t
2332 //oy = _cy0 + (_cy1-_cy0)*t
2333 //oy = nfy0 + (nfy1-nfy0)*t
2334 t = (_fy0-nfy0)/(nfy1-nfy0-_fy1+_fy0);
2335 ox = _x0 + (_x1-_x0)*t;
2336 oy = _fy0 + (_fy1-_fy0)*t;
2337 if (nfy0 > _fy0) { domost(_x0,nfy0,ox,oy,domostmethod); domost(ox,oy,_x1,_fy1,domostmethod); }
2338 else { domost(_x0,_fy0,ox,oy,domostmethod); domost(ox,oy,_x1,nfy1,domostmethod); }
2339 } else domost(_x0,nfy0,_x1,nfy1,domostmethod);
2340
2341 //wall of skybox
2342 drawingskybox = i+1; //i+1th texture/index i of skybox
2343 gdx = (_ryp0-_ryp1)*gxyaspect*(1.f/512.f) / (_ox0-_ox1);
2344 gdy = 0;
2345 gdo = _ryp0*gxyaspect*(1.f/512.f) - gdx*_ox0;
2346 gux = (_t0*_ryp0 - _t1*_ryp1)*gxyaspect*(64.f/512.f) / (_ox0-_ox1);
2347 guo = _t0*_ryp0*gxyaspect*(64.f/512.f) - gux*_ox0;
2348 guy = 0;
2349 _t0 = -8192.0*_ryp0 + ghoriz;
2350 _t1 = -8192.0*_ryp1 + ghoriz;
2351 t = ((gdx*_ox0 + gdo)*8.f) / ((_ox1-_ox0) * _ryp0 * 2048.f);
2352 gvx = (_t0-_t1)*t;
2353 gvy = (_ox1-_ox0)*t;
2354 gvo = -gvx*_ox0 - gvy*_t0;
2355 if ((_cy0 > nfy0) && (_cy1 > nfy1)) domost(_x0,_cy0,_x1,_cy1,domostmethod);
2356 else if ((_cy0 > nfy0) != (_cy1 > nfy1))
2357 {
2358 //(ox,oy) is intersection of: (_x0,_fy0)-(_x1,_fy1)
2359 // (_x0,nfy0)-(_x1,nfy1)
2360 //ox = _x0 + (_x1-_x0)*t
2361 //oy = _fy0 + (_fy1-_fy0)*t
2362 //oy = nfy0 + (nfy1-nfy0)*t
2363 t = (_cy0-nfy0)/(nfy1-nfy0-_cy1+_cy0);
2364 ox = _x0 + (_x1-_x0)*t;
2365 oy = _cy0 + (_cy1-_cy0)*t;
2366 if (nfy0 > _cy0) { domost(_x0,nfy0,ox,oy,domostmethod); domost(ox,oy,_x1,_cy1,domostmethod); }
2367 else { domost(_x0,_cy0,ox,oy,domostmethod); domost(ox,oy,_x1,nfy1,domostmethod); }
2368 } else domost(_x0,nfy0,_x1,nfy1,domostmethod);
2369 }
2370
2371 //Floor of skybox
2372 drawingskybox = 5; //floor/6th texture/index 5 of skybox
2373 ft[0] = 512/16; ft[1] = -512/-16;
2374 ft[2] = ((float)cosglobalang)*(1.f/2147483648.f);
2375 ft[3] = ((float)singlobalang)*(1.f/2147483648.f);
2376 gdx = 0;
2377 gdy = gxyaspect*(-1.f/4194304.f);
2378 gdo = -ghoriz*gdy;
2379 gux = (double)ft[3]*((double)viewingrange)/-65536.0;
2380 gvx = (double)ft[2]*((double)viewingrange)/-65536.0;
2381 guy = (double)ft[0]*gdy; gvy = (double)ft[1]*gdy;
2382 guo = (double)ft[0]*gdo; gvo = (double)ft[1]*gdo;
2383 guo += (double)(ft[2]-gux)*ghalfx;
2384 gvo -= (double)(ft[3]+gvx)*ghalfx;
2385 domost(x0,fy0,x1,fy1,domostmethod);
2386
2387 drawingskybox = 0;
2388 }
2389 if (rendmode == 3)
2390 {
2391 gfogdensity = tempfogdensity;
2392 }
2393 #endif
2394 }
2395
2396 domostmethod = 0;
2397 globalpicnum = sec->ceilingpicnum; globalshade = sec->ceilingshade; globalpal = (int)((unsigned char)sec->ceilingpal);
2398 globalorientation = sec->ceilingstat;
2399 if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,sectnum);
2400 if (!(globalorientation&1))
2401 {
2402 if (!(globalorientation&64))
2403 { ft[0] = globalposx; ft[1] = globalposy; ft[2] = cosglobalang; ft[3] = singlobalang; }
2404 else
2405 {
2406 //relative alignment
2407 fx = (double)(wall[wall[sec->wallptr].point2].x-wall[sec->wallptr].x);
2408 fy = (double)(wall[wall[sec->wallptr].point2].y-wall[sec->wallptr].y);
2409 r = 1.0/sqrt(fx*fx+fy*fy); fx *= r; fy *= r;
2410 ft[2] = cosglobalang*fx + singlobalang*fy;
2411 ft[3] = singlobalang*fx - cosglobalang*fy;
2412 ft[0] = ((double)(globalposx-wall[sec->wallptr].x))*fx + ((double)(globalposy-wall[sec->wallptr].y))*fy;
2413 ft[1] = ((double)(globalposy-wall[sec->wallptr].y))*fx - ((double)(globalposx-wall[sec->wallptr].x))*fy;
2414 if (!(globalorientation&4)) globalorientation ^= 32; else globalorientation ^= 16;
2415 }
2416 gdx = 0;
2417 gdy = gxyaspect;
2418 if (!(globalorientation&2)) gdy /= (double)(sec->ceilingz-globalposz);
2419 gdo = -ghoriz*gdy;
2420 if (globalorientation&8) { ft[0] /= 8; ft[1] /= -8; ft[2] /= 2097152; ft[3] /= 2097152; }
2421 else { ft[0] /= 16; ft[1] /= -16; ft[2] /= 4194304; ft[3] /= 4194304; }
2422 gux = (double)ft[3]*((double)viewingrange)/-65536.0;
2423 gvx = (double)ft[2]*((double)viewingrange)/-65536.0;
2424 guy = (double)ft[0]*gdy; gvy = (double)ft[1]*gdy;
2425 guo = (double)ft[0]*gdo; gvo = (double)ft[1]*gdo;
2426 guo += (double)(ft[2]-gux)*ghalfx;
2427 gvo -= (double)(ft[3]+gvx)*ghalfx;
2428
2429 //Texture flipping
2430 if (globalorientation&4)
2431 {
2432 r = gux; gux = gvx; gvx = r;
2433 r = guy; guy = gvy; gvy = r;
2434 r = guo; guo = gvo; gvo = r;
2435 }
2436 if (globalorientation&16) { gux = -gux; guy = -guy; guo = -guo; }
2437 if (globalorientation&32) { gvx = -gvx; gvy = -gvy; gvo = -gvo; }
2438
2439 //Texture panning
2440 fx = (float)sec->ceilingxpanning*((float)(1<<(picsiz[globalpicnum]&15)))/256.0;
2441 fy = (float)sec->ceilingypanning*((float)(1<<(picsiz[globalpicnum]>>4)))/256.0;
2442 if ((globalorientation&(2+64)) == (2+64)) //Hack for panning for slopes w/ relative alignment
2443 {
2444 r = (float)sec->ceilingheinum / 4096.0; r = 1.0/sqrt(r*r+1);
2445 if (!(globalorientation&4)) fy *= r; else fx *= r;
2446 }
2447 guy += gdy*fx; guo += gdo*fx;
2448 gvy += gdy*fy; gvo += gdo*fy;
2449
2450 if (globalorientation&2) //slopes
2451 {
2452 px[0] = x0; py[0] = ryp0 + ghoriz;
2453 px[1] = x1; py[1] = ryp1 + ghoriz;
2454
2455 //Pick some point guaranteed to be not collinear to the 1st two points
2456 ox = nx0 + (ny1-ny0);
2457 oy = ny0 + (nx0-nx1);
2458 ox2 = (double)(oy-globalposy)*gcosang - (double)(ox-globalposx)*gsinang ;
2459 oy2 = (double)(ox-globalposx)*gcosang2 + (double)(oy-globalposy)*gsinang2;
2460 oy2 = 1.0/oy2;
2461 px[2] = ghalfx*ox2*oy2 + ghalfx; oy2 *= gyxscale;
2462 py[2] = oy2 + ghoriz;
2463
2464 for(i=0;i<3;i++)
2465 {
2466 dd[i] = px[i]*gdx + py[i]*gdy + gdo;
2467 uu[i] = px[i]*gux + py[i]*guy + guo;
2468 vv[i] = px[i]*gvx + py[i]*gvy + gvo;
2469 }
2470
2471 py[0] = cy0;
2472 py[1] = cy1;
2473 py[2] = (getceilzofslope(sectnum,(int)ox,(int)oy)-globalposz)*oy2 + ghoriz;
2474
2475 ox = py[1]-py[2]; oy = py[2]-py[0]; oz = py[0]-py[1];
2476 r = 1.0 / (ox*px[0] + oy*px[1] + oz*px[2]);
2477 gdx = (ox*dd[0] + oy*dd[1] + oz*dd[2])*r;
2478 gux = (ox*uu[0] + oy*uu[1] + oz*uu[2])*r;
2479 gvx = (ox*vv[0] + oy*vv[1] + oz*vv[2])*r;
2480 ox = px[2]-px[1]; oy = px[0]-px[2]; oz = px[1]-px[0];
2481 gdy = (ox*dd[0] + oy*dd[1] + oz*dd[2])*r;
2482 guy = (ox*uu[0] + oy*uu[1] + oz*uu[2])*r;
2483 gvy = (ox*vv[0] + oy*vv[1] + oz*vv[2])*r;
2484 gdo = dd[0] - px[0]*gdx - py[0]*gdy;
2485 guo = uu[0] - px[0]*gux - py[0]*guy;
2486 gvo = vv[0] - px[0]*gvx - py[0]*gvy;
2487
2488 if (globalorientation&64) //Hack for relative alignment on slopes
2489 {
2490 r = (float)sec->ceilingheinum / 4096.0;
2491 r = sqrt(r*r+1);
2492 if (!(globalorientation&4)) { gvx *= r; gvy *= r; gvo *= r; }
2493 else { gux *= r; guy *= r; guo *= r; }
2494 }
2495 }
2496 domostmethod = (globalorientation>>7)&3;
2497 if (globalposz <= getceilzofslope(sectnum,globalposx,globalposy)) domostmethod = -1; //Back-face culling
2498 domost(x1,cy1,x0,cy0,domostmethod); //ceil
2499 }
2500 else if ((nextsectnum < 0) || (!(sector[nextsectnum].ceilingstat&1)))
2501 {
2502 #if USE_OPENGL
2503 float tempfogdensity = gfogdensity;
2504 if (rendmode == 3)
2505 {
2506 gfogdensity = 0.f;
2507
2508 //Use clamping for tiled sky textures
2509 for(i=(1<<pskybits)-1;i>0;i--)
2510 if (pskyoff[i] != pskyoff[i-1])
2511 { domostmethod = METH_CLAMPED; break; }
2512 }
2513 //Parallaxing sky...
2514 if (bpp == 8 || !usehightile || !hicfindsubst(globalpicnum,globalpal,1))
2515 #endif
2516 {
2517 //Render for parallaxtype == 0 / paper-sky
2518 dd[0] = (float)xdimen*.0000001; //Adjust sky depth based on screen size!
2519 t = (double)((1<<(picsiz[globalpicnum]&15))<<pskybits);
2520 vv[1] = dd[0]*((double)xdimscale*(double)viewingrange)/(65536.0*65536.0);
2521 vv[0] = dd[0]*((double)((tilesizy[globalpicnum]>>1)+parallaxyoffs)) - vv[1]*ghoriz;
2522 i = (1<<(picsiz[globalpicnum]>>4)); if (i != tilesizy[globalpicnum]) i += i;
2523 vv[0] += dd[0]*((double)sec->ceilingypanning)*((double)i)/256.0;
2524
2525 //Hack to draw black rectangle below sky when looking down...
2526 gdx = 0; gdy = gxyaspect / -262144.0; gdo = -ghoriz*gdy;
2527 gux = 0; guy = 0; guo = 0;
2528 gvx = 0; gvy = 0; gvo = 0;
2529 oy = -vv[0]/vv[1];
2530 if ((oy < cy0) && (oy < cy1)) domost(x1,oy,x0,oy,domostmethod);
2531 else if ((oy < cy0) != (oy < cy1))
2532 { /* cy1 cy0
2533 // / \
2534 //oy---------- oy---------
2535 // / \
2536 // cy0 cy1
2537 */
2538 ox = (oy-cy0)*(x1-x0)/(cy1-cy0) + x0;
2539 if (oy < cy0) { domost(ox,oy,x0,oy,domostmethod); domost(x1,cy1,ox,oy,domostmethod); }
2540 else { domost(ox,oy,x0,cy0,domostmethod); domost(x1,oy,ox,oy,domostmethod); }
2541 } else domost(x1,cy1,x0,cy0,domostmethod);
2542
2543 gdx = 0; gdy = 0; gdo = dd[0];
2544 gux = gdo*(t*((double)xdimscale)*((double)yxaspect)*((double)viewingrange))/(16384.0*65536.0*65536.0*5.0*1024.0);
2545 guy = 0; //guo calculated later
2546 gvx = 0; gvy = vv[1]; gvo = vv[0];
2547
2548 i = globalpicnum; r = (cy1-cy0)/(x1-x0); //slope of line
2549 oy = ((double)viewingrange)/(ghalfx*256.0); oz = 1/oy;
2550
2551 y = ((((int)((x0-ghalfx)*oy))+globalang)>>(11-pskybits));
2552 fx = x0;
2553 do
2554 {
2555 globalpicnum = pskyoff[y&((1<<pskybits)-1)]+i;
2556 guo = gdo*(t*((double)(globalang-(y<<(11-pskybits))))/2048.0 + (double)sec->ceilingxpanning) - gux*ghalfx;
2557 y++;
2558 ox = fx; fx = ((double)((y<<(11-pskybits))-globalang))*oz+ghalfx;
2559 if (fx > x1) { fx = x1; i = -1; }
2560 domost(fx,(fx-x0)*r+cy0,ox,(ox-x0)*r+cy0,domostmethod); //ceil
2561 } while (i >= 0);
2562 }
2563 #if USE_OPENGL
2564 else
2565 { //Skybox code for parallax ceiling!
2566 double _xp0, _yp0, _xp1, _yp1, _oxp0, _oyp0, _t0, _t1, _nx0, _ny0, _nx1, _ny1;
2567 double _ryp0, _ryp1, _x0, _x1, _cy0, _fy0, _cy1, _fy1, _ox0, _ox1;
2568 double ncy0, ncy1;
2569 int skywalx[4] = {-512,512,512,-512}, skywaly[4] = {-512,-512,512,512};
2570
2571 domostmethod = METH_CLAMPED;
2572
2573 for(i=0;i<4;i++)
2574 {
2575 x = skywalx[i&3]; y = skywaly[i&3];
2576 _xp0 = (double)y*gcosang - (double)x*gsinang;
2577 _yp0 = (double)x*gcosang2 + (double)y*gsinang2;
2578 x = skywalx[(i+1)&3]; y = skywaly[(i+1)&3];
2579 _xp1 = (double)y*gcosang - (double)x*gsinang;
2580 _yp1 = (double)x*gcosang2 + (double)y*gsinang2;
2581
2582 _oxp0 = _xp0; _oyp0 = _yp0;
2583
2584 //Clip to close parallel-screen plane
2585 if (_yp0 < SCISDIST)
2586 {
2587 if (_yp1 < SCISDIST) continue;
2588 _t0 = (SCISDIST-_yp0)/(_yp1-_yp0); _xp0 = (_xp1-_xp0)*_t0+_xp0; _yp0 = SCISDIST;
2589 _nx0 = (skywalx[(i+1)&3]-skywalx[i&3])*_t0+skywalx[i&3];
2590 _ny0 = (skywaly[(i+1)&3]-skywaly[i&3])*_t0+skywaly[i&3];
2591 }
2592 else { _t0 = 0.f; _nx0 = skywalx[i&3]; _ny0 = skywaly[i&3]; }
2593 if (_yp1 < SCISDIST)
2594 {
2595 _t1 = (SCISDIST-_oyp0)/(_yp1-_oyp0); _xp1 = (_xp1-_oxp0)*_t1+_oxp0; _yp1 = SCISDIST;
2596 _nx1 = (skywalx[(i+1)&3]-skywalx[i&3])*_t1+skywalx[i&3];
2597 _ny1 = (skywaly[(i+1)&3]-skywaly[i&3])*_t1+skywaly[i&3];
2598 }
2599 else { _t1 = 1.f; _nx1 = skywalx[(i+1)&3]; _ny1 = skywaly[(i+1)&3]; }
2600
2601 _ryp0 = 1.f/_yp0; _ryp1 = 1.f/_yp1;
2602
2603 //Generate screen coordinates for front side of wall
2604 _x0 = ghalfx*_xp0*_ryp0 + ghalfx;
2605 _x1 = ghalfx*_xp1*_ryp1 + ghalfx;
2606 if (_x1 <= _x0) continue;
2607 if ((_x0 >= x1) || (x0 >= _x1)) continue;
2608
2609 _ryp0 *= gyxscale; _ryp1 *= gyxscale;
2610
2611 _cy0 = -8192.f*_ryp0 + ghoriz;
2612 _fy0 = 8192.f*_ryp0 + ghoriz;
2613 _cy1 = -8192.f*_ryp1 + ghoriz;
2614 _fy1 = 8192.f*_ryp1 + ghoriz;
2615
2616 _ox0 = _x0; _ox1 = _x1;
2617
2618 //Make sure: x0<=_x0<_x1<=_x1
2619 ncy0 = cy0; ncy1 = cy1;
2620 if (_x0 < x0)
2621 {
2622 t = (x0-_x0)/(_x1-_x0);
2623 _cy0 += (_cy1-_cy0)*t;
2624 _fy0 += (_fy1-_fy0)*t;
2625 _x0 = x0;
2626 }
2627 else if (_x0 > x0) ncy0 += (_x0-x0)*(cy1-cy0)/(x1-x0);
2628 if (_x1 > x1)
2629 {
2630 t = (x1-_x1)/(_x1-_x0);
2631 _cy1 += (_cy1-_cy0)*t;
2632 _fy1 += (_fy1-_fy0)*t;
2633 _x1 = x1;
2634 }
2635 else if (_x1 < x1) ncy1 += (_x1-x1)*(cy1-cy0)/(x1-x0);
2636
2637 // (skybox ceiling)
2638 //(_x0,_cy0)-(_x1,_cy1)
2639 // (skybox wall)
2640 //(_x0,_fy0)-(_x1,_fy1)
2641 // (skybox floor)
2642 //(_x0,ncy0)-(_x1,ncy1)
2643
2644 //ceiling of skybox
2645
2646 drawingskybox = 5; //ceiling/5th texture/index 4 of skybox
2647 ft[0] = 512/16; ft[1] = -512/-16;
2648 ft[2] = ((float)cosglobalang)*(1.f/2147483648.f);
2649 ft[3] = ((float)singlobalang)*(1.f/2147483648.f);
2650 gdx = 0;
2651 gdy = gxyaspect*-(1.f/4194304.f);
2652 gdo = -ghoriz*gdy;
2653 gux = (double)ft[3]*((double)viewingrange)/-65536.0;
2654 gvx = (double)ft[2]*((double)viewingrange)/-65536.0;
2655 guy = (double)ft[0]*gdy; gvy = (double)ft[1]*gdy;
2656 guo = (double)ft[0]*gdo; gvo = (double)ft[1]*gdo;
2657 guo += (double)(ft[2]-gux)*ghalfx;
2658 gvo -= (double)(ft[3]+gvx)*ghalfx;
2659 if ((_cy0 < ncy0) && (_cy1 < ncy1)) domost(_x1,_cy1,_x0,_cy0,domostmethod);
2660 else if ((_cy0 < ncy0) != (_cy1 < ncy1))
2661 {
2662 //(ox,oy) is intersection of: (_x0,_cy0)-(_x1,_cy1)
2663 // (_x0,ncy0)-(_x1,ncy1)
2664 //ox = _x0 + (_x1-_x0)*t
2665 //oy = _cy0 + (_cy1-_cy0)*t
2666 //oy = ncy0 + (ncy1-ncy0)*t
2667 t = (_cy0-ncy0)/(ncy1-ncy0-_cy1+_cy0);
2668 ox = _x0 + (_x1-_x0)*t;
2669 oy = _cy0 + (_cy1-_cy0)*t;
2670 if (ncy0 < _cy0) { domost(ox,oy,_x0,ncy0,domostmethod); domost(_x1,_cy1,ox,oy,domostmethod); }
2671 else { domost(ox,oy,_x0,_cy0,domostmethod); domost(_x1,ncy1,ox,oy,domostmethod); }
2672 } else domost(_x1,ncy1,_x0,ncy0,domostmethod);
2673
2674 //wall of skybox
2675 drawingskybox = i+1; //i+1th texture/index i of skybox
2676 gdx = (_ryp0-_ryp1)*gxyaspect*(1.f/512.f) / (_ox0-_ox1);
2677 gdy = 0;
2678 gdo = _ryp0*gxyaspect*(1.f/512.f) - gdx*_ox0;
2679 gux = (_t0*_ryp0 - _t1*_ryp1)*gxyaspect*(64.f/512.f) / (_ox0-_ox1);
2680 guo = _t0*_ryp0*gxyaspect*(64.f/512.f) - gux*_ox0;
2681 guy = 0;
2682 _t0 = -8192.0*_ryp0 + ghoriz;
2683 _t1 = -8192.0*_ryp1 + ghoriz;
2684 t = ((gdx*_ox0 + gdo)*8.f) / ((_ox1-_ox0) * _ryp0 * 2048.f);
2685 gvx = (_t0-_t1)*t;
2686 gvy = (_ox1-_ox0)*t;
2687 gvo = -gvx*_ox0 - gvy*_t0;
2688 if ((_fy0 < ncy0) && (_fy1 < ncy1)) domost(_x1,_fy1,_x0,_fy0,domostmethod);
2689 else if ((_fy0 < ncy0) != (_fy1 < ncy1))
2690 {
2691 //(ox,oy) is intersection of: (_x0,_fy0)-(_x1,_fy1)
2692 // (_x0,ncy0)-(_x1,ncy1)
2693 //ox = _x0 + (_x1-_x0)*t
2694 //oy = _fy0 + (_fy1-_fy0)*t
2695 //oy = ncy0 + (ncy1-ncy0)*t
2696 t = (_fy0-ncy0)/(ncy1-ncy0-_fy1+_fy0);
2697 ox = _x0 + (_x1-_x0)*t;
2698 oy = _fy0 + (_fy1-_fy0)*t;
2699 if (ncy0 < _fy0) { domost(ox,oy,_x0,ncy0,domostmethod); domost(_x1,_fy1,ox,oy,domostmethod); }
2700 else { domost(ox,oy,_x0,_fy0,domostmethod); domost(_x1,ncy1,ox,oy,domostmethod); }
2701 } else domost(_x1,ncy1,_x0,ncy0,domostmethod);
2702 }
2703
2704 //Floor of skybox
2705 drawingskybox = 6; //floor/6th texture/index 5 of skybox
2706 ft[0] = 512/16; ft[1] = 512/-16;
2707 ft[2] = ((float)cosglobalang)*(1.f/2147483648.f);
2708 ft[3] = ((float)singlobalang)*(1.f/2147483648.f);
2709 gdx = 0;
2710 gdy = gxyaspect*(1.f/4194304.f);
2711 gdo = -ghoriz*gdy;
2712 gux = (double)ft[3]*((double)viewingrange)/-65536.0;
2713 gvx = (double)ft[2]*((double)viewingrange)/-65536.0;
2714 guy = (double)ft[0]*gdy; gvy = (double)ft[1]*gdy;
2715 guo = (double)ft[0]*gdo; gvo = (double)ft[1]*gdo;
2716 guo += (double)(ft[2]-gux)*ghalfx;
2717 gvo -= (double)(ft[3]+gvx)*ghalfx;
2718 gvx = -gvx; gvy = -gvy; gvo = -gvo; //y-flip skybox floor
2719 domost(x1,cy1,x0,cy0,domostmethod);
2720
2721 drawingskybox = 0;
2722 }
2723 if (rendmode == 3)
2724 {
2725 gfogdensity = tempfogdensity;
2726 }
2727 #endif
2728 }
2729
2730 //(x0,cy0) == (u= 0,v=0,d=)
2731 //(x1,cy0) == (u=wal->xrepeat*8,v=0)
2732 //(x0,fy0) == (u= 0,v=v)
2733 // u = (gux*sx + guy*sy + guo) / (gdx*sx + gdy*sy + gdo)
2734 // v = (gvx*sx + gvy*sy + gvo) / (gdx*sx + gdy*sy + gdo)
2735 // 0 = (gux*x0 + guy*cy0 + guo) / (gdx*x0 + gdy*cy0 + gdo)
2736 //wal->xrepeat*8 = (gux*x1 + guy*cy0 + guo) / (gdx*x1 + gdy*cy0 + gdo)
2737 // 0 = (gvx*x0 + gvy*cy0 + gvo) / (gdx*x0 + gdy*cy0 + gdo)
2738 // v = (gvx*x0 + gvy*fy0 + gvo) / (gdx*x0 + gdy*fy0 + gdo)
2739 //sx = x0, u = t0*wal->xrepeat*8, d = yp0;
2740 //sx = x1, u = t1*wal->xrepeat*8, d = yp1;
2741 //d = gdx*sx + gdo
2742 //u = (gux*sx + guo) / (gdx*sx + gdo)
2743 //yp0 = gdx*x0 + gdo
2744 //yp1 = gdx*x1 + gdo
2745 //t0*wal->xrepeat*8 = (gux*x0 + guo) / (gdx*x0 + gdo)
2746 //t1*wal->xrepeat*8 = (gux*x1 + guo) / (gdx*x1 + gdo)
2747 //gdx*x0 + gdo = yp0
2748 //gdx*x1 + gdo = yp1
2749 gdx = (ryp0-ryp1)*gxyaspect / (x0-x1);
2750 gdy = 0;
2751 gdo = ryp0*gxyaspect - gdx*x0;
2752
2753 //gux*x0 + guo = t0*wal->xrepeat*8*yp0
2754 //gux*x1 + guo = t1*wal->xrepeat*8*yp1
2755 gux = (t0*ryp0 - t1*ryp1)*gxyaspect*(float)wal->xrepeat*8.f / (x0-x1);
2756 guo = t0*ryp0*gxyaspect*(float)wal->xrepeat*8.f - gux*x0;
2757 guo += (float)wal->xpanning*gdo;
2758 gux += (float)wal->xpanning*gdx;
2759 guy = 0;
2760 //Derivation for u:
2761 // (gvx*x0 + gvy*cy0 + gvo) / (gdx*x0 + gdy*cy0 + gdo) = 0
2762 // (gvx*x1 + gvy*cy1 + gvo) / (gdx*x1 + gdy*cy1 + gdo) = 0
2763 // (gvx*x0 + gvy*fy0 + gvo) / (gdx*x0 + gdy*fy0 + gdo) = v
2764 // (gvx*x1 + gvy*fy1 + gvo) / (gdx*x1 + gdy*fy1 + gdo) = v
2765 // (gvx*x0 + gvy*cy0 + gvo*1) = 0
2766 // (gvx*x1 + gvy*cy1 + gvo*1) = 0
2767 // (gvx*x0 + gvy*fy0 + gvo*1) = t
2768 ogux = gux; oguy = guy; oguo = guo;
2769
2770 if (nextsectnum >= 0)
2771 {
2772 getzsofslope(nextsectnum,(int)nx0,(int)ny0,&cz,&fz);
2773 ocy0 = ((float)(cz-globalposz))*ryp0 + ghoriz;
2774 ofy0 = ((float)(fz-globalposz))*ryp0 + ghoriz;
2775 getzsofslope(nextsectnum,(int)nx1,(int)ny1,&cz,&fz);
2776 ocy1 = ((float)(cz-globalposz))*ryp1 + ghoriz;
2777 ofy1 = ((float)(fz-globalposz))*ryp1 + ghoriz;
2778
2779 if ((wal->cstat&48) == 16) maskwall[maskwallcnt++] = z;
2780
2781 if (((cy0 < ocy0) || (cy1 < ocy1)) && (!((sec->ceilingstat§or[nextsectnum].ceilingstat)&1)))
2782 {
2783 globalpicnum = wal->picnum; globalshade = wal->shade; globalpal = (int)((unsigned char)wal->pal);
2784 if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,wallnum+16384);
2785
2786 if (!(wal->cstat&4)) i = sector[nextsectnum].ceilingz; else i = sec->ceilingz;
2787 t0 = ((float)(i-globalposz))*ryp0 + ghoriz;
2788 t1 = ((float)(i-globalposz))*ryp1 + ghoriz;
2789 t = ((gdx*x0 + gdo) * (float)wal->yrepeat) / ((x1-x0) * ryp0 * 2048.f);
2790 i = (1<<(picsiz[globalpicnum]>>4)); if (i < tilesizy[globalpicnum]) i <<= 1;
2791 fy = (float)wal->ypanning * ((float)i) / 256.0;
2792 gvx = (t0-t1)*t;
2793 gvy = (x1-x0)*t;
2794 gvo = -gvx*x0 - gvy*t0 + fy*gdo; gvx += fy*gdx; gvy += fy*gdy;
2795
2796 if (wal->cstat&8) //xflip
2797 {
2798 t = (float)(wal->xrepeat*8 + wal->xpanning*2);
2799 gux = gdx*t - gux;
2800 guy = gdy*t - guy;
2801 guo = gdo*t - guo;
2802 }
2803 if (wal->cstat&256) { gvx = -gvx; gvy = -gvy; gvo = -gvo; } //yflip
2804
2805 domost(x1,ocy1,x0,ocy0,METH_POW2XSPLIT);
2806
2807 if (wal->cstat&8) { gux = ogux; guy = oguy; guo = oguo; }
2808 }
2809 if (((ofy0 < fy0) || (ofy1 < fy1)) && (!((sec->floorstat§or[nextsectnum].floorstat)&1)))
2810 {
2811 if (!(wal->cstat&2)) nwal = wal;
2812 else
2813 {
2814 nwal = &wall[wal->nextwall];
2815 guo += (float)(nwal->xpanning-wal->xpanning)*gdo;
2816 gux += (float)(nwal->xpanning-wal->xpanning)*gdx;
2817 guy += (float)(nwal->xpanning-wal->xpanning)*gdy;
2818 }
2819 globalpicnum = nwal->picnum; globalshade = nwal->shade; globalpal = (int)((unsigned char)nwal->pal);
2820 if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,wallnum+16384);
2821
2822 if (!(nwal->cstat&4)) i = sector[nextsectnum].floorz; else i = sec->ceilingz;
2823 t0 = ((float)(i-globalposz))*ryp0 + ghoriz;
2824 t1 = ((float)(i-globalposz))*ryp1 + ghoriz;
2825 t = ((gdx*x0 + gdo) * (float)wal->yrepeat) / ((x1-x0) * ryp0 * 2048.f);
2826 i = (1<<(picsiz[globalpicnum]>>4)); if (i < tilesizy[globalpicnum]) i <<= 1;
2827 fy = (float)nwal->ypanning * ((float)i) / 256.0;
2828 gvx = (t0-t1)*t;
2829 gvy = (x1-x0)*t;
2830 gvo = -gvx*x0 - gvy*t0 + fy*gdo; gvx += fy*gdx; gvy += fy*gdy;
2831
2832 if (wal->cstat&8) //xflip
2833 {
2834 t = (float)(wal->xrepeat*8 + nwal->xpanning*2);
2835 gux = gdx*t - gux;
2836 guy = gdy*t - guy;
2837 guo = gdo*t - guo;
2838 }
2839 if (nwal->cstat&256) { gvx = -gvx; gvy = -gvy; gvo = -gvo; } //yflip
2840
2841 domost(x0,ofy0,x1,ofy1,METH_POW2XSPLIT);
2842
2843 if (wal->cstat&(2+8)) { guo = oguo; gux = ogux; guy = oguy; }
2844 }
2845 }
2846
2847 if ((nextsectnum < 0) || (wal->cstat&32)) //White/1-way wall
2848 {
2849 if (nextsectnum < 0) globalpicnum = wal->picnum; else globalpicnum = wal->overpicnum;
2850 globalshade = wal->shade; globalpal = (int)((unsigned char)wal->pal);
2851 if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,wallnum+16384);
2852
2853 if (nextsectnum >= 0) { if (!(wal->cstat&4)) i = nextsec->ceilingz; else i = sec->ceilingz; }
2854 else { if (!(wal->cstat&4)) i = sec->ceilingz; else i = sec->floorz; }
2855 t0 = ((float)(i-globalposz))*ryp0 + ghoriz;
2856 t1 = ((float)(i-globalposz))*ryp1 + ghoriz;
2857 t = ((gdx*x0 + gdo) * (float)wal->yrepeat) / ((x1-x0) * ryp0 * 2048.f);
2858 i = (1<<(picsiz[globalpicnum]>>4)); if (i < tilesizy[globalpicnum]) i <<= 1;
2859 fy = (float)wal->ypanning * ((float)i) / 256.0;
2860 gvx = (t0-t1)*t;
2861 gvy = (x1-x0)*t;
2862 gvo = -gvx*x0 - gvy*t0 + fy*gdo; gvx += fy*gdx; gvy += fy*gdy;
2863
2864 if (wal->cstat&8) //xflip
2865 {
2866 t = (float)(wal->xrepeat*8 + wal->xpanning*2);
2867 gux = gdx*t - gux;
2868 guy = gdy*t - guy;
2869 guo = gdo*t - guo;
2870 }
2871 if (wal->cstat&256) { gvx = -gvx; gvy = -gvy; gvo = -gvo; } //yflip
2872 domost(x0,-10000,x1,-10000,METH_POW2XSPLIT);
2873 }
2874
2875 if (nextsectnum >= 0)
2876 if ((!(gotsector[nextsectnum>>3]&pow2char[nextsectnum&7])) && (testvisiblemost(x0,x1)))
2877 polymost_scansector(nextsectnum);
2878 }
2879 }
2880
polymost_bunchfront(int b1,int b2)2881 static int polymost_bunchfront (int b1, int b2)
2882 {
2883 double x1b1, x1b2, x2b1, x2b2;
2884 int b1f, b2f, i;
2885
2886 b1f = bunchfirst[b1]; x1b1 = dxb1[b1f]; x2b2 = dxb2[bunchlast[b2]]; if (x1b1 >= x2b2) return(-1);
2887 b2f = bunchfirst[b2]; x1b2 = dxb1[b2f]; x2b1 = dxb2[bunchlast[b1]]; if (x1b2 >= x2b1) return(-1);
2888
2889 if (x1b1 >= x1b2)
2890 {
2891 for(i=b2f;dxb2[i]<=x1b1;i=p2[i]);
2892 return(wallfront(b1f,i));
2893 }
2894 for(i=b1f;dxb2[i]<=x1b2;i=p2[i]);
2895 return(wallfront(i,b2f));
2896 }
2897
polymost_scansector(int sectnum)2898 static void polymost_scansector (int sectnum)
2899 {
2900 double d, xp1, yp1, xp2, yp2;
2901 walltype *wal, *wal2;
2902 spritetype *spr;
2903 int z, zz, startwall, endwall, numscansbefore, scanfirst, bunchfrst, nextsectnum;
2904 int xs, ys, x1, y1, x2, y2;
2905
2906 if (sectnum < 0) return;
2907 if (automapping) show2dsector[sectnum>>3] |= pow2char[sectnum&7];
2908
2909 sectorborder[0] = sectnum, sectorbordercnt = 1;
2910 do
2911 {
2912 sectnum = sectorborder[--sectorbordercnt];
2913
2914 for(z=headspritesect[sectnum];z>=0;z=nextspritesect[z])
2915 {
2916 spr = &sprite[z];
2917 if ((((spr->cstat&0x8000) == 0) || (showinvisibility)) &&
2918 (spr->xrepeat > 0) && (spr->yrepeat > 0) &&
2919 (spritesortcnt < MAXSPRITESONSCREEN))
2920 {
2921 xs = spr->x-globalposx; ys = spr->y-globalposy;
2922 if ((spr->cstat&48) || (xs*gcosang+ys*gsinang > 0))
2923 {
2924 copybufbyte(spr,&tsprite[spritesortcnt],sizeof(spritetype));
2925 tsprite[spritesortcnt++].owner = z;
2926 }
2927 }
2928 }
2929
2930 gotsector[sectnum>>3] |= pow2char[sectnum&7];
2931
2932 bunchfrst = numbunches;
2933 numscansbefore = numscans;
2934
2935 startwall = sector[sectnum].wallptr; endwall = sector[sectnum].wallnum+startwall;
2936 scanfirst = numscans;
2937 xp2 = 0; yp2 = 0;
2938 for(z=startwall,wal=&wall[z];z<endwall;z++,wal++)
2939 {
2940 wal2 = &wall[wal->point2];
2941 x1 = wal->x-globalposx; y1 = wal->y-globalposy;
2942 x2 = wal2->x-globalposx; y2 = wal2->y-globalposy;
2943
2944 nextsectnum = wal->nextsector; //Scan close sectors
2945 if ((nextsectnum >= 0) && (!(wal->cstat&32)) && (!(gotsector[nextsectnum>>3]&pow2char[nextsectnum&7])))
2946 {
2947 d = (double)x1*(double)y2 - (double)x2*(double)y1; xp1 = (double)(x2-x1); yp1 = (double)(y2-y1);
2948 if (d*d <= (xp1*xp1 + yp1*yp1)*(SCISDIST*SCISDIST*260.0))
2949 sectorborder[sectorbordercnt++] = nextsectnum;
2950 }
2951
2952 if ((z == startwall) || (wall[z-1].point2 != z))
2953 {
2954 xp1 = ((double)y1*(double)cosglobalang - (double)x1*(double)singlobalang )/64.0;
2955 yp1 = ((double)x1*(double)cosviewingrangeglobalang + (double)y1*(double)sinviewingrangeglobalang)/64.0;
2956 }
2957 else { xp1 = xp2; yp1 = yp2; }
2958 xp2 = ((double)y2*(double)cosglobalang - (double)x2*(double)singlobalang )/64.0;
2959 yp2 = ((double)x2*(double)cosviewingrangeglobalang + (double)y2*(double)sinviewingrangeglobalang)/64.0;
2960 if ((yp1 >= SCISDIST) || (yp2 >= SCISDIST))
2961 if ((double)xp1*(double)yp2 < (double)xp2*(double)yp1) //if wall is facing you...
2962 {
2963 if (yp1 >= SCISDIST)
2964 dxb1[numscans] = (double)xp1*ghalfx/(double)yp1 + ghalfx;
2965 else dxb1[numscans] = -1e32;
2966
2967 if (yp2 >= SCISDIST)
2968 dxb2[numscans] = (double)xp2*ghalfx/(double)yp2 + ghalfx;
2969 else dxb2[numscans] = 1e32;
2970
2971 if (dxb1[numscans] < dxb2[numscans])
2972 { thesector[numscans] = sectnum; thewall[numscans] = z; p2[numscans] = numscans+1; numscans++; }
2973 }
2974
2975 if ((wall[z].point2 < z) && (scanfirst < numscans))
2976 { p2[numscans-1] = scanfirst; scanfirst = numscans; }
2977 }
2978
2979 for(z=numscansbefore;z<numscans;z++)
2980 if ((wall[thewall[z]].point2 != thewall[p2[z]]) || (dxb2[z] > dxb1[p2[z]]))
2981 { bunchfirst[numbunches++] = p2[z]; p2[z] = -1; }
2982
2983 for(z=bunchfrst;z<numbunches;z++)
2984 {
2985 for(zz=bunchfirst[z];p2[zz]>=0;zz=p2[zz]);
2986 bunchlast[z] = zz;
2987 }
2988 } while (sectorbordercnt > 0);
2989 }
2990
polymost_drawrooms()2991 void polymost_drawrooms ()
2992 {
2993 int i, j, k, n, n2, closest;
2994 double ox, oy, oz, ox2, oy2, oz2, r, px[6], py[6], pz[6], px2[6], py2[6], pz2[6], sx[6], sy[6];
2995 static unsigned char tempbuf[MAXWALLS];
2996
2997 if (!rendmode) return;
2998
2999 begindrawing();
3000 frameoffset = frameplace + windowy1*bytesperline + windowx1;
3001
3002 #if USE_OPENGL
3003 if (rendmode == 3)
3004 {
3005 resizeglcheck();
3006
3007 //glfunc.glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
3008 //glfunc.glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); //default anyway
3009 glfunc.glEnable(GL_DEPTH_TEST);
3010 glfunc.glDepthFunc(GL_ALWAYS); //NEVER,LESS,(,L)EQUAL,GREATER,(NOT,G)EQUAL,ALWAYS
3011
3012 //glfunc.glPolygonOffset(1,1); //Supposed to make sprites pasted on walls or floors not disappear
3013 #if (USE_OPENGL == USE_GLES2)
3014 glfunc.glDepthRangef(0.00001f,1.f); //<- this is more widely supported than glPolygonOffset
3015 #else
3016 glfunc.glDepthRange(0.00001,1.0); //<- this is more widely supported than glPolygonOffset
3017 #endif
3018
3019 //Enable this for OpenGL red-blue glasses mode :)
3020 if (glredbluemode)
3021 {
3022 float m[4][4];
3023 static int grbfcnt = 0; grbfcnt++;
3024 if (redblueclearcnt < numpages) { redblueclearcnt++; glfunc.glColorMask(1,1,1,1); glfunc.glClear(GL_COLOR_BUFFER_BIT); }
3025 if (grbfcnt&1)
3026 {
3027 glfunc.glViewport(windowx1-16,yres-(windowy2+1),windowx2-(windowx1-16)+1,windowy2-windowy1+1);
3028 glfunc.glColorMask(1,0,0,1);
3029 globalposx += singlobalang/1024;
3030 globalposy -= cosglobalang/1024;
3031 }
3032 else
3033 {
3034 glfunc.glViewport(windowx1,yres-(windowy2+1),windowx2+16-windowx1+1,windowy2-windowy1+1);
3035 glfunc.glColorMask(0,1,1,1);
3036 globalposx -= singlobalang/1024;
3037 globalposy += cosglobalang/1024;
3038 }
3039 }
3040 }
3041 #endif
3042
3043 //Polymost supports true look up/down :) Here, we convert horizon to angle.
3044 //gchang&gshang are cos&sin of this angle (respectively)
3045 gyxscale = ((double)xdimenscale)/131072.0;
3046 gxyaspect = ((double)xyaspect*(double)viewingrange)*(5.0/(65536.0*262144.0));
3047 gviewxrange = ((double)viewingrange)*((double)xdimen)/(32768.0*1024.0);
3048 gcosang = ((double)cosglobalang)/262144.0;
3049 gsinang = ((double)singlobalang)/262144.0;
3050 gcosang2 = gcosang*((double)viewingrange)/65536.0;
3051 gsinang2 = gsinang*((double)viewingrange)/65536.0;
3052 ghalfx = (double)halfxdimen; grhalfxdown10 = 1.0/(((double)ghalfx)*1024);
3053 ghoriz = (double)globalhoriz;
3054
3055 gvisibility = ((float)globalvisibility)*gxyaspect*FOGSCALE;
3056
3057 //global cos/sin height angle
3058 r = (double)((ydimen>>1)-ghoriz);
3059 gshang = r/sqrt(r*r+ghalfx*ghalfx);
3060 gchang = sqrt(1.0-gshang*gshang);
3061 ghoriz = (double)(ydimen>>1);
3062
3063 //global cos/sin tilt angle
3064 gctang = cos(gtang);
3065 gstang = sin(gtang);
3066 if (fabs(gstang) < .001) //This hack avoids nasty precision bugs in domost()
3067 { gstang = 0; if (gctang > 0) gctang = 1.0; else gctang = -1.0; }
3068
3069 if (inpreparemirror)
3070 gstang = -gstang;
3071
3072 //Generate viewport trapezoid (for handling screen up/down)
3073 px[0] = px[3] = 0-1; px[1] = px[2] = windowx2+1-windowx1+2;
3074 py[0] = py[1] = 0-1; py[2] = py[3] = windowy2+1-windowy1+2; n = 4;
3075 for(i=0;i<n;i++)
3076 {
3077 ox = px[i]-ghalfx; oy = py[i]-ghoriz; oz = ghalfx;
3078
3079 //Tilt rotation (backwards)
3080 ox2 = ox*gctang + oy*gstang;
3081 oy2 = oy*gctang - ox*gstang;
3082 oz2 = oz;
3083
3084 //Up/down rotation (backwards)
3085 px[i] = ox2;
3086 py[i] = oy2*gchang + oz2*gshang;
3087 pz[i] = oz2*gchang - oy2*gshang;
3088 }
3089
3090 //Clip to SCISDIST plane
3091 n2 = 0;
3092 for(i=0;i<n;i++)
3093 {
3094 j = i+1; if (j >= n) j = 0;
3095 if (pz[i] >= SCISDIST) { px2[n2] = px[i]; py2[n2] = py[i]; pz2[n2] = pz[i]; n2++; }
3096 if ((pz[i] >= SCISDIST) != (pz[j] >= SCISDIST))
3097 {
3098 r = (SCISDIST-pz[i])/(pz[j]-pz[i]);
3099 px2[n2] = (px[j]-px[i])*r + px[i];
3100 py2[n2] = (py[j]-py[i])*r + py[i];
3101 pz2[n2] = SCISDIST; n2++;
3102 }
3103 }
3104 if (n2 < 3) { enddrawing(); return; }
3105 for(i=0;i<n2;i++)
3106 {
3107 r = ghalfx / pz2[i];
3108 sx[i] = px2[i]*r + ghalfx;
3109 sy[i] = py2[i]*r + ghoriz;
3110 }
3111 initmosts(sx,sy,n2);
3112
3113 if (searchit == 2)
3114 {
3115 short hitsect, hitwall, hitsprite;
3116 int vx, vy, vz, hitx, hity, hitz;
3117
3118 ox2 = searchx-ghalfx; oy2 = searchy-ghoriz; oz2 = ghalfx;
3119
3120 //Tilt rotation
3121 ox = ox2*gctang + oy2*gstang;
3122 oy = oy2*gctang - ox2*gstang;
3123 oz = oz2;
3124
3125 //Up/down rotation
3126 ox2 = oz*gchang - oy*gshang;
3127 oy2 = ox;
3128 oz2 = oy*gchang + oz*gshang;
3129
3130 //Standard Left/right rotation
3131 vx = (int)(ox2*((float)cosglobalang) - oy2*((float)singlobalang));
3132 vy = (int)(ox2*((float)singlobalang) + oy2*((float)cosglobalang));
3133 vz = (int)(oz2*16384.0);
3134
3135 hitallsprites = 1;
3136 hitscan(globalposx,globalposy,globalposz,globalcursectnum, //Start position
3137 vx>>12,vy>>12,vz>>8,&hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,0xffff0030);
3138 hitallsprites = 0;
3139
3140 searchsector = hitsect;
3141 if (hitwall >= 0)
3142 {
3143 searchwall = hitwall; searchstat = 0;
3144 if (wall[hitwall].nextwall >= 0)
3145 {
3146 int cz, fz;
3147 getzsofslope(wall[hitwall].nextsector,hitx,hity,&cz,&fz);
3148 if (hitz > fz)
3149 {
3150 if (wall[hitwall].cstat&2) //'2' bottoms of walls
3151 searchwall = wall[hitwall].nextwall;
3152 }
3153 else if ((hitz > cz) && (wall[hitwall].cstat&(16+32))) //masking or 1-way
3154 searchstat = 4;
3155 }
3156 }
3157 else if (hitsprite >= 0) { searchwall = hitsprite; searchstat = 3; }
3158 else
3159 {
3160 int cz, fz;
3161 getzsofslope(hitsect,hitx,hity,&cz,&fz);
3162 if ((hitz<<1) < cz+fz) searchstat = 1; else searchstat = 2;
3163 //if (vz < 0) searchstat = 1; else searchstat = 2; //Won't work for slopes :/
3164 }
3165 searchit = 0;
3166 }
3167
3168 numscans = numbunches = 0;
3169
3170 if (globalcursectnum >= MAXSECTORS)
3171 globalcursectnum -= MAXSECTORS;
3172 else
3173 {
3174 i = globalcursectnum;
3175 updatesector(globalposx,globalposy,&globalcursectnum);
3176 if (globalcursectnum < 0) globalcursectnum = i;
3177 }
3178
3179 polymost_scansector(globalcursectnum);
3180
3181 if (inpreparemirror)
3182 {
3183 grhalfxdown10x = -grhalfxdown10;
3184 inpreparemirror = 0;
3185 polymost_drawalls(0);
3186 numbunches--;
3187 bunchfirst[0] = bunchfirst[numbunches];
3188 bunchlast[0] = bunchlast[numbunches];
3189 }
3190 else
3191 grhalfxdown10x = grhalfxdown10;
3192
3193 while (numbunches > 0)
3194 {
3195 memset(tempbuf,0,numbunches+3); tempbuf[0] = 1;
3196
3197 closest = 0; //Almost works, but not quite :(
3198 for(i=1;i<numbunches;i++)
3199 {
3200 j = polymost_bunchfront(i,closest); if (j < 0) continue;
3201 tempbuf[i] = 1;
3202 if (!j) { tempbuf[closest] = 1; closest = i; }
3203 }
3204 for(i=0;i<numbunches;i++) //Double-check
3205 {
3206 if (tempbuf[i]) continue;
3207 j = polymost_bunchfront(i,closest); if (j < 0) continue;
3208 tempbuf[i] = 1;
3209 if (!j) { tempbuf[closest] = 1; closest = i; i = 0; }
3210 }
3211
3212 polymost_drawalls(closest);
3213
3214 if (automapping)
3215 {
3216 for(j=bunchfirst[closest];j>=0;j=p2[j])
3217 show2dwall[thewall[j]>>3] |= pow2char[thewall[j]&7];
3218 }
3219
3220 numbunches--;
3221 bunchfirst[closest] = bunchfirst[numbunches];
3222 bunchlast[closest] = bunchlast[numbunches];
3223 }
3224 #if USE_OPENGL
3225 if (rendmode == 3)
3226 {
3227 glfunc.glDepthFunc(GL_LEQUAL); //NEVER,LESS,(,L)EQUAL,GREATER,(NOT,G)EQUAL,ALWAYS
3228
3229 //glfunc.glPolygonOffset(0,0);
3230 #if (USE_OPENGL == USE_GLES2)
3231 glfunc.glDepthRangef(0.f,0.99999f); //<- this is more widely supported than glPolygonOffset
3232 #else
3233 glfunc.glDepthRange(0.0,0.99999); //<- this is more widely supported than glPolygonOffset
3234 #endif
3235 }
3236 #endif
3237
3238 enddrawing();
3239 }
3240
polymost_drawmaskwall(int damaskwallcnt)3241 void polymost_drawmaskwall (int damaskwallcnt)
3242 {
3243 double dpx[8], dpy[8], dpx2[8], dpy2[8];
3244 float fx, fy, x0, x1, sx0, sy0, sx1, sy1, xp0, yp0, xp1, yp1, oxp0, oyp0, ryp0, ryp1;
3245 float f, r, t, t0, t1, nx0, ny0, nx1, ny1, py[4], csy[4], fsy[4];
3246 int i, j, k, n, n2, x, z, sectnum, z1, z2, lx, rx, cz[4], fz[4], method;
3247 sectortype *sec, *nsec;
3248 walltype *wal, *wal2;
3249
3250 #ifdef DEBUGGINGAIDS
3251 polymostcallcounts.drawmaskwall++;
3252 #endif
3253
3254 z = maskwall[damaskwallcnt];
3255 wal = &wall[thewall[z]]; wal2 = &wall[wal->point2];
3256 sectnum = thesector[z]; sec = §or[sectnum];
3257 nsec = §or[wal->nextsector];
3258 z1 = max(nsec->ceilingz,sec->ceilingz);
3259 z2 = min(nsec->floorz,sec->floorz);
3260
3261 globalpicnum = wal->overpicnum; if ((unsigned int)globalpicnum >= MAXTILES) globalpicnum = 0;
3262 if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)thewall[z]+16384);
3263 globalshade = (int)wal->shade;
3264 globalpal = (int)((unsigned char)wal->pal);
3265 globalorientation = (int)wal->cstat;
3266
3267 sx0 = (float)(wal->x-globalposx); sx1 = (float)(wal2->x-globalposx);
3268 sy0 = (float)(wal->y-globalposy); sy1 = (float)(wal2->y-globalposy);
3269 yp0 = sx0*gcosang2 + sy0*gsinang2;
3270 yp1 = sx1*gcosang2 + sy1*gsinang2;
3271 if ((yp0 < SCISDIST) && (yp1 < SCISDIST)) return;
3272 xp0 = sy0*gcosang - sx0*gsinang;
3273 xp1 = sy1*gcosang - sx1*gsinang;
3274
3275 //Clip to close parallel-screen plane
3276 oxp0 = xp0; oyp0 = yp0;
3277 if (yp0 < SCISDIST) { t0 = (SCISDIST-yp0)/(yp1-yp0); xp0 = (xp1-xp0)*t0+xp0; yp0 = SCISDIST; }
3278 else t0 = 0.f;
3279 if (yp1 < SCISDIST) { t1 = (SCISDIST-oyp0)/(yp1-oyp0); xp1 = (xp1-oxp0)*t1+oxp0; yp1 = SCISDIST; }
3280 else { t1 = 1.f; }
3281
3282 getzsofslope(sectnum,(int)((wal2->x-wal->x)*t0+wal->x),(int)((wal2->y-wal->y)*t0+wal->y),&cz[0],&fz[0]);
3283 getzsofslope(wal->nextsector,(int)((wal2->x-wal->x)*t0+wal->x),(int)((wal2->y-wal->y)*t0+wal->y),&cz[1],&fz[1]);
3284 getzsofslope(sectnum,(int)((wal2->x-wal->x)*t1+wal->x),(int)((wal2->y-wal->y)*t1+wal->y),&cz[2],&fz[2]);
3285 getzsofslope(wal->nextsector,(int)((wal2->x-wal->x)*t1+wal->x),(int)((wal2->y-wal->y)*t1+wal->y),&cz[3],&fz[3]);
3286
3287 ryp0 = 1.f/yp0; ryp1 = 1.f/yp1;
3288
3289 //Generate screen coordinates for front side of wall
3290 x0 = ghalfx*xp0*ryp0 + ghalfx;
3291 x1 = ghalfx*xp1*ryp1 + ghalfx;
3292 if (x1 <= x0) return;
3293
3294 ryp0 *= gyxscale; ryp1 *= gyxscale;
3295
3296 gdx = (ryp0-ryp1)*gxyaspect / (x0-x1);
3297 gdy = 0;
3298 gdo = ryp0*gxyaspect - gdx*x0;
3299
3300 //gux*x0 + guo = t0*wal->xrepeat*8*yp0
3301 //gux*x1 + guo = t1*wal->xrepeat*8*yp1
3302 gux = (t0*ryp0 - t1*ryp1)*gxyaspect*(float)wal->xrepeat*8.f / (x0-x1);
3303 guo = t0*ryp0*gxyaspect*(float)wal->xrepeat*8.f - gux*x0;
3304 guo += (float)wal->xpanning*gdo;
3305 gux += (float)wal->xpanning*gdx;
3306 guy = 0;
3307
3308 if (!(wal->cstat&4)) i = z1; else i = z2;
3309 i -= globalposz;
3310 t0 = ((float)i)*ryp0 + ghoriz;
3311 t1 = ((float)i)*ryp1 + ghoriz;
3312 t = ((gdx*x0 + gdo) * (float)wal->yrepeat) / ((x1-x0) * ryp0 * 2048.f);
3313 i = (1<<(picsiz[globalpicnum]>>4)); if (i < tilesizy[globalpicnum]) i <<= 1;
3314 fy = (float)wal->ypanning * ((float)i) / 256.0;
3315 gvx = (t0-t1)*t;
3316 gvy = (x1-x0)*t;
3317 gvo = -gvx*x0 - gvy*t0 + fy*gdo; gvx += fy*gdx; gvy += fy*gdy;
3318
3319 if (wal->cstat&8) //xflip
3320 {
3321 t = (float)(wal->xrepeat*8 + wal->xpanning*2);
3322 gux = gdx*t - gux;
3323 guy = gdy*t - guy;
3324 guo = gdo*t - guo;
3325 }
3326 if (wal->cstat&256) { gvx = -gvx; gvy = -gvy; gvo = -gvo; } //yflip
3327
3328 method = METH_MASKED;
3329 if (wal->cstat&128) { if (!(wal->cstat&512)) method = METH_TRANS; else method = METH_INTRANS; }
3330 method |= METH_POW2XSPLIT | METH_LAYERS;
3331
3332 #if USE_OPENGL
3333 gfogpalnum = sec->floorpal;
3334 gfogdensity = gvisibility*((float)((unsigned char)(sec->visibility+16)) / 255.f);
3335 #endif
3336
3337 for(i=0;i<2;i++)
3338 {
3339 csy[i] = ((float)(cz[i]-globalposz))*ryp0 + ghoriz;
3340 fsy[i] = ((float)(fz[i]-globalposz))*ryp0 + ghoriz;
3341 csy[i+2] = ((float)(cz[i+2]-globalposz))*ryp1 + ghoriz;
3342 fsy[i+2] = ((float)(fz[i+2]-globalposz))*ryp1 + ghoriz;
3343 }
3344
3345 //Clip 2 quadrilaterals
3346 // /csy3
3347 // / |
3348 // csy0------/----csy2
3349 // | /xxxxxxx|
3350 // | /xxxxxxxxx|
3351 // csy1/xxxxxxxxxxx|
3352 // |xxxxxxxxxxx/fsy3
3353 // |xxxxxxxxx/ |
3354 // |xxxxxxx/ |
3355 // fsy0----/------fsy2
3356 // | /
3357 // fsy1/
3358
3359 dpx[0] = x0; dpy[0] = csy[1];
3360 dpx[1] = x1; dpy[1] = csy[3];
3361 dpx[2] = x1; dpy[2] = fsy[3];
3362 dpx[3] = x0; dpy[3] = fsy[1];
3363 n = 4;
3364
3365 //Clip to (x0,csy[0])-(x1,csy[2])
3366 n2 = 0; t1 = -((dpx[0]-x0)*(csy[2]-csy[0]) - (dpy[0]-csy[0])*(x1-x0));
3367 for(i=0;i<n;i++)
3368 {
3369 j = i+1; if (j >= n) j = 0;
3370
3371 t0 = t1; t1 = -((dpx[j]-x0)*(csy[2]-csy[0]) - (dpy[j]-csy[0])*(x1-x0));
3372 if (t0 >= 0) { dpx2[n2] = dpx[i]; dpy2[n2] = dpy[i]; n2++; }
3373 if ((t0 >= 0) != (t1 >= 0))
3374 {
3375 r = t0/(t0-t1);
3376 dpx2[n2] = (dpx[j]-dpx[i])*r + dpx[i];
3377 dpy2[n2] = (dpy[j]-dpy[i])*r + dpy[i];
3378 n2++;
3379 }
3380 }
3381 if (n2 < 3) return;
3382
3383 //Clip to (x1,fsy[2])-(x0,fsy[0])
3384 n = 0; t1 = -((dpx2[0]-x1)*(fsy[0]-fsy[2]) - (dpy2[0]-fsy[2])*(x0-x1));
3385 for(i=0;i<n2;i++)
3386 {
3387 j = i+1; if (j >= n2) j = 0;
3388
3389 t0 = t1; t1 = -((dpx2[j]-x1)*(fsy[0]-fsy[2]) - (dpy2[j]-fsy[2])*(x0-x1));
3390 if (t0 >= 0) { dpx[n] = dpx2[i]; dpy[n] = dpy2[i]; n++; }
3391 if ((t0 >= 0) != (t1 >= 0))
3392 {
3393 r = t0/(t0-t1);
3394 dpx[n] = (dpx2[j]-dpx2[i])*r + dpx2[i];
3395 dpy[n] = (dpy2[j]-dpy2[i])*r + dpy2[i];
3396 n++;
3397 }
3398 }
3399 if (n < 3) return;
3400
3401 drawpoly(dpx,dpy,n,method);
3402 }
3403
polymost_drawsprite(int snum)3404 void polymost_drawsprite (int snum)
3405 {
3406 double px[6], py[6];
3407 float f, r, c, s, fx, fy, sx0, sy0, sx1, sy1, xp0, yp0, xp1, yp1, oxp0, oyp0, ryp0, ryp1, ft[4];
3408 float x0, y0, x1, y1, sc0, sf0, sc1, sf1, px2[6], py2[6], xv, yv, t0, t1;
3409 int i, j, spritenum, xoff=0, yoff=0, method, npoints;
3410 spritetype *tspr;
3411
3412 #ifdef DEBUGGINGAIDS
3413 polymostcallcounts.drawsprite++;
3414 #endif
3415
3416 tspr = tspriteptr[snum];
3417 if (tspr->owner < 0 || tspr->picnum < 0) return;
3418
3419 globalpicnum = tspr->picnum;
3420 globalshade = tspr->shade;
3421 globalpal = tspr->pal;
3422 globalorientation = tspr->cstat;
3423 spritenum = tspr->owner;
3424
3425 if ((globalorientation&48) != 48) { // only non-voxel sprites should do this
3426 if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,spritenum+32768);
3427
3428 xoff = (int)((signed char)((picanm[globalpicnum]>>8)&255))+((int)tspr->xoffset);
3429 yoff = (int)((signed char)((picanm[globalpicnum]>>16)&255))+((int)tspr->yoffset);
3430 }
3431
3432 method = METH_MASKED;
3433 if (tspr->cstat&2) { if (!(tspr->cstat&512)) method = METH_TRANS; else method = METH_INTRANS; }
3434 method |= METH_CLAMPED | METH_LAYERS;
3435
3436 #if USE_OPENGL
3437 gfogpalnum = sector[tspr->sectnum].floorpal;
3438 gfogdensity = gvisibility*((float)((unsigned char)(sector[tspr->sectnum].visibility+16)) / 255.f);
3439
3440 while (rendmode == 3 && !(spriteext[tspr->owner].flags&SPREXT_NOTMD)) {
3441 if (usemodels && tile2model[tspr->picnum].modelid >= 0 && tile2model[tspr->picnum].framenum >= 0) {
3442 if (mddraw(tspr, 0)) {
3443 if (automapping == 1) show2dsprite[spritenum>>3] |= pow2char[spritenum&7];
3444 return;
3445 }
3446 break; // else, render as flat sprite
3447 }
3448 if (usevoxels && (tspr->cstat&48)!=48 && tiletovox[tspr->picnum] >= 0 && voxmodels[ tiletovox[tspr->picnum] ]) {
3449 if (voxdraw(voxmodels[ tiletovox[tspr->picnum] ], tspr, 0)) {
3450 if (automapping == 1) show2dsprite[spritenum>>3] |= pow2char[spritenum&7];
3451 return;
3452 }
3453 break; // else, render as flat sprite
3454 }
3455 if ((tspr->cstat&48)==48 && voxmodels[ tspr->picnum ]) {
3456 voxdraw(voxmodels[ tspr->picnum ], tspr, 0);
3457 if (automapping == 1) show2dsprite[spritenum>>3] |= pow2char[spritenum&7];
3458 return;
3459 }
3460 break;
3461 }
3462 #endif
3463
3464 switch((globalorientation>>4)&3)
3465 {
3466 case 0: //Face sprite
3467
3468 //Project 3D to 2D
3469 sx0 = (float)(tspr->x-globalposx);
3470 sy0 = (float)(tspr->y-globalposy);
3471 xp0 = sy0*gcosang - sx0*gsinang;
3472 yp0 = sx0*gcosang2 + sy0*gsinang2;
3473 if (yp0 <= SCISDIST) return;
3474 ryp0 = 1/yp0;
3475 sx0 = ghalfx*xp0*ryp0 + ghalfx;
3476 sy0 = ((float)(tspr->z-globalposz))*gyxscale*ryp0 + ghoriz;
3477
3478 f = ryp0*(float)xdimen/160.0;
3479 fx = ((float)tspr->xrepeat)*f;
3480 fy = ((float)tspr->yrepeat)*f*((float)yxaspect/65536.0);
3481 sx0 -= fx*(float)xoff; if (tilesizx[globalpicnum]&1) sx0 += fx*.5;
3482 sy0 -= fy*(float)yoff;
3483 fx *= ((float)tilesizx[globalpicnum]);
3484 fy *= ((float)tilesizy[globalpicnum]);
3485
3486 px[0] = px[3] = sx0-fx*.5; px[1] = px[2] = sx0+fx*.5;
3487 if (!(globalorientation&128)) { py[0] = py[1] = sy0-fy; py[2] = py[3] = sy0; }
3488 else { py[0] = py[1] = sy0-fy*.5; py[2] = py[3] = sy0+fy*.5; }
3489
3490 gdx = gdy = guy = gvx = 0; gdo = ryp0*gviewxrange;
3491 if (!(globalorientation&4))
3492 { gux = (float)tilesizx[globalpicnum]*gdo/(px[1]-px[0]+.002); guo = -gux*(px[0]-.001); }
3493 else { gux = (float)tilesizx[globalpicnum]*gdo/(px[0]-px[1]-.002); guo = -gux*(px[1]+.001); }
3494 if (!(globalorientation&8))
3495 { gvy = (float)tilesizy[globalpicnum]*gdo/(py[3]-py[0]+.002); gvo = -gvy*(py[0]-.001); }
3496 else { gvy = (float)tilesizy[globalpicnum]*gdo/(py[0]-py[3]-.002); gvo = -gvy*(py[3]+.001); }
3497
3498 //Clip sprites to ceilings/floors when no parallaxing and not sloped
3499 if (!(sector[tspr->sectnum].ceilingstat&3))
3500 {
3501 sy0 = ((float)(sector[tspr->sectnum].ceilingz-globalposz))*gyxscale*ryp0 + ghoriz;
3502 if (py[0] < sy0) py[0] = py[1] = sy0;
3503 }
3504 if (!(sector[tspr->sectnum].floorstat&3))
3505 {
3506 sy0 = ((float)(sector[tspr->sectnum].floorz-globalposz))*gyxscale*ryp0 + ghoriz;
3507 if (py[2] > sy0) py[2] = py[3] = sy0;
3508 }
3509
3510 drawpoly(px,py,4,method);
3511 break;
3512 case 1: //Wall sprite
3513
3514 //Project 3D to 2D
3515 if (globalorientation&4) xoff = -xoff;
3516 if (globalorientation&8) yoff = -yoff;
3517
3518 xv = (float)tspr->xrepeat * (float)sintable[(tspr->ang )&2047] / 65536.0;
3519 yv = (float)tspr->xrepeat * (float)sintable[(tspr->ang+1536)&2047] / 65536.0;
3520 f = (float)(tilesizx[globalpicnum]>>1) + (float)xoff;
3521 x0 = (float)(tspr->x-globalposx) - xv*f; x1 = xv*(float)tilesizx[globalpicnum] + x0;
3522 y0 = (float)(tspr->y-globalposy) - yv*f; y1 = yv*(float)tilesizx[globalpicnum] + y0;
3523
3524 yp0 = x0*gcosang2 + y0*gsinang2;
3525 yp1 = x1*gcosang2 + y1*gsinang2;
3526 if ((yp0 <= SCISDIST) && (yp1 <= SCISDIST)) return;
3527 xp0 = y0*gcosang - x0*gsinang;
3528 xp1 = y1*gcosang - x1*gsinang;
3529
3530 //Clip to close parallel-screen plane
3531 oxp0 = xp0; oyp0 = yp0;
3532 if (yp0 < SCISDIST) { t0 = (SCISDIST-yp0)/(yp1-yp0); xp0 = (xp1-xp0)*t0+xp0; yp0 = SCISDIST; }
3533 else { t0 = 0.f; }
3534 if (yp1 < SCISDIST) { t1 = (SCISDIST-oyp0)/(yp1-oyp0); xp1 = (xp1-oxp0)*t1+oxp0; yp1 = SCISDIST; }
3535 else { t1 = 1.f; }
3536
3537 f = ((float)tspr->yrepeat) * (float)tilesizy[globalpicnum] * 4;
3538
3539 ryp0 = 1.0/yp0;
3540 ryp1 = 1.0/yp1;
3541 sx0 = ghalfx*xp0*ryp0 + ghalfx;
3542 sx1 = ghalfx*xp1*ryp1 + ghalfx;
3543 ryp0 *= gyxscale;
3544 ryp1 *= gyxscale;
3545
3546 tspr->z -= ((yoff*tspr->yrepeat)<<2);
3547 if (globalorientation&128)
3548 {
3549 tspr->z += ((tilesizy[globalpicnum]*tspr->yrepeat)<<1);
3550 if (tilesizy[globalpicnum]&1) tspr->z += (tspr->yrepeat<<1); //Odd yspans
3551 }
3552
3553 sc0 = ((float)(tspr->z-globalposz-f))*ryp0 + ghoriz;
3554 sc1 = ((float)(tspr->z-globalposz-f))*ryp1 + ghoriz;
3555 sf0 = ((float)(tspr->z-globalposz))*ryp0 + ghoriz;
3556 sf1 = ((float)(tspr->z-globalposz))*ryp1 + ghoriz;
3557
3558 gdx = (ryp0-ryp1)*gxyaspect / (sx0-sx1);
3559 gdy = 0;
3560 gdo = ryp0*gxyaspect - gdx*sx0;
3561
3562 //Original equations:
3563 //(gux*sx0 + guo)/(gdx*sx1 + gdo) = tilesizx[globalpicnum]*t0
3564 //(gux*sx1 + guo)/(gdx*sx1 + gdo) = tilesizx[globalpicnum]*t1
3565 //
3566 // gvx*sx0 + gvy*sc0 + gvo = 0
3567 // gvy*sx1 + gvy*sc1 + gvo = 0
3568 //(gvx*sx0 + gvy*sf0 + gvo)/(gdx*sx0 + gdo) = tilesizy[globalpicnum]
3569 //(gvx*sx1 + gvy*sf1 + gvo)/(gdx*sx1 + gdo) = tilesizy[globalpicnum]
3570
3571 //gux*sx0 + guo = t0*tilesizx[globalpicnum]*yp0
3572 //gux*sx1 + guo = t1*tilesizx[globalpicnum]*yp1
3573 if (globalorientation&4) { t0 = 1.f-t0; t1 = 1.f-t1; }
3574 gux = (t0*ryp0 - t1*ryp1)*gxyaspect*(float)tilesizx[globalpicnum] / (sx0-sx1);
3575 guy = 0;
3576 guo = t0*ryp0*gxyaspect*(float)tilesizx[globalpicnum] - gux*sx0;
3577
3578 //gvx*sx0 + gvy*sc0 + gvo = 0
3579 //gvx*sx1 + gvy*sc1 + gvo = 0
3580 //gvx*sx0 + gvy*sf0 + gvo = tilesizy[globalpicnum]*(gdx*sx0 + gdo)
3581 f = ((float)tilesizy[globalpicnum])*(gdx*sx0 + gdo) / ((sx0-sx1)*(sc0-sf0));
3582 if (!(globalorientation&8))
3583 {
3584 gvx = (sc0-sc1)*f;
3585 gvy = (sx1-sx0)*f;
3586 gvo = -gvx*sx0 - gvy*sc0;
3587 }
3588 else
3589 {
3590 gvx = (sf1-sf0)*f;
3591 gvy = (sx0-sx1)*f;
3592 gvo = -gvx*sx0 - gvy*sf0;
3593 }
3594
3595 //Clip sprites to ceilings/floors when no parallaxing
3596 if (!(sector[tspr->sectnum].ceilingstat&1))
3597 {
3598 f = ((float)tspr->yrepeat) * (float)tilesizy[globalpicnum] * 4;
3599 if (sector[tspr->sectnum].ceilingz > tspr->z-f)
3600 {
3601 sc0 = ((float)(sector[tspr->sectnum].ceilingz-globalposz))*ryp0 + ghoriz;
3602 sc1 = ((float)(sector[tspr->sectnum].ceilingz-globalposz))*ryp1 + ghoriz;
3603 }
3604 }
3605 if (!(sector[tspr->sectnum].floorstat&1))
3606 {
3607 if (sector[tspr->sectnum].floorz < tspr->z)
3608 {
3609 sf0 = ((float)(sector[tspr->sectnum].floorz-globalposz))*ryp0 + ghoriz;
3610 sf1 = ((float)(sector[tspr->sectnum].floorz-globalposz))*ryp1 + ghoriz;
3611 }
3612 }
3613
3614 if (sx0 > sx1)
3615 {
3616 if (globalorientation&64) return; //1-sided sprite
3617 f = sx0; sx0 = sx1; sx1 = f;
3618 f = sc0; sc0 = sc1; sc1 = f;
3619 f = sf0; sf0 = sf1; sf1 = f;
3620 }
3621
3622 px[0] = sx0; py[0] = sc0;
3623 px[1] = sx1; py[1] = sc1;
3624 px[2] = sx1; py[2] = sf1;
3625 px[3] = sx0; py[3] = sf0;
3626 drawpoly(px,py,4,method);
3627 break;
3628 case 2: //Floor sprite
3629
3630 if ((globalorientation&64) != 0)
3631 if ((globalposz > tspr->z) == (!(globalorientation&8)))
3632 return;
3633 if ((globalorientation&4) > 0) xoff = -xoff;
3634 if ((globalorientation&8) > 0) yoff = -yoff;
3635
3636 i = (tspr->ang&2047);
3637 c = sintable[(i+512)&2047]/65536.0;
3638 s = sintable[i]/65536.0;
3639 x0 = ((tilesizx[globalpicnum]>>1)-xoff)*tspr->xrepeat;
3640 y0 = ((tilesizy[globalpicnum]>>1)-yoff)*tspr->yrepeat;
3641 x1 = ((tilesizx[globalpicnum]>>1)+xoff)*tspr->xrepeat;
3642 y1 = ((tilesizy[globalpicnum]>>1)+yoff)*tspr->yrepeat;
3643
3644 //Project 3D to 2D
3645 for(j=0;j<4;j++)
3646 {
3647 sx0 = (float)(tspr->x-globalposx);
3648 sy0 = (float)(tspr->y-globalposy);
3649 if ((j+0)&2) { sy0 -= s*y0; sx0 -= c*y0; } else { sy0 += s*y1; sx0 += c*y1; }
3650 if ((j+1)&2) { sx0 -= s*x0; sy0 += c*x0; } else { sx0 += s*x1; sy0 -= c*x1; }
3651 px[j] = sy0*gcosang - sx0*gsinang;
3652 py[j] = sx0*gcosang2 + sy0*gsinang2;
3653 }
3654
3655 if (tspr->z < globalposz) //if floor sprite is above you, reverse order of points
3656 {
3657 f = px[0]; px[0] = px[1]; px[1] = f;
3658 f = py[0]; py[0] = py[1]; py[1] = f;
3659 f = px[2]; px[2] = px[3]; px[3] = f;
3660 f = py[2]; py[2] = py[3]; py[3] = f;
3661 }
3662
3663 //Clip to SCISDIST plane
3664 npoints = 0;
3665 for(i=0;i<4;i++)
3666 {
3667 j = ((i+1)&3);
3668 if (py[i] >= SCISDIST) { px2[npoints] = px[i]; py2[npoints] = py[i]; npoints++; }
3669 if ((py[i] >= SCISDIST) != (py[j] >= SCISDIST))
3670 {
3671 f = (SCISDIST-py[i])/(py[j]-py[i]);
3672 px2[npoints] = (px[j]-px[i])*f + px[i];
3673 py2[npoints] = (py[j]-py[i])*f + py[i]; npoints++;
3674 }
3675 }
3676 if (npoints < 3) return;
3677
3678 //Project rotated 3D points to screen
3679 f = ((float)(tspr->z-globalposz))*gyxscale;
3680 for(j=0;j<npoints;j++)
3681 {
3682 ryp0 = 1/py2[j];
3683 px[j] = ghalfx*px2[j]*ryp0 + ghalfx;
3684 py[j] = f*ryp0 + ghoriz;
3685 }
3686
3687 //gd? Copied from floor rendering code
3688 gdx = 0;
3689 gdy = gxyaspect / (double)(tspr->z-globalposz);
3690 gdo = -ghoriz*gdy;
3691 //copied&modified from relative alignment
3692 xv = (float)tspr->x + s*x1 + c*y1; fx = (double)-(x0+x1)*s;
3693 yv = (float)tspr->y + s*y1 - c*x1; fy = (double)+(x0+x1)*c;
3694 f = 1.0/sqrt(fx*fx+fy*fy); fx *= f; fy *= f;
3695 ft[2] = singlobalang*fy + cosglobalang*fx;
3696 ft[3] = singlobalang*fx - cosglobalang*fy;
3697 ft[0] = ((double)(globalposy-yv))*fy + ((double)(globalposx-xv))*fx;
3698 ft[1] = ((double)(globalposx-xv))*fy - ((double)(globalposy-yv))*fx;
3699 gux = (double)ft[3]*((double)viewingrange)/(-65536.0*262144.0);
3700 gvx = (double)ft[2]*((double)viewingrange)/(-65536.0*262144.0);
3701 guy = (double)ft[0]*gdy; gvy = (double)ft[1]*gdy;
3702 guo = (double)ft[0]*gdo; gvo = (double)ft[1]*gdo;
3703 guo += (double)(ft[2]/262144.0-gux)*ghalfx;
3704 gvo -= (double)(ft[3]/262144.0+gvx)*ghalfx;
3705 f = 4.0/(float)tspr->xrepeat; gux *= f; guy *= f; guo *= f;
3706 f =-4.0/(float)tspr->yrepeat; gvx *= f; gvy *= f; gvo *= f;
3707 if (globalorientation&4)
3708 {
3709 gux = ((float)tilesizx[globalpicnum])*gdx - gux;
3710 guy = ((float)tilesizx[globalpicnum])*gdy - guy;
3711 guo = ((float)tilesizx[globalpicnum])*gdo - guo;
3712 }
3713
3714 drawpoly(px,py,npoints,method);
3715 break;
3716
3717 case 3: //Voxel sprite
3718 break;
3719 }
3720 if (automapping == 1) show2dsprite[spritenum>>3] |= pow2char[spritenum&7];
3721 }
3722
3723 //sx,sy center of sprite; screen coods*65536
3724 //z zoom*65536. > is zoomed in
3725 //a angle (0 is default)
3726 //dastat&1 1:translucence
3727 //dastat&2 1:auto-scale mode (use 320*200 coordinates)
3728 //dastat&4 1:y-flip
3729 //dastat&8 1:don't clip to startumost/startdmost
3730 //dastat&16 1:force point passed to be top-left corner, 0:Editart center
3731 //dastat&32 1:reverse translucence
3732 //dastat&64 1:non-masked, 0:masked
3733 //dastat&128 1:draw all pages (permanent)
3734 //cx1,... clip window (actual screen coords)
polymost_dorotatesprite(int sx,int sy,int z,short a,short picnum,signed char dashade,unsigned char dapalnum,unsigned char dastat,int cx1,int cy1,int cx2,int cy2,int uniqid)3735 void polymost_dorotatesprite (int sx, int sy, int z, short a, short picnum,
3736 signed char dashade, unsigned char dapalnum, unsigned char dastat, int cx1, int cy1, int cx2, int cy2, int uniqid)
3737 {
3738 static int onumframes = 0;
3739 int i, n, nn, x, zz, xoff, yoff, xsiz, ysiz, method;
3740 int ogpicnum, ogshade, ogpal, ofoffset, oxdimen, oydimen, oldviewingrange;
3741 double ogxyaspect, ogfogdensity;
3742 double ogchang, ogshang, ogctang, ogstang, oghalfx, oghoriz, fx, fy, x1, y1, z1, x2, y2;
3743 double ogrhalfxdown10, ogrhalfxdown10x;
3744 double d, cosang, sinang, cosang2, sinang2, px[8], py[8], px2[8], py2[8];
3745 float m[4][4];
3746
3747 #if USE_OPENGL
3748 if (rendmode == 3 && usemodels && hudmem[(dastat&4)>>2][picnum].angadd)
3749 {
3750 if ((tile2model[picnum].modelid >= 0) && (tile2model[picnum].framenum >= 0))
3751 {
3752 spritetype tspr;
3753 memset(&tspr,0,sizeof(spritetype));
3754
3755 if (hudmem[(dastat&4)>>2][picnum].flags&1) return; //"HIDE" is specified in DEF
3756
3757 ogchang = gchang; gchang = 1.0;
3758 ogshang = gshang; gshang = 0.0; d = (double)z/(65536.0*16384.0);
3759 ogctang = gctang; gctang = (double)sintable[(a+512)&2047]*d;
3760 ogstang = gstang; gstang = (double)sintable[a&2047]*d;
3761 ogshade = globalshade; globalshade = dashade;
3762 ogpal = globalpal; globalpal = (int)((unsigned char)dapalnum);
3763 ogxyaspect = gxyaspect; gxyaspect = 1.0;
3764 ogfogdensity = gfogdensity; gfogdensity = 0.0;
3765 oldviewingrange = viewingrange; viewingrange = 65536;
3766
3767 x1 = hudmem[(dastat&4)>>2][picnum].xadd;
3768 y1 = hudmem[(dastat&4)>>2][picnum].yadd;
3769 z1 = hudmem[(dastat&4)>>2][picnum].zadd;
3770 if (!(hudmem[(dastat&4)>>2][picnum].flags&2)) //"NOBOB" is specified in DEF
3771 {
3772 fx = ((double)sx)*(1.0/65536.0);
3773 fy = ((double)sy)*(1.0/65536.0);
3774
3775 if (dastat&16)
3776 {
3777 xsiz = tilesizx[picnum]; ysiz = tilesizy[picnum];
3778 xoff = (int)((signed char)((picanm[picnum]>>8)&255))+(xsiz>>1);
3779 yoff = (int)((signed char)((picanm[picnum]>>16)&255))+(ysiz>>1);
3780
3781 d = (double)z/(65536.0*16384.0);
3782 cosang2 = cosang = (double)sintable[(a+512)&2047]*d;
3783 sinang2 = sinang = (double)sintable[a&2047]*d;
3784 if ((dastat&2) || (!(dastat&8))) //Don't aspect unscaled perms
3785 { d = (double)xyaspect/65536.0; cosang2 *= d; sinang2 *= d; }
3786 fx += -(double)xoff*cosang2+ (double)yoff*sinang2;
3787 fy += -(double)xoff*sinang - (double)yoff*cosang;
3788 }
3789
3790 if (!(dastat&2))
3791 {
3792 x1 += fx/((double)(xdim<<15))-1.0; //-1: left of screen, +1: right of screen
3793 y1 += fy/((double)(ydim<<15))-1.0; //-1: top of screen, +1: bottom of screen
3794 }
3795 else
3796 {
3797 x1 += fx/160.0-1.0; //-1: left of screen, +1: right of screen
3798 y1 += fy/100.0-1.0; //-1: top of screen, +1: bottom of screen
3799 }
3800 }
3801 tspr.ang = hudmem[(dastat&4)>>2][picnum].angadd+globalang;
3802 tspr.xrepeat = tspr.yrepeat = 32;
3803
3804 if (dastat&4) { x1 = -x1; y1 = -y1; }
3805 tspr.x = (int)(((double)gcosang*z1 - (double)gsinang*x1)*16384.0 + globalposx);
3806 tspr.y = (int)(((double)gsinang*z1 + (double)gcosang*x1)*16384.0 + globalposy);
3807 tspr.z = (int)(globalposz + y1*16384.0*0.8);
3808 tspr.picnum = picnum;
3809 tspr.shade = dashade;
3810 tspr.pal = dapalnum;
3811 tspr.owner = uniqid+MAXSPRITES;
3812 globalorientation = (dastat&1)+((dastat&32)<<4)+((dastat&4)<<1);
3813
3814 if ((dastat&10) == 2) glfunc.glViewport(windowx1,yres-(windowy2+1),windowx2-windowx1+1,windowy2-windowy1+1);
3815 else { glfunc.glViewport(0,0,xdim,ydim); glox1 = -1; } //Force fullscreen (glox1=-1 forces it to restore)
3816
3817 if (hudmem[(dastat&4)>>2][picnum].flags&8) //NODEPTH flag
3818 glfunc.glDisable(GL_DEPTH_TEST);
3819 else
3820 {
3821 glfunc.glEnable(GL_DEPTH_TEST);
3822 if (onumframes != numframes)
3823 {
3824 onumframes = numframes;
3825 glfunc.glClear(GL_DEPTH_BUFFER_BIT);
3826 }
3827 }
3828
3829 mddraw(&tspr, !!((dastat&10) != 2));
3830
3831 viewingrange = oldviewingrange;
3832 gfogdensity = ogfogdensity;
3833 gxyaspect = ogxyaspect;
3834 globalshade = ogshade;
3835 globalpal = ogpal;
3836 gchang = ogchang;
3837 gshang = ogshang;
3838 gctang = ogctang;
3839 gstang = ogstang;
3840 return;
3841 }
3842 }
3843 #endif
3844
3845 ogpicnum = globalpicnum; globalpicnum = picnum;
3846 ogshade = globalshade; globalshade = dashade;
3847 ogpal = globalpal; globalpal = (int)((unsigned char)dapalnum);
3848 oghalfx = ghalfx; ghalfx = (double)(xdim>>1);
3849 ogrhalfxdown10 = grhalfxdown10; grhalfxdown10 = 1.0/(((double)ghalfx)*1024);
3850 ogrhalfxdown10x = grhalfxdown10x; grhalfxdown10x = grhalfxdown10;
3851 oghoriz = ghoriz; ghoriz = (double)(ydim>>1);
3852 ofoffset = frameoffset; frameoffset = frameplace;
3853 oxdimen = xdimen; xdimen = xdim;
3854 oydimen = ydimen; ydimen = ydim;
3855 ogchang = gchang; gchang = 1.0;
3856 ogshang = gshang; gshang = 0.0;
3857 ogctang = gctang; gctang = 1.0;
3858 ogstang = gstang; gstang = 0.0;
3859
3860 #if USE_OPENGL
3861 if (rendmode == 3)
3862 {
3863 glfunc.glViewport(0,0,xdim,ydim); glox1 = -1; //Force fullscreen (glox1=-1 forces it to restore)
3864 glfunc.glDisable(GL_DEPTH_TEST);
3865 }
3866 #endif
3867
3868 method = METH_SOLID;
3869 if (!(dastat&64))
3870 {
3871 method = METH_MASKED;
3872 if (dastat&1) { if (!(dastat&32)) method = METH_TRANS; else method = METH_INTRANS; }
3873 }
3874 method |= METH_CLAMPED; //Use OpenGL clamping - dorotatesprite never repeats
3875 method |= METH_ROTATESPRITE; //Use rotatesprite projection
3876
3877 xsiz = tilesizx[globalpicnum]; ysiz = tilesizy[globalpicnum];
3878 if (dastat&16) { xoff = 0; yoff = 0; }
3879 else
3880 {
3881 xoff = (int)((signed char)((picanm[globalpicnum]>>8)&255))+(xsiz>>1);
3882 yoff = (int)((signed char)((picanm[globalpicnum]>>16)&255))+(ysiz>>1);
3883 }
3884 if (dastat&4) yoff = ysiz-yoff;
3885
3886 if (dastat&2) //Auto window size scaling
3887 {
3888 if (!(dastat&8))
3889 {
3890 if (widescreen) {
3891 x = ydimenscale; //= scale(xdimen,yxaspect,320);
3892 sx = ((cx1+cx2+2)<<15)+scale(sx-(320<<15),oydimen<<16,200*pixelaspect);
3893 } else {
3894 x = xdimenscale; //= scale(xdimen,yxaspect,320);
3895 sx = ((cx1+cx2+2)<<15)+scale(sx-(320<<15),oxdimen,320);
3896 }
3897 sy = ((cy1+cy2+2)<<15)+mulscale16(sy-(200<<15),x);
3898 }
3899 else
3900 {
3901 //If not clipping to startmosts, & auto-scaling on, as a
3902 //hard-coded bonus, scale to full screen instead
3903 if (widescreen) {
3904 x = scale(ydim<<16,yxaspect,200*pixelaspect);
3905 sx = (xdim<<15)+32768+scale(sx-(320<<15),ydim<<16,200*pixelaspect);
3906 } else {
3907 x = scale(xdim,yxaspect,320);
3908 sx = (xdim<<15)+32768+scale(sx-(320<<15),xdim,320);
3909 }
3910 sy = (ydim<<15)+32768+mulscale16(sy-(200<<15),x);
3911 }
3912 z = mulscale16(z,x);
3913 }
3914
3915 d = (double)z/(65536.0*16384.0);
3916 cosang2 = cosang = (double)sintable[(a+512)&2047]*d;
3917 sinang2 = sinang = (double)sintable[a&2047]*d;
3918 if ((dastat&2) || (!(dastat&8))) //Don't aspect unscaled perms
3919 { d = (double)xyaspect/65536.0; cosang2 *= d; sinang2 *= d; }
3920 px[0] = (double)sx/65536.0 - (double)xoff*cosang2+ (double)yoff*sinang2;
3921 py[0] = (double)sy/65536.0 - (double)xoff*sinang - (double)yoff*cosang;
3922 px[1] = px[0] + (double)xsiz*cosang2;
3923 py[1] = py[0] + (double)xsiz*sinang;
3924 px[3] = px[0] - (double)ysiz*sinang2;
3925 py[3] = py[0] + (double)ysiz*cosang;
3926 px[2] = px[1]+px[3]-px[0];
3927 py[2] = py[1]+py[3]-py[0];
3928 n = 4;
3929
3930 gdx = 0; gdy = 0; gdo = 1.0;
3931 //px[0]*gux + py[0]*guy + guo = 0
3932 //px[1]*gux + py[1]*guy + guo = xsiz-.0001
3933 //px[3]*gux + py[3]*guy + guo = 0
3934 d = 1.0/(px[0]*(py[1]-py[3]) + px[1]*(py[3]-py[0]) + px[3]*(py[0]-py[1]));
3935 gux = (py[3]-py[0])*((double)xsiz-.0001)*d;
3936 guy = (px[0]-px[3])*((double)xsiz-.0001)*d;
3937 guo = 0 - px[0]*gux - py[0]*guy;
3938
3939 if (!(dastat&4))
3940 { //px[0]*gvx + py[0]*gvy + gvo = 0
3941 //px[1]*gvx + py[1]*gvy + gvo = 0
3942 //px[3]*gvx + py[3]*gvy + gvo = ysiz-.0001
3943 gvx = (py[0]-py[1])*((double)ysiz-.0001)*d;
3944 gvy = (px[1]-px[0])*((double)ysiz-.0001)*d;
3945 gvo = 0 - px[0]*gvx - py[0]*gvy;
3946 }
3947 else
3948 { //px[0]*gvx + py[0]*gvy + gvo = ysiz-.0001
3949 //px[1]*gvx + py[1]*gvy + gvo = ysiz-.0001
3950 //px[3]*gvx + py[3]*gvy + gvo = 0
3951 gvx = (py[1]-py[0])*((double)ysiz-.0001)*d;
3952 gvy = (px[0]-px[1])*((double)ysiz-.0001)*d;
3953 gvo = (double)ysiz-.0001 - px[0]*gvx - py[0]*gvy;
3954 }
3955
3956 cx2++; cy2++;
3957 //Clippoly4 (converted from int to double)
3958 nn = z = 0;
3959 do
3960 {
3961 zz = z+1; if (zz == n) zz = 0;
3962 x1 = px[z]; x2 = px[zz]-x1; if ((cx1 <= x1) && (x1 <= cx2)) { px2[nn] = x1; py2[nn] = py[z]; nn++; }
3963 if (x2 <= 0) fx = cx2; else fx = cx1; d = fx-x1;
3964 if ((d < x2) != (d < 0)) { px2[nn] = fx; py2[nn] = (py[zz]-py[z])*d/x2 + py[z]; nn++; }
3965 if (x2 <= 0) fx = cx1; else fx = cx2; d = fx-x1;
3966 if ((d < x2) != (d < 0)) { px2[nn] = fx; py2[nn] = (py[zz]-py[z])*d/x2 + py[z]; nn++; }
3967 z = zz;
3968 } while (z);
3969 if (nn >= 3)
3970 {
3971 n = z = 0;
3972 do
3973 {
3974 zz = z+1; if (zz == nn) zz = 0;
3975 y1 = py2[z]; y2 = py2[zz]-y1; if ((cy1 <= y1) && (y1 <= cy2)) { py[n] = y1; px[n] = px2[z]; n++; }
3976 if (y2 <= 0) fy = cy2; else fy = cy1; d = fy-y1;
3977 if ((d < y2) != (d < 0)) { py[n] = fy; px[n] = (px2[zz]-px2[z])*d/y2 + px2[z]; n++; }
3978 if (y2 <= 0) fy = cy1; else fy = cy2; d = fy-y1;
3979 if ((d < y2) != (d < 0)) { py[n] = fy; px[n] = (px2[zz]-px2[z])*d/y2 + px2[z]; n++; }
3980 z = zz;
3981 } while (z);
3982 drawpoly(px,py,n,method);
3983 }
3984
3985 globalpicnum = ogpicnum;
3986 globalshade = ogshade;
3987 globalpal = ogpal;
3988 ghalfx = oghalfx;
3989 grhalfxdown10 = ogrhalfxdown10;
3990 grhalfxdown10x = ogrhalfxdown10x;
3991 ghoriz = oghoriz;
3992 frameoffset = ofoffset;
3993 xdimen = oxdimen;
3994 ydimen = oydimen;
3995 gchang = ogchang;
3996 gshang = ogshang;
3997 gctang = ogctang;
3998 gstang = ogstang;
3999 }
4000
4001 #if USE_OPENGL
4002
4003 static float trapextx[2];
drawtrap(float x0,float x1,float y0,float x2,float x3,float y1,struct polymostdrawpolycall * draw)4004 static void drawtrap (float x0, float x1, float y0, float x2, float x3, float y1,
4005 struct polymostdrawpolycall *draw)
4006 {
4007 float px[4], py[4];
4008 int i, n;
4009 struct polymostvboitem vboitem[4];
4010
4011 if (y0 == y1) return;
4012 px[0] = x0; py[0] = y0; py[2] = y1;
4013 if (x0 == x1) { px[1] = x3; py[1] = y1; px[2] = x2; n = 3; }
4014 else if (x2 == x3) { px[1] = x1; py[1] = y0; px[2] = x3; n = 3; }
4015 else { px[1] = x1; py[1] = y0; px[2] = x3; px[3] = x2; py[3] = y1; n = 4; }
4016
4017 for(i=0;i<n;i++)
4018 {
4019 px[i] = min(max(px[i],trapextx[0]),trapextx[1]);
4020 vboitem[i].t.s = px[i]*gux + py[i]*guy + guo;
4021 vboitem[i].t.t = px[i]*gvx + py[i]*gvy + gvo;
4022 vboitem[i].v.x = px[i];
4023 vboitem[i].v.y = py[i];
4024 vboitem[i].v.z = 0.f;
4025 }
4026 draw->indexcount = n;
4027 draw->elementcount = n;
4028 draw->elementvbo = vboitem;
4029 polymost_drawpoly_glcall(GL_TRIANGLE_FAN, draw);
4030 draw->elementvbo = NULL;
4031 }
4032
tessectrap(float * px,float * py,int * point2,int numpoints,struct polymostdrawpolycall * draw)4033 static void tessectrap (float *px, float *py, int *point2, int numpoints,
4034 struct polymostdrawpolycall *draw)
4035 {
4036 float x0, x1, m0, m1;
4037 int i, j, k, z, i0, i1, i2, i3, npoints, gap, numrst;
4038
4039 static int allocpoints = 0, *slist = 0, *npoint2 = 0;
4040 typedef struct { float x, y, xi; int i; } raster;
4041 static raster *rst = 0;
4042 static struct polymostvboitem *vboitem = NULL;
4043 if (numpoints+16 > allocpoints) //16 for safety
4044 {
4045 allocpoints = numpoints+16;
4046 rst = (raster*)realloc(rst,allocpoints*sizeof(raster));
4047 slist = (int*)realloc(slist,allocpoints*sizeof(int));
4048 npoint2 = (int*)realloc(npoint2,allocpoints*sizeof(int));
4049 vboitem = (struct polymostvboitem *)realloc(vboitem, allocpoints*sizeof(struct polymostvboitem));
4050 }
4051
4052 //Remove unnecessary collinear points:
4053 for(i=0;i<numpoints;i++) npoint2[i] = point2[i];
4054 npoints = numpoints; z = 0;
4055 for(i=0;i<numpoints;i++)
4056 {
4057 j = npoint2[i]; if ((point2[i] < i) && (i < numpoints-1)) z = 3;
4058 if (j < 0) continue;
4059 k = npoint2[j];
4060 m0 = (px[j]-px[i])*(py[k]-py[j]);
4061 m1 = (py[j]-py[i])*(px[k]-px[j]);
4062 if (m0 < m1) { z |= 1; continue; }
4063 if (m0 > m1) { z |= 2; continue; }
4064 npoint2[i] = k; npoint2[j] = -1; npoints--; i--; //collinear
4065 }
4066 if (!z) return;
4067 trapextx[0] = trapextx[1] = px[0];
4068 for(i=j=0;i<numpoints;i++)
4069 {
4070 if (npoint2[i] < 0) continue;
4071 if (px[i] < trapextx[0]) trapextx[0] = px[i];
4072 if (px[i] > trapextx[1]) trapextx[1] = px[i];
4073 slist[j++] = i;
4074 }
4075 if (z != 3) //Simple polygon... early out
4076 {
4077 for(i=0;i<npoints;i++)
4078 {
4079 j = slist[i];
4080 vboitem[i].t.s = px[j]*gux + py[j]*guy + guo;
4081 vboitem[i].t.t = px[j]*gvx + py[j]*gvy + gvo;
4082 vboitem[i].v.x = px[j];
4083 vboitem[i].v.y = py[j];
4084 vboitem[i].v.z = 0.f;
4085 }
4086 draw->indexcount = npoints;
4087 draw->elementcount = npoints;
4088 draw->elementvbo = vboitem;
4089 polymost_drawpoly_glcall(GL_TRIANGLE_FAN, draw);
4090 return;
4091 }
4092
4093 //Sort points by y's
4094 for(gap=(npoints>>1);gap;gap>>=1)
4095 for(i=0;i<npoints-gap;i++)
4096 for(j=i;j>=0;j-=gap)
4097 {
4098 if (py[npoint2[slist[j]]] <= py[npoint2[slist[j+gap]]]) break;
4099 k = slist[j]; slist[j] = slist[j+gap]; slist[j+gap] = k;
4100 }
4101
4102 numrst = 0;
4103 for(z=0;z<npoints;z++)
4104 {
4105 i0 = slist[z]; i1 = npoint2[i0]; if (py[i0] == py[i1]) continue;
4106 i2 = i1; i3 = npoint2[i1];
4107 if (py[i1] == py[i3]) { i2 = i3; i3 = npoint2[i3]; }
4108
4109 //i0 i3
4110 // \ /
4111 // i1--i2
4112 // / \ ~
4113 //i0 i3
4114
4115 if ((py[i1] < py[i0]) && (py[i2] < py[i3])) //Insert raster
4116 {
4117 for(i=numrst;i>0;i--)
4118 {
4119 if (rst[i-1].xi*(py[i1]-rst[i-1].y) + rst[i-1].x < px[i1]) break;
4120 rst[i+1] = rst[i-1];
4121 }
4122 numrst += 2;
4123
4124 if (i&1) //split inside area
4125 {
4126 j = i-1;
4127
4128 x0 = (py[i1] - rst[j ].y)*rst[j ].xi + rst[j ].x;
4129 x1 = (py[i1] - rst[j+1].y)*rst[j+1].xi + rst[j+1].x;
4130 drawtrap(rst[j].x,rst[j+1].x,rst[j].y,x0,x1,py[i1],draw);
4131 rst[j ].x = x0; rst[j ].y = py[i1];
4132 rst[j+3].x = x1; rst[j+3].y = py[i1];
4133 }
4134
4135 m0 = (px[i0]-px[i1]) / (py[i0]-py[i1]);
4136 m1 = (px[i3]-px[i2]) / (py[i3]-py[i2]);
4137 j = ((px[i1] > px[i2]) || ((i1 == i2) && (m0 >= m1))) + i;
4138 k = (i<<1)+1 - j;
4139 rst[j].i = i0; rst[j].xi = m0; rst[j].x = px[i1]; rst[j].y = py[i1];
4140 rst[k].i = i3; rst[k].xi = m1; rst[k].x = px[i2]; rst[k].y = py[i2];
4141 }
4142 else
4143 { //NOTE:don't count backwards!
4144 if (i1 == i2) { for(i=0;i<numrst;i++) if (rst[i].i == i1) break; }
4145 else { for(i=0;i<numrst;i++) if ((rst[i].i == i1) || (rst[i].i == i2)) break; }
4146 j = i&~1;
4147
4148 if ((py[i1] > py[i0]) && (py[i2] > py[i3])) //Delete raster
4149 {
4150 for(;j<=i+1;j+=2)
4151 {
4152 x0 = (py[i1] - rst[j ].y)*rst[j ].xi + rst[j ].x;
4153 if ((i == j) && (i1 == i2)) x1 = x0; else x1 = (py[i1] - rst[j+1].y)*rst[j+1].xi + rst[j+1].x;
4154 drawtrap(rst[j].x,rst[j+1].x,rst[j].y,x0,x1,py[i1],draw);
4155 rst[j ].x = x0; rst[j ].y = py[i1];
4156 rst[j+1].x = x1; rst[j+1].y = py[i1];
4157 }
4158 numrst -= 2; for(;i<numrst;i++) rst[i] = rst[i+2];
4159 }
4160 else
4161 {
4162 x0 = (py[i1] - rst[j ].y)*rst[j ].xi + rst[j ].x;
4163 x1 = (py[i1] - rst[j+1].y)*rst[j+1].xi + rst[j+1].x;
4164 drawtrap(rst[j].x,rst[j+1].x,rst[j].y,x0,x1,py[i1],draw);
4165 rst[j ].x = x0; rst[j ].y = py[i1];
4166 rst[j+1].x = x1; rst[j+1].y = py[i1];
4167
4168 if (py[i0] < py[i3]) { rst[i].x = px[i2]; rst[i].y = py[i2]; rst[i].i = i3; }
4169 else { rst[i].x = px[i1]; rst[i].y = py[i1]; rst[i].i = i0; }
4170 rst[i].xi = (px[rst[i].i] - rst[i].x) / (py[rst[i].i] - py[i1]);
4171 }
4172 }
4173 }
4174 }
4175
polymost_fillpolygon(int npoints)4176 void polymost_fillpolygon (int npoints)
4177 {
4178 PTHead *pth;
4179 float alphac=0.0;
4180 int i, j, k;
4181 unsigned short ptflags = 0;
4182 struct polymostdrawpolycall draw;
4183
4184 globalx1 = mulscale16(globalx1,xyaspect);
4185 globaly2 = mulscale16(globaly2,xyaspect);
4186 gux = ((double)asm1)*(1.0/4294967296.0);
4187 gvx = ((double)asm2)*(1.0/4294967296.0);
4188 guy = ((double)globalx1)*(1.0/4294967296.0);
4189 gvy = ((double)globaly2)*(-1.0/4294967296.0);
4190 guo = (((double)xdim)*gux + ((double)ydim)*guy)*-.5 + ((double)globalposx)*(1.0/4294967296.0);
4191 gvo = (((double)xdim)*gvx + ((double)ydim)*gvy)*-.5 - ((double)globalposy)*(1.0/4294967296.0);
4192
4193 //Convert int to float (in-place)
4194 for(i=npoints-1;i>=0;i--)
4195 {
4196 ((float *)rx1)[i] = ((float)rx1[i])/4096.0;
4197 ((float *)ry1)[i] = ((float)ry1[i])/4096.0;
4198 }
4199
4200 if ((unsigned int)globalpicnum >= MAXTILES) globalpicnum = 0;
4201 if (!palookup[globalpal]) globalpal = 0;
4202
4203 if (usehightile) ptflags |= PTH_HIGHTILE;
4204
4205 draw.texture0 = 0;
4206 pth = PT_GetHead(globalpicnum, globalpal, ptflags, 0);
4207 if (pth && pth->pic[PTHPIC_BASE]) {
4208 draw.texture0 = pth->pic[ PTHPIC_BASE ]->glpic;
4209 }
4210 draw.texture1 = nulltexture;
4211 draw.alphacut = 0.f;
4212 draw.fogdensity = 0.f;
4213
4214 draw.colour.r = draw.colour.g = draw.colour.b =
4215 ((float)(numpalookups-min(max(globalshade,0),numpalookups)))/((float)numpalookups);
4216 switch ((globalorientation>>7)&3) {
4217 case 0:
4218 case 1: draw.colour.a = 1.0; glfunc.glDisable(GL_BLEND); break;
4219 case 2: draw.colour.a = 0.66; glfunc.glEnable(GL_BLEND); break;
4220 case 3: draw.colour.a = 0.33; glfunc.glEnable(GL_BLEND); break;
4221 }
4222 if (pth && (pth->flags & PTH_HIGHTILE) && (globalpal != pth->repldef->palnum)) {
4223 // apply tinting for replaced textures
4224 draw.colour.r *= (float)hictinting[globalpal].r / 255.0;
4225 draw.colour.g *= (float)hictinting[globalpal].g / 255.0;
4226 draw.colour.b *= (float)hictinting[globalpal].b / 255.0;
4227 }
4228
4229 draw.modelview = &gidentitymat[0][0];
4230 draw.projection = &gorthoprojmat[0][0];
4231
4232 draw.indexbuffer = 0;
4233 draw.elementbuffer = 0;
4234 tessectrap((float *)rx1,(float *)ry1,xb1,npoints,&draw);
4235 }
4236
polymost_drawtilescreen(int tilex,int tiley,int wallnum,int dimen)4237 int polymost_drawtilescreen (int tilex, int tiley, int wallnum, int dimen)
4238 {
4239 float xdime, ydime, xdimepad, ydimepad, scx, scy;
4240 int i;
4241 PTHead *pth;
4242 palette_t bgcolour;
4243 struct polymostdrawauxcall draw;
4244 struct polymostvboitem vboitem[4];
4245
4246 if ((rendmode != 3) || (qsetmode != 200)) return(-1);
4247
4248 xdime = (float)tilesizx[wallnum];
4249 ydime = (float)tilesizy[wallnum];
4250
4251 if ((xdime <= dimen) && (ydime <= dimen)) {
4252 scx = xdime;
4253 scy = ydime;
4254 } else {
4255 scx = (float)dimen;
4256 scy = (float)dimen;
4257 if (xdime < ydime) {
4258 scx *= xdime/ydime;
4259 } else {
4260 scy *= ydime/xdime;
4261 }
4262 }
4263
4264 pth = PT_GetHead(wallnum, 0, (usehightile ? PTH_HIGHTILE : 0) | PTH_CLAMPED, 0);
4265
4266 if (pth) {
4267 xdimepad = (float)pth->pic[PTHPIC_BASE]->tsizx / (float)pth->pic[PTHPIC_BASE]->sizx;
4268 ydimepad = (float)pth->pic[PTHPIC_BASE]->tsizy / (float)pth->pic[PTHPIC_BASE]->sizy;
4269 } else {
4270 xdimepad = 1.0;
4271 ydimepad = 1.0;
4272 }
4273
4274 bgcolour = curpalette[255];
4275 if (!gammabrightness) {
4276 bgcolour.r = britable[curbrightness][bgcolour.r];
4277 bgcolour.g = britable[curbrightness][bgcolour.g];
4278 bgcolour.b = britable[curbrightness][bgcolour.b];
4279 }
4280
4281 draw.mode = 1; // Tile.
4282
4283 draw.texture0 = nulltexture;
4284 if (pth) {
4285 if (pth->pic[PTHPIC_BASE]) {
4286 draw.texture0 = pth->pic[PTHPIC_BASE]->glpic;
4287 }
4288 }
4289
4290 draw.bgcolour.r = bgcolour.r / 255.f;
4291 draw.bgcolour.g = bgcolour.g / 255.f;
4292 draw.bgcolour.b = bgcolour.b / 255.f;
4293 draw.bgcolour.a = 1.f;
4294
4295 vboitem[0].v.x = (GLfloat)tilex;
4296 vboitem[0].v.y = (GLfloat)tiley;
4297 vboitem[0].v.z = 0.f;
4298 vboitem[0].t.s = 0.f;
4299 vboitem[0].t.t = 0.f;
4300
4301 vboitem[1].v.x = (GLfloat)tilex+scx;
4302 vboitem[1].v.y = (GLfloat)tiley;
4303 vboitem[1].v.z = 0.f;
4304 vboitem[1].t.s = xdimepad;
4305 vboitem[1].t.t = 0.f;
4306
4307 vboitem[2].v.x = (GLfloat)tilex+scx;
4308 vboitem[2].v.y = (GLfloat)tiley+scy;
4309 vboitem[2].v.z = 0.f;
4310 vboitem[2].t.s = xdimepad;
4311 vboitem[2].t.t = ydimepad;
4312
4313 vboitem[3].v.x = (GLfloat)tilex;
4314 vboitem[3].v.y = (GLfloat)tiley+scy;
4315 vboitem[3].v.z = 0.f;
4316 vboitem[3].t.s = 0.f;
4317 vboitem[3].t.t = ydimepad;
4318
4319 draw.indexcount = 4;
4320 draw.indexes = NULL;
4321 draw.elementcount = 4;
4322 draw.elementvbo = vboitem;
4323
4324 polymost_drawaux_glcall(GL_TRIANGLE_FAN, &draw);
4325
4326 return(0);
4327 }
4328
polymost_printext256(int xpos,int ypos,short col,short backcol,const char * name,char fontsize)4329 int polymost_printext256(int xpos, int ypos, short col, short backcol, const char *name, char fontsize)
4330 {
4331 GLfloat tx, ty, txc, tyc, tyoff, cx, cy;
4332 int c, indexcnt, vbocnt;
4333 palette_t colour;
4334 struct polymostdrawauxcall draw;
4335 struct polymostvboitem vboitem[80*4];
4336 GLushort vboindexes[80*6];
4337
4338 if ((rendmode != 3) || (qsetmode != 200)) return(-1);
4339
4340 polymost_preparetext();
4341 setpolymost2dview(); // disables blending, texturing, and depth testing
4342 glfunc.glDepthMask(GL_FALSE); // disable writing to the z-buffer
4343 glfunc.glEnable(GL_BLEND);
4344
4345 draw.mode = 0; // Text.
4346
4347 draw.texture0 = texttexture;
4348
4349 colour = curpalette[col];
4350 if (!gammabrightness) {
4351 colour.r = britable[curbrightness][ colour.r ];
4352 colour.g = britable[curbrightness][ colour.g ];
4353 colour.b = britable[curbrightness][ colour.b ];
4354 }
4355 draw.colour.r = colour.r / 255.f;
4356 draw.colour.g = colour.g / 255.f;
4357 draw.colour.b = colour.b / 255.f;
4358 draw.colour.a = 1.f;
4359
4360 colour = curpalette[min(0, backcol)];
4361 if (!gammabrightness) {
4362 colour.r = britable[curbrightness][ colour.r ];
4363 colour.g = britable[curbrightness][ colour.g ];
4364 colour.b = britable[curbrightness][ colour.b ];
4365 }
4366 draw.bgcolour.r = colour.r / 255.f;
4367 draw.bgcolour.g = colour.g / 255.f;
4368 draw.bgcolour.b = colour.b / 255.f;
4369 if (backcol >= 0) {
4370 draw.bgcolour.a = 1.f;
4371 } else {
4372 draw.bgcolour.a = 0.f;
4373 }
4374
4375 if (fontsize) {
4376 tyoff = 8.f;
4377 cx = 4.f;
4378 cy = 6.f;
4379 } else {
4380 tyoff = 0.f;
4381 cx = 8.f;
4382 cy = 8.f;
4383 }
4384 txc = cx/256.f;
4385 tyc = cy/128.f;
4386
4387 draw.indexes = vboindexes;
4388 draw.elementvbo = vboitem;
4389
4390 c = 0;
4391 indexcnt = vbocnt = 0;
4392 while (name[c]) {
4393 for (; name[c] && indexcnt < 80*6; c++) {
4394 tx = (GLfloat)(name[c]%32)/32.0;
4395 ty = ((GLfloat)(name[c]/32) + tyoff)/16.0;
4396
4397 vboindexes[indexcnt + 0] = vbocnt+0;
4398 vboindexes[indexcnt + 1] = vbocnt+1;
4399 vboindexes[indexcnt + 2] = vbocnt+2;
4400 vboindexes[indexcnt + 3] = vbocnt+0;
4401 vboindexes[indexcnt + 4] = vbocnt+2;
4402 vboindexes[indexcnt + 5] = vbocnt+3;
4403
4404 vboitem[vbocnt + 0].v.x = (GLfloat)xpos;
4405 vboitem[vbocnt + 0].v.y = (GLfloat)ypos;
4406 vboitem[vbocnt + 0].v.z = 0.f;
4407 vboitem[vbocnt + 0].t.s = tx;
4408 vboitem[vbocnt + 0].t.t = ty;
4409
4410 vboitem[vbocnt + 1].v.x = (GLfloat)xpos+cx;
4411 vboitem[vbocnt + 1].v.y = (GLfloat)ypos;
4412 vboitem[vbocnt + 1].v.z = 0.f;
4413 vboitem[vbocnt + 1].t.s = tx+txc;
4414 vboitem[vbocnt + 1].t.t = ty;
4415
4416 vboitem[vbocnt + 2].v.x = (GLfloat)xpos+cx;
4417 vboitem[vbocnt + 2].v.y = (GLfloat)ypos+cy;
4418 vboitem[vbocnt + 2].v.z = 0.f;
4419 vboitem[vbocnt + 2].t.s = tx+txc;
4420 vboitem[vbocnt + 2].t.t = ty+tyc;
4421
4422 vboitem[vbocnt + 3].v.x = (GLfloat)xpos;
4423 vboitem[vbocnt + 3].v.y = (GLfloat)ypos+cy;
4424 vboitem[vbocnt + 3].v.z = 0.f;
4425 vboitem[vbocnt + 3].t.s = tx;
4426 vboitem[vbocnt + 3].t.t = ty+tyc;
4427
4428 indexcnt += 6;
4429 vbocnt += 4;
4430 xpos += (8>>fontsize);
4431 }
4432
4433 draw.indexcount = indexcnt;
4434 draw.elementcount = vbocnt;
4435
4436 polymost_drawaux_glcall(GL_TRIANGLES, &draw);
4437
4438 indexcnt = vbocnt = 0;
4439 }
4440
4441 glfunc.glDepthMask(GL_TRUE); // re-enable writing to the z-buffer
4442
4443 return 0;
4444 }
4445
polymost_drawline256(int x1,int y1,int x2,int y2,unsigned char col)4446 int polymost_drawline256(int x1, int y1, int x2, int y2, unsigned char col)
4447 {
4448 palette_t colour;
4449 struct polymostdrawauxcall draw;
4450 struct polymostvboitem vboitem[2];
4451
4452 if ((rendmode != 3) || (qsetmode != 200)) return(-1);
4453
4454 polymost_preparetext();
4455 setpolymost2dview(); // disables blending, texturing, and depth testing
4456 glfunc.glDepthMask(GL_FALSE); // disable writing to the z-buffer
4457 glfunc.glEnable(GL_BLEND);
4458
4459 draw.mode = 2; // Solid colour.
4460
4461 colour = curpalette[col];
4462 if (!gammabrightness) {
4463 colour.r = britable[curbrightness][ colour.r ];
4464 colour.g = britable[curbrightness][ colour.g ];
4465 colour.b = britable[curbrightness][ colour.b ];
4466 }
4467 draw.colour.r = colour.r / 255.f;
4468 draw.colour.g = colour.g / 255.f;
4469 draw.colour.b = colour.b / 255.f;
4470 draw.colour.a = 1.f;
4471
4472 vboitem[0].v.x = (GLfloat)(x1+2048)/4096.f;
4473 vboitem[0].v.y = (GLfloat)(y1+2048)/4096.f;
4474 vboitem[0].v.z = 0.f;
4475
4476 vboitem[1].v.x = (GLfloat)(x2+2048)/4096.f;
4477 vboitem[1].v.y = (GLfloat)(y2+2048)/4096.f;
4478 vboitem[1].v.z = 0.f;
4479
4480 draw.indexcount = 2;
4481 draw.indexes = NULL;
4482 draw.elementcount = 2;
4483 draw.elementvbo = vboitem;
4484
4485 polymost_drawaux_glcall(GL_LINES, &draw);
4486
4487 glfunc.glDepthMask(GL_TRUE); // re-enable writing to the z-buffer
4488
4489 return 0;
4490 }
4491
polymost_plotpixel(int x,int y,unsigned char col)4492 int polymost_plotpixel(int x, int y, unsigned char col)
4493 {
4494 palette_t colour;
4495 struct polymostdrawauxcall draw;
4496 struct polymostvboitem vboitem[1];
4497
4498 if ((rendmode != 3) || (qsetmode != 200)) return(-1);
4499
4500 setpolymost2dview(); // disables blending, texturing, and depth testing
4501 glfunc.glDepthMask(GL_FALSE); // disable writing to the z-buffer
4502 glfunc.glEnable(GL_BLEND);
4503
4504 draw.mode = 2; // Solid colour.
4505
4506 colour = curpalette[col];
4507 if (!gammabrightness) {
4508 colour.r = britable[curbrightness][ colour.r ];
4509 colour.g = britable[curbrightness][ colour.g ];
4510 colour.b = britable[curbrightness][ colour.b ];
4511 }
4512 draw.colour.r = colour.r / 255.f;
4513 draw.colour.g = colour.g / 255.f;
4514 draw.colour.b = colour.b / 255.f;
4515 draw.colour.a = 1.f;
4516
4517 vboitem[0].v.x = (GLfloat)x;
4518 vboitem[0].v.y = (GLfloat)y;
4519 vboitem[0].v.z = 0.f;
4520
4521 draw.indexcount = 1;
4522 draw.indexes = NULL;
4523 draw.elementcount = 1;
4524 draw.elementvbo = vboitem;
4525
4526 polymost_drawaux_glcall(GL_POINTS, &draw);
4527
4528 glfunc.glDepthMask(GL_TRUE); // re-enable writing to the z-buffer
4529
4530 return 0;
4531 }
4532
polymost_preparetext(void)4533 static int polymost_preparetext(void)
4534 {
4535 unsigned char *cptr;
4536 unsigned int *tbuf, *tptr;
4537 int h,i,j,l;
4538
4539 if (texttexture) {
4540 return 0;
4541 }
4542
4543 // construct a 256x128 rgba texture for the font glyph matrix
4544 glfunc.glGenTextures(1,&texttexture);
4545 if (!texttexture) return -1;
4546
4547 tbuf = (unsigned int *)Bcalloc(256*128, sizeof(unsigned int));
4548 if (!tbuf) {
4549 glfunc.glDeleteTextures(1,&texttexture);
4550 texttexture = 0;
4551 return -1;
4552 }
4553
4554 cptr = (unsigned char*)textfont;
4555 for (h=0;h<256;h++) {
4556 tptr = tbuf + (h%32)*8 + (h/32)*256*8;
4557 for (i=0;i<8;i++) {
4558 for (j=0;j<8;j++) {
4559 if (cptr[h*8+i] & pow2char[7-j]) tptr[j] = 0xffffffff;
4560 }
4561 tptr += 256;
4562 }
4563 }
4564
4565 cptr = (unsigned char*)smalltextfont;
4566 for (h=0;h<256;h++) {
4567 tptr = tbuf + 256*64 + (h%32)*8 + (h/32)*256*8;
4568 for (i=1;i<7;i++) {
4569 for (j=2;j<6;j++) {
4570 if (cptr[h*8+i] & pow2char[7-j]) tptr[j-2] = 0xffffffff;
4571 }
4572 tptr += 256;
4573 }
4574 }
4575
4576 glfunc.glActiveTexture(GL_TEXTURE0);
4577 glfunc.glBindTexture(GL_TEXTURE_2D, texttexture);
4578 glfunc.glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,256,128,0,GL_RGBA,GL_UNSIGNED_BYTE,(GLvoid*)tbuf);
4579 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
4580 glfunc.glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
4581 free(tbuf);
4582
4583 return 0;
4584 }
4585
polymost_precache_begin()4586 void polymost_precache_begin()
4587 {
4588 PTBeginPriming();
4589 }
4590
polymost_precache(int dapicnum,int dapalnum,int datype)4591 void polymost_precache(int dapicnum, int dapalnum, int datype)
4592 {
4593 // dapicnum and dapalnum are like you'd expect
4594 // datype is 0 for a wall/floor/ceiling and 1 for a sprite
4595 // basically this just means walls are repeating
4596 // while sprites are clamped
4597 int mid;
4598 unsigned short flags;
4599
4600 if (rendmode < 3) return;
4601
4602 if (!palookup[dapalnum]) return;//dapalnum = 0;
4603
4604 //FIXME
4605 //buildprintf("precached %d %d type %d\n", dapicnum, dapalnum, datype);
4606 flags = (datype & 1) ? PTH_CLAMPED :0;
4607 if (usehightile) flags |= PTH_HIGHTILE;
4608 PTMarkPrime(dapicnum, dapalnum, flags);
4609
4610 if (datype == 0) return;
4611
4612 mid = md_tilehasmodel(dapicnum);
4613 if (mid < 0 || models[mid]->mdnum < 2) return;
4614
4615 {
4616 int i,j=0;
4617
4618 if (models[mid]->mdnum == 3)
4619 j = ((md3model *)models[mid])->head.numsurfs;
4620
4621 for (i=0;i<=j;i++)
4622 mdloadskin((md2model*)models[mid], 0, dapalnum, i);
4623 }
4624 }
4625
polymost_precache_run(int * done,int * total)4626 int polymost_precache_run(int* done, int* total)
4627 {
4628 return PTDoPrime(done, total);
4629 }
4630
4631 #ifdef DEBUGGINGAIDS
4632 // because I'm lazy
osdcmd_debugdumptexturedefs(const osdfuncparm_t * UNUSED (parm))4633 static int osdcmd_debugdumptexturedefs(const osdfuncparm_t * UNUSED(parm))
4634 {
4635 hicreplctyp *hr;
4636 int i;
4637
4638 if (!hicfirstinit) return OSDCMD_OK;
4639
4640 buildprintf("// Begin Texture Dump\n");
4641 for (i=0;i<MAXTILES;i++) {
4642 hr = hicreplc[i];
4643 if (!hr) continue;
4644 buildprintf("texture %d {\n", i);
4645 for (; hr; hr = hr->next) {
4646 if (!hr->filename) continue;
4647 buildprintf(" pal %d { name \"%s\" ", hr->palnum, hr->filename);
4648 if (hr->alphacut >= 0.0) buildprintf("alphacut %g ", hr->alphacut);
4649 buildprintf("}\n");
4650 }
4651 buildprintf("}\n");
4652 }
4653 buildprintf("// End Texture Dump\n");
4654
4655 return OSDCMD_OK; // no replacement found
4656 }
4657
osdcmd_debugtexturehash(const osdfuncparm_t * UNUSED (parm))4658 static int osdcmd_debugtexturehash(const osdfuncparm_t * UNUSED(parm))
4659 {
4660 PTIter iter;
4661 PTHead * pth;
4662 int i;
4663
4664 if (!hicfirstinit) {
4665 return OSDCMD_OK;
4666 }
4667
4668 buildprintf("// Begin texture hash dump\n");
4669 iter = PTIterNew();
4670 while ((pth = PTIterNext(iter)) != 0) {
4671 buildprintf(" picnum:%d palnum:%d flags:%04X repldef:%p\n",
4672 pth->picnum, pth->palnum, pth->flags,
4673 pth->repldef);
4674 for (i=0; i<6; i++) {
4675 if (pth->pic[i]) {
4676 buildprintf(" pic[%d]: %p => glpic:%d flags:%x sizx/y:%d/%d tsizx/y:%d/%d\n",
4677 i, pth->pic[i], pth->pic[i]->glpic, pth->pic[i]->flags,
4678 pth->pic[i]->sizx, pth->pic[i]->sizy,
4679 pth->pic[i]->tsizx, pth->pic[i]->tsizy);
4680 }
4681 }
4682 }
4683 PTIterFree(iter);
4684 buildprintf("// End texture hash dump\n");
4685
4686 return OSDCMD_OK; // no replacement found
4687 }
4688 #endif
4689
4690 #ifdef SHADERDEV
osdcmd_debugreloadshaders(const osdfuncparm_t * UNUSED (parm))4691 static int osdcmd_debugreloadshaders(const osdfuncparm_t *UNUSED(parm))
4692 {
4693 polymost_loadshaders();
4694 return OSDCMD_OK;
4695 }
4696 #endif
4697
osdcmd_gltexturemode(const osdfuncparm_t * parm)4698 static int osdcmd_gltexturemode(const osdfuncparm_t *parm)
4699 {
4700 int m;
4701 const char *p;
4702
4703 if (parm->numparms != 1) {
4704 buildprintf("Current texturing mode is %s\n", glfiltermodes[gltexfiltermode].name);
4705 buildprintf(" Vaild modes are:\n");
4706 for (m = 0; m < (int)numglfiltermodes; m++)
4707 buildprintf(" %d - %s\n",m,glfiltermodes[m].name);
4708
4709 return OSDCMD_OK;
4710 }
4711
4712 m = Bstrtoul(parm->parms[0], (char **)&p, 10);
4713 if (p == parm->parms[0]) {
4714 // string
4715 for (m = 0; m < (int)numglfiltermodes; m++) {
4716 if (!Bstrcasecmp(parm->parms[0], glfiltermodes[m].name)) break;
4717 }
4718 if (m == numglfiltermodes) m = gltexfiltermode; // no change
4719 } else {
4720 if (m < 0) m = 0;
4721 else if (m >= (int)numglfiltermodes) m = numglfiltermodes - 1;
4722 }
4723
4724 if (m != gltexfiltermode) {
4725 gltexfiltermode = m;
4726 gltexapplyprops();
4727 }
4728
4729 buildprintf("Texture filtering mode changed to %s\n", glfiltermodes[gltexfiltermode].name );
4730
4731 return OSDCMD_OK;
4732 }
4733
osdcmd_gltextureanisotropy(const osdfuncparm_t * parm)4734 static int osdcmd_gltextureanisotropy(const osdfuncparm_t *parm)
4735 {
4736 int l;
4737 const char *p;
4738
4739 if (parm->numparms != 1) {
4740 buildprintf("Current texture anisotropy is %d\n", glanisotropy);
4741 buildprintf(" Maximum is %f\n", glinfo.maxanisotropy);
4742
4743 return OSDCMD_OK;
4744 }
4745
4746 l = Bstrtoul(parm->parms[0], (char **)&p, 10);
4747 if (l < 0 || l > glinfo.maxanisotropy) l = 0;
4748
4749 if (l != gltexfiltermode) {
4750 glanisotropy = l;
4751 gltexapplyprops();
4752 }
4753
4754 buildprintf("Texture anisotropy changed to %d\n", glanisotropy );
4755
4756 return OSDCMD_OK;
4757 }
4758
osdcmd_forcetexcacherebuild(const osdfuncparm_t * UNUSED (parm))4759 static int osdcmd_forcetexcacherebuild(const osdfuncparm_t *UNUSED(parm))
4760 {
4761 PTCacheForceRebuild();
4762 buildprintf("Compressed texture cache invalidated. Use 'restartvid' to reinitialise it.\n");
4763 return OSDCMD_OK;
4764 }
4765
4766 #endif //USE_OPENGL
4767
osdcmd_polymostvars(const osdfuncparm_t * parm)4768 static int osdcmd_polymostvars(const osdfuncparm_t *parm)
4769 {
4770 int showval = (parm->numparms < 1), val = 0;
4771
4772 if (!showval) val = atoi(parm->parms[0]);
4773 #if USE_OPENGL
4774 if (!Bstrcasecmp(parm->name, "usemodels")) {
4775 if (showval) { buildprintf("usemodels is %d\n", usemodels); }
4776 else usemodels = (val != 0);
4777 return OSDCMD_OK;
4778 }
4779 else if (!Bstrcasecmp(parm->name, "usehightile")) {
4780 if (showval) { buildprintf("usehightile is %d\n", usehightile); }
4781 else usehightile = (val != 0);
4782 return OSDCMD_OK;
4783 }
4784 else if (!Bstrcasecmp(parm->name, "glusetexcompr")) {
4785 if (showval) { buildprintf("glusetexcompr is %d\n", glusetexcompr); }
4786 else glusetexcompr = (val != 0);
4787 return OSDCMD_OK;
4788 }
4789 else if (!Bstrcasecmp(parm->name, "gltexcomprquality")) {
4790 if (showval) { buildprintf("gltexcomprquality is %d\n", gltexcomprquality); }
4791 else {
4792 if (val < 0 || val > 2) val = 0;
4793 gltexcomprquality = val;
4794 }
4795 return OSDCMD_OK;
4796 }
4797 else if (!Bstrcasecmp(parm->name, "glredbluemode")) {
4798 if (showval) { buildprintf("glredbluemode is %d\n", glredbluemode); }
4799 else glredbluemode = (val != 0);
4800 return OSDCMD_OK;
4801 }
4802 else if (!Bstrcasecmp(parm->name, "gltexturemaxsize")) {
4803 if (showval) { buildprintf("gltexturemaxsize is %d\n", gltexmaxsize); }
4804 else gltexmaxsize = val;
4805 return OSDCMD_OK;
4806 }
4807 else if (!Bstrcasecmp(parm->name, "gltexturemiplevel")) {
4808 if (showval) { buildprintf("gltexturemiplevel is %d\n", gltexmiplevel); }
4809 else gltexmiplevel = val;
4810 return OSDCMD_OK;
4811 }
4812 else if (!Bstrcasecmp(parm->name, "usegoodalpha")) {
4813 if (showval) { buildprintf("usegoodalpha is %d\n", usegoodalpha); }
4814 else usegoodalpha = (val != 0);
4815 return OSDCMD_OK;
4816 }
4817 else if (!Bstrcasecmp(parm->name, "glpolygonmode")) {
4818 if (showval) { buildprintf("glpolygonmode is %d\n", glpolygonmode); }
4819 else glpolygonmode = val;
4820 return OSDCMD_OK;
4821 }
4822 else if (!Bstrcasecmp(parm->name, "glusetexcache")) {
4823 if (showval) { buildprintf("glusetexcache is %d\n", glusetexcache); }
4824 else glusetexcache = (val != 0);
4825 return OSDCMD_OK;
4826 }
4827 else if (!Bstrcasecmp(parm->name, "glmultisample")) {
4828 if (showval) { buildprintf("glmultisample is %d\n", glmultisample); }
4829 else glmultisample = max(0,val);
4830 return OSDCMD_OK;
4831 }
4832 else if (!Bstrcasecmp(parm->name, "glnvmultisamplehint")) {
4833 if (showval) { buildprintf("glnvmultisamplehint is %d\n", glnvmultisamplehint); }
4834 else glnvmultisamplehint = (val != 0);
4835 return OSDCMD_OK;
4836 }
4837 else if (!Bstrcasecmp(parm->name, "polymosttexverbosity")) {
4838 if (showval) { buildprintf("polymosttexverbosity is %d\n", polymosttexverbosity); }
4839 else {
4840 if (val < 0 || val > 2) val = 1;
4841 polymosttexverbosity = val;
4842 }
4843 return OSDCMD_OK;
4844 }
4845 #endif //USE_OPENGL
4846 #ifdef DEBUGGINGAIDS
4847 if (!Bstrcasecmp(parm->name, "debugshowcallcounts")) {
4848 if (showval) { buildprintf("debugshowcallcounts is %d\n", polymostshowcallcounts); }
4849 else polymostshowcallcounts = (val != 0);
4850 return OSDCMD_OK;
4851 }
4852 #endif
4853 return OSDCMD_SHOWHELP;
4854 }
4855
polymost_initosdfuncs(void)4856 void polymost_initosdfuncs(void)
4857 {
4858 #if USE_OPENGL
4859 OSD_RegisterFunction("usemodels","usemodels: enable/disable model rendering in >8-bit mode",osdcmd_polymostvars);
4860 OSD_RegisterFunction("usehightile","usehightile: enable/disable hightile texture rendering in >8-bit mode",osdcmd_polymostvars);
4861 OSD_RegisterFunction("glusetexcompr","glusetexcompr: enable/disable OpenGL texture compression",osdcmd_polymostvars);
4862 OSD_RegisterFunction("gltexcomprquality","gltexcomprquality: sets texture compression quality. 0 = fast (default), 1 = slow, 2 = very slow",osdcmd_polymostvars);
4863 OSD_RegisterFunction("glredbluemode","glredbluemode: enable/disable experimental OpenGL red-blue glasses mode",osdcmd_polymostvars);
4864 OSD_RegisterFunction("gltexturemode", "gltexturemode: changes the texture filtering settings", osdcmd_gltexturemode);
4865 OSD_RegisterFunction("gltextureanisotropy", "gltextureanisotropy: changes the OpenGL texture anisotropy setting", osdcmd_gltextureanisotropy);
4866 OSD_RegisterFunction("gltexturemaxsize","gltexturemaxsize: changes the maximum OpenGL texture size limit",osdcmd_polymostvars);
4867 OSD_RegisterFunction("gltexturemiplevel","gltexturemiplevel: changes the highest OpenGL mipmap level used",osdcmd_polymostvars);
4868 OSD_RegisterFunction("usegoodalpha","usegoodalpha: enable/disable better looking OpenGL alpha hack",osdcmd_polymostvars);
4869 OSD_RegisterFunction("glpolygonmode","glpolygonmode: debugging feature. 0 = normal, 1 = edges, 2 = points, 3 = clear each frame",osdcmd_polymostvars);
4870 OSD_RegisterFunction("glusetexcache","glusetexcache: enable/disable OpenGL compressed texture cache",osdcmd_polymostvars);
4871 OSD_RegisterFunction("glmultisample","glmultisample: sets the number of samples used for antialiasing (0 = off)",osdcmd_polymostvars);
4872 OSD_RegisterFunction("glnvmultisamplehint","glnvmultisamplehint: enable/disable Nvidia multisampling hinting",osdcmd_polymostvars);
4873 OSD_RegisterFunction("polymosttexverbosity","polymosttexverbosity: sets the level of chatter during texture loading. 0 = none, 1 = errors (default), 2 = all",osdcmd_polymostvars);
4874 OSD_RegisterFunction("forcetexcacherebuild","forcetexcacherebuild: invalidates the compressed texture cache", osdcmd_forcetexcacherebuild);
4875 #ifdef SHADERDEV
4876 OSD_RegisterFunction("debugreloadshaders","debugreloadshaders: reloads the OpenGL shaders",osdcmd_debugreloadshaders);
4877 #endif
4878 #ifdef DEBUGGINGAIDS
4879 OSD_RegisterFunction("debugdumptexturedefs","dumptexturedefs: dumps all texture definitions in the new style",osdcmd_debugdumptexturedefs);
4880 OSD_RegisterFunction("debugtexturehash","debugtexturehash: dumps all the entries in the texture hash",osdcmd_debugtexturehash);
4881 OSD_RegisterFunction("debugshowcallcounts","debugshowcallcounts: display rendering call counts",osdcmd_polymostvars);
4882 #endif
4883 #endif //USE_OPENGL
4884 }
4885
4886 #endif //USE_POLYMOST
4887
4888 // vim:ts=4:sw=4:
4889