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