DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/voodoo_opengl.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 // Tell Mac OS X to shut up about deprecated OpenGL calls
00020 #ifndef GL_SILENCE_DEPRECATION
00021 #define GL_SILENCE_DEPRECATION
00022 #endif
00023 
00024 #include <stdlib.h>
00025 #include <math.h>
00026 #include <map>
00027 
00028 #include "dosbox.h"
00029 #include "video.h"
00030 
00031 #include "voodoo_emu.h"
00032 #include "voodoo_opengl.h"
00033 #include "sdlmain.h"
00034 
00035 #if C_OPENGL
00036 
00037 #if defined(_MSC_VER)
00038 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00039 #endif
00040 
00041 #include "voodoo_def.h"
00042 
00043 SDL_Surface* ogl_surface = NULL;
00044 
00045 INT32 cached_line_front_y=-1;
00046 INT32 cached_line_front_width = -1;
00047 INT32 cached_line_front_length=-1;
00048 INT32 cached_line_front_pixels=-1;
00049 UINT32* cached_line_front_data=NULL;
00050 
00051 INT32 cached_line_back_y=-1;
00052 INT32 cached_line_back_width = -1;
00053 INT32 cached_line_back_length=-1;
00054 INT32 cached_line_back_pixels=-1;
00055 UINT32* cached_line_back_data=NULL;
00056 
00057 static INT32 adjust_x=0;
00058 static INT32 adjust_y=0;
00059 
00060 static UINT32 last_clear_color=0;
00061 
00062 static UINT32 last_width=0;
00063 static UINT32 last_height=0;
00064 static INT32 last_orientation=-1;
00065 
00066 
00067 static UINT32 ogl_texture_index = 1;
00068 
00069 
00070 /* texture cache buffer */
00071 UINT32 texrgb[256*256];
00072 
00073 
00074 /* texture address map */
00075 std::map <const UINT32, ogl_texmap> textures[2];
00076 
00077 void GFX_PreventFullscreen(bool lockout);
00078 
00079 int Voodoo_OGL_GetWidth() {
00080         if (v != NULL)
00081                 return (int)v->fbi.width;
00082         else
00083                 return 0;
00084 }
00085 
00086 int Voodoo_OGL_GetHeight() {
00087         if (v != NULL)
00088                 return (int)v->fbi.height;
00089         else
00090                 return 0;
00091 }
00092 
00093 bool Voodoo_OGL_Active() {
00094         return (v != NULL && v->clock_enabled && v->output_on);
00095 }
00096 
00097 static void ogl_get_depth(voodoo_state* VV, INT32 ITERZ, INT64 ITERW, INT32 *depthval, INT32 *out_wfloat)
00098 {
00099         INT32 wfloat;
00100         UINT32 FBZMODE = VV->reg[fbzMode].u;
00101         UINT32 FBZCOLORPATH = VV->reg[fbzColorPath].u;
00102 
00103         /* compute "floating point" W value (used for depth and fog) */
00104         if ((ITERW) & LONGTYPE(0xffff00000000))
00105                 wfloat = 0x0000;
00106         else
00107         {
00108                 UINT32 temp = (UINT32)(ITERW);
00109                 if ((temp & 0xffff0000) == 0)
00110                         wfloat = 0xffff;
00111                 else
00112                 {
00113                         int exp = count_leading_zeros(temp);
00114                         wfloat = ((exp << 12) | (INT32)(((~temp) >> (unsigned int)(19 - exp)) & 0xfffu));
00115                         if (wfloat < 0xffff) wfloat++;
00116                 }
00117         }
00118 
00119         /* compute depth value (W or Z) for this pixel */
00120         if (FBZMODE_WBUFFER_SELECT(FBZMODE) == 0)
00121                 CLAMPED_Z(ITERZ, FBZCOLORPATH, *depthval);
00122         else if (FBZMODE_DEPTH_FLOAT_SELECT(FBZMODE) == 0)
00123                 *depthval = wfloat;
00124         else
00125         {
00126                 if ((unsigned int)(ITERZ) & 0xf0000000l)
00127                         *depthval = 0x0000;
00128                 else
00129                 {
00130                         UINT32 temp = (UINT32)((ITERZ) << 4);
00131                         if ((temp & 0xffff0000ul) == 0)
00132                                 *depthval = 0xffff;
00133                         else
00134                         {
00135                                 int exp = count_leading_zeros(temp);
00136                                 *depthval = ((exp << 12) | (INT32)(((~temp) >> (unsigned int)(19 - exp)) & 0xfffu));
00137                                 if (*depthval < 0xffff) (*depthval)++;
00138                         }
00139                 }
00140         }
00141 
00142         /* add the bias */
00143         if (FBZMODE_ENABLE_DEPTH_BIAS(FBZMODE))
00144         {
00145                 *depthval += (INT16)(VV)->reg[zaColor].u;
00146                 CLAMP(*depthval, 0, 0xffff);
00147         }
00148 
00149         *out_wfloat = wfloat;
00150 }
00151 
00152 void ogl_get_fog_blend(voodoo_state* v, INT32 wfloat, INT32 ITERZ, INT64 ITERW, INT32 *fogblend)
00153 {
00154         UINT32 FOGMODE = v->reg[fogMode].u;
00155         UINT32 FBZCP = v->reg[fbzColorPath].u;
00156 
00157         *fogblend = 0;
00158         if (FOGMODE_ENABLE_FOG(FOGMODE) && !FOGMODE_FOG_CONSTANT(FOGMODE))
00159         {
00160                 /* fog blending mode */
00161                 switch (FOGMODE_FOG_ZALPHA(FOGMODE))
00162                 {
00163                 case 0:         /* fog table */
00164                         {
00165                                 INT32 delta = v->fbi.fogdelta[wfloat >> 10];
00166                                 INT32 deltaval;
00167 
00168                                 /* perform the multiply against lower 8 bits of wfloat */
00169                                 deltaval = (delta & v->fbi.fogdelta_mask) *
00170                                         ((wfloat >> 2) & 0xff);
00171 
00172                                 /* fog zones allow for negating this value */
00173                                 if (FOGMODE_FOG_ZONES(FOGMODE) && (delta & 2))
00174                                         deltaval = -deltaval;
00175                                 deltaval >>= 6;
00176 
00177                                 /* apply dither */
00178 //                              if (FOGMODE_FOG_DITHER(FOGMODE))
00179 //                                      deltaval += DITHER4[(XX) & 3];
00180                                 deltaval >>= 4;
00181 
00182                                 /* add to the blending factor */
00183                                 *fogblend = v->fbi.fogblend[wfloat >> 10] + deltaval;
00184                                 break;
00185                         }
00186 
00187                 case 1:         /* iterated A */
00188 //                      fogblend = ITERAXXX.rgb.a;
00189                         break;
00190 
00191                 case 2:         /* iterated Z */
00192                         CLAMPED_Z((ITERZ), FBZCP, *fogblend);
00193                         *fogblend >>= 8;
00194                         break;
00195 
00196                 case 3:         /* iterated W - Voodoo 2 only */
00197                         CLAMPED_W((ITERW), FBZCP, *fogblend);
00198                         break;
00199                 }
00200 
00201         }
00202 }
00203 
00204 void ogl_get_vertex_data(INT32 x, INT32 y, const void *extradata, ogl_vertex_data *vd) {
00205         const poly_extra_data *extra = (const poly_extra_data *)extradata;
00206         v=(voodoo_state*)extra->state;
00207         INT32 iterr, iterg, iterb, itera;
00208         INT32 iterz;
00209         INT64 iterw;
00210         INT32 dx, dy;
00211         INT32 d;
00212 
00213         dx = x - extra->ax;
00214         dy = y - extra->ay;
00215         iterr = extra->startr + ((dy * extra->drdy)>>4) + ((dx * extra->drdx)>>4);
00216         iterg = extra->startg + ((dy * extra->dgdy)>>4) + ((dx * extra->dgdx)>>4);
00217         iterb = extra->startb + ((dy * extra->dbdy)>>4) + ((dx * extra->dbdx)>>4);
00218         itera = extra->starta + ((dy * extra->dady)>>4) + ((dx * extra->dadx)>>4);
00219         iterz = extra->startz + ((dy * extra->dzdy)>>4) + ((dx * extra->dzdx)>>4);
00220         iterw = extra->startw + ((dy * extra->dwdy)>>4) + ((dx * extra->dwdx)>>4);
00221 
00222         for (Bitu i=0; i<extra->texcount; i++) {
00223                 INT64 iters,itert,iterw2;
00224                 UINT32 smax,tmax;
00225                 INT64 s, t;
00226                 INT32 lod=0;
00227 
00228                 UINT32 texmode=v->tmu[i].reg[textureMode].u;
00229                 UINT32 TEXMODE = texmode;
00230                 INT32 LODBASE = (i==0) ? extra->lodbase0 : extra->lodbase1;
00231 
00232                 UINT32 ilod = (UINT32)(v->tmu[i].lodmin >> 8);
00233                 if (!((v->tmu[i].lodmask >> ilod) & 1))
00234                         ilod++;
00235 
00236                 smax = (v->tmu[i].wmask >> ilod) + 1;
00237                 tmax = (v->tmu[i].hmask >> ilod) + 1;
00238 
00239                 iterw2 = v->tmu[i].startw + ((dy * v->tmu[i].dwdy)>>4) + ((dx * v->tmu[i].dwdx)>>4);
00240                 iters = v->tmu[i].starts + ((dy * v->tmu[i].dsdy)>>4) + ((dx * v->tmu[i].dsdx)>>4);
00241                 itert = v->tmu[i].startt + ((dy * v->tmu[i].dtdy)>>4) + ((dx * v->tmu[i].dtdx)>>4);
00242 
00243                 /* determine the S/T/LOD values for this texture */
00244                 if (TEXMODE_ENABLE_PERSPECTIVE(texmode))
00245                 {
00246                         INT64 oow = fast_reciplog((iterw2), &lod);
00247                         s = (oow * (iters)) >> 29;
00248                         t = (oow * (itert)) >> 29;
00249                         lod += LODBASE;
00250                 }
00251                 else
00252                 {
00253                         s = (iters) >> 14;
00254                         t = (itert) >> 14;
00255                         lod = LODBASE;
00256                 }
00257 
00258                 /* clamp the LOD */
00259                 lod += v->tmu[i].lodbias;
00260 //              if (TEXMODE_ENABLE_LOD_DITHER(TEXMODE))
00261 //                      lod += DITHER4[(XX) & 3] << 4;
00262                 if (lod < v->tmu[i].lodmin)
00263                         lod = v->tmu[i].lodmin;
00264                 if (lod > v->tmu[i].lodmax)
00265                         lod = v->tmu[i].lodmax;
00266 
00267                 /* clamp W */
00268                 if (TEXMODE_CLAMP_NEG_W(texmode) && (iterw2) < 0)
00269                         s = t = 0;
00270 
00271                 if (s != 0) vd->m[i].s = (float)((float)s/(float)(smax*(1u<<(18u+ilod))));
00272                 else vd->m[i].s = 0.0f;
00273                 if (t != 0) vd->m[i].t = (float)((float)t/(float)(tmax*(1u<<(18u+ilod))));
00274                 else vd->m[i].t = 0.0f;
00275                 if (iterw2 != 0) vd->m[i].w = (float)((float)iterw2/(float)(0xffffff));
00276                 else vd->m[i].w = 0.0f;
00277 
00278                 vd->m[i].sw = vd->m[i].s * vd->m[i].w;
00279                 vd->m[i].tw = vd->m[i].t * vd->m[i].w;
00280                 vd->m[i].z  = 0.0f;
00281 
00282                 INT32 lodblend=0;
00283 
00284                 if ((TEXMODE_TC_MSELECT(TEXMODE)==4) || (TEXMODE_TCA_MSELECT(TEXMODE)==4))
00285                 {
00286                         if (v->tmu[i].detailbias <= lod)
00287                                 lodblend = 0;
00288                         else
00289                         {
00290                                 lodblend = (((v->tmu[i].detailbias - lod) << v->tmu[i].detailscale) >> 8);
00291                                 if (lodblend > v->tmu[i].detailmax)
00292                                         lodblend = v->tmu[i].detailmax;
00293                         }
00294                 } else if ((TEXMODE_TC_MSELECT(TEXMODE)==5) || (TEXMODE_TCA_MSELECT(TEXMODE)==5))
00295                         lodblend = lod & 0xff;
00296 
00297                 vd->m[i].lodblend = (float)lodblend/255.0f;
00298         }
00299 
00300         vd->r = (float)((float)iterr/(float)(1<<20));
00301         vd->g = (float)((float)iterg/(float)(1<<20));
00302         vd->b = (float)((float)iterb/(float)(1<<20));
00303         vd->a = (float)((float)itera/(float)(1<<20));
00304         vd->z = (float)((float)iterz/(float)(1<<20));
00305         vd->w = (float)((float)iterw/(float)(0xffffff));
00306 
00307         INT32 wfloat;
00308         ogl_get_depth(v,iterz,iterw,&d,&wfloat);
00309         vd->d = (float)((float)d/(float)(0xffff));
00310 
00311         INT32 fogblend;
00312         ogl_get_fog_blend(v,wfloat,iterz,iterw,&fogblend);
00313         vd->fogblend = (float)fogblend/255.0f;
00314 
00315 //      vd->x = (float)x / (16.0f);
00316 //      vd->y = (float)y / (16.0f);
00317 
00318         // OpenGL-correction for Blood/ShadowWarrior
00319         vd->x = (((float)x) - (1.0f/16.0f)) / 16.0f;
00320         vd->y = (((float)y) - (1.0f/16.0f)) / 16.0f;
00321 }
00322 
00323 static UINT32 crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
00324 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
00325 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
00326 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
00327 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
00328 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
00329 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
00330 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
00331 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
00332 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
00333 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
00334 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
00335 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
00336 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
00337 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
00338 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
00339 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
00340 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
00341 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
00342 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
00343 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
00344 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
00345 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
00346 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
00347 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
00348 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
00349 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
00350 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
00351 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
00352 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
00353 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
00354 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
00355 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
00356 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
00357 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
00358 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
00359 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
00360 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
00361 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
00362 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
00363 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
00364 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
00365 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
00366 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
00367 };
00368 
00369 UINT32 calculate_palsum(UINT32 tmunum) {
00370         UINT32 csum = 0;
00371         for (Bitu pct=0; pct<256; pct++) {
00372                 UINT32 pval = v->tmu[tmunum].palette[pct];
00373                 csum = crc_32_tab[(csum ^ pval) & 0xff] ^ (csum>>8);
00374                 csum = crc_32_tab[(csum ^ (pval>>8)) & 0xff] ^ (csum>>8);
00375                 csum = crc_32_tab[(csum ^ (pval>>16)) & 0xff] ^ (csum>>8);
00376                 csum = crc_32_tab[(csum ^ (pval>>24)) & 0xff] ^ (csum>>8);
00377         }
00378         return csum;
00379 }
00380 
00381 void ogl_cache_texture(const poly_extra_data *extra, ogl_texture_data *td) {
00382         v=(voodoo_state*)extra->state;
00383 
00384         INT32 smax, tmax;
00385         UINT32 *texrgbp;
00386         GLuint texID;
00387 
00388         UINT32 num_tmus = 1;
00389         if (v->tmu[1].ram != NULL) num_tmus++;
00390 
00391         for (UINT32 j=0; j<num_tmus; j++) {
00392                 UINT32 TEXMODE = (UINT32)(j==0 ? extra->r_textureMode0 : extra->r_textureMode1);
00393 
00394                 UINT32 ilod = (UINT32)(v->tmu[j].lodmin >> 8);
00395                 if (!((v->tmu[j].lodmask >> ilod) & 1))
00396                         ilod++;
00397 
00398                 UINT32 texbase = v->tmu[j].lodoffset[ilod];
00399 
00400                 if ( extra->texcount && (extra->texcount >= j) && (v->tmu[j].lodmin < (8 << 8)) ) {
00401                         bool valid_texid = true;
00402                         std::map<const UINT32, ogl_texmap>::iterator t;
00403                         t = textures[j].find(texbase);
00404                         bool reuse_id = false;
00405                         if (t != textures[j].end())  {
00406                                 if (t->second.valid_pal) {
00407                                         texID = t->second.current_id;
00408                                         if (!t->second.valid_data) {
00409                                                 valid_texid = false;
00410                                                 reuse_id = true;
00411                                                 t->second.valid_data = true;
00412                                         }
00413                                 } else {
00414                                         UINT32 psum = calculate_palsum(j);
00415                                         std::map<const UINT32, GLuint>::iterator u = t->second.ids->find(psum);
00416                                         if (u != t->second.ids->end()) {
00417                                                 t->second.valid_pal = true;
00418                                                 t->second.current_id = u->second;
00419                                                 texID = u->second;
00420                                         } else {
00421                                                 valid_texid = false;
00422 //                                              LOG_MSG("texture removed... size %d",t->second.ids->size());
00423                                                 if (t->second.ids->size() > 8) {
00424                                                         for (u=t->second.ids->begin(); u!=t->second.ids->end(); ++u) {
00425                                                                 glDeleteTextures(1,&u->second);
00426                                                         }
00427                                                         t->second.ids->clear();
00428                                                 }
00429                                                 t->second.valid_pal = true;
00430                                         }
00431                                 }
00432                         } else {
00433                                 valid_texid = false;
00434                         }
00435                         if (!valid_texid) {
00436                                 smax = (INT32)(v->tmu[j].wmask >> ilod) + 1;
00437                                 tmax = (INT32)(v->tmu[j].hmask >> ilod) + 1;
00438 
00439                                 UINT32 texboffset = texbase;
00440                                 texrgbp = (UINT32 *)&texrgb[0];
00441                                 memset(texrgbp,0,256*256*4);
00442 
00443                                 if (!reuse_id) {
00444                                         texID = ogl_texture_index++;
00445                                         glGenTextures(1, &texID);
00446                                 }
00447 
00448                                 if (TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u) < 8) {
00449                                         if (TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u) != 5) {
00450                                                 for (int i=0; i<(smax*tmax); i++) {
00451                                                         UINT8 *texptr8 = (UINT8 *)&v->tmu[j].ram[(texboffset) & v->tmu[j].mask];
00452                                                         UINT32 data = v->tmu[j].lookup[*texptr8];
00453                                                         *texrgbp = data;
00454                                                         texboffset++;
00455                                                         texrgbp++;
00456                                                 }
00457                                         } else {
00458                                                 for (int i=0; i<(smax*tmax); i++) {
00459                                                         UINT8 *texptr8 = (UINT8 *)&v->tmu[j].ram[(texboffset) & v->tmu[j].mask];
00460                                                         UINT8 texel = *texptr8;
00461                                                         UINT32 data = v->tmu[j].lookup[texel];
00462                                                         *texrgbp = data;
00463                                                         texboffset++;
00464                                                         texrgbp++;
00465                                                 }
00466                                         }
00467                                 } else if (TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u) >= 10 && TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u) <= 12) {
00468                                         for (int i=0; i<(smax*tmax); i++) {
00469                                                 UINT16 *texptr16 = (UINT16 *)&v->tmu[j].ram[(texboffset) & v->tmu[j].mask];
00470                                                 UINT32 data = v->tmu[j].lookup[*texptr16];
00471                                                 *texrgbp = data;
00472                                                 texboffset+=2;
00473                                                 texrgbp++;
00474                                         }
00475                                 } else if (TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u) != 14) {
00476                                         for (int i=0; i<(smax*tmax); i++) {
00477                                                 UINT16 *texptr16 = (UINT16 *)&v->tmu[j].ram[(texboffset) & v->tmu[j].mask];
00478                                                 UINT32 data = (v->tmu[j].lookup[*texptr16 & 0xFF] & 0xFFFFFF) | ((*texptr16 & 0xff00u) << 16u);
00479                                                 *texrgbp = data;
00480                                                 texboffset+=2;
00481                                                 texrgbp++;
00482                                         }
00483                                 } else {
00484                                         for (int i=0; i<(smax*tmax); i++) {
00485                                                 UINT16 *texptr16 = (UINT16 *)&v->tmu[j].ram[(texboffset) & v->tmu[j].mask];
00486                                                 UINT16 texel1 = *texptr16 & 0xFF;
00487                                                 UINT32 data = (v->tmu[j].lookup[texel1] & 0xFFFFFF) | ((*texptr16 & 0xff00u) << 16u);
00488                                                 *texrgbp = data;
00489                                                 texboffset+=2;
00490                                                 texrgbp++;
00491                                         }
00492                                 }
00493 
00494                                 texrgbp = (UINT32 *)&texrgb[0];
00495 //                              LOG_MSG("texid %d format %d -- %d x %d",
00496 //                                      texID,TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u),smax,tmax);
00497 
00498                                 glBindTexture(GL_TEXTURE_2D, texID);
00499                                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
00500                                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
00501                                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,TEXMODE_CLAMP_S(TEXMODE)?GL_CLAMP_TO_EDGE:GL_REPEAT);
00502                                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,TEXMODE_CLAMP_T(TEXMODE)?GL_CLAMP_TO_EDGE:GL_REPEAT);
00503                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, smax, tmax, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, texrgbp);
00504                                 extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
00505                                 glGenerateMipmapEXT(GL_TEXTURE_2D);
00506                                 if ((TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u)==0x05) || (TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u)==0x0e)) {
00507                                         UINT32 palsum = calculate_palsum(j);
00508                                         if (t == textures[j].end()) {
00509                                                 std::map<const UINT32, GLuint>* ids = new std::map<const UINT32, GLuint>();
00510                                                 (*ids)[palsum] = texID;
00511                                                 ogl_texmap tex = { true, true, TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u),
00512                                                                                         texID, ids };
00513                                                 textures[j][texbase] = tex;
00514                                         } else {
00515                                                 (*textures[j][texbase].ids)[palsum] = texID;
00516                                                 textures[j][texbase].current_id = texID;
00517                                         }
00518                                 } else {
00519                                         ogl_texmap tex = { true, true, TEXMODE_FORMAT(v->tmu[j].reg[textureMode].u),
00520                                                                                 texID, NULL };
00521                                         textures[j][texbase] = tex;
00522                                 }
00523                         }
00524 
00525                         td[j].texID = texID;
00526                         td[j].enable = true;
00527                 } else {
00528                         td[j].enable = false;
00529                 }
00530         }
00531 }
00532 
00533 void voodoo_ogl_invalidate_paltex(void) {
00534         std::map<const UINT32, ogl_texmap>::iterator t;
00535         for (int j=0; j<2; j++) {
00536                 for (t=textures[j].begin(); t!=textures[j].end(); ++t) {
00537                         if ((t->second.format == 0x05) || (t->second.format == 0x0e)) {
00538                                 t->second.valid_pal = false;
00539                         }
00540                 }
00541         }
00542 }
00543 
00544 
00545 GLhandleARB m_hProgramObject   = (GLhandleARB)NULL;
00546 
00547 
00548 void ogl_printInfoLog(GLhandleARB obj)
00549 {
00550     int infologLength = 0;
00551     int charsWritten  = 0;
00552 
00553     glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);
00554 
00555     if (infologLength > 0)
00556     {
00557                 char *infoLog = (char *)malloc((size_t)infologLength);
00558                 glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog);
00559                 LOG_MSG("%s\n",infoLog);
00560                 free(infoLog);
00561     }
00562 }
00563 
00564 void ogl_sh_tex_combine(std::string *strFShader, const int TMU, const poly_extra_data *extra) {
00565         v=(voodoo_state*)extra->state;
00566 
00567         UINT32 TEXMODE     = v->tmu[TMU].reg[textureMode].u;
00568 
00569         if (!TEXMODE_TC_ZERO_OTHER(TEXMODE))
00570                 *strFShader += "  tt.rgb = cother.rgb;\n";
00571         else
00572                 *strFShader += "  tt.rgb = vec3(0.0);\n";
00573 
00574         if (!TEXMODE_TCA_ZERO_OTHER(TEXMODE))
00575                 *strFShader += "  tt.a = cother.a;\n";
00576         else
00577                 *strFShader += "  tt.a = 0.0;\n";
00578 
00579         if (TEXMODE_TC_SUB_CLOCAL(TEXMODE))
00580                 *strFShader += "  tt.rgb -= clocal.rgb;\n";
00581         if (TEXMODE_TCA_SUB_CLOCAL(TEXMODE))
00582                 *strFShader += "  tt.a -= clocal.a;\n";
00583 
00584         switch (TEXMODE_TC_MSELECT(TEXMODE))
00585         {
00586         default:
00587         case 0:
00588                 *strFShader += "  blend.rgb = vec3(0.0);\n";
00589                 break;
00590         case 1:
00591                 *strFShader += "  blend.rgb = clocal.rgb;\n";
00592                 break;
00593         case 2:
00594                 *strFShader += "  blend.rgb = vec3(cother.a);\n";
00595                 break;
00596         case 3:
00597                 *strFShader += "  blend.rgb = vec3(clocal.a);\n";
00598                 break;
00599         case 4:
00600                 // detail //
00601         case 5:
00602                 // LOD //
00603                 *strFShader += "  blend.rgb = vec3(f_lodblend";
00604                 *strFShader += TMU==0?"0":"1";
00605                 *strFShader += ");\n";
00606                 break;
00607         }
00608 
00609         switch (TEXMODE_TCA_MSELECT(TEXMODE))
00610         {
00611         default:
00612         case 0:
00613                 *strFShader += "  blend.a = 0.0;\n";
00614                 break;
00615         case 1:
00616                 *strFShader += "  blend.a = clocal.a;\n";
00617                 break;
00618         case 2:
00619                 *strFShader += "  blend.a = cother.a;\n";
00620                 break;
00621         case 3:
00622                 *strFShader += "  blend.a = clocal.a;\n";
00623                 break;
00624         case 4:
00625                 // detail //
00626         case 5:
00627                 // LOD //
00628                 *strFShader += "  blend.a = f_lodblend";
00629                 *strFShader += TMU==0?"0":"1";
00630                 *strFShader += ";\n";
00631                 break;
00632         }
00633 
00634         if (!TEXMODE_TC_REVERSE_BLEND(TEXMODE))
00635                 *strFShader += "  blend.rgb = vec3(1.0) - blend.rgb;\n";
00636 
00637         if (!TEXMODE_TCA_REVERSE_BLEND(TEXMODE))
00638                 *strFShader += "  blend.a = 1.0 - blend.a;\n";
00639 
00640         *strFShader += "  tt *= blend;\n";
00641 
00642         switch (TEXMODE_TC_ADD_ACLOCAL(TEXMODE))
00643         {
00644         case 3:
00645         case 0:
00646                 break;
00647         case 1:
00648                 *strFShader += "  tt.rgb += clocal.rgb;\n";
00649                 break;
00650         case 2:
00651                 *strFShader += "  tt.rgb += vec3(clocal.a);\n";
00652                 break;
00653         }
00654 
00655         if (TEXMODE_TCA_ADD_ACLOCAL(TEXMODE))
00656                 *strFShader += "  tt.a += clocal.a;\n";
00657 
00658         *strFShader += "  clocal = tt;\n";
00659 
00660         if (TEXMODE_TC_INVERT_OUTPUT(TEXMODE))
00661                 *strFShader += "  clocal.rgb = vec3(1.0)-clocal.rgb;\n";
00662 
00663         if (TEXMODE_TCA_INVERT_OUTPUT(TEXMODE))
00664                 *strFShader += "  clocal.a = 1.0 - clocal.a;\n";
00665 
00666 }
00667 
00668 void ogl_sh_color_path(std::string *strFShader, const poly_extra_data *extra) {
00669         v=(voodoo_state*)extra->state;
00670 
00671         UINT32 FBZCOLORPATH = v->reg[fbzColorPath].u;
00672         UINT32 FBZMODE = v->reg[fbzMode].u;
00673         UINT32 ALPHAMODE = v->reg[alphaMode].u;
00674 
00675         switch (FBZCP_CC_RGBSELECT(FBZCOLORPATH))
00676         {
00677         case 0:
00678                 *strFShader += "  cother = gl_Color;\n";
00679                 break;
00680         case 1:
00681                 *strFShader += "  cother = texel;\n";
00682                 break;
00683         case 2:
00684                 *strFShader += "  cother = color1;\n";
00685                 break;
00686         default:
00687                 *strFShader += "  cother = vec4(0.0);\n";
00688         }
00689 
00690         // TODO fix chroma key //
00691         if (FBZMODE_ENABLE_CHROMAKEY(FBZMODE)) {
00692 //              if (!CHROMARANGE_ENABLE(v->reg[chromaRange].u))
00693                         *strFShader +=  "  if (distance (cother.rgb , chromaKey.rgb) < 0.0001) discard;\n";
00694 //              else {
00695 //                      *strFShader +=  "  if ((cother.rgb >= (chromaKey.rgb-0.01)) && (cother.rgb <= (chromaRange.rgb+0.01))) discard;";
00696 //              }
00697         }
00698 
00699 
00700         switch (FBZCP_CC_ASELECT(FBZCOLORPATH))
00701         {
00702         case 0:
00703                 *strFShader += "  cother.a = gl_Color.a;\n";
00704                 break;
00705         case 1:
00706                 *strFShader += "  cother.a = texel.a;\n";
00707                 break;
00708         case 2:
00709                 *strFShader += "  cother.a = color1.a;\n";
00710                 break;
00711         default:
00712                 *strFShader += "  cother.a = 0.0;\n";
00713                 break;
00714         }
00715 
00716         // TODO check alpha mask //
00717 //      if (FBZMODE_ENABLE_ALPHA_MASK(FBZMODE))
00718 //              *strFShader += "  if (cother.a > 0.0) discard;";
00719 
00720         if (ALPHAMODE_ALPHATEST(ALPHAMODE))
00721                 switch (ALPHAMODE_ALPHAFUNCTION(ALPHAMODE)) {
00722                         case 0:
00723                                 *strFShader += "  discard;\n";
00724                                 break;
00725                         case 1:
00726                                 *strFShader += "  if (cother.a >= alphaRef) discard;\n";
00727                                 break;
00728                         case 2:
00729 //                              *strFShader += "  if (cother.a != alphaRef) discard;\n";
00730                                 *strFShader += "  if (distance(cother.a , alphaRef) > 0.0001) discard;\n";
00731                                 break;
00732                         case 3:
00733                                 *strFShader += "  if (cother.a >  alphaRef) discard;\n";
00734                                 break;
00735                         case 4:
00736                                 *strFShader += "  if (cother.a <= alphaRef) discard;\n";
00737                                 break;
00738                         case 5:
00739 //                              *strFShader += "  if (cother.a == alphaRef) discard;\n";
00740                                 *strFShader += "  if (distance(cother.a , alphaRef) < 0.0001) discard;\n";
00741                                 break;
00742                         case 6:
00743                                 *strFShader += "  if (cother.a <  alphaRef) discard;\n";
00744                                 break;
00745                         case 7:
00746                                 break;
00747         }
00748 
00749         if (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) == 0)
00750         {
00751                 if (FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0)
00752                         *strFShader += "  clocal = gl_Color;\n";
00753                 else
00754                         *strFShader += "  clocal = color0;\n";
00755         }
00756         else
00757         {
00758                 *strFShader +=  "  if (texel.a < 0.5) {\n"
00759                                                         "    clocal = gl_Color;\n"
00760                                                 "  } else {\n"
00761                                                         "    clocal = color0;\n"
00762                                                 "  }\n";
00763         }
00764 
00765         switch (FBZCP_CCA_LOCALSELECT(FBZCOLORPATH))
00766         {
00767         default:
00768         case 0:
00769                 *strFShader += "  clocal.a = gl_Color.a;\n";
00770                 break;
00771         case 1:
00772                 *strFShader += "  clocal.a = color0.a;\n";
00773                 break;
00774         case 2:
00775                 *strFShader += "  clocal.a = gl_Color.a;\n"; // TODO CLAMPED_Z
00776                 break;
00777         case 3:
00778                 // voodoo2 only
00779                 break;
00780         }
00781 
00782         if (FBZCP_CC_ZERO_OTHER(FBZCOLORPATH) == 0)
00783                 *strFShader += "  tt.rgb = cother.rgb;\n";
00784         else
00785                 *strFShader += "  tt.rgb = vec3(0.0);\n";
00786 
00787         if (FBZCP_CCA_ZERO_OTHER(FBZCOLORPATH) == 0)
00788                 *strFShader += "  tt.a = cother.a;\n";
00789         else
00790                 *strFShader += "  tt.a = 0.0;\n";
00791 
00792         if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH))
00793                 *strFShader += "  tt.rgb -= clocal.rgb;\n";
00794 
00795         if (FBZCP_CCA_SUB_CLOCAL(FBZCOLORPATH))
00796                 *strFShader += "  tt.a -= clocal.a;\n";
00797 
00798         switch (FBZCP_CC_MSELECT(FBZCOLORPATH))
00799         {
00800         default:
00801         case 0:
00802                 *strFShader += "  blend.rgb = vec3(0.0);\n";
00803                 break;
00804         case 1:
00805                 *strFShader += "  blend.rgb = clocal.rgb;\n";
00806                 break;
00807         case 2:
00808                 *strFShader += "  blend.rgb = vec3(cother.a);\n";
00809                 break;
00810         case 3:
00811                 *strFShader += "  blend.rgb = vec3(clocal.a);\n";
00812                 break;
00813         case 4:
00814                 *strFShader += "  blend.rgb = vec3(texel.a);\n";
00815                 break;
00816         case 5:
00817                 // voodoo2 only
00818                 *strFShader += "  blend.rgb = texel.rgb;\n";
00819                 break;
00820         }
00821 
00822         switch (FBZCP_CCA_MSELECT(FBZCOLORPATH))
00823         {
00824         default:
00825         case 0:
00826                 *strFShader += "  blend.a = 0.0;\n";
00827                 break;
00828         case 1:
00829                 *strFShader += "  blend.a = clocal.a;\n";
00830                 break;
00831         case 2:
00832                 *strFShader += "  blend.a = cother.a;\n";
00833                 break;
00834         case 3:
00835                 *strFShader += "  blend.a = clocal.a;\n";
00836                 break;
00837         case 4:
00838                 *strFShader += "  blend.a = texel.a;\n";
00839                 break;
00840         }
00841 
00842         if (!FBZCP_CC_REVERSE_BLEND(FBZCOLORPATH))
00843                 *strFShader += "  blend.rgb = vec3(1.0) - blend.rgb;\n";
00844 
00845         if (!FBZCP_CCA_REVERSE_BLEND(FBZCOLORPATH))
00846                 *strFShader += "  blend.a = 1.0 - blend.a;\n";
00847 
00848         *strFShader += "  tt *= blend;\n";
00849 
00850         switch (FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH))
00851         {
00852         case 3:
00853         case 0:
00854                 break;
00855         case 1:
00856                 *strFShader += "  tt.rgb += clocal.rgb;\n";
00857                 break;
00858         case 2:
00859                 *strFShader += "  tt.rgb += vec3(clocal.a);\n";
00860                 break;
00861         }
00862 
00863         if (FBZCP_CCA_ADD_ACLOCAL(FBZCOLORPATH))
00864                 *strFShader += "  tt.a += clocal.a;\n";
00865 
00866         // clamp ?? //
00867 
00868         *strFShader += "  pixel = tt;\n";
00869 
00870         if (FBZCP_CC_INVERT_OUTPUT(FBZCOLORPATH))
00871                 *strFShader += "  pixel.rgb = vec3(1.0) - tt.rgb;\n";
00872 
00873         if (FBZCP_CCA_INVERT_OUTPUT(FBZCOLORPATH))
00874                 *strFShader += "  pixel.a = 1.0 - tt.a;\n";
00875 }
00876 
00877 void ogl_sh_fog(std::string *strFShader, const poly_extra_data *extra) {
00878         v=(voodoo_state*)extra->state;
00879 
00880         UINT32 FOGMODE = v->reg[fogMode].u;
00881 
00882         *strFShader += "  vec4 ff;\n";
00883 
00884         /* constant fog bypasses everything else */
00885         if (FOGMODE_FOG_CONSTANT(FOGMODE))
00886                 *strFShader += "  ff = fogColor;\n";
00887 
00888         /* non-constant fog comes from several sources */
00889         else {
00890                 /* if fog_add is zero, we start with the fog color */
00891                 if (FOGMODE_FOG_ADD(FOGMODE) == 0)
00892                         *strFShader += "  ff = fogColor;\n";
00893                 else
00894                         *strFShader += "  ff = vec4(0.0);\n";
00895 
00896                 /* if fog_mult is zero, we subtract the incoming color */
00897                 if (FOGMODE_FOG_MULT(FOGMODE) == 0)
00898                         *strFShader += "  ff -= pixel;\n";
00899 
00900                 *strFShader += "  float fogblend;\n";
00901                 /* fog blending mode */
00902                 switch (FOGMODE_FOG_ZALPHA(FOGMODE))
00903                 {
00904                         case 0:         /* fog table */
00905                                 // blend factor calculated in ogl_get_fog_blend //
00906                                 *strFShader += "  fogblend = f_fogblend;\n";
00907                                 break;
00908                         case 1:         /* iterated A */
00909                                 *strFShader += "  fogblend = gl_Color.a;\n";
00910                                 break;
00911                         case 2:         /* iterated Z */
00912                                 *strFShader += "  fogblend = f_fogblend;\n";
00913                                 break;
00914                         case 3:         /* iterated W - Voodoo 2 only */
00915                                 *strFShader += "  fogblend = f_fogblend;\n";
00916                                 break;
00917                 }
00918 
00919                 /* perform the blend */
00920                 *strFShader += "  ff *= fogblend;\n";
00921 
00922                 /* if fog_mult is 0, we add this to the original color */
00923                 if (FOGMODE_FOG_MULT(FOGMODE) == 0)
00924                         *strFShader += "  pixel.rgb += ff.rgb;\n";
00925                 /* otherwise this just becomes the new color */
00926                 else
00927                         *strFShader += "  pixel.rgb = ff.rgb;\n";
00928 
00929         }
00930 }
00931 
00932 
00933 void ogl_shaders(const poly_extra_data *extra) {
00934         v=(voodoo_state*)extra->state;
00935 
00936         GLint res;
00937         std::string strVShader, strFShader;
00938 
00939         /* shaders extensions not loaded */
00940         if (!glCreateShaderObjectARB) return;
00941 
00942 //      UINT32 FBZMODE      = extra->r_fbzMode;
00943         UINT32 FOGMODE      = extra->r_fogMode;
00944         UINT32 texcount     = extra->texcount;
00945 
00946         /* build a new shader program */
00947         if (!extra->info->shader_ready) {
00948 
00949                 /* create vertex shader */
00950                 int fcount=0;
00951                 while (glGetError()!=0) {
00952                         fcount++;
00953                         if (fcount>1000) E_Exit("opengl error");
00954                 }
00955 
00956                 GLhandleARB m_hVertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
00957 
00958                 strVShader =
00959                         "attribute float v_fogblend;\n"
00960                         "varying   float f_fogblend;\n"
00961                         "attribute float v_lodblend0;\n"
00962                         "varying   float f_lodblend0;\n"
00963                         "attribute float v_lodblend1;\n"
00964                         "varying   float f_lodblend1;\n"
00965                         "\n"
00966                         "void main()"
00967                         "{\n"
00968                                 "  gl_TexCoord[0] = gl_MultiTexCoord0;\n"
00969                                 "  gl_TexCoord[1] = gl_MultiTexCoord1;\n"
00970                                 "  gl_FrontColor = gl_Color;\n"
00971                                 "  f_fogblend = v_fogblend;\n"
00972                                 "  f_lodblend0 = v_lodblend0;\n"
00973                                 "  f_lodblend1 = v_lodblend1;\n"
00974                                 "  gl_Position = ftransform();\n"
00975                         "}\n";
00976 
00977                 const char *szVShader = strVShader.c_str();
00978                 glShaderSourceARB(m_hVertexShader, 1, &szVShader, NULL);
00979                 glCompileShaderARB(m_hVertexShader);
00980                 glGetObjectParameterivARB(m_hVertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &res);
00981                 if(res == 0) {
00982                         char infobuffer[1000];
00983                         int infobufferlen = 0;
00984                         glGetInfoLogARB(m_hVertexShader, 999, &infobufferlen, infobuffer);
00985                         infobuffer[infobufferlen] = 0;
00986                         ogl_printInfoLog(m_hVertexShader);
00987                         E_Exit("ERROR: Error compiling vertex shader");
00988                         return;
00989                 }
00990 
00991                 /* create fragment shader */
00992                 GLhandleARB m_hFragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
00993                 strFShader =
00994                         "varying float f_fogblend;\n"
00995                         "varying float f_lodblend0;\n"
00996                         "varying float f_lodblend1;\n"
00997                         "uniform sampler2D tex0;\n"
00998                         "uniform sampler2D tex1;\n"
00999                         "uniform vec4 color0;\n"
01000                         "uniform vec4 color1;\n"
01001                         "uniform vec4 chromaKey;\n"
01002                         "uniform vec4 chromaRange;\n"
01003                         "uniform float alphaRef;\n"
01004                         "uniform float zaColor;\n"
01005                         "uniform vec4 fogColor;\n"
01006                         "\n"
01007                         "void main()"
01008                         "{\n"
01009                                 "  vec4 pixel  = vec4(0.0);\n"
01010                                 "  vec4 texel  = vec4(1.0);\n"
01011                                 "  vec4 clocal = vec4(1.0);\n"
01012                                 "  vec4 cother = vec4(0.0);\n"
01013                                 "  vec4 tt     = vec4(0.0);\n"
01014                                 "  vec4 blend  = vec4(0.0);\n";
01015 
01016                                 // TODO glsl depth test? //
01017 
01018                                 if (texcount >= 2 && v->tmu[1].lodmin < (8 << 8))
01019                                 {
01020                                         strFShader += "  clocal = texture2DProj(tex1,gl_TexCoord[1]);\n";
01021                                         ogl_sh_tex_combine(&strFShader, 1, extra);
01022                                         strFShader += "  cother = clocal;\n";
01023                                         strFShader += "  texel = clocal;\n";
01024                                 }
01025 
01026                                 if (texcount >= 1 && v->tmu[0].lodmin < (8 << 8))
01027                                 {
01028                                         strFShader += "  clocal = texture2DProj(tex0,gl_TexCoord[0]);\n";
01029                                         ogl_sh_tex_combine(&strFShader, 0, extra);
01030                                         strFShader += "  texel = clocal;\n";
01031                                 }
01032 
01033                                 // TODO Clamped ARGB //
01034 
01035                                 ogl_sh_color_path(&strFShader, extra);
01036 
01037                                 // fogging //
01038                                 if (FOGMODE_ENABLE_FOG(FOGMODE))
01039                                         ogl_sh_fog(&strFShader, extra);
01040 
01041                                 strFShader += "  gl_FragColor = pixel;\n";
01042 
01043                                 strFShader +=
01044                         "}";
01045 
01046                 const char *szFShader = strFShader.c_str();
01047                 glShaderSourceARB(m_hFragmentShader, 1, &szFShader, NULL);
01048 
01049                 glCompileShaderARB(m_hFragmentShader);
01050                 glGetObjectParameterivARB(m_hFragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &res);
01051                 if(res == 0) {
01052                         ogl_printInfoLog(m_hFragmentShader);
01053                         E_Exit("ERROR: Error compiling fragment shader");
01054                         return;
01055                 }
01056 
01057 
01058                 /* create program object */
01059                 m_hProgramObject = glCreateProgramObjectARB();
01060 
01061                 glAttachObjectARB(m_hProgramObject, m_hVertexShader);
01062                 glAttachObjectARB(m_hProgramObject, m_hFragmentShader);
01063 
01064                 glLinkProgramARB(m_hProgramObject);
01065 
01066                 glGetObjectParameterivARB(m_hProgramObject, GL_OBJECT_LINK_STATUS_ARB, &res);
01067                 if(res == 0) {
01068                         ogl_printInfoLog(m_hProgramObject);
01069                         E_Exit("ERROR: Error linking program");
01070                         return;
01071                 }
01072 
01073                 /* use this shader */
01074                 glUseProgramObjectARB(m_hProgramObject);
01075                 extra->info->so_shader_program=(uintptr_t)m_hProgramObject;
01076                 extra->info->so_vertex_shader=(uintptr_t)m_hVertexShader;
01077                 extra->info->so_fragment_shader=(uintptr_t)m_hFragmentShader;
01078 
01079                 extra->info->shader_ready=true;
01080 
01081                 GLenum glerr=glGetError();
01082                 if (glerr!=0) {
01083                         E_Exit("create shader start glError->%x",glerr);
01084                 }
01085 
01086                 int* locations=new int[12];
01087                 locations[0]=glGetUniformLocationARB(m_hProgramObject, "chromaKey");
01088                 locations[1]=glGetUniformLocationARB(m_hProgramObject, "chromaRange");
01089                 locations[2]=glGetUniformLocationARB(m_hProgramObject, "color0");
01090                 locations[3]=glGetUniformLocationARB(m_hProgramObject, "color1");
01091                 locations[4]=glGetUniformLocationARB(m_hProgramObject, "alphaRef");
01092                 locations[5]=glGetUniformLocationARB(m_hProgramObject, "zaColor");
01093                 locations[6]=glGetUniformLocationARB(m_hProgramObject, "tex0");
01094                 locations[7]=glGetUniformLocationARB(m_hProgramObject, "tex1");
01095                 locations[8]=glGetUniformLocationARB(m_hProgramObject, "fogColor");
01096 
01097                 locations[9] = glGetAttribLocationARB(m_hProgramObject, "v_fogblend");
01098                 locations[10] = glGetAttribLocationARB(m_hProgramObject, "v_lodblend0");
01099                 locations[11] = glGetAttribLocationARB(m_hProgramObject, "v_lodblend1");
01100                 extra->info->shader_ulocations=locations;
01101         } else {
01102                 /* use existing shader program */
01103                 if (m_hProgramObject != (GLhandleARB)extra->info->so_shader_program) {
01104                         glUseProgramObjectARB((GLhandleARB)extra->info->so_shader_program);
01105                         m_hProgramObject = (GLhandleARB)extra->info->so_shader_program;
01106                 }
01107         }
01108 
01109         if (extra->info->shader_ulocations[0]>=0) glUniform4fARB(extra->info->shader_ulocations[0], v->reg[chromaKey].rgb.r/255.0f, v->reg[chromaKey].rgb.g/255.0f, v->reg[chromaKey].rgb.b/255.0f,0);
01110         if (extra->info->shader_ulocations[1]>=0) glUniform4fARB(extra->info->shader_ulocations[1], v->reg[chromaRange].rgb.r/255.0f, v->reg[chromaRange].rgb.g/255.0f, v->reg[chromaRange].rgb.b/255.0f,0);
01111         if (extra->info->shader_ulocations[2]>=0) glUniform4fARB(extra->info->shader_ulocations[2], v->reg[color0].rgb.r/255.0f, v->reg[color0].rgb.g/255.0f, v->reg[color0].rgb.b/255.0f, v->reg[color0].rgb.a/255.0f);
01112         if (extra->info->shader_ulocations[3]>=0) glUniform4fARB(extra->info->shader_ulocations[3], v->reg[color1].rgb.r/255.0f, v->reg[color1].rgb.g/255.0f, v->reg[color1].rgb.b/255.0f, v->reg[color1].rgb.a/255.0f);
01113         if (extra->info->shader_ulocations[4]>=0) glUniform1fARB(extra->info->shader_ulocations[4], v->reg[alphaMode].rgb.a/255.0f);
01114         if (extra->info->shader_ulocations[5]>=0) glUniform1fARB(extra->info->shader_ulocations[5], (float)((UINT16)v->reg[zaColor].u)/65535.0f);
01115         if (extra->info->shader_ulocations[8]>=0) glUniform4fARB(extra->info->shader_ulocations[8], v->reg[fogColor].rgb.r/255.0f, v->reg[fogColor].rgb.g/255.0f, v->reg[fogColor].rgb.b/255.0f,1.0f);
01116 
01117 }
01118 
01119 
01120 void voodoo_ogl_draw_triangle(poly_extra_data *extra) {
01121         v=extra->state;
01122         ogl_texture_data td[2];
01123         ogl_vertex_data vd[3];
01124 
01125         VOGL_ClearBeginMode();
01126 
01127         td[0].enable = false;
01128         td[1].enable = false;
01129 
01130         UINT32 ALPHAMODE = extra->r_alphaMode;
01131         UINT32 FBZMODE   = extra->r_fbzMode;
01132 
01133 
01134         ogl_get_vertex_data(v->fbi.ax, v->fbi.ay, (void*)extra, &vd[0]);
01135         ogl_get_vertex_data(v->fbi.bx, v->fbi.by, (void*)extra, &vd[1]);
01136         ogl_get_vertex_data(v->fbi.cx, v->fbi.cy, (void*)extra, &vd[2]);
01137 
01138 
01139         if (FBZMODE_DEPTH_SOURCE_COMPARE(FBZMODE) && VOGL_CheckFeature(VOGL_HAS_STENCIL_BUFFER)) {
01140                 if (m_hProgramObject != 0) {
01141                         glUseProgramObjectARB(0);
01142                         m_hProgramObject = 0;
01143                 }
01144 
01145                 if ((FBZMODE_ENABLE_DEPTHBUF(FBZMODE)) && (FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) == 0)) {
01146                         VOGL_SetDepthMode(1,FBZMODE_DEPTH_FUNCTION(FBZMODE));
01147                 } else {
01148                         VOGL_SetDepthMode(0,0);
01149                 }
01150 
01151                 VOGL_SetDepthMaskMode(false);
01152                 VOGL_SetColorMaskMode(false, false);
01153 
01154                 VOGL_SetAlphaMode(0, 0,0,0,0);
01155 
01156                 if (FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u)==0) {
01157                         VOGL_SetDrawMode(true);
01158                 } else {
01159                         VOGL_SetDrawMode(false);
01160                 }
01161 
01162                 glEnable(GL_STENCIL_TEST);
01163                 glClear(GL_STENCIL_BUFFER_BIT);
01164                 glStencilFunc(GL_ALWAYS, 1, 1);
01165                 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
01166 
01167                 glBegin(GL_TRIANGLES);
01168 
01169                 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
01170 
01171                 float depth = (float)(v->reg[zaColor].u&0xffff)/(float)0xffff;
01172                 for (int i=0;i<3;i++)
01173                         glVertex3f(vd[i].x, vd[i].y, depth);
01174 
01175                 glEnd();
01176         }
01177 
01178         ogl_cache_texture(extra,td);
01179         ogl_shaders(extra);
01180 
01181         if (extra->texcount > 0) {
01182                 for (unsigned int t=0; t<2; t++)
01183                 if ( td[t].enable ) {
01184                         UINT32 TEXMODE = v->tmu[t].reg[textureMode].u;
01185                         glActiveTexture(GL_TEXTURE0_ARB+t);
01186                         glBindTexture (GL_TEXTURE_2D, td[t].texID);
01187                         if (!extra->info->shader_ready) {
01188                                 glEnable (GL_TEXTURE_2D);
01189                                 // TODO proper fixed-pipeline combiners
01190                                 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
01191                         } else {
01192                                 if (extra->info->shader_ulocations[6+t] >= 0)
01193                                         glUniform1iARB(extra->info->shader_ulocations[6+t],(GLint)t);
01194                         }
01195 
01196                         GLint minFilter;
01197                         minFilter = (int)GL_NEAREST + (int)TEXMODE_MINIFICATION_FILTER(TEXMODE);
01198                         if (v->tmu[t].lodmin != v->tmu[t].lodmax)
01199                                 minFilter += 0x0100 + (int)TEXMODE_TRILINEAR(TEXMODE)*2;
01200                         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,minFilter);
01201                         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,(int)GL_NEAREST+(int)TEXMODE_MAGNIFICATION_FILTER(TEXMODE));
01202                         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,TEXMODE_CLAMP_S(TEXMODE)?GL_CLAMP_TO_EDGE:GL_REPEAT);
01203                         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,TEXMODE_CLAMP_T(TEXMODE)?GL_CLAMP_TO_EDGE:GL_REPEAT);
01204                 }
01205         }
01206 
01207         if (FBZMODE_DEPTH_SOURCE_COMPARE(FBZMODE) && VOGL_CheckFeature(VOGL_HAS_STENCIL_BUFFER)) {
01208                 glStencilFunc(GL_EQUAL, 1, 1);
01209                 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
01210                 if (FBZMODE_ENABLE_DEPTHBUF(FBZMODE)) {
01211                         VOGL_SetDepthMode(1,GL_ALWAYS-GL_NEVER);
01212                 } else {
01213                         VOGL_SetDepthMode(0,0);
01214                 }
01215         } else {
01216                 if (FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) == 0) {
01217                         if (FBZMODE_ENABLE_DEPTHBUF(FBZMODE)) {
01218                                 VOGL_SetDepthMode(1,FBZMODE_DEPTH_FUNCTION(FBZMODE));
01219                         } else {
01220                                 if (FBZMODE_AUX_BUFFER_MASK(FBZMODE) > 0) {
01221                                         VOGL_SetDepthMode(1,GL_ALWAYS-GL_NEVER);
01222                                 } else {
01223                                         VOGL_SetDepthMode(0,0);
01224                                 }
01225                         }
01226                 } else {
01227                         VOGL_SetDepthMode(1,GL_ALWAYS-GL_NEVER);
01228                 }
01229         }
01230 
01231         bool color_mask = (FBZMODE_RGB_BUFFER_MASK(FBZMODE) > 0);
01232 
01233         if (FBZMODE_AUX_BUFFER_MASK(FBZMODE) > 0) {
01234                 VOGL_SetDepthMaskMode(FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) == 0);
01235                 VOGL_SetColorMaskMode(color_mask, true);
01236         } else {
01237                 VOGL_SetDepthMaskMode(false);
01238                 VOGL_SetColorMaskMode(color_mask, false);
01239         }
01240 
01241         if (ALPHAMODE_ALPHABLEND(ALPHAMODE)) {
01242                 VOGL_SetAlphaMode(1, ogl_sfactor[ALPHAMODE_SRCRGBBLEND(ALPHAMODE)], ogl_dfactor[ALPHAMODE_DSTRGBBLEND(ALPHAMODE)],
01243                         (ALPHAMODE_SRCALPHABLEND(ALPHAMODE)==4)?GL_ONE:GL_ZERO,
01244                         (ALPHAMODE_DSTALPHABLEND(ALPHAMODE)==4)?GL_ONE:GL_ZERO);
01245         } else {
01246                 VOGL_SetAlphaMode(0, 0,0,0,0);
01247         }
01248 
01249         if (FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u)==0) {
01250                 VOGL_SetDrawMode(true);
01251                 v->fbi.vblank_flush_pending=true;
01252                 cached_line_front_y=-1;
01253         } else {
01254                 VOGL_SetDrawMode(false);
01255                 cached_line_back_y=-1;
01256         }
01257 
01258 
01259         glBegin(GL_TRIANGLES);
01260 
01261         for (unsigned int i=0;i<3;i++) {
01262                 glColor4fv(&vd[i].r);
01263 
01264                 for (unsigned int t=0;t<2;t++)
01265                         if (td[t].enable) {
01266                                 glMultiTexCoord4fv(GL_TEXTURE0_ARB+t,&vd[i].m[t].sw);
01267                                 if (extra->info->shader_ulocations[10u+t] >= 0)
01268                                         glVertexAttrib1fARB((GLuint)extra->info->shader_ulocations[10u+t],vd[i].m[t].lodblend);
01269                         }
01270 
01271                 if (extra->info->shader_ulocations[9] >= 0)
01272                         glVertexAttrib1fARB((GLuint)extra->info->shader_ulocations[9],vd[i].fogblend);
01273 
01274                 glVertex3fv(&vd[i].x);
01275         }
01276 
01277         glEnd();
01278 
01279         if (FBZMODE_DEPTH_SOURCE_COMPARE(FBZMODE) && VOGL_CheckFeature(VOGL_HAS_STENCIL_BUFFER)) {
01280                 glDisable(GL_STENCIL_TEST);
01281         }
01282 
01283         if (!extra->info->shader_ready) {
01284                 glDisable (GL_TEXTURE_2D);
01285         }
01286 }
01287 
01288 
01289 void voodoo_ogl_swap_buffer() {
01290         VOGL_ClearBeginMode();
01291 
01292         SDL_GL_SwapBuffers();
01293 
01294         cached_line_front_y=-1;
01295         cached_line_back_y=-1;
01296 }
01297 
01298 
01299 void voodoo_ogl_texture_clear(UINT32 texbase, int TMU) {
01300         std::map<const UINT32, ogl_texmap>::iterator t;
01301         t=textures[TMU].find(texbase);
01302         if (t != textures[TMU].end()) {
01303                 VOGL_ClearBeginMode();
01304                 if (t->second.ids != NULL) {
01305                         std::map<const UINT32, GLuint>::iterator u;
01306                         for (u=t->second.ids->begin(); u!=t->second.ids->end(); ++u) {
01307                                 glDeleteTextures(1,&u->second);
01308                         }
01309                         delete t->second.ids;
01310                         t->second.ids = NULL;
01311                 } else {
01312                         t->second.valid_data = false;
01313                 }
01314                 textures[TMU].erase(t);
01315         }
01316 }
01317 
01318 void voodoo_ogl_draw_pixel(int x, int y, bool has_rgb, bool has_alpha, int r, int g, int b, int a) {
01319         GLfloat x2, y2;
01320 
01321         if (m_hProgramObject != 0) {
01322                 glUseProgramObjectARB(0);
01323                 m_hProgramObject = 0;
01324         }
01325 
01326         if (LFBMODE_WRITE_BUFFER_SELECT(v->reg[lfbMode].u)==0) {
01327                 VOGL_SetDrawMode(true);
01328                 v->fbi.vblank_flush_pending=true;
01329         } else {
01330                 VOGL_SetDrawMode(false);
01331         }
01332 
01333         VOGL_SetDepthMode(0,0);
01334 
01335         VOGL_SetDepthMaskMode(false);
01336         VOGL_SetColorMaskMode(has_rgb, has_alpha);
01337 
01338         VOGL_SetAlphaMode(0, 0,0,0,0);
01339 
01340         x2 = (GLfloat) x + 0.5;
01341         y2 = (GLfloat) y + 0.5;
01342 
01343         VOGL_BeginMode(GL_POINTS);
01344         glColor4ub((GLubyte)(r&0xff), (GLubyte)(g&0xff), (GLubyte)(b&0xff), (GLubyte)(a&0xff));
01345         glVertex2f(x2, y2);
01346 }
01347 
01348 void voodoo_ogl_draw_z(int x, int y, int z) {
01349 //      VOGL_ClearBeginMode();
01350 
01351         if (m_hProgramObject != 0) {
01352                 glUseProgramObjectARB(0);
01353                 m_hProgramObject = 0;
01354         }
01355 
01356         if (LFBMODE_WRITE_BUFFER_SELECT(v->reg[lfbMode].u)==0) {
01357                 VOGL_SetDrawMode(true);
01358                 v->fbi.vblank_flush_pending=true;
01359         } else {
01360                 VOGL_SetDrawMode(false);
01361         }
01362 
01363         VOGL_SetDepthMode(1,GL_ALWAYS-GL_NEVER);
01364 
01365         VOGL_SetDepthMaskMode(true);
01366         VOGL_SetColorMaskMode(false, false);
01367 
01368         VOGL_SetAlphaMode(0, 0,0,0,0);
01369 
01370         VOGL_BeginMode(GL_POINTS);
01371 //      glBegin(GL_POINTS);
01372         glVertex3i(x, y, z);    // z adjustment??
01373 //      glEnd();
01374 }
01375 
01376 void voodoo_ogl_draw_pixel_pipeline(int x, int y, int r, int g, int b) {
01377 //      VOGL_ClearBeginMode();
01378         GLfloat x2, y2;
01379 
01380         // TODO redo everything //
01381         if (m_hProgramObject != 0) {
01382                 glUseProgramObjectARB(0);
01383                 m_hProgramObject = 0;
01384         }
01385 
01386         if (LFBMODE_WRITE_BUFFER_SELECT(v->reg[lfbMode].u)==0) {
01387                 VOGL_SetDrawMode(true);
01388                 v->fbi.vblank_flush_pending=true;
01389         } else {
01390                 VOGL_SetDrawMode(false);
01391         }
01392 
01393         VOGL_SetDepthMode(0,0);
01394 
01395         VOGL_SetDepthMaskMode(false);
01396         if (FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u) > 0) {
01397                 VOGL_SetColorMaskMode(true, true);
01398         } else {
01399                 VOGL_SetColorMaskMode(true, false);
01400         }
01401 
01402         if (ALPHAMODE_ALPHABLEND(v->reg[alphaMode].u)) {
01403                 VOGL_SetAlphaMode(1, ogl_sfactor[ALPHAMODE_SRCRGBBLEND(v->reg[alphaMode].u)], ogl_dfactor[ALPHAMODE_DSTRGBBLEND(v->reg[alphaMode].u)],
01404                         (ALPHAMODE_SRCALPHABLEND(v->reg[alphaMode].u)==4)?GL_ONE:GL_ZERO,
01405                         (ALPHAMODE_DSTALPHABLEND(v->reg[alphaMode].u)==4)?GL_ONE:GL_ZERO);
01406         } else {
01407                 VOGL_SetAlphaMode(0, 0,0,0,0);
01408         }
01409 
01410         x2 = (GLfloat) x + 0.5;
01411         y2 = (GLfloat) y + 0.5;
01412 
01413         VOGL_BeginMode(GL_POINTS);
01414 //      glBegin(GL_POINTS);
01415 //      glColor3f((float)r/255.0f, (float)g/255.0f, (float)b/255.0f);
01416         glColor3ub((GLubyte)(r&0xff), (GLubyte)(g&0xff), (GLubyte)(b&0xff));
01417         glVertex2f(x2, y2);
01418 //      glEnd();
01419 }
01420 
01421 
01422 void voodoo_ogl_clip_window(voodoo_state *v) {
01423     (void)v;//UNUSED
01424 /*      VOGL_ClearBeginMode();
01425 
01426         int sx = (v->reg[clipLeftRight].u >> 16) & 0x3ff;
01427         int ex = (v->reg[clipLeftRight].u >> 0) & 0x3ff;
01428         int sy = (v->reg[clipLowYHighY].u >> 16) & 0x3ff;
01429         int ey = (v->reg[clipLowYHighY].u >> 0) & 0x3ff;
01430 
01431         if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u)) {
01432                 sy = (v->fbi.yorigin+1 - sy) & 0x3ff;
01433                 ey = (v->fbi.yorigin+1 - ey) & 0x3ff;
01434         }
01435 
01436         if ((sx>0) || (sy>0) || (ex<v->fbi.width) || (ey<v->fbi.height))
01437         {
01438                 glEnable(GL_SCISSOR_TEST);
01439                 glScissor(sx,sy,ex-sx,ey-sy);
01440         } else {
01441                 glScissor(0,0,v->fbi.width,v->fbi.height);
01442                 glDisable(GL_SCISSOR_TEST);
01443         } */
01444 }
01445 
01446 
01447 void voodoo_ogl_fastfill(void) {
01448         VOGL_ClearBeginMode();
01449 
01450         VOGL_SetDepthMaskMode(true);
01451 
01452         int sx = (v->reg[clipLeftRight].u >> 16) & 0x3ff;
01453         int ex = (v->reg[clipLeftRight].u >> 0) & 0x3ff;
01454         int sy = (v->reg[clipLowYHighY].u >> 16) & 0x3ff;
01455         int ey = (v->reg[clipLowYHighY].u >> 0) & 0x3ff;
01456 
01457 //      if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
01458         {
01459                 int tmp = ((int)v->fbi.yorigin+1 - ey) & 0x3ff;
01460                 ey = ((int)v->fbi.yorigin+1 - sy) & 0x3ff;
01461                 sy = tmp;
01462         }
01463 
01464         bool scissors_needed = true;
01465         if ((sx == 0) && (sy == 0)) {
01466                 if (((Bitu)ex == (Bitu)v->fbi.width) && ((Bitu)ey == (Bitu)v->fbi.height)) scissors_needed = false;
01467         }
01468 
01469         if (scissors_needed) {
01470                 glEnable(GL_SCISSOR_TEST);
01471                 glScissor(sx,sy,ex-sx,ey-sy);
01472         }
01473 
01474 
01475         Bit32u clear_mask=0;
01476         if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u)) {
01477                 clear_mask|=GL_COLOR_BUFFER_BIT;
01478 
01479 //              if (FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u) && v->fbi.auxoffs != (UINT32)(~0)) ...
01480                 VOGL_SetColorMaskMode(true, true);
01481 
01482                 if (last_clear_color!=v->reg[color1].u) {
01483                         glClearColor((float)v->reg[color1].rgb.r/255.0f,
01484                                 (float)v->reg[color1].rgb.g/255.0f,
01485                                 (float)v->reg[color1].rgb.b/255.0f,
01486                                 (float)v->reg[color1].rgb.a/255.0f);
01487                         last_clear_color=v->reg[color1].u;
01488                 }
01489                 if (FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u)==0) {
01490                         VOGL_SetDrawMode(true);
01491                         v->fbi.vblank_flush_pending=true;
01492                         cached_line_front_y=-1;
01493                 } else {
01494                         VOGL_SetDrawMode(false);
01495                         cached_line_back_y=-1;
01496                 }
01497         }
01498         if (FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u) && v->fbi.auxoffs != (UINT32)(~0)) {
01499 //      if (FBZMODE_ENABLE_DEPTHBUF(v->reg[fbzMode].u)) {
01500                 clear_mask|=GL_DEPTH_BUFFER_BIT;
01501                 glClearDepth((float)((UINT16)v->reg[zaColor].u)/65535.0f);
01502         }
01503 
01504         if (clear_mask) glClear(clear_mask);
01505 
01506         if (scissors_needed) {
01507                 glScissor(0,0,(int)v->fbi.width,(int)v->fbi.height);
01508                 glDisable(GL_SCISSOR_TEST);
01509         }
01510 }
01511 
01512 void voodoo_ogl_clear(void) {
01513         VOGL_ClearBeginMode();
01514 
01515         VOGL_SetDrawMode(false);
01516 
01517         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
01518         last_clear_color = 0;
01519         glClearDepth(1.0f);
01520         glClearStencil(0);
01521 
01522         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01523         voodoo_ogl_swap_buffer();
01524         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01525 }
01526 
01527 
01528 UINT32 voodoo_ogl_read_pixel(int x, int y) {
01529         UINT32 data[2];
01530         if ((x < 0) || (y < 0) || (x >= (INT32)v->fbi.width) || (y >= (INT32)v->fbi.height)) return 0xffffffff;
01531 
01532         UINT32 mode=GL_RGBA;
01533         switch (LFBMODE_READ_BUFFER_SELECT(v->reg[lfbMode].u)) {
01534                 case 0:                 /* front buffer */
01535                         VOGL_SetReadMode(true);
01536                         if ((cached_line_front_y != y) || (x+1 >= cached_line_front_width)) {
01537                                 if (cached_line_front_length<(INT32)v->fbi.width) {
01538                                         if (cached_line_front_data!=NULL) free(cached_line_front_data);
01539                                         size_t span_length=((v->fbi.width+64u)&(~15u));
01540                                         cached_line_front_data=(UINT32*)malloc(sizeof(UINT32)*span_length);
01541                                         cached_line_front_length=(INT32)span_length;
01542                                 }
01543                                 glReadPixels(0,(int)v->fbi.height-y,(int)v->fbi.width,1,mode,GL_UNSIGNED_BYTE,cached_line_front_data);
01544                                 cached_line_front_y=y;
01545                                 cached_line_front_width = (INT32)v->fbi.width;
01546                         }
01547                         data[0]=cached_line_front_data[x];
01548                         data[1]=cached_line_front_data[x+1];
01549                         break;
01550                 case 1:                 /* back buffer */
01551                         VOGL_SetReadMode(false);
01552                         if ((cached_line_back_y != y) || (x+1 >= cached_line_back_width)) {
01553                                 if (cached_line_back_length<(INT32)v->fbi.width) {
01554                                         if (cached_line_back_data!=NULL) free(cached_line_back_data);
01555                                         size_t span_length=((v->fbi.width+64u)&(~15u));
01556                                         cached_line_back_data=(UINT32*)malloc(sizeof(UINT32)*span_length);
01557                                         cached_line_back_length=(INT32)span_length;
01558                                 }
01559                                 glReadPixels(0,(int)v->fbi.height-y,(int)v->fbi.width,1,mode,GL_UNSIGNED_BYTE,cached_line_back_data);
01560                                 cached_line_back_y=y;
01561                                 cached_line_back_width = (INT32)v->fbi.width;
01562                         }
01563                         data[0]=cached_line_back_data[x];
01564                         data[1]=cached_line_back_data[x+1];
01565                         break;
01566                 case 2:                 /* aux buffer */
01567                         mode=GL_DEPTH_COMPONENT;
01568                         VOGL_SetReadMode(false);
01569                         glReadPixels(x,(int)v->fbi.height-y,2,1,mode,GL_UNSIGNED_INT,&data);
01570                         return ((data[0]>>16)&0xffff) | (data[1] & 0xffff0000);
01571                 default:
01572                         E_Exit("read from invalid buf %x",LFBMODE_READ_BUFFER_SELECT(v->reg[lfbMode].u));
01573                         break;
01574         }
01575 
01576         return ((RGB_BLUE(data[0])>>3)<<11) | ((RGB_GREEN(data[0])>>2)<<5) | (RGB_RED(data[0])>>3) |
01577                         ((RGB_BLUE(data[1])>>3)<<27) | ((RGB_GREEN(data[1])>>2)<<21) | ((RGB_RED(data[1])>>3)<<16);
01578 }
01579 
01580 
01581 void voodoo_ogl_vblank_flush(void) {
01582         VOGL_ClearBeginMode();
01583         glFlush();
01584 }
01585 
01586 
01587 void voodoo_ogl_set_window(voodoo_state *v) {
01588         VOGL_ClearBeginMode();
01589 
01590         //      matrix mode GL_PROJECTION assumed
01591         bool size_changed=false;
01592         if ((v->fbi.width!=last_width) || (v->fbi.height!=last_height)) size_changed=true;
01593         if (size_changed || (last_orientation != (INT32)FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))) {
01594                 glLoadIdentity( );
01595                 if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
01596                         glOrtho( 0, v->fbi.width, 0, v->fbi.height, 0.0f, -1.0f );
01597                 else
01598                         glOrtho( 0, v->fbi.width, v->fbi.height, 0, 0.0f, -1.0f );
01599                 if (last_orientation != (INT32)FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
01600                         last_orientation = FBZMODE_Y_ORIGIN(v->reg[fbzMode].u);
01601         }
01602         if (size_changed) {
01603                 //correction for viewport if 640x400
01604                 if( v->fbi.height < 480 && GFX_IsFullscreen()) adjust_y=(480-(int)v->fbi.height)/2;
01605                 if( v->fbi.width < 640 && GFX_IsFullscreen()) adjust_x=(640-(int)v->fbi.width)/2;
01606                 glViewport( adjust_x, adjust_y, (int)v->fbi.width, (int)v->fbi.height );
01607                 last_width = v->fbi.width;
01608                 last_height = v->fbi.height;
01609         }
01610 }
01611 
01612 void voodoo_ogl_reset_videomode(void) {
01613 #if defined(WIN32) && !defined(C_SDL2)
01614     /* always show the menu */
01615     void DOSBox_SetMenu(void);
01616     DOSBox_SetMenu();
01617 #endif
01618 
01619 #if defined(C_SDL2)
01620     E_Exit("SDL2 3Dfx OpenGL emulation not implemented yet");
01621 #else
01622     GFX_PreventFullscreen(true);
01623 
01624         last_clear_color=0;
01625 
01626         last_width=0;
01627         last_height=0;
01628         last_orientation=-1;
01629 
01630         VOGL_Reset();
01631 
01632         GFX_TearDown();
01633 
01634         bool full_sdl_restart = true;   // make dependent on surface=opengl
01635 
01636         SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
01637         SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
01638         SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
01639 
01640         bool has_alpha = true;
01641         SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
01642 
01643         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
01644 
01645         bool has_stencil = true;
01646         SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
01647 
01648         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
01649 
01650         /*glMatrixMode( GL_PROJECTION );
01651         glLoadIdentity();
01652         glOrtho( 0, v->fbi.width, v->fbi.height, 0, -1, 1 );
01653         glMatrixMode( GL_MODELVIEW );
01654         glLoadIdentity();*/
01655         // END OF FIX
01656 
01657 #if defined (WIN32) && SDL_VERSION_ATLEAST(1, 2, 11)
01658         SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 0 );
01659 #endif
01660 
01661 #if !defined (WIN32) && SDL_VERSION_ATLEAST(1, 2, 10)
01662         // broken on windows (longstanding SDL bug), may help other platforms to force hardware acceleration
01663         SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
01664 #endif
01665 
01666     ogl_surface = NULL;
01667 
01668     void GFX_ReleaseMouse(void);
01669     void GFX_ForceFullscreenExit(void);
01670 
01671     GFX_ReleaseMouse();
01672     GFX_ForceFullscreenExit();
01673 
01674         Uint32 sdl_flags = SDL_OPENGL;
01675 
01676     ogl_surface = SDL_SetVideoMode((int)v->fbi.width, (int)v->fbi.height, 32, sdl_flags);
01677 
01678         if (ogl_surface == NULL) {
01679                 if (full_sdl_restart) {
01680                         SDL_QuitSubSystem(SDL_INIT_VIDEO);
01681                         SDL_InitSubSystem(SDL_INIT_VIDEO);
01682                         ogl_surface = SDL_SetVideoMode((int)v->fbi.width, (int)v->fbi.height, 32, sdl_flags);
01683                 }
01684                 if (ogl_surface == NULL) {
01685                         has_alpha = false;
01686                         SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
01687                         if ((ogl_surface = SDL_SetVideoMode((int)v->fbi.width, (int)v->fbi.height, 32, sdl_flags)) == NULL) {
01688                                 has_stencil = false;
01689                                 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
01690                                 if ((ogl_surface = SDL_SetVideoMode((int)v->fbi.width, (int)v->fbi.height, 32, sdl_flags)) == NULL) {
01691                                         if (sdl_flags & SDL_FULLSCREEN) {
01692                                                 sdl_flags &= ~(SDL_FULLSCREEN);
01693                                                 if ((ogl_surface = SDL_SetVideoMode((int)v->fbi.width, (int)v->fbi.height, 32, sdl_flags)) == NULL) {
01694                                                         E_Exit("VOODOO: opengl init error");
01695                                                 }
01696                                         } else {
01697                                                 E_Exit("VOODOO: opengl init error");
01698                                         }
01699                                 }
01700                                 LOG_MSG("VOODOO: Graphics mode does not support Stencil/Alpha channels");
01701                         } else {
01702                                 LOG_MSG("VOODOO: Graphics mode does not support Alpha channel");
01703                         }
01704                 }
01705         }
01706 
01707     v->ogl_dimchange = true;
01708 
01709         glViewport( 0, 0, (int)v->fbi.width, (int)v->fbi.height );
01710         last_width = v->fbi.width;
01711         last_height = v->fbi.height;
01712 
01713     /* NTS: Some demoscene 3Dfx stuff looks terrible without this.
01714      *      This is said to be the initial state of an OpenGL context.
01715      *      This is in direct contradiction to the OpenGL output setup
01716      *      in src/gui/sdlmain.cpp that sets up GL_FLAT shading */
01717     glShadeModel (GL_SMOOTH);
01718 
01719         GFX_UpdateSDLCaptureState();
01720 
01721         int value;
01722 
01723         bool few_colors = false;
01724         if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value) == 0) {
01725                 if (value < 8) few_colors = true;
01726         }
01727         if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value) == 0) {
01728                 if (value < 8) few_colors = true;
01729         }
01730         if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value) == 0) {
01731                 if (value < 8) few_colors = true;
01732         }
01733         if (few_colors) LOG_MSG("opengl: warning: graphics mode with insufficient color depth");
01734 
01735         if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value) == 0) {
01736                 if (value < 24) LOG_MSG("opengl: warning: depth buffer with insufficient resolution");
01737         }
01738 
01739         if (SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &value) == 0) {
01740                 if (value < 1) has_stencil = false;
01741         }
01742         if (SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &value) == 0) {
01743                 if (value < 8) has_alpha = false;
01744         }
01745 
01746         if (has_stencil) VOGL_FlagFeature(VOGL_HAS_STENCIL_BUFFER);
01747         if (has_alpha) VOGL_FlagFeature(VOGL_HAS_ALPHA_PLANE);
01748 
01749         GLint depth_csize;
01750         glGetIntegerv(GL_DEPTH_BITS, &depth_csize);
01751         if (depth_csize < 16) {
01752                 LOG_MSG("VOODOO: OpenGL: invalid depth size %d",depth_csize);
01753         }
01754 
01755 #if defined(WIN32) && !defined(C_SDL2)
01756         // Windows SDL 1.x builds may destroy and re-create the window, and lose our menu bar.
01757         // make sure to put it back.
01758         void DOSBox_SetMenu(void);
01759         DOSBox_SetMenu();
01760 #endif
01761 
01762         /* Something in Windows keeps changing the shade model on us from the last glShadeModel() call. Change it back. */
01763         glShadeModel(GL_SMOOTH);
01764 
01765         LOG_MSG("VOODOO: OpenGL: mode set, resolution %d:%d %s", v->fbi.width, v->fbi.height, (sdl_flags & SDL_FULLSCREEN) ? "(fullscreen)" : "");
01766 #endif
01767 }
01768 
01769 void voodoo_ogl_update_dimensions(void) {
01770         voodoo_ogl_leave(false);
01771 
01772         voodoo_ogl_reset_videomode();
01773 
01774         glMatrixMode( GL_PROJECTION );
01775         voodoo_ogl_set_window(v);
01776 
01777         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
01778 
01779         glMatrixMode( GL_MODELVIEW );
01780         glLoadIdentity( );
01781         glMatrixMode( GL_PROJECTION );
01782 }
01783 
01784 bool voodoo_ogl_init(voodoo_state *v) {
01785         extern void CPU_Core_Dyn_X86_SetFPUMode(bool dh_fpu);
01786 //      CPU_Core_Dyn_X86_SetFPUMode(false);
01787 
01788         extern void CPU_Core_Dyn_X86_Cache_Reset(void);
01789 //      CPU_Core_Dyn_X86_Cache_Reset();
01790 
01791 
01792         voodoo_ogl_reset_videomode();
01793 
01794         if (!VOGL_Initialize()) {
01795                 VOGL_Reset();
01796                 // reset video mode etc.
01797                 return false;
01798         }
01799 
01800 /*      std::string features = "";
01801         if (VOGL_CheckFeature(VOGL_HAS_SHADERS)) features += " shader";
01802         if (VOGL_CheckFeature(VOGL_HAS_ALPHA_PLANE)) features += " alpha-plane";
01803         if (VOGL_CheckFeature(VOGL_HAS_STENCIL_BUFFER)) features += " stencil-buffer";
01804 
01805         if (features == "") features = " none";
01806 
01807         LOG_MSG("VOODOO: OpenGL: features enabled:%s",features.c_str()); */
01808 
01809 
01810         glMatrixMode( GL_PROJECTION );
01811         voodoo_ogl_set_window(v);
01812 
01813         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
01814 
01815         glMatrixMode( GL_MODELVIEW );
01816         glLoadIdentity( );
01817         glMatrixMode( GL_PROJECTION );
01818 
01819         return true;
01820 }
01821 
01822 void voodoo_ogl_leave(bool leavemode) {
01823         VOGL_ClearBeginMode();
01824 
01825         std::map<const UINT32, ogl_texmap>::iterator t;
01826         for (int j=0; j<2; j++) {
01827                 for (t=textures[j].begin(); t!=textures[j].end(); ++t) {
01828                         if (t->second.ids != NULL) {
01829                                 std::map<const UINT32, GLuint>::iterator u;
01830                                 for (u=t->second.ids->begin(); u!=t->second.ids->end(); ++u) {
01831                                         glDeleteTextures(1,&u->second);
01832                                 }
01833                                 if (!t->second.ids->empty()) t->second.ids->clear();
01834                                 delete t->second.ids;
01835                                 t->second.ids = NULL;
01836                         } else {
01837                                 glDeleteTextures(1,&t->second.current_id);
01838                         }
01839                 }
01840                 if (!textures[j].empty()) textures[j].clear();
01841         }
01842 
01843 
01844         if (m_hProgramObject != 0) {
01845                 glUseProgramObjectARB(0);
01846                 m_hProgramObject = 0;
01847         }
01848 
01849         for (int hct=0; hct<RASTER_HASH_SIZE; hct++) {
01850                 raster_info *info = v->raster_hash[hct];
01851                 for (; info; info = info->next) {
01852                         if (info->shader_ready) {
01853                                 delete[] info->shader_ulocations;
01854                                 info->shader_ulocations=NULL;
01855 
01856                                 if (info->so_shader_program > 0) {
01857                                         if (info->so_vertex_shader > 0) glDetachObjectARB((GLhandleARB)info->so_shader_program, (GLhandleARB)info->so_vertex_shader);
01858                                         if (info->so_fragment_shader > 0) glDetachObjectARB((GLhandleARB)info->so_shader_program, (GLhandleARB)info->so_fragment_shader);
01859                                         if (info->so_vertex_shader > 0) glDeleteObjectARB((GLhandleARB)info->so_vertex_shader);
01860                                         if (info->so_fragment_shader > 0) glDeleteObjectARB((GLhandleARB)info->so_fragment_shader);
01861                                         glDeleteObjectARB((GLhandleARB)info->so_shader_program);
01862                                 }
01863 
01864                                 info->shader_ready=false;
01865                         }
01866                 }
01867         }
01868 
01869 
01870         cached_line_front_y=-1;
01871         cached_line_back_y=-1;
01872 
01873         if (leavemode) {
01874                 LOG_MSG("VOODOO: OpenGL: quit");
01875 
01876         ogl_surface = NULL;
01877         GFX_PreventFullscreen(false);
01878         GFX_RestoreMode();
01879     }
01880 }
01881 
01882 void voodoo_ogl_shutdown(voodoo_state *v) {
01883         // TODO revert to previous video mode //
01884 
01885         voodoo_ogl_leave(false);
01886 
01887         v->active = false;
01888 }
01889 
01890 #else
01891 
01892 
01893 bool voodoo_ogl_init(voodoo_state *v) {
01894     (void)v;
01895         return false;
01896 }
01897 
01898 void voodoo_ogl_leave(void) {
01899 }
01900 
01901 void voodoo_ogl_shutdown(voodoo_state *v) {
01902     (void)v;
01903 }
01904 
01905 void voodoo_ogl_set_window(voodoo_state *v) {
01906     (void)v;
01907         E_Exit("invalid call to voodoo_ogl_set_window");
01908 }
01909 
01910 void voodoo_ogl_swap_buffer(void) {
01911         E_Exit("invalid call to voodoo_ogl_swap_buffer");
01912 }
01913 
01914 void voodoo_ogl_vblank_flush(void) {
01915         E_Exit("invalid call to voodoo_ogl_vblank_flush");
01916 }
01917 
01918 void voodoo_ogl_clear(void) {
01919         E_Exit("invalid call to voodoo_ogl_clear");
01920 }
01921 
01922 void voodoo_ogl_fastfill(void) {
01923         E_Exit("invalid call to voodoo_ogl_fastfill");
01924 }
01925 
01926 void voodoo_ogl_clip_window(voodoo_state *v) {
01927     (void)v;
01928         E_Exit("invalid call to voodoo_ogl_clip_window");
01929 }
01930 
01931 void voodoo_ogl_texture_clear(UINT32 texbase, int TMU) {
01932     (void)texbase;
01933     (void)TMU;
01934         E_Exit("invalid call to voodoo_ogl_texture_clear");
01935 }
01936 
01937 void voodoo_ogl_invalidate_paltex(void) {
01938         E_Exit("invalid call to voodoo_ogl_invalidate_paltex");
01939 }
01940 
01941 void voodoo_ogl_draw_pixel(int x, int y, bool has_rgb, bool has_alpha, int r, int g, int b, int a) {
01942     (void)has_alpha;
01943     (void)has_rgb;
01944     (void)x;
01945     (void)y;
01946     (void)r;
01947     (void)g;
01948     (void)b;
01949     (void)a;
01950         E_Exit("invalid call to voodoo_ogl_draw_pixel");
01951 }
01952 
01953 void voodoo_ogl_draw_z(int x, int y, int z1, int z2) {
01954     (void)z1;
01955     (void)z2;
01956     (void)x;
01957     (void)y;
01958         E_Exit("invalid call to voodoo_ogl_draw_z");
01959 }
01960 
01961 void voodoo_ogl_draw_pixel_pipeline(int x, int y, int r, int g, int b) {
01962     (void)x;
01963     (void)y;
01964     (void)r;
01965     (void)g;
01966     (void)b;
01967         E_Exit("invalid call to voodoo_ogl_draw_pixel_pipeline");
01968 }
01969 
01970 UINT32 voodoo_ogl_read_pixel(int x, int y) {
01971     (void)x;
01972     (void)y;
01973         E_Exit("invalid call to voodoo_ogl_read_pixel");
01974         return 0;
01975 }
01976 
01977 void voodoo_ogl_draw_triangle(poly_extra_data *extra) {
01978     (void)extra;
01979         E_Exit("invalid call to voodoo_ogl_draw_triangle");
01980 }
01981 
01982 #endif