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