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