1 /*
2  * Copyright (c) 2009-2012 Hypertriton, Inc. <http://hypertriton.com/>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 /*
27  * Routines common to all OpenGL drivers.
28  */
29 
30 #include <agar/core/core.h>
31 #include <agar/gui/gui.h>
32 #include <agar/gui/window.h>
33 #include <agar/gui/gui_math.h>
34 #include <agar/gui/text.h>
35 #include <agar/gui/packedpixel.h>
36 #include <agar/gui/opengl.h>
37 
38 /*
39  * Initialize an OpenGL context for Agar GUI rendering.
40  *
41  * This routine is usually invoked once when initially creating a window,
42  * but single-window drivers such as "sdlgl" may Init/Destroy the context
43  * during rendering (i.e., to implement the AG_DRIVER_SW_OVERLAY mode).
44  */
45 int
AG_GL_InitContext(void * obj,AG_GL_Context * gl)46 AG_GL_InitContext(void *obj, AG_GL_Context *gl)
47 {
48 	AG_Driver *drv = obj;
49 	AG_ClipRect *cr;
50 
51 	gl->textureGC = NULL;
52 	gl->nTextureGC = 0;
53 	gl->listGC = NULL;
54 	gl->nListGC = 0;
55 	memset(&gl->bs, sizeof(AG_GL_BlendState), sizeof(AG_GL_BlendState));
56 	memset(gl->dither, 0xaa, sizeof(gl->dither));
57 
58 	glMatrixMode(GL_MODELVIEW);
59 	glLoadIdentity();
60 
61 	glShadeModel(GL_FLAT);
62 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
63 
64 	glEnable(GL_TEXTURE_2D);
65 	glDisable(GL_DEPTH_TEST);
66 	glDisable(GL_CULL_FACE);
67 	glDisable(GL_DITHER);
68 	glDisable(GL_BLEND);
69 	glDisable(GL_LIGHTING);
70 
71 	/* Initialize our clipping rectangles. */
72 	memset(gl->clipStates, 0, sizeof(gl->clipStates));
73 	if ((gl->clipRects = TryMalloc(sizeof(AG_ClipRect))) == NULL) {
74 		return (-1);
75 	}
76 	gl->nClipRects = 1;
77 
78 	/* Initialize the first clipping rectangle. */
79 	cr = &gl->clipRects[0];
80 	cr->r = AG_RECT(0,0,0,0);
81 	cr->eqns[0][0] = 1.0;	cr->eqns[0][1] = 0.0;
82 	cr->eqns[0][2] = 0.0;	cr->eqns[0][3] = 0.0;
83 	cr->eqns[1][0] = 0.0;	cr->eqns[1][1] = 1.0;
84 	cr->eqns[1][2] = 0.0;	cr->eqns[1][3] = 0.0;
85 	cr->eqns[2][0] = -1.0;	cr->eqns[2][1] = 0.0;
86 	cr->eqns[2][2] = 0.0;	cr->eqns[2][3] = 0.0; /* w */
87 	cr->eqns[3][0] = 0.0;	cr->eqns[3][1] = -1.0;
88 	cr->eqns[3][2] = 0.0;	cr->eqns[3][3] = 0.0; /* h */
89 
90 	drv->gl = gl;
91 	return (0);
92 }
93 
94 /*
95  * Size or resize an OpenGL context to specified dimensions.
96  */
97 void
AG_GL_SetViewport(AG_GL_Context * gl,AG_Rect vp)98 AG_GL_SetViewport(AG_GL_Context *gl, AG_Rect vp)
99 {
100 	AG_ClipRect *cr = &gl->clipRects[0];
101 
102 	/* Set up the view port and projection */
103 	glViewport(vp.x, vp.y, vp.w, vp.h);
104 	glMatrixMode(GL_PROJECTION);
105 	glLoadIdentity();
106 	glOrtho(0, vp.w, vp.h, 0, -1.0, 1.0);
107 
108 	/* Update clipping rectangle 0. */
109 	cr->r.w = vp.w;
110 	cr->r.h = vp.h;
111 	cr->eqns[2][3] = (double)vp.w;
112 	cr->eqns[3][3] = (double)vp.h;
113 }
114 
115 /* Destroy an OpenGL rendering context. */
116 void
AG_GL_DestroyContext(void * obj)117 AG_GL_DestroyContext(void *obj)
118 {
119 	AG_Driver *drv = obj;
120 	AG_GL_Context *gl = drv->gl;
121 	AG_Glyph *glyph;
122 	int i;
123 
124 	if (gl == NULL)
125 		return;
126 
127 	/* Restore the previous clipping rectangle state. */
128 	if (gl->clipStates[0])	{ glEnable(GL_CLIP_PLANE0); }
129 	else			{ glDisable(GL_CLIP_PLANE0); }
130 	if (gl->clipStates[1])	{ glEnable(GL_CLIP_PLANE1); }
131 	else			{ glDisable(GL_CLIP_PLANE1); }
132 	if (gl->clipStates[2])	{ glEnable(GL_CLIP_PLANE2); }
133 	else			{ glDisable(GL_CLIP_PLANE2); }
134 	if (gl->clipStates[3])	{ glEnable(GL_CLIP_PLANE3); }
135 	else			{ glDisable(GL_CLIP_PLANE3); }
136 
137 	/* Invalidate any cached glyph renderings. */
138 	for (i = 0; i < AG_GLYPH_NBUCKETS; i++) {
139 		SLIST_FOREACH(glyph, &drv->glyphCache[i].glyphs, glyphs) {
140 			if (glyph->texture != 0) {
141 				glDeleteTextures(1, (GLuint *)&glyph->texture);
142 				glyph->texture = 0;
143 			}
144 		}
145 	}
146 
147 	/* Destroy any texture or display list queued for deletion. */
148 	glDeleteTextures(gl->nTextureGC, gl->textureGC);
149 	for (i = 0; i < gl->nListGC; i++) {
150 		glDeleteLists(gl->listGC[i], 1);
151 	}
152 	gl->nTextureGC = 0;
153 	gl->nListGC = 0;
154 	Free(gl->textureGC);
155 	Free(gl->listGC);
156 
157 	free(gl->clipRects);
158 	gl->clipRects = NULL;
159 	gl->nClipRects = 0;
160 
161 	drv->gl = NULL;
162 }
163 
164 /*
165  * Standard clipping rectangle operations.
166  */
167 void
AG_GL_StdPushClipRect(void * obj,AG_Rect r)168 AG_GL_StdPushClipRect(void *obj, AG_Rect r)
169 {
170 	AG_Driver *drv = obj;
171 	AG_GL_Context *gl = drv->gl;
172 	AG_ClipRect *cr, *crPrev;
173 
174 	gl->clipRects = Realloc(gl->clipRects, (gl->nClipRects+1)*
175 	                                         sizeof(AG_ClipRect));
176 	crPrev = &gl->clipRects[gl->nClipRects-1];
177 	cr = &gl->clipRects[gl->nClipRects++];
178 
179 	cr->eqns[0][0] = 1.0;
180 	cr->eqns[0][1] = 0.0;
181 	cr->eqns[0][2] = 0.0;
182 	cr->eqns[0][3] = MIN(crPrev->eqns[0][3], -(double)(r.x));
183 	glClipPlane(GL_CLIP_PLANE0, (const GLdouble *)&cr->eqns[0]);
184 
185 	cr->eqns[1][0] = 0.0;
186 	cr->eqns[1][1] = 1.0;
187 	cr->eqns[1][2] = 0.0;
188 	cr->eqns[1][3] = MIN(crPrev->eqns[1][3], -(double)(r.y));
189 	glClipPlane(GL_CLIP_PLANE1, (const GLdouble *)&cr->eqns[1]);
190 
191 	cr->eqns[2][0] = -1.0;
192 	cr->eqns[2][1] = 0.0;
193 	cr->eqns[2][2] = 0.0;
194 	cr->eqns[2][3] = MIN(crPrev->eqns[2][3], (double)(r.x+r.w));
195 	glClipPlane(GL_CLIP_PLANE2, (const GLdouble *)&cr->eqns[2]);
196 
197 	cr->eqns[3][0] = 0.0;
198 	cr->eqns[3][1] = -1.0;
199 	cr->eqns[3][2] = 0.0;
200 	cr->eqns[3][3] = MIN(crPrev->eqns[3][3], (double)(r.y+r.h));
201 	glClipPlane(GL_CLIP_PLANE3, (const GLdouble *)&cr->eqns[3]);
202 }
203 void
AG_GL_StdPopClipRect(void * obj)204 AG_GL_StdPopClipRect(void *obj)
205 {
206 	AG_Driver *drv = obj;
207 	AG_GL_Context *gl = drv->gl;
208 	AG_ClipRect *cr;
209 
210 #ifdef AG_DEBUG
211 	if (gl->nClipRects < 1)
212 		AG_FatalError("PopClipRect() without PushClipRect()");
213 #endif
214 	cr = &gl->clipRects[gl->nClipRects-2];
215 	gl->nClipRects--;
216 
217 	glClipPlane(GL_CLIP_PLANE0, (const GLdouble *)&cr->eqns[0]);
218 	glClipPlane(GL_CLIP_PLANE1, (const GLdouble *)&cr->eqns[1]);
219 	glClipPlane(GL_CLIP_PLANE2, (const GLdouble *)&cr->eqns[2]);
220 	glClipPlane(GL_CLIP_PLANE3, (const GLdouble *)&cr->eqns[3]);
221 }
222 
223 /*
224  * Standard blending control operations.
225  */
226 void
AG_GL_StdPushBlendingMode(void * obj,AG_BlendFn fnSrc,AG_BlendFn fnDst)227 AG_GL_StdPushBlendingMode(void *obj, AG_BlendFn fnSrc, AG_BlendFn fnDst)
228 {
229 	AG_Driver *drv = obj;
230 	AG_GL_Context *gl = drv->gl;
231 
232 	/* XXX TODO: stack */
233 	glGetTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &gl->bs[0].texEnvMode);
234 	glGetBooleanv(GL_BLEND, &gl->bs[0].enabled);
235 	glGetIntegerv(GL_BLEND_SRC, &gl->bs[0].srcFactor);
236 	glGetIntegerv(GL_BLEND_DST, &gl->bs[0].dstFactor);
237 
238 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
239 	glEnable(GL_BLEND);
240 	glBlendFunc(AG_GL_GetBlendingFunc(fnSrc), AG_GL_GetBlendingFunc(fnDst));
241 }
242 void
AG_GL_StdPopBlendingMode(void * obj)243 AG_GL_StdPopBlendingMode(void *obj)
244 {
245 	AG_Driver *drv = obj;
246 	AG_GL_Context *gl = drv->gl;
247 
248 	/* XXX TODO: stack */
249 	if (gl->bs[0].enabled) {
250 		glEnable(GL_BLEND);
251 	} else {
252 		glDisable(GL_BLEND);
253 	}
254 	glBlendFunc(gl->bs[0].srcFactor, gl->bs[0].dstFactor);
255 }
256 
257 /*
258  * Standard texture management operations.
259  */
260 void
AG_GL_StdDeleteTexture(void * obj,Uint texture)261 AG_GL_StdDeleteTexture(void *obj, Uint texture)
262 {
263 	AG_Driver *drv = obj;
264 	AG_GL_Context *gl = drv->gl;
265 
266 	gl->textureGC = Realloc(gl->textureGC, (gl->nTextureGC+1)*sizeof(Uint));
267 	gl->textureGC[gl->nTextureGC++] = texture;
268 }
269 void
AG_GL_StdDeleteList(void * obj,Uint list)270 AG_GL_StdDeleteList(void *obj, Uint list)
271 {
272 	AG_Driver *drv = obj;
273 	AG_GL_Context *gl = drv->gl;
274 
275 	gl->listGC = Realloc(gl->listGC, (gl->nListGC+1)*sizeof(Uint));
276 	gl->listGC[gl->nListGC++] = list;
277 }
278 
279 void
AG_GL_StdUploadTexture(void * obj,Uint * rv,AG_Surface * su,AG_TexCoord * tc)280 AG_GL_StdUploadTexture(void *obj, Uint *rv, AG_Surface *su, AG_TexCoord *tc)
281 {
282 	AG_Surface *gsu;
283 	GLuint texture;
284 
285 	if (su->flags & AG_SURFACE_GLTEXTURE) {
286 		gsu = su;
287 	} else {
288 		if ((gsu = AG_SurfaceStdGL(su->w, su->h)) == NULL) {
289 			AG_FatalError(NULL);
290 		}
291 		AG_SurfaceCopy(gsu, su);
292 	}
293 	if (tc != NULL) {
294 		tc->x = 0.0f;
295 		tc->y = 0.0f;
296 		tc->w = (float)su->w / (float)gsu->w;
297 		tc->h = (float)su->h / (float)gsu->h;
298 	}
299 
300 	/* Upload as an OpenGL texture. */
301 	glGenTextures(1, &texture);
302 	glBindTexture(GL_TEXTURE_2D, texture);
303 #if 0
304 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
305 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
306 #else
307 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
308 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
309 #endif
310 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
311 	    gsu->w, gsu->h, 0,
312 	    GL_RGBA,
313 	    GL_UNSIGNED_BYTE,
314 	    gsu->pixels);
315 	glBindTexture(GL_TEXTURE_2D, 0);
316 
317 	if (!(su->flags & AG_SURFACE_GLTEXTURE)) {
318 		AG_SurfaceFree(gsu);
319 	}
320 	*rv = texture;
321 }
322 
323 int
AG_GL_StdUpdateTexture(void * obj,Uint texture,AG_Surface * su,AG_TexCoord * tc)324 AG_GL_StdUpdateTexture(void *obj, Uint texture, AG_Surface *su, AG_TexCoord *tc)
325 {
326 	AG_Surface *gsu;
327 
328 	if (su->flags & AG_SURFACE_GLTEXTURE) {
329 		gsu = su;
330 	} else {
331 		if ((gsu = AG_SurfaceStdGL(su->w, su->h)) == NULL) {
332 			return (-1);
333 		}
334 		AG_SurfaceCopy(gsu, su);
335 	}
336 	if (tc != NULL) {
337 		tc->x = 0.0f;
338 		tc->y = 0.0f;
339 		tc->w = (float)gsu->w / (float)su->w;
340 		tc->h = (float)gsu->h / (float)su->h;
341 	}
342 
343 	glBindTexture(GL_TEXTURE_2D, (GLuint)texture);
344 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
345 	    gsu->w, gsu->h, 0,
346 	    GL_RGBA,
347 	    GL_UNSIGNED_BYTE,
348 	    gsu->pixels);
349 	glBindTexture(GL_TEXTURE_2D, 0);
350 
351 	if (!(su->flags & AG_SURFACE_GLTEXTURE)) {
352 		AG_SurfaceFree(gsu);
353 	}
354 	return (0);
355 }
356 
357 /* Prepare a widget-bound texture for rendering. */
358 void
AG_GL_PrepareTexture(void * obj,int s)359 AG_GL_PrepareTexture(void *obj, int s)
360 {
361 	AG_Widget *wid = obj;
362 	AG_Driver *drv = wid->drv;
363 
364 	if (wid->textures[s] == 0) {
365 		AG_GL_UploadTexture(drv, &wid->textures[s], wid->surfaces[s],
366 		    &wid->texcoords[s]);
367 	} else if (wid->surfaceFlags[s] & AG_WIDGET_SURFACE_REGEN) {
368 		wid->surfaceFlags[s] &= ~(AG_WIDGET_SURFACE_REGEN);
369 		AG_GL_UpdateTexture(drv, wid->textures[s],
370 		    wid->surfaces[s], &wid->texcoords[s]);
371 	}
372 }
373 
374 /* Generic emulated BlitSurface() for GL drivers. */
375 void
AG_GL_BlitSurface(void * obj,AG_Widget * wid,AG_Surface * s,int x,int y)376 AG_GL_BlitSurface(void *obj, AG_Widget *wid, AG_Surface *s, int x, int y)
377 {
378 	AG_Driver *drv = obj;
379 	GLuint texture;
380 	AG_TexCoord tc;
381 
382 	AG_ASSERT_CLASS(obj, "AG_Driver:*");
383 	AG_ASSERT_CLASS(wid, "AG_Widget:*");
384 
385 	AG_GL_UploadTexture(drv, &texture, s, &tc);
386 
387 	AGDRIVER_CLASS(drv)->pushBlendingMode(drv,
388 	    AG_ALPHA_SRC,
389 	    AG_ALPHA_ONE_MINUS_SRC);
390 
391 	glBindTexture(GL_TEXTURE_2D, texture);
392 	glBegin(GL_POLYGON);
393 	{
394 		glTexCoord2f(tc.x, tc.y);	glVertex2i(x,      y);
395 		glTexCoord2f(tc.w, tc.y);	glVertex2i(x+s->w, y);
396 		glTexCoord2f(tc.w, tc.h);	glVertex2i(x+s->w, y+s->h);
397 		glTexCoord2f(tc.x, tc.h);	glVertex2i(x,      y+s->h);
398 	}
399 	glEnd();
400 	glBindTexture(GL_TEXTURE_2D, 0);
401 	glDeleteTextures(1, &texture);
402 
403 	AGDRIVER_CLASS(drv)->popBlendingMode(drv);
404 }
405 
406 /*
407  * Generic BlitSurfaceFrom() for GL drivers. We simply render a rectangle
408  * bound to the corresponding texture.
409  */
410 void
AG_GL_BlitSurfaceFrom(void * obj,AG_Widget * wid,AG_Widget * widSrc,int s,AG_Rect * r,int x,int y)411 AG_GL_BlitSurfaceFrom(void *obj, AG_Widget *wid, AG_Widget *widSrc, int s,
412     AG_Rect *r, int x, int y)
413 {
414 	AG_Driver *drv = obj;
415 	AG_Surface *su = widSrc->surfaces[s];
416 	AG_TexCoord tcTmp, *tc;
417 
418 	AG_ASSERT_CLASS(obj, "AG_Driver:*");
419 	AG_ASSERT_CLASS(wid, "AG_Widget:*");
420 	AG_ASSERT_CLASS(widSrc, "AG_Widget:*");
421 
422 	AG_GL_PrepareTexture(widSrc, s);
423 
424 	if (r == NULL) {
425 		tc = &widSrc->texcoords[s];
426 	} else {
427 		tc = &tcTmp;
428 		tcTmp.x = (float)r->x/PowOf2i(r->x);
429 		tcTmp.y = (float)r->y/PowOf2i(r->y);
430 		tcTmp.w = (float)r->w/PowOf2i(r->w);
431 		tcTmp.h = (float)r->h/PowOf2i(r->h);
432 	}
433 
434 	AGDRIVER_CLASS(drv)->pushBlendingMode(drv,
435 	    AG_ALPHA_SRC,
436 	    AG_ALPHA_ONE_MINUS_SRC);
437 
438 	glBindTexture(GL_TEXTURE_2D, widSrc->textures[s]);
439 	glBegin(GL_POLYGON);
440 	{
441 		glTexCoord2f(tc->x, tc->y);	glVertex2i(x,       y);
442 		glTexCoord2f(tc->w, tc->y);	glVertex2i(x+su->w, y);
443 		glTexCoord2f(tc->w, tc->h);	glVertex2i(x+su->w, y+su->h);
444 		glTexCoord2f(tc->x, tc->h);	glVertex2i(x,       y+su->h);
445 	}
446 	glEnd();
447 	glBindTexture(GL_TEXTURE_2D, 0);
448 	AGDRIVER_CLASS(drv)->popBlendingMode(drv);
449 }
450 
451 /* Generic BlitSurfaceGL() operation for GL drivers. */
452 void
AG_GL_BlitSurfaceGL(void * obj,AG_Widget * wid,AG_Surface * s,float w,float h)453 AG_GL_BlitSurfaceGL(void *obj, AG_Widget *wid, AG_Surface *s, float w, float h)
454 {
455 	AG_Driver *drv = obj;
456 	GLuint texture;
457 	AG_TexCoord tc;
458 	float w2 = w/2.0f;
459 	float h2 = h/2.0f;
460 
461 	AG_GL_UploadTexture(drv, &texture, s, &tc);
462 
463 	AGDRIVER_CLASS(drv)->pushBlendingMode(drv,
464 	    AG_ALPHA_SRC,
465 	    AG_ALPHA_ONE_MINUS_SRC);
466 
467 	glBindTexture(GL_TEXTURE_2D, texture);
468 	glBegin(GL_POLYGON);
469 	{
470 		glTexCoord2f(tc.x, tc.y);	glVertex2f( w2,  h2);
471 		glTexCoord2f(tc.w, tc.y);	glVertex2f(-w2,  h2);
472 		glTexCoord2f(tc.w, tc.h);	glVertex2f(-w2, -h2);
473 		glTexCoord2f(tc.x, tc.h);	glVertex2f( w2, -h2);
474 	}
475 	glEnd();
476 	glBindTexture(GL_TEXTURE_2D, 0);
477 	glDeleteTextures(1, &texture);
478 
479 	AGDRIVER_CLASS(drv)->popBlendingMode(drv);
480 }
481 
482 /* Generic BlitSurfaceFromGL() operation for GL drivers. */
483 void
AG_GL_BlitSurfaceFromGL(void * obj,AG_Widget * wid,int s,float w,float h)484 AG_GL_BlitSurfaceFromGL(void *obj, AG_Widget *wid, int s, float w, float h)
485 {
486 	AG_Driver *drv = obj;
487 	AG_TexCoord *tc;
488 	float w2 = w/2.0f;
489 	float h2 = h/2.0f;
490 
491 	AG_GL_PrepareTexture(wid, s);
492 	tc = &wid->texcoords[s];
493 
494 	AGDRIVER_CLASS(drv)->pushBlendingMode(drv,
495 	    AG_ALPHA_SRC,
496 	    AG_ALPHA_ONE_MINUS_SRC);
497 
498 	glBindTexture(GL_TEXTURE_2D, wid->textures[s]);
499 	glBegin(GL_POLYGON);
500 	{
501 		glTexCoord2f(tc->x, tc->y);	glVertex2f( w2,  h2);
502 		glTexCoord2f(tc->w, tc->y);	glVertex2f(-w2,  h2);
503 		glTexCoord2f(tc->w, tc->h);	glVertex2f(-w2, -h2);
504 		glTexCoord2f(tc->x, tc->h);	glVertex2f( w2, -h2);
505 	}
506 	glEnd();
507 	glBindTexture(GL_TEXTURE_2D, 0);
508 
509 	AGDRIVER_CLASS(drv)->popBlendingMode(drv);
510 }
511 
512 /* Generic BlitSurfaceFlippedGL() operation for GL drivers. */
513 void
AG_GL_BlitSurfaceFlippedGL(void * obj,AG_Widget * wid,int s,float w,float h)514 AG_GL_BlitSurfaceFlippedGL(void *obj, AG_Widget *wid, int s, float w, float h)
515 {
516 	AG_Driver *drv = obj;
517 	AG_TexCoord *tc;
518 
519 	AG_GL_PrepareTexture(wid, s);
520 	tc = &wid->texcoords[s];
521 
522 	AGDRIVER_CLASS(drv)->pushBlendingMode(drv,
523 	    AG_ALPHA_SRC,
524 	    AG_ALPHA_ONE_MINUS_SRC);
525 
526 	glBindTexture(GL_TEXTURE_2D, (GLuint)wid->textures[s]);
527 	glBegin(GL_POLYGON);
528 	{
529 		glTexCoord2f(tc->w, tc->y);	glVertex2f(0.0, 0.0);
530 		glTexCoord2f(tc->x, tc->y);	glVertex2f(w,   0.0);
531 		glTexCoord2f(tc->x, tc->h);	glVertex2f(w,   h);
532 		glTexCoord2f(tc->w, tc->h);	glVertex2f(0.0, h);
533 	}
534 	glEnd();
535 	glBindTexture(GL_TEXTURE_2D, 0);
536 
537 	AGDRIVER_CLASS(drv)->popBlendingMode(drv);
538 }
539 
540 /*
541  * Generic BackupSurfaces() operation for GL drivers. We simply copy the
542  * textures back to software surfaces, where necessary, using glGetTexImage().
543  */
544 void
AG_GL_BackupSurfaces(void * obj,AG_Widget * wid)545 AG_GL_BackupSurfaces(void *obj, AG_Widget *wid)
546 {
547 	AG_Surface *su;
548 	GLint w, h;
549 	Uint i;
550 
551 	AG_ObjectLock(wid);
552 	for (i = 0; i < wid->nsurfaces; i++)  {
553 		if (wid->textures[i] == 0 ||
554 		    wid->surfaces[i] != NULL) {
555 			continue;
556 		}
557 		glBindTexture(GL_TEXTURE_2D, (GLuint)wid->textures[i]);
558 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
559 		    &w);
560 		glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
561 		    &h);
562 
563 		if ((su = AG_SurfaceStdGL(w, h)) == NULL) {
564 			AG_FatalError("Backup texture: %s",
565 			    AG_GetError());
566 		}
567 		glGetTexImage(GL_TEXTURE_2D, 0,
568 		    GL_RGBA,
569 		    GL_UNSIGNED_BYTE,
570 		    su->pixels);
571 		glBindTexture(GL_TEXTURE_2D, 0);
572 		wid->surfaces[i] = su;
573 	}
574 	glDeleteTextures(wid->nsurfaces, (GLuint *)wid->textures);
575 	memset(wid->textures, 0, wid->nsurfaces*sizeof(Uint));
576 	AG_ObjectUnlock(wid);
577 }
578 
579 /*
580  * Generic RestoreSurfaces() operation for GL drivers. We recreate
581  * corresponding textures for all surfaces.
582  */
583 void
AG_GL_RestoreSurfaces(void * obj,AG_Widget * wid)584 AG_GL_RestoreSurfaces(void *obj, AG_Widget *wid)
585 {
586 	Uint i;
587 
588 	AG_ObjectLock(wid);
589 	for (i = 0; i < wid->nsurfaces; i++)  {
590 		if (wid->surfaces[i] != NULL) {
591 			AG_GL_UploadTexture(wid->drv, &wid->textures[i],
592 			    wid->surfaces[i], &wid->texcoords[i]);
593 		} else {
594 			wid->textures[i] = 0;
595 		}
596 	}
597 	AG_ObjectUnlock(wid);
598 }
599 
600 /*
601  * Generic RenderToSurface() operation for GL drivers.
602  * XXX XXX TODO render to offscreen buffer instead of display!
603  */
604 int
AG_GL_RenderToSurface(void * obj,AG_Widget * wid,AG_Surface ** s)605 AG_GL_RenderToSurface(void *obj, AG_Widget *wid, AG_Surface **s)
606 {
607 	AG_Driver *drv = obj;
608 	Uint8 *pixels;
609 	int visiblePrev;
610 
611 	AG_BeginRendering(drv);
612 	visiblePrev = wid->window->visible;
613 	wid->window->visible = 1;
614 	AG_WindowDraw(wid->window);
615 	wid->window->visible = visiblePrev;
616 	AG_EndRendering(drv);
617 
618 	if ((pixels = AG_TryMalloc(wid->w*wid->h*4)) == NULL) {
619 		return (-1);
620 	}
621 	if (AGDRIVER_MULTIPLE(drv)) {
622 		glReadPixels(
623 		    wid->rView.x1,
624 		    HEIGHT(AGDRIVER_MW(drv)->win) - wid->rView.y2,
625 		    wid->w,
626 		    wid->h,
627 		    GL_RGBA, GL_UNSIGNED_BYTE, pixels);
628 	} else {
629 		glReadPixels(
630 		    wid->rView.x1,
631 		    agDriverSw->h - wid->rView.y2,
632 		    wid->w,
633 		    wid->h,
634 		    GL_RGBA, GL_UNSIGNED_BYTE, pixels);
635 	}
636 	if (AG_PackedPixelFlip(pixels, wid->h, wid->w*4) == -1) {
637 		goto fail;
638 	}
639 	*s = AG_SurfaceFromPixelsRGBA(pixels,
640 	    wid->w, wid->h,
641 	    32,
642 	    0x000000ff, 0x0000ff00, 0x00ff0000, 0);
643 	if (*s == NULL) {
644 		goto fail;
645 	}
646 	return (0);
647 fail:
648 	Free(pixels);
649 	return (-1);
650 }
651 
652 /*
653  * Generic GL rendering operations (rendering context)
654  */
655 
656 void
AG_GL_PutPixel(void * obj,int x,int y,AG_Color C)657 AG_GL_PutPixel(void *obj, int x, int y, AG_Color C)
658 {
659 	glBegin(GL_POINTS);
660 	glColor3ub(C.r, C.g, C.b);
661 	glVertex2i(x, y);
662 	glEnd();
663 }
664 
665 void
AG_GL_PutPixel32(void * obj,int x,int y,Uint32 c)666 AG_GL_PutPixel32(void *obj, int x, int y, Uint32 c)
667 {
668 	AG_Driver *drv = obj;
669 	Uint8 r, g, b;
670 
671 	AG_GetPixelRGB(c, drv->videoFmt, &r,&g,&b);
672 	glBegin(GL_POINTS);
673 	glColor3ub(r, g, b);
674 	glVertex2i(x, y);
675 	glEnd();
676 }
677 
678 void
AG_GL_PutPixelRGB(void * obj,int x,int y,Uint8 r,Uint8 g,Uint8 b)679 AG_GL_PutPixelRGB(void *obj, int x, int y, Uint8 r, Uint8 g, Uint8 b)
680 {
681 	glBegin(GL_POINTS);
682 	glColor3ub(r, g, b);
683 	glVertex2i(x, y);
684 	glEnd();
685 }
686 
687 void
AG_GL_BlendPixel(void * obj,int x,int y,AG_Color C,AG_BlendFn fnSrc,AG_BlendFn fnDst)688 AG_GL_BlendPixel(void *obj, int x, int y, AG_Color C, AG_BlendFn fnSrc,
689     AG_BlendFn fnDst)
690 {
691 	AG_Driver *drv = obj;
692 
693 	/* XXX inefficient */
694 
695 	AGDRIVER_CLASS(drv)->pushBlendingMode(drv, fnSrc, fnDst);
696 	glBegin(GL_POINTS);
697 	glColor4ub(C.r, C.g, C.b, C.a);
698 	glVertex2i(x, y);
699 	glEnd();
700 	AGDRIVER_CLASS(drv)->popBlendingMode(drv);
701 }
702 
703 void
AG_GL_DrawLine(void * obj,int x1,int y1,int x2,int y2,AG_Color C)704 AG_GL_DrawLine(void *obj, int x1, int y1, int x2, int y2, AG_Color C)
705 {
706 	glBegin(GL_LINES);
707 	glColor3ub(C.r, C.g, C.b);
708 	glVertex2s(x1, y1);
709 	glVertex2s(x2, y2);
710 	glEnd();
711 }
712 
713 void
AG_GL_DrawLineH(void * obj,int x1,int x2,int y,AG_Color C)714 AG_GL_DrawLineH(void *obj, int x1, int x2, int y, AG_Color C)
715 {
716 	glBegin(GL_LINES);
717 	glColor3ub(C.r, C.g, C.b);
718 	glVertex2s(x1, y);
719 	glVertex2s(x2, y);
720 	glEnd();
721 }
722 
723 void
AG_GL_DrawLineV(void * obj,int x,int y1,int y2,AG_Color C)724 AG_GL_DrawLineV(void *obj, int x, int y1, int y2, AG_Color C)
725 {
726 	glBegin(GL_LINES);
727 	glColor3ub(C.r, C.g, C.b);
728 	glVertex2s(x, y1);
729 	glVertex2s(x, y2);
730 	glEnd();
731 }
732 
733 void
AG_GL_DrawLineBlended(void * obj,int x1,int y1,int x2,int y2,AG_Color C,AG_BlendFn fnSrc,AG_BlendFn fnDst)734 AG_GL_DrawLineBlended(void *obj, int x1, int y1, int x2, int y2, AG_Color C,
735     AG_BlendFn fnSrc, AG_BlendFn fnDst)
736 {
737 	if (C.a < 255)
738 		AGDRIVER_CLASS(obj)->pushBlendingMode(obj, fnSrc, fnDst);
739 
740 	glBegin(GL_LINES);
741 	glColor4ub(C.r, C.g, C.b, C.a);
742 	glVertex2s(x1, y1);
743 	glVertex2s(x2, y2);
744 	glEnd();
745 
746 	if (C.a < 255)
747 		AGDRIVER_CLASS(obj)->popBlendingMode(obj);
748 }
749 
750 void
AG_GL_DrawArrowUp(void * obj,int x,int y,int h,AG_Color C[2])751 AG_GL_DrawArrowUp(void *obj, int x, int y, int h, AG_Color C[2])
752 {
753 	int h2 = h>>1;
754 
755 	/* XXX c2 */
756 	glBegin(GL_POLYGON);
757 	{
758 		glColor3ub(C[0].r, C[0].g, C[0].b);
759 		glVertex2i(x,		y - h2);
760 		glVertex2i(x - h2,	y + h2);
761 		glVertex2i(x + h2,	y + h2);
762 	}
763 	glEnd();
764 }
765 
766 void
AG_GL_DrawArrowDown(void * obj,int x,int y,int h,AG_Color C[2])767 AG_GL_DrawArrowDown(void *obj, int x, int y, int h, AG_Color C[2])
768 {
769 	int h2 = h>>1;
770 
771 	/* XXX c2 */
772 	glBegin(GL_POLYGON);
773 	{
774 		glColor3ub(C[0].r, C[0].g, C[0].b);
775 		glVertex2i(x - h2,	y - h2);
776 		glVertex2i(x + h2,	y - h2);
777 		glVertex2i(x,		y + h2);
778 	}
779 	glEnd();
780 }
781 
782 void
AG_GL_DrawArrowLeft(void * obj,int x,int y,int h,AG_Color C[2])783 AG_GL_DrawArrowLeft(void *obj, int x, int y, int h, AG_Color C[2])
784 {
785 	int h2 = h>>1;
786 
787 	/* XXX c2 */
788 	glBegin(GL_POLYGON);
789 	{
790 		glColor3ub(C[0].r, C[0].g, C[0].b);
791 		glVertex2i(x - h2,	y);
792 		glVertex2i(x + h2,	y + h2);
793 		glVertex2i(x + h2,	y - h2);
794 	}
795 	glEnd();
796 }
797 
798 void
AG_GL_DrawArrowRight(void * obj,int x,int y,int h,AG_Color C[2])799 AG_GL_DrawArrowRight(void *obj, int x, int y, int h, AG_Color C[2])
800 {
801 	int h2 = h>>1;
802 
803 	/* XXX c2 */
804 	glBegin(GL_POLYGON);
805 	{
806 		glColor3ub(C[0].r, C[0].g, C[0].b);
807 		glVertex2i(x + h2,	y);
808 		glVertex2i(x - h2,	y + h2);
809 		glVertex2i(x - h2,	y - h2);
810 	}
811 	glEnd();
812 }
813 
814 /* Generic FillRect() operation for GL drivers. */
815 void
AG_GL_FillRect(void * obj,AG_Rect r,AG_Color c)816 AG_GL_FillRect(void *obj, AG_Rect r, AG_Color c)
817 {
818 	int x2 = r.x + r.w - 1;
819 	int y2 = r.y + r.h - 1;
820 
821 	glBegin(GL_POLYGON);
822 	glColor3ub(c.r, c.g, c.b);
823 	glVertex2i(r.x, r.y);
824 	glVertex2i(x2, r.y);
825 	glVertex2i(x2, y2);
826 	glVertex2i(r.x, y2);
827 	glEnd();
828 }
829 
830 void
AG_GL_DrawRectDithered(void * obj,AG_Rect r,AG_Color C)831 AG_GL_DrawRectDithered(void *obj, AG_Rect r, AG_Color C)
832 {
833 	AG_Driver *drv = obj;
834 	AG_GL_Context *gl = drv->gl;
835 	int stipplePrev;
836 
837 	stipplePrev = glIsEnabled(GL_POLYGON_STIPPLE);
838 	glEnable(GL_POLYGON_STIPPLE);
839 	glPushAttrib(GL_POLYGON_STIPPLE_BIT);
840 	glPolygonStipple((GLubyte *)gl->dither);
841 	AG_GL_DrawRectFilled(obj, r, C);
842 	glPopAttrib();
843 	if (!stipplePrev) { glDisable(GL_POLYGON_STIPPLE); }
844 }
845 
846 void
AG_GL_DrawBoxRounded(void * obj,AG_Rect r,int z,int radius,AG_Color C[3])847 AG_GL_DrawBoxRounded(void *obj, AG_Rect r, int z, int radius, AG_Color C[3])
848 {
849 	float rad = (float)radius;
850 	float i, nFull = 10.0, nQuart = nFull/4.0;
851 
852 	glMatrixMode(GL_MODELVIEW);
853 	glPushMatrix();
854 
855 	glTranslatef((float)r.x + rad,
856 	             (float)r.y + rad,
857 		     0.0);
858 
859 	glBegin(GL_POLYGON);
860 	glColor3ub(C[0].r, C[0].g, C[0].b);
861 	{
862 		for (i = 0.0; i < nQuart; i++) {
863 			glVertex2f(-rad*Cos((2.0*AG_PI*i)/nFull),
864 			           -rad*Sin((2.0*AG_PI*i)/nFull));
865 		}
866 		for (i = nQuart-1; i > 0.0; i--) {
867 			glVertex2f(r.w - rad*2 + rad*Cos((2.0*AG_PI*i)/nFull),
868 			                       - rad*Sin((2.0*AG_PI*i)/nFull));
869 		}
870 		for (i = 0.0; i < nQuart; i++) {
871 			glVertex2f(r.w - rad*2 + rad*Cos((2.0*AG_PI*i)/nFull),
872 			           r.h - rad*2 + rad*Sin((2.0*AG_PI*i)/nFull));
873 		}
874 		for (i = nQuart; i > 0.0; i--) {
875 			glVertex2f(            - rad*Cos((2.0*AG_PI*i)/nFull),
876 			           r.h - rad*2 + rad*Sin((2.0*AG_PI*i)/nFull));
877 		}
878 	}
879 	glEnd();
880 
881 	glBegin(GL_LINE_STRIP);
882 	{
883 		glColor3ub(C[1].r, C[1].g, C[1].b);
884 		for (i = 0.0; i < nQuart; i++) {
885 			glVertex2f(-rad*Cos((2.0*AG_PI*i)/nFull),
886 			           -rad*Sin((2.0*AG_PI*i)/nFull));
887 		}
888 		glVertex2f(r.w - rad*2 + rad*Cos((2.0*AG_PI*nQuart)/nFull),
889 		                       - rad*Sin((2.0*AG_PI*nQuart)/nFull));
890 
891 		glColor3ub(C[2].r, C[2].g, C[2].b);
892 		for (i = nQuart-1; i > 0.0; i--) {
893 			glVertex2f(r.w - rad*2 + rad*Cos((2.0*AG_PI*i)/nFull),
894 			                       - rad*Sin((2.0*AG_PI*i)/nFull));
895 		}
896 		for (i = 0.0; i < nQuart; i++) {
897 			glVertex2f(r.w - rad*2 + rad*Cos((2.0*AG_PI*i)/nFull),
898 			           r.h - rad*2 + rad*Sin((2.0*AG_PI*i)/nFull));
899 		}
900 		for (i = nQuart; i > 0.0; i--) {
901 			glVertex2f(            - rad*Cos((2.0*AG_PI*i)/nFull),
902 			           r.h - rad*2 + rad*Sin((2.0*AG_PI*i)/nFull));
903 		}
904 		glColor3ub(C[1].r, C[1].g, C[1].b);
905 		glVertex2f(-rad, 0.0);
906 	}
907 	glEnd();
908 
909 	glPopMatrix();
910 }
911 
912 void
AG_GL_DrawBoxRoundedTop(void * obj,AG_Rect r,int z,int radius,AG_Color C[3])913 AG_GL_DrawBoxRoundedTop(void *obj, AG_Rect r, int z, int radius, AG_Color C[3])
914 {
915 	float rad = (float)radius;
916 	float i, nFull = 10.0, nQuart = nFull/4.0;
917 
918 	glMatrixMode(GL_MODELVIEW);
919 	glPushMatrix();
920 
921 	glTranslatef((float)r.x + rad,
922 	             (float)r.y + rad,
923 		     0.0);
924 
925 	glBegin(GL_POLYGON);
926 	glColor3ub(C[0].r, C[0].g, C[0].b);
927 	{
928 		glVertex2f(-rad, (float)r.h - rad);
929 
930 		for (i = 0.0; i < nQuart; i++) {
931 			glVertex2f(-rad*Cos((2.0*AG_PI*i)/nFull),
932 			           -rad*Sin((2.0*AG_PI*i)/nFull));
933 		}
934 		glVertex2f(0.0, -rad);
935 
936 		for (i = nQuart; i > 0.0; i--) {
937 			glVertex2f(r.w - rad*2 + rad*Cos((2.0*AG_PI*i)/nFull),
938 			                       - rad*Sin((2.0*AG_PI*i)/nFull));
939 		}
940 		glVertex2f((float)r.w - rad,
941 		           (float)r.h - rad);
942 	}
943 	glEnd();
944 
945 	glBegin(GL_LINE_STRIP);
946 	{
947 		glColor3ub(C[1].r, C[1].g, C[1].b);
948 		glVertex2i(-rad, r.h-rad);
949 		for (i = 0.0; i < nQuart; i++) {
950 			glVertex2f(-(float)rad*Cos((2.0*AG_PI*i)/nFull),
951 			           -(float)rad*Sin((2.0*AG_PI*i)/nFull));
952 		}
953 		glVertex2f(0.0, -rad);
954 		glVertex2f(r.w - rad*2 + rad*Cos((2.0*AG_PI*nQuart)/nFull),
955 		                       - rad*Sin((2.0*AG_PI*nQuart)/nFull));
956 
957 		glColor3ub(C[2].r, C[2].g, C[2].b);
958 		for (i = nQuart-1; i > 0.0; i--) {
959 			glVertex2f(r.w - rad*2 + rad*Cos((2.0*AG_PI*i)/nFull),
960 			                       - rad*Sin((2.0*AG_PI*i)/nFull));
961 		}
962 		glVertex2f((float)r.w - rad,
963 		           (float)r.h - rad);
964 	}
965 	glEnd();
966 
967 	glPopMatrix();
968 }
969 
970 void
AG_GL_DrawCircle(void * obj,int x,int y,int r,AG_Color C)971 AG_GL_DrawCircle(void *obj, int x, int y, int r, AG_Color C)
972 {
973 	float i, nEdges = r*2;
974 
975 	glMatrixMode(GL_MODELVIEW);
976 	glPushMatrix();
977 	glTranslatef((float)x, (float)y, 0.0);
978 
979 	glBegin(GL_LINE_LOOP);
980 	glColor3ub(C.r, C.g, C.b);
981 	for (i = 0; i < nEdges; i++) {
982 		glVertex2f((float)r*Cos((2.0*AG_PI*i)/nEdges),
983 		           (float)r*Sin((2.0*AG_PI*i)/nEdges));
984 	}
985 	glEnd();
986 
987 	glPopMatrix();
988 }
989 
990 void
AG_GL_DrawCircleFilled(void * obj,int x,int y,int r,AG_Color C)991 AG_GL_DrawCircleFilled(void *obj, int x, int y, int r, AG_Color C)
992 {
993 	float i, nEdges = r*2;
994 
995 	glMatrixMode(GL_MODELVIEW);
996 	glPushMatrix();
997 	glTranslatef((float)x, (float)y, 0.0);
998 
999 	glBegin(GL_POLYGON);
1000 	glColor3ub(C.r, C.g, C.b);
1001 	for (i = 0; i < nEdges; i++) {
1002 		glVertex2f((float)r*Cos((2.0*AG_PI*i)/nEdges),
1003 		           (float)r*Sin((2.0*AG_PI*i)/nEdges));
1004 	}
1005 	glEnd();
1006 
1007 	glPopMatrix();
1008 }
1009 
1010 void
AG_GL_DrawCircle2(void * obj,int x,int y,int r,AG_Color C)1011 AG_GL_DrawCircle2(void *obj, int x, int y, int r, AG_Color C)
1012 {
1013 	float i, nEdges = r*2;
1014 
1015 	glMatrixMode(GL_MODELVIEW);
1016 	glPushMatrix();
1017 	glTranslatef((float)x, (float)y, 0.0);
1018 
1019 	glBegin(GL_LINE_LOOP);
1020 	glColor3ub(C.r, C.g, C.b);
1021 	for (i = 0; i < nEdges; i++) {
1022 		glVertex2f((float)r*Cos((2.0*AG_PI*i)/nEdges),
1023 		           (float)r*Sin((2.0*AG_PI*i)/nEdges));
1024 		glVertex2f(((float)r + 1.0)*Cos((2.0*AG_PI*i)/nEdges),
1025 		           ((float)r + 1.0)*Sin((2.0*AG_PI*i)/nEdges));
1026 	}
1027 	glEnd();
1028 
1029 	glPopMatrix();
1030 }
1031 
1032 void
AG_GL_DrawRectFilled(void * obj,AG_Rect r,AG_Color C)1033 AG_GL_DrawRectFilled(void *obj, AG_Rect r, AG_Color C)
1034 {
1035 	int x2 = r.x + r.w - 1;
1036 	int y2 = r.y + r.h - 1;
1037 
1038 	glBegin(GL_POLYGON);
1039 	glColor3ub(C.r, C.g, C.b);
1040 	glVertex2i(r.x, r.y);
1041 	glVertex2i(x2, r.y);
1042 	glVertex2i(x2, y2);
1043 	glVertex2i(r.x, y2);
1044 	glEnd();
1045 }
1046 
1047 void
AG_GL_DrawRectBlended(void * obj,AG_Rect r,AG_Color C,AG_BlendFn fnSrc,AG_BlendFn fnDst)1048 AG_GL_DrawRectBlended(void *obj, AG_Rect r, AG_Color C, AG_BlendFn fnSrc,
1049     AG_BlendFn fnDst)
1050 {
1051 	int x1 = r.x;
1052 	int y1 = r.y;
1053 	int x2 = x1+r.w;
1054 	int y2 = y1+r.h;
1055 
1056 	if (C.a < 255)
1057 		AGDRIVER_CLASS(obj)->pushBlendingMode(obj, fnSrc, fnDst);
1058 
1059 	glBegin(GL_POLYGON);
1060 	glColor4ub(C.r, C.g, C.b, C.a);
1061 	glVertex2i(x1, y1);
1062 	glVertex2i(x2, y1);
1063 	glVertex2i(x2, y2);
1064 	glVertex2i(x1, y2);
1065 	glEnd();
1066 
1067 	if (C.a < 255)
1068 		AGDRIVER_CLASS(obj)->popBlendingMode(obj);
1069 }
1070 
1071 void
AG_GL_UpdateGlyph(void * obj,AG_Glyph * gl)1072 AG_GL_UpdateGlyph(void *obj, AG_Glyph *gl)
1073 {
1074 	AG_GL_UploadTexture(obj, &gl->texture, gl->su, &gl->texcoords);
1075 }
1076 
1077 void
AG_GL_DrawGlyph(void * obj,const AG_Glyph * gl,int x,int y)1078 AG_GL_DrawGlyph(void *obj, const AG_Glyph *gl, int x, int y)
1079 {
1080 	AG_Surface *su = gl->su;
1081 	const AG_TexCoord *tc = &gl->texcoords;
1082 
1083 	glBindTexture(GL_TEXTURE_2D, gl->texture);
1084 	glBegin(GL_POLYGON);
1085 	{
1086 		glTexCoord2f(tc->x, tc->y);	glVertex2i(x,       y);
1087 		glTexCoord2f(tc->w, tc->y);	glVertex2i(x+su->w, y);
1088 		glTexCoord2f(tc->w, tc->h);	glVertex2i(x+su->w, y+su->h);
1089 		glTexCoord2f(tc->x, tc->h);	glVertex2i(x,       y+su->h);
1090 	}
1091 	glEnd();
1092 	glBindTexture(GL_TEXTURE_2D, 0);
1093 }
1094