1 /* $Id: ogl.c,v 1.27 2004-05-22 08:47:14 btb Exp $ */
4 * Graphics support functions for OpenGL.
19 #if defined(__APPLE__) && defined(__MACH__)
20 #include <OpenGL/gl.h>
21 #include <OpenGL/glu.h>
31 #include "../../3d/globvars.h"
50 //change to 1 for lots of spew.
52 #define glmprintf(a) mprintf(a)
61 #if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) || defined(__sun__)
62 #define cosf(a) cos(a)
63 #define sinf(a) sin(a)
66 unsigned char *ogl_pal=gr_palette;
68 int GL_texmagfilt=GL_NEAREST;
69 int GL_texminfilt=GL_NEAREST;
70 float GL_texanisofilt = 0;
73 int last_width=-1,last_height=-1;
74 int GL_TEXTURE_2D_enabled=-1;
75 int GL_texclamp_enabled=-1;
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;
84 int ogl_readpixels_ok=1;
85 int ogl_gettexlevelparam_ok=1;
86 #ifdef GL_ARB_multitexture
87 int ogl_arb_multitexture_ok=0;
89 #ifdef GL_SGIS_multitexture
90 int ogl_sgis_multitexture_ok=0;
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;
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};
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);
111 ogl_texture ogl_texture_list[OGL_TEXTURE_LIST_SIZE];
112 int ogl_texture_list_cur;
114 /* some function prototypes */
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);
127 void ogl_init_texture_stats(ogl_texture* t){
128 t->prio=0.3;//default prio
132 void ogl_init_texture(ogl_texture* t){
134 t->internalformat=ogl_rgba_format;
136 t->wrapstate[0] = -1;
137 t->wrapstate[1] = -1;
139 ogl_init_texture_stats(t);
141 void ogl_reset_texture_stats_internal(void){
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]);
148 void ogl_init_texture_list_internal(void){
150 ogl_texture_list_cur=0;
151 for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++)
152 ogl_init_texture(&ogl_texture_list[i]);
154 void ogl_smash_texture_list_internal(void){
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;
165 ogl_texture_list[i].wrapstate[0] = -1;
166 ogl_texture_list[i].wrapstate[1] = -1;
169 void ogl_vivify_texture_list_internal(void){
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);
181 ogl_texture* ogl_get_free_texture(void){
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;
189 Error("OGL: texture list full!\n");
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;
197 for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++){
198 t=&ogl_texture_list[i];
201 datatexel+=t->w*t->h;
202 truetexel+=t->tw*t->th;
203 databytes+=t->bytesu;
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++;
216 int idx, r, g, b, a, dbl, depth, res, colorsize, depthsize;
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);
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);
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));
236 int ogl_mem_target=-1;
237 void ogl_clean_texture_cache(void){
242 if (ogl_mem_target<0){
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];
253 if (t->lastrend+f1_0*time<GameTime){
256 if (bytes<ogl_mem_target)
262 Error("not enough mem?");
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);
280 //gltexture MUST be bound first
281 void ogl_texwrap(ogl_texture *gltexture,int state)
283 if (gltexture->wrapstate[active_texture_unit] != state || gltexture->numrend < 1)
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;
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
297 void ogl_cache_polymodel_textures(int model_num)
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]);
310 void ogl_cache_vclip_textures(vclip *vc){
312 for (i=0;i<vc->num_frames;i++){
313 PIGGY_PAGE_IN(vc->frames[i]);
314 ogl_loadbmtexture(&GameBitmaps[vc->frames[i].index]);
318 void ogl_cache_vclipn_textures(int i)
320 if (i >= 0 && i < VCLIP_MAXNUM)
321 ogl_cache_vclip_textures(&Vclip[i]);
324 void ogl_cache_weapon_textures(int weapon_type)
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)
338 ogl_cache_polymodel_textures(w->model_num);
339 ogl_cache_polymodel_textures(w->model_num_inner);
343 void ogl_cache_level_textures(void)
352 ogl_reset_texture_stats_internal();//loading a new lev should reset textures
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) )
358 if (ec->vc.num_frames>max_efx)
359 max_efx=ec->vc.num_frames;
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) )
366 // if (ec->vc.num_frames>max_efx)
367 // max_efx=ec->vc.num_frames;
370 do_special_effects();
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));
382 PIGGY_PAGE_IN(Textures[tmap1]);
383 bm = &GameBitmaps[Textures[tmap1].index];
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 );
390 ogl_loadbmtexture(bm2);
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));
394 ogl_loadbmtexture(bm);
397 glmprintf((0,"finished ef:%i\n",ef));
399 reset_special_effects();
400 init_special_effects();
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);
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){
418 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[LASER_INDEX]);
422 case POW_VULCAN_WEAPON:
423 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[VULCAN_INDEX]);
425 case POW_SPREADFIRE_WEAPON:
426 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[SPREADFIRE_INDEX]);
428 case POW_PLASMA_WEAPON:
429 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[PLASMA_INDEX]);
431 case POW_FUSION_WEAPON:
432 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[FUSION_INDEX]);
434 /* case POW_MISSILE_1:
436 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[CONCUSSION_INDEX]);
438 case POW_PROXIMITY_WEAPON:
439 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[PROXIMITY_INDEX]);
441 case POW_HOMING_AMMO_1:
442 case POW_HOMING_AMMO_4:
443 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[HOMING_INDEX]);
445 case POW_SMARTBOMB_WEAPON:
446 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[SMART_INDEX]);
448 case POW_MEGA_WEAPON:
449 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[MEGA_INDEX]);
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);
462 glmprintf((0,"finished caching\n"));
463 r_cachedtexcount = r_texcount;
466 int r_polyc,r_tpolyc,r_bitmapc,r_ubitmapc,r_ubitbltc,r_upixelc;
467 #define f2glf(x) (f2fl(x))
469 bool g3_draw_line(g3s_point *p0,g3s_point *p1)
472 c=grd_curcanv->cv_color;
473 OGL_DISABLE(TEXTURE_2D);
474 glColor3f(PAL2Tr(c),PAL2Tg(c),PAL2Tb(c));
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));
481 void ogl_drawcircle2(int nsides,int type,float xsc,float xo,float ysc,float yo){
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);
491 void ogl_drawcircle(int nsides,int type){
495 for (i=0; i<nsides; i++) {
496 ang = 2.0*M_PI*i/nsides;
497 glVertex2f(cosf(ang),sinf(ang));
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);
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;
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.
519 OGL_DISABLE(TEXTURE_2D);
521 if (!cross_lh[cross]){
522 cross_lh[cross]=glGenLists(1);
523 glNewList(cross_lh[cross], GL_COMPILE_AND_EXECUTE);
526 glColor3fv(darker_g);
527 glVertex2f(-4.0,4.0);
529 glColor3fv(bright_g);
532 glVertex2f(-2.0,2.0);
536 glVertex2f(-3.0,-2.0);
538 glColor3fv(bright_g);
539 glVertex2f(-2.0,-1.0);
542 glColor3fv(darker_g);
545 glColor3fv(bright_g);
552 glVertex2f(3.0,-2.0);
554 glColor3fv(bright_g);
555 glVertex2f(2.0,-1.0);
560 glCallList(cross_lh[cross]);
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);
571 glVertex2f(-14.0,-8.0);
572 glVertex2f(-8.0,-5.0);
574 glVertex2f(14.0,-8.0);
575 glVertex2f(8.0,-5.0);
580 glColor3fv(bright_g);
582 ogl_drawcircle2(6,GL_POLYGON,1.5,-7.0,1.5,-5.0);
584 ogl_drawcircle2(6,GL_POLYGON,1.5,7.0,1.5,-5.0);
588 glColor3fv(bright_g);
590 ogl_drawcircle2(4,GL_POLYGON,1.0,-14.0,1.0,-8.0);
592 ogl_drawcircle2(4,GL_POLYGON,1.0,14.0,1.0,-8.0);
596 glCallList(primary_lh[primary]);
597 // if (Canvas_height>200)
600 if (!secondary_lh[secondary]){
601 secondary_lh[secondary]=glGenLists(1);
602 glNewList(secondary_lh[secondary], GL_COMPILE_AND_EXECUTE);
606 glColor3fv(darker_g);
608 glColor3fv(bright_g);
609 ogl_drawcircle2(8,GL_LINE_LOOP,2.0,-10.0,2.0,-1.0);
612 glColor3fv(darker_g);
614 glColor3fv(bright_g);
615 ogl_drawcircle2(8,GL_LINE_LOOP,2.0,10.0,2.0,-1.0);
617 //bottom/middle secondary
619 glColor3fv(darker_g);
621 glColor3fv(bright_g);
622 ogl_drawcircle2(8,GL_LINE_LOOP,2.0,0.0,2.0,-7.0);
626 glCallList(secondary_lh[secondary]);
630 int g3_draw_sphere(g3s_point *pnt,fix rad){
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));
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);
648 int gr_ucircle(fix xc1, fix yc1, fix r1)
651 c=grd_curcanv->cv_color;
652 OGL_DISABLE(TEXTURE_2D);
653 glColor3f(CPAL2Tr(c),CPAL2Tg(c),CPAL2Tb(c));
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);
663 int gr_circle(fix xc1,fix yc1,fix r1){
664 return gr_ucircle(xc1,yc1,r1);
667 bool g3_draw_poly(int nv,g3s_point **pointlist)
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));
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);
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));
687 void gr_upoly_tmap(int nverts, int *vert ){
688 mprintf((0,"gr_upoly_tmap: unhandled\n"));//should never get called
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
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)
698 if (tmap_drawer_ptr==draw_tmap_flat){
699 /* fix average_light=0;
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);
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));
714 }else if (tmap_drawer_ptr==draw_tmap){
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);
720 ogl_texwrap(bm->gltexture,GL_REPEAT);
721 glBegin(GL_TRIANGLE_FAN);
723 if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
726 //l=f2fl(uvl_list[c].l)+gr_palette_gamma/63.0;
727 l=f2fl(uvl_list[c].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));
736 mprintf((0,"g3_draw_tmap: unhandled tmap_drawer %p\n",tmap_drawer_ptr));
741 int active_texture_unit = 0;
743 void ogl_setActiveTexture(int t)
745 if (ogl_arb_multitexture_ok)
747 #ifdef GL_ARB_multitexture
749 glActiveTextureARB(GL_TEXTURE0_ARB);
751 glActiveTextureARB(GL_TEXTURE1_ARB);
754 else if (ogl_sgis_multitexture_ok)
756 #ifdef GL_SGIS_multitexture
758 glSelectTextureSGIS(GL_TEXTURE0_SGIS);
760 glSelectTextureSGIS(GL_TEXTURE1_SGIS);
763 active_texture_unit = t;
766 void ogl_MultiTexCoord2f(int t, float u, float v)
768 if (ogl_arb_multitexture_ok)
770 #ifdef GL_ARB_multitexture
772 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
774 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
777 else if (ogl_sgis_multitexture_ok)
779 #ifdef GL_SGIS_multitexture
781 glMultiTexCoord2fSGIS(GL_TEXTURE0_SGIS, u, v);
783 glMultiTexCoord2fSGIS(GL_TEXTURE1_SGIS, u, v);
788 bool g3_draw_tmap_2(int nv, g3s_point **pointlist, g3s_uvl *uvl_list, grs_bitmap *bmbot, grs_bitmap *bm, int orient)
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))
796 if (tmap_drawer_ptr != draw_tmap)
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
807 ogl_setActiveTexture(1);
808 glEnable(GL_TEXTURE_2D);
810 ogl_texwrap(bm->gltexture,GL_REPEAT);
812 // GL_DECAL works sorta ok but the top texture is fullbright.
813 //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
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);
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);
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);
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);
832 // add up alpha channels
833 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
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);
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);
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);
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);
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);
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);
867 glBegin(GL_TRIANGLE_FAN);
871 u1=1.0-f2glf(uvl_list[c].v);
872 v1=f2glf(uvl_list[c].u);
875 u1=1.0-f2glf(uvl_list[c].u);
876 v1=1.0-f2glf(uvl_list[c].v);
879 u1=f2glf(uvl_list[c].v);
880 v1=1.0-f2glf(uvl_list[c].u);
883 u1=f2glf(uvl_list[c].u);
884 v1=f2glf(uvl_list[c].v);
887 if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
890 l=f2fl(uvl_list[c].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));
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);
911 g3_draw_tmap(nv,pointlist,uvl_list,bmbot);//draw the bottom texture first.. could be optimized with multitexturing..
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);
918 ogl_texwrap(bm->gltexture,GL_REPEAT);
919 glBegin(GL_TRIANGLE_FAN);
923 u1=1.0-f2glf(uvl_list[c].v);
924 v1=f2glf(uvl_list[c].u);
927 u1=1.0-f2glf(uvl_list[c].u);
928 v1=1.0-f2glf(uvl_list[c].v);
931 u1=f2glf(uvl_list[c].v);
932 v1=1.0-f2glf(uvl_list[c].u);
935 u1=f2glf(uvl_list[c].u);
936 v1=f2glf(uvl_list[c].v);
939 if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
942 //l=f2fl(uvl_list[c].l)+gr_palette_gamma/63.0;
943 l=f2fl(uvl_list[c].l);
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));
956 bool g3_draw_bitmap(vms_vector *pos,fix width,fix height,grs_bitmap *bm, int orientation)
959 vms_vector pv,v1;//,v2;
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));
966 OGL_ENABLE(TEXTURE_2D);
968 ogl_texwrap(bm->gltexture,GL_CLAMP);
971 glColor3f(1.0,1.0,1.0);
972 width = fixmul(width,Matrix_scale.x);
973 height = fixmul(height,Matrix_scale.y);
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));
981 glTexCoord2f(0.0, 0.0);
986 glTexCoord2f(bm->gltexture->u, 0.0);
991 glTexCoord2f(bm->gltexture->u, bm->gltexture->v);
996 glTexCoord2f(0.0, bm->gltexture->v);
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));
1014 bool ogl_ubitmapm_c(int x, int y,grs_bitmap *bm,int c)
1016 GLfloat xo,yo,xf,yf;
1017 GLfloat u1,u2,v1,v2;
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;
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));
1029 /* glEnABLE(ALPHA_TEST);
1030 glAlphaFunc(GL_GREATER,0.0);*/
1032 OGL_ENABLE(TEXTURE_2D);
1034 ogl_texwrap(bm->gltexture,GL_CLAMP);
1038 if (bm->bm_w==bm->gltexture->w)
1039 u2=bm->gltexture->u;
1041 u2=(bm->bm_w+bm->bm_x)/(float)bm->gltexture->tw;
1043 u1=bm->bm_x/(float)bm->gltexture->tw;
1044 u2=(bm->bm_w+bm->bm_x)/(float)bm->gltexture->tw;
1048 if (bm->bm_h==bm->gltexture->h)
1049 v2=bm->gltexture->v;
1051 v2=(bm->bm_h+bm->bm_y)/(float)bm->gltexture->th;
1053 v1=bm->bm_y/(float)bm->gltexture->th;
1054 v2=(bm->bm_h+bm->bm_y)/(float)bm->gltexture->th;
1059 glColor3f(1.0,1.0,1.0);
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);
1067 // glDisABLE(ALPHA_TEST);
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);
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)
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));
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;
1092 // OGL_ENABLE(TEXTURE_2D);
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);
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)
1105 GLfloat xo,yo,xs,ys;
1106 GLfloat u1,v1;//,u2,v2;
1108 // unsigned char *oldpal;
1111 ogl_init_texture(&tex);
1113 tex.prio=0.0;tex.wantmip=0;
1114 tex.lw=src->bm_rowsize;
1116 /* if (w==src->bm_w && sx==0){
1119 u1=sx/(float)src->bm_w*src->glu;
1120 u2=w/(float)src->bm_w*src->glu+u1;
1122 if (h==src->bm_h && sy==0){
1125 v1=sy/(float)src->bm_h*src->glv;
1126 v2=h/(float)src->bm_h*src->glv+v1;
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;
1137 OGL_ENABLE(TEXTURE_2D);
1140 ogl_pal=gr_current_pal;
1141 ogl_loadtexture(src->bm_data, sx, sy, &tex, src->bm_flags);
1144 OGL_BINDTEXTURE(tex.handle);
1146 ogl_texwrap(&tex,GL_CLAMP);
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);
1155 ogl_freetexture(&tex);
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);
1162 bool ogl_ubitblt_tolinear(int w,int h,int dx,int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest){
1164 unsigned char *d,*s;
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");
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);
1179 memset(texbuf,0,w1*h1*3);
1183 d=dest->bm_data+dx+(dy+i)*dest->bm_rowsize;
1184 s=texbuf+((h1-(i+sy+1))*w1+sx)*3;
1186 *d=gr_find_closest_color(s[0]/4,s[1]/4,s[2]/4);
1193 unsigned char *d,*s,*e;
1194 if (w*h*3>OGLTEXBUFSIZE)
1195 Error("ogl_ubitblt_tolinear: size larger than OGLTEXBUFSIZE\n");
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);
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;
1210 s=texbuf+w*(h-(i+1))*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);
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);
1226 d+=dest->bm_rowsize;
1228 glmprintf((0,"c=%i w*h=%i\n",c,w*h));
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;
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;
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);
1256 grs_canvas *offscreen_save_canv = NULL, *offscreen_canv = NULL;
1258 void ogl_start_offscreen_render(int x, int y, int w, int h)
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);
1267 void ogl_end_offscreen_render(void)
1271 if (!offscreen_canv)
1272 Error("ogl_end_offscreen_render: no offscreen_canv");
1274 glDrawBuffer(GL_FRONT);
1275 glReadBuffer(GL_BACK);
1276 OGL_DISABLE(TEXTURE_2D);
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);
1284 gr_free_sub_canvas(offscreen_canv);
1285 gr_set_current_canvas(offscreen_save_canv);
1286 offscreen_canv=NULL;
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;
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
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);
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);
1324 void merge_textures_stats(void);
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);
1330 // merge_textures_stats();
1331 // ogl_texture_stats();
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);
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
1352 ogl_swap_buffers_internal();
1353 glClear(GL_COLOR_BUFFER_BIT);
1356 void ogl_init_shared_palette(void)
1358 #ifdef GL_EXT_paletted_texture
1359 if (ogl_shared_palette_ok)
1363 glEnable(GL_SHARED_TEXTURE_PALETTE_EXT);
1364 //glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, ogl_pal);
1366 for (i = 0; i < 256; i++)
1371 texbuf[i * 4 + 1] = 0;
1372 texbuf[i * 4 + 2] = 0;
1373 texbuf[i * 4 + 3] = 0;
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;
1383 glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, texbuf);
1388 int tex_format_supported(int iformat,int format){
1391 if (!ogl_intensity4_ok) return 0; break;
1392 case GL_LUMINANCE4_ALPHA4:
1393 if (!ogl_luminance4_alpha4_ok) return 0; break;
1395 if (!ogl_rgba2_ok) return 0; break;
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,
1404 return (internalFormat==iformat);
1409 //little hack to find the largest or equal multiple of 2 for a given number
1412 for (i=2;i<=4096;i*=2)
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)
1421 // GLushort *tex=(GLushort *)texp;
1423 if (twidth*theight*4>sizeof(texbuf))//shouldn't happen, descent never uses textures that big.
1424 Error("texture toobig %i %i",twidth,theight);
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)
1433 c=255;//fill the pad space with transparancy
1439 case GL_LUMINANCE_ALPHA:
1447 (*(texp++))=0;//transparent pixel
1449 case GL_COLOR_INDEX:
1453 Error("ogl_filltexbuf unknown texformat\n");
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. :)
1462 case GL_LUMINANCE_ALPHA:
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);
1476 case GL_COLOR_INDEX:
1480 Error("ogl_filltexbuf unknown texformat\n");
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){
1492 if (ogl_luminance4_alpha4_ok){
1493 tex->internalformat=GL_LUMINANCE4_ALPHA4;
1494 tex->format=GL_LUMINANCE_ALPHA;
1496 }//note how it will fall through here if the statement is false
1497 case GL_LUMINANCE4_ALPHA4:
1499 tex->internalformat=GL_RGBA2;
1500 tex->format=GL_RGBA;
1502 }//note how it will fall through here if the statement is false
1504 tex->internalformat=ogl_rgba_format;
1505 tex->format=GL_RGBA;
1508 mprintf((0,"...no tex format to fall back on\n"));
1511 glmprintf((0,"...falling back to %x\n",tex->internalformat));
1515 void tex_set_size1(ogl_texture *tex,int dbits,int bits,int w, int h){
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"));
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;
1526 tex->bytes=((float)w*h*bits)/8.0;
1527 tex->bytesu=((float)u*bits)/8.0;
1529 glmprintf((0,"tex_set_size1: %ix%i, %ib(%i) %iB\n",w,h,bits,dbits,tex->bytes));
1531 void tex_set_size(ogl_texture *tex){
1534 if (ogl_gettexlevelparam_ok){
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)
1547 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INDEX_SIZE_EXT, &t);
1555 switch (tex->format){
1559 case GL_LUMINANCE_ALPHA:
1565 case GL_COLOR_INDEX:
1569 Error("tex_set_size unknown texformat\n");
1572 tex_set_size1(tex,bi,a,w,h);
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)
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;
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?
1588 if(gr_badtexture>0) return;
1590 #if !(defined(__APPLE__) && defined(__MACH__))
1591 // always fails on OS X, but textures work fine!
1592 if (tex_format_verify(tex))
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;
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.
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))
1613 for (i=0; i < tex->w * tex->h; ++i)
1615 usesthetransparentindexcolor += 1;
1617 if (!usesthetransparentindexcolor)
1619 tex->internalformat = GL_COLOR_INDEX8_EXT;
1620 tex->format = GL_COLOR_INDEX;
1623 // printf("bm data=%p w=%i h=%i used the transparent color %i times\n",data, tex->w, tex->h, usesthetransparentindexcolor);
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);
1631 // Generate OpenGL texture IDs.
1632 glGenTextures(1, &tex->handle);
1635 glPrioritizeTextures(1,&tex->handle,&tex->prio);
1637 // Give our data to OpenGL.
1639 OGL_BINDTEXTURE(tex->handle);
1641 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
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);
1650 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1651 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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.
1656 if (tex->wantmip && GL_needmipmaps)
1657 gluBuild2DMipmaps( GL_TEXTURE_2D, tex->internalformat, tex->tw,
1658 tex->th, tex->format, GL_UNSIGNED_BYTE, texbuf);
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.
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));
1672 unsigned char decodebuf[512*512];
1674 void ogl_loadbmtexture_m(grs_bitmap *bm,int domipmap)
1677 while (bm->bm_parent)
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;
1688 if (bm->gltexture->handle>0)
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;
1696 if (bm->bm_flags & BM_FLAG_RLE){
1697 unsigned char * dbits;
1698 unsigned char * sbits;
1702 if (bm->bm_flags & BM_FLAG_RLE_BIG)
1705 sbits = &bm->bm_data[4 + (bm->bm_h * data_offset)];
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)])));
1713 sbits += (int)bm->bm_data[4+i];
1718 ogl_loadtexture(buf, 0, 0, bm->gltexture, bm->bm_flags);
1721 void ogl_loadbmtexture(grs_bitmap *bm)
1723 ogl_loadbmtexture_m(bm,1);
1726 void ogl_freetexture(ogl_texture *gltexture)
1728 if (gltexture->handle>0) {
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);
1736 void ogl_freebmtexture(grs_bitmap *bm){
1738 ogl_freetexture(bm->gltexture);
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;