~ubuntu-branches/ubuntu/quantal/mupen64plus/quantal

« back to all changes in this revision

Viewing changes to .pc/dejavu-font.patch/opengl/osd.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sven Eckelmann, Sven Eckelmann, Piotr Ożarowski
  • Date: 2010-05-06 11:34:46 UTC
  • mfrom: (3.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20100506113446-jfcd6uk7waudel82
Tags: 1.5+dfsg1-10
[ Sven Eckelmann ]
* debian/patches:
  - Add rsp_ucode2_reset.patch, Reset status of specific ucode2 hacks after
    starting again
  - Add rsp_hle_bigendian.patch, Fix wrong high level emulation of rsp on big
    endian systems
  - Add rice-crash-vendorstring.patch, Don't crash on long OpenGL vendor
    string (Closes: #580480, LP: #575968)

[ Piotr Ożarowski ]
* DMUA flag set to yes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
2
 *   Mupen64plus - osd.cpp                                                 *
 
3
 *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
 
4
 *   Copyright (C) 2008 Nmn Ebenblues                                      *
 
5
 *                                                                         *
 
6
 *   This program is free software; you can redistribute it and/or modify  *
 
7
 *   it under the terms of the GNU General Public License as published by  *
 
8
 *   the Free Software Foundation; either version 2 of the License, or     *
 
9
 *   (at your option) any later version.                                   *
 
10
 *                                                                         *
 
11
 *   This program is distributed in the hope that it will be useful,       *
 
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
14
 *   GNU General Public License for more details.                          *
 
15
 *                                                                         *
 
16
 *   You should have received a copy of the GNU General Public License     *
 
17
 *   along with this program; if not, write to the                         *
 
18
 *   Free Software Foundation, Inc.,                                       *
 
19
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 
20
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
21
 
 
22
// On-screen Display
 
23
#include <limits.h>
 
24
 
 
25
#include "OGLFT.h"
 
26
#include "osd.h"
 
27
 
 
28
extern "C" {
 
29
    #include "../main/main.h"
 
30
    #include "../main/plugin.h"
 
31
    #include "../main/util.h"
 
32
}
 
33
 
 
34
#define FONT_FILENAME "font.ttf"
 
35
 
 
36
#ifdef __WIN32__
 
37
# warning This hack should be fixed at some point
 
38
# define glActiveTexture(x)
 
39
#endif
 
40
 
 
41
// static variables for OSD
 
42
static int l_OsdInitialized = 0;
 
43
 
 
44
static list_t l_messageQueue = NULL;
 
45
static OGLFT::Monochrome *l_font;
 
46
static float l_fLineHeight = -1.0;
 
47
 
 
48
static void animation_none(osd_message_t *);
 
49
static void animation_fade(osd_message_t *);
 
50
 
 
51
static float fCornerScroll[OSD_NUM_CORNERS]; 
 
52
 
 
53
// animation handlers
 
54
static void (*l_animations[OSD_NUM_ANIM_TYPES])(osd_message_t *) = {
 
55
    animation_none, // animation handler for OSD_NONE
 
56
    animation_fade  // animation handler for OSD_FADE
 
57
};
 
58
 
 
59
// private functions
 
60
// draw message on screen
 
61
static void draw_message(osd_message_t *msg, int width, int height)
 
62
{
 
63
    float x = 0.,
 
64
          y = 0.;
 
65
 
 
66
    if(!l_font || !l_font->isValid())
 
67
        return;
 
68
 
 
69
    // set color. alpha is hard coded to 1. animation can change this
 
70
    l_font->setForegroundColor(msg->color[R], msg->color[G], msg->color[B], 1.0);
 
71
    l_font->setBackgroundColor(0.0, 0.0, 0.0, 0.0);
 
72
 
 
73
    // set justification based on corner
 
74
    switch(msg->corner)
 
75
    {
 
76
        case OSD_TOP_LEFT:
 
77
            l_font->setVerticalJustification(OGLFT::Face::TOP);
 
78
            l_font->setHorizontalJustification(OGLFT::Face::LEFT);
 
79
            x = 0.;
 
80
            y = (float)height;
 
81
            break;
 
82
        case OSD_TOP_CENTER:
 
83
            l_font->setVerticalJustification(OGLFT::Face::TOP);
 
84
            l_font->setHorizontalJustification(OGLFT::Face::CENTER);
 
85
            x = ((float)width)/2.0;
 
86
            y = (float)height;
 
87
            break;
 
88
        case OSD_TOP_RIGHT:
 
89
            l_font->setVerticalJustification(OGLFT::Face::TOP);
 
90
            l_font->setHorizontalJustification(OGLFT::Face::RIGHT);
 
91
            x = (float)width;
 
92
            y = (float)height;
 
93
            break;
 
94
        case OSD_MIDDLE_LEFT:
 
95
            l_font->setVerticalJustification(OGLFT::Face::MIDDLE);
 
96
            l_font->setHorizontalJustification(OGLFT::Face::LEFT);
 
97
            x = 0.;
 
98
            y = ((float)height)/2.0;
 
99
            break;
 
100
        case OSD_MIDDLE_CENTER:
 
101
            l_font->setVerticalJustification(OGLFT::Face::MIDDLE);
 
102
            l_font->setHorizontalJustification(OGLFT::Face::CENTER);
 
103
            x = ((float)width)/2.0;
 
104
            y = ((float)height)/2.0;
 
105
            break;
 
106
        case OSD_MIDDLE_RIGHT:
 
107
            l_font->setVerticalJustification(OGLFT::Face::MIDDLE);
 
108
            l_font->setHorizontalJustification(OGLFT::Face::RIGHT);
 
109
            x = (float)width;
 
110
            y = ((float)height)/2.0;
 
111
            break;
 
112
        case OSD_BOTTOM_LEFT:
 
113
            l_font->setVerticalJustification(OGLFT::Face::BOTTOM);
 
114
            l_font->setHorizontalJustification(OGLFT::Face::LEFT);
 
115
            x = 0.;
 
116
            y = 0.;
 
117
            break;
 
118
        case OSD_BOTTOM_CENTER:
 
119
            l_font->setVerticalJustification(OGLFT::Face::BOTTOM);
 
120
            l_font->setHorizontalJustification(OGLFT::Face::CENTER);
 
121
            x = ((float)width)/2.0;
 
122
            y = 0.;
 
123
            break;
 
124
        case OSD_BOTTOM_RIGHT:
 
125
            l_font->setVerticalJustification(OGLFT::Face::BOTTOM);
 
126
            l_font->setHorizontalJustification(OGLFT::Face::RIGHT);
 
127
            x = (float)width;
 
128
            y = 0.;
 
129
            break;
 
130
        default:
 
131
            l_font->setVerticalJustification(OGLFT::Face::BOTTOM);
 
132
            l_font->setHorizontalJustification(OGLFT::Face::LEFT);
 
133
            x = 0.;
 
134
            y = 0.;
 
135
            break;
 
136
    }
 
137
 
 
138
    // apply animation for current message state
 
139
    (*l_animations[msg->animation[msg->state]])(msg);
 
140
 
 
141
    // xoffset moves message left
 
142
    x -= msg->xoffset;
 
143
    // yoffset moves message up
 
144
    y += msg->yoffset;
 
145
 
 
146
    // get the bounding box if invalid
 
147
    if (msg->sizebox[0] == 0 && msg->sizebox[2] == 0)  // xmin and xmax
 
148
    {
 
149
        OGLFT::BBox bbox = l_font->measure_nominal(msg->text);
 
150
        msg->sizebox[0] = bbox.x_min_;
 
151
        msg->sizebox[1] = bbox.y_min_;
 
152
        msg->sizebox[2] = bbox.x_max_;
 
153
        msg->sizebox[3] = bbox.y_max_;
 
154
    }
 
155
 
 
156
    // draw the text line
 
157
    l_font->draw(x, y, msg->text, msg->sizebox);
 
158
}
 
159
 
 
160
// null animation handler
 
161
static void animation_none(osd_message_t *msg) { }
 
162
 
 
163
// fade in/out animation handler
 
164
static void animation_fade(osd_message_t *msg)
 
165
{
 
166
    float alpha = 1.;
 
167
    float elapsed_frames;
 
168
    float total_frames = (float)msg->timeout[msg->state];
 
169
 
 
170
    switch(msg->state)
 
171
    {
 
172
        case OSD_DISAPPEAR:
 
173
            elapsed_frames = (float)(total_frames - msg->frames);
 
174
            break;
 
175
        case OSD_APPEAR:
 
176
        default:
 
177
            elapsed_frames = (float)msg->frames;
 
178
            break;
 
179
    }
 
180
 
 
181
    if(total_frames != 0.)
 
182
        alpha = elapsed_frames / total_frames;
 
183
 
 
184
    l_font->setForegroundColor(msg->color[R], msg->color[G], msg->color[B], alpha);
 
185
}
 
186
 
 
187
// sets message Y offset depending on where they are in the message queue
 
188
static float get_message_offset(osd_message_t *msg, float fLinePos)
 
189
{
 
190
    float offset = l_font->height() * fLinePos;
 
191
 
 
192
    switch(msg->corner)
 
193
    {
 
194
        case OSD_TOP_LEFT:
 
195
        case OSD_TOP_CENTER:
 
196
        case OSD_TOP_RIGHT:
 
197
            return -offset;
 
198
            break;
 
199
        default:
 
200
            return offset;
 
201
            break;
 
202
    }
 
203
}
 
204
 
 
205
// public functions
 
206
extern "C"
 
207
void osd_init(int width, int height)
 
208
{
 
209
    char fontpath[PATH_MAX];
 
210
 
 
211
    snprintf(fontpath, PATH_MAX, "%sfonts/%s", get_installpath(), FONT_FILENAME);
 
212
    l_font = new OGLFT::Monochrome(fontpath, height / 35);  // make font size proportional to screen height
 
213
 
 
214
    if(!l_font || !l_font->isValid())
 
215
    {
 
216
        printf("Could not construct face from %s\n", fontpath);
 
217
        return;
 
218
    }
 
219
 
 
220
    // clear statics
 
221
    for (int i = 0; i < OSD_NUM_CORNERS; i++)
 
222
        fCornerScroll[i] = 0.0;
 
223
 
 
224
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
225
#if defined(GL_RASTER_POSITION_UNCLIPPED_IBM)
 
226
    glEnable(GL_RASTER_POSITION_UNCLIPPED_IBM);
 
227
#endif
 
228
 
 
229
    // set initialized flag
 
230
    l_OsdInitialized = 1;
 
231
}
 
232
 
 
233
extern "C"
 
234
void osd_exit(void)
 
235
{
 
236
    list_node_t *node;
 
237
    osd_message_t *msg;
 
238
 
 
239
    // delete font renderer
 
240
    if (l_font)
 
241
    {
 
242
        delete l_font;
 
243
        l_font = NULL;
 
244
    }
 
245
 
 
246
    // delete message queue
 
247
    list_foreach(l_messageQueue, node)
 
248
    {
 
249
        msg = (osd_message_t *)node->data;
 
250
 
 
251
        if(msg->text)
 
252
            free(msg->text);
 
253
        free(msg);
 
254
    }
 
255
    list_delete(&l_messageQueue);
 
256
 
 
257
    // reset initialized flag
 
258
    l_OsdInitialized = 0;
 
259
}
 
260
 
 
261
// renders the current osd message queue to the screen
 
262
extern "C"
 
263
void osd_render()
 
264
{
 
265
    list_node_t *node;
 
266
    osd_message_t *msg, *msg_to_delete = NULL;
 
267
    int i;
 
268
 
 
269
    // if we're not initialized or list is empty, then just skip it all
 
270
    if (!l_OsdInitialized || l_messageQueue == NULL)
 
271
        return;
 
272
 
 
273
    // get the viewport dimensions
 
274
    GLint viewport[4];
 
275
    glGetIntegerv(GL_VIEWPORT, viewport);
 
276
 
 
277
    // save all the attributes
 
278
    glPushAttrib(GL_ALL_ATTRIB_BITS);
 
279
    bool bFragmentProg = glIsEnabled(GL_FRAGMENT_PROGRAM_ARB);
 
280
    bool bColorArray = glIsEnabled(GL_COLOR_ARRAY);
 
281
    bool bTexCoordArray = glIsEnabled(GL_TEXTURE_COORD_ARRAY);
 
282
    bool bSecColorArray = glIsEnabled(GL_SECONDARY_COLOR_ARRAY);
 
283
 
 
284
    // deactivate all the texturing units
 
285
    GLint  iActiveTex;
 
286
    bool bTexture2D[8];
 
287
    glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &iActiveTex);
 
288
    for (i = 0; i < 8; i++)
 
289
    {
 
290
        glActiveTexture(GL_TEXTURE0_ARB + i);
 
291
        bTexture2D[i] = glIsEnabled(GL_TEXTURE_2D);
 
292
        glDisable(GL_TEXTURE_2D);
 
293
    }
 
294
 
 
295
    // save the matrices and set up new ones
 
296
    glMatrixMode(GL_PROJECTION);
 
297
    glPushMatrix();
 
298
    glLoadIdentity();
 
299
    gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);
 
300
 
 
301
    glMatrixMode(GL_MODELVIEW);
 
302
    glPushMatrix();
 
303
    glLoadIdentity();
 
304
 
 
305
    // setup for drawing text
 
306
    glDisable(GL_FOG);
 
307
    glDisable(GL_LIGHTING);
 
308
    glDisable(GL_DEPTH_TEST);
 
309
    glDisable(GL_CULL_FACE);
 
310
    glDisable(GL_SCISSOR_TEST);
 
311
    glDisable(GL_STENCIL_TEST);
 
312
    glDisable(GL_FRAGMENT_PROGRAM_ARB);
 
313
    glDisable(GL_REGISTER_COMBINERS_NV);
 
314
    glDisable(GL_COLOR_MATERIAL);
 
315
 
 
316
    glEnable(GL_BLEND);
 
317
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
318
 
 
319
    glDisableClientState(GL_COLOR_ARRAY);
 
320
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
321
    glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
 
322
    glShadeModel(GL_FLAT);
 
323
 
 
324
    // get line height if invalid
 
325
    if (l_fLineHeight < 0.0)
 
326
    {
 
327
        OGLFT::BBox bbox = l_font->measure("01abjZpqRGB");
 
328
        l_fLineHeight = (bbox.y_max_ - bbox.y_min_) / 30.0;
 
329
    }
 
330
 
 
331
    // keeps track of next message position for each corner
 
332
    float fCornerPos[OSD_NUM_CORNERS];
 
333
    for (i = 0; i < OSD_NUM_CORNERS; i++)
 
334
        fCornerPos[i] = 0.5 * l_fLineHeight;
 
335
 
 
336
    list_foreach(l_messageQueue, node)
 
337
    {
 
338
        msg = (osd_message_t *)node->data;
 
339
 
 
340
        // if previous message was marked for deletion, delete it
 
341
        if(msg_to_delete)
 
342
        {
 
343
            osd_delete_message(msg_to_delete);
 
344
            msg_to_delete = NULL;
 
345
        }
 
346
 
 
347
        // update message state
 
348
        if(msg->timeout[msg->state] != OSD_INFINITE_TIMEOUT &&
 
349
           ++msg->frames >= msg->timeout[msg->state])
 
350
        {
 
351
            // if message is in last state, mark it for deletion and continue to the next message
 
352
            if(msg->state >= OSD_NUM_STATES - 1)
 
353
            {
 
354
                msg_to_delete = msg;
 
355
                continue;
 
356
            }
 
357
 
 
358
            // go to next state and reset frame count
 
359
            msg->state++;
 
360
            msg->frames = 0;
 
361
        }
 
362
 
 
363
        // offset y depending on how many other messages are in the same corner
 
364
        float fStartOffset;
 
365
        if (msg->corner >= OSD_MIDDLE_LEFT && msg->corner <= OSD_MIDDLE_RIGHT)  // don't scroll the middle messages
 
366
            fStartOffset = fCornerPos[msg->corner];
 
367
        else
 
368
            fStartOffset = fCornerPos[msg->corner] + (fCornerScroll[msg->corner] * l_fLineHeight);
 
369
        msg->yoffset += get_message_offset(msg, fStartOffset);
 
370
 
 
371
        draw_message(msg, viewport[2], viewport[3]);
 
372
 
 
373
        msg->yoffset -= get_message_offset(msg, fStartOffset);
 
374
        fCornerPos[msg->corner] += l_fLineHeight;
 
375
    }
 
376
 
 
377
    // do the scrolling
 
378
    for (int i = 0; i < OSD_NUM_CORNERS; i++)
 
379
    {
 
380
        fCornerScroll[i] += 0.1;
 
381
        if (fCornerScroll[i] >= 0.0)
 
382
            fCornerScroll[i] = 0.0;
 
383
    }
 
384
 
 
385
    // if last message was marked for deletion, delete it
 
386
    if(msg_to_delete)
 
387
        osd_delete_message(msg_to_delete);
 
388
 
 
389
    // restore the matrices
 
390
    glMatrixMode(GL_MODELVIEW);
 
391
    glPopMatrix();
 
392
    glMatrixMode(GL_PROJECTION);
 
393
    glPopMatrix();
 
394
 
 
395
    // restore the attributes
 
396
    for (int i = 0; i < 8; i++)
 
397
    {
 
398
        glActiveTexture(GL_TEXTURE0_ARB + i);
 
399
        if (bTexture2D[i])
 
400
            glEnable(GL_TEXTURE_2D);
 
401
        else
 
402
            glDisable(GL_TEXTURE_2D);
 
403
    }
 
404
    glActiveTexture(iActiveTex);
 
405
    glPopAttrib();
 
406
    if (bFragmentProg)
 
407
        glEnable(GL_FRAGMENT_PROGRAM_ARB);
 
408
    if (bColorArray)
 
409
        glEnableClientState(GL_COLOR_ARRAY);
 
410
    if (bTexCoordArray)
 
411
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
412
    if (bSecColorArray)
 
413
        glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
 
414
 
 
415
    glFinish();
 
416
}
 
