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