]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grgl2render.cpp
first pass at OpenGL ES 2 support
[taylor/freespace2.git] / src / graphics / grgl2render.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 #include "SDL_opengles2.h"
10
11 #include "pstypes.h"
12 #include "2d.h"
13 #include "gropengl.h"
14 #include "gropenglinternal.h"
15 #include "grgl2.h"
16 #include "bmpman.h"
17 #include "grinternal.h"
18 #include "3d.h"
19 #include "neb.h"
20 #include "line.h"
21 #include "palman.h"
22
23
24 #define NEBULA_COLORS   20
25
26 int cntZval = 0;
27 int cntCorrect = 0;
28 int cntAlpha = 0;
29 int cntNebula = 0;
30 int cntRamp = 0;
31 int cntRGB = 0;
32
33 static void opengl2_tmapper_internal(int nv, vertex **verts, uint flags, int is_scaler)
34 {
35         int i;
36         float u_scale = 1.0f, v_scale = 1.0f;
37
38         gr_texture_source texture_source = TEXTURE_SOURCE_NONE;
39         gr_alpha_blend alpha_blend = ALPHA_BLEND_ALPHA_BLEND_ALPHA;
40         gr_zbuffer_type zbuffer_type = ZBUFFER_TYPE_NONE;
41
42         if (Gr_zbuffering) {
43                 if ( is_scaler || (gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER) ) {
44                         zbuffer_type = ZBUFFER_TYPE_READ;
45                 } else {
46                         zbuffer_type = ZBUFFER_TYPE_FULL;
47                 }
48         }
49
50         int tmap_type = TCACHE_TYPE_NORMAL;
51
52         ubyte r = 255, g = 255, b = 255, a = 255;
53
54         if ( !(flags & TMAP_FLAG_TEXTURED) ) {
55                 r = gr_screen.current_color.red;
56                 g = gr_screen.current_color.green;
57                 b = gr_screen.current_color.blue;
58         }
59
60         if (gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER) {
61                 alpha_blend = ALPHA_BLEND_ALPHA_ADDITIVE;
62
63                 // Blend with screen pixel using src*alpha+dst
64
65                 if (gr_screen.current_alpha < 1.0f) {
66                         r = ubyte((r * gr_screen.current_alpha) + 0.5f);
67                         g = ubyte((g * gr_screen.current_alpha) + 0.5f);
68                         b = ubyte((b * gr_screen.current_alpha) + 0.5f);
69                 }
70         }
71
72         if (flags & TMAP_FLAG_BITMAP_SECTION) {
73                 SDL_assert( !(flags & TMAP_FLAG_BITMAP_INTERFACE) );
74                 tmap_type = TCACHE_TYPE_BITMAP_SECTION;
75         } else if (flags & TMAP_FLAG_BITMAP_INTERFACE) {
76                 SDL_assert( !(flags & TMAP_FLAG_BITMAP_SECTION) );
77                 tmap_type = TCACHE_TYPE_BITMAP_INTERFACE;
78         }
79
80         if (flags & TMAP_FLAG_TEXTURED) {
81                 if ( !opengl2_tcache_set(gr_screen.current_bitmap, tmap_type, &u_scale,
82                                 &v_scale, 0) )
83                 {
84                         mprintf(( "Not rendering a texture because it didn't fit in VRAM!\n" ));
85                         return;
86                 }
87
88                 // use non-filtered textures for bitmap sections and UI graphics
89                 switch (tmap_type) {
90                         case TCACHE_TYPE_BITMAP_INTERFACE:
91                         case TCACHE_TYPE_BITMAP_SECTION:
92                                 texture_source = TEXTURE_SOURCE_NO_FILTERING;
93                                 break;
94
95                         default:
96                                 texture_source = TEXTURE_SOURCE_DECAL;
97                                 break;
98                 }
99         }
100
101
102         opengl2_set_state( texture_source, alpha_blend, zbuffer_type );
103
104         float ox = gr_screen.offset_x * 16.0f;
105         float oy = gr_screen.offset_y * 16.0f;
106 /*
107         float fr = 1.0f, fg = 1.0f, fb = 1.0f;
108
109         if (flags & TMAP_FLAG_PIXEL_FOG) {
110                 int r, g, b;
111                 int ra, ga, ba;
112                 float sx, sy;
113
114                 ra = ga = ba = 0;
115
116                 for (i=nv-1;i>=0;i--)   // DDOI - change polygon winding
117                 {
118                         vertex * va = verts[i];
119
120                         sx = (va->sx * 16.0f + ox) / 16.0f;
121                         sy = (va->sy * 16.0f + oy) / 16.0f;
122
123                         neb2_get_pixel((int)sx, (int)sy, &r, &g, &b);
124
125                         ra += r;
126                         ga += g;
127                         ba += b;
128                 }
129
130                 ra /= nv;
131                 ga /= nv;
132                 ba /= nv;
133
134                 gr_fog_set(GR_FOGMODE_FOG, ra, ga, ba, -1.0f, -1.0f);
135
136                 fr = ra / 255.0f;
137                 fg = ga / 255.0f;
138                 fb = ba / 255.0f;
139         }
140 */
141         opengl_alloc_render_buffer(nv);
142
143         int rb_offset = 0;
144
145         float sx, sy, sz = 0.99f, rhw = 1.0f;
146
147         bool bZval = (Gr_zbuffering || (flags & TMAP_FLAG_NEBULA));
148         bool bCorrect = (flags & TMAP_FLAG_CORRECT);
149         bool bAlpha = (flags & TMAP_FLAG_ALPHA);
150         bool bNebula = (flags & TMAP_FLAG_NEBULA);
151         bool bRamp = ((flags & TMAP_FLAG_RAMP) && (flags & TMAP_FLAG_GOURAUD));
152         bool bRGB = ((flags & TMAP_FLAG_RGB) && (flags & TMAP_FLAG_GOURAUD));
153         bool bTextured = (flags & TMAP_FLAG_TEXTURED);
154
155         for (i = nv-1; i >= 0; i--) {
156                 vertex *va = verts[i];
157
158                 if (bZval) {
159                         sz = 1.0f - 1.0f / (1.0f + va->z / (32768.0f / 256.0f));
160
161                         if ( sz > 0.98f ) {
162                                 sz = 0.98f;
163                         }
164                 }
165
166                 if (bCorrect) {
167                         rhw = 1.0f / va->sw;
168                 }
169
170                 if (bAlpha) {
171                         a = va->a;
172                 }
173
174                 if (bRGB) {
175                         // Make 0.75 be 256.0f
176                         r = Gr_gamma_lookup[va->r];
177                         g = Gr_gamma_lookup[va->g];
178                         b = Gr_gamma_lookup[va->b];
179                 } else if (bNebula) {
180                         int pal = (va->b*(NEBULA_COLORS-1))/255;
181                         r = gr_palette[pal*3+0];
182                         g = gr_palette[pal*3+1];
183                         b = gr_palette[pal*3+2];
184                 } else if (bRamp) {
185                         r = g = b = Gr_gamma_lookup[va->b];
186                 }
187
188                 render_buffer[rb_offset].r = r;
189                 render_buffer[rb_offset].g = g;
190                 render_buffer[rb_offset].b = b;
191                 render_buffer[rb_offset].a = a;
192 /*
193                 if ( (flags & TMAP_FLAG_PIXEL_FOG) && (OGL_fog_mode == 1) ) {
194                         float f_val;
195
196                         opengl1_stuff_fog_value(va->z, &f_val);
197
198                         render_buffer[rb_offset].sr = (ubyte)(((fr * f_val) * 255.0f) + 0.5f);
199                         render_buffer[rb_offset].sg = (ubyte)(((fg * f_val) * 255.0f) + 0.5f);
200                         render_buffer[rb_offset].sb = (ubyte)(((fb * f_val) * 255.0f) + 0.5f);
201                 }
202 */
203                 sx = (va->sx * 16.0f + ox) / 16.0f;
204                 sy = (va->sy * 16.0f + oy) / 16.0f;
205
206                 if (bTextured) {
207                         render_buffer[rb_offset].u = va->u * u_scale;
208                         render_buffer[rb_offset].v = va->v * v_scale;
209                 }
210
211                 render_buffer[rb_offset].x = sx * rhw;
212                 render_buffer[rb_offset].y = sy * rhw;
213                 render_buffer[rb_offset].z = -sz * rhw;
214                 render_buffer[rb_offset].w = rhw;
215
216                 ++rb_offset;
217         }
218
219         if (flags & TMAP_FLAG_TEXTURED) {
220                 glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].u);
221                 glEnableVertexAttribArray(3);
222         }
223 /*
224         if ( (gr_screen.current_fog_mode != GR_FOGMODE_NONE) && (OGL_fog_mode == 1) ) {
225                 glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
226                 vglSecondaryColorPointer(3, GL_UNSIGNED_BYTE, sizeof(rb_t), &render_buffer[0].sr);
227         }
228 */
229         glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(rb_t), &render_buffer[0].r);
230         glEnableVertexAttribArray(2);
231
232         glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].x);
233         glEnableVertexAttribArray(1);
234
235         glDrawArrays(GL_TRIANGLE_FAN, 0, rb_offset);
236
237         glDisableVertexAttribArray(1);
238         glDisableVertexAttribArray(2);
239         glDisableVertexAttribArray(3);
240 }
241
242 void opengl2_rect_internal(int x, int y, int w, int h, int r, int g, int b, int a)
243 {
244         int saved_zbuf;
245         vertex v[4];
246         vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]};
247
248         saved_zbuf = gr_zbuffer_get();
249
250         // start the frame, no zbuffering, no culling
251         g3_start_frame(1);
252         gr_zbuffer_set(GR_ZBUFF_NONE);
253         gr_opengl_set_cull(0);
254
255         // stuff coords
256         v[0].sx = i2fl(x);
257         v[0].sy = i2fl(y);
258         v[0].sw = 0.0f;
259         v[0].u = 0.0f;
260         v[0].v = 0.0f;
261         v[0].flags = PF_PROJECTED;
262         v[0].codes = 0;
263         v[0].r = (ubyte)r;
264         v[0].g = (ubyte)g;
265         v[0].b = (ubyte)b;
266         v[0].a = (ubyte)a;
267
268         v[1].sx = i2fl(x + w);
269         v[1].sy = i2fl(y);
270         v[1].sw = 0.0f;
271         v[1].u = 0.0f;
272         v[1].v = 0.0f;
273         v[1].flags = PF_PROJECTED;
274         v[1].codes = 0;
275         v[1].r = (ubyte)r;
276         v[1].g = (ubyte)g;
277         v[1].b = (ubyte)b;
278         v[1].a = (ubyte)a;
279
280         v[2].sx = i2fl(x + w);
281         v[2].sy = i2fl(y + h);
282         v[2].sw = 0.0f;
283         v[2].u = 0.0f;
284         v[2].v = 0.0f;
285         v[2].flags = PF_PROJECTED;
286         v[2].codes = 0;
287         v[2].r = (ubyte)r;
288         v[2].g = (ubyte)g;
289         v[2].b = (ubyte)b;
290         v[2].a = (ubyte)a;
291
292         v[3].sx = i2fl(x);
293         v[3].sy = i2fl(y + h);
294         v[3].sw = 0.0f;
295         v[3].u = 0.0f;
296         v[3].v = 0.0f;
297         v[3].flags = PF_PROJECTED;
298         v[3].codes = 0;
299         v[3].r = (ubyte)r;
300         v[3].g = (ubyte)g;
301         v[3].b = (ubyte)b;
302         v[3].a = (ubyte)a;
303
304         // draw the polys
305         g3_draw_poly_constant_sw(4, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_FLAG_ALPHA, 0.1f);
306
307         g3_end_frame();
308
309         // restore zbuffer and culling
310         gr_zbuffer_set(saved_zbuf);
311         gr_opengl_set_cull(1);
312 }
313
314 void opengl2_aabitmap_ex_internal(int x, int y, int w, int h, int sx, int sy)
315 {
316         if ( (w < 1) || (h < 1) ) {
317                 return;
318         }
319
320         if ( !gr_screen.current_color.is_alphacolor ) {
321                 return;
322         }
323
324         float u_scale, v_scale;
325
326         if ( !opengl2_tcache_set(gr_screen.current_bitmap, TCACHE_TYPE_AABITMAP,
327                         &u_scale, &v_scale, 0) )
328         {
329                 // Couldn't set texture
330                 mprintf(( "WARNING: Error setting aabitmap texture!\n" ));
331                 return;
332         }
333
334         opengl2_set_state( TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
335
336         float u0, u1, v0, v1;
337         float x1, x2, y1, y2;
338         int bw, bh;
339
340         bm_get_info( gr_screen.current_bitmap, &bw, &bh );
341
342         u0 = u_scale*i2fl(sx)/i2fl(bw);
343         v0 = v_scale*i2fl(sy)/i2fl(bh);
344
345         u1 = u_scale*i2fl(sx+w)/i2fl(bw);
346         v1 = v_scale*i2fl(sy+h)/i2fl(bh);
347
348         x1 = i2fl(x+gr_screen.offset_x);
349         y1 = i2fl(y+gr_screen.offset_y);
350         x2 = i2fl(x+w+gr_screen.offset_x);
351         y2 = i2fl(y+h+gr_screen.offset_y);
352
353         float r, g, b, a;
354         gr_get_colorf(&r, &g, &b, &a);
355         glVertexAttrib4f(1, r, g, b, a);
356
357         opengl_alloc_render_buffer(4);
358
359         render_buffer[0].x = x1;
360         render_buffer[0].y = y1;
361         render_buffer[0].u = u0;
362         render_buffer[0].v = v0;
363
364         render_buffer[1].x = x1;
365         render_buffer[1].y = y2;
366         render_buffer[1].u = u0;
367         render_buffer[1].v = v1;
368
369         render_buffer[2].x = x2;
370         render_buffer[2].y = y1;
371         render_buffer[2].u = u1;
372         render_buffer[2].v = v0;
373
374         render_buffer[3].x = x2;
375         render_buffer[3].y = y2;
376         render_buffer[3].u = u1;
377         render_buffer[3].v = v1;
378
379         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].x);
380         glEnableVertexAttribArray(0);
381
382         glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].u);
383         glEnableVertexAttribArray(2);
384
385         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
386
387         glDisableVertexAttribArray(0);
388         glDisableVertexAttribArray(2);
389 }
390
391 void gr_opengl2_rect(int x, int y, int w, int h)
392 {
393         opengl2_rect_internal(x, y, w, h, gr_screen.current_color.red,
394                         gr_screen.current_color.green, gr_screen.current_color.blue,
395                         gr_screen.current_color.alpha);
396 }
397
398 void gr_opengl2_shade(int x, int y, int w, int h)
399 {
400         int r,g,b,a;
401
402         float shade1 = 1.0f;
403         float shade2 = 6.0f;
404
405         r = fl2i(gr_screen.current_shader.r*255.0f*shade1);
406         CAP(r, 0, 255);
407         g = fl2i(gr_screen.current_shader.g*255.0f*shade1);
408         CAP(g, 0, 255);
409         b = fl2i(gr_screen.current_shader.b*255.0f*shade1);
410         CAP(b, 0, 255);
411         a = fl2i(gr_screen.current_shader.c*255.0f*shade2);
412         CAP(a, 0, 255);
413
414         opengl2_rect_internal(x, y, w, h, r, g, b, a);
415 }
416
417 void gr_opengl2_aabitmap_ex(int x, int y, int w, int h, int sx, int sy)
418 {
419         int reclip;
420         #ifndef NDEBUG
421         int count = 0;
422         #endif
423
424         int dx1=x, dx2=x+w-1;
425         int dy1=y, dy2=y+h-1;
426
427         int bw, bh;
428         bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
429
430         do {
431                 reclip = 0;
432                 #ifndef NDEBUG
433                         if ( count > 1 ) Int3();
434                         count++;
435                 #endif
436
437                 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
438                 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
439                 if ( dx1 < gr_screen.clip_left ) { sx += gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
440                 if ( dy1 < gr_screen.clip_top ) { sy += gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
441                 if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
442                 if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
443
444                 if ( sx < 0 ) {
445                         dx1 -= sx;
446                         sx = 0;
447                         reclip = 1;
448                 }
449
450                 if ( sy < 0 ) {
451                         dy1 -= sy;
452                         sy = 0;
453                         reclip = 1;
454                 }
455
456                 w = dx2-dx1+1;
457                 h = dy2-dy1+1;
458
459                 if ( sx + w > bw ) {
460                         w = bw - sx;
461                         dx2 = dx1 + w - 1;
462                 }
463
464                 if ( sy + h > bh ) {
465                         h = bh - sy;
466                         dy2 = dy1 + h - 1;
467                 }
468
469                 if ( w < 1 ) return;            // clipped away!
470                 if ( h < 1 ) return;            // clipped away!
471
472         } while (reclip);
473
474         // Make sure clipping algorithm works
475         #ifndef NDEBUG
476                 SDL_assert( w > 0 );
477                 SDL_assert( h > 0 );
478                 SDL_assert( w == (dx2-dx1+1) );
479                 SDL_assert( h == (dy2-dy1+1) );
480                 SDL_assert( sx >= 0 );
481                 SDL_assert( sy >= 0 );
482                 SDL_assert( sx+w <= bw );
483                 SDL_assert( sy+h <= bh );
484                 SDL_assert( dx2 >= dx1 );
485                 SDL_assert( dy2 >= dy1 );
486                 SDL_assert( (dx1 >= gr_screen.clip_left ) && (dx1 <= gr_screen.clip_right) );
487                 SDL_assert( (dx2 >= gr_screen.clip_left ) && (dx2 <= gr_screen.clip_right) );
488                 SDL_assert( (dy1 >= gr_screen.clip_top ) && (dy1 <= gr_screen.clip_bottom) );
489                 SDL_assert( (dy2 >= gr_screen.clip_top ) && (dy2 <= gr_screen.clip_bottom) );
490         #endif
491
492         // We now have dx1,dy1 and dx2,dy2 and sx, sy all set validly within clip regions.
493         opengl2_aabitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
494 }
495
496 void gr_opengl2_aabitmap(int x, int y)
497 {
498         int w, h;
499
500         bm_get_info( gr_screen.current_bitmap, &w, &h, NULL );
501         int dx1=x, dx2=x+w-1;
502         int dy1=y, dy2=y+h-1;
503         int sx=0, sy=0;
504
505         if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
506         if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
507         if ( dx1 < gr_screen.clip_left ) { sx = gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
508         if ( dy1 < gr_screen.clip_top ) { sy = gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
509         if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
510         if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
511
512         if ( sx < 0 ) return;
513         if ( sy < 0 ) return;
514         if ( sx >= w ) return;
515         if ( sy >= h ) return;
516
517         // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
518         gr_opengl2_aabitmap_ex(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
519 }
520
521 void opengl2_error_check(const char *name, int lno)
522 {
523         GLenum error = GL_NO_ERROR;
524
525         do {
526                 error = glGetError();
527
528                 if (error != GL_NO_ERROR) {
529                         nprintf(("Warning", "!!DEBUG!! OpenGL Error: %d at %s:%d\n", error, name, lno));
530                 }
531         } while (error != GL_NO_ERROR);
532 }
533
534
535 void gr_opengl2_string(int sx, int sy, const char *s)
536 {
537         int width, spacing, letter;
538         int x, y;
539         int rb_offset;
540         float u_scale, v_scale;
541         float u0, u1, v0, v1;
542         float x1, x2, y1, y2;
543         int bw, bh;
544         float fbw, fbh;
545
546         if ( !Current_font )    {
547                 return;
548         }
549
550         gr_set_bitmap(Current_font->bitmap_id, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
551
552         if ( !opengl2_tcache_set( gr_screen.current_bitmap, TCACHE_TYPE_AABITMAP, &u_scale, &v_scale, 0 ) )     {
553                 // Couldn't set texture
554                 mprintf(( "WARNING: Error setting aabitmap texture!\n" ));
555                 return;
556         }
557
558         bm_get_info( gr_screen.current_bitmap, &bw, &bh );
559
560         fbw = 1.0f / i2fl(bw);
561         fbh = 1.0f / i2fl(bh);
562
563         opengl2_set_state( TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
564
565         // don't want to create a super huge buffer size (i.e. credits text)
566         const int alocsize = 320;       // 80 characters max per render call
567         opengl_alloc_render_buffer(alocsize);
568
569         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].x);
570         glEnableVertexAttribArray(1);
571
572         float r, g, b, a;
573         gr_get_colorf(&r, &g, &b, &a);
574         glVertexAttrib4f(2, r, g, b, a);
575
576         glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &render_buffer[0].u);
577         glEnableVertexAttribArray(3);
578
579
580         y = sy;
581
582         if (sx==0x8000) {                       //centered
583                 x = get_centered_x(s);
584         } else {
585                 x = sx;
586         }
587
588         spacing = 0;
589         rb_offset = 0;
590
591         while (*s)      {
592                 x += spacing;
593
594                 while (*s== '\n' )      {
595                         s++;
596                         y += Current_font->h;
597                         if (sx==0x8000) {                       //centered
598                                 x = get_centered_x(s);
599                         } else {
600                                 x = sx;
601                         }
602                 }
603                 if (*s == 0 ) break;
604
605                 letter = get_char_width(s[0],s[1],&width,&spacing);
606                 s++;
607
608                 //not in font, draw as space
609                 if (letter<0)   {
610                         continue;
611                 }
612
613                 int xd, yd, xc, yc;
614                 int wc, hc;
615
616                 // Check if this character is totally clipped
617                 if ( x + width < gr_screen.clip_left ) continue;
618                 if ( y + Current_font->h < gr_screen.clip_top ) continue;
619                 if ( x > gr_screen.clip_right ) continue;
620                 if ( y > gr_screen.clip_bottom ) continue;
621
622                 xd = yd = 0;
623                 if ( x < gr_screen.clip_left ) xd = gr_screen.clip_left - x;
624                 if ( y < gr_screen.clip_top ) yd = gr_screen.clip_top - y;
625                 xc = x+xd;
626                 yc = y+yd;
627
628                 wc = width - xd; hc = Current_font->h - yd;
629                 if ( xc + wc > gr_screen.clip_right ) wc = gr_screen.clip_right - xc;
630                 if ( yc + hc > gr_screen.clip_bottom ) hc = gr_screen.clip_bottom - yc;
631
632                 if ( wc < 1 ) continue;
633                 if ( hc < 1 ) continue;
634
635                 float u = i2fl(Current_font->bm_u[letter] + xd);
636                 float v = i2fl(Current_font->bm_v[letter] + yd);
637
638                 x1 = i2fl(xc + gr_screen.offset_x);
639                 y1 = i2fl(yc + gr_screen.offset_y);
640                 x2 = x1 + i2fl(wc);
641                 y2 = y1 + i2fl(hc);
642
643                 u0 = u_scale * (u * fbw);
644                 v0 = v_scale * (v * fbh);
645
646                 u1 = u_scale * ((u+i2fl(wc)) * fbw);
647                 v1 = v_scale * ((v+i2fl(hc)) * fbh);
648
649                 // maybe go ahead and draw
650                 if (rb_offset == alocsize) {
651                         glDrawArrays(GL_TRIANGLE_STRIP, 0, rb_offset);
652                         rb_offset = 0;
653                 }
654
655                 render_buffer[rb_offset].x = x1;
656                 render_buffer[rb_offset].y = y1;
657                 render_buffer[rb_offset].u = u0;
658                 render_buffer[rb_offset].v = v0;
659                 ++rb_offset;
660
661                 render_buffer[rb_offset].x = x1;
662                 render_buffer[rb_offset].y = y2;
663                 render_buffer[rb_offset].u = u0;
664                 render_buffer[rb_offset].v = v1;
665                 ++rb_offset;
666
667                 render_buffer[rb_offset].x = x2;
668                 render_buffer[rb_offset].y = y1;
669                 render_buffer[rb_offset].u = u1;
670                 render_buffer[rb_offset].v = v0;
671                 ++rb_offset;
672
673                 render_buffer[rb_offset].x = x2;
674                 render_buffer[rb_offset].y = y2;
675                 render_buffer[rb_offset].u = u1;
676                 render_buffer[rb_offset].v = v1;
677                 ++rb_offset;
678         }
679
680         if (rb_offset) {
681                 glDrawArrays(GL_TRIANGLE_STRIP, 0, rb_offset);
682         }
683
684         glDisableVertexAttribArray(1);
685         glDisableVertexAttribArray(3);
686 }
687
688 void gr_opengl2_line(int x1, int y1, int x2, int y2)
689 {
690
691 }
692
693 void gr_opengl2_aaline(vertex *v1, vertex *v2)
694 {
695         gr_opengl2_line( fl2i(v1->sx), fl2i(v1->sy), fl2i(v2->sx), fl2i(v2->sy) );
696 }
697
698 void gr_opengl2_gradient(int x1, int y1, int x2, int y2)
699 {
700
701 }
702
703 void gr_opengl2_circle(int xc, int yc, int d)
704 {
705         int p,x, y, r;
706
707         r = d/2;
708         p=3-d;
709         x=0;
710         y=r;
711
712         // Big clip
713         if ( (xc+r) < gr_screen.clip_left ) return;
714         if ( (xc-r) > gr_screen.clip_right ) return;
715         if ( (yc+r) < gr_screen.clip_top ) return;
716         if ( (yc-r) > gr_screen.clip_bottom ) return;
717
718         while(x<y)      {
719                 // Draw the first octant
720                 gr_opengl2_line( xc-y, yc-x, xc+y, yc-x );
721                 gr_opengl2_line( xc-y, yc+x, xc+y, yc+x );
722
723                 if (p<0)
724                         p=p+(x<<2)+6;
725                 else    {
726                         // Draw the second octant
727                         gr_opengl2_line( xc-x, yc-y, xc+x, yc-y );
728                         gr_opengl2_line( xc-x, yc+y, xc+x, yc+y );
729
730                         p=p+((x-y)<<2)+10;
731                         y--;
732                 }
733                 x++;
734         }
735         if(x==y) {
736                 gr_opengl2_line( xc-x, yc-y, xc+x, yc-y );
737                 gr_opengl2_line( xc-x, yc+y, xc+x, yc+y );
738         }
739 }
740
741 void gr_opengl2_pixel(int x, int y)
742 {
743         gr_opengl2_line(x,y,x,y);
744 }
745
746 void gr_opengl2_cross_fade(int bmap1, int bmap2, int x1, int y1, int x2, int y2, float pct)
747 {
748         gr_set_bitmap(bmap1, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.0f - pct );
749         gr_bitmap(x1, y1);
750
751         gr_set_bitmap(bmap2, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, pct );
752         gr_bitmap(x2, y2);
753 }
754
755 void gr_opengl2_flash(int r, int g, int b)
756 {
757
758 }
759
760 void gr_opengl2_tmapper(int nverts, vertex **verts, uint flags)
761 {
762         opengl2_tmapper_internal(nverts, verts, flags, 0);
763 }
764
765 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (((((x)-(x0))*((y1)-(y0)))/((x1)-(x0)))+(y0))
766
767 void gr_opengl2_scaler(vertex *va, vertex *vb)
768 {
769         float x0, y0, x1, y1;
770         float u0, v0, u1, v1;
771         float clipped_x0, clipped_y0, clipped_x1, clipped_y1;
772         float clipped_u0, clipped_v0, clipped_u1, clipped_v1;
773         float xmin, xmax, ymin, ymax;
774         int dx0, dy0, dx1, dy1;
775
776         //============= CLIP IT =====================
777
778         x0 = va->sx; y0 = va->sy;
779         x1 = vb->sx; y1 = vb->sy;
780
781         xmin = i2fl(gr_screen.clip_left); ymin = i2fl(gr_screen.clip_top);
782         xmax = i2fl(gr_screen.clip_right); ymax = i2fl(gr_screen.clip_bottom);
783
784         u0 = va->u; v0 = va->v;
785         u1 = vb->u; v1 = vb->v;
786
787         // Check for obviously offscreen bitmaps...
788         if ( (y1<=y0) || (x1<=x0) ) return;
789         if ( (x1<xmin ) || (x0>xmax) ) return;
790         if ( (y1<ymin ) || (y0>ymax) ) return;
791
792         clipped_u0 = u0; clipped_v0 = v0;
793         clipped_u1 = u1; clipped_v1 = v1;
794
795         clipped_x0 = x0; clipped_y0 = y0;
796         clipped_x1 = x1; clipped_y1 = y1;
797
798         // Clip the left, moving u0 right as necessary
799         if ( x0 < xmin )        {
800                 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
801                 clipped_x0 = xmin;
802         }
803
804         // Clip the right, moving u1 left as necessary
805         if ( x1 > xmax )        {
806                 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
807                 clipped_x1 = xmax;
808         }
809
810         // Clip the top, moving v0 down as necessary
811         if ( y0 < ymin )        {
812                 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
813                 clipped_y0 = ymin;
814         }
815
816         // Clip the bottom, moving v1 up as necessary
817         if ( y1 > ymax )        {
818                 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
819                 clipped_y1 = ymax;
820         }
821
822         dx0 = fl2i(clipped_x0); dx1 = fl2i(clipped_x1);
823         dy0 = fl2i(clipped_y0); dy1 = fl2i(clipped_y1);
824
825         if (dx1<=dx0) return;
826         if (dy1<=dy0) return;
827
828         //============= DRAW IT =====================
829
830         vertex v[4];
831         vertex *vl[4];
832
833         vl[0] = &v[0];
834         v[0].sx = clipped_x0;
835         v[0].sy = clipped_y0;
836         v[0].sw = va->sw;
837         v[0].z = va->z;
838         v[0].u = clipped_u0;
839         v[0].v = clipped_v0;
840
841         vl[1] = &v[1];
842         v[1].sx = clipped_x1;
843         v[1].sy = clipped_y0;
844         v[1].sw = va->sw;
845         v[1].z = va->z;
846         v[1].u = clipped_u1;
847         v[1].v = clipped_v0;
848
849         vl[2] = &v[2];
850         v[2].sx = clipped_x1;
851         v[2].sy = clipped_y1;
852         v[2].sw = va->sw;
853         v[2].z = va->z;
854         v[2].u = clipped_u1;
855         v[2].v = clipped_v1;
856
857         vl[3] = &v[3];
858         v[3].sx = clipped_x0;
859         v[3].sy = clipped_y1;
860         v[3].sw = va->sw;
861         v[3].z = va->z;
862         v[3].u = clipped_u0;
863         v[3].v = clipped_v1;
864
865         opengl2_tmapper_internal( 4, vl, TMAP_FLAG_TEXTURED, 1 );
866 }