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