Avoid non-alpha characters in _qdgdfv_alnum in win32.
[qdgdf.git] / qdgdf_video.c
blob9f0e00eb19be222a0740c6009a0275967df29c27
1 /*
3 Quick and Dirty Game Development Framework (QDGDF)
5 Copyright (C) 2001/2011 Angel Ortega <angel@triptico.com>
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 http://www.triptico.com
25 #include "config.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
32 #include "qdgdf_video.h"
35 /** data **/
37 /**
38 * _qdgdfv_fopen_path - Search path for qdgdfv_fopen().
40 * This string can contain a semicolon-separated list of paths
41 * where files to be open with qdgdfv_fopen() will be tried
42 * before banging.
43 * [Support Variables]
45 char _qdgdfv_fopen_path[250] = "";
47 /**
48 * _qdgdfv_virtual_screen - The virtual screen.
50 * This variable points to a buffer of (_qdgdfv_screen_x_size *
51 * _qdgdfv_screen_y_size) unsigned chars. All video operations are
52 * done over this space. To dump it to the real screen, use
53 * qdgdfv_dump_virtual_screen().
54 * [Video Variables]
56 unsigned char *_qdgdfv_virtual_screen = NULL;
58 /**
59 * _qdgdfv_clear_color - The clear color.
61 * This color will be used to clear the screen when using
62 * qdgdfv_clear_virtual_screen().
63 * [Video Variables]
65 unsigned char _qdgdfv_clear_color = 0;
67 /**
68 * _qdgdfv_screen_x_size - Horizontal screen size.
70 * This variable holds the horizontal screen size in pixels. It can be
71 * set to whatever wanted before the startup. The real horizontal
72 * screen size will be stored here after the startup (it can be a
73 * different value).
74 * [Video Variables]
76 unsigned int _qdgdfv_screen_x_size = 320;
78 /**
79 * _qdgdfv_screen_y_size - Vertical screen size.
81 * This variable holds the vertical screen size in pixels. It can be
82 * set to whatever wanted before the startup. The real vertical
83 * screen size will be stored here after the startup (it can be a
84 * different value).
85 * [Video Variables]
87 unsigned int _qdgdfv_screen_y_size = 200;
89 /**
90 * _qdgdfv_window_x - Initial x position of the window.
92 * This variable must be set before startup and holds the desired
93 * initial position of the window. Not all supported systems let
94 * this be set (some of them even have no window at all, just
95 * fullscreen graphics), so it's purely orientative there.
96 * [Video Variables]
98 int _qdgdfv_window_x = 60;
101 * _qdgdfv_window_y - Initial y position of the window.
103 * This variable must be set before startup and holds the desired
104 * initial position of the window. Not all supported systems let
105 * this be set (some of them even have no window at all, just
106 * fullscreen graphics), so it's purely orientative there.
107 * [Video Variables]
109 int _qdgdfv_window_y = 60;
113 * _qdgdfv_scale - Sets the scale.
115 * Sets the scale. If not set, a 1 scale (no scale) will be tried;
116 * if it's impossible to set due to hardware limitations (for example,
117 * a 320x200 resolution has been requested and current hardware don't
118 * support it, but can do 640x400), a 2 scale (double) will be tried.
119 * Some drivers allow even bigger scales.
121 * This variable obsoletes the old _qdgdfv_double_mode.
122 * [Video Variables]
124 int _qdgdfv_scale = 0;
127 * _qdgdfv_double_mode - Sets the double mode.
129 * The use of this variable is deprecated. Use _qdgdfv_scale instead.
130 * [Video Variables]
132 int _qdgdfv_double_mode = 0;
135 * _qdgdfv_double_antialias - Antialias flag for double modes.
137 * If you set this variable, double modes will be dumped using
138 * a basic antialiasing mechanism, if the video driver implements one.
139 * [Video Variables]
141 int _qdgdfv_double_antialias = 0;
144 * _qdgdfv_scale2x - Scale2x algorithm flag.
146 * When set, double screen dumping is done by using the scale2x
147 * algorithm (read about it at http://scale2x.sourceforge.net).
148 * It's set by default.
149 * [Video Variables]
151 int _qdgdfv_scale2x = 1;
154 * _qdgdfv_window_title - Title for the window.
156 * This string holds the title for the window. Take note
157 * that some systems are fullscreen and has no window titles.
158 * [Video Variables]
160 char _qdgdfv_window_title[150] = "qdgdf Window";
163 * _qdgdfv_additional_info - Additional string info for the driver.
165 * This string can be filled with some information for the driver.
166 * Its content is purposely driver dependent and can contain,
167 * for example, the remote X Window display.
168 * [Video Variables]
170 char _qdgdfv_additional_info[150] = "";
173 * _qdgdfv_additional_int_info - Additional integer info for the driver.
175 * This integer can be filled with some information for the driver.
176 * Its content is purposely driver dependent and can contain,
177 * for example, the Windows instance handler.
178 * [Video Variables]
180 int _qdgdfv_additional_int_info = 0;
183 * _qdgdfv_gamma_correct - Gamma correction.
185 * This variable containts the amount of gamma correction to
186 * be applied when colors are created. It ranges from 0 (colors as
187 * defined in the palette) to 255 (absolutely saturate).
189 int _qdgdfv_gamma_correct = 0;
191 /* the keys */
194 * _qdgdfv_key_ - The key flags.
196 * This variables are set by qdgdfv_input_poll() accordingly to
197 * the current keyboard status. These variables are:
198 * _qdgdfv_key_up, _qdgdfv_key_down, _qdgdfv_key_left,
199 * _qdgdfv_key_right, _qdgdfv_key_escape, _qdgdfv_key_space,
200 * _qdgdfv_key_enter, _qdgdfv_key_control_l, _qdgdfv_key_control_r,
201 * _qdgdfv_key_control, _qdgdfv_key_shift_l, _qdgdfv_key_shift_r,
202 * _qdgdfv_key_pgup, _qdgdfv_key_pgdn, _qdgdfv_key_home, _qdgdfv_key_end
203 * and _qdgdfv_key_f1 to f10.
204 * [Keyboard Variables]
206 int _qdgdfv_key_up = 0;
207 int _qdgdfv_key_down = 0;
208 int _qdgdfv_key_left = 0;
209 int _qdgdfv_key_right = 0;
210 int _qdgdfv_key_escape = 0;
211 int _qdgdfv_key_space = 0;
212 int _qdgdfv_key_enter = 0;
213 int _qdgdfv_key_control_l = 0;
214 int _qdgdfv_key_control_r = 0;
215 int _qdgdfv_key_pgup = 0;
216 int _qdgdfv_key_pgdn = 0;
217 int _qdgdfv_key_home = 0;
218 int _qdgdfv_key_end = 0;
219 int _qdgdfv_key_f1 = 0;
220 int _qdgdfv_key_f2 = 0;
221 int _qdgdfv_key_f3 = 0;
222 int _qdgdfv_key_f4 = 0;
223 int _qdgdfv_key_f5 = 0;
224 int _qdgdfv_key_f6 = 0;
225 int _qdgdfv_key_f7 = 0;
226 int _qdgdfv_key_f8 = 0;
227 int _qdgdfv_key_f9 = 0;
228 int _qdgdfv_key_f10 = 0;
230 /* Dan Compton added these changes */
231 int _qdgdfv_key_control = 0;
232 int _qdgdfv_key_shift_l = 0;
233 int _qdgdfv_key_shift_r = 0;
234 int _qdgdfv_key_alnum = 0;
235 char _qdgdfv_alnum = 0;
236 /* End changes */
238 /* extended key information */
239 static struct __qdgdfv_extended_key_status {
240 int *key_var; /* pointer to key variable */
241 int last_val; /* last seen value */
242 } _qdgdfv_extended_key_status[] = {
243 { &_qdgdfv_key_up, 0},
244 { &_qdgdfv_key_down, 0},
245 { &_qdgdfv_key_left, 0},
246 { &_qdgdfv_key_right, 0},
247 { &_qdgdfv_key_escape, 0},
248 { &_qdgdfv_key_space, 0},
249 { &_qdgdfv_key_enter, 0},
250 { &_qdgdfv_key_control_l, 0},
251 { &_qdgdfv_key_control_r, 0},
252 { &_qdgdfv_key_pgup, 0},
253 { &_qdgdfv_key_pgdn, 0},
254 { &_qdgdfv_key_home, 0},
255 { &_qdgdfv_key_end, 0},
256 { &_qdgdfv_key_f1, 0},
257 { &_qdgdfv_key_f2, 0},
258 { &_qdgdfv_key_f3, 0},
259 { &_qdgdfv_key_f4, 0},
260 { &_qdgdfv_key_f5, 0},
261 { &_qdgdfv_key_f6, 0},
262 { &_qdgdfv_key_f7, 0},
263 { &_qdgdfv_key_f8, 0},
264 { &_qdgdfv_key_f9, 0},
265 { &_qdgdfv_key_f10, 0},
266 { &_qdgdfv_key_control, 0},
267 { &_qdgdfv_key_shift_l, 0},
268 { &_qdgdfv_key_shift_r, 0},
269 { NULL, 0}
273 /** static data **/
275 /* the palette. Includes by default the original palette from
276 the never-finished game Freak Wars (256*rgb) */
278 unsigned int _qdgdfv_palette[256 * 3] = {
279 0, 0, 0, 28, 24, 12, 20, 16, 8, 68, 68, 68, 255, 224, 0, 24, 24, 24,
280 16, 20, 20, 8, 12, 12, 4, 8, 8, 40, 52, 28, 32, 40, 16, 20, 28, 8,
281 12, 24, 0, 68, 56, 40, 64, 48, 32, 56, 40, 24, 255, 69, 0, 220, 152, 152,
282 216, 148, 148, 208, 136, 136, 204, 128, 128, 196, 120, 120, 196, 112, 112,
283 188, 104, 104, 180, 96, 96, 176, 88, 88, 168, 84, 84, 164, 80, 80,
284 160, 72, 72, 156, 64, 64, 148, 56, 56, 144, 56, 56, 136, 48, 48,
285 132, 44, 44, 128, 40, 40, 124, 32, 32, 116, 28, 28, 112, 24, 24,
286 104, 24, 24, 100, 20, 20, 96, 16, 16, 92, 12, 12, 84, 8, 8, 80, 8, 8,
287 72, 8, 8, 68, 0, 0, 64, 0, 0, 255, 191, 0, 228, 212, 200, 228, 204, 188,
288 228, 196, 180, 228, 188, 168, 228, 184, 160, 228, 180, 152, 228, 172, 140,
289 228, 168, 132, 228, 160, 120, 220, 152, 112, 212, 148, 104, 204, 140, 96,
290 196, 132, 88, 192, 124, 84, 184, 120, 76, 180, 116, 72, 168, 112, 68,
291 160, 104, 64, 152, 100, 60, 144, 96, 56, 136, 88, 56, 128, 88, 52,
292 120, 80, 48, 112, 76, 44, 104, 72, 40, 96, 64, 36, 84, 60, 32, 72, 56, 28,
293 68, 52, 24, 56, 44, 24, 44, 40, 20, 36, 32, 16, 212, 216, 216,
294 204, 208, 208, 196, 200, 200, 196, 196, 196, 188, 188, 188, 180, 184, 184,
295 176, 180, 180, 168, 172, 172, 164, 164, 164, 160, 160, 160, 152, 152, 152,
296 148, 152, 152, 140, 144, 144, 132, 136, 136, 132, 132, 132, 124, 124, 124,
297 116, 120, 120, 112, 116, 116, 104, 108, 108, 100, 100, 100, 96, 96, 96,
298 88, 88, 88, 80, 84, 84, 76, 80, 80, 68, 72, 72, 64, 64, 64, 60, 60, 60,
299 52, 56, 56, 48, 52, 52, 40, 44, 44, 36, 36, 36, 32, 32, 32, 255, 89, 0,
300 100, 216, 92, 92, 200, 88, 84, 184, 80, 80, 172, 72, 72, 156, 64,
301 68, 144, 56, 60, 132, 52, 56, 120, 44, 48, 104, 40, 40, 88, 32,
302 36, 76, 24, 28, 60, 24, 20, 48, 16, 16, 32, 12, 255, 29, 0, 168, 152, 128,
303 164, 144, 120, 156, 136, 116, 148, 128, 108, 140, 120, 100, 136, 116, 96,
304 132, 112, 88, 124, 104, 84, 116, 96, 80, 108, 88, 72, 104, 88, 68,
305 100, 80, 60, 92, 76, 56, 84, 68, 52, 76, 60, 48, 72, 56, 44, 140, 120, 88,
306 128, 108, 76, 116, 96, 68, 104, 88, 56, 92, 76, 48, 80, 64, 40,
307 68, 56, 32, 60, 48, 24, 108, 116, 88, 100, 104, 80, 92, 96, 72,
308 80, 88, 64, 72, 80, 56, 64, 72, 48, 56, 64, 40, 48, 56, 36, 228, 228, 104,
309 208, 196, 80, 192, 168, 60, 172, 140, 44, 156, 112, 28, 136, 84, 20,
310 120, 60, 8, 100, 40, 0, 228, 228, 228, 228, 196, 196, 228, 168, 168,
311 228, 140, 140, 228, 112, 112, 228, 88, 88, 228, 56, 56, 228, 28, 28,
312 228, 0, 0, 212, 0, 0, 200, 0, 0, 192, 0, 0, 180, 0, 0, 168, 0, 0,
313 160, 0, 0, 148, 0, 0, 136, 0, 0, 124, 0, 0, 112, 0, 0, 100, 0, 0,
314 92, 0, 0, 80, 0, 0, 68, 0, 0, 60, 0, 0, 204, 208, 228, 176, 180, 228,
315 152, 152, 228, 128, 128, 228, 100, 104, 228, 72, 76, 228, 48, 52, 228,
316 24, 24, 228, 0, 0, 228, 0, 0, 204, 0, 0, 184, 0, 0, 160, 0, 0, 140,
317 0, 0, 120, 0, 0, 96, 0, 0, 76, 228, 228, 228, 228, 212, 196, 228, 192, 168,
318 228, 180, 140, 228, 160, 112, 228, 148, 84, 228, 128, 56, 228, 116, 24,
319 216, 104, 24, 208, 100, 16, 196, 92, 16, 192, 88, 12, 180, 80, 8,
320 172, 72, 0, 164, 64, 0, 156, 60, 0, 228, 228, 228, 228, 228, 192,
321 228, 228, 160, 228, 228, 128, 228, 228, 96, 228, 228, 64, 228, 228, 32,
322 228, 228, 0, 148, 56, 0, 140, 52, 0, 132, 44, 0, 120, 32, 0, 68, 56, 36,
323 60, 44, 24, 48, 32, 20, 40, 24, 12, 255, 204, 0, 0, 0, 64, 0, 0, 56,
324 0, 0, 44, 0, 0, 32, 0, 0, 24, 0, 0, 12, 148, 96, 96, 228, 144, 60,
325 228, 208, 68, 255, 181, 0, 255, 159, 0, 255, 139, 0, 255, 119, 0,
326 255, 109, 0, 255, 0, 255
330 * _qdgdfv_use_logger - Logger use flag.
332 * If this variable is set, the logger will be active.
333 * [Support Variables]
335 int _qdgdfv_use_logger = 1;
338 * _qdgdfv_logger_file - Logger file.
340 * This string holds the path of the logger file.
341 * [Support Variables]
343 char _qdgdfv_logger_file[150] = "";
345 char *_qdgdfv_version = VERSION;
349 * _qdgdfv_accum_buffer - Accumulation buffer.
351 * This buffer holds the last dumped virtual screen if
352 * the accumulation buffer is used, or a NULL pointer
353 * otherwise. It's rarely used directly, as the accumulation
354 * buffer is treated transparently.
355 * [Video Variables]
357 unsigned char *_qdgdfv_accum_buffer = NULL;
359 unsigned char _qdgdfv_accum_table[256][256];
361 /* the extended palette (for 15, 16, 24 and 32 bpp) */
362 unsigned int _qdgdfv_extended_palette[256];
364 /* pixel size (1, 2 or 4) */
365 int _qdgdfv_pixel_size;
367 /* video driver */
368 static struct _qdgdfv_driver *drv = NULL;
370 /* masks and shifts for pixel sizes > 1 */
371 unsigned int _qdgdfv_red_mask;
372 unsigned int _qdgdfv_green_mask;
373 unsigned int _qdgdfv_blue_mask;
374 int _qdgdfv_red_shift;
375 int _qdgdfv_green_shift;
376 int _qdgdfv_blue_shift;
379 * _qdgdfv_full_screen - Full screen flag.
381 * When set before initialization, it expresses the preference
382 * of running full screen or not (a value of -1 means it doesn't matter).
383 * After initialization, contains what really happened.
385 int _qdgdfv_full_screen = -1;
388 /** code **/
390 #include "qdgdf_path.c"
392 /** basic tools **/
395 * qdgdfv_sprintf - Static sprintf.
396 * @fmt: the format string
398 * Formats a string, using sprintf.
399 * A static buffer is returned.
400 * [Support Functions]
402 char *qdgdfv_sprintf(char *fmt, ...)
404 static char sp_buf[4096];
405 va_list argptr;
407 va_start(argptr, fmt);
408 vsprintf(sp_buf, fmt, argptr);
409 va_end(argptr);
411 return sp_buf;
416 * qdgdfv_logger - Logs a message.
417 * @where: caller function name
418 * @msg: message
420 * Logs the @message to the logger file, usually an error.
421 * [Support Functions]
423 void qdgdfv_logger(char *where, char *msg)
425 FILE *f;
427 if (_qdgdfv_use_logger && _qdgdfv_logger_file[0] != '\0') {
428 if ((f = fopen(_qdgdfv_logger_file, "a")) != NULL) {
429 fprintf(f, "%s: %s\n", where, msg);
431 fclose(f);
438 * qdgdfv_bang - Bangs on unrecoverable problems.
439 * @where: caller function name
440 * @msg: message
442 * Logs the @message to the logger and returns to the system.
443 * [Support Functions]
445 void qdgdfv_bang(char *where, char *msg)
447 qdgdfv_logger(where, msg);
449 printf("\nBANG! %s: %s\n", where, msg);
450 fflush(stdout);
452 exit(1);
457 * qdgdfv_malloc - 'Secure' malloc.
458 * @size: the size of the block to malloc
460 * Tries to alloc the desired memory @size and, if not succesful,
461 * bangs out to the system. This make unnecesary to test if
462 * the block could be allocated.
463 * Returns the allocated block.
464 * [Support Functions]
466 void *qdgdfv_malloc(int size)
468 void *ptr;
470 ptr = malloc(size);
472 if (!ptr)
473 qdgdfv_bang("a_malloc", "Out of memory");
475 return ptr;
479 FILE *_qdgdfv_fopen(char *file, char *mode)
481 return _path_fopen(_qdgdfv_fopen_path, file, mode);
486 * qdgdfv_path_find - Finds a file in _qdgdfv_fopen_path.
487 * @file: the file to be found
489 * Searches for @file in the path stored in _qdgdfv_fopen_path.
490 * If it's found in some of the directories there, a string is
491 * allocated contaning the full path, that should be freed
492 * when no longer needed. Otherwise, returns NULL.
494 char *qdgdfv_path_find(const char *file)
496 return _path_find(_qdgdfv_fopen_path, file);
501 * qdgdfv_fopen - 'Secure' open.
502 * @file: file to be opened
503 * @mode: mode for the file
505 * Opens a file, banging if could not be opened. Optional search paths
506 * can be defined in _qdgdfv_fopen_path.
507 * Returns the opened file.
508 * [Support Functions]
510 FILE *qdgdfv_fopen(char *file, char *mode)
512 FILE *f;
514 if ((f = _qdgdfv_fopen(file, mode)) == NULL)
515 qdgdfv_bang("qdgdfv_fopen: can't open", file);
517 return f;
521 static void load_pcx(unsigned char *pcx, char *pcxfile, int size, int usepal)
523 int n, m;
524 unsigned char c;
525 FILE *f;
526 unsigned char _pcx_palette[256][3];
528 f = qdgdfv_fopen(pcxfile, "rb");
530 /* skips header */
531 fseek(f, 128, SEEK_SET);
533 n = 0;
534 while (n < size) {
535 c = fgetc(f);
537 if (c > 0xC0) {
538 /* run-length */
539 m = c & 0x3F;
541 c = fgetc(f);
543 else
544 m = 1;
546 while (m) {
547 pcx[n++] = c;
548 m--;
552 /* reads palette */
553 fseek(f, -((long) sizeof(_pcx_palette)), SEEK_END);
554 fread(_pcx_palette, 3, 256, f);
556 fclose(f);
558 /* if the palette is not to be used, it's over */
559 if (!usepal)
560 return;
562 if (usepal == 1) {
563 /* fixes the pcx to use current palette */
564 for (n = 0; n < size; n++) {
565 c = pcx[n];
566 pcx[n] = qdgdfv_seek_color(_pcx_palette[c][0],
567 _pcx_palette[c][1], _pcx_palette[c][2]
571 else if (usepal == 2) {
572 /* transfers this pcx's palette to system one */
573 for (n = 0; n < 256; n++) {
574 _qdgdfv_palette[n * 3] = _pcx_palette[n][0];
575 _qdgdfv_palette[(n * 3) + 1] = _pcx_palette[n][1];
576 _qdgdfv_palette[(n * 3) + 2] = _pcx_palette[n][2];
579 /* and set it */
580 qdgdfv_set_palette();
586 * qdgdfv_load_pcx - Loads a graphic in PCX format.
587 * @pcx: the buffer where the graphic will be stored
588 * @pcxfile: the file containing the graphic
589 * @size: the size in bytes of the graphic data
591 * Loads a graphic into the supplied @pcx buffer. The file must be
592 * in 256 color PCX format. The palette included inside the file
593 * is not used.
594 * [Video Functions]
596 void qdgdfv_load_pcx(unsigned char *pcx, char *pcxfile, int size)
598 load_pcx(pcx, pcxfile, size, 0);
603 * qdgdfv_load_pcx_pal - Loads a graphic in PCX format using its palette.
604 * @pcx: the buffer where the graphic will be stored
605 * @pcxfile: the file containing the graphic
606 * @size: the size in bytes of the graphic data
608 * This function does the same as qdgdfv_load_pcx(), but taking into
609 * account the palette information stored inside the file to match
610 * the current palette.
611 * [Video Functions]
613 void qdgdfv_load_pcx_pal(unsigned char *pcx, char *pcxfile, int size)
615 load_pcx(pcx, pcxfile, size, 1);
620 * qdgdfv_load_pcx_pal_set - Loads a graphic in PCX format setting its palette.
621 * @pcx: the buffer where the graphic will be stored
622 * @pcxfile: the file containing the graphic
623 * @size: the size in bytes of the graphic data
625 * This function does the same as qdgdfv_load_pcx(), but setting the palette
626 * store inside the file as the default.
627 * [Video Functions]
629 void qdgdfv_load_pcx_pal_set(unsigned char *pcx, char *pcxfile, int size)
631 load_pcx(pcx, pcxfile, size, 2);
636 * qdgdfv_load_palette - Loads an external palette.
637 * @palette_file: the file containing the palette
639 * Loads an external palette. The file is a text one having
640 * lines with three decimal values from 0 to 255 for the red,
641 * green and blue parts of each color, respectively. To be used,
642 * qdgdfv_set_palette() must be called afterwards.
643 * [Video Functions]
645 void qdgdfv_load_palette(char *palette_file)
647 int n;
648 FILE *f;
649 char lin[80];
650 unsigned int r, g, b;
652 if (*palette_file == '\0')
653 return;
655 f = qdgdfv_fopen(palette_file, "r");
657 /* ignores first three lines */
658 fgets(lin, sizeof(lin) - 1, f);
659 fgets(lin, sizeof(lin) - 1, f);
660 fgets(lin, sizeof(lin) - 1, f);
662 for (n = 0; n < 256; n++) {
663 if (fscanf(f, "%u %u %u\n", &r, &g, &b) != 3)
664 break;
666 _qdgdfv_palette[n * 3] = r;
667 _qdgdfv_palette[(n * 3) + 1] = g;
668 _qdgdfv_palette[(n * 3) + 2] = b;
671 /* fills to the end with zeroes */
672 for (; n < 256; n++) {
673 _qdgdfv_palette[n * 3] = 0;
674 _qdgdfv_palette[(n * 3) + 1] = 0;
675 _qdgdfv_palette[(n * 3) + 2] = 0;
678 fclose(f);
682 static void fill_extended_palette(void)
684 int n;
685 unsigned int r, g, b;
686 int *pal;
688 pal = (int *) _qdgdfv_palette;
690 for (n = 0; n < 256; n++) {
692 if ((r = (unsigned int) pal[n * 3] + _qdgdfv_gamma_correct) > 255)
693 r = 255;
695 if ((g = (unsigned int) pal[(n * 3) + 1] + _qdgdfv_gamma_correct) > 255)
696 g = 255;
698 if ((b = (unsigned int) pal[(n * 3) + 2] + _qdgdfv_gamma_correct) > 255)
699 b = 255;
701 r = ((r << 24) & _qdgdfv_red_mask) >> _qdgdfv_red_shift;
702 g = ((g << 24) & _qdgdfv_green_mask) >> _qdgdfv_green_shift;
703 b = ((b << 24) & _qdgdfv_blue_mask) >> _qdgdfv_blue_shift;
705 _qdgdfv_extended_palette[n] = r | g | b;
711 * qdgdfv_set_palette - Sets the palette.
713 * Sets the stored palette as the current one, probably
714 * loading it into video hardware.
715 * [Video Functions]
717 void qdgdfv_set_palette(void)
719 /* call the driver setting */
720 drv->set_palette();
722 if (_qdgdfv_pixel_size > 1)
723 fill_extended_palette();
728 * qdgdfv_clear_virtual_screen - Clears the virtual screen.
730 * Clears the virtual screen, using _qdgdfv_clear_color.
731 * [Video Functions]
733 void qdgdfv_clear_virtual_screen(void)
735 memset(_qdgdfv_virtual_screen, _qdgdfv_clear_color,
736 _qdgdfv_screen_x_size * _qdgdfv_screen_y_size);
740 /* screen dumping */
742 #define DUMP_PLAIN(NAME,TYPE) \
743 void NAME(unsigned char * screen, TYPE * dscreen) { \
744 int n; TYPE a; \
745 for(n = _qdgdfv_screen_x_size * _qdgdfv_screen_y_size;n > 0;n--) { \
746 a = (TYPE) _qdgdfv_extended_palette[(int)*screen++]; \
747 *dscreen++ = a; \
751 DUMP_PLAIN(_qdgdfv_dump2_screen, short)
752 DUMP_PLAIN(_qdgdfv_dump4_screen, int)
754 #define DOUBLE_DUMP_PLAIN(NAME,TYPE) \
755 void NAME(unsigned char * screen, TYPE * dscreen) { \
756 int n, m, l; TYPE a; \
757 l = _qdgdfv_screen_x_size * 2; \
758 for(n = 0;n < _qdgdfv_screen_y_size;n++) { \
759 for(m = 0;m < _qdgdfv_screen_x_size;m++) { \
760 a = (TYPE) _qdgdfv_extended_palette[(int)*screen++]; \
761 *dscreen = a; *(dscreen + l) = a; dscreen++; \
762 *dscreen = a; *(dscreen + l) = a; dscreen++; \
764 dscreen += l; \
767 DOUBLE_DUMP_PLAIN(_qdgdfv_double_dump1_screen, char)
768 DOUBLE_DUMP_PLAIN(_qdgdfv_double_dump2_screen, short)
769 DOUBLE_DUMP_PLAIN(_qdgdfv_double_dump4_screen, int)
771 #define TRIPLE_DUMP_PLAIN(NAME,TYPE) \
772 void NAME(unsigned char * screen, TYPE * dscreen) { \
773 int n, m, l, l2; TYPE a; \
774 l = _qdgdfv_screen_x_size * 3; \
775 l2 = _qdgdfv_screen_x_size * 3 * 2; \
776 for(n = 0;n < _qdgdfv_screen_y_size;n++) { \
777 for(m = 0;m < _qdgdfv_screen_x_size;m++) { \
778 a = (TYPE) _qdgdfv_extended_palette[(int)*screen++]; \
779 *dscreen = a; *(dscreen + l) = a; *(dscreen + l2) = a; dscreen++; \
780 *dscreen = a; *(dscreen + l) = a; *(dscreen + l2) = a; dscreen++; \
781 *dscreen = a; *(dscreen + l) = a; *(dscreen + l2) = a; dscreen++; \
783 dscreen += l2; \
786 TRIPLE_DUMP_PLAIN(_qdgdfv_triple_dump1_screen, char)
787 TRIPLE_DUMP_PLAIN(_qdgdfv_triple_dump2_screen, short)
788 TRIPLE_DUMP_PLAIN(_qdgdfv_triple_dump4_screen, int)
791 /** scale2x: algorithm taken from http://scale2x.sourceforge.net **/
793 static void scale2x_peek(unsigned char *p, int tx, unsigned char o[9])
795 o[0] = *(p - tx - 1); o[1] = *(p - tx); o[2] = *(p - tx + 1);
796 o[3] = *(p - 1); o[4] = *p; o[5] = *(p + 1);
797 o[6] = *(p + tx - 1); o[7] = *(p + tx); o[8] = *(p + tx + 1);
801 void qdgdfv_scale2x_p(unsigned char *p, int tx, int o[4])
803 unsigned char i[9];
805 scale2x_peek(p, tx, i);
807 o[0] = (i[3] == i[1] && i[1] != i[5] && i[3] != i[7]) ? i[3] : i[4];
808 o[1] = (i[1] == i[5] && i[1] != i[3] && i[5] != i[7]) ? i[5] : i[4];
809 o[2] = (i[3] == i[7] && i[3] != i[1] && i[7] != i[5]) ? i[3] : i[4];
810 o[3] = (i[7] == i[5] && i[3] != i[7] && i[1] != i[5]) ? i[5] : i[4];
814 void qdgdfv_scale3x_p(unsigned char *p, int tx, int o[9])
816 unsigned char i[9];
818 scale2x_peek(p, tx, i);
820 if (i[1] != i[7] && i[3] != i[5]) {
821 o[0] = i[3] == i[1] ? i[3] : i[4];
822 o[1] = (i[3] == i[1] && i[4] != i[2]) ||
823 (i[1] == i[5] && i[4] != i[0]) ? i[1] : i[4];
824 o[2] = i[1] == i[5] ? i[5] : i[4];
825 o[3] = (i[3] == i[1] && i[4] != i[6]) ||
826 (i[3] == i[1] && i[4] != i[0]) ? i[3] : i[4];
827 o[4] = i[4];
828 o[5] = (i[1] == i[5] && i[4] != i[8]) ||
829 (i[7] == i[5] && i[4] != i[2]) ? i[5] : i[4];
830 o[6] = i[3] == i[7] ? i[3] : i[4];
831 o[7] = (i[3] == i[7] && i[4] != i[8]) ||
832 (i[7] == i[5] && i[4] != i[6]) ? i[7] : i[4];
833 o[8] = i[7] == i[5] ? i[5] : i[4];
835 else {
836 int n;
838 for (n = 0; n < 9; n++)
839 o[n] = i[4];
843 #define DOUBLE_DUMP_S2X(NAME,TYPE) \
844 void NAME(unsigned char * screen, TYPE * dscreen) { \
845 int n, m, l; \
846 l = _qdgdfv_screen_x_size * 2; \
847 screen += _qdgdfv_screen_x_size + 1; \
848 for(n = 0; n < _qdgdfv_screen_y_size - 2; n++) { \
849 for(m = 0; m < _qdgdfv_screen_x_size; m++) { \
850 int o[4]; \
851 qdgdfv_scale2x_p(screen, _qdgdfv_screen_x_size, o); \
852 screen++; \
853 *dscreen = (TYPE)_qdgdfv_extended_palette[o[0]]; \
854 *(dscreen + l) = (TYPE)_qdgdfv_extended_palette[o[2]]; \
855 dscreen++; \
856 *dscreen = (TYPE)_qdgdfv_extended_palette[o[1]]; \
857 *(dscreen + l) = (TYPE)_qdgdfv_extended_palette[o[3]]; \
858 dscreen++; \
860 dscreen += l; \
863 DOUBLE_DUMP_S2X(_qdgdfv_s2x_dump1_screen, char)
864 DOUBLE_DUMP_S2X(_qdgdfv_s2x_dump2_screen, short)
865 DOUBLE_DUMP_S2X(_qdgdfv_s2x_dump4_screen, int)
867 #define TRIPLE_DUMP_S3X(NAME,TYPE) \
868 void NAME(unsigned char * screen, TYPE * dscreen) { \
869 int n, m, l, l2; \
870 l = _qdgdfv_screen_x_size * 3; \
871 l2 = _qdgdfv_screen_x_size * 3 * 2; \
872 screen += _qdgdfv_screen_x_size + 1; \
873 for(n = 0;n < _qdgdfv_screen_y_size - 2;n++) { \
874 for(m = 0;m < _qdgdfv_screen_x_size;m++) { \
875 int o[9]; \
876 qdgdfv_scale3x_p(screen, _qdgdfv_screen_x_size, o); \
877 screen++; \
878 *dscreen = (TYPE)_qdgdfv_extended_palette[o[0]]; \
879 *(dscreen + l) = (TYPE)_qdgdfv_extended_palette[o[3]]; \
880 *(dscreen + l2) = (TYPE)_qdgdfv_extended_palette[o[6]]; \
881 dscreen++; \
882 *dscreen = (TYPE)_qdgdfv_extended_palette[o[1]]; \
883 *(dscreen + l) = (TYPE)_qdgdfv_extended_palette[o[4]]; \
884 *(dscreen + l2) = (TYPE)_qdgdfv_extended_palette[o[7]]; \
885 dscreen++; \
886 *dscreen = (TYPE)_qdgdfv_extended_palette[o[2]]; \
887 *(dscreen + l) = (TYPE)_qdgdfv_extended_palette[o[5]]; \
888 *(dscreen + l2) = (TYPE)_qdgdfv_extended_palette[o[8]]; \
889 dscreen++; \
891 dscreen += l2; \
894 TRIPLE_DUMP_S3X(_qdgdfv_s3x_dump1_screen, char)
895 TRIPLE_DUMP_S3X(_qdgdfv_s3x_dump2_screen, short)
896 TRIPLE_DUMP_S3X(_qdgdfv_s3x_dump4_screen, int)
900 * qdgdfv_dump_virtual_screen - Dumps the virtual screen.
902 * Dumps the virtual screen into the real one.
903 * [Video Functions]
905 void qdgdfv_dump_virtual_screen(void)
907 if (_qdgdfv_accum_buffer) {
908 int n;
910 for (n = 0; n < _qdgdfv_screen_x_size * _qdgdfv_screen_y_size; n++)
911 _qdgdfv_virtual_screen[n] =
912 _qdgdfv_accum_table[_qdgdfv_virtual_screen[n]]
913 [_qdgdfv_accum_buffer[n]];
916 drv->dump_virtual_screen();
918 if (_qdgdfv_accum_buffer)
919 memcpy(_qdgdfv_accum_buffer, _qdgdfv_virtual_screen,
920 _qdgdfv_screen_x_size * _qdgdfv_screen_y_size);
925 * qdgdfv_assert_in_virtual_screen - Asserts that a pointer is inside the virtual screen.
926 * @func: function where the test is happening
927 * @ptr: the pointer
929 * Asserts that a pointer falls inside the virtual screen.
930 * If it's outside (less than _qdgdfv_virtual_screen or further the
931 * end of the virtual screen), aborts.
933 void qdgdfv_assert_in_virtual_screen(char *func, unsigned char *ptr)
935 int diff;
937 diff = (int) (ptr - _qdgdfv_virtual_screen);
939 if (diff < 0 || diff >= (_qdgdfv_screen_x_size * _qdgdfv_screen_y_size))
940 qdgdfv_bang(func, qdgdfv_sprintf("virtual screen diff: %d", diff));
945 * qdgdfv_input_poll - Polls the input system.
947 * Polls the input system, setting the individual key variables
948 * accordingly.
949 * [Keyboard Functions]
951 void qdgdfv_input_poll(void)
953 drv->input_poll();
958 * qdgdfv_timer - Returns the elapsed time in microseconds.
959 * @reset: reset flag
961 * Returns the elapsed time between calls, in milliseconds. If @reset
962 * is set to 1, the timer is reset any time the function is called,
963 * or accumulative otherwise. It's mainly used for calculating the
964 * elapsed time per frame. It's wise to reset the timer just before
965 * entering the main loop.
966 * [Support Functions]
968 int qdgdfv_timer(int reset)
970 return (drv->timer(reset));
974 #define qdgdfv_max(a,b) ((a) > (b)) ? (a) : (b)
977 * qdgdfv_seek_color - Searches for the nearest matching color.
978 * @r: the red part of the color
979 * @g: the green part of the color
980 * @b: the blue part of the color
982 * Searches the internal palette for the nearest color matching
983 * the r, g and b values. This values must range from 0 to 255.
984 * Returns the selected color.
985 * [Video Functions]
987 unsigned char qdgdfv_seek_color(int r, int g, int b)
989 int n, i;
990 int mindif;
991 int best;
992 unsigned int *pal;
993 int rr, gg, bb;
995 if (r > 255)
996 r = 255;
997 if (g > 255)
998 g = 255;
999 if (b > 255)
1000 b = 255;
1002 best = 255;
1003 mindif = 0x7fffffff;
1004 pal = _qdgdfv_palette;
1006 for (n = 0; n < 256; n++, pal += 3) {
1007 rr = abs(r - *pal);
1008 gg = abs(g - *(pal + 1));
1009 bb = abs(b - *(pal + 2));
1011 i = qdgdfv_max(rr, qdgdfv_max(gg, bb));
1013 if (mindif > i) {
1014 mindif = i;
1015 best = n;
1019 return (unsigned char) best;
1024 * qdgdfv_build_light_table - Builds a light table.
1025 * @lut: the buffer where to store the light table
1026 * @levels: number of light levels
1027 * @mid: the level where color is 100%
1029 * Builds a light table. The @lut argument must have enough size to
1030 * store (256 * levels) bytes, and be easily accessed (so it can wisely
1031 * be defined as unsigned char lut[levels][256]). The @mid value
1032 * is the level where color is 100% (i.e. equal to the color itself).
1033 * Below, colors fade to black and above colors saturate to white.
1034 * [Video Functions]
1036 void qdgdfv_build_light_table(unsigned char *lut, int levels, int mid)
1038 qdgdfv_build_light_table_ext(lut, levels, mid, 0, 0, 0);
1043 * qdgdfv_build_light_table_ext - Builds a light table (extended).
1044 * @lut: the buffer where to store the light table
1045 * @levels: number of light levels
1046 * @mid: the level where color is 100%
1047 * @fr: red component of fade color
1048 * @fg: green component of fade color
1049 * @fb: blue component of fade color
1051 * This function is an extended version of qdgdfv_build_light_table().
1052 * Instead of fading to black, this function allows to specify what
1053 * color the dark light levels fade to.
1054 * [Video Functions]
1056 void qdgdfv_build_light_table_ext(unsigned char *lut, int levels,
1057 int mid, int fr, int fg, int fb)
1059 int n, m;
1060 int r, g, b;
1062 mid--;
1063 mid = levels - mid;
1065 for (n = 0; n < levels; n++) {
1066 for (m = 0; m < 255; m++) {
1067 r = _qdgdfv_palette[m * 3];
1068 g = _qdgdfv_palette[(m * 3) + 1];
1069 b = _qdgdfv_palette[(m * 3) + 2];
1071 /* old algorithm was r=(r*(n+mid))/levels; */
1073 r += ((fr - r) / levels) * (levels - (n + mid));
1074 g += ((fg - g) / levels) * (levels - (n + mid));
1075 b += ((fb - b) / levels) * (levels - (n + mid));
1077 lut[(n * 256) + m] = qdgdfv_seek_color(r, g, b);
1080 lut[(n * 256) + 255] = 255;
1086 * qdgdfv_blend_color - Blends two colors into one.
1087 * @c1: first color
1088 * @c2: second color
1089 * @percent: percentage of blending
1091 * Blends two colors into the nearest matching one. If @percent is 100,
1092 * the returned color will be @c1, if it's 0, @c2, or a blending between
1093 * both otherwise.
1094 * [Video Functions]
1096 unsigned char qdgdfv_blend_color(unsigned char c1, unsigned char c2, int percent)
1098 int r, g, b;
1099 int *p;
1101 if (percent == 100)
1102 return c1;
1103 if (percent == 0)
1104 return c2;
1106 p = (int *) &_qdgdfv_palette[(int) c1 * 3];
1108 r = (*(p++) * percent) / 100;
1109 g = (*(p++) * percent) / 100;
1110 b = (*p * percent) / 100;
1112 percent = 100 - percent;
1114 p = (int *) &_qdgdfv_palette[(int) c2 * 3];
1116 r += (*(p++) * percent) / 100;
1117 g += (*(p++) * percent) / 100;
1118 b += (*p * percent) / 100;
1120 return qdgdfv_seek_color(r, g, b);
1125 * qdgdfv_set_accum_buffer - Sets or resets the accumulation buffer.
1126 * @percent: percentage of buffer lasting
1128 * If @percent is set to a non zero value (the default), the contents
1129 * of the previous frame is blended with the actual one with the
1130 * specified percent.
1131 * [Video Functions]
1133 void qdgdfv_set_accum_buffer(int percent)
1135 int x, y;
1137 if (_qdgdfv_accum_buffer)
1138 free(_qdgdfv_accum_buffer);
1140 if (percent == 0)
1141 _qdgdfv_accum_buffer = NULL;
1142 else {
1143 /* alloc a buffer */
1144 _qdgdfv_accum_buffer = qdgdfv_malloc(_qdgdfv_screen_x_size *
1145 _qdgdfv_screen_y_size);
1148 /* build the table */
1149 for (y = 0; y < 256; y++)
1150 for (x = 0; x < 256; x++)
1151 _qdgdfv_accum_table[x][y] = qdgdfv_blend_color(y, x, percent);
1157 * qdgdfv_extended_key_status - Returns more status about a key.
1158 * @key_var: pointer to the wanted key variable (_qdgdfv_key_up, etc.)
1160 * Returns extended status for the variable pointed by @key_var.
1161 * Returned values are: 0, key not pressed; 1, key just pressed;
1162 * 2, key pressed; 3, key just released; -1, no information about
1163 * the key is found.
1164 * [Keyboard Functions]
1166 int qdgdfv_extended_key_status(int *key_var)
1168 int n;
1169 int ret = -1;
1170 struct __qdgdfv_extended_key_status *xk;
1172 for (n = 0; ret == -1; n++) {
1173 xk = &_qdgdfv_extended_key_status[n];
1175 /* no more keys */
1176 if (xk->key_var == NULL)
1177 break;
1179 /* is this the wanted key? */
1180 if (xk->key_var == key_var) {
1181 if (*key_var == 0)
1182 ret = xk->last_val == 1 ? 3 : 0;
1183 else
1184 ret = xk->last_val == 1 ? 2 : 1;
1186 xk->last_val = *key_var;
1190 return ret;
1195 * qdgdfv_home_dir - Returns the home user directory.
1197 * Returns a system-dependent directory where the user can write
1198 * documents and create subdirectories.
1199 * [File Management]
1201 char *qdgdfv_home_dir(void)
1203 return _home_dir();
1208 * qdgdfv_app_dir - Returns the applications directory.
1210 * Returns a system-dependent directory where the applications store
1211 * their private data, as components or resources.
1212 * [File Management]
1214 char *qdgdfv_app_dir(void)
1216 return _app_dir();
1221 * qdgdfv_opengl - Enables or disables the use of OpenGL.
1222 * @onoff: boolean value
1224 * Enables or disables the use of OpenGL using the @onoff argument.
1225 * Returns 1 if the operation succeeded or 0 if not. When the OpenGL
1226 * mode is active, OpenGL code can be used before dumping the virtual
1227 * screen.
1228 * [Video Functions]
1230 int qdgdfv_opengl(int onoff)
1232 int ret = 0;
1234 if (drv->opengl != NULL)
1235 ret = drv->opengl(onoff);
1237 return ret;
1242 * qdgdfv_startup - Inits the video system.
1244 * Starts up the video system.
1245 * [Video Functions]
1247 void qdgdfv_startup(void)
1249 char *logger;
1251 /* force logging */
1252 if ((logger = getenv("QDGDF_LOG")) != NULL) {
1253 _qdgdfv_use_logger = 1;
1254 strncpy(_qdgdfv_logger_file, logger, sizeof(_qdgdfv_logger_file) - 1);
1255 _qdgdfv_logger_file[sizeof(_qdgdfv_logger_file)] = '\0';
1258 /* scale setting */
1259 if (_qdgdfv_scale == 0)
1260 _qdgdfv_scale = _qdgdfv_double_mode ? 2 : 1;
1262 if (!TRY_VIDEO_DRIVERS())
1263 qdgdfv_bang("qdgdfv_startup", "No usable video driver found");
1265 qdgdfv_set_palette();
1267 atexit(qdgdfv_shutdown);
1272 * qdgdfv_shutdown - Shuts down the video system.
1274 * Shuts down the video system.
1275 * [Video Functions]
1277 void qdgdfv_shutdown(void)
1279 if (drv == NULL)
1280 return;
1282 drv->shutdown();
1284 drv = NULL;