]> icculus.org git repositories - btb/d2x.git/blob - arch/ogl/ogl.c
more header cleanup
[btb/d2x.git] / arch / ogl / ogl.c
1 /*
2  *
3  * Graphics support functions for OpenGL.
4  *
5  *
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <conf.h>
10 #endif
11
12 //#include <stdio.h>
13 #ifdef _WIN32
14 #include <windows.h>
15 #include <stddef.h>
16 #endif
17 #include "internal.h"
18 #if defined(__APPLE__) && defined(__MACH__)
19 #include <OpenGL/gl.h>
20 #include <OpenGL/glu.h>
21 #include <OpenGL/glext.h>
22 #else
23 #include <GL/gl.h>
24 #include <GL/glu.h>
25 #endif
26 #include <string.h>
27 #include <math.h>
28 #include <stdio.h>
29
30 #include "3d.h"
31 #include "inferno.h"
32 #include "../../3d/globvars.h"
33 #include "error.h"
34 #include "texmap.h"
35 #include "gr.h"
36 #include "mono.h"
37 #ifdef HAVE_LIBPNG
38 #include "pngfile.h"
39 #endif
40
41 #include "byteswap.h"
42
43
44 //change to 1 for lots of spew.
45 #if 0
46 #define glmprintf(a) mprintf(a)
47 #else
48 #define glmprintf(a)
49 #endif
50
51 #ifndef M_PI
52 #define M_PI 3.14159
53 #endif
54
55 #if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) || defined(__sun__) || defined(macintosh)
56 #define cosf(a) cos(a)
57 #define sinf(a) sin(a)
58 #endif
59
60 unsigned char *ogl_pal=gr_palette;
61
62 int GL_texmagfilt=GL_NEAREST;
63 int GL_texminfilt=GL_NEAREST;
64 float GL_texanisofilt = 0;
65 int GL_needmipmaps=0;
66
67 int last_width=-1,last_height=-1;
68 int GL_TEXTURE_2D_enabled=-1;
69 int GL_texclamp_enabled=-1;
70
71 extern int gr_badtexture;
72 int r_texcount = 0, r_cachedtexcount = 0;
73 int ogl_alttexmerge=1;//merge textures by just printing the seperate textures?
74 int ogl_rgba_internalformat = GL_RGBA8;
75 int ogl_rgb_internalformat = GL_RGB8;
76 int ogl_intensity4_ok=1;
77 int ogl_luminance4_alpha4_ok=1;
78 int ogl_rgba2_ok=1;
79 int ogl_readpixels_ok=1;
80 int ogl_gettexlevelparam_ok=1;
81 #ifdef GL_ARB_multitexture
82 int ogl_arb_multitexture_ok=0;
83 #endif
84 #ifdef GL_SGIS_multitexture
85 int ogl_sgis_multitexture_ok=0;
86 #endif
87 int ogl_nv_texture_env_combine4_ok = 0;
88 #ifdef GL_NV_register_combiners
89 int ogl_nv_register_combiners_ok = 0;
90 #endif
91 int ogl_ext_texture_filter_anisotropic_ok = 0;
92 #ifdef GL_EXT_paletted_texture
93 int ogl_shared_palette_ok = 0;
94 int ogl_paletted_texture_ok = 0;
95 #endif
96
97 int sphereh=0;
98 int cross_lh[2]={0,0};
99 int primary_lh[3]={0,0,0};
100 int secondary_lh[5]={0,0,0,0,0};
101 /*int lastbound=-1;
102
103 #define OGL_BINDTEXTURE(a) if(gr_badtexture>0) glBindTexture(GL_TEXTURE_2D, 0);\
104         else if(a!=lastbound) {glBindTexture(GL_TEXTURE_2D, a);lastbound=a;}*/
105 #define OGL_BINDTEXTURE(a) if(gr_badtexture>0) glBindTexture(GL_TEXTURE_2D, 0);\
106         else glBindTexture(GL_TEXTURE_2D, a);
107
108
109 ogl_texture ogl_texture_list[OGL_TEXTURE_LIST_SIZE];
110 int ogl_texture_list_cur;
111
112 /* some function prototypes */
113
114 //#define OGLTEXBUFSIZE (1024*1024*4)
115 #define OGLTEXBUFSIZE (2048*2048*4)
116 extern GLubyte texbuf[OGLTEXBUFSIZE];
117 //void ogl_filltexbuf(unsigned char *data,GLubyte *texp,int width,int height,int  twidth,int theight);
118 void ogl_filltexbuf(unsigned char *data, GLubyte *texp, int truewidth, int width, int height, int dxo, int dyo, int twidth, int theight, int type, int bm_flags, int data_format);
119 void ogl_loadbmtexture(grs_bitmap *bm);
120 //void ogl_loadtexture(unsigned char * data, int width, int height,int dxo,intdyo , int *texid,float *u,float *v,char domipmap,float prio);
121 void ogl_loadtexture(unsigned char *data, int dxo, int dyo, ogl_texture *tex, int bm_flags, int data_format);
122 void ogl_freetexture(ogl_texture *gltexture);
123 void ogl_do_palfx(void);
124
125 void ogl_init_texture_stats(ogl_texture* t){
126         t->prio=0.3;//default prio
127         t->lastrend=0;
128         t->numrend=0;
129 }
130 void ogl_init_texture(ogl_texture* t, int w, int h, int flags)
131 {
132         t->handle = 0;
133         if (flags & OGL_FLAG_NOCOLOR)
134         {
135                 // use GL_INTENSITY instead of GL_RGB
136                 if (flags & OGL_FLAG_ALPHA)
137                 {
138                         if (ogl_intensity4_ok)
139                         {
140                                 t->internalformat = GL_INTENSITY4;
141                                 t->format = GL_LUMINANCE;
142                         }
143                         else if (ogl_luminance4_alpha4_ok)
144                         {
145                                 t->internalformat = GL_LUMINANCE4_ALPHA4;
146                                 t->format = GL_LUMINANCE_ALPHA;
147                         }
148                         else if (ogl_rgba2_ok)
149                         {
150                                 t->internalformat = GL_RGBA2;
151                                 t->format = GL_RGBA;
152                         }
153                         else
154                         {
155                                 t->internalformat = ogl_rgba_internalformat;
156                                 t->format = GL_RGBA;
157                         }
158                 }
159                 else
160                 {
161                         // there are certainly smaller formats we could use here, but nothing needs it ATM.
162                         t->internalformat = ogl_rgb_internalformat;
163                         t->format = GL_RGB;
164                 }
165         }
166         else
167         {
168                 if (flags & OGL_FLAG_ALPHA)
169                 {
170                         t->internalformat = ogl_rgba_internalformat;
171                         t->format = GL_RGBA;
172                 }
173                 else
174                 {
175                         t->internalformat = ogl_rgb_internalformat;
176                         t->format = GL_RGB;
177                 }
178         }
179         t->wrapstate[0] = -1;
180         t->wrapstate[1] = -1;
181         t->lw = t->w = w;
182         t->h = h;
183         t->wantmip = flags & OGL_FLAG_MIPMAP;
184         ogl_init_texture_stats(t);
185 }
186
187 void ogl_reset_texture(ogl_texture* t)
188 {
189         ogl_init_texture(t, 0, 0, 0);
190 }
191
192 void ogl_reset_texture_stats_internal(void){
193         int i;
194         for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++)
195                 if (ogl_texture_list[i].handle>0){
196                         ogl_init_texture_stats(&ogl_texture_list[i]);
197                 }
198 }
199 void ogl_init_texture_list_internal(void){
200         int i;
201         ogl_texture_list_cur=0;
202         for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++)
203                 ogl_reset_texture(&ogl_texture_list[i]);
204 }
205 void ogl_smash_texture_list_internal(void){
206         int i;
207         sphereh=0;
208         memset(cross_lh,0,sizeof(cross_lh));
209         memset(primary_lh,0,sizeof(primary_lh));
210         memset(secondary_lh,0,sizeof(secondary_lh));
211         for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++){
212                 if (ogl_texture_list[i].handle>0){
213                         glDeleteTextures( 1, &ogl_texture_list[i].handle );
214                         ogl_texture_list[i].handle=0;
215                 }
216                 ogl_texture_list[i].wrapstate[0] = -1;
217                 ogl_texture_list[i].wrapstate[1] = -1;
218         }
219 }
220 void ogl_vivify_texture_list_internal(void){
221 /*
222    int i;
223         ogl_texture* t;
224         for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++){
225                 t=&ogl_texture_list[i];
226                 if (t->w>0){//erk, realised this can't be done since we'd need the texture bm_data too. hmmm.
227                         ogl_loadbmtexture(t);
228         }
229 */
230 }
231
232 ogl_texture* ogl_get_free_texture(void){
233         int i;
234         for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++){
235                 if (ogl_texture_list[ogl_texture_list_cur].handle<=0 && ogl_texture_list[ogl_texture_list_cur].w==0)
236                         return &ogl_texture_list[ogl_texture_list_cur];
237                 if (++ogl_texture_list_cur>=OGL_TEXTURE_LIST_SIZE)
238                         ogl_texture_list_cur=0;
239         }
240         Error("OGL: texture list full!\n");
241 //      return NULL;
242 }
243 int ogl_texture_stats(void){
244         int used = 0, usedother = 0, usedidx = 0, usedrgb = 0, usedrgba = 0;
245         int databytes = 0, truebytes = 0, datatexel = 0, truetexel = 0, i;
246         int prio0=0,prio1=0,prio2=0,prio3=0,prioh=0;
247 //      int grabbed=0;
248         ogl_texture* t;
249         for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++){
250                 t=&ogl_texture_list[i];
251                 if (t->handle>0){
252                         used++;
253                         datatexel+=t->w*t->h;
254                         truetexel+=t->tw*t->th;
255                         databytes+=t->bytesu;
256                         truebytes+=t->bytes;
257                         if (t->prio<0.299)prio0++;
258                         else if (t->prio<0.399)prio1++;
259                         else if (t->prio<0.499)prio2++;
260                         else if (t->prio<0.599)prio3++;
261                         else prioh++;
262                         if (t->format == GL_RGBA)
263                                 usedrgba++;
264                         else if (t->format == GL_RGB)
265                                 usedrgb++;
266                         else if (t->format == GL_COLOR_INDEX)
267                                 usedidx++;
268                         else
269                                 usedother++;
270                 }
271 //              else if(t->w!=0)
272 //                      grabbed++;
273         }
274         if (gr_renderstats)
275         {
276                 GLint idx, r, g, b, a, dbl, depth;
277                 int res, colorsize, depthsize;
278
279                 res = SWIDTH * SHEIGHT;
280                 glGetIntegerv(GL_INDEX_BITS, &idx);
281                 glGetIntegerv(GL_RED_BITS, &r);
282                 glGetIntegerv(GL_GREEN_BITS, &g);
283                 glGetIntegerv(GL_BLUE_BITS, &b);
284                 glGetIntegerv(GL_ALPHA_BITS, &a);
285                 glGetIntegerv(GL_DOUBLEBUFFER, &dbl);
286                 dbl += 1;
287                 glGetIntegerv(GL_DEPTH_BITS, &depth);
288                 colorsize = (idx * res * dbl) / 8;
289                 depthsize = res * depth / 8;
290                 gr_printf(5, GAME_FONT->ft_h * 14 + 3 * 14, "%i(%i,%i,%i,%i) %iK(%iK wasted) (%i postcachedtex)", used, usedrgba, usedrgb, usedidx, usedother, truebytes / 1024, (truebytes - databytes) / 1024, r_texcount - r_cachedtexcount);
291                 gr_printf(5, GAME_FONT->ft_h * 15 + 3 * 15, "%ibpp(r%i,g%i,b%i,a%i)x%i=%iK depth%i=%iK", idx, r, g, b, a, dbl, colorsize / 1024, depth, depthsize / 1024);
292                 gr_printf(5, GAME_FONT->ft_h * 16 + 3 * 16, "total=%iK", (colorsize + depthsize + truebytes) / 1024);
293         }
294 //      glmprintf((0,"ogl tex stats: %i(%i,%i|%i,%i,%i,%i,%i) %i(%i)b (%i(%i)wasted)\n",used,usedrgba,usedl4a4,prio0,prio1,prio2,prio3,prioh,truebytes,truetexel,truebytes-databytes,truetexel-datatexel));
295         return truebytes;
296 }
297 int ogl_mem_target=-1;
298 void ogl_clean_texture_cache(void){
299         ogl_texture* t;
300         int i,bytes;
301         int time=120;
302         
303         if (ogl_mem_target<0){
304                 if (gr_renderstats)
305                         ogl_texture_stats();
306                 return;
307         }
308         
309         bytes=ogl_texture_stats();
310         while (bytes>ogl_mem_target){
311                 for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++){
312                         t=&ogl_texture_list[i];
313                         if (t->handle>0){
314                                 if (t->lastrend+f1_0*time<GameTime){
315                                         ogl_freetexture(t);
316                                         bytes-=t->bytes;
317                                         if (bytes<ogl_mem_target)
318                                                 return;
319                                 }
320                         }
321                 }
322                 if (time==0)
323                         Error("not enough mem?");
324                 time=time/2;
325         }
326         
327 }
328 void ogl_bindbmtex(grs_bitmap *bm){
329         if (bm->gltexture==NULL || bm->gltexture->handle<=0)
330                 ogl_loadbmtexture(bm);
331         OGL_BINDTEXTURE(bm->gltexture->handle);
332         bm->gltexture->lastrend=GameTime;
333         bm->gltexture->numrend++;
334 ////    if (bm->gltexture->numrend==80 || bm->gltexture->numrend==4000 || bm->gltexture->numrend==80000){
335 //      if (bm->gltexture->numrend==100){
336 //              bm->gltexture->prio+=0.1;
337 ////            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_PRIORITY,bm->gltexture->prio);
338 //              glPrioritizeTextures(1,&bm->gltexture->handle,&bm->gltexture->prio);
339 //      }
340 }
341 //gltexture MUST be bound first
342 void ogl_texwrap(ogl_texture *gltexture,int state)
343 {
344         if (gltexture->wrapstate[active_texture_unit] != state || gltexture->numrend < 1)
345         {
346                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, state);
347                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, state);
348                 gltexture->wrapstate[active_texture_unit] = state;
349         }
350 }
351
352 //crude texture precaching
353 //handles: powerups, walls, weapons, polymodels, etc.
354 //it is done with the horrid do_special_effects kludge so that sides that have to be texmerged and have animated textures will be correctly cached.
355 //similarly, with the objects(esp weapons), we could just go through and cache em all instead, but that would get ones that might not even be on the level
356 //TODO: doors
357
358 void ogl_cache_polymodel_textures(int model_num)
359 {
360         polymodel *po;
361         int i;
362
363         if (model_num < 0)
364                 return;
365         po = &Polygon_models[model_num];
366         for (i=0;i<po->n_textures;i++)  {
367 //              texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]];
368                 ogl_loadbmtexture(&GameBitmaps[ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]].index]);
369         }
370 }
371 void ogl_cache_vclip_textures(vclip *vc){
372         int i;
373         for (i=0;i<vc->num_frames;i++){
374                 PIGGY_PAGE_IN(vc->frames[i]);
375                 ogl_loadbmtexture(&GameBitmaps[vc->frames[i].index]);
376         }
377 }
378
379 void ogl_cache_vclipn_textures(int i)
380 {
381         if (i >= 0 && i < VCLIP_MAXNUM)
382                 ogl_cache_vclip_textures(&Vclip[i]);
383 }
384
385 void ogl_cache_weapon_textures(int weapon_type)
386 {
387         weapon_info *w;
388
389         if (weapon_type < 0)
390                 return;
391         w = &Weapon_info[weapon_type];
392         ogl_cache_vclipn_textures(w->flash_vclip);
393         ogl_cache_vclipn_textures(w->robot_hit_vclip);
394         ogl_cache_vclipn_textures(w->wall_hit_vclip);
395         if (w->render_type==WEAPON_RENDER_VCLIP)
396                 ogl_cache_vclipn_textures(w->weapon_vclip);
397         else if (w->render_type == WEAPON_RENDER_POLYMODEL)
398         {
399                 ogl_cache_polymodel_textures(w->model_num);
400                 ogl_cache_polymodel_textures(w->model_num_inner);
401         }
402 }
403
404 void ogl_cache_level_textures(void)
405 {
406         int seg,side,i;
407         eclip *ec;
408         short tmap1,tmap2;
409         grs_bitmap *bm,*bm2;
410         struct side *sidep;
411         int max_efx=0,ef;
412         
413         ogl_reset_texture_stats_internal();//loading a new lev should reset textures
414         
415         for (i=0,ec=Effects;i<Num_effects;i++,ec++) {
416                 ogl_cache_vclipn_textures(Effects[i].dest_vclip);
417                 if ((Effects[i].changing_wall_texture == -1) && (Effects[i].changing_object_texture==-1) )
418                         continue;
419                 if (ec->vc.num_frames>max_efx)
420                         max_efx=ec->vc.num_frames;
421         }
422         glmprintf((0,"max_efx:%i\n",max_efx));
423         for (ef=0;ef<max_efx;ef++){
424                 for (i=0,ec=Effects;i<Num_effects;i++,ec++) {
425                         if ((Effects[i].changing_wall_texture == -1) && (Effects[i].changing_object_texture==-1) )
426                                 continue;
427 //                      if (ec->vc.num_frames>max_efx)
428 //                              max_efx=ec->vc.num_frames;
429                         ec->time_left=-1;
430                 }
431                 do_special_effects();
432
433                 for (seg=0;seg<Num_segments;seg++){
434                         for (side=0;side<MAX_SIDES_PER_SEGMENT;side++){
435                                 sidep=&Segments[seg].sides[side];
436                                 tmap1=sidep->tmap_num;
437                                 tmap2=sidep->tmap_num2;
438                                 if (tmap1<0 || tmap1>=NumTextures){
439                                         glmprintf((0,"ogl_cache_level_textures %i %i %i %i\n",seg,side,tmap1,NumTextures));
440                                         //                              tmap1=0;
441                                         continue;
442                                 }
443                                 PIGGY_PAGE_IN(Textures[tmap1]);
444                                 bm = &GameBitmaps[Textures[tmap1].index];
445                                 if (tmap2 != 0){
446                                         PIGGY_PAGE_IN(Textures[tmap2&0x3FFF]);
447                                         bm2 = &GameBitmaps[Textures[tmap2&0x3FFF].index];
448                                         if (ogl_alttexmerge == 0 || (!OGL_SUPER_TRANSPARENT_OK && (bm2->bm_flags & BM_FLAG_SUPER_TRANSPARENT)))
449                                                 bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
450                                         else {
451                                                 ogl_loadbmtexture(bm2);
452                                         }
453                                         //                              glmprintf((0,"ogl_cache_level_textures seg %i side %i t1 %i t2 %x bm %p NT %i\n",seg,side,tmap1,tmap2,bm,NumTextures));
454                                 }
455                                 ogl_loadbmtexture(bm);
456                         }
457                 }
458                 glmprintf((0,"finished ef:%i\n",ef));
459         }
460         reset_special_effects();
461         init_special_effects();
462         {
463 //              int laserlev=1;
464
465                 // always have lasers, concs, flares.  Always shows player appearance, and at least concs are always available to disappear.
466                 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[LASER_INDEX]);
467                 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[CONCUSSION_INDEX]);
468                 ogl_cache_weapon_textures(FLARE_ID);
469                 ogl_cache_vclipn_textures(VCLIP_PLAYER_APPEARANCE);
470                 ogl_cache_vclipn_textures(VCLIP_POWERUP_DISAPPEARANCE);
471                 ogl_cache_polymodel_textures(Player_ship->model_num);
472                 ogl_cache_vclipn_textures(Player_ship->expl_vclip_num);
473
474                 for (i=0;i<Highest_object_index;i++){
475                         if(Objects[i].render_type==RT_POWERUP){
476                                 ogl_cache_vclipn_textures(Objects[i].rtype.vclip_info.vclip_num);
477                                 switch (Objects[i].id){
478 /*                                      case POW_LASER:
479                                                 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[LASER_INDEX]);
480 //                                              if (laserlev<4)
481 //                                                      laserlev++;
482                                                 break;*/
483                                         case POW_VULCAN_WEAPON:
484                                                 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[VULCAN_INDEX]);
485                                                 break;
486                                         case POW_SPREADFIRE_WEAPON:
487                                                 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[SPREADFIRE_INDEX]);
488                                                 break;
489                                         case POW_PLASMA_WEAPON:
490                                                 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[PLASMA_INDEX]);
491                                                 break;
492                                         case POW_FUSION_WEAPON:
493                                                 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[FUSION_INDEX]);
494                                                 break;
495 /*                                      case POW_MISSILE_1:
496                                         case POW_MISSILE_4:
497                                                 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[CONCUSSION_INDEX]);
498                                                 break;*/
499                                         case POW_PROXIMITY_WEAPON:
500                                                 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[PROXIMITY_INDEX]);
501                                                 break;
502                                         case POW_HOMING_AMMO_1:
503                                         case POW_HOMING_AMMO_4:
504                                                 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[HOMING_INDEX]);
505                                                 break;
506                                         case POW_SMARTBOMB_WEAPON:
507                                                 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[SMART_INDEX]);
508                                                 break;
509                                         case POW_MEGA_WEAPON:
510                                                 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[MEGA_INDEX]);
511                                                 break;
512                                 }
513                         }
514                         else if(Objects[i].render_type==RT_POLYOBJ){
515                                 //printf("robot %i model %i rmodel %i\n", Objects[i].id, Objects[i].rtype.pobj_info.model_num, Robot_info[Objects[i].id].model_num);
516                                 if (Objects[i].type == OBJ_ROBOT)
517                                 {
518                                         ogl_cache_vclipn_textures(Robot_info[Objects[i].id].exp1_vclip_num);
519                                         ogl_cache_vclipn_textures(Robot_info[Objects[i].id].exp2_vclip_num);
520                                         ogl_cache_weapon_textures(Robot_info[Objects[i].id].weapon_type);
521                                 }
522                                 if (Objects[i].rtype.pobj_info.tmap_override != -1)
523                                         ogl_loadbmtexture(&GameBitmaps[Textures[Objects[i].rtype.pobj_info.tmap_override].index]);
524                                 else
525                                         ogl_cache_polymodel_textures(Objects[i].rtype.pobj_info.model_num);
526                         }
527                 }
528         }
529         glmprintf((0,"finished caching\n"));
530         r_cachedtexcount = r_texcount;
531 }
532
533 int r_polyc,r_tpolyc,r_bitmapc,r_ubitmapc,r_ubitbltc,r_upixelc;
534 #define f2glf(x) (f2fl(x))
535
536 bool g3_draw_line(g3s_point *p0,g3s_point *p1)
537 {
538         int c;
539         c=grd_curcanv->cv_color;
540         OGL_DISABLE(TEXTURE_2D);
541         glColor3f(PAL2Tr(c),PAL2Tg(c),PAL2Tb(c));
542         glBegin(GL_LINES);
543         glVertex3f(f2glf(p0->p3_vec.x),f2glf(p0->p3_vec.y),-f2glf(p0->p3_vec.z));
544         glVertex3f(f2glf(p1->p3_vec.x),f2glf(p1->p3_vec.y),-f2glf(p1->p3_vec.z));
545         glEnd();
546         return 1;
547 }
548 void ogl_drawcircle2(int nsides,int type,float xsc,float xo,float ysc,float yo){
549         int i;
550         float ang;
551         glBegin(type);
552         for (i=0; i<nsides; i++) {
553                 ang = 2.0*M_PI*i/nsides;
554                 glVertex2f(cosf(ang)*xsc+xo,sinf(ang)*ysc+yo);
555         }
556         glEnd();
557 }
558 void ogl_drawcircle(int nsides,int type){
559         int i;
560         float ang;
561         glBegin(type);
562         for (i=0; i<nsides; i++) {
563                 ang = 2.0*M_PI*i/nsides;
564                 glVertex2f(cosf(ang),sinf(ang));
565         }
566         glEnd();
567 }
568 int circle_list_init(int nsides,int type,int mode) {
569         int hand=glGenLists(1);
570         glNewList(hand, mode);
571         /* draw a unit radius circle in xy plane centered on origin */
572         ogl_drawcircle(nsides,type);
573         glEndList();
574         return hand;
575 }
576 float bright_g[4]={     32.0/256,       252.0/256,      32.0/256};
577 float dark_g[4]={       32.0/256,       148.0/256,      32.0/256};
578 float darker_g[4]={     32.0/256,       128.0/256,      32.0/256};
579 void ogl_draw_reticle(int cross,int primary,int secondary){
580         float scale=(float)Canvas_height/(float)grd_curscreen->sc_h;
581         glPushMatrix();
582 //      glTranslatef(0.5,0.5,0);
583         glTranslatef((grd_curcanv->cv_bitmap.bm_w/2+grd_curcanv->cv_bitmap.bm_x)/(float)last_width,1.0-(grd_curcanv->cv_bitmap.bm_h/2+grd_curcanv->cv_bitmap.bm_y)/(float)last_height,0);
584         glScalef(scale/320.0,scale/200.0,scale);//the positions are based upon the standard reticle at 320x200 res.
585         
586         OGL_DISABLE(TEXTURE_2D);
587
588         if (!cross_lh[cross]){
589                 cross_lh[cross]=glGenLists(1);
590                 glNewList(cross_lh[cross], GL_COMPILE_AND_EXECUTE);
591                 glBegin(GL_LINES);
592                 //cross top left
593                 glColor3fv(darker_g);
594                 glVertex2f(-4.0,4.0);
595                 if (cross)
596                         glColor3fv(bright_g);
597                 else
598                         glColor3fv(dark_g);
599                 glVertex2f(-2.0,2.0);
600
601                 //cross bottom left
602                 glColor3fv(dark_g);
603                 glVertex2f(-3.0,-2.0);
604                 if (cross)
605                         glColor3fv(bright_g);
606                 glVertex2f(-2.0,-1.0);
607
608                 //cross top right
609                 glColor3fv(darker_g);
610                 glVertex2f(4.0,4.0);
611                 if (cross)
612                         glColor3fv(bright_g);
613                 else
614                         glColor3fv(dark_g);
615                 glVertex2f(2.0,2.0);
616
617                 //cross bottom right
618                 glColor3fv(dark_g);
619                 glVertex2f(3.0,-2.0);
620                 if (cross)
621                         glColor3fv(bright_g);
622                 glVertex2f(2.0,-1.0);
623
624                 glEnd();
625                 glEndList();
626         }else
627                 glCallList(cross_lh[cross]);
628
629 //      if (Canvas_height>200)
630 //              glLineWidth(Canvas_height/(float)200);
631         if (!primary_lh[primary]){
632                 primary_lh[primary]=glGenLists(1);
633                 glNewList(primary_lh[primary], GL_COMPILE_AND_EXECUTE);
634
635                 glColor3fv(dark_g);
636                 glBegin(GL_LINES);
637                 //left primary bar
638                 glVertex2f(-14.0,-8.0);
639                 glVertex2f(-8.0,-5.0);
640                 //right primary bar
641                 glVertex2f(14.0,-8.0);
642                 glVertex2f(8.0,-5.0);
643                 glEnd();
644                 if (primary==0)
645                         glColor3fv(dark_g);
646                 else
647                         glColor3fv(bright_g);
648                 //left upper
649                 ogl_drawcircle2(6,GL_POLYGON,1.5,-7.0,1.5,-5.0);
650                 //right upper
651                 ogl_drawcircle2(6,GL_POLYGON,1.5,7.0,1.5,-5.0);
652                 if (primary!=2)
653                         glColor3fv(dark_g);
654                 else
655                         glColor3fv(bright_g);
656                 //left lower
657                 ogl_drawcircle2(4,GL_POLYGON,1.0,-14.0,1.0,-8.0);
658                 //right lower
659                 ogl_drawcircle2(4,GL_POLYGON,1.0,14.0,1.0,-8.0);
660
661                 glEndList();
662         }else
663                 glCallList(primary_lh[primary]);
664 //      if (Canvas_height>200)
665 //              glLineWidth(1);
666
667         if (!secondary_lh[secondary]){
668                 secondary_lh[secondary]=glGenLists(1);
669                 glNewList(secondary_lh[secondary], GL_COMPILE_AND_EXECUTE);
670                 if (secondary<=2){
671                         //left secondary
672                         if (secondary!=1)
673                                 glColor3fv(darker_g);
674                         else
675                                 glColor3fv(bright_g);
676                         ogl_drawcircle2(8,GL_LINE_LOOP,2.0,-10.0,2.0,-1.0);
677                         //right secondary
678                         if (secondary!=2)
679                                 glColor3fv(darker_g);
680                         else
681                                 glColor3fv(bright_g);
682                         ogl_drawcircle2(8,GL_LINE_LOOP,2.0,10.0,2.0,-1.0);
683                 }else{
684                         //bottom/middle secondary
685                         if (secondary!=4)
686                                 glColor3fv(darker_g);
687                         else
688                                 glColor3fv(bright_g);
689                         ogl_drawcircle2(8,GL_LINE_LOOP,2.0,0.0,2.0,-7.0);
690                 }
691                 glEndList();
692         }else
693                 glCallList(secondary_lh[secondary]);
694
695         glPopMatrix();
696 }
697 int g3_draw_sphere(g3s_point *pnt,fix rad){
698         int c;
699         c=grd_curcanv->cv_color;
700         OGL_DISABLE(TEXTURE_2D);
701 //      glPointSize(f2glf(rad));
702         glColor3f(CPAL2Tr(c),CPAL2Tg(c),CPAL2Tb(c));
703 //      glBegin(GL_POINTS);
704 //      glVertex3f(f2glf(pnt->p3_vec.x),f2glf(pnt->p3_vec.y),-f2glf(pnt->p3_vec.z));
705 //      glEnd();
706         glPushMatrix();
707         glTranslatef(f2glf(pnt->p3_vec.x),f2glf(pnt->p3_vec.y),-f2glf(pnt->p3_vec.z));
708         glScalef(f2glf(rad),f2glf(rad),f2glf(rad));
709         if (!sphereh) sphereh=circle_list_init(20,GL_POLYGON,GL_COMPILE_AND_EXECUTE);
710         else glCallList(sphereh);
711         glPopMatrix();
712         return 0;
713
714 }
715 int gr_ucircle(fix xc1, fix yc1, fix r1)
716 {
717         int c;
718         c=grd_curcanv->cv_color;
719         OGL_DISABLE(TEXTURE_2D);
720         glColor3f(CPAL2Tr(c),CPAL2Tg(c),CPAL2Tb(c));
721         glPushMatrix();
722         glTranslatef(
723                      (f2fl(xc1) + grd_curcanv->cv_bitmap.bm_x + 0.5) / (float)last_width,
724                      1.0 - (f2fl(yc1) + grd_curcanv->cv_bitmap.bm_y + 0.5) / (float)last_height,0);
725         glScalef(f2fl(r1) / last_width, f2fl(r1) / last_height, 1.0);
726         ogl_drawcircle(10 + 2 * (int)(M_PI * f2fl(r1) / 19), GL_LINE_LOOP);
727         glPopMatrix();
728         return 0;
729 }
730 int gr_circle(fix xc1,fix yc1,fix r1){
731         return gr_ucircle(xc1,yc1,r1);
732 }
733
734 bool g3_draw_poly(int nv,g3s_point **pointlist)
735 {
736         int c;
737         r_polyc++;
738         c=grd_curcanv->cv_color;
739 //      glColor3f((gr_palette[c*3] + gr_palette_gamma.intval) / 63.0, (gr_palette[c*3+1] + gr_palette_gamma.intval) / 63.0, (gr_palette[c*3+2] + gr_palette_gamma.intval) / 63.0);
740         OGL_DISABLE(TEXTURE_2D);
741         if (Gr_scanline_darkening_level >= GR_FADE_LEVELS)
742                 glColor3f(PAL2Tr(c), PAL2Tg(c), PAL2Tb(c));
743         else
744                 glColor4f(PAL2Tr(c), PAL2Tg(c), PAL2Tb(c), 1.0 - (float)Gr_scanline_darkening_level / ((float)GR_FADE_LEVELS - 1.0));
745         glBegin(GL_TRIANGLE_FAN);
746         for (c=0;c<nv;c++){
747         //      glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),f2glf(pointlist[c]->p3_vec.z));
748                 glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),-f2glf(pointlist[c]->p3_vec.z));
749         }
750         glEnd();
751         return 0;
752 }
753
754 void gr_upoly_tmap(int nverts, int *vert ){
755                 mprintf((0,"gr_upoly_tmap: unhandled\n"));//should never get called
756 }
757 void draw_tmap_flat(grs_bitmap *bm,int nv,g3s_point **vertlist){
758                 mprintf((0,"draw_tmap_flat: unhandled\n"));//should never get called
759 }
760 extern void (*tmap_drawer_ptr)(grs_bitmap *bm,int nv,g3s_point **vertlist);
761 bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm)
762 {
763         int c;
764         float l;
765         if (tmap_drawer_ptr==draw_tmap_flat){
766 /*              fix average_light=0;
767                 int i;
768                 for (i=0; i<nv; i++)
769                         average_light += uvl_list[i].l;*/
770                 OGL_DISABLE(TEXTURE_2D);
771 //              glmprintf((0,"Gr_scanline_darkening_level=%i %f\n",Gr_scanline_darkening_level,Gr_scanline_darkening_level/(float)NUM_LIGHTING_LEVELS));
772                 glColor4f(0,0,0,1.0-(Gr_scanline_darkening_level/(float)NUM_LIGHTING_LEVELS));
773                 //glColor4f(0,0,0,f2fl(average_light/nv));
774                 glBegin(GL_TRIANGLE_FAN);
775                 for (c=0;c<nv;c++){
776 //                      glColor4f(0,0,0,f2fl(uvl_list[c].l));
777 //                      glTexCoord2f(f2glf(uvl_list[c].u),f2glf(uvl_list[c].v));
778                         glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),-f2glf(pointlist[c]->p3_vec.z));
779                 }
780                 glEnd();
781         }else if (tmap_drawer_ptr==draw_tmap){
782                 r_tpolyc++;
783                 /*      if (bm->bm_w !=64||bm->bm_h!=64)
784                         printf("g3_draw_tmap w %i h %i\n",bm->bm_w,bm->bm_h);*/
785                 OGL_ENABLE(TEXTURE_2D);
786                 ogl_bindbmtex(bm);
787                 ogl_texwrap(bm->gltexture,GL_REPEAT);
788                 glBegin(GL_TRIANGLE_FAN);
789                 for (c=0;c<nv;c++){
790                         if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
791                                 l=1.0;
792                         }else{
793                                 //l = f2fl(uvl_list[c].l) + gr_palette_gamma.intval / 63.0;
794                                 l=f2fl(uvl_list[c].l);
795                         }
796                         glColor3f(l,l,l);
797                         glTexCoord2f(f2glf(uvl_list[c].u),f2glf(uvl_list[c].v));
798                         //glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),f2glf(pointlist[c]->p3_vec.z));
799                         glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),-f2glf(pointlist[c]->p3_vec.z));
800                 }
801                 glEnd();
802         }else{
803                 mprintf((0,"g3_draw_tmap: unhandled tmap_drawer %p\n",tmap_drawer_ptr));
804         }
805         return 0;
806 }
807
808 int active_texture_unit = 0;
809
810 void ogl_setActiveTexture(int t)
811 {
812         if (ogl_arb_multitexture_ok)
813         {
814 #ifdef GL_ARB_multitexture
815                 if (t == 0)
816                         glActiveTextureARB(GL_TEXTURE0_ARB);
817                 else
818                         glActiveTextureARB(GL_TEXTURE1_ARB);
819 #endif
820         }
821         else if (ogl_sgis_multitexture_ok)
822         {
823 #ifdef GL_SGIS_multitexture
824                 if (t == 0)
825                         glSelectTextureSGIS(GL_TEXTURE0_SGIS);
826                 else
827                         glSelectTextureSGIS(GL_TEXTURE1_SGIS);
828 #endif
829         }
830         active_texture_unit = t;
831 }
832
833 void ogl_MultiTexCoord2f(int t, float u, float v)
834 {
835         if (ogl_arb_multitexture_ok)
836         {
837 #ifdef GL_ARB_multitexture
838                 if (t == 0)
839                         glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
840                 else
841                         glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
842 #endif
843         }
844         else if (ogl_sgis_multitexture_ok)
845         {
846 #ifdef GL_SGIS_multitexture
847                 if (t == 0)
848                         glMultiTexCoord2fSGIS(GL_TEXTURE0_SGIS, u, v);
849                 else
850                         glMultiTexCoord2fSGIS(GL_TEXTURE1_SGIS, u, v);
851 #endif
852         }
853 }
854
855 bool g3_draw_tmap_2(int nv, g3s_point **pointlist, g3s_uvl *uvl_list, grs_bitmap *bmbot, grs_bitmap *bm, int orient)
856 {
857 #if ((defined(GL_NV_register_combiners) || defined(GL_NV_texture_env_combine4)) && (defined(GL_ARB_multitexture) || defined(GL_SGIS_multitexture)))
858         if ((/*ogl_nv_register_combiners_ok ||*/ ogl_nv_texture_env_combine4_ok) && (ogl_arb_multitexture_ok || ogl_sgis_multitexture_ok))
859         {
860                 int c;
861                 float l, u1, v1;
862
863                 if (tmap_drawer_ptr != draw_tmap)
864                         Error("WTFF\n");
865
866                 r_tpolyc+=2;
867
868                 //ogl_setActiveTexture(0);
869                 OGL_ENABLE(TEXTURE_2D);
870                 ogl_bindbmtex(bmbot);
871                 ogl_texwrap(bmbot->gltexture, GL_REPEAT);
872                 // GL_MODULATE is fine for texture 0
873
874                 ogl_setActiveTexture(1);
875                 glEnable(GL_TEXTURE_2D);
876                 ogl_bindbmtex(bm);
877                 ogl_texwrap(bm->gltexture,GL_REPEAT);
878
879 #ifdef GL_NV_register_combiners
880                 if (ogl_nv_register_combiners_ok)
881                 {
882                         glEnable(GL_REGISTER_COMBINERS_NV);
883                         glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1);
884                         // spare0 = tex0 * (1-alpha1) + tex1 * alpha1
885                         glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
886                         glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE1_ARB, GL_UNSIGNED_INVERT_NV, GL_ALPHA);
887                         glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
888                         glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
889                         glCombinerOutputNV(
890                                            GL_COMBINER0_NV,   //GLenum stage
891                                            GL_RGB,            //GLenum portion,
892                                            GL_DISCARD_NV,     //GLenum abOutput,
893                                            GL_DISCARD_NV,     //GLenum cdOutput,
894                                            GL_SPARE0_NV,      //GLenum sumOutput,
895                                            GL_NONE,           //GLenum scale,
896                                            GL_NONE,           //GLenum bias,
897                                            GL_FALSE,          //GLboolean abDotProduct,
898                                            GL_FALSE,          //GLboolean cdDotProduct,
899                                            GL_FALSE           //GLboolean muxSum
900                                            );
901                         // out = spare0 * color
902                         // ( out = AB + (1-A)C + D )
903                         glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
904                         glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
905                         glFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
906                         glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
907
908                         if (bm->bm_flags & BM_FLAG_SUPER_TRANSPARENT)
909                         {
910                                 // out = alpha0*(1-tex1) + alpha1
911                                 glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
912                                 glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_TEXTURE1_ARB, GL_UNSIGNED_INVERT_NV, GL_BLUE);
913                                 glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
914                                 glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA);
915                         }
916                         else
917                         {
918                                 // out = alpha0 + alpha1
919                                 glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
920                                 glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA);
921                                 glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
922                                 glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA);
923                         }
924                         glCombinerOutputNV(
925                                            GL_COMBINER0_NV,   //GLenum stage
926                                            GL_ALPHA,          //GLenum portion,
927                                            GL_DISCARD_NV,     //GLenum abOutput,
928                                            GL_DISCARD_NV,     //GLenum cdOutput,
929                                            GL_SPARE0_NV,      //GLenum sumOutput,
930                                            GL_NONE,           //GLenum scale,
931                                            GL_NONE,           //GLenum bias,
932                                            GL_FALSE,          //GLboolean abDotProduct,
933                                            GL_FALSE,          //GLboolean cdDotProduct,
934                                            GL_FALSE           //GLboolean muxSum
935                                            );
936                         glFinalCombinerInputNV(GL_VARIABLE_G_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
937                 }
938                 else
939 #endif
940                 {
941                         //http://oss.sgi.com/projects/ogl-sample/registry/NV/texture_env_combine4.txt
942                         //only GL_NV_texture_env_combine4 lets us do what we need:
943                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV);
944
945                         //multiply top texture by color(vertex lighting) and add bottom texture(where alpha says to)
946                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
947
948                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
949                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
950                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_TEXTURE);
951                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_PREVIOUS_EXT);
952
953                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
954                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
955                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA);
956                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_COLOR);
957
958                         //add up alpha channels
959                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
960
961                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE);
962                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_ZERO);
963                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_PREVIOUS_EXT);
964                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_ZERO);
965
966                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA);
967                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
968                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
969                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA);
970                 }
971
972                 // GL_DECAL works sorta ok but the top texture is fullbright.
973                 //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
974
975                 // GL_ARB_texture_env_combine comes close, but doesn't quite make it.
976                 //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
977
978                 //// this gives effect like GL_DECAL:
979                 //glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE);
980                 //glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
981                 //glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
982                 //glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
983
984
985                 // this properly shades the top texture, but the bottom texture doesn't get through.
986                 //glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
987                 //glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
988                 //glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
989
990
991                 // add up alpha
992                 //glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_ADD);
993                 //glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
994                 //glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
995
996                 glBegin(GL_TRIANGLE_FAN);
997                 for (c=0;c<nv;c++){
998                         switch(orient){
999                                 case 1:
1000                                         u1=1.0-f2glf(uvl_list[c].v);
1001                                         v1=f2glf(uvl_list[c].u);
1002                                         break;
1003                                 case 2:
1004                                         u1=1.0-f2glf(uvl_list[c].u);
1005                                         v1=1.0-f2glf(uvl_list[c].v);
1006                                         break;
1007                                 case 3:
1008                                         u1=f2glf(uvl_list[c].v);
1009                                         v1=1.0-f2glf(uvl_list[c].u);
1010                                         break;
1011                                 default:
1012                                         u1=f2glf(uvl_list[c].u);
1013                                         v1=f2glf(uvl_list[c].v);
1014                                         break;
1015                         }
1016                         if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
1017                                 l=1.0;
1018                         }else{
1019                                 l=f2fl(uvl_list[c].l);
1020                         }
1021                         glColor3f(l,l,l);
1022                         ogl_MultiTexCoord2f(0, f2glf(uvl_list[c].u), f2glf(uvl_list[c].v));
1023                         ogl_MultiTexCoord2f(1, u1, v1);
1024                         //glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),f2glf(pointlist[c]->p3_vec.z));
1025                         //glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),f2glf(pointlist[c]->p3_vec.z));
1026                         glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),-f2glf(pointlist[c]->p3_vec.z));
1027                 }
1028                 glEnd();
1029                 //ogl_setActiveTexture(1); // still the active texture
1030 #ifdef GL_NV_register_combiners
1031                 if (ogl_nv_register_combiners_ok)
1032                 {
1033                         glDisable(GL_REGISTER_COMBINERS_NV);
1034                 }
1035                 else
1036 #endif
1037                 {
1038                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1039                 }
1040                 glDisable(GL_TEXTURE_2D);
1041                 ogl_setActiveTexture(0);
1042         }
1043         else
1044 #endif
1045         {
1046                 int c;
1047                 float l,u1,v1;
1048
1049                 g3_draw_tmap(nv,pointlist,uvl_list,bmbot);//draw the bottom texture first.. could be optimized with multitexturing..
1050
1051                 r_tpolyc++;
1052                 /*      if (bm->bm_w !=64||bm->bm_h!=64)
1053                         printf("g3_draw_tmap w %i h %i\n",bm->bm_w,bm->bm_h);*/
1054                 OGL_ENABLE(TEXTURE_2D);
1055                 ogl_bindbmtex(bm);
1056                 ogl_texwrap(bm->gltexture,GL_REPEAT);
1057                 glBegin(GL_TRIANGLE_FAN);
1058                 for (c=0;c<nv;c++){
1059                         switch(orient){
1060                                 case 1:
1061                                         u1=1.0-f2glf(uvl_list[c].v);
1062                                         v1=f2glf(uvl_list[c].u);
1063                                         break;
1064                                 case 2:
1065                                         u1=1.0-f2glf(uvl_list[c].u);
1066                                         v1=1.0-f2glf(uvl_list[c].v);
1067                                         break;
1068                                 case 3:
1069                                         u1=f2glf(uvl_list[c].v);
1070                                         v1=1.0-f2glf(uvl_list[c].u);
1071                                         break;
1072                                 default:
1073                                         u1=f2glf(uvl_list[c].u);
1074                                         v1=f2glf(uvl_list[c].v);
1075                                         break;
1076                         }
1077                         if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
1078                                 l=1.0;
1079                         }else{
1080                                 //l = f2fl(uvl_list[c].l) + gr_palette_gamma.intval / 63.0;
1081                                 l=f2fl(uvl_list[c].l);
1082                         }
1083                         glColor3f(l,l,l);
1084                         glTexCoord2f(u1,v1);
1085                         //glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),f2glf(pointlist[c]->p3_vec.z));
1086                         //glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),f2glf(pointlist[c]->p3_vec.z));
1087                         glVertex3f(f2glf(pointlist[c]->p3_vec.x),f2glf(pointlist[c]->p3_vec.y),-f2glf(pointlist[c]->p3_vec.z));
1088                 }
1089                 glEnd();
1090         }
1091         return 0;
1092 }
1093
1094 bool g3_draw_bitmap(vms_vector *pos,fix width,fix height,grs_bitmap *bm, int orientation)
1095 {
1096         //float l=1.0;
1097         vms_vector pv,v1;//,v2;
1098         int i;
1099         r_bitmapc++;
1100         v1.z=0;
1101 //      printf("g3_draw_bitmap: %f,%f,%f - ",f2glf(pos->x),f2glf(pos->y),-f2glf(pos->z));
1102 //      printf("(%f,%f,%f) ",f2glf(View_position.x),f2glf(View_position.y),-f2glf(View_position.z));
1103
1104         OGL_ENABLE(TEXTURE_2D);
1105         ogl_bindbmtex(bm);
1106         ogl_texwrap(bm->gltexture,GL_CLAMP);
1107
1108         glBegin(GL_QUADS);
1109         glColor3f(1.0,1.0,1.0);
1110     width = fixmul(width,Matrix_scale.x);       
1111     height = fixmul(height,Matrix_scale.y);     
1112         for (i=0;i<4;i++){
1113 //              g3_rotate_point(&p[i],pos);
1114                 vm_vec_sub(&v1,pos,&View_position);
1115                 vm_vec_rotate(&pv,&v1,&View_matrix);
1116 //              printf(" %f,%f,%f->",f2glf(pv.x),f2glf(pv.y),-f2glf(pv.z));
1117                 switch (i){
1118                         case 0:
1119                                 glTexCoord2f(0.0, 0.0);
1120                                 pv.x+=-width;
1121                                 pv.y+=height;
1122                                 break;
1123                         case 1:
1124                                 glTexCoord2f(bm->gltexture->u, 0.0);
1125                                 pv.x+=width;
1126                                 pv.y+=height;
1127                                 break;
1128                         case 2:
1129                                 glTexCoord2f(bm->gltexture->u, bm->gltexture->v);
1130                                 pv.x+=width;
1131                                 pv.y+=-height;
1132                                 break;
1133                         case 3:
1134                                 glTexCoord2f(0.0, bm->gltexture->v);
1135                                 pv.x+=-width;
1136                                 pv.y+=-height;
1137                                 break;
1138                 }
1139 //              vm_vec_rotate(&v2,&v1,&View_matrix);
1140 //              vm_vec_sub(&v1,&v2,&pv);
1141                 //vm_vec_sub(&v1,&pv,&v2);
1142 //              vm_vec_sub(&v2,&pv,&v1);
1143                 glVertex3f(f2glf(pv.x),f2glf(pv.y),-f2glf(pv.z));
1144 //              printf("%f,%f,%f ",f2glf(v1.x),f2glf(v1.y),-f2glf(v1.z));
1145         }
1146         glEnd();
1147 //      printf("\n");
1148
1149         return 0;
1150 }
1151
1152 bool ogl_ubitmapm_c(int x, int y,grs_bitmap *bm,int c)
1153 {
1154         GLfloat xo,yo,xf,yf;
1155         GLfloat u1,u2,v1,v2;
1156         r_ubitmapc++;
1157         x+=grd_curcanv->cv_bitmap.bm_x;
1158         y+=grd_curcanv->cv_bitmap.bm_y;
1159         xo=x/(float)last_width;
1160         xf=(bm->bm_w+x)/(float)last_width;
1161         yo=1.0-y/(float)last_height;
1162         yf=1.0-(bm->bm_h+y)/(float)last_height;
1163
1164 //      printf("g3_draw_bitmap: %f,%f,%f - ",f2glf(pos->x),f2glf(pos->y),-f2glf(pos->z));
1165 //      printf("(%f,%f,%f) ",f2glf(View_position.x),f2glf(View_position.y),-f2glf(View_position.z));
1166
1167 /*              glEnABLE(ALPHA_TEST);
1168         glAlphaFunc(GL_GREATER,0.0);*/
1169
1170         OGL_ENABLE(TEXTURE_2D);
1171         ogl_bindbmtex(bm);
1172         ogl_texwrap(bm->gltexture,GL_CLAMP);
1173         
1174         if (bm->bm_x==0){
1175                 u1=0;
1176                 if (bm->bm_w==bm->gltexture->w)
1177                         u2=bm->gltexture->u;
1178                 else
1179                         u2=(bm->bm_w+bm->bm_x)/(float)bm->gltexture->tw;
1180         }else {
1181                 u1=bm->bm_x/(float)bm->gltexture->tw;
1182                 u2=(bm->bm_w+bm->bm_x)/(float)bm->gltexture->tw;
1183         }
1184         if (bm->bm_y==0){
1185                 v1=0;
1186                 if (bm->bm_h==bm->gltexture->h)
1187                         v2=bm->gltexture->v;
1188                 else
1189                         v2=(bm->bm_h+bm->bm_y)/(float)bm->gltexture->th;
1190         }else{
1191                 v1=bm->bm_y/(float)bm->gltexture->th;
1192                 v2=(bm->bm_h+bm->bm_y)/(float)bm->gltexture->th;
1193         }
1194
1195         glBegin(GL_QUADS);
1196         if (c<0)
1197                 glColor3f(1.0,1.0,1.0);
1198         else
1199                 glColor3f(CPAL2Tr(c),CPAL2Tg(c),CPAL2Tb(c));
1200         glTexCoord2f(u1, v1); glVertex2f(xo, yo);
1201         glTexCoord2f(u2, v1); glVertex2f(xf, yo);
1202         glTexCoord2f(u2, v2); glVertex2f(xf, yf);
1203         glTexCoord2f(u1, v2); glVertex2f(xo, yf);
1204         glEnd();
1205 //      glDisABLE(ALPHA_TEST);
1206         
1207         return 0;
1208 }
1209 bool ogl_ubitmapm(int x, int y,grs_bitmap *bm){
1210         return ogl_ubitmapm_c(x,y,bm,-1);
1211 //      return ogl_ubitblt(bm->bm_w,bm->bm_h,x,y,0,0,bm,NULL);
1212 }
1213 #if 0
1214 //also upsidedown, currently.
1215 bool ogl_ubitblt(int w,int h,int dx,int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest)
1216 {
1217         GLfloat xo,yo;//,xs,ys;
1218         glmprintf((0,"ogl_ubitblt(w=%i,h=%i,dx=%i,dy=%i,sx=%i,sy=%i,src=%p,dest=%p\n",w,h, dx, dy,sx, sy,  src,dest));
1219         
1220         dx+=dest->bm_x;
1221         dy+=dest->bm_y;
1222         
1223         xo=dx/(float)last_width;
1224 //      xo=dx/(float)grd_curscreen->sc_w;
1225 //      xs=w/(float)last_width;
1226         //yo=1.0-dy/(float)last_height;
1227         yo=1.0-(dy+h)/(float)last_height;
1228 //      ys=h/(float)last_height;
1229         
1230 //      OGL_ENABLE(TEXTURE_2D);
1231         
1232         OGL_DISABLE(TEXTURE_2D);
1233         glRasterPos2f(xo,yo);
1234         ogl_filltexbuf(src->bm_data,texbuf,src->bm_w,w,h,sx,sy,w,h,GL_RGBA);
1235         glDrawPixels(w,h,GL_RGBA,GL_UNSIGNED_BYTE,texbuf);
1236         glRasterPos2f(0,0);
1237         
1238         return 0;
1239 }
1240 #else
1241 bool ogl_ubitblt_i(int dw,int dh,int dx,int dy, int sw, int sh, int sx, int sy, grs_bitmap * src, grs_bitmap * dest)
1242 {
1243         GLfloat xo,yo,xs,ys;
1244         GLfloat u1,v1;//,u2,v2;
1245         ogl_texture tex;
1246 //      unsigned char *oldpal;
1247         r_ubitbltc++;
1248
1249         ogl_init_texture(&tex, sw, sh, OGL_FLAG_ALPHA);
1250         tex.prio = 0.0;
1251         tex.lw=src->bm_rowsize;
1252
1253 /*      if (w==src->bm_w && sx==0){
1254                 u1=0;u2=src->glu;
1255         }else{
1256                 u1=sx/(float)src->bm_w*src->glu;
1257                 u2=w/(float)src->bm_w*src->glu+u1;
1258         }
1259         if (h==src->bm_h && sy==0){
1260                 v1=0;v2=src->glv;
1261         }else{
1262                 v1=sy/(float)src->bm_h*src->glv;
1263                 v2=h/(float)src->bm_h*src->glv+v1;
1264         }*/
1265         u1=v1=0;
1266         
1267         dx+=dest->bm_x;
1268         dy+=dest->bm_y;
1269         xo=dx/(float)last_width;
1270         xs=dw/(float)last_width;
1271         yo=1.0-dy/(float)last_height;
1272         ys=dh/(float)last_height;
1273         
1274         OGL_ENABLE(TEXTURE_2D);
1275         
1276 //      oldpal=ogl_pal;
1277         ogl_pal=gr_current_pal;
1278         ogl_loadtexture(src->bm_data, sx, sy, &tex, src->bm_flags, 0);
1279 //      ogl_pal=oldpal;
1280         ogl_pal=gr_palette;
1281         OGL_BINDTEXTURE(tex.handle);
1282         
1283         ogl_texwrap(&tex,GL_CLAMP);
1284
1285         glBegin(GL_QUADS);
1286         glColor3f(1.0,1.0,1.0);
1287         glTexCoord2f(u1, v1); glVertex2f(xo, yo);
1288         glTexCoord2f(tex.u, v1); glVertex2f(xo+xs, yo);
1289         glTexCoord2f(tex.u, tex.v); glVertex2f(xo+xs, yo-ys);
1290         glTexCoord2f(u1, tex.v); glVertex2f(xo, yo-ys);
1291         glEnd();
1292         ogl_freetexture(&tex);
1293         return 0;
1294 }
1295 bool ogl_ubitblt(int w,int h,int dx,int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest){
1296         return ogl_ubitblt_i(w,h,dx,dy,w,h,sx,sy,src,dest);
1297 }
1298 #endif
1299 bool ogl_ubitblt_tolinear(int w,int h,int dx,int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest){
1300 #if 1
1301         unsigned char *d,*s;
1302         int i,j;
1303         int w1,h1;
1304 //      w1=w;h1=h;
1305         w1=grd_curscreen->sc_w;h1=grd_curscreen->sc_h;
1306         if (w1*h1*3>OGLTEXBUFSIZE)
1307                 Error("ogl_ubitblt_tolinear: screen res larger than OGLTEXBUFSIZE\n");
1308
1309         if (ogl_readpixels_ok>0){
1310                 OGL_DISABLE(TEXTURE_2D);
1311                 glReadBuffer(GL_FRONT);
1312                 glReadPixels(0,0,w1,h1,GL_RGB,GL_UNSIGNED_BYTE,texbuf);
1313 //              glReadPixels(sx,grd_curscreen->sc_h-(sy+h),w,h,GL_RGB,GL_UNSIGNED_BYTE,texbuf);
1314 //              glReadPixels(sx,sy,w+sx,h+sy,GL_RGB,GL_UNSIGNED_BYTE,texbuf);
1315         }else
1316                 memset(texbuf,0,w1*h1*3);
1317         sx+=src->bm_x;
1318         sy+=src->bm_y;
1319         for (i=0;i<h;i++){
1320                 d=dest->bm_data+dx+(dy+i)*dest->bm_rowsize;
1321                 s=texbuf+((h1-(i+sy+1))*w1+sx)*3;
1322                 for (j=0;j<w;j++){
1323                         *d=gr_find_closest_color(s[0]/4,s[1]/4,s[2]/4);
1324                         s+=3;
1325                         d++;
1326                 }
1327         }
1328 #else
1329         int i,j,c=0;
1330         unsigned char *d,*s,*e;
1331         if (w*h*3>OGLTEXBUFSIZE)
1332                 Error("ogl_ubitblt_tolinear: size larger than OGLTEXBUFSIZE\n");
1333         sx+=src->bm_x;
1334         sy+=src->bm_y;
1335 #if 1//also seems to cause a mess.  need to look into it a bit more..
1336         if (ogl_readpixels_ok>0){
1337                 OGL_DISABLE(TEXTURE_2D);
1338                 glReadBuffer(GL_FRONT);
1339 //              glReadPixels(0,0,w,h,GL_RGB,GL_UNSIGNED_BYTE,texbuf);
1340                 glReadPixels(sx,grd_curscreen->sc_h-(sy+h),w,h,GL_RGB,GL_UNSIGNED_BYTE,texbuf);
1341         }else
1342 #endif
1343                 memset(texbuf,0,w*h*3);
1344 //      d=dest->bm_data+dx+(dy+i)*dest->bm_rowsize;
1345         d=dest->bm_data+dx+dy*dest->bm_rowsize;
1346         for (i=0;i<h;i++){
1347                 s=texbuf+w*(h-(i+1))*3;
1348 //              s=texbuf+w*i*3;
1349                 if (s<texbuf){Error("blah1\n");}
1350                 if (d<dest->bm_data){Error("blah3\n");}
1351 //              d=dest->bm_data+(i*dest->bm_rowsize);
1352
1353                 e=d;
1354                 for (j=0;j<w;j++){
1355                         if (s>texbuf+w*h*3-3){Error("blah2\n");}
1356                         if (d>dest->bm_data+dest->bm_rowsize*(h+dy)+dx  ){Error("blah4\n");}
1357                         *d=gr_find_closest_color(s[0]/4,s[1]/4,s[2]/4);
1358                         s+=3;
1359                         d++;
1360                         c++;
1361                 }
1362                 d=e;
1363                 d+=dest->bm_rowsize;
1364         }
1365         glmprintf((0,"c=%i w*h=%i\n",c,w*h));
1366 #endif
1367         return 0;
1368 }
1369
1370 bool ogl_ubitblt_copy(int w,int h,int dx,int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest){
1371 #if 0 //just seems to cause a mess.
1372         GLfloat xo,yo;//,xs,ys;
1373         
1374         dx+=dest->bm_x;
1375         dy+=dest->bm_y;
1376         
1377 //      xo=dx/(float)last_width;
1378         xo=dx/(float)grd_curscreen->sc_w;
1379 //      yo=1.0-(dy+h)/(float)last_height;
1380         yo=1.0-(dy+h)/(float)grd_curscreen->sc_h;
1381         sx+=src->bm_x;
1382         sy+=src->bm_y;
1383         OGL_DISABLE(TEXTURE_2D);
1384         glReadBuffer(GL_FRONT);
1385         glRasterPos2f(xo,yo);
1386 //      glReadPixels(0,0,w,h,GL_RGB,GL_UNSIGNED_BYTE,texbuf);
1387         glCopyPixels(sx,grd_curscreen->sc_h-(sy+h),w,h,GL_COLOR);
1388         glRasterPos2f(0,0);
1389 #endif
1390         return 0;
1391 }
1392
1393 grs_canvas *offscreen_save_canv = NULL, *offscreen_canv = NULL;
1394
1395 void ogl_start_offscreen_render(int x, int y, int w, int h)
1396 {
1397         if (offscreen_canv)
1398                 Error("ogl_start_offscreen_render: offscreen_canv!=NULL");
1399         offscreen_save_canv = grd_curcanv;
1400         offscreen_canv = gr_create_sub_canvas(grd_curcanv, x, y, w, h);
1401         gr_set_current_canvas(offscreen_canv);
1402         glDrawBuffer(GL_BACK);
1403 }
1404 void ogl_end_offscreen_render(void)
1405 {
1406         int y;
1407
1408         if (!offscreen_canv)
1409                 Error("ogl_end_offscreen_render: no offscreen_canv");
1410
1411         glDrawBuffer(GL_FRONT);
1412         glReadBuffer(GL_BACK);
1413         OGL_DISABLE(TEXTURE_2D);
1414
1415         y = last_height - offscreen_canv->cv_bitmap.bm_y - offscreen_canv->cv_bitmap.bm_h;
1416         glRasterPos2f(offscreen_canv->cv_bitmap.bm_x/(float)last_width, y/(float)last_height);
1417         glCopyPixels(offscreen_canv->cv_bitmap.bm_x, y,
1418                      offscreen_canv->cv_bitmap.bm_w,
1419                  offscreen_canv->cv_bitmap.bm_h, GL_COLOR);
1420
1421         gr_free_sub_canvas(offscreen_canv);
1422         gr_set_current_canvas(offscreen_save_canv);
1423         offscreen_canv=NULL;
1424 }
1425
1426 void ogl_start_frame(void){
1427         r_polyc=0;r_tpolyc=0;r_bitmapc=0;r_ubitmapc=0;r_ubitbltc=0;r_upixelc=0;
1428 //      gl_badtexture=500;
1429
1430         OGL_VIEWPORT(grd_curcanv->cv_bitmap.bm_x,grd_curcanv->cv_bitmap.bm_y,Canvas_width,Canvas_height);
1431         glClearColor(0.0, 0.0, 0.0, 0.0);
1432 //      glEnable(GL_ALPHA_TEST);
1433 //      glAlphaFunc(GL_GREATER,0.01);
1434         glShadeModel(GL_SMOOTH);
1435         glMatrixMode(GL_PROJECTION);
1436         glLoadIdentity();//clear matrix
1437         //gluPerspective(90.0,(GLfloat)(grd_curscreen->sc_w*3)/(GLfloat)(grd_curscreen->sc_h*4),1.0,1000000.0);
1438         //gluPerspective(90.0,(GLfloat)(grd_curscreen->sc_w*3)/(GLfloat)(grd_curscreen->sc_h*4),0.01,1000000.0);
1439         gluPerspective(90.0,1.0,0.01,1000000.0);
1440         //gluPerspective(90.0,(GLfloat)(Canvas_width*3)/(GLfloat)(Canvas_height*4),0.01,1000000.0);
1441 //      gluPerspective(75.0,(GLfloat)Canvas_width/(GLfloat)Canvas_height,1.0,1000000.0);
1442         glMatrixMode(GL_MODELVIEW);
1443         glLoadIdentity();//clear matrix
1444         glEnable(GL_BLEND);
1445         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1446 //      glDisABLE(DITHER);
1447 //      glScalef(1.0,1.0,-1.0);
1448 //      glScalef(1.0,1.0,-1.0);
1449 //      glPushMatrix();
1450         
1451 //      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1452 //      OGL_TEXENV(GL_TEXTURE_ENV_MODE,GL_MODULATE);
1453 //      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_texmagfilt);
1454 //      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_texminfilt);
1455 //      OGL_TEXPARAM(GL_TEXTURE_MAG_FILTER,GL_texmagfilt);
1456 //      OGL_TEXPARAM(GL_TEXTURE_MIN_FILTER,GL_texminfilt);
1457 //      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1458 //      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1459 }
1460 #ifndef NMONO
1461 void merge_textures_stats(void);
1462 #endif
1463 void ogl_end_frame(void){
1464 //      OGL_VIEWPORT(grd_curcanv->cv_bitmap.bm_x,grd_curcanv->cv_bitmap.bm_y,);
1465         OGL_VIEWPORT(0,0,grd_curscreen->sc_w,grd_curscreen->sc_h);
1466 #ifndef NMONO
1467 //      merge_textures_stats();
1468 //      ogl_texture_stats();
1469 #endif
1470 //      glViewport(0,0,grd_curscreen->sc_w,grd_curscreen->sc_h);
1471         glMatrixMode(GL_PROJECTION);
1472         glLoadIdentity();//clear matrix
1473         glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
1474         glMatrixMode(GL_MODELVIEW);
1475         glLoadIdentity();//clear matrix
1476 //      glDisABLE(BLEND);
1477         //glDisABLE(ALPHA_TEST);
1478         //gluPerspective(90.0,(GLfloat)(grd_curscreen->sc_w*3)/(GLfloat)(grd_curscreen->sc_h*4),1.0,1000000.0);
1479 //      ogl_swap_buffers();//platform specific code
1480 //      glClear(GL_COLOR_BUFFER_BIT);
1481 }
1482 void ogl_swap_buffers(void){
1483         ogl_clean_texture_cache();
1484         if (gr_renderstats){
1485                 gr_printf(5,GAME_FONT->ft_h*13+3*13,"%i flat %i tex %i sprites %i bitmaps",r_polyc,r_tpolyc,r_bitmapc,r_ubitmapc);
1486 //      glmprintf((0,"ogl_end_frame: %i polys, %i tmaps, %i sprites, %i bitmaps, %i bitblts, %i pixels\n",r_polyc,r_tpolyc,r_bitmapc,r_ubitmapc,r_ubitbltc,r_upixelc));//we need to do it here because some things get drawn after end_frame
1487         }
1488         ogl_do_palfx();
1489         ogl_swap_buffers_internal();
1490         glClear(GL_COLOR_BUFFER_BIT);
1491 }
1492
1493 void ogl_init_shared_palette(void)
1494 {
1495 #ifdef GL_EXT_paletted_texture
1496         if (ogl_shared_palette_ok)
1497         {
1498                 int i;
1499
1500                 glEnable(GL_SHARED_TEXTURE_PALETTE_EXT);
1501                 //glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, ogl_pal);
1502
1503                 for (i = 0; i < 256; i++)
1504                 {
1505                         if (i == 254)
1506                         {
1507                                 texbuf[i * 4] = 255;
1508                                 texbuf[i * 4 + 1] = 255;
1509                                 texbuf[i * 4 + 2] = 255;
1510                                 texbuf[i * 4 + 3] = 0;
1511                         }
1512                         else if (i == 255)
1513                         {
1514                                 texbuf[i * 4] = 0;
1515                                 texbuf[i * 4 + 1] = 0;
1516                                 texbuf[i * 4 + 2] = 0;
1517                                 texbuf[i * 4 + 3] = 0;
1518                         }
1519                         else
1520                         {
1521                                 texbuf[i * 4] = gr_current_pal[i * 3] * 4;
1522                                 texbuf[i * 4 + 1] = gr_current_pal[i * 3 + 1] * 4;
1523                                 texbuf[i * 4 + 2] = gr_current_pal[i * 3 + 2] * 4;
1524                                 texbuf[i * 4 + 3] = 255;
1525                         }
1526                 }
1527                 glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, texbuf);
1528         }
1529 #endif
1530 }
1531
1532 int tex_format_supported(int iformat,int format){
1533         switch (iformat){
1534                 case GL_INTENSITY4:
1535                         return ogl_intensity4_ok;
1536                 case GL_LUMINANCE4_ALPHA4:
1537                         return ogl_luminance4_alpha4_ok;
1538                 case GL_RGBA2:
1539                         return ogl_rgba2_ok;
1540         }
1541         if (ogl_gettexlevelparam_ok){
1542                 GLint internalFormat;
1543                 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, iformat, 64, 64, 0,
1544                                 format, GL_UNSIGNED_BYTE, texbuf);//NULL?
1545                 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0,
1546                                 GL_TEXTURE_INTERNAL_FORMAT,
1547                                 &internalFormat);
1548                 return (internalFormat==iformat);
1549         }else
1550                 return 1;
1551 }
1552
1553 //little hack to find the largest or equal multiple of 2 for a given number
1554 int pow2ize(int x){
1555         int i;
1556
1557         for (i = 1; i <= 4096; i *= 2)
1558                 if (x<=i) return i;
1559         return i;
1560 }
1561
1562 //GLubyte texbuf[512*512*4];
1563 GLubyte texbuf[OGLTEXBUFSIZE];
1564
1565 void ogl_filltexbuf(unsigned char *data, GLubyte *texp, int truewidth, int width, int height, int dxo, int dyo, int twidth, int theight, int type, int bm_flags, int data_format)
1566 {
1567 //      GLushort *tex=(GLushort *)texp;
1568         int x,y,c,i;
1569         if (twidth*theight*4>sizeof(texbuf))//shouldn't happen, descent never uses textures that big.
1570                 Error("texture toobig %i %i",twidth,theight);
1571
1572         i=0;
1573         for (y=0;y<theight;y++){
1574                 i=dxo+truewidth*(y+dyo);
1575                 for (x=0;x<twidth;x++){
1576                         if (x<width && y<height)
1577                                 if (data_format)
1578                                 {
1579                                         int j;
1580
1581                                         for (j = 0; j < data_format; ++j)
1582                                                 (*(texp++)) = data[i * data_format + j];
1583                                         i++;
1584                                         continue;
1585                                 }
1586                                 else
1587                                         c = data[i++];
1588                         else
1589                                 c = 256; // fill the pad space with transparency (or blackness)
1590                         if (c == 254 && (bm_flags & BM_FLAG_SUPER_TRANSPARENT))
1591                         {
1592                                 switch (type)
1593                                 {
1594                                 case GL_LUMINANCE_ALPHA:
1595                                         (*(texp++)) = 255;
1596                                         (*(texp++)) = 0;
1597                                         break;
1598                                 case GL_RGBA:
1599                                         (*(texp++)) = 255;
1600                                         (*(texp++)) = 255;
1601                                         (*(texp++)) = 255;
1602                                         (*(texp++)) = 0; // transparent pixel
1603                                         break;
1604                                 case GL_COLOR_INDEX:
1605                                         (*(texp++)) = c;
1606                                         break;
1607                                 default:
1608                                         Error("ogl_filltexbuf unhandled super-transparent texformat\n");
1609                                         break;
1610                                 }
1611                         }
1612                         else if ((c == 255 && (bm_flags & BM_FLAG_TRANSPARENT)) || c == 256)
1613                         {
1614                                 switch (type){
1615                                         case GL_LUMINANCE:
1616                                                 (*(texp++))=0;
1617                                                 break;
1618                                         case GL_LUMINANCE_ALPHA:
1619                                                 (*(texp++))=0;
1620                                                 (*(texp++))=0;
1621                                                 break;
1622                                         case GL_RGB:
1623                                                 (*(texp++)) = 0;
1624                                                 (*(texp++)) = 0;
1625                                                 (*(texp++)) = 0;
1626                                                 break;
1627                                         case GL_RGBA:
1628                                                 (*(texp++))=0;
1629                                                 (*(texp++))=0;
1630                                                 (*(texp++))=0;
1631                                                 (*(texp++))=0;//transparent pixel
1632                                                 break;
1633                                         case GL_COLOR_INDEX:
1634                                                 (*(texp++)) = c;
1635                                                 break;
1636                                         default:
1637                                                 Error("ogl_filltexbuf unknown texformat\n");
1638                                                 break;
1639                                 }
1640                         }else{
1641                                 switch (type){
1642                                         case GL_LUMINANCE://these could prolly be done to make the intensity based upon the intensity of the resulting color, but its not needed for anything (yet?) so no point. :)
1643                                                 (*(texp++))=255;
1644                                                 break;
1645                                         case GL_LUMINANCE_ALPHA:
1646                                                 (*(texp++))=255;
1647                                                 (*(texp++))=255;
1648                                                 break;
1649                                         case GL_RGB:
1650                                                 (*(texp++)) = ogl_pal[c * 3] * 4;
1651                                                 (*(texp++)) = ogl_pal[c * 3 + 1] * 4;
1652                                                 (*(texp++)) = ogl_pal[c * 3 + 2] * 4;
1653                                                 break;
1654                                         case GL_RGBA:
1655                                                 //(*(texp++))=gr_palette[c*3]*4;
1656                                                 //(*(texp++))=gr_palette[c*3+1]*4;
1657                                                 //(*(texp++))=gr_palette[c*3+2]*4;
1658                                                 (*(texp++))=ogl_pal[c*3]*4;
1659                                                 (*(texp++))=ogl_pal[c*3+1]*4;
1660                                                 (*(texp++))=ogl_pal[c*3+2]*4;
1661                                                 (*(texp++))=255;//not transparent
1662                                                 //                              (*(tex++))=(ogl_pal[c*3]>>1) + ((ogl_pal[c*3+1]>>1)<<5) + ((ogl_pal[c*3+2]>>1)<<10) + (1<<15);
1663                                                 break;
1664                                         case GL_COLOR_INDEX:
1665                                                 (*(texp++)) = c;
1666                                                 break;
1667                                         default:
1668                                                 Error("ogl_filltexbuf unknown texformat\n");
1669                                                 break;
1670                                 }
1671                         }
1672                 }
1673         }
1674 }
1675
1676 int tex_format_verify(ogl_texture *tex){
1677         while (!tex_format_supported(tex->internalformat,tex->format)){
1678                 glmprintf((0,"tex format %x not supported",tex->internalformat));
1679                 switch (tex->internalformat){
1680                         case GL_INTENSITY4:
1681                                 if (ogl_luminance4_alpha4_ok){
1682                                         tex->internalformat=GL_LUMINANCE4_ALPHA4;
1683                                         tex->format=GL_LUMINANCE_ALPHA;
1684                                         break;
1685                                 }//note how it will fall through here if the statement is false
1686                         case GL_LUMINANCE4_ALPHA4:
1687                                 if (ogl_rgba2_ok){
1688                                         tex->internalformat=GL_RGBA2;
1689                                         tex->format=GL_RGBA;
1690                                         break;
1691                                 }//note how it will fall through here if the statement is false
1692                         case GL_RGBA2:
1693 #if defined(__APPLE__) && defined(__MACH__)
1694                         case GL_RGB8:   // Quartz doesn't support RGB only
1695 #endif
1696                                 tex->internalformat = ogl_rgba_internalformat;
1697                                 tex->format=GL_RGBA;
1698                                 break;
1699                         default:
1700                                 mprintf((0,"...no tex format to fall back on\n"));
1701                                 return 1;
1702                 }
1703                 glmprintf((0,"...falling back to %x\n",tex->internalformat));
1704         }
1705         return 0;
1706 }
1707 void tex_set_size1(ogl_texture *tex,int dbits,int bits,int w, int h){
1708         int u;
1709         if (tex->tw!=w || tex->th!=h){
1710                 u=(tex->w/(float)tex->tw*w) * (tex->h/(float)tex->th*h);
1711                 glmprintf((0,"shrunken texture?\n"));
1712         }else
1713                 u=tex->w*tex->h;
1714         if (bits<=0){//the beta nvidia GLX server. doesn't ever return any bit sizes, so just use some assumptions.
1715                 tex->bytes=((float)w*h*dbits)/8.0;
1716                 tex->bytesu=((float)u*dbits)/8.0;
1717         }else{
1718                 tex->bytes=((float)w*h*bits)/8.0;
1719                 tex->bytesu=((float)u*bits)/8.0;
1720         }
1721         glmprintf((0,"tex_set_size1: %ix%i, %ib(%i) %iB\n",w,h,bits,dbits,tex->bytes));
1722 }
1723 void tex_set_size(ogl_texture *tex){
1724         GLint w,h;
1725         int bi=16,a=0;
1726         if (ogl_gettexlevelparam_ok){
1727                 GLint t;
1728                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&w);
1729                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&h);
1730                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_LUMINANCE_SIZE,&t);a+=t;
1731                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_INTENSITY_SIZE,&t);a+=t;
1732                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_RED_SIZE,&t);a+=t;
1733                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_GREEN_SIZE,&t);a+=t;
1734                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_BLUE_SIZE,&t);a+=t;
1735                 glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_ALPHA_SIZE,&t);a+=t;
1736 #ifdef GL_EXT_paletted_texture
1737                 if (ogl_paletted_texture_ok)
1738                 {
1739                         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INDEX_SIZE_EXT, &t);
1740                         a += t;
1741                 }
1742 #endif
1743         }else{
1744                 w=tex->tw;
1745                 h=tex->th;
1746         }
1747         switch (tex->format){
1748                 case GL_LUMINANCE:
1749                         bi=8;
1750                         break;
1751                 case GL_LUMINANCE_ALPHA:
1752                         bi=8;
1753                         break;
1754                 case GL_RGB:
1755                 case GL_RGBA:
1756                         bi=16;
1757                         break;
1758                 case GL_COLOR_INDEX:
1759                         bi = 8;
1760                         break;
1761                 default:
1762                         Error("tex_set_size unknown texformat\n");
1763                         break;
1764         }
1765         tex_set_size1(tex,bi,a,w,h);
1766 }
1767 //loads a palettized bitmap into a ogl RGBA texture.
1768 //Sizes and pads dimensions to multiples of 2 if necessary.
1769 //In theory this could be a problem for repeating textures, but all real
1770 //textures (not sprites, etc) in descent are 64x64, so we are ok.
1771 //stores OpenGL textured id in *texid and u/v values required to get only the real data in *u/*v
1772 void ogl_loadtexture(unsigned char *data, int dxo, int dyo, ogl_texture *tex, int bm_flags, int data_format)
1773 {
1774 //void ogl_loadtexture(unsigned char * data, int width, int height,int dxo,int dyo, int *texid,float *u,float *v,char domipmap,float prio){
1775 //      int internalformat=GL_RGBA;
1776 //      int format=GL_RGBA;
1777         //int filltype=0;
1778         tex->tw=pow2ize(tex->w);tex->th=pow2ize(tex->h);//calculate smallest texture size that can accomodate us (must be multiples of 2)
1779 //      tex->tw=tex->w;tex->th=tex->h;//feeling lucky?
1780         
1781         if(gr_badtexture>0) return;
1782
1783         if (tex_format_verify(tex))
1784                 return;
1785
1786         //calculate u/v values that would make the resulting texture correctly sized
1787         tex->u=(float)tex->w/(float)tex->tw;
1788         tex->v=(float)tex->h/(float)tex->th;
1789
1790 #ifdef GL_EXT_paletted_texture
1791         if (ogl_shared_palette_ok && data_format == 0 && (tex->format == GL_RGBA || tex->format == GL_RGB) &&
1792                 !(tex->wantmip && GL_needmipmaps) // gluBuild2DMipmaps doesn't support paletted textures.. this could be worked around be generating our own mipmaps, but thats too much trouble at the moment.
1793                 )
1794         {
1795                 // descent makes palette entries 254 and 255 both do double duty, depending upon the setting of BM_FLAG_SUPER_TRANSPARENT and BM_FLAG_TRANSPARENT.
1796                 // So if the texture doesn't have BM_FLAG_TRANSPARENT set, yet uses index 255, we cannot use the palette for it since that color would be incorrect. (this case is much less common than transparent textures, hence why we don't exclude those instead.)
1797                 // We don't handle super transparent textures with ogl yet, so we don't bother checking that here.
1798                 int usesthetransparentindexcolor = 0, usesthesupertransparentindexcolor = 0;
1799
1800                 if (!(bm_flags & BM_FLAG_SUPER_TRANSPARENT))
1801                 {
1802                         int i;
1803
1804                         for (i = 0; i < tex->w * tex->h; ++i)
1805                                 if (data[i] == 254)
1806                                         usesthesupertransparentindexcolor += 1;
1807                 }
1808                 if (!(bm_flags & BM_FLAG_TRANSPARENT))
1809                 {
1810                         int i;
1811
1812                         for (i=0; i < tex->w * tex->h; ++i)
1813                                 if (data[i] == 255)
1814                                         usesthetransparentindexcolor += 1;
1815                 }
1816                 if (!usesthetransparentindexcolor && !usesthesupertransparentindexcolor)
1817                 {
1818                         tex->internalformat = GL_COLOR_INDEX8_EXT;
1819                         tex->format = GL_COLOR_INDEX;
1820                 }
1821                 //else
1822                 //      printf("bm data=%p w=%i h=%i transparent:%i supertrans:%i\n", data, tex->w, tex->h, usesthetransparentindexcolor, usesthesupertransparentindexcolor);
1823         }
1824 #endif
1825
1826         //      if (width!=twidth || height!=theight)
1827         //              glmprintf((0,"sizing %ix%i texture up to %ix%i\n",width,height,twidth,theight));
1828         ogl_filltexbuf(data, texbuf, tex->lw, tex->w, tex->h, dxo, dyo, tex->tw, tex->th, tex->format, bm_flags, data_format);
1829
1830         // Generate OpenGL texture IDs.
1831         glGenTextures(1, &tex->handle);
1832
1833         //set priority
1834         glPrioritizeTextures(1,&tex->handle,&tex->prio);
1835         
1836         // Give our data to OpenGL.
1837
1838         OGL_BINDTEXTURE(tex->handle);
1839
1840         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1841         if (tex->wantmip){
1842                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_texmagfilt);
1843                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_texminfilt);
1844                 if (ogl_ext_texture_filter_anisotropic_ok && GL_texanisofilt)
1845                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GL_texanisofilt);
1846         }
1847         else
1848         {
1849                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1850                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1851         }
1852 //      domipmap=0;//mipmaps aren't used in GL_NEAREST anyway, and making the mipmaps is pretty slow
1853         //however, if texturing mode becomes an ingame option, they would need to be made regardless, so it could switch to them later.  OTOH, texturing mode could just be made a command line arg.
1854
1855         if (tex->wantmip && GL_needmipmaps)
1856                 gluBuild2DMipmaps( GL_TEXTURE_2D, tex->internalformat, tex->tw,
1857                                 tex->th, tex->format, GL_UNSIGNED_BYTE, texbuf);
1858         else
1859                 glTexImage2D(GL_TEXTURE_2D, 0, tex->internalformat,
1860                         tex->tw, tex->th, 0, tex->format, // RGBA textures.
1861                         GL_UNSIGNED_BYTE, // imageData is a GLubyte pointer.
1862                         texbuf);
1863         
1864         tex_set_size(tex);
1865
1866         r_texcount++; 
1867         glmprintf((0,"ogl_loadtexture(%p,%i,%i,%ix%i,%p):%i u=%f v=%f b=%i bu=%i (%i)\n",data,tex->tw,tex->th,dxo,dyo,tex,tex->handle,tex->u,tex->v,tex->bytes,tex->bytesu,r_texcount));
1868
1869 }
1870
1871 unsigned char decodebuf[1024*1024];
1872
1873 void ogl_loadbmtexture_f(grs_bitmap *bm, int flags)
1874 {
1875         unsigned char *buf;
1876 #ifdef HAVE_LIBPNG
1877         char *bitmapname;
1878 #endif
1879
1880         while (bm->bm_parent)
1881                 bm=bm->bm_parent;
1882         if (bm->gltexture && bm->gltexture->handle > 0)
1883                 return;
1884         buf=bm->bm_data;
1885 #ifdef HAVE_LIBPNG
1886         if ((bitmapname = piggy_game_bitmap_name(bm)))
1887         {
1888                 char filename[64];
1889                 png_data pdata;
1890
1891                 sprintf(filename, "textures/%s.png", bitmapname);
1892                 if (read_png(filename, &pdata))
1893                 {
1894                         printf("%s: %ux%ux%i p=%i(%i) c=%i a=%i chans=%i\n", filename, pdata.width, pdata.height, pdata.depth, pdata.paletted, pdata.num_palette, pdata.color, pdata.alpha, pdata.channels);
1895                         if (pdata.depth == 8 && pdata.color)
1896                         {
1897                                 if (bm->gltexture == NULL)
1898                                         ogl_init_texture(bm->gltexture = ogl_get_free_texture(), pdata.width, pdata.height, flags | ((pdata.alpha || bm->bm_flags & BM_FLAG_TRANSPARENT) ? OGL_FLAG_ALPHA : 0));
1899                                 ogl_loadtexture(pdata.data, 0, 0, bm->gltexture, bm->bm_flags, pdata.paletted ? 0 : pdata.channels);
1900                                 free(pdata.data);
1901                                 if (pdata.palette)
1902                                         free(pdata.palette);
1903                                 return;
1904                         }
1905                         else
1906                         {
1907                                 printf("%s: unsupported texture format: must be rgb, rgba, or paletted, and depth 8\n", filename);
1908                                 free(pdata.data);
1909                                 if (pdata.palette)
1910                                         free(pdata.palette);
1911                         }
1912                 }
1913         }
1914 #endif
1915         if (bm->gltexture == NULL){
1916                 ogl_init_texture(bm->gltexture = ogl_get_free_texture(), bm->bm_w, bm->bm_h, flags | ((bm->bm_flags & (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT))? OGL_FLAG_ALPHA : 0));
1917         }
1918         else {
1919                 if (bm->gltexture->handle>0)
1920                         return;
1921                 if (bm->gltexture->w==0){
1922                         bm->gltexture->lw=bm->bm_w;
1923                         bm->gltexture->w=bm->bm_w;
1924                         bm->gltexture->h=bm->bm_h;
1925                 }
1926         }
1927         if (bm->bm_flags & BM_FLAG_RLE){
1928                 unsigned char * dbits;
1929                 unsigned char * sbits;
1930                 int i, data_offset;
1931
1932                 data_offset = 1;
1933                 if (bm->bm_flags & BM_FLAG_RLE_BIG)
1934                         data_offset = 2;
1935
1936                 sbits = &bm->bm_data[4 + (bm->bm_h * data_offset)];
1937                 dbits = decodebuf;
1938
1939                 for (i=0; i < bm->bm_h; i++ )    {
1940                         gr_rle_decode(sbits,dbits);
1941                         if ( bm->bm_flags & BM_FLAG_RLE_BIG )
1942                                 sbits += (int)INTEL_SHORT(*((short *)&(bm->bm_data[4+(i*data_offset)])));
1943                         else
1944                                 sbits += (int)bm->bm_data[4+i];
1945                         dbits += bm->bm_w;
1946                 }
1947                 buf=decodebuf;
1948         }
1949         ogl_loadtexture(buf, 0, 0, bm->gltexture, bm->bm_flags, 0);
1950 }
1951
1952 void ogl_loadbmtexture(grs_bitmap *bm)
1953 {
1954         ogl_loadbmtexture_f(bm, OGL_FLAG_MIPMAP);
1955 }
1956
1957 void ogl_freetexture(ogl_texture *gltexture)
1958 {
1959         if (gltexture->handle>0) {
1960                 r_texcount--;
1961                 glmprintf((0,"ogl_freetexture(%p):%i (last rend %is) (%i left)\n",gltexture,gltexture->handle,(GameTime-gltexture->lastrend)/f1_0,r_texcount));
1962                 glDeleteTextures( 1, &gltexture->handle );
1963 //              gltexture->handle=0;
1964                 ogl_reset_texture(gltexture);
1965         }
1966 }
1967 void ogl_freebmtexture(grs_bitmap *bm){
1968         if (bm->gltexture){
1969                 ogl_freetexture(bm->gltexture);
1970                 bm->gltexture=NULL;
1971 //              r_texcount--;
1972 //              glmprintf((0,"ogl_freebmtexture(%p,%p):%i (%i left)\n",bm->bm_data,&bm->gltexture,bm->gltexture,r_texcount));
1973 //              glDeleteTextures( 1, &bm->gltexture );
1974 //              bm->gltexture=-1;
1975         }
1976 }
1977
1978
1979 bool ogl_ubitmapm_cs(int x, int y, int dw, int dh, grs_bitmap *bm, int c, int scale, int orient)
1980 {
1981         GLfloat xo, yo, xf, yf;
1982         GLfloat u1, u2, v1, v2;
1983         GLdouble h, a;
1984
1985         r_ubitmapc++;
1986         x += grd_curcanv->cv_bitmap.bm_x;
1987         y += grd_curcanv->cv_bitmap.bm_y;
1988         xo = x / (float)last_width;
1989         xf = (bm->bm_w + x) / (float)last_width;
1990         yo = 1.0 - y / (float)last_height;
1991         yf = 1.0 - (bm->bm_h + y) / (float)last_height;
1992
1993         if (dw < 0)
1994                 dw = grd_curcanv->cv_bitmap.bm_w;
1995         else if (dw == 0)
1996                 dw = bm->bm_w;
1997         if (dh < 0)
1998                 dh = grd_curcanv->cv_bitmap.bm_h;
1999         else if (dh == 0)
2000                 dh = bm->bm_h;
2001         r_ubitmapc++;
2002
2003         if (orient & 1) {
2004                 int h = dw;
2005
2006                 dw = dh;
2007                 dh = h;
2008                 x += grd_curcanv->cv_bitmap.bm_y;
2009                 y += grd_curcanv->cv_bitmap.bm_x;
2010         } else {
2011                 x += grd_curcanv->cv_bitmap.bm_x;
2012                 y += grd_curcanv->cv_bitmap.bm_y;
2013         }
2014
2015         a = (double) grd_curscreen->sc_w / (double) grd_curscreen->sc_h;
2016         h = (double) scale / (double) F1_0;
2017
2018         xo = x / ((double) last_width * h);
2019         xf = (dw + x) / ((double) last_width * h);
2020         yo = 1.0 - y / ((double) last_height * h);
2021         yf = 1.0 - (dh + y) / ((double) last_height * h);
2022
2023         OGL_ENABLE(TEXTURE_2D);
2024         ogl_bindbmtex(bm);
2025         ogl_texwrap(bm->gltexture,GL_CLAMP);
2026
2027         if (bm->bm_x == 0) {
2028                 u1 = 0;
2029                 if (bm->bm_w == bm->gltexture->w)
2030                         u2 = bm->gltexture->u;
2031                 else
2032                         u2 = (bm->bm_w + bm->bm_x) / (float)bm->gltexture->tw;
2033         } else {
2034                 u1 = bm->bm_x / (float)bm->gltexture->tw;
2035                 u2 = (bm->bm_w + bm->bm_x) / (float)bm->gltexture->tw;
2036         }
2037
2038         if (bm->bm_y == 0) {
2039                 v1 = 0;
2040                 if (bm->bm_h == bm->gltexture->h)
2041                         v2 = bm->gltexture->v;
2042                 else
2043                         v2 = (bm->bm_h + bm->bm_y) / (float)bm->gltexture->th;
2044         } else {
2045                 v1 = bm->bm_y / (float)bm->gltexture->th;
2046                 v2 = (bm->bm_h + bm->bm_y) / (float)bm->gltexture->th;
2047         }
2048
2049         glBegin(GL_QUADS);
2050         if (c < 0)
2051                 glColor3f(1.0, 1.0, 1.0);
2052         else
2053                 glColor3f(CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c));
2054         glTexCoord2f(u1, v1); glVertex2f(xo, yo);
2055         glTexCoord2f(u2, v1); glVertex2f(xf, yo);
2056         glTexCoord2f(u2, v2); glVertex2f(xf, yf);
2057         glTexCoord2f(u1, v2); glVertex2f(xo, yf);
2058 #ifndef _WIN32 // ZICO - hack
2059         glActiveTexture(GL_TEXTURE0_ARB);
2060 #endif
2061         glEnd();
2062
2063         return 0;
2064 }