417
 
 
418
// creates a new osd_message_t, adds it to the message queue and returns it in case
 
419
// the user wants to modify its parameters. Note, if the message can't be created,
 
420
// NULL is returned.
 
421
extern "C"
 
422
osd_message_t * osd_new_message(enum osd_corner eCorner, const char *fmt, ...)
 
423
{
 
424
    va_list ap;
 
425
    char buf[PATH_MAX];
 
426
 
 
427
    if (!l_OsdInitialized) return NULL;
 
428
 
 
429
    osd_message_t *msg = (osd_message_t *)malloc(sizeof(osd_message_t));
 
430
 
 
431
    if (!msg) return NULL;
 
432
 
 
433
    va_start(ap, fmt);
 
434
    vsnprintf(buf, PATH_MAX, fmt, ap);
 
435
    va_end(ap);
 
436
 
 
437
    // set default values
 
438
    memset(msg, 0, sizeof(osd_message_t));
 
439
    msg->text = strdup(buf);
 
440
    // default to white
 
441
    msg->color[R] = 1.;
 
442
    msg->color[G] = 1.;
 
443
    msg->color[B] = 1.;
 
444
 
 
445
    msg->sizebox[0] = 0.0;  // set a null bounding box
 
446
    msg->sizebox[1] = 0.0;
 
447
    msg->sizebox[2] = 0.0;
 
448
    msg->sizebox[3] = 0.0;
 
449
 
 
450
    msg->corner = eCorner;
 
451
    msg->state = OSD_APPEAR;
 
452
    fCornerScroll[eCorner] -= 1.0;  // start this one before the beginning of the list and scroll it in
 
453
 
 
454
    msg->animation[OSD_APPEAR] = OSD_FADE;
 
455
    msg->animation[OSD_DISPLAY] = OSD_NONE;
 
456
    msg->animation[OSD_DISAPPEAR] = OSD_FADE;
 
457
 
 
458
    if (eCorner >= OSD_MIDDLE_LEFT && eCorner <= OSD_MIDDLE_RIGHT)
 
459
    {
 
460
        msg->timeout[OSD_APPEAR] = 20;
 
461
        msg->timeout[OSD_DISPLAY] = 60;
 
462
        msg->timeout[OSD_DISAPPEAR] = 20;
 
463
    }
 
464
    else
 
465
    {
 
466
        msg->timeout[OSD_APPEAR] = 20;
 
467
        msg->timeout[OSD_DISPLAY] = 180;
 
468
        msg->timeout[OSD_DISAPPEAR] = 40;
 
469
    }
 
470
 
 
471
    // add to message queue
 
472
    list_prepend(&l_messageQueue, msg);
 
473
 
 
474
    return msg;
 
475
}
 
