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

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