1 /* $Id: ogl.c,v 1.28 2004-05-22 09:15:26 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_internalformat = GL_RGBA8;
81 int ogl_rgb_internalformat = GL_RGB8;
82 int ogl_intensity4_ok=1;
83 int ogl_luminance4_alpha4_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;
90 #ifdef GL_SGIS_multitexture
91 int ogl_sgis_multitexture_ok=0;
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;
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};
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);
112 ogl_texture ogl_texture_list[OGL_TEXTURE_LIST_SIZE];
113 int ogl_texture_list_cur;
115 /* some function prototypes */
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);
128 void ogl_init_texture_stats(ogl_texture* t){
129 t->prio=0.3;//default prio
133 void ogl_init_texture(ogl_texture* t, int w, int h, int flags)
136 if (flags & OGL_FLAG_NOCOLOR)
138 // use GL_INTENSITY instead of GL_RGB
139 if (flags & OGL_FLAG_ALPHA)
141 if (ogl_intensity4_ok)
143 t->internalformat = GL_INTENSITY4;
144 t->format = GL_LUMINANCE;
146 else if (ogl_luminance4_alpha4_ok)
148 t->internalformat = GL_LUMINANCE4_ALPHA4;
149 t->format = GL_LUMINANCE_ALPHA;
151 else if (ogl_rgba2_ok)
153 t->internalformat = GL_RGBA2;
158 t->internalformat = ogl_rgba_internalformat;
164 // there are certainly smaller formats we could use here, but nothing needs it ATM.
165 t->internalformat = ogl_rgb_internalformat;
171 if (flags & OGL_FLAG_ALPHA)
173 t->internalformat = ogl_rgba_internalformat;
178 t->internalformat = ogl_rgb_internalformat;
182 t->wrapstate[0] = -1;
183 t->wrapstate[1] = -1;
186 ogl_init_texture_stats(t);
189 void ogl_reset_texture(ogl_texture* t)
191 ogl_init_texture(t, 0, 0, 0);
194 void ogl_reset_texture_stats_internal(void){
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]);
201 void ogl_init_texture_list_internal(void){
203 ogl_texture_list_cur=0;
204 for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++)
205 ogl_reset_texture(&ogl_texture_list[i]);
207 void ogl_smash_texture_list_internal(void){
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;
218 ogl_texture_list[i].wrapstate[0] = -1;
219 ogl_texture_list[i].wrapstate[1] = -1;
222 void ogl_vivify_texture_list_internal(void){
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);
234 ogl_texture* ogl_get_free_texture(void){
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;
242 Error("OGL: texture list full!\n");
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;
251 for (i=0;i<OGL_TEXTURE_LIST_SIZE;i++){
252 t=&ogl_texture_list[i];
255 datatexel+=t->w*t->h;
256 truetexel+=t->tw*t->th;
257 databytes+=t->bytesu;
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++;
264 if (t->format == GL_RGBA)
266 else if (t->format == GL_RGB)
268 else if (t->format == GL_COLOR_INDEX)
278 int idx, r, g, b, a, dbl, depth, res, colorsize, depthsize;
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);
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);
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));
298 int ogl_mem_target=-1;
299 void ogl_clean_texture_cache(void){
304 if (ogl_mem_target<0){
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];
315 if (t->lastrend+f1_0*time<GameTime){
318 if (bytes<ogl_mem_target)
324 Error("not enough mem?");
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);
342 //gltexture MUST be bound first
343 void ogl_texwrap(ogl_texture *gltexture,int state)
345 if (gltexture->wrapstate[active_texture_unit] != state || gltexture->numrend < 1)
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;
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
359 void ogl_cache_polymodel_textures(int model_num)
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]);
372 void ogl_cache_vclip_textures(vclip *vc){
374 for (i=0;i<vc->num_frames;i++){
375 PIGGY_PAGE_IN(vc->frames[i]);
376 ogl_loadbmtexture(&GameBitmaps[vc->frames[i].index]);
380 void ogl_cache_vclipn_textures(int i)
382 if (i >= 0 && i < VCLIP_MAXNUM)
383 ogl_cache_vclip_textures(&Vclip[i]);
386 void ogl_cache_weapon_textures(int weapon_type)
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)
400 ogl_cache_polymodel_textures(w->model_num);
401 ogl_cache_polymodel_textures(w->model_num_inner);
405 void ogl_cache_level_textures(void)
414 ogl_reset_texture_stats_internal();//loading a new lev should reset textures
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) )
420 if (ec->vc.num_frames>max_efx)
421 max_efx=ec->vc.num_frames;
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) )
428 // if (ec->vc.num_frames>max_efx)
429 // max_efx=ec->vc.num_frames;
432 do_special_effects();
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));
444 PIGGY_PAGE_IN(Textures[tmap1]);
445 bm = &GameBitmaps[Textures[tmap1].index];
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 );
452 ogl_loadbmtexture(bm2);
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));
456 ogl_loadbmtexture(bm);
459 glmprintf((0,"finished ef:%i\n",ef));
461 reset_special_effects();
462 init_special_effects();
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);
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){
480 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[LASER_INDEX]);
484 case POW_VULCAN_WEAPON:
485 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[VULCAN_INDEX]);
487 case POW_SPREADFIRE_WEAPON:
488 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[SPREADFIRE_INDEX]);
490 case POW_PLASMA_WEAPON:
491 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[PLASMA_INDEX]);
493 case POW_FUSION_WEAPON:
494 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[FUSION_INDEX]);
496 /* case POW_MISSILE_1:
498 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[CONCUSSION_INDEX]);
500 case POW_PROXIMITY_WEAPON:
501 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[PROXIMITY_INDEX]);
503 case POW_HOMING_AMMO_1:
504 case POW_HOMING_AMMO_4:
505 ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[HOMING_INDEX]);
507 case POW_SMARTBOMB_WEAPON:
508 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[SMART_INDEX]);
510 case POW_MEGA_WEAPON:
511 ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[MEGA_INDEX]);
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);
524 glmprintf((0,"finished caching\n"));
525 r_cachedtexcount = r_texcount;
528 int r_polyc,r_tpolyc,r_bitmapc,r_ubitmapc,r_ubitbltc,r_upixelc;
529 #define f2glf(x) (f2fl(x))
531 bool g3_draw_line(g3s_point *p0,g3s_point *p1)
534 c=grd_curcanv->cv_color;
535 OGL_DISABLE(TEXTURE_2D);
536 glColor3f(PAL2Tr(c),PAL2Tg(c),PAL2Tb(c));
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));
543 void ogl_drawcircle2(int nsides,int type,float xsc,float xo,float ysc,float yo){
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);
553 void ogl_drawcircle(int nsides,int type){
557 for (i=0; i<nsides; i++) {
558 ang = 2.0*M_PI*i/nsides;
559 glVertex2f(cosf(ang),sinf(ang));
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);
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;
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.
581 OGL_DISABLE(TEXTURE_2D);
583 if (!cross_lh[cross]){
584 cross_lh[cross]=glGenLists(1);
585 glNewList(cross_lh[cross], GL_COMPILE_AND_EXECUTE);
588 glColor3fv(darker_g);
589 glVertex2f(-4.0,4.0);
591 glColor3fv(bright_g);
594 glVertex2f(-2.0,2.0);
598 glVertex2f(-3.0,-2.0);
600 glColor3fv(bright_g);
601 glVertex2f(-2.0,-1.0);
604 glColor3fv(darker_g);
607 glColor3fv(bright_g);
614 glVertex2f(3.0,-2.0);
616 glColor3fv(bright_g);
617 glVertex2f(2.0,-1.0);
622 glCallList(cross_lh[cross]);
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);
633 glVertex2f(-14.0,-8.0);
634 glVertex2f(-8.0,-5.0);
636 glVertex2f(14.0,-8.0);
637 glVertex2f(8.0,-5.0);
642 glColor3fv(bright_g);
644 ogl_drawcircle2(6,GL_POLYGON,1.5,-7.0,1.5,-5.0);
646 ogl_drawcircle2(6,GL_POLYGON,1.5,7.0,1.5,-5.0);
650 glColor3fv(bright_g);
652 ogl_drawcircle2(4,GL_POLYGON,1.0,-14.0,1.0,-8.0);
654 ogl_drawcircle2(4,GL_POLYGON,1.0,14.0,1.0,-8.0);
658 glCallList(primary_lh[primary]);
659 // if (Canvas_height>200)
662 if (!secondary_lh[secondary]){
663 secondary_lh[secondary]=glGenLists(1);
664 glNewList(secondary_lh[secondary], GL_COMPILE_AND_EXECUTE);
668 glColor3fv(darker_g);
670 glColor3fv(bright_g);
671 ogl_drawcircle2(8,GL_LINE_LOOP,2.0,-10.0,2.0,-1.0);
674 glColor3fv(darker_g);
676 glColor3fv(bright_g);
677 ogl_drawcircle2(8,GL_LINE_LOOP,2.0,10.0,2.0,-1.0);
679 //bottom/middle secondary
681 glColor3fv(darker_g);
683 glColor3fv(bright_g);
684 ogl_drawcircle2(8,GL_LINE_LOOP,2.0,0.0,2.0,-7.0);
688 glCallList(secondary_lh[secondary]);
692 int g3_draw_sphere(g3s_point *pnt,fix rad){
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));
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);
710 int gr_ucircle(fix xc1, fix yc1, fix r1)
713 c=grd_curcanv->cv_color;
714 OGL_DISABLE(TEXTURE_2D);
715 glColor3f(CPAL2Tr(c),CPAL2Tg(c),CPAL2Tb(c));
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);
725 int gr_circle(fix xc1,fix yc1,fix r1){
726 return gr_ucircle(xc1,yc1,r1);
729 bool g3_draw_poly(int nv,g3s_point **pointlist)
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));
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);
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));
749 void gr_upoly_tmap(int nverts, int *vert ){
750 mprintf((0,"gr_upoly_tmap: unhandled\n"));//should never get called
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
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)
760 if (tmap_drawer_ptr==draw_tmap_flat){
761 /* fix average_light=0;
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);
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));
776 }else if (tmap_drawer_ptr==draw_tmap){
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);
782 ogl_texwrap(bm->gltexture,GL_REPEAT);
783 glBegin(GL_TRIANGLE_FAN);
785 if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
788 //l=f2fl(uvl_list[c].l)+gr_palette_gamma/63.0;
789 l=f2fl(uvl_list[c].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));
798 mprintf((0,"g3_draw_tmap: unhandled tmap_drawer %p\n",tmap_drawer_ptr));
803 int active_texture_unit = 0;
805 void ogl_setActiveTexture(int t)
807 if (ogl_arb_multitexture_ok)
809 #ifdef GL_ARB_multitexture
811 glActiveTextureARB(GL_TEXTURE0_ARB);
813 glActiveTextureARB(GL_TEXTURE1_ARB);
816 else if (ogl_sgis_multitexture_ok)
818 #ifdef GL_SGIS_multitexture
820 glSelectTextureSGIS(GL_TEXTURE0_SGIS);
822 glSelectTextureSGIS(GL_TEXTURE1_SGIS);
825 active_texture_unit = t;
828 void ogl_MultiTexCoord2f(int t, float u, float v)
830 if (ogl_arb_multitexture_ok)
832 #ifdef GL_ARB_multitexture
834 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
836 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
839 else if (ogl_sgis_multitexture_ok)
841 #ifdef GL_SGIS_multitexture
843 glMultiTexCoord2fSGIS(GL_TEXTURE0_SGIS, u, v);
845 glMultiTexCoord2fSGIS(GL_TEXTURE1_SGIS, u, v);
850 bool g3_draw_tmap_2(int nv, g3s_point **pointlist, g3s_uvl *uvl_list, grs_bitmap *bmbot, grs_bitmap *bm, int orient)
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))
858 if (tmap_drawer_ptr != draw_tmap)
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
869 ogl_setActiveTexture(1);
870 glEnable(GL_TEXTURE_2D);
872 ogl_texwrap(bm->gltexture,GL_REPEAT);
874 // GL_DECAL works sorta ok but the top texture is fullbright.
875 //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
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);
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);
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);
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);
894 // add up alpha channels
895 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
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);
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);
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);
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);
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);
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);
929 glBegin(GL_TRIANGLE_FAN);
933 u1=1.0-f2glf(uvl_list[c].v);
934 v1=f2glf(uvl_list[c].u);
937 u1=1.0-f2glf(uvl_list[c].u);
938 v1=1.0-f2glf(uvl_list[c].v);
941 u1=f2glf(uvl_list[c].v);
942 v1=1.0-f2glf(uvl_list[c].u);
945 u1=f2glf(uvl_list[c].u);
946 v1=f2glf(uvl_list[c].v);
949 if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
952 l=f2fl(uvl_list[c].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));
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);
973 g3_draw_tmap(nv,pointlist,uvl_list,bmbot);//draw the bottom texture first.. could be optimized with multitexturing..
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);
980 ogl_texwrap(bm->gltexture,GL_REPEAT);
981 glBegin(GL_TRIANGLE_FAN);
985 u1=1.0-f2glf(uvl_list[c].v);
986 v1=f2glf(uvl_list[c].u);
989 u1=1.0-f2glf(uvl_list[c].u);
990 v1=1.0-f2glf(uvl_list[c].v);
993 u1=f2glf(uvl_list[c].v);
994 v1=1.0-f2glf(uvl_list[c].u);
997 u1=f2glf(uvl_list[c].u);
998 v1=f2glf(uvl_list[c].v);
1001 if (bm->bm_flags&BM_FLAG_NO_LIGHTING){
1004 //l=f2fl(uvl_list[c].l)+gr_palette_gamma/63.0;
1005 l=f2fl(uvl_list[c].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));
1018 bool g3_draw_bitmap(vms_vector *pos,fix width,fix height,grs_bitmap *bm, int orientation)
1021 vms_vector pv,v1;//,v2;
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));
1028 OGL_ENABLE(TEXTURE_2D);
1030 ogl_texwrap(bm->gltexture,GL_CLAMP);
1033 glColor3f(1.0,1.0,1.0);
1034 width = fixmul(width,Matrix_scale.x);
1035 height = fixmul(height,Matrix_scale.y);
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));
1043 glTexCoord2f(0.0, 0.0);
1048 glTexCoord2f(bm->gltexture->u, 0.0);
1053 glTexCoord2f(bm->gltexture->u, bm->gltexture->v);
1058 glTexCoord2f(0.0, bm->gltexture->v);
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));
1076 bool ogl_ubitmapm_c(int x, int y,grs_bitmap *bm,int c)
1078 GLfloat xo,yo,xf,yf;
1079 GLfloat u1,u2,v1,v2;
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;
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));
1091 /* glEnABLE(ALPHA_TEST);
1092 glAlphaFunc(GL_GREATER,0.0);*/
1094 OGL_ENABLE(TEXTURE_2D);
1096 ogl_texwrap(bm->gltexture,GL_CLAMP);
1100 if (bm->bm_w==bm->gltexture->w)
1101 u2=bm->gltexture->u;
1103 u2=(bm->bm_w+bm->bm_x)/(float)bm->gltexture->tw;
1105 u1=bm->bm_x/(float)bm->gltexture->tw;
1106 u2=(bm->bm_w+bm->bm_x)/(float)bm->gltexture->tw;
1110 if (bm->bm_h==bm->gltexture->h)
1111 v2=bm->gltexture->v;
1113 v2=(bm->bm_h+bm->bm_y)/(float)bm->gltexture->th;
1115 v1=bm->bm_y/(float)bm->gltexture->th;
1116 v2=(bm->bm_h+bm->bm_y)/(float)bm->gltexture->th;
1121 glColor3f(1.0,1.0,1.0);
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);
1129 // glDisABLE(ALPHA_TEST);
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);
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)
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));
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;
1154 // OGL_ENABLE(TEXTURE_2D);
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);
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)
1167 GLfloat xo,yo,xs,ys;
1168 GLfloat u1,v1;//,u2,v2;
1170 // unsigned char *oldpal;
1173 ogl_init_texture(&tex, sw, sh, OGL_FLAG_ALPHA);
1175 tex.lw=src->bm_rowsize;
1177 /* if (w==src->bm_w && sx==0){
1180 u1=sx/(float)src->bm_w*src->glu;
1181 u2=w/(float)src->bm_w*src->glu+u1;
1183 if (h==src->bm_h && sy==0){
1186 v1=sy/(float)src->bm_h*src->glv;
1187 v2=h/(float)src->bm_h*src->glv+v1;
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;
1198 OGL_ENABLE(TEXTURE_2D);
1201 ogl_pal=gr_current_pal;
1202 ogl_loadtexture(src->bm_data, sx, sy, &tex, src->bm_flags);
1205 OGL_BINDTEXTURE(tex.handle);
1207 ogl_texwrap(&tex,GL_CLAMP);
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);
1216 ogl_freetexture(&tex);
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);
1223 bool ogl_ubitblt_tolinear(int w,int h,int dx,int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest){
1225 unsigned char *d,*s;
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");
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);
1240 memset(texbuf,0,w1*h1*3);
1244 d=dest->bm_data+dx+(dy+i)*dest->bm_rowsize;
1245 s=texbuf+((h1-(i+sy+1))*w1+sx)*3;
1247 *d=gr_find_closest_color(s[0]/4,s[1]/4,s[2]/4);
1254 unsigned char *d,*s,*e;
1255 if (w*h*3>OGLTEXBUFSIZE)
1256 Error("ogl_ubitblt_tolinear: size larger than OGLTEXBUFSIZE\n");
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);
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;
1271 s=texbuf+w*(h-(i+1))*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);
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);
1287 d+=dest->bm_rowsize;
1289 glmprintf((0,"c=%i w*h=%i\n",c,w*h));
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;
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;
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);
1317 grs_canvas *offscreen_save_canv = NULL, *offscreen_canv = NULL;
1319 void ogl_start_offscreen_render(int x, int y, int w, int h)
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);
1328 void ogl_end_offscreen_render(void)
1332 if (!offscreen_canv)
1333 Error("ogl_end_offscreen_render: no offscreen_canv");
1335 glDrawBuffer(GL_FRONT);
1336 glReadBuffer(GL_BACK);
1337 OGL_DISABLE(TEXTURE_2D);
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);
1345 gr_free_sub_canvas(offscreen_canv);
1346 gr_set_current_canvas(offscreen_save_canv);
1347 offscreen_canv=NULL;
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;
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
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);
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);
1385 void merge_textures_stats(void);
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);
1391 // merge_textures_stats();
1392 // ogl_texture_stats();
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);
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
1413 ogl_swap_buffers_internal();
1414 glClear(GL_COLOR_BUFFER_BIT);
1417 void ogl_init_shared_palette(void)
1419 #ifdef GL_EXT_paletted_texture
1420 if (ogl_shared_palette_ok)
1424 glEnable(GL_SHARED_TEXTURE_PALETTE_EXT);
1425 //glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, ogl_pal);
1427 for (i = 0; i < 256; i++)
1432 texbuf[i * 4 + 1] = 0;
1433 texbuf[i * 4 + 2] = 0;
1434 texbuf[i * 4 + 3] = 0;
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;
1444 glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, texbuf);
1449 int tex_format_supported(int iformat,int format){
1452 if (!ogl_intensity4_ok) return 0; break;
1453 case GL_LUMINANCE4_ALPHA4:
1454 if (!ogl_luminance4_alpha4_ok) return 0; break;
1456 if (!ogl_rgba2_ok) return 0; break;
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,
1465 return (internalFormat==iformat);
1470 //little hack to find the largest or equal multiple of 2 for a given number
1473 for (i=2;i<=4096;i*=2)
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)
1482 // GLushort *tex=(GLushort *)texp;
1484 if (twidth*theight*4>sizeof(texbuf))//shouldn't happen, descent never uses textures that big.
1485 Error("texture toobig %i %i",twidth,theight);
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)
1494 c = 256; // fill the pad space with transparancy
1495 if ((c == 255 && (bm_flags & BM_FLAG_TRANSPARENT)) || c == 256)
1501 case GL_LUMINANCE_ALPHA:
1514 (*(texp++))=0;//transparent pixel
1516 case GL_COLOR_INDEX:
1520 Error("ogl_filltexbuf unknown texformat\n");
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. :)
1529 case GL_LUMINANCE_ALPHA:
1534 (*(texp++)) = ogl_pal[c * 3] * 4;
1535 (*(texp++)) = ogl_pal[c * 3 + 1] * 4;
1536 (*(texp++)) = ogl_pal[c * 3 + 2] * 4;
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);
1548 case GL_COLOR_INDEX:
1552 Error("ogl_filltexbuf unknown texformat\n");
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){
1564 if (ogl_luminance4_alpha4_ok){
1565 tex->internalformat=GL_LUMINANCE4_ALPHA4;
1566 tex->format=GL_LUMINANCE_ALPHA;
1568 }//note how it will fall through here if the statement is false
1569 case GL_LUMINANCE4_ALPHA4:
1571 tex->internalformat=GL_RGBA2;
1572 tex->format=GL_RGBA;
1574 }//note how it will fall through here if the statement is false
1576 tex->internalformat = ogl_rgba_internalformat;
1577 tex->format=GL_RGBA;
1580 mprintf((0,"...no tex format to fall back on\n"));
1583 glmprintf((0,"...falling back to %x\n",tex->internalformat));
1587 void tex_set_size1(ogl_texture *tex,int dbits,int bits,int w, int h){
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"));
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;
1598 tex->bytes=((float)w*h*bits)/8.0;
1599 tex->bytesu=((float)u*bits)/8.0;
1601 glmprintf((0,"tex_set_size1: %ix%i, %ib(%i) %iB\n",w,h,bits,dbits,tex->bytes));
1603 void tex_set_size(ogl_texture *tex){
1606 if (ogl_gettexlevelparam_ok){
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)
1619 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INDEX_SIZE_EXT, &t);
1627 switch (tex->format){
1631 case GL_LUMINANCE_ALPHA:
1638 case GL_COLOR_INDEX:
1642 Error("tex_set_size unknown texformat\n");
1645 tex_set_size1(tex,bi,a,w,h);
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)
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;
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?
1661 if(gr_badtexture>0) return;
1663 #if !(defined(__APPLE__) && defined(__MACH__))
1664 // always fails on OS X, but textures work fine!
1665 if (tex_format_verify(tex))
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;
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.
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))
1686 for (i=0; i < tex->w * tex->h; ++i)
1688 usesthetransparentindexcolor += 1;
1690 if (!usesthetransparentindexcolor)
1692 tex->internalformat = GL_COLOR_INDEX8_EXT;
1693 tex->format = GL_COLOR_INDEX;
1696 // printf("bm data=%p w=%i h=%i used the transparent color %i times\n",data, tex->w, tex->h, usesthetransparentindexcolor);
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);
1704 // Generate OpenGL texture IDs.
1705 glGenTextures(1, &tex->handle);
1708 glPrioritizeTextures(1,&tex->handle,&tex->prio);
1710 // Give our data to OpenGL.
1712 OGL_BINDTEXTURE(tex->handle);
1714 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
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);
1723 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1724 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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.
1729 if (tex->wantmip && GL_needmipmaps)
1730 gluBuild2DMipmaps( GL_TEXTURE_2D, tex->internalformat, tex->tw,
1731 tex->th, tex->format, GL_UNSIGNED_BYTE, texbuf);
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.
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));
1745 unsigned char decodebuf[512*512];
1747 void ogl_loadbmtexture_f(grs_bitmap *bm, int flags)
1750 while (bm->bm_parent)
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));
1757 if (bm->gltexture->handle>0)
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;
1765 if (bm->bm_flags & BM_FLAG_RLE){
1766 unsigned char * dbits;
1767 unsigned char * sbits;
1771 if (bm->bm_flags & BM_FLAG_RLE_BIG)
1774 sbits = &bm->bm_data[4 + (bm->bm_h * data_offset)];
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)])));
1782 sbits += (int)bm->bm_data[4+i];
1787 ogl_loadtexture(buf, 0, 0, bm->gltexture, bm->bm_flags);
1790 void ogl_loadbmtexture(grs_bitmap *bm)
1792 ogl_loadbmtexture_f(bm, OGL_FLAG_MIPMAP);
1795 void ogl_freetexture(ogl_texture *gltexture)
1797 if (gltexture->handle>0) {
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);
1805 void ogl_freebmtexture(grs_bitmap *bm){
1807 ogl_freetexture(bm->gltexture);
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;