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

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