1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: r_glide.c 1388 2018-04-15 02:10:08Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2012 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: r_glide.c,v $
20 // Revision 1.26  2001/08/26 15:27:30  bpereira
21 // added fov for glide and fixed newcoronas code
22 //
23 // Revision 1.25  2001/08/20 18:34:20  bpereira
24 // glide ligthing and map30 bug
25 //
26 // Revision 1.24  2001/08/19 15:40:07  bpereira
27 // added Treansform (and lighting) to glide
28 //
29 // Revision 1.23  2001/07/28 16:18:39  bpereira
30 // Revision 1.22  2001/02/24 13:35:22  bpereira
31 // Revision 1.21  2001/01/25 18:56:28  bpereira
32 //
33 // Revision 1.20  2001/01/05 18:19:13  hurdler
34 // add renderer version checking
35 //
36 // Revision 1.19  2000/11/04 16:23:45  bpereira
37 // Revision 1.18  2000/10/08 13:30:02  bpereira
38 //
39 // Revision 1.17  2000/10/04 16:29:57  hurdler
40 // Implement hardware texture memory stats (TODO in glide mode)
41 //
42 // Revision 1.16  2000/09/28 20:57:21  bpereira
43 // Revision 1.15  2000/08/31 14:30:57  bpereira
44 //
45 // Revision 1.14  2000/08/10 14:17:58  hurdler
46 // add waitvbl
47 //
48 // Revision 1.13  2000/08/03 17:57:42  bpereira
49 // Revision 1.12  2000/07/01 09:23:50  bpereira
50 // Revision 1.11  2000/05/09 20:50:57  hurdler
51 // Revision 1.10  2000/05/05 18:00:06  bpereira
52 // Revision 1.9  2000/04/30 10:30:10  bpereira
53 // Revision 1.8  2000/04/23 16:19:52  bpereira
54 // Revision 1.7  2000/04/18 12:50:55  hurdler
55 //
56 // Revision 1.5  2000/04/14 16:38:24  hurdler
57 // some nice changes for coronas
58 //
59 // Revision 1.4  2000/03/06 15:26:17  hurdler
60 // Revision 1.3  2000/02/27 00:42:11  hurdler
61 // Revision 1.2  2000/02/26 00:28:42  hurdler
62 // Mostly bug fix (see borislog.txt 23-2-2000, 24-2-2000)
63 //
64 //
65 // DESCRIPTION:
66 //      3Dfx Glide Render driver
67 //
68 //-----------------------------------------------------------------------------
69 
70 //output debugging msgs to r_glide.log
71 //#define DEBUG_GLIDE_TO_FILE
72 
73 #ifndef SMIF_WIN_NATIVE
74 # error r_glide is WIN_NATIVE only
75 #endif
76 
77 #include <windows.h>
78 #include <glide.h>
79 #include <math.h>
80 
81 #define  HWRAPI_CREATE_DLL
82 #include "hardware/hw_drv.h"
83 
84 #include "screen.h"
85 #include "3dmath.h"
86 
87 
88 // **************************************************************************
89 //                                                                     PROTOS
90 // **************************************************************************
91 
92 // output all debugging messages to this file
93 #ifdef DEBUG_GLIDE_TO_FILE
94 static HANDLE  glide_logstream;
95 #endif
96 
97 static void GR_ResetStates(viddef_t *lvid);
98 static void GR_InitMipmapCache(void);
99 static void GR_ClearMipmapCache(void);
100 
101 static void MakeFogTable(void);
102 static void FreeFogTable(void);
103 static void ReSetSpecialState(void);
104 
105 // **************************************************************************
106 //                                                                    GLOBALS
107 // **************************************************************************
108 
109 //0 means glide mode not set yet, this is returned by grSstWinOpen()
110 static GrContext_t grPreviousContext = 0;
111 
112 // align boundary for textures in texture cache, set at Init()
113 static FxU32 gr_alignboundary;
114 
115 static FBITFIELD CurrentPolyFlags;
116 static FBITFIELD CurrentTextureFlags;
117 
118 static vxtx3d_t tmpVerts[MAXCLIPVERTS*2];
119 static vxtx3d_t tmp2Verts[MAXCLIPVERTS*2];
120 static vxtx3d_t tmp3Verts[MAXCLIPVERTS*2];
121 
122 static FTransform_t grTransform;
123 static FTransform_t defaulttransform = {0,0,0,0,90,1,1,1,90,90};
124 static float szsinx, szcosx, siny, cosy, sxsiny, sxcosy, sysinx, sycosx;
125 
126 static I_Error_t I_ErrorGr = NULL;
127 static glide_initialized = false;
128 static int glide_state[HWD_NUMSTATE];
129 
130 // **************************************************************************
131 //                                                            DLL ENTRY POINT
132 // **************************************************************************
DllMain(HANDLE hModule,DWORD fdwReason,LPVOID lpReserved)133 BOOL APIENTRY DllMain( HANDLE hModule,      // handle to DLL module
134                        DWORD fdwReason,     // reason for calling function
135                        LPVOID lpReserved )  // reserved
136 {
137     // Perform actions based on the reason for calling.
138     switch( fdwReason )
139     {
140         case DLL_PROCESS_ATTACH:
141          // Initialize once for each new process.
142          // Return FALSE to fail DLL load.
143 #ifdef DEBUG_GLIDE_TO_FILE
144             glide_logstream = INVALID_HANDLE_VALUE;
145             glide_logstream = CreateFile ("r_glide.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
146                                      FILE_ATTRIBUTE_NORMAL/*|FILE_FLAG_WRITE_THROUGH*/, NULL);
147             if (glide_logstream == INVALID_HANDLE_VALUE)
148                 return FALSE;
149 #endif
150             break;
151 
152         case DLL_THREAD_ATTACH:
153          // Do thread-specific initialization.
154             break;
155 
156         case DLL_THREAD_DETACH:
157          // Do thread-specific cleanup.
158             break;
159 
160         case DLL_PROCESS_DETACH:
161          // Perform any necessary cleanup.
162 #ifdef DEBUG_GLIDE_TO_FILE
163             if ( glide_logstream != INVALID_HANDLE_VALUE ) {
164                 CloseHandle ( glide_logstream );
165                 glide_logstream  = INVALID_HANDLE_VALUE;
166             }
167 #endif
168             break;
169     }
170     return TRUE;  // Successful DLL_PROCESS_ATTACH.
171 }
172 
173 
174 // ----------
175 // DBG_Printf
176 // Output error messages to debug log if DEBUG_GLIDE_TO_FILE is defined,
177 // else do nothing
178 // ----------
DBG_Printf(LPCTSTR lpFmt,...)179 void DBG_Printf (LPCTSTR lpFmt, ...)
180 {
181 #ifdef DEBUG_GLIDE_TO_FILE
182     char    str[1999];
183     va_list arglist;
184     DWORD   bytesWritten;
185 
186     va_start  (arglist, lpFmt);
187     vsprintf (str, lpFmt, arglist);
188     va_end    (arglist);
189 
190     if ( glide_logstream != INVALID_HANDLE_VALUE )
191         WriteFile (glide_logstream, str, lstrlen(str), &bytesWritten, NULL);
192 #endif
193 }
194 
195 
196 // error callback function
GrErrorCallbackFnc(const char * string,FxBool fatal)197 void GrErrorCallbackFnc (const char *string, FxBool fatal)
198 {
199     DBG_Printf ("Glide error(%d) : %s\n",string,fatal);
200     if( fatal && I_ErrorGr )
201         I_ErrorGr ("Glide error : %s",string);
202 }
203 
204 // ==========================================================================
205 // Initialise
206 // ==========================================================================
HWRAPI(Init)207 EXPORT BOOL HWRAPI( Init ) (I_Error_t FatalErrorFunction)
208 {
209     FxU32 numboards;
210     FxI32 fxret;
211 
212     I_ErrorGr = FatalErrorFunction;
213     DBG_Printf ("HWRAPI Init(): 3Dfx Glide Render driver for Doom Legacy v1.31\n");
214 
215     // check for Voodoo card
216     // - the ONLY possible call before GlideInit
217     grGet (GR_NUM_BOARDS,4,&numboards);
218     DBG_Printf ("Num 3Dfx boards : %d\n", numboards);
219     if (!numboards) {
220         I_ErrorGr ("3dfx chipset not detected\n");
221         return FALSE;
222     }
223 
224     // init
225     grGlideInit();
226     grErrorSetCallback(GrErrorCallbackFnc);
227 
228     // select subsystem
229     grSstSelect( 0 );
230 
231     DBG_Printf( "GR_VENDOR: %s\n", grGetString(GR_VENDOR) );
232     DBG_Printf( "GR_EXTENSION: %s\n", grGetString(GR_EXTENSION) );
233     DBG_Printf( "GR_HARDWARE: %s\n", grGetString(GR_HARDWARE) );
234     DBG_Printf( "GR_RENDERER: %s\n", grGetString(GR_RENDERER) );
235     DBG_Printf( "GR_VERSION: %s\n", grGetString(GR_VERSION) );
236 
237     // info
238     grGet (GR_MAX_TEXTURE_SIZE, 4, &fxret);
239     DBG_Printf ( "Max texture size : %d\n", fxret);
240     grGet (GR_NUM_TMU, 4, &fxret);
241     DBG_Printf ( "Number of TMU's : %d\n", fxret);
242     grGet (GR_TEXTURE_ALIGN, 4, &fxret);
243     DBG_Printf ( "Align boundary for textures : %d\n", fxret);
244     // save for later!
245     gr_alignboundary = fxret;
246     if (fxret==0)
247         gr_alignboundary = 16;  //hack, need to be > 0
248 
249     glide_state[HWD_SET_FOG_MODE] = 1;
250     glide_state[HWD_SET_FOG_COLOR] = 0x7f7f7f;
251     glide_state[HWD_SET_FOG_DENSITY] = 500;
252     glide_state[HWD_SET_POLYGON_SMOOTH] = false;
253     glide_state[HWD_SET_TEXTUREFILTERMODE] = HWD_SET_TEXTUREFILTER_BILINEAR;
254 
255     SetTransform(NULL);
256 
257     return TRUE;
258 }
259 
260 
261 static viddef_t* viddef;
262 // ==========================================================================
263 //
264 // ==========================================================================
HWRAPI(Shutdown)265 EXPORT void HWRAPI( Shutdown ) (void)
266 {
267     DBG_Printf ("HWRAPI Shutdown()\n");
268     grGlideShutdown();
269     FreeFogTable();
270     glide_initialized = false;
271 }
272 
273 
274 // **************************************************************************
275 //                                                  3DFX DISPLAY MODES DRIVER
276 // **************************************************************************
277 
278 static int Set3DfxMode (viddef_t *lvid, vmode_t *pcurrentmode) ;
279 
280 
281 // --------------------------------------------------------------------------
282 //
283 // --------------------------------------------------------------------------
284 #define MAX_VIDEO_MODES         30
285 static  vmode_t         video_modes[MAX_VIDEO_MODES] = {{NULL, NULL}};
286 
287 
HWRAPI(GetModeList)288 EXPORT void HWRAPI( GetModeList ) (vmode_t** pvidmodes, int* numvidmodes)
289 {
290     GrResolution query;
291     GrResolution *list;
292     GrResolution *grRes;
293     char*   resTxt;
294     int     listSize;
295     int     listPos;
296     int     iPrevWidth, iPrevHeight;    //skip duplicate modes
297     int     iMode, iWidth, iHeight;
298 
299     DBG_Printf ("HWRAPI GetModeList()\n");
300 
301     // find all possible modes that include a z-buffer
302     query.resolution = GR_QUERY_ANY;
303     query.refresh    = GR_QUERY_ANY;
304     query.numColorBuffers = 2;  //GR_QUERY_ANY;
305     query.numAuxBuffers = 1;
306     listSize = grQueryResolutions (&query, NULL);
307     list = _alloca(listSize);
308     grQueryResolutions (&query, list);
309 
310     iMode=0;
311     grRes = list;
312     iPrevWidth = 0; iPrevHeight = 0;
313     for (listPos=0; listPos<listSize; listPos+=sizeof(GrResolution) , grRes++)
314     {
315         if (iMode>=MAX_VIDEO_MODES)
316         {
317             DBG_Printf ("Too many vidmode\n");
318             break; // quit the for
319         }
320 
321         switch (grRes->resolution)
322         {
323         case GR_RESOLUTION_320x200  : resTxt = "320x200";   iWidth = 320;  iHeight = 200;  break;
324         case GR_RESOLUTION_320x240  : resTxt = "320x240";   iWidth = 320;  iHeight = 240;  break;
325         case GR_RESOLUTION_400x256  : resTxt = "400x256";   iWidth = 400;  iHeight = 256;  break;
326         case GR_RESOLUTION_512x384  : resTxt = "512x384";   iWidth = 512;  iHeight = 384;  break;
327         case GR_RESOLUTION_640x200  : resTxt = "640x200";   iWidth = 640;  iHeight = 200;  break;
328         case GR_RESOLUTION_640x350  : resTxt = "640x350";   iWidth = 640;  iHeight = 350;  break;
329         case GR_RESOLUTION_640x400  : resTxt = "640x400";   iWidth = 640;  iHeight = 400;  break;
330         case GR_RESOLUTION_640x480  : resTxt = "640x480";   iWidth = 640;  iHeight = 480;  break;
331         case GR_RESOLUTION_800x600  : resTxt = "800x600";   iWidth = 800;  iHeight = 600;  break;
332         case GR_RESOLUTION_960x720  : resTxt = "960x720";   iWidth = 960;  iHeight = 720;  break;
333         case GR_RESOLUTION_856x480  : resTxt = "856x480";   iWidth = 856;  iHeight = 480;  break;
334         case GR_RESOLUTION_512x256  : resTxt = "512x256";   iWidth = 512;  iHeight = 256;  break;
335         case GR_RESOLUTION_1024x768 : resTxt = "1024x768";  iWidth = 1024; iHeight = 768;  break;
336         case GR_RESOLUTION_1280x1024: resTxt = "1280x1024"; iWidth = 1280; iHeight = 1024; break;
337         case GR_RESOLUTION_1600x1200: resTxt = "1600x1200"; iWidth = 1600; iHeight = 1200; break;
338         case GR_RESOLUTION_400x300  : resTxt = "400x300";   iWidth = 400;  iHeight = 300;  break;
339         case GR_RESOLUTION_NONE     : resTxt = "NONE";      iWidth = 0;    iHeight = 0;    break;
340         default:
341             iWidth = 0; iHeight = 0;
342             resTxt = "unknown resolution"; break;
343         }
344 
345         if( iWidth == 0 || iHeight == 0)
346         {
347             DBG_Printf ("Wrong Mode (%s)\n",resTxt);
348             continue;
349         }
350 
351         // skip duplicate resolutions where only the refresh rate changes
352         if( iWidth==iPrevWidth && iHeight==iPrevHeight)
353         {
354             DBG_Printf ("Same mode (%s) %d\n",resTxt,grRes->refresh);
355             continue;
356         }
357 
358         // disable too big modes until we get it fixed
359         if ( iWidth > MAXVIDWIDTH || iHeight > MAXVIDHEIGHT )
360         {
361             DBG_Printf ("Mode too big (%s)\n",resTxt);
362             continue;
363         }
364 
365         // save video mode information for video modes menu
366         video_modes[iMode].pnext = &video_modes[iMode+1];
367         video_modes[iMode].windowed = 0;
368         video_modes[iMode].misc = grRes->resolution;
369         video_modes[iMode].name = resTxt;
370         video_modes[iMode].width = iWidth;
371         video_modes[iMode].height = iHeight;
372         video_modes[iMode].rowbytes = iWidth * 2;   //framebuffer 16bit, but we don't use this anyway..
373         video_modes[iMode].bytesperpixel = 2;
374         video_modes[iMode].pextradata = NULL;       // for VESA, unused here
375         video_modes[iMode].setmode = Set3DfxMode;
376         DBG_Printf ("Mode %d : %s (%dx%d) %dHz ires %d \n",
377                      iMode,resTxt, iWidth, iHeight, grRes->refresh, grRes->resolution);
378         iMode++;
379         iPrevWidth = iWidth; iPrevHeight = iHeight;
380     }
381 
382     // add video modes to the list
383     if (iMode>0)
384     {
385         video_modes[iMode-1].pnext = NULL;
386         (*(vmode_t**)pvidmodes) = &video_modes[0];
387         (*numvidmodes) = iMode;
388     }
389 
390     // VGA Init equivalent (add first defautlt mode)
391     //glidevidmodes[NUMGLIDEVIDMODES-1].pnext = NULL;
392     //*((vmode_t**)pvidmodes) = &glidevidmodes[0];
393     //*numvidmodes = NUMGLIDEVIDMODES;
394 }
395 
396 static int currentmode_width;
397 static int currentmode_height;
398 
399 // Set3DfxMode
400 // switch to one of the video modes querried at initialization
Set3DfxMode(viddef_t * lvid,vmode_t * pcurrentmode)401 static int Set3DfxMode (viddef_t *lvid, vmode_t *pcurrentmode)
402 {
403     int     iResolution;
404 
405     // we stored the GR_RESOLUTION_XXX number into the 'misc' field
406     iResolution = pcurrentmode->misc;
407 
408     DBG_Printf ("Set3DfxMode() iResolution(%d)\n", iResolution);
409 
410     // this is normally not used (but we are actually double-buffering with glide)
411     lvid->u.numpages = 2;
412 
413     // Change window attributes
414     SetWindowLong (lvid->WndParent, GWL_STYLE, WS_POPUP | WS_VISIBLE);
415     SetWindowPos(lvid->WndParent, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE |
416                  SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
417 
418 
419     //cleanup previous mode
420     if (grPreviousContext) {
421         // close the current graphics subsystem
422         DBG_Printf ("grSstWinClose()\n");
423         grSstWinClose (grPreviousContext);
424     }
425 
426     // create Glide window
427     grPreviousContext = grSstWinOpen( (FxU32)lvid->WndParent,
428                         iResolution,
429                         GR_REFRESH_60Hz,      //note: we could always use the higher refresh?
430                         GR_COLORFORMAT_ABGR,
431                         GR_ORIGIN_UPPER_LEFT,
432                         2, 1 );
433 
434     if ( !grPreviousContext ) {
435         DBG_Printf ("grSstWinOpen() FAILED\n");
436         return 0;
437     }
438 
439     // for glide debug console
440     //tlSetScreen (pcurrentmode->width, pcurrentmode->height);
441     glide_initialized = true;
442     GR_ResetStates (lvid);
443 
444     // force reload of patches because the memory is trashed while we change the screen
445     GR_InitMipmapCache();
446 
447     lvid->buffer = NULL;    //unless we use the software view
448     lvid->direct = NULL;    //direct access to video memory, old DOS crap
449 
450     currentmode_width = pcurrentmode->width;
451     currentmode_height = pcurrentmode->height;
452 
453     // remember lvid here, to free the software buffer if we used it (software view)
454     viddef = lvid;
455 
456     return 1;
457 }
458 
459 
460 // --------------------------------------------------------------------------
461 // Swap front and back buffers
462 // --------------------------------------------------------------------------
463 static int glide_console = 1;
HWRAPI(FinishUpdate)464 EXPORT void HWRAPI( FinishUpdate ) ( int waitvbl )
465 {
466     if (!grPreviousContext) {
467         DBG_Printf ("HWRAPI FinishUpdate() : display not set\n");
468         return;
469     }
470 
471     /*
472 static int frame=0;
473 static int lasttic=0;
474     int tic,fps;
475 
476     // draw silly stuff here
477     if (glide_console & 1)
478         tlPrintNumber (frame++);
479 
480     if (glide_console & 1)
481     {
482         tic = dl.I_GetTime();
483         fps = TICRATE - (tic - lasttic) + 1;
484         lasttic = tic;
485         tlPrintNumber (fps);
486     }
487 */
488 
489     //DBG_Printf ("HWRAPI FinishUpdate()\n");
490 
491     // flip screen
492     grBufferSwap( waitvbl );
493 }
494 
495 
496 // --------------------------------------------------------------------------
497 //
498 // --------------------------------------------------------------------------
499 static unsigned long myPaletteData[256];  // 256 ARGB entries
500 //TODO: do the chroma key stuff out of here
HWRAPI(SetPalette)501 EXPORT void HWRAPI( SetPalette ) (RGBA_t* pal, RGBA_t *gamma)
502 {
503     int i;
504 
505     if (!grPreviousContext) {
506         DBG_Printf ("HWRAPI SetPalette() : display not set\n");
507         return;
508     }
509 
510     // create the palette in the format used for downloading to 3Dfx card
511     for (i=0; i<256; i++)
512         myPaletteData[i] = (pal[i].s.alpha << 24) |
513                            (pal[i].s.red<<16)     |
514                            (pal[i].s.green<<8)    |
515                             pal[i].s.blue;
516 
517     // make sure the chromakey color is always the same value
518     myPaletteData[HWR_PATCHES_CHROMAKEY_COLORINDEX] = HWR_PATCHES_CHROMAKEY_COLORVALUE;
519 
520     grTexDownloadTable (GR_TEXTABLE_PALETTE, (void*)myPaletteData);
521     guGammaCorrectionRGB(gamma->s.red/127.0f,gamma->s.green/127.0f,gamma->s.blue/127.0f);
522 }
523 
524 
525 // **************************************************************************
526 //
527 // **************************************************************************
528 
529 // store min/max w depth buffer values here, used to clear buffer
530 static  FxU32  gr_wrange[2];
531 
532 
533 // --------------------------------------------------------------------------
534 // Do a full buffer clear including color / alpha / and Z buffers
535 // --------------------------------------------------------------------------
BufferClear(void)536 static void BufferClear (void)
537 {
538     if (!grPreviousContext) {
539         DBG_Printf ("BufferClear() : display not set\n");
540         return;
541     }
542     grDepthMask (FXTRUE);
543     grColorMask (FXTRUE,FXFALSE);
544     grBufferClear(0x00000000, 0, gr_wrange[1]);
545 }
546 
547 
548 //
549 // set initial state of 3d card settings
550 //
GR_ResetStates(viddef_t * lvid)551 static void GR_ResetStates (viddef_t *lvid)
552 {
553     DBG_Printf ("ResetStates()\n");
554 
555     if (!grPreviousContext) {
556         DBG_Printf ("ResetStates() : display not set\n");
557         return;
558     }
559     //grSplash( 64, 64, SCREEN_WIDTH-64, SCREEN_HEIGHT-64, 0 ); //splash screen!
560 
561     // get min/max w buffer range values
562     grGet (GR_WDEPTH_MIN_MAX, 8, gr_wrange);
563     grCoordinateSpace(GR_CLIP_COORDS);
564     grViewport((FxU32)0, (FxU32)0, (FxU32)lvid->width, (FxU32)lvid->height);
565 
566     // don't work ! the only function that support this is drawpoly
567     // y=0 is in lower left corner, (not like in vga)
568     //grSstOrigin( GR_ORIGIN_LOWER_LEFT );
569 
570 
571     // initialize depth buffer type
572     grDepthRange( 0.0, 1.0 );
573     grDepthBufferMode(GR_DEPTHBUFFER_WBUFFER);
574     grDepthBufferFunction( GR_CMP_LEQUAL );
575     grDepthMask( FXTRUE );
576     grColorMask ( FXTRUE, FXFALSE);
577 
578     // my vertex format
579     grVertexLayout(GR_PARAM_XY   , FIELD_OFFSET(vxtx3d_t,x)   , GR_PARAM_ENABLE);
580 #ifdef _GLIDE_ARGB_
581     grVertexLayout(GR_PARAM_PARGB, FIELD_OFFSET(vxtx3d_t,argb), GR_PARAM_ENABLE);
582 #endif
583     //grVertexLayout(GR_PARAM_Q, 12, GR_PARAM_ENABLE);
584     grVertexLayout(GR_PARAM_W    , FIELD_OFFSET(vxtx3d_t,z) , GR_PARAM_ENABLE);
585     grVertexLayout(GR_PARAM_ST0  , FIELD_OFFSET(vxtx3d_t,sow) , GR_PARAM_ENABLE);  //s and t for tmu0
586 
587     grTexCombine (GR_TMU0, GR_COMBINE_FUNCTION_LOCAL,
588                   GR_COMBINE_FACTOR_NONE,
589                   GR_COMBINE_FUNCTION_LOCAL,
590                   GR_COMBINE_FACTOR_NONE,
591                   FXFALSE, FXFALSE );
592 
593     // no mipmaps based on depth
594     grTexMipMapMode (GR_TMU0, GR_MIPMAP_DISABLE, FXFALSE );
595 
596     grConstantColorValue (0xffffffff);
597 
598     grChromakeyValue(HWR_PATCHES_CHROMAKEY_COLORVALUE);
599 
600     grAlphaTestReferenceValue( 0 );
601 
602     // this set CurrentPolyFlags to the acctual configuration
603     CurrentPolyFlags = 0xffffffff;
604     SetBlend(0);
605 
606     BufferClear();
607     MakeFogTable();
608     ReSetSpecialState();
609 }
610 
611 
612 // **************************************************************************
613 //                                               3DFX MEMORY CACHE MANAGEMENT
614 // **************************************************************************
615 
616 #define TEXMEM_2MB_EDGE         (1<<21)
617 
618 static  FxU32           gr_cachemin;
619 static  FxU32           gr_cachemax;
620 
621 static  FxU32           gr_cachepos;
622 static  Mipmap_t*  gr_cachetail = NULL;
623 static  Mipmap_t*  gr_cachehead;
624 static  Mipmap_t*  lastmipmapset;
625 
626 // --------------------------------------------------------------------------
627 // This must be done once only for all program execution
628 // --------------------------------------------------------------------------
629 Mipmap_t fakemipmap;
GR_ClearMipmapCache(void)630 static void GR_ClearMipmapCache (void)
631 {
632     while (gr_cachetail)
633     {
634         gr_cachetail->downloaded = false;
635         gr_cachehead = gr_cachetail;
636         gr_cachetail = gr_cachetail->nextmipmap;
637         gr_cachehead->nextmipmap = NULL;
638     }
639 
640     // make a dummy first just for easy cache handling
641     fakemipmap.cachepos = gr_cachemin;
642     fakemipmap.mipmapSize = grTexCalcMemRequired(GR_LOD_LOG2_1,GR_LOD_LOG2_1,GR_ASPECT_LOG2_1x1,GR_TEXFMT_P_8);
643     fakemipmap.downloaded = true;
644     fakemipmap.nextmipmap = NULL;
645     lastmipmapset = NULL;
646 
647     gr_cachetail = &fakemipmap;
648     gr_cachehead = &fakemipmap;
649     gr_cachepos = gr_cachetail->cachepos + fakemipmap.mipmapSize;
650 
651     DBG_Printf ("Cache cleared\n");
652 }
653 
HWRAPI(ClearMipMapCache)654 EXPORT void HWRAPI( ClearMipMapCache ) (void)
655 {
656     GR_ClearMipmapCache ();
657 }
658 
GR_InitMipmapCache(void)659 static void GR_InitMipmapCache (void)
660 {
661     gr_cachemin = grTexMinAddress(GR_TMU0);
662     gr_cachemax = grTexMaxAddress(GR_TMU0);
663 
664     // deboging...
665     // reduise memory so there will use more the legacy heap
666     //gr_cachemax = gr_cachemin + (256<<10);
667 
668     if( gr_cachemax-gr_cachemin < 64<<10 )
669         I_ErrorGr("R_Glide : Only %d memory available for texture !\n",gr_cachemax-gr_cachemin);
670 
671     GR_ClearMipmapCache();
672 
673     DBG_Printf ("HWR_InitMipmapCache() : %d kb, from %x to %x\n"
674                 "tmu2 : from %x to %x\n", (gr_cachemax-gr_cachemin)>>10,gr_cachemin,gr_cachemax,
675                                            grTexMinAddress(GR_TMU1),grTexMaxAddress(GR_TMU1));
676 }
677 
678 static boolean possibleproblem=false;
679 
GR_FlushMipmap()680 static void GR_FlushMipmap ()
681 {
682     if( !gr_cachetail)
683         return;
684     if(!gr_cachetail->downloaded)
685         DBG_Printf ("flush not dowloaded !!\n");
686     gr_cachetail->downloaded = false;
687     // should never happen
688     if (!gr_cachetail->nextmipmap)
689     {
690         if( possibleproblem )
691             I_ErrorGr ("This just CAN'T HAPPEN!!! So you think you're different eh ?");
692         possibleproblem=true;
693         DBG_Printf ("Never happen happen !!\n");
694         GR_ClearMipmapCache ();
695     }
696     else
697     {
698 //        DBG_Printf ("flushing mipmap at position %d (%d bytes) tailpos=%d (%d byte)\n",gr_cachetail->cachepos,gr_cachetail->mipmapSize,gr_cachetail->nextmipmap->cachepos,gr_cachetail->nextmipmap->mipmapSize);
699         gr_cachetail->cachepos = 0;
700         gr_cachetail->mipmapSize = -1;
701         gr_cachetail = gr_cachetail->nextmipmap;
702     }
703 }
704 
705 // --------------------------------------------------------------------------
706 // Download a 'surface' into the graphics card memory
707 // --------------------------------------------------------------------------
GR_DownloadMipmap(Mipmap_t * grMipmap)708 static void GR_DownloadMipmap (Mipmap_t* grMipmap)
709 {
710     FxU32   mipmapSize;
711 
712     if (!grPreviousContext) {
713         DBG_Printf ("HWRAPI DownloadMipmap() : display not set\n");
714         return;
715     }
716 
717     if ( !grMipmap->grInfo.data ) {
718         DBG_Printf ("HWRAPI DownloadMipmap() : No DATA !!!\n");
719         return;
720     }
721 
722     mipmapSize = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &grMipmap->grInfo);
723 
724     while (1)
725     {
726         // 3Dfx specs : a mipmap level can not straddle the 2MByte boundary
727         if (gr_cachetail->cachepos >= gr_cachepos)
728         {
729             if (gr_cachetail->cachepos >= gr_cachepos + mipmapSize)
730                 if((gr_cachepos < TEXMEM_2MB_EDGE) && (gr_cachepos+mipmapSize > TEXMEM_2MB_EDGE))
731                 {
732                     if( gr_cachetail->cachepos >= TEXMEM_2MB_EDGE )
733                     {
734                         gr_cachepos = TEXMEM_2MB_EDGE;
735                         continue;
736                     }
737                     // else FlushMipmap
738                 }
739                 else
740                     break;
741             GR_FlushMipmap ();
742         }
743         else
744         {
745             if (gr_cachemax >= gr_cachepos + mipmapSize)
746             {
747                 if((gr_cachepos < TEXMEM_2MB_EDGE) && (gr_cachepos+mipmapSize > TEXMEM_2MB_EDGE) && (gr_cachetail->cachepos < TEXMEM_2MB_EDGE))
748                     gr_cachepos = TEXMEM_2MB_EDGE;
749                 else
750                     break;
751             }
752             else
753                 // not enough space in the end of the buffer
754                 gr_cachepos = gr_cachemin;
755                 //dbg_printf ("        cycle over\n");
756         }
757         //dbg_printf ("        tailpos: %7d pos: %7d size: %7d free: %7d\n",
758         //            gr_cachetail->cachepos, gr_cachepos, mipmapsize, freespace);
759     }
760     gr_cachehead->nextmipmap = grMipmap;
761 
762     //DBG_Printf ("download %d byte at %d\n",mipmapSize,gr_cachepos);
763 
764     grTexDownloadMipMap (GR_TMU0, gr_cachepos, GR_MIPMAPLEVELMASK_BOTH, &grMipmap->grInfo);
765     grMipmap->cachepos     = gr_cachepos;
766     grMipmap->mipmapSize   = mipmapSize;
767     grMipmap->downloaded   = true;
768     grMipmap->nextmipmap    = NULL;     // the head don't have next
769 
770     gr_cachepos += mipmapSize;
771 
772     gr_cachehead = grMipmap;   // the head is the last loaded texture (FIFO)
773     possibleproblem=false;
774 }
775 
776 
777 // ==========================================================================
778 // The mipmap becomes the current texture source
779 // ==========================================================================
HWRAPI(SetTexture)780 EXPORT void HWRAPI( SetTexture ) (Mipmap_t* grMipmap)
781 {
782     FBITFIELD xor;
783     if (!grPreviousContext) {
784         DBG_Printf ("HWRAPI SetTexture() : display not set\n");
785         return;
786     }
787 
788     // don't set exactly the same mipmap
789     if( lastmipmapset == grMipmap )
790         return;
791 
792     if (!grMipmap->downloaded)
793         GR_DownloadMipmap (grMipmap);
794 
795     xor = grMipmap->tfflags ^ CurrentTextureFlags;
796     if(xor)
797     {
798         if(xor&TF_WRAPXY)
799         {
800             switch(grMipmap->tfflags & TF_WRAPXY)
801         {
802             case 0 :
803                 grTexClampMode (GR_TMU0, GR_TEXTURECLAMP_CLAMP, GR_TEXTURECLAMP_CLAMP);
804                 break;
805             case TF_WRAPX :
806                 grTexClampMode (GR_TMU0, GR_TEXTURECLAMP_WRAP , GR_TEXTURECLAMP_CLAMP);
807                 break;
808             case TF_WRAPY :
809                 grTexClampMode (GR_TMU0, GR_TEXTURECLAMP_CLAMP, GR_TEXTURECLAMP_WRAP);
810                 break;
811             case TF_WRAPXY :
812                 grTexClampMode (GR_TMU0, GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP);
813                 break;
814         }
815         }
816         if( xor & TF_CHROMAKEYED )
817         {
818             if(grMipmap->tfflags & TF_CHROMAKEYED )
819                 grChromakeyMode (GR_CHROMAKEY_ENABLE);
820             else
821                 grChromakeyMode (GR_CHROMAKEY_DISABLE);
822         }
823         CurrentTextureFlags = grMipmap->tfflags;
824     }
825     grTexSource (GR_TMU0, grMipmap->cachepos, GR_MIPMAPLEVELMASK_BOTH, &grMipmap->grInfo);
826     lastmipmapset = grMipmap;
827 }
828 
829 
830 // -----------------+
831 // SetBlend         : Set render mode
832 // -----------------+
833 // PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0,
834 //             is it faster when pixels are discarded ?
HWRAPI(SetBlend)835 EXPORT void HWRAPI(     SetBlend ) ( FBITFIELD PolyFlags )
836 {
837     FBITFIELD Xor;
838 
839     if (!grPreviousContext) {
840         DBG_Printf ("HWRAPI SetBlend() : display not set\n");
841         return;
842     }
843 
844     // Detect changes in the blending modes.
845     Xor = CurrentPolyFlags^PolyFlags;
846     if( !Xor )
847         return;
848 
849     if( Xor&(PF_Blending) ) // if blending mode must be changed
850     {
851         switch(PolyFlags & PF_Blending) {
852             case PF_Translucent & PF_Blending:
853                 grAlphaBlendFunction (GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA,
854                                       GR_BLEND_ONE      , GR_BLEND_ZERO );
855                 break;
856             case PF_Masked & PF_Blending:
857                 // no alpha blending
858                 grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ZERO, GR_BLEND_ONE, GR_BLEND_ZERO);
859                 break;
860             case PF_Additive & PF_Blending:
861                 // blend destination for transparency, but no source for additive
862                 grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE, GR_BLEND_ONE, GR_BLEND_ZERO);
863                 break;
864             case PF_Environment & PF_Blending:
865                 grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ONE_MINUS_SRC_ALPHA,
866                                       GR_BLEND_ONE, GR_BLEND_ZERO );
867                 break;
868             case PF_Substractive & PF_Blending:
869                 // not realy but what else ?
870                 grAlphaBlendFunction (GR_BLEND_ZERO, GR_BLEND_ONE_MINUS_SRC_COLOR,
871                                       GR_BLEND_ONE , GR_BLEND_ZERO );
872                 break;
873             default :
874                 grAlphaBlendFunction (GR_BLEND_ONE,GR_BLEND_ZERO,GR_BLEND_ONE,GR_BLEND_ZERO );
875                 break;
876         }
877     }
878     if( Xor & PF_NoAlphaTest)
879     {
880         if( PolyFlags & PF_NoAlphaTest)
881             // desable alpha testing
882             grAlphaTestFunction (GR_CMP_ALWAYS);
883         else
884             // discard 0 alpha pixels (holes in texture)
885             grAlphaTestFunction (GR_CMP_GREATER);
886     }
887     if( Xor & PF_Decal )
888     {
889         // work a little but not like opengl one :(
890         if( PolyFlags & PF_Decal )
891             grDepthBiasLevel( -1 );
892         else
893             grDepthBiasLevel( 0 );
894     }
895     if( Xor&(PF_Modulated | PF_NoTexture))
896     {
897         switch (PolyFlags & (PF_Modulated | PF_NoTexture)) {
898         case 0 :
899             // colour from texture is unchanged before blending
900             grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
901                             GR_COMBINE_FACTOR_ONE,
902                             GR_COMBINE_LOCAL_NONE,
903                             GR_COMBINE_OTHER_TEXTURE,
904                             FXFALSE );
905             // use alpha texture only
906             grAlphaCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
907                             GR_COMBINE_FACTOR_ONE,
908                             GR_COMBINE_LOCAL_NONE,
909                             GR_COMBINE_OTHER_TEXTURE,
910                             FXFALSE );
911             break;
912         case PF_Modulated :
913             // mix texture colour with Surface->FlatColor (constant color)
914             grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,        // factor * Color other
915                             GR_COMBINE_FACTOR_LOCAL,                // or local_alpha ???
916                             GR_COMBINE_LOCAL_CONSTANT,              // local is constant color
917                             GR_COMBINE_OTHER_TEXTURE,               // color from texture map
918                             FXFALSE );
919             // use (alpha constant)*(alpha texture)
920             grAlphaCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
921                             GR_COMBINE_FACTOR_LOCAL,
922                             GR_COMBINE_LOCAL_CONSTANT,
923                             GR_COMBINE_OTHER_TEXTURE,
924                             FXFALSE );
925             break;
926         case PF_NoTexture :
927             // no texture, no modulate what color use ?
928             // in opengl fab use white texture
929             grConstantColorValue(0xffFFffFF);
930             // no need break
931         case PF_Modulated | PF_NoTexture :
932             grColorCombine( GR_COMBINE_FUNCTION_LOCAL,              // factor * Color other
933                             GR_COMBINE_FACTOR_NONE,
934                             GR_COMBINE_LOCAL_CONSTANT,              // local is constant color
935                             GR_COMBINE_OTHER_NONE,                  // color from texture map
936                             FXFALSE);
937             // use (alpha constant)*(alpha texture)
938             grAlphaCombine( GR_COMBINE_FUNCTION_LOCAL,
939                             GR_COMBINE_FACTOR_NONE,
940                             GR_COMBINE_LOCAL_CONSTANT,
941                             GR_COMBINE_OTHER_NONE,
942                             FXFALSE );
943             break;
944         }
945     }
946     if( Xor&PF_NoDepthTest )
947     {
948         if( PolyFlags & PF_NoDepthTest )
949             grDepthBufferFunction(GR_CMP_ALWAYS);
950         else
951             grDepthBufferFunction(GR_CMP_LEQUAL);
952     }
953     if( Xor & PF_Occlude )
954     {
955         // depth is tested but no writed
956         grDepthMask( (PolyFlags&PF_Occlude)!=0 );
957     }
958     if( Xor & PF_Invisible )
959     {
960         grColorMask( (PolyFlags&PF_Invisible)==0 , FXFALSE );
961     }
962 
963     CurrentPolyFlags = PolyFlags;
964 }
965 
966 
967 // ==========================================================================
968 // Read a rectangle region of the truecolor framebuffer
969 // store pixels as 16bit 565 RGB
970 // ==========================================================================
HWRAPI(ReadRect)971 EXPORT void HWRAPI( ReadRect ) (int x, int y, int width, int height,
972                                 /*OUT*/ byte * buf, byte * bitpp )
973 {
974     if (!grPreviousContext) {
975         DBG_Printf ("HWRAPI ReadRect() : display not set\n");
976         return;
977     }
978     // dst_stride = width*2
979     grLfbReadRegion (GR_BUFFER_FRONTBUFFER,
980                      x, y, width, height, width*2, (uint16_t*)buf);
981     *bitpp = 16;  // return output
982 }
983 
984 
985 // ==========================================================================
986 // Defines the 2D hardware clipping window
987 // ==========================================================================
HWRAPI(GClipRect)988 EXPORT void HWRAPI( GClipRect ) (int minx, int miny, int maxx, int maxy, float nearclip)
989 {
990     if (!grPreviousContext) {
991         DBG_Printf ("HWRAPI GClipRect() : display not set\n");
992         return;
993     }
994     // BP: swap maxy and miny because wrong axe position
995     grClipWindow ( (FxU32)minx, (FxU32)miny, (FxU32)maxx, (FxU32)maxy);
996 }
997 
998 
999 // -----------------+
1000 // HWRAPI ClearBuffer
1001 //                  : Clear the color/alpha/depth buffer(s)
1002 // -----------------+
HWRAPI(ClearBuffer)1003 EXPORT void HWRAPI( ClearBuffer ) ( boolean ColorMask, boolean DepthMask,
1004                                     RGBA_float_t * ClearColor )
1005 {
1006     FBITFIELD polyflags;
1007 
1008     if (!grPreviousContext) {
1009         DBG_Printf ("HWRAPI ClearBuffer() : display not set\n");
1010         return;
1011     }
1012 
1013     grColorMask (ColorMask, FXFALSE);
1014 
1015     polyflags = CurrentPolyFlags;
1016     // enable or desable z-buffer
1017     if( DepthMask )
1018         polyflags |= PF_Occlude;
1019     else
1020         polyflags &= ~PF_Occlude;
1021     // enable disable colorbuffer
1022     if( ColorMask )
1023         polyflags &= ~PF_Invisible;
1024     else
1025         polyflags |= PF_Invisible;
1026 
1027     SetBlend( polyflags );
1028 
1029     if( ClearColor )
1030         grBufferClear ((int)(ClearColor->alpha*255)<<24|
1031                        (int)(ClearColor->red*255)<<16  |
1032                        (int)(ClearColor->green*255)<<8 |
1033                        (int)(ClearColor->blue)*255,
1034                        0, gr_wrange[1]);
1035     else
1036         grBufferClear (0,0,gr_wrange[1]);
1037 }
1038 
1039 
1040 // -----------------+
1041 // HWRAPI Draw2DLine: Render a 2D line
1042 // -----------------+
HWRAPI(Draw2DLine)1043 EXPORT void HWRAPI( Draw2DLine ) ( v2d_t * v1, v2d_t * v2, RGBA_t Color )
1044 {
1045     vxtx3d_t a,b;
1046 
1047     if (!grPreviousContext) {
1048         DBG_Printf ("HWRAPI DrawLine() : display not set\n");
1049         return;
1050     }
1051 
1052     a.x = v1->x;
1053     a.y = v1->y;
1054     a.z = 1.0f;
1055 
1056     b.x = v2->x;
1057     b.y = v2->y;
1058     b.z = 1.0f;
1059 
1060     SetBlend( PF_Modulated|PF_NoTexture );
1061     grConstantColorValue(Color.rgba);
1062 
1063     // damed, 3dfx have a bug in grDrawLine !
1064     //v1->y = -v1->y;
1065     //v2->y = -v2->y;
1066 
1067     grDrawLine (&a, &b);
1068 }
1069 
1070 // convert 4exp mantice 12 (w-buffer) to ieee float
1071 #define W16_TO_FLOAT(w) ((( ( ((int)w) & 0xF000) <<11) + 0x3F800000) | ((( ((int)w) & 0xFFF)<<11) + (1<<10)) )
1072 // convert ieee float to 4exp mantice 12 (w-buffer)
1073 #define FLOAT_TO_W16(f) ( ( ( ( (*(int*)&(f)) & 0x7F800000) - 0x3F800000)>>11 ) | ( ( *(int*)&(f) & 0x7FFFFF)>>11)  )
1074 #define BYTEPERPIXEL 2
1075 
1076 // test if center of corona is visible with the zbuffer (need raw acces to zbuffer)
ComputeCoronaAlpha(float * retscalef,vxtx3d_t * projVerts)1077 static boolean ComputeCoronaAlpha( float *retscalef, vxtx3d_t *projVerts )
1078 {
1079 #define NUMPIXELS 8
1080     unsigned short buf[NUMPIXELS][NUMPIXELS];
1081     float     cx, cy, cz;
1082     float     scalef = 0;
1083     int       x,y;
1084     int       i,j;
1085     unsigned short z;
1086 
1087     // negative z, so not drawed !
1088     if( projVerts[0].z < 0)
1089         return false;
1090 
1091     cx = (projVerts[0].x + projVerts[2].x) / 2.0f; // we should change the coronas' ...
1092     cy = (projVerts[0].y + projVerts[2].y) / 2.0f; // ... code so its only done once.
1093     cz = projVerts[0].z;
1094     //DBG_Printf("z : %f\n",cz);
1095 
1096     // project (note y is -y in glide)
1097     x = (int)(currentmode_width * (1 + cx / cz) /2);
1098     if(x>=currentmode_width || x<0) return false;
1099     y = (int)(currentmode_height * (1 - cy / cz) /2);
1100     if(y>=currentmode_height || y<0) return false;
1101 
1102     // get z buffer
1103     grLfbReadRegion( GR_BUFFER_AUXBUFFER,
1104                      x-NUMPIXELS/2,y-NUMPIXELS/2,NUMPIXELS,NUMPIXELS,
1105                      BYTEPERPIXEL*NUMPIXELS,buf);
1106 
1107     // comparaison in float are the same as in int so use int compare
1108     // anyway 1 comparaison is better than 64 !
1109     z = FLOAT_TO_W16(cz);
1110     //DBG_Printf("z (w16) : %x\n",z);
1111     for (i=0; i<NUMPIXELS; i++)
1112         if(i+x>=0 && i+x<currentmode_width)
1113             for (j=0; j<NUMPIXELS; j++)
1114             {
1115                 // BP: it seam like not perfect :( not find why ...
1116 #if 1
1117                 if(z < buf[i][j] && j+y>=0 && j+y<currentmode_height)
1118                     scalef += 1;
1119                 //DBG_Printf("buf[%d][%d]=%x (w16) : %x scale %f\n",i,j,buf[i][j],z,scalef);
1120 #else
1121                 float f;
1122                 *(int *)&f = W16_TO_FLOAT(buf[i][j]);
1123                 if(cz < f && j+y>=0 && j+y<currentmode_height)
1124                     scalef += 1;
1125                 //DBG_Printf("buf[%d][%d] : %f scale %f\n",i,j,f,scalef);
1126 #endif
1127 
1128             }
1129 
1130     scalef /= NUMPIXELS*NUMPIXELS;
1131 
1132 #if 0 // see what pixel we are testing !
1133             // write white rectangle
1134     for(i=0;i<NUMPIXELS;i++)
1135         for(j=0;j<NUMPIXELS;j++)
1136             buf[i][j] = 0xffff;
1137     grLfbWriteRegion( GR_BUFFER_BACKBUFFER,
1138                       x-NUMPIXELS/2,y-NUMPIXELS/2,GR_LFB_SRC_FMT_565,
1139                       NUMPIXELS,NUMPIXELS,FXTRUE,
1140                       BYTEPERPIXEL*NUMPIXELS,buf);
1141 
1142     // can't be overwrited, z=0
1143     for(i=0;i<8;i++)
1144         for(j=0;j<8;j++)
1145             buf[i][j] = 0x0000;
1146     grLfbWriteRegion( GR_BUFFER_AUXBUFFER,
1147                       x-NUMPIXELS/2,y-NUMPIXELS/2,GR_LFB_SRC_FMT_ZA16,
1148                       NUMPIXELS,NUMPIXELS,FXTRUE,
1149                       BYTEPERPIXEL*NUMPIXELS,buf);
1150 
1151 #endif
1152     if (scalef < 0.05) // alpha too small so don't draw
1153         return false;
1154 
1155     *retscalef = scalef;
1156     return true;
1157 }
1158 
doTransform(vxtx3d_t * projVerts,FUINT nClipVerts)1159 static vxtx3d_t * doTransform(vxtx3d_t *projVerts,
1160                                FUINT       nClipVerts )
1161 {
1162     float tx,ty,tz;
1163     FUINT i;
1164     vxtx3d_t *p = tmp3Verts;
1165 
1166     for(i=0;i<nClipVerts;i++,p++,projVerts++)
1167     {
1168 
1169         *p = *projVerts; // copy texture coord too
1170         tx = projVerts->x - grTransform.x;
1171         ty = projVerts->y - grTransform.z;
1172         tz = projVerts->z - grTransform.y;
1173 
1174         p->x = tx*sxsiny - tz * sxcosy;
1175         tz   = tx*cosy + tz * siny;
1176 
1177         p->y =  ty * sycosx - tz * sysinx;
1178         p->z =  ty * szsinx + tz * szcosx;
1179 
1180     }
1181 
1182     return tmp3Verts;
1183 }
1184 
1185 
1186 // ==========================================================================
1187 // Draw a triangulated polygon
1188 // ==========================================================================
HWRAPI(DrawPolygon)1189 EXPORT void HWRAPI( DrawPolygon ) ( FSurfaceInfo  *pSurf,
1190                                     vxtx3d_t      *projVerts,
1191                                     FUINT         nClipVerts,
1192                                     FBITFIELD     PolyFlags )
1193 {
1194     int i;
1195 
1196     if (!grPreviousContext) {
1197         DBG_Printf ("HWRAPI DrawPolygon() : display not set\n");
1198         return;
1199     }
1200 
1201     if (nClipVerts < 3)
1202         return;
1203 
1204     SetBlend( PolyFlags );
1205 
1206     projVerts = doTransform(projVerts, nClipVerts);
1207 
1208     // this test is added for new coronas' code (without depth buffer)
1209     // I think I should do a separate function for drawing coronas, so it will be a little faster
1210     if (PolyFlags & PF_Corona) // check to see if we need to draw the corona
1211     {
1212         RGBA_t c;
1213         float  scalef;
1214 
1215         if( !ComputeCoronaAlpha(&scalef, projVerts) )
1216             return;
1217 
1218         c.rgba = pSurf->FlatColor.rgba;
1219         c.s.alpha *= scalef; // change the alpha value (it seems better than changing the size of the corona)
1220         grConstantColorValue(c.rgba);
1221     }
1222     else
1223     if( (CurrentPolyFlags & PF_Modulated) && pSurf )
1224         grConstantColorValue(pSurf->FlatColor.rgba);
1225 
1226 
1227     // cut polygone to the screen
1228     if( CurrentPolyFlags & PF_Clip )
1229     {
1230         if( CurrentPolyFlags & PF_NoZClip )
1231         {
1232             nClipVerts = ClipToFrustum (projVerts, tmp2Verts, nClipVerts );
1233 
1234             if (nClipVerts<3)
1235                 return;
1236         }
1237         else
1238         {
1239             // clip to near z plane
1240             nClipVerts = ClipZ (projVerts, tmpVerts, nClipVerts );
1241 
1242             // -!!!- EXIT HERE if not enough points
1243             if (nClipVerts<3)
1244                 return;
1245             nClipVerts = ClipToFrustum (tmpVerts, tmp2Verts, nClipVerts );
1246 
1247             if (nClipVerts<3)
1248                 return;
1249         }
1250 
1251         projVerts=tmp2Verts;
1252     }
1253 
1254     for(i=0; (FUINT)i < nClipVerts; i++)
1255         projVerts[i].y = -projVerts[i].y;
1256 
1257     grDrawVertexArrayContiguous(GR_POLYGON, nClipVerts, projVerts, sizeof(vxtx3d_t));
1258 }
1259 
1260 // ==========================================================================
1261 // Fog stuff
1262 // ==========================================================================
1263 static GrFog_t *fogtable =NULL;
1264 static float fogdensity=500.0f/(6000.0f);
1265 static int nFog=0;
1266 
ComputeFogTable(void)1267 static void ComputeFogTable(void)
1268 {
1269     int     i,j;
1270 
1271     // happen because cvar execution of config.cfg
1272     if(!fogtable)
1273     {
1274         DBG_Printf ("Fog table size: nFog %d\n", nFog);
1275         return;
1276     }
1277 
1278     // the table is an exponential fog table. It computes q from i using guFogTableIndexToW()
1279     // and then computes the fog table entries as fog[i]=(1�e -kw )�255 where k is a user-defined
1280     // constant, FOG_DENSITY.
1281     for (i=0; i<nFog; i++) {
1282         // remove (float) to see original doom bands
1283 
1284         //j = (int) (exp((float)i*fogdensity)-1);
1285         //j = (int)((1 - exp((- fogdensity) * guFogTableIndexToW(i))) * 255);
1286         j = fogdensity * i*i;//guFogTableIndexToW(i);
1287         //DBG_Printf ("Fog[%d]= %d\n", i, j);
1288         // see something even if far
1289         //if (j > 128) j = 128;
1290         if (j > 200) j = 200;
1291         fogtable[i] = j;
1292 
1293     }
1294     grFogTable (fogtable);
1295 }
1296 
MakeFogTable(void)1297 static void MakeFogTable(void)
1298 {
1299     FreeFogTable();
1300 
1301     grGet (GR_FOG_TABLE_ENTRIES, 4, &nFog);
1302 
1303     fogtable = (GrFog_t*) malloc(nFog * sizeof(GrFog_t) );
1304 
1305     if (!fogtable)
1306         I_ErrorGr ("could not allocate fog table\n");
1307     else
1308         DBG_Printf ("Fog table size: nFog %d\n", nFog);
1309 
1310     ComputeFogTable();
1311 }
1312 
FreeFogTable(void)1313 static void FreeFogTable(void)
1314 {
1315     if(fogtable)
1316     {
1317         free(fogtable);
1318         fogtable = NULL;
1319     }
1320 }
1321 
1322 
1323 
1324 // ==========================================================================
1325 //
1326 // ==========================================================================
Glide_SetSpecialState(hwd_specialstate_e IdState,int value)1327 static Glide_SetSpecialState( hwd_specialstate_e IdState, int value )
1328 {
1329     switch (IdState)
1330     {
1331         case HWD_SET_FOG_MODE:
1332             if( value )
1333                 grFogMode (GR_FOG_WITH_TABLE_ON_Q);
1334             else
1335                 grFogMode (GR_FOG_DISABLE);
1336             break;
1337 
1338         case HWD_SET_FOG_COLOR:
1339             grFogColorValue (value);
1340             break;
1341 
1342         case HWD_SET_FOG_DENSITY:
1343             fogdensity = (float)value/(6000.0f);
1344             ComputeFogTable();
1345             break;
1346 
1347         case HWD_SET_FOV:
1348             //can't be implementd until we find a "Liang-Barsky" algo for non 90�
1349             break;
1350 
1351         case HWD_SET_POLYGON_SMOOTH:
1352             if( value )
1353                 grEnable(GR_AA_ORDERED);
1354             else
1355                 grDisable(GR_AA_ORDERED);
1356             break;
1357         case HWD_SET_TEXTUREFILTERMODE:
1358             switch (value) {
1359                 case HWD_SET_TEXTUREFILTER_BILINEAR :
1360                 case HWD_SET_TEXTUREFILTER_TRILINEAR:
1361                      grTexFilterMode (GR_TMU0, GR_TEXTUREFILTER_BILINEAR,
1362                                                GR_TEXTUREFILTER_BILINEAR);
1363                      break;
1364                 case HWD_SET_TEXTUREFILTER_POINTSAMPLED :
1365                      grTexFilterMode (GR_TMU0, GR_TEXTUREFILTER_POINT_SAMPLED,
1366                                                GR_TEXTUREFILTER_POINT_SAMPLED);
1367                      break;
1368                 case HWD_SET_TEXTUREFILTER_MIXED1 :
1369                      grTexFilterMode (GR_TMU0, GR_TEXTUREFILTER_BILINEAR,
1370                                                GR_TEXTUREFILTER_POINT_SAMPLED);
1371                      break;
1372                 case HWD_SET_TEXTUREFILTER_MIXED2 :
1373                      grTexFilterMode (GR_TMU0, GR_TEXTUREFILTER_POINT_SAMPLED,
1374                                                GR_TEXTUREFILTER_BILINEAR);
1375                      break;
1376             }
1377             break;
1378     }
1379 }
1380 
ReSetSpecialState(void)1381 static void ReSetSpecialState(void)
1382 {
1383     int i;
1384     for(i=0;i<HWD_NUMSTATE;i++)
1385         Glide_SetSpecialState(i, glide_state[i]);
1386 }
1387 
HWRAPI(SetSpecialState)1388 EXPORT void HWRAPI( SetSpecialState ) (hwdspecialstate_t IdState, int value)
1389 {
1390     glide_state[IdState]=value;
1391     if( glide_initialized )
1392         Glide_SetSpecialState(IdState, value);
1393 }
1394 
1395 
1396 // -----------------+
1397 // HWRAPI DrawMD2   : Draw an MD2 model with glcommands
1398 // -----------------+
HWRAPI(DrawMD2)1399 EXPORT void HWRAPI( DrawMD2 ) (int *gl_cmd_buffer, md2_frame_t *frame,
1400                                FTransform_t *pos, float scale)
1401 {
1402 }
1403 
HWRAPI(SetTransform)1404 EXPORT void HWRAPI( SetTransform ) (FTransform_t *transform_parm)
1405 {
1406     float sinx, cosx;
1407 
1408     if( transform_parm )
1409         grTransform = *transform_parm;
1410     else
1411         grTransform = defaulttransform;
1412 
1413     sinx = sin( grTransform.anglex*2*PI/360);
1414     cosx = cos( grTransform.anglex*2*PI/360);
1415     siny = sin( grTransform.angley*2*PI/360);
1416     cosy = cos( grTransform.angley*2*PI/360);
1417 
1418     szsinx = sinx * grTransform.scalez;
1419     szcosx = cosx * grTransform.scalez;
1420     sxsiny = siny * grTransform.scalex * (1/tan(grTransform.fovxangle*PI/360));
1421     sxcosy = cosy * grTransform.scalex * (1/tan(grTransform.fovxangle*PI/360));
1422     sysinx = sinx * grTransform.scaley * (1/tan(grTransform.fovyangle*PI/360));
1423     sycosx = cosx * grTransform.scaley * (1/tan(grTransform.fovyangle*PI/360));
1424 }
1425 
1426 
HWRAPI(GetTextureUsed)1427 EXPORT int  HWRAPI( GetTextureUsed ) (void)
1428 {
1429     FTextureInfo*   tmp = gr_cachehead;
1430     int             res = 0;
1431 
1432     for(tmp=gr_cachetail;tmp;tmp = tmp->nextmipmap)
1433         res += tmp->mipmapSize;
1434     return res;
1435 }
1436 
HWRAPI(GetRenderVersion)1437 EXPORT int  HWRAPI( GetRenderVersion ) (void)
1438 {
1439     return VERSION;
1440 }
1441