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

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