source: libcaca/trunk/caca/driver_gl.c @ 810

Last change on this file since 810 was 810, checked in by Sam Hocevar, 14 years ago
  • Renamed cucul_t into cucul_canvas_t. Eh ouais mon con.
  • Property svn:keywords set to Id
File size: 13.0 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: driver_gl.c 810 2006-04-18 12:59:07Z sam $
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14/*
15 *  This file contains the libcaca OpenGL input and output driver
16 */
17
18#include "config.h"
19
20#if defined(USE_GL)
21
22#ifdef HAVE_OPENGL_GL_H
23#   include <OpenGL/gl.h>
24#   include <GLUT/glut.h>
25#else
26#   include <GL/gl.h>
27#   include <GL/glut.h>
28#   include <GL/freeglut_ext.h>
29#endif
30
31#include <string.h>
32#include <stdlib.h>
33#include <stdio.h>
34
35#include "caca.h"
36#include "caca_internals.h"
37#include "cucul.h"
38#include "cucul_internals.h"
39
40/*
41 * Global variables
42 */
43
44static caca_t *gl_kk; /* FIXME: we ought to get rid of this */
45
46/*
47 * Local functions
48 */
49static void gl_handle_keyboard(unsigned char, int, int);
50static void gl_handle_special_key(int, int, int);
51static void gl_handle_reshape(int, int);
52static void gl_handle_mouse(int, int, int, int);
53static void gl_handle_mouse_motion(int, int);
54#ifdef HAVE_GLUTCLOSEFUNC
55static void gl_handle_close(void);
56#endif
57static void _display(void);
58
59struct driver_private
60{
61    int window;
62    unsigned int width, height;
63    unsigned int new_width, new_height;
64    float font_width, font_height;
65    float incx, incy;
66    int id[128 - 32];
67    unsigned char close;
68    unsigned char bit;
69    unsigned char mouse_changed, mouse_clicked;
70    unsigned int mouse_x, mouse_y;
71    unsigned int mouse_button, mouse_state;
72
73    unsigned char key;
74    int special_key;
75
76    float sw, sh;
77};
78
79static int gl_init_graphics(caca_t *kk)
80{
81    char *empty_texture;
82    char const *geometry;
83    char *argv[2] = { "", NULL };
84    unsigned int width = 0, height = 0;
85    int argc = 1;
86    int i;
87
88    kk->drv.p = malloc(sizeof(struct driver_private));
89
90    gl_kk = kk;
91
92#if defined(HAVE_GETENV)
93    geometry = getenv("CACA_GEOMETRY");
94    if(geometry && *geometry)
95        sscanf(geometry, "%ux%u", &width, &height);
96#endif
97
98    if(width && height)
99        _cucul_set_size(kk->c, width, height);
100
101    kk->drv.p->font_width = 9;
102    kk->drv.p->font_height = 15;
103
104    kk->drv.p->width = kk->c->width * kk->drv.p->font_width;
105    kk->drv.p->height = kk->c->height * kk->drv.p->font_height;
106
107#ifdef HAVE_GLUTCLOSEFUNC
108    kk->drv.p->close = 0;
109#endif
110    kk->drv.p->bit = 0;
111
112    kk->drv.p->mouse_changed = kk->drv.p->mouse_clicked = 0;
113    kk->drv.p->mouse_button = kk->drv.p->mouse_state = 0;
114
115    kk->drv.p->key = 0;
116    kk->drv.p->special_key = 0;
117
118    kk->drv.p->sw = 9.0f / 16.0f;
119    kk->drv.p->sh = 15.0f / 16.0f;
120
121    glutInit(&argc, argv);
122
123    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
124    glutInitWindowSize(kk->drv.p->width, kk->drv.p->height);
125    kk->drv.p->window = glutCreateWindow("caca for GL");
126
127    gluOrtho2D(0, kk->drv.p->width, kk->drv.p->height, 0);
128
129    glDisable(GL_CULL_FACE);
130    glDisable(GL_DEPTH_TEST);
131
132    glutKeyboardFunc(gl_handle_keyboard);
133    glutSpecialFunc(gl_handle_special_key);
134    glutReshapeFunc(gl_handle_reshape);
135    glutDisplayFunc(_display);
136
137#ifdef HAVE_GLUTCLOSEFUNC
138    glutCloseFunc(gl_handle_close);
139#endif
140
141    glutMouseFunc(gl_handle_mouse);
142    glutMotionFunc(gl_handle_mouse_motion);
143    glutPassiveMotionFunc(gl_handle_mouse_motion);
144
145    glLoadIdentity();
146
147    glMatrixMode(GL_PROJECTION);
148    glPushMatrix();
149    glLoadIdentity();
150    gluOrtho2D(0, kk->drv.p->width, kk->drv.p->height, 0);
151
152    glMatrixMode(GL_MODELVIEW);
153
154    glClear(GL_COLOR_BUFFER_BIT);
155
156    empty_texture = malloc(16 * 16 * 4);
157    if(empty_texture == NULL)
158        return -1;
159
160    memset(empty_texture, 0xff, 16 * 16 * 4);
161    glEnable(GL_TEXTURE_2D);
162
163    for(i = 32; i < 128; i++)
164    {
165        glGenTextures(1, (GLuint*)&kk->drv.p->id[i - 32]);
166        glBindTexture(GL_TEXTURE_2D, kk->drv.p->id[i - 32]);
167        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
168        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
169        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
170                     16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture);
171    }
172
173    for(i = 32; i < 128; i++)
174    {
175        glDisable(GL_TEXTURE_2D);
176        glClear(GL_COLOR_BUFFER_BIT);
177
178        glColor3f(1, 1, 1);
179        glRasterPos2f(0, 15);
180        glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i);
181
182        glEnable(GL_TEXTURE_2D);
183        glBindTexture(GL_TEXTURE_2D, kk->drv.p->id[i - 32]);
184        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
185                         0, kk->drv.p->height - 16, 16, 16, 0);
186
187#ifdef HAVE_GLUTCHECKLOOP
188        glutCheckLoop();
189#else
190        glutMainLoopEvent();
191#endif
192        glutPostRedisplay();
193    }
194
195    return 0;
196}
197
198static int gl_end_graphics(caca_t *kk)
199{
200    glutDestroyWindow(kk->drv.p->window);
201    free(kk->drv.p);
202    return 0;
203}
204
205static int gl_set_window_title(caca_t *kk, char const *title)
206{
207    glutSetWindowTitle(title);
208    return 0;
209}
210
211static unsigned int gl_get_window_width(caca_t *kk)
212{
213    return kk->drv.p->width;
214}
215
216static unsigned int gl_get_window_height(caca_t *kk)
217{
218    return kk->drv.p->height;
219}
220
221static void gl_display(caca_t *kk)
222{
223    unsigned int x, y, line;
224
225    glClear(GL_COLOR_BUFFER_BIT);
226
227    line = 0;
228    for(y = 0; y < kk->drv.p->height; y += kk->drv.p->font_height)
229    {
230        uint32_t *attr = kk->c->attr + line * kk->c->width;
231
232        for(x = 0; x < kk->drv.p->width; x += kk->drv.p->font_width)
233        {
234            uint16_t bg = _cucul_argb32_to_rgb12bg(*attr++);
235            glDisable(GL_TEXTURE_2D);
236            glColor3b(((bg & 0xf00) >> 8) * 8,
237                      ((bg & 0x0f0) >> 4) * 8,
238                      (bg & 0x00f) * 8);
239            glBegin(GL_QUADS);
240                glVertex2f(x, y);
241                glVertex2f(x + kk->drv.p->font_width, y);
242                glVertex2f(x + kk->drv.p->font_width,
243                           y + kk->drv.p->font_height);
244                glVertex2f(x, y + kk->drv.p->font_height);
245            glEnd();
246        }
247
248        line++;
249    }
250
251    /* 2nd pass, avoids changing render state too much */
252    glEnable(GL_BLEND);
253    glEnable(GL_TEXTURE_2D);
254    glBlendFunc(GL_ONE, GL_ONE);
255
256    line = 0;
257    for(y = 0; y < kk->drv.p->height; y += kk->drv.p->font_height)
258    {
259        uint32_t *attr = kk->c->attr + line * kk->c->width;
260        uint32_t *chars = kk->c->chars + line * kk->c->width;
261
262        for(x = 0; x < kk->drv.p->width; x += kk->drv.p->font_width)
263        {
264            uint32_t c = *chars++;
265
266            if(c > 0x00000020 && c < 0x00000080)
267            {
268                uint16_t fg = _cucul_argb32_to_rgb12fg(*attr);
269                glBindTexture(GL_TEXTURE_2D, kk->drv.p->id[c - 32]);
270                glColor3b(((fg & 0xf00) >> 8) * 8,
271                          ((fg & 0x0f0) >> 4) * 8,
272                          (fg & 0x00f) * 8);
273                glBegin(GL_QUADS);
274                    glTexCoord2f(0, kk->drv.p->sh);
275                    glVertex2f(x, y);
276                    glTexCoord2f(kk->drv.p->sw, kk->drv.p->sh);
277                    glVertex2f(x + kk->drv.p->font_width, y);
278                    glTexCoord2f(kk->drv.p->sw, 0);
279                    glVertex2f(x + kk->drv.p->font_width,
280                               y + kk->drv.p->font_height);
281                    glTexCoord2f(0, 0);
282                    glVertex2f(x, y + kk->drv.p->font_height);
283                glEnd();
284            }
285
286            attr++;
287        }
288        line++;
289    }
290    glDisable(GL_BLEND);
291    glDisable(GL_TEXTURE_2D);
292
293#ifdef HAVE_GLUTCHECKLOOP
294    glutCheckLoop();
295#else
296    glutMainLoopEvent();
297#endif
298    glutSwapBuffers();
299    glutPostRedisplay();
300}
301
302static void gl_handle_resize(caca_t *kk)
303{
304    kk->drv.p->width = kk->drv.p->new_width;
305    kk->drv.p->height = kk->drv.p->new_height;
306
307    glMatrixMode(GL_PROJECTION);
308    glPushMatrix();
309    glLoadIdentity();
310
311    glViewport(0, 0, kk->drv.p->width, kk->drv.p->height);
312    gluOrtho2D(0, kk->drv.p->width, kk->drv.p->height, 0);
313    glMatrixMode(GL_MODELVIEW);
314}
315
316static int gl_get_event(caca_t *kk, caca_event_t *ev)
317{
318#ifdef HAVE_GLUTCHECKLOOP
319    glutCheckLoop();
320#else
321    glutMainLoopEvent();
322#endif
323
324#ifdef HAVE_GLUTCLOSEFUNC
325    if(kk->drv.p->close)
326    {
327        kk->drv.p->close = 0;
328        ev->type = CACA_EVENT_QUIT;
329        return 1;
330    }
331#endif
332
333    if(kk->resize.resized)
334    {
335        ev->type = CACA_EVENT_RESIZE;
336        ev->data.resize.w = kk->c->width;
337        ev->data.resize.h = kk->c->height;
338        return 1;
339    }
340
341    if(kk->drv.p->mouse_changed)
342    {
343        ev->type = CACA_EVENT_MOUSE_MOTION;
344        ev->data.mouse.x = kk->mouse.x;
345        ev->data.mouse.y = kk->mouse.y;
346        kk->drv.p->mouse_changed = 0;
347
348        if(kk->drv.p->mouse_clicked)
349        {
350            _push_event(kk, ev);
351            ev->type = CACA_EVENT_MOUSE_PRESS;
352            ev->data.mouse.button = kk->drv.p->mouse_button;
353            kk->drv.p->mouse_clicked = 0;
354        }
355
356        return 1;
357    }
358
359    if(kk->drv.p->key != 0)
360    {
361        ev->type = CACA_EVENT_KEY_PRESS;
362        ev->data.key.ch = kk->drv.p->key;
363        ev->data.key.ucs4 = (uint32_t)kk->drv.p->key;
364        ev->data.key.utf8[0] = kk->drv.p->key;
365        ev->data.key.utf8[1] = '\0';
366        kk->drv.p->key = 0;
367        return 1;
368    }
369
370    if(kk->drv.p->special_key != 0)
371    {
372        switch(kk->drv.p->special_key)
373        {
374            case GLUT_KEY_F1 : ev->data.key.ch = CACA_KEY_F1; break;
375            case GLUT_KEY_F2 : ev->data.key.ch = CACA_KEY_F2; break;
376            case GLUT_KEY_F3 : ev->data.key.ch = CACA_KEY_F3; break;
377            case GLUT_KEY_F4 : ev->data.key.ch = CACA_KEY_F4; break;
378            case GLUT_KEY_F5 : ev->data.key.ch = CACA_KEY_F5; break;
379            case GLUT_KEY_F6 : ev->data.key.ch = CACA_KEY_F6; break;
380            case GLUT_KEY_F7 : ev->data.key.ch = CACA_KEY_F7; break;
381            case GLUT_KEY_F8 : ev->data.key.ch = CACA_KEY_F8; break;
382            case GLUT_KEY_F9 : ev->data.key.ch = CACA_KEY_F9; break;
383            case GLUT_KEY_F10: ev->data.key.ch = CACA_KEY_F10; break;
384            case GLUT_KEY_F11: ev->data.key.ch = CACA_KEY_F11; break;
385            case GLUT_KEY_F12: ev->data.key.ch = CACA_KEY_F12; break;
386            case GLUT_KEY_LEFT : ev->data.key.ch = CACA_KEY_LEFT; break;
387            case GLUT_KEY_RIGHT: ev->data.key.ch = CACA_KEY_RIGHT; break;
388            case GLUT_KEY_UP   : ev->data.key.ch = CACA_KEY_UP; break;
389            case GLUT_KEY_DOWN : ev->data.key.ch = CACA_KEY_DOWN; break;
390            default: ev->type = CACA_EVENT_NONE; return 0;
391        }
392
393        ev->type = CACA_EVENT_KEY_PRESS;
394        ev->data.key.ucs4 = 0;
395        ev->data.key.utf8[0] = '\0';
396
397        kk->drv.p->special_key = 0;
398        return 1;
399    }
400
401    ev->type = CACA_EVENT_NONE;
402    return 0;
403}
404
405
406static void gl_set_mouse(caca_t *kk, int flag)
407{
408    if(flag)
409        glutSetCursor(GLUT_CURSOR_RIGHT_ARROW);
410    else
411        glutSetCursor(GLUT_CURSOR_NONE);
412}
413
414/*
415 * XXX: following functions are local
416 */
417
418static void gl_handle_keyboard(unsigned char key, int x, int y)
419{
420    caca_t *kk = gl_kk;
421
422    kk->drv.p->key = key;
423}
424
425static void gl_handle_special_key(int key, int x, int y)
426{
427    caca_t *kk = gl_kk;
428
429    kk->drv.p->special_key = key;
430}
431
432static void gl_handle_reshape(int w, int h)
433{
434    caca_t *kk = gl_kk;
435
436    if(kk->drv.p->bit) /* Do not handle reshaping at the first time */
437    {
438        kk->drv.p->new_width = w;
439        kk->drv.p->new_height = h;
440
441        kk->resize.w = w / kk->drv.p->font_width;
442        kk->resize.h = (h / kk->drv.p->font_height) + 1;
443
444        kk->resize.resized = 1;
445    }
446    else
447        kk->drv.p->bit = 1;
448}
449
450static void gl_handle_mouse(int button, int state, int x, int y)
451{
452    caca_t *kk = gl_kk;
453
454    kk->drv.p->mouse_clicked = 1;
455    kk->drv.p->mouse_button = button;
456    kk->drv.p->mouse_state = state;
457    kk->drv.p->mouse_x = x / kk->drv.p->font_width;
458    kk->drv.p->mouse_y = y / kk->drv.p->font_height;
459    kk->mouse.x = kk->drv.p->mouse_x;
460    kk->mouse.y = kk->drv.p->mouse_y;
461    kk->drv.p->mouse_changed = 1;
462}
463
464static void gl_handle_mouse_motion(int x, int y)
465{
466    caca_t *kk = gl_kk;
467    kk->drv.p->mouse_x = x / kk->drv.p->font_width;
468    kk->drv.p->mouse_y = y / kk->drv.p->font_height;
469    kk->mouse.x = kk->drv.p->mouse_x;
470    kk->mouse.y = kk->drv.p->mouse_y;
471    kk->drv.p->mouse_changed = 1;
472}
473
474#ifdef HAVE_GLUTCLOSEFUNC
475static void gl_handle_close(void)
476{
477    caca_t *kk = gl_kk;
478    kk->drv.p->close = 1;
479}
480#endif
481
482static void _display(void)
483{
484    caca_t *kk = gl_kk;
485    gl_display(kk);
486}
487
488
489/*
490 * Driver initialisation
491 */
492
493int gl_install(caca_t *kk)
494{
495#if defined(HAVE_GETENV) && defined(GLUT_XLIB_IMPLEMENTATION)
496    if(!getenv("DISPLAY") || !*(getenv("DISPLAY")))
497        return -1;
498#endif
499
500    kk->drv.driver = CACA_DRIVER_GL;
501
502    kk->drv.init_graphics = gl_init_graphics;
503    kk->drv.end_graphics = gl_end_graphics;
504    kk->drv.set_window_title = gl_set_window_title;
505    kk->drv.get_window_width = gl_get_window_width;
506    kk->drv.get_window_height = gl_get_window_height;
507    kk->drv.display = gl_display;
508    kk->drv.handle_resize = gl_handle_resize;
509    kk->drv.get_event = gl_get_event;
510    kk->drv.set_mouse = gl_set_mouse;
511
512    return 0;
513}
514
515#endif /* USE_GL */
516
Note: See TracBrowser for help on using the repository browser.