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