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

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