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