476
 
 
477
// update message string
 
478
extern "C"
 
479
void osd_update_message(osd_message_t *msg, const char *fmt, ...)
 
480
{
 
481
    va_list ap;
 
482
    char buf[PATH_MAX];
 
483
 
 
484
    if (!l_OsdInitialized || !msg) return;
 
485
 
 
486
    va_start(ap, fmt);
 
487
    vsnprintf(buf, PATH_MAX, fmt, ap);
 
488
    va_end(ap);
 
489
 
 
490
    if(msg->text)
 
491
        free(msg->text);
 
492
 
 
493
    msg->text = strdup(buf);
 
494
 
 
495
    // reset bounding box
 
496
    msg->sizebox[0] = 0.0;
 
497
    msg->sizebox[1] = 0.0;
 
498
    msg->sizebox[2] = 0.0;
 
499
    msg->sizebox[3] = 0.0;
 
500
 
 
501
    // reset display time counter
 
502
    if (msg->state >= OSD_DISPLAY)
 
503
    {
 
504
        msg->state = OSD_DISPLAY;
 
505
        msg->frames = 0;
 
506
    }
 
507
 
 
508
}
 
509
 
 
510
// remove message from message queue
 
511
extern "C"
 
512
void osd_delete_message(osd_message_t *msg)
 
