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

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