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

Last change on this file since 700 was 700, checked in by Jean-Yves Lamoureux, 14 years ago
  • Fixed OpenGL mouse handling

Sam Le Vieux Porc

(\/)

Le / @@ \ Le

( (oo) )

`-..-' Vieux

Vieux / \

@/ \_

(/ / \ \) Porc

Porc WW`----'WW

Sam Le Vieux Porc

  • 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 700 2006-03-27 18:17:09Z jylam $
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        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#ifdef HAVE_GLUTCHECKLOOP
308    glutCheckLoop();
309#else
310    glutMainLoopEvent();
311#endif
312    glutSwapBuffers();
313    glutPostRedisplay();
314}
315
316static void gl_handle_resize(caca_t *kk)
317{
318    kk->drv.p->width = kk->drv.p->new_width;
319    kk->drv.p->height = kk->drv.p->new_height;
320
321    glMatrixMode(GL_PROJECTION);
322    glPushMatrix();
323    glLoadIdentity();
324
325    glViewport(0, 0, kk->drv.p->width, kk->drv.p->height);
326    gluOrtho2D(0, kk->drv.p->width, kk->drv.p->height, 0);
327    glMatrixMode(GL_MODELVIEW);
328}
329
330static int gl_get_event(caca_t *kk, struct caca_event *ev)
331{
332#ifdef HAVE_GLUTCHECKLOOP
333    glutCheckLoop();
334#else
335    glutMainLoopEvent();
336#endif
337
338    if(kk->resize.resized)
339    {
340        ev->type = CACA_EVENT_RESIZE;
341        ev->data.resize.w = kk->qq->width;
342        ev->data.resize.h = kk->qq->height;
343        return 1;
344    }
345
346    if(kk->drv.p->mouse_changed)
347    {
348        ev->type = CACA_EVENT_MOUSE_MOTION;
349        ev->data.mouse.x = kk->mouse.x;
350        ev->data.mouse.y = kk->mouse.y;
351        kk->drv.p->mouse_changed = 0;
352
353        if(kk->drv.p->mouse_clicked)
354        {
355            _push_event(kk, ev);
356            ev->type = CACA_EVENT_MOUSE_PRESS;
357            ev->data.mouse.button = kk->drv.p->mouse_button;
358            kk->drv.p->mouse_clicked = 0;
359        }
360
361        return 1;
362    }
363
364    if(kk->drv.p->key != 0)
365    {
366        ev->type = CACA_EVENT_KEY_PRESS;
367        ev->data.key.c = kk->drv.p->key;
368        ev->data.key.ucs4 = (uint32_t)kk->drv.p->key;
369        ev->data.key.utf8[0] = kk->drv.p->key;
370        ev->data.key.utf8[1] = '\0';
371        kk->drv.p->key = 0;
372        return 1;
373    }
374
375    if(kk->drv.p->special_key != 0)
376    {
377        switch(kk->drv.p->special_key)
378        {
379            case GLUT_KEY_F1 : ev->data.key.c = CACA_KEY_F1; break;
380            case GLUT_KEY_F2 : ev->data.key.c = CACA_KEY_F2; break;
381            case GLUT_KEY_F3 : ev->data.key.c = CACA_KEY_F3; break;
382            case GLUT_KEY_F4 : ev->data.key.c = CACA_KEY_F4; break;
383            case GLUT_KEY_F5 : ev->data.key.c = CACA_KEY_F5; break;
384            case GLUT_KEY_F6 : ev->data.key.c = CACA_KEY_F6; break;
385            case GLUT_KEY_F7 : ev->data.key.c = CACA_KEY_F7; break;
386            case GLUT_KEY_F8 : ev->data.key.c = CACA_KEY_F8; break;
387            case GLUT_KEY_F9 : ev->data.key.c = CACA_KEY_F9; break;
388            case GLUT_KEY_F10: ev->data.key.c = CACA_KEY_F10; break;
389            case GLUT_KEY_F11: ev->data.key.c = CACA_KEY_F11; break;
390            case GLUT_KEY_F12: ev->data.key.c = CACA_KEY_F12; break;
391            case GLUT_KEY_LEFT : ev->data.key.c = CACA_KEY_LEFT; break;
392            case GLUT_KEY_RIGHT: ev->data.key.c = CACA_KEY_RIGHT; break;
393            case GLUT_KEY_UP   : ev->data.key.c = CACA_KEY_UP; break;
394            case GLUT_KEY_DOWN : ev->data.key.c = CACA_KEY_DOWN; break;
395            default: ev->type = CACA_EVENT_NONE; return 0;
396        }
397
398        ev->type = CACA_EVENT_KEY_PRESS;
399        ev->data.key.ucs4 = 0;
400        ev->data.key.utf8[0] = '\0';
401
402        kk->drv.p->special_key = 0;
403        return 1;
404    }
405
406    ev->type = CACA_EVENT_NONE;
407    return 0;
408}
409
410
411static void gl_set_mouse(caca_t *kk, int flag)
412{
413    if(flag)
414        glutSetCursor(GLUT_CURSOR_RIGHT_ARROW);
415    else
416        glutSetCursor(GLUT_CURSOR_NONE);
417}
418
419/*
420 * XXX: following functions are local
421 */
422
423static void gl_handle_keyboard(unsigned char key, int x, int y)
424{
425    caca_t *kk = gl_kk;
426
427    kk->drv.p->key = key;
428}
429
430static void gl_handle_special_key(int key, int x, int y)
431{
432    caca_t *kk = gl_kk;
433
434    kk->drv.p->special_key = key;
435}
436
437static void gl_handle_reshape(int w, int h)
438{
439    caca_t *kk = gl_kk;
440
441    if(kk->drv.p->bit) /* Do not handle reshaping at the first time */
442    {
443        kk->drv.p->new_width = w;
444        kk->drv.p->new_height = h;
445
446        kk->resize.w = w / kk->drv.p->font_width;
447        kk->resize.h = (h / kk->drv.p->font_height) + 1;
448
449        kk->resize.resized = 1;
450    }
451    else
452        kk->drv.p->bit = 1;
453}
454
455static void gl_handle_mouse(int button, int state, int x, int y)
456{
457    caca_t *kk = gl_kk;
458
459    kk->drv.p->mouse_clicked = 1;
460    kk->drv.p->mouse_button = button;
461    kk->drv.p->mouse_state = state;
462    kk->drv.p->mouse_x = x / kk->drv.p->font_width;
463    kk->drv.p->mouse_y = y / kk->drv.p->font_height;
464    kk->mouse.x = kk->drv.p->mouse_x;
465    kk->mouse.y = kk->drv.p->mouse_y;
466    kk->drv.p->mouse_changed = 1;
467}
468
469static void gl_handle_mouse_motion(int x, int y)
470{
471    caca_t *kk = gl_kk;
472    kk->drv.p->mouse_x = x / kk->drv.p->font_width;
473    kk->drv.p->mouse_y = y / kk->drv.p->font_height;
474    kk->mouse.x = kk->drv.p->mouse_x;
475    kk->mouse.y = kk->drv.p->mouse_y;
476    kk->drv.p->mouse_changed = 1;
477}
478
479
480
481static void _display(void)
482{
483    caca_t *kk = gl_kk;
484    gl_display(kk);
485}
486
487
488/*
489 * Driver initialisation
490 */
491
492int gl_install(caca_t *kk)
493{
494#if defined(HAVE_GETENV) && defined(GLUT_XLIB_IMPLEMENTATION)
495    if(!getenv("DISPLAY") || !*(getenv("DISPLAY")))
496        return -1;
497#endif
498
499    kk->drv.driver = CACA_DRIVER_GL;
500
501    kk->drv.init_graphics = gl_init_graphics;
502    kk->drv.end_graphics = gl_end_graphics;
503    kk->drv.set_window_title = gl_set_window_title;
504    kk->drv.get_window_width = gl_get_window_width;
505    kk->drv.get_window_height = gl_get_window_height;
506    kk->drv.display = gl_display;
507    kk->drv.handle_resize = gl_handle_resize;
508    kk->drv.get_event = gl_get_event;
509    kk->drv.set_mouse = gl_set_mouse;
510
511    return 0;
512}
513
514#endif /* USE_GL */
515
Note: See TracBrowser for help on using the repository browser.