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

Last change on this file since 632 was 613, checked in by Sam Hocevar, 14 years ago
  • Minor coding style fixes.
  • Property svn:keywords set to Id
File size: 11.9 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 613 2006-03-15 10:03:04Z 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    { 0x1f, 0x1f, 0x1f, 0x7f },
54    { 0x1f, 0x1f, 0x7f, 0x7f },
55    { 0x1f, 0x7f, 0x1f, 0x7f },
56    { 0x1f, 0x7f, 0x7f, 0x7f },
57    { 0x7f, 0x1f, 0x1f, 0x7f },
58    { 0x7f, 0x1f, 0x7f, 0x7f },
59    { 0x7f, 0x7f, 0x1f, 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,
276                               y + kk->drv.p->font_height);
277                    glTexCoord2f(0, 0);
278                    glVertex2f(x, y + kk->drv.p->font_height);
279                glEnd();
280            }
281
282            attr++;
283        }
284        line++;
285    }
286    glDisable(GL_BLEND);
287    glDisable(GL_TEXTURE_2D);
288
289    glutMainLoopEvent();
290    glutSwapBuffers();
291    glutPostRedisplay();
292}
293
294static void gl_handle_resize(caca_t *kk)
295{
296    kk->drv.p->width = kk->drv.p->new_width;
297    kk->drv.p->height = kk->drv.p->new_height;
298
299    glMatrixMode(GL_PROJECTION);
300    glPushMatrix();
301    glLoadIdentity();
302
303    glViewport(0, 0, kk->drv.p->width, kk->drv.p->height);
304    gluOrtho2D(0, kk->drv.p->width, kk->drv.p->height, 0);
305    glMatrixMode(GL_MODELVIEW);
306}
307
308static unsigned int gl_get_event(caca_t *kk)
309{
310    unsigned int event = 0;
311
312    glutMainLoopEvent();
313
314    if(kk->resize.resized)
315        return CACA_EVENT_RESIZE;
316
317    if(kk->drv.p->mouse_changed)
318    {
319        if(kk->drv.p->mouse_clicked)
320        {
321            event |= CACA_EVENT_MOUSE_PRESS | kk->drv.p->mouse_button;
322            kk->drv.p->mouse_clicked = 0;
323        }
324        kk->mouse.x = kk->drv.p->mouse_x;
325        kk->mouse.y = kk->drv.p->mouse_y;
326        event |= CACA_EVENT_MOUSE_MOTION | (kk->mouse.x << 12) | kk->mouse.y;
327        kk->drv.p->mouse_changed = 0;
328    }
329
330    if(kk->drv.p->key != 0)
331    {
332        event |= CACA_EVENT_KEY_PRESS;
333        event |= kk->drv.p->key;
334        kk->drv.p->key = 0;
335        return event;
336    }
337
338    if(kk->drv.p->special_key != 0)
339    {
340        event |= CACA_EVENT_KEY_PRESS;
341
342        switch(kk->drv.p->special_key)
343        {
344            case GLUT_KEY_F1 : kk->drv.p->special_key = 0; return event | CACA_KEY_F1;
345            case GLUT_KEY_F2 : kk->drv.p->special_key = 0; return event | CACA_KEY_F2;
346            case GLUT_KEY_F3 : kk->drv.p->special_key = 0; return event | CACA_KEY_F3;
347            case GLUT_KEY_F4 : kk->drv.p->special_key = 0; return event | CACA_KEY_F4;
348            case GLUT_KEY_F5 : kk->drv.p->special_key = 0; return event | CACA_KEY_F5;
349            case GLUT_KEY_F6 : kk->drv.p->special_key = 0; return event | CACA_KEY_F6;
350            case GLUT_KEY_F7 : kk->drv.p->special_key = 0; return event | CACA_KEY_F7;
351            case GLUT_KEY_F8 : kk->drv.p->special_key = 0; return event | CACA_KEY_F8;
352            case GLUT_KEY_F9 : kk->drv.p->special_key = 0; return event | CACA_KEY_F9;
353            case GLUT_KEY_F10: kk->drv.p->special_key = 0; return event | CACA_KEY_F10;
354            case GLUT_KEY_F11: kk->drv.p->special_key = 0; return event | CACA_KEY_F11;
355            case GLUT_KEY_F12: kk->drv.p->special_key = 0; return event | CACA_KEY_F12;
356            case GLUT_KEY_LEFT : kk->drv.p->special_key = 0; return event | CACA_KEY_LEFT;
357            case GLUT_KEY_RIGHT: kk->drv.p->special_key = 0; return event | CACA_KEY_RIGHT;
358            case GLUT_KEY_UP   : kk->drv.p->special_key = 0; return event | CACA_KEY_UP;
359            case GLUT_KEY_DOWN : kk->drv.p->special_key = 0; return event | CACA_KEY_DOWN;
360            default: return CACA_EVENT_NONE;
361        }
362    }
363    return CACA_EVENT_NONE;
364}
365
366/*
367 * XXX: following functions are local
368 */
369
370static void gl_handle_keyboard(unsigned char key, int x, int y)
371{
372    caca_t *kk = gl_kk;
373
374    kk->drv.p->key = key;
375}
376
377static void gl_handle_special_key(int key, int x, int y)
378{
379    caca_t *kk = gl_kk;
380
381    kk->drv.p->special_key = key;
382}
383
384static void gl_handle_reshape(int w, int h)
385{
386    caca_t *kk = gl_kk;
387
388    if(kk->drv.p->bit) /* Do not handle reshaping at the first time */
389    {
390        kk->drv.p->new_width = w;
391        kk->drv.p->new_height = h;
392
393        kk->resize.w = w / kk->drv.p->font_width;
394        kk->resize.h = (h / kk->drv.p->font_height) + 1;
395
396        kk->resize.resized = 1;
397    }
398    else
399        kk->drv.p->bit = 1;
400}
401
402static void gl_handle_mouse(int button, int state, int x, int y)
403{
404    caca_t *kk = gl_kk;
405
406    kk->drv.p->mouse_clicked = 1;
407    kk->drv.p->mouse_button = button;
408    kk->drv.p->mouse_state = state;
409    kk->drv.p->mouse_x = x / kk->drv.p->font_width;
410    kk->drv.p->mouse_y = y / kk->drv.p->font_height;
411    kk->drv.p->mouse_changed = 1;
412}
413
414static void gl_handle_mouse_motion(int x, int y)
415{
416    caca_t *kk = gl_kk;
417
418    kk->drv.p->mouse_x = x / kk->drv.p->font_width;
419    kk->drv.p->mouse_y = y / kk->drv.p->font_height;
420    kk->drv.p->mouse_changed = 1;
421}
422
423/*
424 * Driver initialisation
425 */
426
427void gl_init_driver(caca_t *kk)
428{
429    kk->drv.driver = CACA_DRIVER_GL;
430
431    kk->drv.init_graphics = gl_init_graphics;
432    kk->drv.end_graphics = gl_end_graphics;
433    kk->drv.set_window_title = gl_set_window_title;
434    kk->drv.get_window_width = gl_get_window_width;
435    kk->drv.get_window_height = gl_get_window_height;
436    kk->drv.display = gl_display;
437    kk->drv.handle_resize = gl_handle_resize;
438    kk->drv.get_event = gl_get_event;
439}
440
441#endif /* USE_GL */
442
Note: See TracBrowser for help on using the repository browser.