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

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