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

Last change on this file since 568 was 558, checked in by Sam Hocevar, 14 years ago
  • Made the OpenGL colors slightly less saturated.
  • Property svn:keywords set to Id
File size: 11.9 KB
RevLine 
[35]1/*
[268]2 *  libcaca       ASCII-Art library
[527]3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
[268]4 *                All Rights Reserved
[35]5 *
[268]6 *  This library is free software; you can redistribute it and/or
[522]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.
[35]10 */
[17]11
[540]12/** \file driver_gl.c
[268]13 *  \version \$Id: driver_gl.c 558 2006-03-08 22:39:43Z sam $
[540]14 *  \author Jean-Yves Lamoureux <jylam@lnxscene.org>
15 *  \brief OpenGL driver
[205]16 *
[540]17 *  This file contains the libcaca OpenGL input and output driver
[205]18 */
19
[63]20#include "config.h"
21
[539]22#if defined(USE_GL)
23
24#include <GL/gl.h>
25#include <GL/glut.h>
26#include <GL/freeglut_ext.h>
27
[147]28#include <string.h>
[17]29#include <stdlib.h>
[550]30#include <stdio.h>
[17]31
[185]32#include "caca.h"
33#include "caca_internals.h"
[524]34#include "cucul.h"
35#include "cucul_internals.h"
[17]36
[247]37/*
38 * Global variables
39 */
40
[533]41/* Ok, I just suck. */
[531]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 },
[483]52    // + intensity
[558]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 },
[531]60    { 0x7f, 0x7f, 0x7f, 0x7f }
61};
[483]62
[527]63static caca_t *gl_kk; /* FIXME: we ought to get rid of this */
[483]64
[281]65/*
66 * Local functions
67 */
[511]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);
[483]73
[550]74struct driver_private
75{
76    int window;
77    unsigned int width, height;
[553]78    unsigned int new_width, new_height;
[550]79    float font_width, font_height;
80    float incx, incy;
[557]81    int id[128 - 32];
[553]82    unsigned char bit;
[550]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
[540]93static int gl_init_graphics(caca_t *kk)
[227]94{
[539]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;
[348]101
[550]102    kk->drv.p = malloc(sizeof(struct driver_private));
103
[539]104    gl_kk = kk;
[227]105
[539]106    geometry = getenv("CACA_GEOMETRY");
107    if(geometry && *(geometry))
108        sscanf(geometry, "%ux%u", &width, &height);
[231]109
[539]110    if(width && height)
111        cucul_set_size(kk->qq, width, height);
[227]112
[550]113    kk->drv.p->font_width = 9;
114    kk->drv.p->font_height = 15;
[227]115
[550]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;
[227]118
[550]119    kk->drv.p->bit = 0;
[227]120
[550]121    kk->drv.p->mouse_changed = kk->drv.p->mouse_clicked = 0;
122    kk->drv.p->mouse_button = kk->drv.p->mouse_state = 0;
[227]123
[550]124    kk->drv.p->key = 0;
125    kk->drv.p->special_key = 0;
[227]126
[550]127    kk->drv.p->sw = 9.0f / 16.0f;
128    kk->drv.p->sh = 15.0f / 16.0f;
[251]129
[539]130    glutInit(&argc, argv);
[261]131
[539]132    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
[550]133    glutInitWindowSize(kk->drv.p->width, kk->drv.p->height);
134    kk->drv.p->window = glutCreateWindow("caca for GL");
[274]135
[550]136    gluOrtho2D(0, kk->drv.p->width, kk->drv.p->height, 0);
[263]137
[539]138    glDisable(GL_CULL_FACE);
139    glDisable(GL_DEPTH_TEST);
[251]140
[539]141    glutKeyboardFunc(gl_handle_keyboard);
142    glutSpecialFunc(gl_handle_special_key);
143    glutReshapeFunc(gl_handle_reshape);
[263]144
[539]145    glutMouseFunc(gl_handle_mouse);
146    glutMotionFunc(gl_handle_mouse_motion);
147    glutPassiveMotionFunc(gl_handle_mouse_motion);
[300]148
[539]149    glLoadIdentity();
[263]150
[539]151    glMatrixMode(GL_PROJECTION);
152    glPushMatrix();
153    glLoadIdentity();
[550]154    gluOrtho2D(0, kk->drv.p->width, kk->drv.p->height, 0);
[527]155
[539]156    glMatrixMode(GL_MODELVIEW);
[527]157
[539]158    glClear(GL_COLOR_BUFFER_BIT);
[263]159
[539]160    empty_texture = malloc(16 * 16 * 4);
161    if(empty_texture == NULL)
162        return -1;
[300]163
[539]164    memset(empty_texture, 0xff, 16 * 16 * 4);
165    glEnable(GL_TEXTURE_2D);
[263]166
[557]167    for(i = 32; i < 128; i++)
[539]168    {
[557]169        glGenTextures(1, (GLuint*)&kk->drv.p->id[i - 32]);
170        glBindTexture(GL_TEXTURE_2D, kk->drv.p->id[i - 32]);
[539]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);
[265]175    }
[336]176
[557]177    for(i = 32; i < 128; i++)
[508]178    {
[539]179        glDisable(GL_TEXTURE_2D);
[508]180        glClear(GL_COLOR_BUFFER_BIT);
[483]181
[539]182        glColor3f(1, 1, 1);
183        glRasterPos2f(0, 15);
[557]184        glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i);
[483]185
[508]186        glEnable(GL_TEXTURE_2D);
[557]187        glBindTexture(GL_TEXTURE_2D, kk->drv.p->id[i - 32]);
[539]188        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
[550]189                         0, kk->drv.p->height - 16, 16, 16, 0);
[491]190
[539]191        glutMainLoopEvent();
192        glutPostRedisplay();
[508]193    }
[265]194
[227]195    return 0;
196}
197
[540]198static int gl_end_graphics(caca_t *kk)
[251]199{
[550]200    glutDestroyWindow(kk->drv.p->window);
201    free(kk->drv.p);
[251]202    return 0;
203}
204
[540]205static int gl_set_window_title(caca_t *kk, char const *title)
[343]206{
[539]207    glutSetWindowTitle(title);
[343]208    return 0;
209}
210
[540]211static unsigned int gl_get_window_width(caca_t *kk)
[352]212{
[550]213    return kk->drv.p->width;
[352]214}
215
[540]216static unsigned int gl_get_window_height(caca_t *kk)
[352]217{
[550]218    return kk->drv.p->height;
[352]219}
220
[540]221static void gl_display(caca_t *kk)
[227]222{
[539]223    unsigned int x, y, line;
[227]224
[539]225    glClear(GL_COLOR_BUFFER_BIT);
[227]226
[539]227    line = 0;
[550]228    for(y = 0; y < kk->drv.p->height; y += kk->drv.p->font_height)
[265]229    {
[539]230        uint8_t *attr = kk->qq->attr + line * kk->qq->width;
[261]231
[550]232        for(x = 0; x < kk->drv.p->width; x += kk->drv.p->font_width)
[300]233        {
[539]234            glDisable(GL_TEXTURE_2D);
235            glColor4bv(gl_bgpal[attr[0] >> 4]);
236            glBegin(GL_QUADS);
237                glVertex2f(x, y);
[550]238                glVertex2f(x + kk->drv.p->font_width, y);
[557]239                glVertex2f(x + kk->drv.p->font_width,
240                           y + kk->drv.p->font_height);
[550]241                glVertex2f(x, y + kk->drv.p->font_height);
[539]242            glEnd();
[300]243
[539]244            attr++;
[303]245        }
[300]246
[539]247        line++;
[265]248    }
[227]249
[539]250    /* 2nd pass, avoids changing render state too much */
251    glEnable(GL_BLEND);
252    glEnable(GL_TEXTURE_2D);
253    glBlendFunc(GL_ONE, GL_ONE);
[336]254
[539]255    line = 0;
[550]256    for(y = 0; y < kk->drv.p->height; y += kk->drv.p->font_height)
[508]257    {
[539]258        uint8_t *attr = kk->qq->attr + line * kk->qq->width;
259        uint32_t *chars = kk->qq->chars + line * kk->qq->width;
[483]260
[550]261        for(x = 0; x < kk->drv.p->width; x += kk->drv.p->font_width)
[508]262        {
[557]263            uint32_t c = *chars++;
264
265            if(c > 0x00000020 && c < 0x00000080)
[539]266            {
[557]267                glBindTexture(GL_TEXTURE_2D, kk->drv.p->id[c - 32]);
[539]268                glColor4bv(gl_bgpal[attr[0] & 0xf]);
[488]269                glBegin(GL_QUADS);
[550]270                    glTexCoord2f(0, kk->drv.p->sh);
[511]271                    glVertex2f(x, y);
[550]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);
[558]275                    glVertex2f(x + kk->drv.p->font_width,
276                               y + kk->drv.p->font_height);
[539]277                    glTexCoord2f(0, 0);
[550]278                    glVertex2f(x, y + kk->drv.p->font_height);
[488]279                glEnd();
[508]280            }
[491]281
[539]282            attr++;
[508]283        }
[539]284        line++;
[508]285    }
[539]286    glDisable(GL_BLEND);
287    glDisable(GL_TEXTURE_2D);
[336]288
[539]289    glutMainLoopEvent();
290    glutSwapBuffers();
291    glutPostRedisplay();
[227]292}
293
[553]294static void gl_handle_resize(caca_t *kk)
[347]295{
[550]296    kk->drv.p->width = kk->drv.p->new_width;
297    kk->drv.p->height = kk->drv.p->new_height;
[349]298
[539]299    glMatrixMode(GL_PROJECTION);
300    glPushMatrix();
301    glLoadIdentity();
[354]302
[550]303    glViewport(0, 0, kk->drv.p->width, kk->drv.p->height);
304    gluOrtho2D(0, kk->drv.p->width, kk->drv.p->height, 0);
[539]305    glMatrixMode(GL_MODELVIEW);
[347]306}
307
[548]308static unsigned int gl_get_event(caca_t *kk)
309{
310    unsigned int event = 0;
311
312    glutMainLoopEvent();
313
[553]314    if(kk->resize.resized)
[548]315        return CACA_EVENT_RESIZE;
316
[550]317    if(kk->drv.p->mouse_changed)
[548]318    {
[550]319        if(kk->drv.p->mouse_clicked)
[548]320        {
[550]321            event |= CACA_EVENT_MOUSE_PRESS | kk->drv.p->mouse_button;
322            kk->drv.p->mouse_clicked = 0;
[548]323        }
[551]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;
[550]327        kk->drv.p->mouse_changed = 0;
[548]328    }
329
[550]330    if(kk->drv.p->key != 0)
[548]331    {
332        event |= CACA_EVENT_KEY_PRESS;
[550]333        event |= kk->drv.p->key;
334        kk->drv.p->key = 0;
[548]335        return event;
336    }
337
[550]338    if(kk->drv.p->special_key != 0)
[548]339    {
340        event |= CACA_EVENT_KEY_PRESS;
341
[550]342        switch(kk->drv.p->special_key)
[548]343        {
[550]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;
[548]360            default: return CACA_EVENT_NONE;
361        }
362    }
363    return CACA_EVENT_NONE;
364}
365
[539]366/*
367 * XXX: following functions are local
368 */
[281]369
[511]370static void gl_handle_keyboard(unsigned char key, int x, int y)
371{
[527]372    caca_t *kk = gl_kk;
373
[550]374    kk->drv.p->key = key;
[511]375}
376
377static void gl_handle_special_key(int key, int x, int y)
378{
[527]379    caca_t *kk = gl_kk;
380
[550]381    kk->drv.p->special_key = key;
[511]382}
383
384static void gl_handle_reshape(int w, int h)
385{
[527]386    caca_t *kk = gl_kk;
387
[550]388    if(kk->drv.p->bit) /* Do not handle reshaping at the first time */
[511]389    {
[550]390        kk->drv.p->new_width = w;
391        kk->drv.p->new_height = h;
[511]392
[553]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;
[511]397    }
398    else
[550]399        kk->drv.p->bit = 1;
[511]400}
401
402static void gl_handle_mouse(int button, int state, int x, int y)
403{
[527]404    caca_t *kk = gl_kk;
405
[550]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;
[511]412}
413
414static void gl_handle_mouse_motion(int x, int y)
415{
[527]416    caca_t *kk = gl_kk;
417
[550]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;
[511]421}
422
[539]423/*
424 * Driver initialisation
425 */
426
427void gl_init_driver(caca_t *kk)
428{
[550]429    kk->drv.driver = CACA_DRIVER_GL;
[539]430
[550]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;
[539]439}
440
441#endif /* USE_GL */
442
Note: See TracBrowser for help on using the repository browser.