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 = &sector[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 = &sector[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&sector[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&sector[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 = &sector[sectnum];
3257 	nsec = &sector[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