513
{
 
514
    list_node_t *node;
 
515
 
 
516
    if (!l_OsdInitialized || !msg) return;
 
517
 
 
518
    if (msg->text)
 
519
        free(msg->text);
 
520
 
 
521
    node = list_find_node(l_messageQueue, msg);
 
522
    free(msg);
 
523
    list_node_delete(&l_messageQueue, node);
 
524
}
 
525
 
 
526
// set "corner" of the screen that message appears in.
 
527
extern "C"
 
528
void osd_message_set_corner(osd_message_t *msg, enum osd_corner corner)
 
529
{
 
530
    if (!l_OsdInitialized || !msg) return;
 
531
 
 
532
    msg->corner = corner;
 
533
}
 
534
 
 
535
// set message so it doesn't automatically expire in a certain number of frames.
 
536
extern "C"
 
537
void osd_message_set_static(osd_message_t *msg)
 
538
{
 
539
    if (!l_OsdInitialized || !msg) return;
 
540
 
 
541
    msg->timeout[OSD_DISPLAY] = OSD_INFINITE_TIMEOUT;
 
542
    msg->state = OSD_DISPLAY;
 
543
    msg->frames = 0;
 
544
}
 
545
 
 
546
// return message pointer if valid (in the OSD list), otherwise return NULL
 
547
extern "C"
 
548
osd_message_t * osd_message_valid(osd_message_t *testmsg)
 
549
{
 
550
    if (!l_OsdInitialized || !testmsg) return NULL;
 
551
 
 
552
    if (list_find_node(l_messageQueue, testmsg) == NULL)
 
553
        return NULL;
 
554
    else
 
555
        return testmsg;
 
556
}
 
557