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

Last change on this file since 549 was 549, checked in by Sam Hocevar, 14 years ago
  • Cleaned up useless header includes.
  • Property svn:keywords set to Id
File size: 11.2 KB
Line 
1/*
2 *  libcaca       ASCII-Art library
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the Do What The Fuck You Want To
8 *  Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12/** \file driver_gl.c
13 *  \version \$Id: driver_gl.c 549 2006-03-08 09:51:53Z sam $
14 *  \author Jean-Yves Lamoureux <jylam@lnxscene.org>
15 *  \brief OpenGL driver
16 *
17 *  This file contains the libcaca OpenGL input and output driver
18 */
19
20#include "config.h"
21
22#if defined(USE_GL)
23
24#include <GL/gl.h>
25#include <GL/glut.h>
26#include <GL/freeglut_ext.h>
27
28#include <string.h>
29#include <stdlib.h>
30
31#include "caca.h"
32#include "caca_internals.h"
33#include "cucul.h"
34#include "cucul_internals.h"
35
36/*
37 * Global variables
38 */
39
40/* Ok, I just suck. */
41static GLbyte const gl_bgpal[][4] =
42{
43    { 0x00, 0x00, 0x00, 0x7f },
44    { 0x00, 0x00, 0x3f, 0x7f },
45    { 0x00, 0x3f, 0x00, 0x7f },
46    { 0x00, 0x3f, 0x3f, 0x7f },
47    { 0x3f, 0x00, 0x00, 0x7f },
48    { 0x3f, 0x00, 0x3f, 0x7f },
49    { 0x3f, 0x3f, 0x00, 0x7f },
50    { 0x3f, 0x3f, 0x3f, 0x7f },
51    // + intensity
52    { 0x00, 0x00, 0x00, 0x7f },
53    { 0x00, 0x00, 0x7f, 0x7f },
54    { 0x00, 0x7f, 0x00, 0x7f },
55    { 0x00, 0x7f, 0x7f, 0x7f },
56    { 0x7f, 0x00, 0x00, 0x7f },
57    { 0x7f, 0x00, 0x7f, 0x7f },
58    { 0x7f, 0x7f, 0x00, 0x7f },
59    { 0x7f, 0x7f, 0x7f, 0x7f }
60};
61
62static caca_t *gl_kk; /* FIXME: we ought to get rid of this */
63
64/*
65 * Local functions
66 */
67static void gl_handle_keyboard(unsigned char, int, int);
68static void gl_handle_special_key(int, int, int);
69static void gl_handle_reshape(int, int);
70static void gl_handle_mouse(int, int, int, int);
71static void gl_handle_mouse_motion(int, int);
72
73static int gl_init_graphics(caca_t *kk)
74{
75    char *empty_texture;
76    char const *geometry;
77    char *argv[2] = { "", NULL };
78    unsigned int width = 0, height = 0;
79    int argc = 1;
80    int i;
81
82    gl_kk = kk;
83
84    geometry = getenv("CACA_GEOMETRY");
85    if(geometry && *(geometry))
86        sscanf(geometry, "%ux%u", &width, &height);
87
88    if(width && height)
89        cucul_set_size(kk->qq, width, height);
90
91    kk->gl.font_width = 9;
92    kk->gl.font_height = 15;
93
94    kk->gl.width = kk->qq->width * kk->gl.font_width;
95    kk->gl.height = kk->qq->height * kk->gl.font_height;
96
97    kk->gl.resized = 0;
98    kk->gl.bit = 0;
99
100    kk->gl.mouse_changed = kk->gl.mouse_clicked = 0;
101    kk->gl.mouse_button = kk->gl.mouse_state = 0;
102
103    kk->gl.key = 0;
104    kk->gl.special_key = 0;
105
106    kk->gl.sw = 9.0f / 16.0f;
107    kk->gl.sh = 15.0f / 16.0f;
108
109    glutInit(&argc, argv);
110
111    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
112    glutInitWindowSize(kk->gl.width, kk->gl.height);
113    kk->gl.window = glutCreateWindow("caca for GL");
114
115    gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
116
117    glDisable(GL_CULL_FACE);
118    glDisable(GL_DEPTH_TEST);
119
120    glutKeyboardFunc(gl_handle_keyboard);
121    glutSpecialFunc(gl_handle_special_key);
122    glutReshapeFunc(gl_handle_reshape);
123
124    glutMouseFunc(gl_handle_mouse);
125    glutMotionFunc(gl_handle_mouse_motion);
126    glutPassiveMotionFunc(gl_handle_mouse_motion);
127
128    glLoadIdentity();
129
130    glMatrixMode(GL_PROJECTION);
131    glPushMatrix();
132    glLoadIdentity();
133    gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
134
135    glMatrixMode(GL_MODELVIEW);
136
137    glClear(GL_COLOR_BUFFER_BIT);
138
139    empty_texture = malloc(16 * 16 * 4);
140    if(empty_texture == NULL)
141        return -1;
142
143    memset(empty_texture, 0xff, 16 * 16 * 4);
144    glEnable(GL_TEXTURE_2D);
145
146    for(i = 0; i < 94; i++)
147    {
148        glGenTextures(1, (GLuint*)&kk->gl.id[i]);
149        glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
150        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
151        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
152        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
153                     16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture);
154    }
155
156    for(i = 0; i < 94; i++)
157    {
158        glDisable(GL_TEXTURE_2D);
159        glClear(GL_COLOR_BUFFER_BIT);
160
161        glColor3f(1, 1, 1);
162        glRasterPos2f(0, 15);
163        glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32);
164
165        glEnable(GL_TEXTURE_2D);
166        glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
167        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
168                         0, kk->gl.height - 16, 16, 16, 0);
169
170        glutMainLoopEvent();
171        glutPostRedisplay();
172    }
173
174    return 0;
175}
176
177static int gl_end_graphics(caca_t *kk)
178{
179    glutDestroyWindow(kk->gl.window);
180    return 0;
181}
182
183static int gl_set_window_title(caca_t *kk, char const *title)
184{
185    glutSetWindowTitle(title);
186    return 0;
187}
188
189static unsigned int gl_get_window_width(caca_t *kk)
190{
191    return kk->gl.width;
192}
193
194static unsigned int gl_get_window_height(caca_t *kk)
195{
196    return kk->gl.height;
197}
198
199static void gl_display(caca_t *kk)
200{
201    unsigned int x, y, line;
202
203    glClear(GL_COLOR_BUFFER_BIT);
204
205    line = 0;
206    for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
207    {
208        uint8_t *attr = kk->qq->attr + line * kk->qq->width;
209
210        for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
211        {
212            glDisable(GL_TEXTURE_2D);
213            glColor4bv(gl_bgpal[attr[0] >> 4]);
214            glBegin(GL_QUADS);
215                glVertex2f(x, y);
216                glVertex2f(x + kk->gl.font_width, y);
217                glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
218                glVertex2f(x, y + kk->gl.font_height);
219            glEnd();
220
221            attr++;
222        }
223
224        line++;
225    }
226
227    /* 2nd pass, avoids changing render state too much */
228    glEnable(GL_BLEND);
229    glEnable(GL_TEXTURE_2D);
230    glBlendFunc(GL_ONE, GL_ONE);
231
232    line = 0;
233    for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
234    {
235        uint8_t *attr = kk->qq->attr + line * kk->qq->width;
236        uint32_t *chars = kk->qq->chars + line * kk->qq->width;
237
238        for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
239        {
240            if(*chars != (uint32_t)' ')
241            {
242                char ch = *chars & 0x7f;
243
244                /* FIXME: check ch bounds */
245                glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]);
246                glColor4bv(gl_bgpal[attr[0] & 0xf]);
247                glBegin(GL_QUADS);
248                    glTexCoord2f(0, kk->gl.sh);
249                    glVertex2f(x, y);
250                    glTexCoord2f(kk->gl.sw, kk->gl.sh);
251                    glVertex2f(x + kk->gl.font_width, y);
252                    glTexCoord2f(kk->gl.sw, 0);
253                    glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
254                    glTexCoord2f(0, 0);
255                    glVertex2f(x, y + kk->gl.font_height);
256                glEnd();
257            }
258
259            attr++;
260            chars++;
261        }
262        line++;
263    }
264    glDisable(GL_BLEND);
265    glDisable(GL_TEXTURE_2D);
266
267    glutMainLoopEvent();
268    glutSwapBuffers();
269    glutPostRedisplay();
270}
271
272static void gl_handle_resize(caca_t *kk, unsigned int *new_width,
273                                         unsigned int *new_height)
274{
275    kk->gl.width = kk->gl.new_width;
276    kk->gl.height = kk->gl.new_height;
277
278    *new_width = kk->gl.width / kk->gl.font_width;
279    *new_height = (kk->gl.height / kk->gl.font_height) + 1;
280
281    glMatrixMode(GL_PROJECTION);
282    glPushMatrix();
283    glLoadIdentity();
284
285    glViewport(0, 0, kk->gl.width, kk->gl.height);
286    gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
287    glMatrixMode(GL_MODELVIEW);
288}
289
290static unsigned int gl_get_event(caca_t *kk)
291{
292    unsigned int event = 0;
293
294    glutMainLoopEvent();
295
296    if(kk->gl.resized && !kk->resize)
297    {
298        kk->resize = 1;
299        kk->gl.resized = 0;
300        return CACA_EVENT_RESIZE;
301    }
302
303    if(kk->gl.mouse_changed)
304    {
305        if(kk->gl.mouse_clicked)
306        {
307            event |= CACA_EVENT_MOUSE_PRESS | kk->gl.mouse_button;
308            kk->gl.mouse_clicked = 0;
309        }
310        kk->mouse_x = kk->gl.mouse_x;
311        kk->mouse_y = kk->gl.mouse_y;
312        event |= CACA_EVENT_MOUSE_MOTION | (kk->mouse_x << 12) | kk->mouse_y;
313        kk->gl.mouse_changed = 0;
314    }
315
316    if(kk->gl.key != 0)
317    {
318        event |= CACA_EVENT_KEY_PRESS;
319        event |= kk->gl.key;
320        kk->gl.key = 0;
321        return event;
322    }
323
324    if(kk->gl.special_key != 0)
325    {
326        event |= CACA_EVENT_KEY_PRESS;
327
328        switch(kk->gl.special_key)
329        {
330            case GLUT_KEY_F1 : kk->gl.special_key = 0; return event | CACA_KEY_F1;
331            case GLUT_KEY_F2 : kk->gl.special_key = 0; return event | CACA_KEY_F2;
332            case GLUT_KEY_F3 : kk->gl.special_key = 0; return event | CACA_KEY_F3;
333            case GLUT_KEY_F4 : kk->gl.special_key = 0; return event | CACA_KEY_F4;
334            case GLUT_KEY_F5 : kk->gl.special_key = 0; return event | CACA_KEY_F5;
335            case GLUT_KEY_F6 : kk->gl.special_key = 0; return event | CACA_KEY_F6;
336            case GLUT_KEY_F7 : kk->gl.special_key = 0; return event | CACA_KEY_F7;
337            case GLUT_KEY_F8 : kk->gl.special_key = 0; return event | CACA_KEY_F8;
338            case GLUT_KEY_F9 : kk->gl.special_key = 0; return event | CACA_KEY_F9;
339            case GLUT_KEY_F10: kk->gl.special_key = 0; return event | CACA_KEY_F10;
340            case GLUT_KEY_F11: kk->gl.special_key = 0; return event | CACA_KEY_F11;
341            case GLUT_KEY_F12: kk->gl.special_key = 0; return event | CACA_KEY_F12;
342            case GLUT_KEY_LEFT : kk->gl.special_key = 0; return event | CACA_KEY_LEFT;
343            case GLUT_KEY_RIGHT: kk->gl.special_key = 0; return event | CACA_KEY_RIGHT;
344            case GLUT_KEY_UP   : kk->gl.special_key = 0; return event | CACA_KEY_UP;
345            case GLUT_KEY_DOWN : kk->gl.special_key = 0; return event | CACA_KEY_DOWN;
346            default: return CACA_EVENT_NONE;
347        }
348    }
349    return CACA_EVENT_NONE;
350}
351
352/*
353 * XXX: following functions are local
354 */
355
356static void gl_handle_keyboard(unsigned char key, int x, int y)
357{
358    caca_t *kk = gl_kk;
359
360    kk->gl.key = key;
361}
362
363static void gl_handle_special_key(int key, int x, int y)
364{
365    caca_t *kk = gl_kk;
366
367    kk->gl.special_key = key;
368}
369
370static void gl_handle_reshape(int w, int h)
371{
372    caca_t *kk = gl_kk;
373
374    if(kk->gl.bit) /* Do not handle reshaping at the first time */
375    {
376        kk->gl.new_width = w;
377        kk->gl.new_height = h;
378
379        kk->gl.resized = 1;
380    }
381    else
382        kk->gl.bit = 1;
383}
384
385static void gl_handle_mouse(int button, int state, int x, int y)
386{
387    caca_t *kk = gl_kk;
388
389    kk->gl.mouse_clicked = 1;
390    kk->gl.mouse_button = button;
391    kk->gl.mouse_state = state;
392    kk->gl.mouse_x = x / kk->gl.font_width;
393    kk->gl.mouse_y = y / kk->gl.font_height;
394    kk->gl.mouse_changed = 1;
395}
396
397static void gl_handle_mouse_motion(int x, int y)
398{
399    caca_t *kk = gl_kk;
400
401    kk->gl.mouse_x = x / kk->gl.font_width;
402    kk->gl.mouse_y = y / kk->gl.font_height;
403    kk->gl.mouse_changed = 1;
404}
405
406/*
407 * Driver initialisation
408 */
409
410void gl_init_driver(caca_t *kk)
411{
412    kk->driver.driver = CACA_DRIVER_GL;
413
414    kk->driver.init_graphics = gl_init_graphics;
415    kk->driver.end_graphics = gl_end_graphics;
416    kk->driver.set_window_title = gl_set_window_title;
417    kk->driver.get_window_width = gl_get_window_width;
418    kk->driver.get_window_height = gl_get_window_height;
419    kk->driver.display = gl_display;
420    kk->driver.handle_resize = gl_handle_resize;
421    kk->driver.get_event = gl_get_event;
422}
423
424#endif /* USE_GL */
425
Note: See TracBrowser for help on using the repository browser.