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

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