1 | /* |
---|
2 | * libcaca ASCII-Art library |
---|
3 | * Copyright (c) 2002, 2003 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 GNU Lesser General Public |
---|
8 | * License as published by the Free Software Foundation; either |
---|
9 | * version 2 of the License, or (at your option) any later version. |
---|
10 | * |
---|
11 | * This library 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 GNU |
---|
14 | * Lesser General Public License for more details. |
---|
15 | * |
---|
16 | * You should have received a copy of the GNU Lesser General Public |
---|
17 | * License along with this library; if not, write to the Free Software |
---|
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
---|
19 | * 02111-1307 USA |
---|
20 | */ |
---|
21 | |
---|
22 | /** \file graphics.c |
---|
23 | * \version \$Id: graphics.c 486 2005-06-21 16:13:41Z jylam $ |
---|
24 | * \author Sam Hocevar <sam@zoy.org> |
---|
25 | * \brief Character drawing |
---|
26 | * |
---|
27 | * This file contains character and string drawing functions. |
---|
28 | */ |
---|
29 | |
---|
30 | #include "config.h" |
---|
31 | |
---|
32 | #if defined(USE_SLANG) |
---|
33 | # if defined(HAVE_SLANG_SLANG_H) |
---|
34 | # include <slang/slang.h> |
---|
35 | # else |
---|
36 | # include <slang.h> |
---|
37 | # endif |
---|
38 | #endif |
---|
39 | #if defined(USE_NCURSES) |
---|
40 | # if defined(HAVE_NCURSES_H) |
---|
41 | # include <ncurses.h> |
---|
42 | # else |
---|
43 | # include <curses.h> |
---|
44 | # endif |
---|
45 | #endif |
---|
46 | #if defined(USE_CONIO) |
---|
47 | # include <conio.h> |
---|
48 | # if defined(SCREENUPDATE_IN_PC_H) |
---|
49 | # include <pc.h> |
---|
50 | # endif |
---|
51 | #endif |
---|
52 | #if defined(USE_X11) |
---|
53 | # include <X11/Xlib.h> |
---|
54 | # if defined(HAVE_X11_XKBLIB_H) |
---|
55 | # include <X11/XKBlib.h> |
---|
56 | # endif |
---|
57 | #endif |
---|
58 | #if defined(USE_WIN32) |
---|
59 | # include <windows.h> |
---|
60 | #endif |
---|
61 | #if defined(USE_GL) |
---|
62 | # include <GL/gl.h> |
---|
63 | # include <GL/glut.h> |
---|
64 | #endif |
---|
65 | #if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) |
---|
66 | # include <inttypes.h> |
---|
67 | #else |
---|
68 | typedef unsigned char uint8_t; |
---|
69 | #endif |
---|
70 | |
---|
71 | #include <stdio.h> /* BUFSIZ */ |
---|
72 | #include <string.h> |
---|
73 | #include <stdlib.h> |
---|
74 | #if defined(HAVE_UNISTD_H) |
---|
75 | # include <unistd.h> |
---|
76 | #endif |
---|
77 | #include <stdarg.h> |
---|
78 | |
---|
79 | #if defined(HAVE_SIGNAL_H) |
---|
80 | # include <signal.h> |
---|
81 | #endif |
---|
82 | #if defined(HAVE_SYS_IOCTL_H) |
---|
83 | # include <sys/ioctl.h> |
---|
84 | #endif |
---|
85 | |
---|
86 | #include "caca.h" |
---|
87 | #include "caca_internals.h" |
---|
88 | |
---|
89 | /* |
---|
90 | * Global variables |
---|
91 | */ |
---|
92 | #if !defined(_DOXYGEN_SKIP_ME) |
---|
93 | unsigned int _caca_width = 0; |
---|
94 | unsigned int _caca_height = 0; |
---|
95 | int _caca_resize = 0; |
---|
96 | int _caca_resize_event = 0; |
---|
97 | #endif |
---|
98 | |
---|
99 | /* |
---|
100 | * Local variables |
---|
101 | */ |
---|
102 | #if !defined(_DOXYGEN_SKIP_ME) |
---|
103 | static uint8_t *cache_char, *cache_attr; |
---|
104 | #endif |
---|
105 | |
---|
106 | #if defined(USE_NCURSES) |
---|
107 | static int ncurses_attr[16*16]; |
---|
108 | #endif |
---|
109 | |
---|
110 | #if defined(USE_SLANG) |
---|
111 | /* Tables generated by test/optipal.c */ |
---|
112 | static int const slang_palette[2*16*16] = |
---|
113 | { |
---|
114 | 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, |
---|
115 | 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 0, 8, |
---|
116 | 8, 7, 7, 8, 15, 7, 7, 15, 15, 9, 9, 15, 1, 9, 9, 1, |
---|
117 | 7, 9, 9, 7, 8, 1, 1, 8, 0, 1, 15, 10, 10, 15, 2, 10, |
---|
118 | 10, 2, 7, 10, 10, 7, 8, 2, 2, 8, 0, 2, 15, 11, 11, 15, |
---|
119 | 3, 11, 11, 3, 7, 11, 11, 7, 8, 3, 3, 8, 0, 3, 15, 12, |
---|
120 | 12, 15, 4, 12, 12, 4, 7, 12, 12, 7, 8, 4, 4, 8, 0, 4, |
---|
121 | 15, 13, 13, 15, 5, 13, 13, 5, 7, 13, 13, 7, 8, 5, 5, 8, |
---|
122 | 0, 5, 15, 14, 14, 15, 6, 14, 14, 6, 7, 14, 14, 7, 8, 6, |
---|
123 | 6, 8, 0, 6, 4, 6, 6, 4, 12, 14, 14, 12, 6, 2, 2, 6, |
---|
124 | 14, 10, 10, 14, 2, 3, 3, 2, 10, 11, 11, 10, 3, 1, 1, 3, |
---|
125 | 11, 9, 9, 11, 1, 5, 5, 1, 9, 13, 13, 9, 5, 4, 4, 5, |
---|
126 | 13, 12, 12, 13, 4, 14, 6, 12, 12, 6, 14, 4, 6, 10, 2, 14, |
---|
127 | 14, 2, 10, 6, 2, 11, 3, 10, 10, 3, 11, 2, 3, 9, 1, 11, |
---|
128 | 11, 1, 9, 3, 1, 13, 5, 9, 9, 5, 13, 1, 5, 12, 4, 13, |
---|
129 | 13, 4, 12, 5, 0, 7, 0, 15, 15, 8, 8, 15, 15, 1, 7, 1, |
---|
130 | 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 0, 0, 1, 1, |
---|
131 | 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 2, 2, 3, 3, |
---|
132 | 4, 4, 5, 5, 6, 6, 7, 7, 14, 9, 1, 15, 8, 9, 8, 8, |
---|
133 | 9, 9, 1, 7, 0, 9, 9, 8, 6, 9, 13, 10, 2, 15, 8, 10, |
---|
134 | 7, 2, 15, 2, 2, 7, 0, 10, 10, 8, 5, 10, 12, 11, 3, 15, |
---|
135 | 8, 11, 7, 3, 15, 3, 3, 7, 0, 11, 11, 8, 4, 11, 11, 12, |
---|
136 | 4, 15, 8, 12, 7, 4, 15, 4, 4, 7, 0, 12, 12, 8, 3, 12, |
---|
137 | 10, 13, 5, 15, 8, 13, 7, 5, 15, 5, 5, 7, 0, 13, 13, 8, |
---|
138 | 2, 13, 9, 14, 6, 15, 8, 14, 7, 6, 15, 6, 6, 7, 0, 14, |
---|
139 | 14, 8, 1, 14, 5, 6, 2, 4, 13, 14, 10, 12, 4, 2, 3, 6, |
---|
140 | 12, 10, 11, 14, 6, 3, 1, 2, 14, 11, 9, 10, 2, 1, 5, 3, |
---|
141 | 10, 9, 13, 11, 3, 5, 4, 1, 11, 13, 12, 9, 1, 4, 6, 5, |
---|
142 | 9, 12, 14, 13, 5, 14, 2, 12, 13, 6, 10, 4, 4, 10, 3, 14, |
---|
143 | 12, 2, 11, 6, 6, 11, 1, 10, 14, 3, 9, 2, 2, 9, 5, 11, |
---|
144 | 10, 1, 13, 3, 3, 13, 4, 9, 11, 5, 12, 1, 1, 12, 6, 13, |
---|
145 | 9, 4, 14, 5, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, |
---|
146 | }; |
---|
147 | |
---|
148 | static int const slang_assoc[16*16] = |
---|
149 | { |
---|
150 | 134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
---|
151 | 28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126, |
---|
152 | 37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161, |
---|
153 | 46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170, |
---|
154 | 55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179, |
---|
155 | 64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188, |
---|
156 | 73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197, |
---|
157 | 122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18, |
---|
158 | 15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124, |
---|
159 | 154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20, |
---|
160 | 163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29, |
---|
161 | 172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38, |
---|
162 | 181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47, |
---|
163 | 190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56, |
---|
164 | 199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65, |
---|
165 | 123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255, |
---|
166 | }; |
---|
167 | #endif |
---|
168 | |
---|
169 | #if defined(USE_CONIO) |
---|
170 | static struct text_info conio_ti; |
---|
171 | static char *conio_screen; |
---|
172 | #endif |
---|
173 | |
---|
174 | #if defined(USE_X11) && !defined(_DOXYGEN_SKIP_ME) |
---|
175 | Display *x11_dpy; |
---|
176 | Window x11_window; |
---|
177 | Pixmap x11_pixmap; |
---|
178 | GC x11_gc; |
---|
179 | long int x11_event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
---|
180 | | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask |
---|
181 | | ExposureMask; |
---|
182 | int x11_font_width, x11_font_height; |
---|
183 | unsigned int x11_new_width, x11_new_height; |
---|
184 | static int x11_colors[16]; |
---|
185 | static Font x11_font; |
---|
186 | static XFontStruct *x11_font_struct; |
---|
187 | static int x11_font_offset; |
---|
188 | #if defined(HAVE_X11_XKBLIB_H) |
---|
189 | static Bool x11_detect_autorepeat; |
---|
190 | #endif |
---|
191 | #endif |
---|
192 | |
---|
193 | #if defined(USE_WIN32) |
---|
194 | HANDLE win32_hin, win32_hout; |
---|
195 | static HANDLE win32_front, win32_back; |
---|
196 | static CHAR_INFO *win32_buffer; |
---|
197 | |
---|
198 | static int const win32_fg_palette[] = |
---|
199 | { |
---|
200 | 0, |
---|
201 | FOREGROUND_BLUE, |
---|
202 | FOREGROUND_GREEN, |
---|
203 | FOREGROUND_GREEN | FOREGROUND_BLUE, |
---|
204 | FOREGROUND_RED, |
---|
205 | FOREGROUND_RED | FOREGROUND_BLUE, |
---|
206 | FOREGROUND_RED | FOREGROUND_GREEN, |
---|
207 | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, |
---|
208 | FOREGROUND_INTENSITY, |
---|
209 | FOREGROUND_INTENSITY | FOREGROUND_BLUE, |
---|
210 | FOREGROUND_INTENSITY | FOREGROUND_GREEN, |
---|
211 | FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE, |
---|
212 | FOREGROUND_INTENSITY | FOREGROUND_RED, |
---|
213 | FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE, |
---|
214 | FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN, |
---|
215 | FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
---|
216 | }; |
---|
217 | |
---|
218 | static int const win32_bg_palette[] = |
---|
219 | { |
---|
220 | 0, |
---|
221 | BACKGROUND_BLUE, |
---|
222 | BACKGROUND_GREEN, |
---|
223 | BACKGROUND_GREEN | BACKGROUND_BLUE, |
---|
224 | BACKGROUND_RED, |
---|
225 | BACKGROUND_RED | BACKGROUND_BLUE, |
---|
226 | BACKGROUND_RED | BACKGROUND_GREEN, |
---|
227 | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE, |
---|
228 | BACKGROUND_INTENSITY, |
---|
229 | BACKGROUND_INTENSITY | BACKGROUND_BLUE, |
---|
230 | BACKGROUND_INTENSITY | BACKGROUND_GREEN, |
---|
231 | BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE, |
---|
232 | BACKGROUND_INTENSITY | BACKGROUND_RED, |
---|
233 | BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE, |
---|
234 | BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN, |
---|
235 | BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE |
---|
236 | }; |
---|
237 | #endif |
---|
238 | #if defined(USE_GL) |
---|
239 | |
---|
240 | static unsigned int const gl_bg_palette[] = |
---|
241 | { |
---|
242 | 0, |
---|
243 | 0x0000007F, |
---|
244 | 0x00007F00, |
---|
245 | 0x00007F7F, |
---|
246 | 0x007F0000, |
---|
247 | 0x007F007F, |
---|
248 | 0x007F7F00, |
---|
249 | 0x007F7F7F, |
---|
250 | // + intensity |
---|
251 | 0x00000000, |
---|
252 | 0x000000FF, |
---|
253 | 0x0000FF00, |
---|
254 | 0x0000FFFF, |
---|
255 | 0x00FF0000, |
---|
256 | 0x00FF00FF, |
---|
257 | 0x00FFFF00, |
---|
258 | 0x00FFFFFF, |
---|
259 | |
---|
260 | }; |
---|
261 | |
---|
262 | int gl_window; |
---|
263 | unsigned int gl_width, gl_height; |
---|
264 | float gl_font_width, gl_font_height; |
---|
265 | float gl_incx, gl_incy; |
---|
266 | int id[94]; |
---|
267 | unsigned char gl_resized=0, gl_bit=0; |
---|
268 | #endif |
---|
269 | |
---|
270 | |
---|
271 | static char *_caca_empty_line; |
---|
272 | static char *_caca_scratch_line; |
---|
273 | |
---|
274 | static unsigned int _caca_delay; |
---|
275 | static unsigned int _caca_rendertime; |
---|
276 | |
---|
277 | #if defined(OPTIMISE_SLANG_PALETTE) |
---|
278 | static int _caca_fgisbg = 0; |
---|
279 | #endif |
---|
280 | static enum caca_color _caca_fgcolor = CACA_COLOR_LIGHTGRAY; |
---|
281 | static enum caca_color _caca_bgcolor = CACA_COLOR_BLACK; |
---|
282 | |
---|
283 | /* |
---|
284 | * Local functions |
---|
285 | */ |
---|
286 | static void caca_handle_resize(void); |
---|
287 | |
---|
288 | #if defined(USE_SLANG) |
---|
289 | static void slang_init_palette(void); |
---|
290 | #endif |
---|
291 | |
---|
292 | #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG)) |
---|
293 | static RETSIGTYPE sigwinch_handler(int); |
---|
294 | #endif |
---|
295 | |
---|
296 | #if defined(USE_X11) |
---|
297 | static int x11_error_handler(Display *, XErrorEvent *); |
---|
298 | #endif |
---|
299 | |
---|
300 | #if defined(USE_GL) |
---|
301 | unsigned char gl_key = 0; |
---|
302 | int gl_special_key=0; |
---|
303 | int gl_new_width; |
---|
304 | int gl_new_height; |
---|
305 | |
---|
306 | |
---|
307 | static void gl_handle_keyboard(unsigned char key, int x, int y) |
---|
308 | { |
---|
309 | gl_key = key; |
---|
310 | } |
---|
311 | static void gl_handle_special_key(int key, int x, int y) |
---|
312 | { |
---|
313 | gl_special_key = key; |
---|
314 | } |
---|
315 | static void gl_handle_reshape (int w, int h) |
---|
316 | { |
---|
317 | if(gl_bit) /* Do not handle reshaping at the first time*/ |
---|
318 | { |
---|
319 | |
---|
320 | gl_new_width = w; |
---|
321 | gl_new_height = h; |
---|
322 | |
---|
323 | gl_resized = 1; |
---|
324 | } |
---|
325 | else |
---|
326 | gl_bit=1; |
---|
327 | |
---|
328 | } |
---|
329 | #endif |
---|
330 | |
---|
331 | |
---|
332 | |
---|
333 | /** \brief Set the default colour pair. |
---|
334 | * |
---|
335 | * This function sets the default colour pair. String functions such as |
---|
336 | * caca_printf() and graphical primitive functions such as caca_draw_line() |
---|
337 | * will use these colour pairs. |
---|
338 | * |
---|
339 | * \param fgcolor The requested foreground colour. |
---|
340 | * \param bgcolor The requested background colour. |
---|
341 | */ |
---|
342 | void caca_set_color(enum caca_color fgcolor, enum caca_color bgcolor) |
---|
343 | { |
---|
344 | if(fgcolor < 0 || fgcolor > 15 || bgcolor < 0 || bgcolor > 15) |
---|
345 | return; |
---|
346 | |
---|
347 | _caca_fgcolor = fgcolor; |
---|
348 | _caca_bgcolor = bgcolor; |
---|
349 | |
---|
350 | switch(_caca_driver) |
---|
351 | { |
---|
352 | #if defined(USE_SLANG) |
---|
353 | case CACA_DRIVER_SLANG: |
---|
354 | |
---|
355 | #if defined(OPTIMISE_SLANG_PALETTE) |
---|
356 | /* If foreground == background, discard this colour pair. Functions |
---|
357 | * such as caca_putchar will print spaces instead of characters */ |
---|
358 | if(fgcolor != bgcolor) |
---|
359 | _caca_fgisbg = 0; |
---|
360 | else |
---|
361 | { |
---|
362 | _caca_fgisbg = 1; |
---|
363 | if(fgcolor == CACA_COLOR_BLACK) |
---|
364 | fgcolor = CACA_COLOR_WHITE; |
---|
365 | else if(fgcolor == CACA_COLOR_WHITE |
---|
366 | || fgcolor <= CACA_COLOR_LIGHTGRAY) |
---|
367 | fgcolor = CACA_COLOR_BLACK; |
---|
368 | else |
---|
369 | fgcolor = CACA_COLOR_WHITE; |
---|
370 | } |
---|
371 | #endif |
---|
372 | |
---|
373 | #if defined(OPTIMISE_SLANG_PALETTE) |
---|
374 | SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]); |
---|
375 | #else |
---|
376 | SLsmg_set_color(fgcolor + 16 * bgcolor); |
---|
377 | #endif |
---|
378 | break; |
---|
379 | #endif |
---|
380 | #if defined(USE_NCURSES) |
---|
381 | case CACA_DRIVER_NCURSES: |
---|
382 | attrset(ncurses_attr[fgcolor + 16 * bgcolor]); |
---|
383 | break; |
---|
384 | #endif |
---|
385 | #if defined(USE_CONIO) |
---|
386 | case CACA_DRIVER_CONIO: |
---|
387 | textbackground(bgcolor); |
---|
388 | textcolor(fgcolor); |
---|
389 | break; |
---|
390 | #endif |
---|
391 | #if defined(USE_X11) |
---|
392 | case CACA_DRIVER_X11: |
---|
393 | /* Nothing to do */ |
---|
394 | break; |
---|
395 | #endif |
---|
396 | #if defined(USE_WIN32) |
---|
397 | case CACA_DRIVER_WIN32: |
---|
398 | /* Nothing to do */ |
---|
399 | break; |
---|
400 | #endif |
---|
401 | #if defined(USE_GL) |
---|
402 | case CACA_DRIVER_GL: |
---|
403 | /* Nothing to do */ |
---|
404 | break; |
---|
405 | #endif |
---|
406 | default: |
---|
407 | break; |
---|
408 | } |
---|
409 | } |
---|
410 | |
---|
411 | /** \brief Get the current foreground colour. |
---|
412 | * |
---|
413 | * This function returns the current foreground colour that was set with |
---|
414 | * caca_set_color(). |
---|
415 | * |
---|
416 | * \return The current foreground colour. |
---|
417 | */ |
---|
418 | enum caca_color caca_get_fg_color(void) |
---|
419 | { |
---|
420 | return _caca_fgcolor; |
---|
421 | } |
---|
422 | |
---|
423 | /** \brief Get the current background colour. |
---|
424 | * |
---|
425 | * This function returns the current background colour that was set with |
---|
426 | * caca_set_color(). |
---|
427 | * |
---|
428 | * \return The current background colour. |
---|
429 | */ |
---|
430 | enum caca_color caca_get_bg_color(void) |
---|
431 | { |
---|
432 | return _caca_bgcolor; |
---|
433 | } |
---|
434 | |
---|
435 | /** \brief Print a character. |
---|
436 | * |
---|
437 | * This function prints a character at the given coordinates, using the |
---|
438 | * default foreground and background values. If the coordinates are outside |
---|
439 | * the screen boundaries, nothing is printed. |
---|
440 | * |
---|
441 | * \param x X coordinate. |
---|
442 | * \param y Y coordinate. |
---|
443 | * \param c The character to print. |
---|
444 | */ |
---|
445 | void caca_putchar(int x, int y, char c) |
---|
446 | { |
---|
447 | #if defined(USE_CONIO) |
---|
448 | char *data; |
---|
449 | #endif |
---|
450 | if(x < 0 || x >= (int)_caca_width || |
---|
451 | y < 0 || y >= (int)_caca_height) |
---|
452 | return; |
---|
453 | |
---|
454 | cache_char[x + y * _caca_width] = c; |
---|
455 | cache_attr[x + y * _caca_width] = (_caca_bgcolor << 4) | _caca_fgcolor; |
---|
456 | |
---|
457 | switch(_caca_driver) |
---|
458 | { |
---|
459 | #if defined(USE_SLANG) |
---|
460 | case CACA_DRIVER_SLANG: |
---|
461 | SLsmg_gotorc(y, x); |
---|
462 | #if defined(OPTIMISE_SLANG_PALETTE) |
---|
463 | if(_caca_fgisbg) |
---|
464 | SLsmg_write_char(' '); |
---|
465 | else |
---|
466 | #endif |
---|
467 | SLsmg_write_char(c); |
---|
468 | break; |
---|
469 | #endif |
---|
470 | #if defined(USE_NCURSES) |
---|
471 | case CACA_DRIVER_NCURSES: |
---|
472 | move(y, x); |
---|
473 | addch(c); |
---|
474 | break; |
---|
475 | #endif |
---|
476 | #if defined(USE_CONIO) |
---|
477 | case CACA_DRIVER_CONIO: |
---|
478 | data = conio_screen + 2 * (x + y * _caca_width); |
---|
479 | data[0] = c; |
---|
480 | data[1] = (_caca_bgcolor << 4) | _caca_fgcolor; |
---|
481 | break; |
---|
482 | #endif |
---|
483 | #if defined(USE_X11) |
---|
484 | case CACA_DRIVER_X11: |
---|
485 | break; |
---|
486 | #endif |
---|
487 | #if defined(USE_WIN32) |
---|
488 | case CACA_DRIVER_WIN32: |
---|
489 | break; |
---|
490 | #endif |
---|
491 | #if defined(USE_GL) |
---|
492 | case CACA_DRIVER_GL: |
---|
493 | break; |
---|
494 | #endif |
---|
495 | default: |
---|
496 | break; |
---|
497 | } |
---|
498 | } |
---|
499 | |
---|
500 | /** \brief Print a string. |
---|
501 | * |
---|
502 | * This function prints a string at the given coordinates, using the |
---|
503 | * default foreground and background values. The coordinates may be outside |
---|
504 | * the screen boundaries (eg. a negative Y coordinate) and the string will |
---|
505 | * be cropped accordingly if it is too long. |
---|
506 | * |
---|
507 | * \param x X coordinate. |
---|
508 | * \param y Y coordinate. |
---|
509 | * \param s The string to print. |
---|
510 | */ |
---|
511 | void caca_putstr(int x, int y, char const *s) |
---|
512 | { |
---|
513 | char *charbuf; |
---|
514 | char *attrbuf; |
---|
515 | char const *t; |
---|
516 | unsigned int len; |
---|
517 | |
---|
518 | if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width) |
---|
519 | return; |
---|
520 | |
---|
521 | len = strlen(s); |
---|
522 | |
---|
523 | if(x < 0) |
---|
524 | { |
---|
525 | if(len < (unsigned int)-x) |
---|
526 | return; |
---|
527 | len -= -x; |
---|
528 | s += -x; |
---|
529 | x = 0; |
---|
530 | } |
---|
531 | |
---|
532 | if(x + len >= _caca_width) |
---|
533 | { |
---|
534 | len = _caca_width - x; |
---|
535 | memcpy(_caca_scratch_line, s, len); |
---|
536 | _caca_scratch_line[len] = '\0'; |
---|
537 | s = _caca_scratch_line; |
---|
538 | } |
---|
539 | |
---|
540 | charbuf = cache_char + x + y * _caca_width; |
---|
541 | attrbuf = cache_attr + x + y * _caca_width; |
---|
542 | t = s; |
---|
543 | while(*t) |
---|
544 | { |
---|
545 | *charbuf++ = *t++; |
---|
546 | *attrbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor; |
---|
547 | } |
---|
548 | |
---|
549 | switch(_caca_driver) |
---|
550 | { |
---|
551 | #if defined(USE_SLANG) |
---|
552 | case CACA_DRIVER_SLANG: |
---|
553 | SLsmg_gotorc(y, x); |
---|
554 | #if defined(OPTIMISE_SLANG_PALETTE) |
---|
555 | if(_caca_fgisbg) |
---|
556 | SLsmg_write_string(_caca_empty_line + _caca_width - len); |
---|
557 | else |
---|
558 | #endif |
---|
559 | { |
---|
560 | union { char *ch; const char *constch; } u; |
---|
561 | u.constch = s; |
---|
562 | SLsmg_write_string(u.ch); |
---|
563 | } |
---|
564 | break; |
---|
565 | #endif |
---|
566 | #if defined(USE_NCURSES) |
---|
567 | case CACA_DRIVER_NCURSES: |
---|
568 | move(y, x); |
---|
569 | addstr(s); |
---|
570 | break; |
---|
571 | #endif |
---|
572 | #if defined(USE_CONIO) |
---|
573 | case CACA_DRIVER_CONIO: |
---|
574 | charbuf = conio_screen + 2 * (x + y * _caca_width); |
---|
575 | while(*s) |
---|
576 | { |
---|
577 | *charbuf++ = *s++; |
---|
578 | *charbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor; |
---|
579 | } |
---|
580 | break; |
---|
581 | #endif |
---|
582 | #if defined(USE_X11) |
---|
583 | case CACA_DRIVER_X11: |
---|
584 | break; |
---|
585 | #endif |
---|
586 | #if defined(USE_WIN32) |
---|
587 | case CACA_DRIVER_WIN32: |
---|
588 | break; |
---|
589 | #endif |
---|
590 | #if defined(USE_GL) |
---|
591 | case CACA_DRIVER_GL: |
---|
592 | break; |
---|
593 | #endif |
---|
594 | default: |
---|
595 | break; |
---|
596 | } |
---|
597 | } |
---|
598 | |
---|
599 | /** \brief Format a string. |
---|
600 | * |
---|
601 | * This function formats a string at the given coordinates, using the |
---|
602 | * default foreground and background values. The coordinates may be outside |
---|
603 | * the screen boundaries (eg. a negative Y coordinate) and the string will |
---|
604 | * be cropped accordingly if it is too long. The syntax of the format |
---|
605 | * string is the same as for the C printf() function. |
---|
606 | * |
---|
607 | * \param x X coordinate. |
---|
608 | * \param y Y coordinate. |
---|
609 | * \param format The format string to print. |
---|
610 | * \param ... Arguments to the format string. |
---|
611 | */ |
---|
612 | void caca_printf(int x, int y, char const *format, ...) |
---|
613 | { |
---|
614 | char tmp[BUFSIZ]; |
---|
615 | char *buf = tmp; |
---|
616 | va_list args; |
---|
617 | |
---|
618 | if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width) |
---|
619 | return; |
---|
620 | |
---|
621 | if(_caca_width - x + 1 > BUFSIZ) |
---|
622 | buf = malloc(_caca_width - x + 1); |
---|
623 | |
---|
624 | va_start(args, format); |
---|
625 | #if defined(HAVE_VSNPRINTF) |
---|
626 | vsnprintf(buf, _caca_width - x + 1, format, args); |
---|
627 | #else |
---|
628 | vsprintf(buf, format, args); |
---|
629 | #endif |
---|
630 | buf[_caca_width - x] = '\0'; |
---|
631 | va_end(args); |
---|
632 | |
---|
633 | caca_putstr(x, y, buf); |
---|
634 | |
---|
635 | if(buf != tmp) |
---|
636 | free(buf); |
---|
637 | } |
---|
638 | |
---|
639 | /** \brief Get the screen. |
---|
640 | * |
---|
641 | * This function fills a byte array with the character values. |
---|
642 | */ |
---|
643 | void caca_get_screen(char *buffer) |
---|
644 | { |
---|
645 | unsigned int x, y; |
---|
646 | |
---|
647 | for(y = 0; y < _caca_height; y++) |
---|
648 | { |
---|
649 | for(x = 0; x < _caca_width; x++) |
---|
650 | { |
---|
651 | *buffer++ = cache_attr[x + y * _caca_width]; |
---|
652 | *buffer++ = cache_char[x + y * _caca_width]; |
---|
653 | } |
---|
654 | } |
---|
655 | } |
---|
656 | |
---|
657 | /** \brief Clear the screen. |
---|
658 | * |
---|
659 | * This function clears the screen using a black background. |
---|
660 | */ |
---|
661 | void caca_clear(void) |
---|
662 | { |
---|
663 | enum caca_color oldfg = caca_get_fg_color(); |
---|
664 | enum caca_color oldbg = caca_get_bg_color(); |
---|
665 | int y = _caca_height; |
---|
666 | |
---|
667 | caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK); |
---|
668 | |
---|
669 | /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */ |
---|
670 | while(y--) |
---|
671 | caca_putstr(0, y, _caca_empty_line); |
---|
672 | |
---|
673 | caca_set_color(oldfg, oldbg); |
---|
674 | } |
---|
675 | |
---|
676 | #if !defined(_DOXYGEN_SKIP_ME) |
---|
677 | int _caca_init_graphics(void) |
---|
678 | { |
---|
679 | #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG)) |
---|
680 | signal(SIGWINCH, sigwinch_handler); |
---|
681 | #endif |
---|
682 | |
---|
683 | #if defined(USE_SLANG) |
---|
684 | if(_caca_driver == CACA_DRIVER_SLANG) |
---|
685 | { |
---|
686 | slang_init_palette(); |
---|
687 | |
---|
688 | /* Disable alt charset support so that we get a chance to have all |
---|
689 | * 256 colour pairs */ |
---|
690 | SLtt_Has_Alt_Charset = 0; |
---|
691 | |
---|
692 | _caca_width = SLtt_Screen_Cols; |
---|
693 | _caca_height = SLtt_Screen_Rows; |
---|
694 | } |
---|
695 | else |
---|
696 | #endif |
---|
697 | #if defined(USE_NCURSES) |
---|
698 | if(_caca_driver == CACA_DRIVER_NCURSES) |
---|
699 | { |
---|
700 | static int curses_colors[] = |
---|
701 | { |
---|
702 | /* Standard curses colours */ |
---|
703 | COLOR_BLACK, |
---|
704 | COLOR_BLUE, |
---|
705 | COLOR_GREEN, |
---|
706 | COLOR_CYAN, |
---|
707 | COLOR_RED, |
---|
708 | COLOR_MAGENTA, |
---|
709 | COLOR_YELLOW, |
---|
710 | COLOR_WHITE, |
---|
711 | /* Extra values for xterm-16color */ |
---|
712 | COLOR_BLACK + 8, |
---|
713 | COLOR_BLUE + 8, |
---|
714 | COLOR_GREEN + 8, |
---|
715 | COLOR_CYAN + 8, |
---|
716 | COLOR_RED + 8, |
---|
717 | COLOR_MAGENTA + 8, |
---|
718 | COLOR_YELLOW + 8, |
---|
719 | COLOR_WHITE + 8 |
---|
720 | }; |
---|
721 | |
---|
722 | int fg, bg, max; |
---|
723 | |
---|
724 | /* Activate colour */ |
---|
725 | start_color(); |
---|
726 | |
---|
727 | /* If COLORS == 16, it means the terminal supports full bright colours |
---|
728 | * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8), |
---|
729 | * we can build 16*16 colour pairs. |
---|
730 | * If COLORS == 8, it means the terminal does not know about bright |
---|
731 | * colours and we need to get them through A_BOLD and A_BLINK (\e[1m |
---|
732 | * and \e[5m). We can only build 8*8 colour pairs. */ |
---|
733 | max = COLORS >= 16 ? 16 : 8; |
---|
734 | |
---|
735 | for(bg = 0; bg < max; bg++) |
---|
736 | for(fg = 0; fg < max; fg++) |
---|
737 | { |
---|
738 | /* Use ((max + 7 - fg) % max) instead of fg so that colour 0 |
---|
739 | * is light gray on black, since some terminals don't like |
---|
740 | * this colour pair to be redefined. */ |
---|
741 | int col = ((max + 7 - fg) % max) + max * bg; |
---|
742 | init_pair(col, curses_colors[fg], curses_colors[bg]); |
---|
743 | ncurses_attr[fg + 16 * bg] = COLOR_PAIR(col); |
---|
744 | |
---|
745 | if(max == 8) |
---|
746 | { |
---|
747 | /* Bright fg on simple bg */ |
---|
748 | ncurses_attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col); |
---|
749 | /* Simple fg on bright bg */ |
---|
750 | ncurses_attr[fg + 16 * (bg + 8)] = A_BLINK |
---|
751 | | COLOR_PAIR(col); |
---|
752 | /* Bright fg on bright bg */ |
---|
753 | ncurses_attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD |
---|
754 | | COLOR_PAIR(col); |
---|
755 | } |
---|
756 | } |
---|
757 | |
---|
758 | _caca_width = COLS; |
---|
759 | _caca_height = LINES; |
---|
760 | } |
---|
761 | else |
---|
762 | #endif |
---|
763 | #if defined(USE_CONIO) |
---|
764 | if(_caca_driver == CACA_DRIVER_CONIO) |
---|
765 | { |
---|
766 | gettextinfo(&conio_ti); |
---|
767 | conio_screen = malloc(2 * conio_ti.screenwidth |
---|
768 | * conio_ti.screenheight * sizeof(char)); |
---|
769 | if(conio_screen == NULL) |
---|
770 | return -1; |
---|
771 | # if defined(SCREENUPDATE_IN_PC_H) |
---|
772 | ScreenRetrieve(conio_screen); |
---|
773 | # else |
---|
774 | /* FIXME */ |
---|
775 | # endif |
---|
776 | _caca_width = conio_ti.screenwidth; |
---|
777 | _caca_height = conio_ti.screenheight; |
---|
778 | } |
---|
779 | else |
---|
780 | #endif |
---|
781 | #if defined(USE_X11) |
---|
782 | if(_caca_driver == CACA_DRIVER_X11) |
---|
783 | { |
---|
784 | static int x11_palette[] = |
---|
785 | { |
---|
786 | /* Standard curses colours */ |
---|
787 | 0x0, 0x0, 0x0, |
---|
788 | 0x0, 0x0, 0x8000, |
---|
789 | 0x0, 0x8000, 0x0, |
---|
790 | 0x0, 0x8000, 0x8000, |
---|
791 | 0x8000, 0x0, 0x0, |
---|
792 | 0x8000, 0x0, 0x8000, |
---|
793 | 0x8000, 0x8000, 0x0, |
---|
794 | 0x8000, 0x8000, 0x8000, |
---|
795 | /* Extra values for xterm-16color */ |
---|
796 | 0x4000, 0x4000, 0x4000, |
---|
797 | 0x4000, 0x4000, 0xffff, |
---|
798 | 0x4000, 0xffff, 0x4000, |
---|
799 | 0x4000, 0xffff, 0xffff, |
---|
800 | 0xffff, 0x4000, 0x4000, |
---|
801 | 0xffff, 0x4000, 0xffff, |
---|
802 | 0xffff, 0xffff, 0x4000, |
---|
803 | 0xffff, 0xffff, 0xffff, |
---|
804 | }; |
---|
805 | |
---|
806 | Colormap colormap; |
---|
807 | XSetWindowAttributes x11_winattr; |
---|
808 | int (*old_error_handler)(Display *, XErrorEvent *); |
---|
809 | char const *font_name = "8x13bold"; |
---|
810 | int i; |
---|
811 | |
---|
812 | if(getenv("CACA_GEOMETRY") && *(getenv("CACA_GEOMETRY"))) |
---|
813 | sscanf(getenv("CACA_GEOMETRY"), |
---|
814 | "%ux%u", &_caca_width, &_caca_height); |
---|
815 | |
---|
816 | if(!_caca_width) |
---|
817 | _caca_width = 80; |
---|
818 | if(!_caca_height) |
---|
819 | _caca_height = 32; |
---|
820 | |
---|
821 | x11_dpy = XOpenDisplay(NULL); |
---|
822 | if(x11_dpy == NULL) |
---|
823 | return -1; |
---|
824 | |
---|
825 | if(getenv("CACA_FONT") && *(getenv("CACA_FONT"))) |
---|
826 | font_name = getenv("CACA_FONT"); |
---|
827 | |
---|
828 | /* Ignore font errors */ |
---|
829 | old_error_handler = XSetErrorHandler(x11_error_handler); |
---|
830 | |
---|
831 | x11_font = XLoadFont(x11_dpy, font_name); |
---|
832 | if(!x11_font) |
---|
833 | { |
---|
834 | XCloseDisplay(x11_dpy); |
---|
835 | return -1; |
---|
836 | } |
---|
837 | |
---|
838 | x11_font_struct = XQueryFont(x11_dpy, x11_font); |
---|
839 | if(!x11_font_struct) |
---|
840 | { |
---|
841 | XUnloadFont(x11_dpy, x11_font); |
---|
842 | XCloseDisplay(x11_dpy); |
---|
843 | return -1; |
---|
844 | } |
---|
845 | |
---|
846 | /* Reset the default X11 error handler */ |
---|
847 | XSetErrorHandler(old_error_handler); |
---|
848 | |
---|
849 | x11_font_width = x11_font_struct->max_bounds.width; |
---|
850 | x11_font_height = x11_font_struct->max_bounds.ascent |
---|
851 | + x11_font_struct->max_bounds.descent; |
---|
852 | x11_font_offset = x11_font_struct->max_bounds.descent; |
---|
853 | |
---|
854 | colormap = DefaultColormap(x11_dpy, DefaultScreen(x11_dpy)); |
---|
855 | for(i = 0; i < 16; i++) |
---|
856 | { |
---|
857 | XColor color; |
---|
858 | color.red = x11_palette[i * 3]; |
---|
859 | color.green = x11_palette[i * 3 + 1]; |
---|
860 | color.blue = x11_palette[i * 3 + 2]; |
---|
861 | XAllocColor(x11_dpy, colormap, &color); |
---|
862 | x11_colors[i] = color.pixel; |
---|
863 | } |
---|
864 | |
---|
865 | x11_winattr.backing_store = Always; |
---|
866 | x11_winattr.background_pixel = x11_colors[0]; |
---|
867 | x11_winattr.event_mask = ExposureMask | StructureNotifyMask; |
---|
868 | |
---|
869 | x11_window = XCreateWindow(x11_dpy, DefaultRootWindow(x11_dpy), 0, 0, |
---|
870 | _caca_width * x11_font_width, |
---|
871 | _caca_height * x11_font_height, |
---|
872 | 0, 0, InputOutput, 0, |
---|
873 | CWBackingStore | CWBackPixel | CWEventMask, |
---|
874 | &x11_winattr); |
---|
875 | |
---|
876 | XStoreName(x11_dpy, x11_window, "caca for X"); |
---|
877 | |
---|
878 | XSelectInput(x11_dpy, x11_window, StructureNotifyMask); |
---|
879 | XMapWindow(x11_dpy, x11_window); |
---|
880 | |
---|
881 | x11_gc = XCreateGC(x11_dpy, x11_window, 0, NULL); |
---|
882 | XSetForeground(x11_dpy, x11_gc, x11_colors[15]); |
---|
883 | XSetFont(x11_dpy, x11_gc, x11_font); |
---|
884 | |
---|
885 | for(;;) |
---|
886 | { |
---|
887 | XEvent event; |
---|
888 | XNextEvent(x11_dpy, &event); |
---|
889 | if (event.type == MapNotify) |
---|
890 | break; |
---|
891 | } |
---|
892 | |
---|
893 | /* Disable autorepeat */ |
---|
894 | #if defined(HAVE_X11_XKBLIB_H) |
---|
895 | XkbSetDetectableAutoRepeat(x11_dpy, True, &x11_detect_autorepeat); |
---|
896 | if(!x11_detect_autorepeat) |
---|
897 | XAutoRepeatOff(x11_dpy); |
---|
898 | #endif |
---|
899 | |
---|
900 | XSelectInput(x11_dpy, x11_window, x11_event_mask); |
---|
901 | |
---|
902 | XSync(x11_dpy, False); |
---|
903 | |
---|
904 | x11_pixmap = XCreatePixmap(x11_dpy, x11_window, |
---|
905 | _caca_width * x11_font_width, |
---|
906 | _caca_height * x11_font_height, |
---|
907 | DefaultDepth(x11_dpy, |
---|
908 | DefaultScreen(x11_dpy))); |
---|
909 | |
---|
910 | x11_new_width = x11_new_height = 0; |
---|
911 | } |
---|
912 | else |
---|
913 | #endif |
---|
914 | #if defined(USE_WIN32) |
---|
915 | if(_caca_driver == CACA_DRIVER_WIN32) |
---|
916 | { |
---|
917 | CONSOLE_CURSOR_INFO cci; |
---|
918 | CONSOLE_SCREEN_BUFFER_INFO csbi; |
---|
919 | COORD size; |
---|
920 | |
---|
921 | win32_front = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, |
---|
922 | 0, NULL, |
---|
923 | CONSOLE_TEXTMODE_BUFFER, NULL); |
---|
924 | if(!win32_front || win32_front == INVALID_HANDLE_VALUE) |
---|
925 | return -1; |
---|
926 | |
---|
927 | win32_back = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, |
---|
928 | 0, NULL, |
---|
929 | CONSOLE_TEXTMODE_BUFFER, NULL); |
---|
930 | if(!win32_back || win32_back == INVALID_HANDLE_VALUE) |
---|
931 | return -1; |
---|
932 | |
---|
933 | if(!GetConsoleScreenBufferInfo(win32_hout, &csbi)) |
---|
934 | return -1; |
---|
935 | |
---|
936 | /* Sample code to get the biggest possible window */ |
---|
937 | //size = GetLargestConsoleWindowSize(win32_hout); |
---|
938 | |
---|
939 | _caca_width = csbi.srWindow.Right - csbi.srWindow.Left + 1; |
---|
940 | _caca_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; |
---|
941 | |
---|
942 | size.X = _caca_width; |
---|
943 | size.Y = _caca_height; |
---|
944 | SetConsoleScreenBufferSize(win32_front, size); |
---|
945 | SetConsoleScreenBufferSize(win32_back, size); |
---|
946 | |
---|
947 | SetConsoleMode(win32_front, 0); |
---|
948 | SetConsoleMode(win32_back, 0); |
---|
949 | |
---|
950 | GetConsoleCursorInfo(win32_front, &cci); |
---|
951 | cci.dwSize = 0; |
---|
952 | cci.bVisible = FALSE; |
---|
953 | SetConsoleCursorInfo(win32_front, &cci); |
---|
954 | SetConsoleCursorInfo(win32_back, &cci); |
---|
955 | |
---|
956 | SetConsoleActiveScreenBuffer(win32_front); |
---|
957 | |
---|
958 | win32_buffer = malloc(_caca_width * _caca_height * sizeof(CHAR_INFO)); |
---|
959 | if(win32_buffer == NULL) |
---|
960 | return -1; |
---|
961 | } |
---|
962 | else |
---|
963 | #endif |
---|
964 | #if defined(USE_GL) |
---|
965 | if(_caca_driver == CACA_DRIVER_GL) |
---|
966 | { |
---|
967 | int i; |
---|
968 | char *empty; |
---|
969 | |
---|
970 | if(getenv("CACA_GEOMETRY") && *(getenv("CACA_GEOMETRY"))) |
---|
971 | sscanf(getenv("CACA_GEOMETRY"), |
---|
972 | "%ux%u", &_caca_width, &_caca_height); |
---|
973 | |
---|
974 | if(!_caca_width) |
---|
975 | _caca_width = 80; |
---|
976 | if(!_caca_height) |
---|
977 | _caca_height = 32; |
---|
978 | |
---|
979 | gl_font_width = 9; |
---|
980 | gl_font_height = 15; |
---|
981 | |
---|
982 | gl_width = _caca_width*gl_font_width; |
---|
983 | gl_height = _caca_height*gl_font_height; |
---|
984 | |
---|
985 | glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); |
---|
986 | glutInitWindowSize(gl_width, gl_height); |
---|
987 | gl_window = glutCreateWindow("caca for GL"); |
---|
988 | |
---|
989 | gluOrtho2D(0,gl_width, gl_height, 0); |
---|
990 | |
---|
991 | glDisable(GL_CULL_FACE); |
---|
992 | glDisable(GL_DEPTH_TEST); |
---|
993 | |
---|
994 | glutKeyboardFunc(gl_handle_keyboard); |
---|
995 | glutSpecialFunc(gl_handle_special_key); |
---|
996 | glutReshapeFunc(gl_handle_reshape); |
---|
997 | |
---|
998 | glLoadIdentity(); |
---|
999 | |
---|
1000 | glMatrixMode(GL_PROJECTION); |
---|
1001 | glPushMatrix(); |
---|
1002 | glLoadIdentity(); |
---|
1003 | gluOrtho2D(0, gl_width, gl_height, 0); |
---|
1004 | |
---|
1005 | glMatrixMode(GL_MODELVIEW); |
---|
1006 | |
---|
1007 | |
---|
1008 | glClear(GL_COLOR_BUFFER_BIT); |
---|
1009 | |
---|
1010 | |
---|
1011 | |
---|
1012 | empty = malloc(16*16*4); |
---|
1013 | if(empty == NULL) |
---|
1014 | return -1; |
---|
1015 | |
---|
1016 | memset(empty, 255, 16*16*4); |
---|
1017 | glEnable(GL_TEXTURE_2D); |
---|
1018 | |
---|
1019 | for(i=0;i<94;i++) |
---|
1020 | { |
---|
1021 | glGenTextures(1,&id[i]); |
---|
1022 | glBindTexture(GL_TEXTURE_2D, id[i]); |
---|
1023 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
---|
1024 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
---|
1025 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, |
---|
1026 | 16,16, |
---|
1027 | 0, GL_RGB, GL_UNSIGNED_BYTE, empty); |
---|
1028 | } |
---|
1029 | for(i=0;i<94;i++) |
---|
1030 | { |
---|
1031 | |
---|
1032 | glDisable(GL_TEXTURE_2D); |
---|
1033 | glClear(GL_COLOR_BUFFER_BIT); |
---|
1034 | |
---|
1035 | glColor3f(1,1,1); |
---|
1036 | glRasterPos2f(0,15); |
---|
1037 | glutBitmapCharacter(GLUT_BITMAP_9_BY_15,i+32); |
---|
1038 | |
---|
1039 | |
---|
1040 | glEnable(GL_TEXTURE_2D); |
---|
1041 | glBindTexture(GL_TEXTURE_2D,id[i]); |
---|
1042 | glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, gl_height-16, 16,16, 0); |
---|
1043 | |
---|
1044 | glutMainLoopEvent(); |
---|
1045 | glutPostRedisplay(); |
---|
1046 | } |
---|
1047 | } |
---|
1048 | else |
---|
1049 | #endif |
---|
1050 | |
---|
1051 | { |
---|
1052 | /* Dummy */ |
---|
1053 | } |
---|
1054 | |
---|
1055 | cache_char = malloc(_caca_width * _caca_height * sizeof(uint8_t)); |
---|
1056 | if(cache_char == NULL) |
---|
1057 | return -1; |
---|
1058 | |
---|
1059 | cache_attr = malloc(_caca_width * _caca_height * sizeof(uint8_t)); |
---|
1060 | if(cache_attr == NULL) |
---|
1061 | { |
---|
1062 | free(cache_char); |
---|
1063 | return -1; |
---|
1064 | } |
---|
1065 | |
---|
1066 | memset(cache_char, 0, _caca_width * _caca_height * sizeof(uint8_t)); |
---|
1067 | memset(cache_attr, 0, _caca_width * _caca_height * sizeof(uint8_t)); |
---|
1068 | |
---|
1069 | _caca_empty_line = malloc(_caca_width + 1); |
---|
1070 | memset(_caca_empty_line, ' ', _caca_width); |
---|
1071 | _caca_empty_line[_caca_width] = '\0'; |
---|
1072 | |
---|
1073 | _caca_scratch_line = malloc(_caca_width + 1); |
---|
1074 | |
---|
1075 | _caca_delay = 0; |
---|
1076 | _caca_rendertime = 0; |
---|
1077 | |
---|
1078 | return 0; |
---|
1079 | } |
---|
1080 | |
---|
1081 | int _caca_end_graphics(void) |
---|
1082 | { |
---|
1083 | free(cache_char); |
---|
1084 | free(cache_attr); |
---|
1085 | |
---|
1086 | #if defined(USE_SLANG) |
---|
1087 | /* Nothing to do */ |
---|
1088 | #endif |
---|
1089 | #if defined(USE_NCURSES) |
---|
1090 | /* Nothing to do */ |
---|
1091 | #endif |
---|
1092 | #if defined(USE_CONIO) |
---|
1093 | if(_caca_driver == CACA_DRIVER_CONIO) |
---|
1094 | { |
---|
1095 | free(conio_screen); |
---|
1096 | } |
---|
1097 | else |
---|
1098 | #endif |
---|
1099 | #if defined(USE_X11) |
---|
1100 | if(_caca_driver == CACA_DRIVER_X11) |
---|
1101 | { |
---|
1102 | XSync(x11_dpy, False); |
---|
1103 | #if defined(HAVE_X11_XKBLIB_H) |
---|
1104 | if(!x11_detect_autorepeat) |
---|
1105 | XAutoRepeatOn(x11_dpy); |
---|
1106 | #endif |
---|
1107 | XFreePixmap(x11_dpy, x11_pixmap); |
---|
1108 | XFreeFont(x11_dpy, x11_font_struct); |
---|
1109 | XFreeGC(x11_dpy, x11_gc); |
---|
1110 | XUnmapWindow(x11_dpy, x11_window); |
---|
1111 | XDestroyWindow(x11_dpy, x11_window); |
---|
1112 | XCloseDisplay(x11_dpy); |
---|
1113 | } |
---|
1114 | else |
---|
1115 | #endif |
---|
1116 | #if defined(USE_WIN32) |
---|
1117 | if(_caca_driver == CACA_DRIVER_WIN32) |
---|
1118 | { |
---|
1119 | SetConsoleActiveScreenBuffer(win32_hout); |
---|
1120 | CloseHandle(win32_back); |
---|
1121 | CloseHandle(win32_front); |
---|
1122 | } |
---|
1123 | else |
---|
1124 | #endif |
---|
1125 | #if defined(USE_GL) |
---|
1126 | if(_caca_driver == CACA_DRIVER_GL) |
---|
1127 | { |
---|
1128 | glutDestroyWindow(gl_window); |
---|
1129 | } |
---|
1130 | else |
---|
1131 | #endif |
---|
1132 | { |
---|
1133 | /* Dummy */ |
---|
1134 | } |
---|
1135 | |
---|
1136 | free(_caca_empty_line); |
---|
1137 | |
---|
1138 | return 0; |
---|
1139 | } |
---|
1140 | #endif /* _DOXYGEN_SKIP_ME */ |
---|
1141 | |
---|
1142 | /** \brief Set the window title. |
---|
1143 | * |
---|
1144 | * If libcaca runs in a window, try to change its title. This works with |
---|
1145 | * the X11 and Win32 drivers. |
---|
1146 | * |
---|
1147 | * \param title The desired window title. |
---|
1148 | * \return 0 upon success, a non-zero value if an error occurs. |
---|
1149 | */ |
---|
1150 | int caca_set_window_title(char const *title) |
---|
1151 | { |
---|
1152 | #if defined(USE_X11) |
---|
1153 | if(_caca_driver == CACA_DRIVER_X11) |
---|
1154 | { |
---|
1155 | XStoreName(x11_dpy, x11_window, title); |
---|
1156 | } |
---|
1157 | else |
---|
1158 | #endif |
---|
1159 | #if defined(USE_WIN32) |
---|
1160 | if(_caca_driver == CACA_DRIVER_WIN32) |
---|
1161 | { |
---|
1162 | SetConsoleTitle(title); |
---|
1163 | } |
---|
1164 | else |
---|
1165 | #endif |
---|
1166 | #if defined(USE_GL) |
---|
1167 | if(_caca_driver == CACA_DRIVER_GL) |
---|
1168 | { |
---|
1169 | glutSetWindowTitle(title); |
---|
1170 | } |
---|
1171 | else |
---|
1172 | #endif |
---|
1173 | { |
---|
1174 | /* Not supported */ |
---|
1175 | return -1; |
---|
1176 | } |
---|
1177 | |
---|
1178 | return 0; |
---|
1179 | } |
---|
1180 | |
---|
1181 | /** \brief Get the window width. |
---|
1182 | * |
---|
1183 | * If libcaca runs in a window, get the usable window width. This value can |
---|
1184 | * be used for aspect ratio calculation. If libcaca does not run in a window |
---|
1185 | * or if there is no way to know the font size, assume a 6x10 font is being |
---|
1186 | * used. Note that the units are not necessarily pixels. |
---|
1187 | * |
---|
1188 | * \return The window width. |
---|
1189 | */ |
---|
1190 | unsigned int caca_get_window_width(void) |
---|
1191 | { |
---|
1192 | #if defined(USE_X11) |
---|
1193 | if(_caca_driver == CACA_DRIVER_X11) |
---|
1194 | { |
---|
1195 | return _caca_width * x11_font_width; |
---|
1196 | } |
---|
1197 | else |
---|
1198 | #endif |
---|
1199 | #if defined(USE_WIN32) |
---|
1200 | if(_caca_driver == CACA_DRIVER_WIN32) |
---|
1201 | { |
---|
1202 | /* FIXME */ |
---|
1203 | } |
---|
1204 | else |
---|
1205 | #endif |
---|
1206 | #if defined(USE_GL) |
---|
1207 | if(_caca_driver == CACA_DRIVER_GL) |
---|
1208 | { |
---|
1209 | return gl_width; |
---|
1210 | } |
---|
1211 | else |
---|
1212 | #endif |
---|
1213 | { |
---|
1214 | /* Dummy */ |
---|
1215 | } |
---|
1216 | |
---|
1217 | /* Fallback to a 6x10 font */ |
---|
1218 | return _caca_width * 6; |
---|
1219 | } |
---|
1220 | |
---|
1221 | /** \brief Get the window height. |
---|
1222 | * |
---|
1223 | * If libcaca runs in a window, get the usable window height. This value can |
---|
1224 | * be used for aspect ratio calculation. If libcaca does not run in a window |
---|
1225 | * or if there is no way to know the font size, assume a 6x10 font is being |
---|
1226 | * used. Note that the units are not necessarily pixels. |
---|
1227 | * |
---|
1228 | * \return The window height. |
---|
1229 | */ |
---|
1230 | unsigned int caca_get_window_height(void) |
---|
1231 | { |
---|
1232 | #if defined(USE_X11) |
---|
1233 | if(_caca_driver == CACA_DRIVER_X11) |
---|
1234 | { |
---|
1235 | return _caca_height * x11_font_height; |
---|
1236 | } |
---|
1237 | else |
---|
1238 | #endif |
---|
1239 | #if defined(USE_WIN32) |
---|
1240 | if(_caca_driver == CACA_DRIVER_WIN32) |
---|
1241 | { |
---|
1242 | /* FIXME */ |
---|
1243 | } |
---|
1244 | else |
---|
1245 | #endif |
---|
1246 | #if defined(USE_GL) |
---|
1247 | if(_caca_driver == CACA_DRIVER_GL) |
---|
1248 | { |
---|
1249 | return gl_height; |
---|
1250 | } |
---|
1251 | else |
---|
1252 | #endif |
---|
1253 | { |
---|
1254 | /* Dummy */ |
---|
1255 | } |
---|
1256 | |
---|
1257 | /* Fallback to a 6x10 font */ |
---|
1258 | return _caca_height * 10; |
---|
1259 | } |
---|
1260 | |
---|
1261 | /** \brief Set the refresh delay. |
---|
1262 | * |
---|
1263 | * This function sets the refresh delay in microseconds. The refresh delay |
---|
1264 | * is used by caca_refresh() to achieve constant framerate. See the |
---|
1265 | * caca_refresh() documentation for more details. |
---|
1266 | * |
---|
1267 | * If the argument is zero, constant framerate is disabled. This is the |
---|
1268 | * default behaviour. |
---|
1269 | * |
---|
1270 | * \param usec The refresh delay in microseconds. |
---|
1271 | */ |
---|
1272 | void caca_set_delay(unsigned int usec) |
---|
1273 | { |
---|
1274 | _caca_delay = usec; |
---|
1275 | } |
---|
1276 | |
---|
1277 | /** \brief Get the average rendering time. |
---|
1278 | * |
---|
1279 | * This function returns the average rendering time, which is the average |
---|
1280 | * measured time between two caca_refresh() calls, in microseconds. If |
---|
1281 | * constant framerate was activated by calling caca_set_delay(), the average |
---|
1282 | * rendering time will not be considerably shorter than the requested delay |
---|
1283 | * even if the real rendering time was shorter. |
---|
1284 | * |
---|
1285 | * \return The render time in microseconds. |
---|
1286 | */ |
---|
1287 | unsigned int caca_get_rendertime(void) |
---|
1288 | { |
---|
1289 | return _caca_rendertime; |
---|
1290 | } |
---|
1291 | |
---|
1292 | /** \brief Flush pending changes and redraw the screen. |
---|
1293 | * |
---|
1294 | * This function flushes all graphical operations and prints them to the |
---|
1295 | * screen. Nothing will show on the screen until caca_refresh() is |
---|
1296 | * called. |
---|
1297 | * |
---|
1298 | * If caca_set_delay() was called with a non-zero value, caca_refresh() |
---|
1299 | * will use that value to achieve constant framerate: if two consecutive |
---|
1300 | * calls to caca_refresh() are within a time range shorter than the value |
---|
1301 | * set with caca_set_delay(), the second call will wait a bit before |
---|
1302 | * performing the screen refresh. |
---|
1303 | */ |
---|
1304 | void caca_refresh(void) |
---|
1305 | { |
---|
1306 | #if !defined(_DOXYGEN_SKIP_ME) |
---|
1307 | #define IDLE_USEC 10000 |
---|
1308 | #endif |
---|
1309 | static struct caca_timer timer = CACA_TIMER_INITIALIZER; |
---|
1310 | static int lastticks = 0; |
---|
1311 | int ticks = lastticks + _caca_getticks(&timer); |
---|
1312 | |
---|
1313 | #if defined(USE_SLANG) |
---|
1314 | if(_caca_driver == CACA_DRIVER_SLANG) |
---|
1315 | { |
---|
1316 | SLsmg_refresh(); |
---|
1317 | } |
---|
1318 | else |
---|
1319 | #endif |
---|
1320 | #if defined(USE_NCURSES) |
---|
1321 | if(_caca_driver == CACA_DRIVER_NCURSES) |
---|
1322 | { |
---|
1323 | refresh(); |
---|
1324 | } |
---|
1325 | else |
---|
1326 | #endif |
---|
1327 | #if defined(USE_CONIO) |
---|
1328 | if(_caca_driver == CACA_DRIVER_CONIO) |
---|
1329 | { |
---|
1330 | # if defined(SCREENUPDATE_IN_PC_H) |
---|
1331 | ScreenUpdate(conio_screen); |
---|
1332 | # else |
---|
1333 | /* FIXME */ |
---|
1334 | # endif |
---|
1335 | } |
---|
1336 | else |
---|
1337 | #endif |
---|
1338 | #if defined(USE_X11) |
---|
1339 | if(_caca_driver == CACA_DRIVER_X11) |
---|
1340 | { |
---|
1341 | unsigned int x, y, len; |
---|
1342 | |
---|
1343 | /* First draw the background colours. Splitting the process in two |
---|
1344 | * loops like this is actually slightly faster. */ |
---|
1345 | for(y = 0; y < _caca_height; y++) |
---|
1346 | { |
---|
1347 | for(x = 0; x < _caca_width; x += len) |
---|
1348 | { |
---|
1349 | uint8_t *attr = cache_attr + x + y * _caca_width; |
---|
1350 | |
---|
1351 | len = 1; |
---|
1352 | while(x + len < _caca_width |
---|
1353 | && (attr[len] >> 4) == (attr[0] >> 4)) |
---|
1354 | len++; |
---|
1355 | |
---|
1356 | XSetForeground(x11_dpy, x11_gc, x11_colors[attr[0] >> 4]); |
---|
1357 | XFillRectangle(x11_dpy, x11_pixmap, x11_gc, |
---|
1358 | x * x11_font_width, y * x11_font_height, |
---|
1359 | len * x11_font_width, x11_font_height); |
---|
1360 | } |
---|
1361 | } |
---|
1362 | |
---|
1363 | /* Then print the foreground characters */ |
---|
1364 | for(y = 0; y < _caca_height; y++) |
---|
1365 | { |
---|
1366 | for(x = 0; x < _caca_width; x += len) |
---|
1367 | { |
---|
1368 | uint8_t *attr = cache_attr + x + y * _caca_width; |
---|
1369 | |
---|
1370 | len = 1; |
---|
1371 | |
---|
1372 | /* Skip spaces */ |
---|
1373 | if(cache_char[x + y * _caca_width] == ' ') |
---|
1374 | continue; |
---|
1375 | |
---|
1376 | while(x + len < _caca_width |
---|
1377 | && (attr[len] & 0xf) == (attr[0] & 0xf)) |
---|
1378 | len++; |
---|
1379 | |
---|
1380 | XSetForeground(x11_dpy, x11_gc, x11_colors[attr[0] & 0xf]); |
---|
1381 | XDrawString(x11_dpy, x11_pixmap, x11_gc, x * x11_font_width, |
---|
1382 | (y + 1) * x11_font_height - x11_font_offset, |
---|
1383 | cache_char + x + y * _caca_width, len); |
---|
1384 | } |
---|
1385 | } |
---|
1386 | |
---|
1387 | XCopyArea(x11_dpy, x11_pixmap, x11_window, x11_gc, 0, 0, |
---|
1388 | _caca_width * x11_font_width, _caca_height * x11_font_height, |
---|
1389 | 0, 0); |
---|
1390 | XFlush(x11_dpy); |
---|
1391 | } |
---|
1392 | else |
---|
1393 | #endif |
---|
1394 | #if defined(USE_WIN32) |
---|
1395 | if(_caca_driver == CACA_DRIVER_WIN32) |
---|
1396 | { |
---|
1397 | COORD size, pos; |
---|
1398 | SMALL_RECT rect; |
---|
1399 | unsigned int i; |
---|
1400 | |
---|
1401 | /* Render everything to our back buffer */ |
---|
1402 | for(i = 0; i < _caca_width * _caca_height; i++) |
---|
1403 | { |
---|
1404 | win32_buffer[i].Char.AsciiChar = cache_char[i]; |
---|
1405 | win32_buffer[i].Attributes = win32_fg_palette[cache_attr[i] & 0xf] |
---|
1406 | | win32_bg_palette[cache_attr[i] >> 4]; |
---|
1407 | } |
---|
1408 | |
---|
1409 | /* Blit the back buffer to the front buffer */ |
---|
1410 | size.X = _caca_width; |
---|
1411 | size.Y = _caca_height; |
---|
1412 | pos.X = pos.Y = 0; |
---|
1413 | rect.Left = rect.Top = 0; |
---|
1414 | rect.Right = _caca_width - 1; |
---|
1415 | rect.Bottom = _caca_height - 1; |
---|
1416 | WriteConsoleOutput(win32_front, win32_buffer, size, pos, &rect); |
---|
1417 | } |
---|
1418 | else |
---|
1419 | #endif |
---|
1420 | #if defined(USE_GL) |
---|
1421 | if(_caca_driver == CACA_DRIVER_GL) |
---|
1422 | { |
---|
1423 | unsigned int x, y, offsetx, offsety; |
---|
1424 | |
---|
1425 | |
---|
1426 | glClear(GL_COLOR_BUFFER_BIT); |
---|
1427 | |
---|
1428 | offsety=0; |
---|
1429 | for(y=0;y<gl_height;y+=gl_font_height) |
---|
1430 | { |
---|
1431 | offsetx = 0; |
---|
1432 | for(x=0;x<gl_width;x+=gl_font_width) |
---|
1433 | { |
---|
1434 | uint8_t *attr = cache_attr + offsetx + offsety * _caca_width; |
---|
1435 | int offset; |
---|
1436 | float br, bg, bb; |
---|
1437 | offset = attr[0]>>4; |
---|
1438 | |
---|
1439 | br = ((gl_bg_palette[offset]&0x00FF0000)>>16)/255.0f; |
---|
1440 | bg = ((gl_bg_palette[offset]&0x0000FF00)>>8)/255.0f; |
---|
1441 | bb = ((gl_bg_palette[offset]&0x000000FF))/255.0f; |
---|
1442 | |
---|
1443 | glDisable(GL_TEXTURE_2D); |
---|
1444 | glColor3f(br, bg, bb); |
---|
1445 | glBegin(GL_QUADS); |
---|
1446 | glVertex2f(x,y); |
---|
1447 | glVertex2f(x+gl_font_width,y); |
---|
1448 | glVertex2f(x+gl_font_width,y+gl_font_height); |
---|
1449 | glVertex2f(x,y+gl_font_height); |
---|
1450 | glEnd(); |
---|
1451 | |
---|
1452 | |
---|
1453 | offsetx++; |
---|
1454 | } |
---|
1455 | |
---|
1456 | offsety++; |
---|
1457 | } |
---|
1458 | |
---|
1459 | |
---|
1460 | |
---|
1461 | /* 2nd pass, avoids changing render state too much */ |
---|
1462 | glEnable(GL_BLEND); |
---|
1463 | glEnable(GL_TEXTURE_2D); |
---|
1464 | glBlendFunc(GL_ONE, GL_ONE); |
---|
1465 | |
---|
1466 | offsety=0; |
---|
1467 | for(y=0;y<gl_height;y+=gl_font_height) |
---|
1468 | { |
---|
1469 | offsetx = 0; |
---|
1470 | for(x=0;x<gl_width;x+=gl_font_width) |
---|
1471 | { |
---|
1472 | uint8_t *attr = cache_attr + offsetx + offsety * _caca_width; |
---|
1473 | unsigned char *chr = cache_char + offsetx + offsety * _caca_width; |
---|
1474 | float fr, fg, fb; |
---|
1475 | |
---|
1476 | |
---|
1477 | fr = ((gl_bg_palette[attr[0] & 0xf]&0x00FF0000)>>16)/255.0f; |
---|
1478 | fg = ((gl_bg_palette[attr[0] & 0xf]&0x0000FF00)>>8)/255.0f; |
---|
1479 | fb = ((gl_bg_palette[attr[0] & 0xf]&0x000000FF))/255.0f; |
---|
1480 | |
---|
1481 | if(chr[0] != ' ') |
---|
1482 | { |
---|
1483 | glBindTexture(GL_TEXTURE_2D, id[chr[0]-32]); |
---|
1484 | |
---|
1485 | glColor3f(fr, fg, fb); |
---|
1486 | glBegin(GL_QUADS); |
---|
1487 | glTexCoord2f(0,1); |
---|
1488 | glVertex2f(x,y); |
---|
1489 | glTexCoord2f(0.5,1); |
---|
1490 | glVertex2f(x+gl_font_width,y); |
---|
1491 | glTexCoord2f(0.5,0); |
---|
1492 | glVertex2f(x+gl_font_width,y+gl_font_height); |
---|
1493 | glTexCoord2f(0,0); |
---|
1494 | glVertex2f(x,y+gl_font_height); |
---|
1495 | glEnd(); |
---|
1496 | } |
---|
1497 | offsetx++; |
---|
1498 | } |
---|
1499 | offsety++; |
---|
1500 | } |
---|
1501 | glDisable(GL_BLEND); |
---|
1502 | glDisable(GL_TEXTURE_2D); |
---|
1503 | |
---|
1504 | |
---|
1505 | |
---|
1506 | glutMainLoopEvent(); |
---|
1507 | glutSwapBuffers(); |
---|
1508 | glutPostRedisplay(); |
---|
1509 | } |
---|
1510 | else |
---|
1511 | #endif |
---|
1512 | { |
---|
1513 | /* Dummy */ |
---|
1514 | } |
---|
1515 | |
---|
1516 | if(_caca_resize) |
---|
1517 | { |
---|
1518 | _caca_resize = 0; |
---|
1519 | caca_handle_resize(); |
---|
1520 | } |
---|
1521 | |
---|
1522 | /* Wait until _caca_delay + time of last call */ |
---|
1523 | ticks += _caca_getticks(&timer); |
---|
1524 | for(ticks += _caca_getticks(&timer); |
---|
1525 | ticks + IDLE_USEC < (int)_caca_delay; |
---|
1526 | ticks += _caca_getticks(&timer)) |
---|
1527 | { |
---|
1528 | _caca_sleep(IDLE_USEC); |
---|
1529 | } |
---|
1530 | |
---|
1531 | /* Update the sliding mean of the render time */ |
---|
1532 | _caca_rendertime = (7 * _caca_rendertime + ticks) / 8; |
---|
1533 | |
---|
1534 | lastticks = ticks - _caca_delay; |
---|
1535 | |
---|
1536 | /* If we drifted too much, it's bad, bad, bad. */ |
---|
1537 | if(lastticks > (int)_caca_delay) |
---|
1538 | lastticks = 0; |
---|
1539 | } |
---|
1540 | |
---|
1541 | /* |
---|
1542 | * XXX: following functions are loca |
---|
1543 | */ |
---|
1544 | static void caca_handle_resize(void) |
---|
1545 | { |
---|
1546 | unsigned int old_width = _caca_width; |
---|
1547 | unsigned int old_height = _caca_height; |
---|
1548 | |
---|
1549 | #if defined(USE_SLANG) |
---|
1550 | if(_caca_driver == CACA_DRIVER_SLANG) |
---|
1551 | { |
---|
1552 | SLtt_get_screen_size(); |
---|
1553 | _caca_width = SLtt_Screen_Cols; |
---|
1554 | _caca_height = SLtt_Screen_Rows; |
---|
1555 | |
---|
1556 | if(_caca_width != old_width || _caca_height != old_height) |
---|
1557 | SLsmg_reinit_smg(); |
---|
1558 | } |
---|
1559 | else |
---|
1560 | #endif |
---|
1561 | #if defined(USE_NCURSES) |
---|
1562 | if(_caca_driver == CACA_DRIVER_NCURSES) |
---|
1563 | { |
---|
1564 | struct winsize size; |
---|
1565 | |
---|
1566 | if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) |
---|
1567 | { |
---|
1568 | _caca_width = size.ws_col; |
---|
1569 | _caca_height = size.ws_row; |
---|
1570 | #if defined(HAVE_RESIZE_TERM) |
---|
1571 | resize_term(_caca_height, _caca_width); |
---|
1572 | #else |
---|
1573 | resizeterm(_caca_height, _caca_width); |
---|
1574 | #endif |
---|
1575 | wrefresh(curscr); |
---|
1576 | } |
---|
1577 | } |
---|
1578 | else |
---|
1579 | #endif |
---|
1580 | #if defined(USE_CONIO) |
---|
1581 | if(_caca_driver == CACA_DRIVER_CONIO) |
---|
1582 | { |
---|
1583 | } |
---|
1584 | else |
---|
1585 | #endif |
---|
1586 | #if defined(USE_X11) |
---|
1587 | if(_caca_driver == CACA_DRIVER_X11) |
---|
1588 | { |
---|
1589 | Pixmap new_pixmap; |
---|
1590 | |
---|
1591 | _caca_width = x11_new_width; |
---|
1592 | _caca_height = x11_new_height; |
---|
1593 | |
---|
1594 | new_pixmap = XCreatePixmap(x11_dpy, x11_window, |
---|
1595 | _caca_width * x11_font_width, |
---|
1596 | _caca_height * x11_font_height, |
---|
1597 | DefaultDepth(x11_dpy, |
---|
1598 | DefaultScreen(x11_dpy))); |
---|
1599 | XCopyArea(x11_dpy, x11_pixmap, new_pixmap, x11_gc, 0, 0, |
---|
1600 | old_width * x11_font_width, old_height * x11_font_height, |
---|
1601 | 0, 0); |
---|
1602 | XFreePixmap(x11_dpy, x11_pixmap); |
---|
1603 | x11_pixmap = new_pixmap; |
---|
1604 | } |
---|
1605 | else |
---|
1606 | #endif |
---|
1607 | #if defined(USE_WIN32) |
---|
1608 | if(_caca_driver == CACA_DRIVER_WIN32) |
---|
1609 | { |
---|
1610 | } |
---|
1611 | else |
---|
1612 | #endif |
---|
1613 | #if defined(USE_GL) |
---|
1614 | if(_caca_driver == CACA_DRIVER_GL) |
---|
1615 | { |
---|
1616 | gl_width = gl_new_width; |
---|
1617 | gl_height = gl_new_height; |
---|
1618 | |
---|
1619 | _caca_width = gl_width/gl_font_width; |
---|
1620 | _caca_height = (gl_height/gl_font_height)+1; |
---|
1621 | |
---|
1622 | glMatrixMode(GL_PROJECTION); |
---|
1623 | glPushMatrix(); |
---|
1624 | glLoadIdentity(); |
---|
1625 | |
---|
1626 | glViewport(0,0,gl_width, gl_height); |
---|
1627 | gluOrtho2D(0, gl_width, gl_height, 0); |
---|
1628 | glMatrixMode(GL_MODELVIEW); |
---|
1629 | |
---|
1630 | } |
---|
1631 | else |
---|
1632 | #endif |
---|
1633 | { |
---|
1634 | /* Dummy */ |
---|
1635 | } |
---|
1636 | |
---|
1637 | if(_caca_width != old_width || _caca_height != old_height) |
---|
1638 | { |
---|
1639 | free(cache_char); |
---|
1640 | free(cache_attr); |
---|
1641 | |
---|
1642 | cache_char = malloc(_caca_width * _caca_height * sizeof(uint8_t)); |
---|
1643 | memset(cache_char, 0, _caca_width * _caca_height * sizeof(uint8_t)); |
---|
1644 | cache_attr = malloc(_caca_width * _caca_height * sizeof(uint8_t)); |
---|
1645 | memset(cache_attr, 0, _caca_width * _caca_height * sizeof(uint8_t)); |
---|
1646 | } |
---|
1647 | |
---|
1648 | if(_caca_width != old_width) |
---|
1649 | { |
---|
1650 | free(_caca_empty_line); |
---|
1651 | _caca_empty_line = malloc(_caca_width + 1); |
---|
1652 | memset(_caca_empty_line, ' ', _caca_width); |
---|
1653 | _caca_empty_line[_caca_width] = '\0'; |
---|
1654 | |
---|
1655 | free(_caca_scratch_line); |
---|
1656 | _caca_scratch_line = malloc(_caca_width + 1); |
---|
1657 | } |
---|
1658 | } |
---|
1659 | |
---|
1660 | #if defined(USE_SLANG) |
---|
1661 | static void slang_init_palette(void) |
---|
1662 | { |
---|
1663 | /* See SLang ref., 5.4.4. */ |
---|
1664 | static char *slang_colors[16] = |
---|
1665 | { |
---|
1666 | /* Standard colours */ |
---|
1667 | "black", |
---|
1668 | "blue", |
---|
1669 | "green", |
---|
1670 | "cyan", |
---|
1671 | "red", |
---|
1672 | "magenta", |
---|
1673 | "brown", |
---|
1674 | "lightgray", |
---|
1675 | /* Bright colours */ |
---|
1676 | "gray", |
---|
1677 | "brightblue", |
---|
1678 | "brightgreen", |
---|
1679 | "brightcyan", |
---|
1680 | "brightred", |
---|
1681 | "brightmagenta", |
---|
1682 | "yellow", |
---|
1683 | "white", |
---|
1684 | }; |
---|
1685 | |
---|
1686 | #if defined(OPTIMISE_SLANG_PALETTE) |
---|
1687 | int i; |
---|
1688 | |
---|
1689 | for(i = 0; i < 16 * 16; i++) |
---|
1690 | SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]], |
---|
1691 | slang_colors[slang_palette[i * 2 + 1]]); |
---|
1692 | #else |
---|
1693 | int fg, bg; |
---|
1694 | |
---|
1695 | for(bg = 0; bg < 16; bg++) |
---|
1696 | for(fg = 0; fg < 16; fg++) |
---|
1697 | { |
---|
1698 | int i = fg + 16 * bg; |
---|
1699 | SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]); |
---|
1700 | } |
---|
1701 | #endif |
---|
1702 | } |
---|
1703 | #endif /* USE_SLANG */ |
---|
1704 | |
---|
1705 | #if defined(USE_X11) |
---|
1706 | static int x11_error_handler(Display *dpy, XErrorEvent *event) |
---|
1707 | { |
---|
1708 | /* Ignore the error */ |
---|
1709 | return 0; |
---|
1710 | } |
---|
1711 | #endif |
---|
1712 | |
---|
1713 | #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG)) |
---|
1714 | static RETSIGTYPE sigwinch_handler(int sig) |
---|
1715 | { |
---|
1716 | _caca_resize_event = 1; |
---|
1717 | |
---|
1718 | signal(SIGWINCH, sigwinch_handler);; |
---|
1719 | } |
---|
1720 | #endif |
---|
1721 | |
---|
1722 | /* Exporters */ |
---|
1723 | |
---|
1724 | |
---|
1725 | /* HTML */ |
---|
1726 | static int const html_palette[] = |
---|
1727 | { |
---|
1728 | 0, |
---|
1729 | 0x00007F, |
---|
1730 | 0x007F00, |
---|
1731 | 0x007F7F, |
---|
1732 | 0x7F0000, |
---|
1733 | 0x7F007F, |
---|
1734 | 0x7F7F00, |
---|
1735 | 0x7F7F7F, |
---|
1736 | 0, |
---|
1737 | 0x0000FF, |
---|
1738 | 0x00FF00, |
---|
1739 | 0x00FFFF, |
---|
1740 | 0xFF0000, |
---|
1741 | 0xFF00FF, |
---|
1742 | 0xFFFF00, |
---|
1743 | 0xFFFFFF, |
---|
1744 | |
---|
1745 | }; |
---|
1746 | |
---|
1747 | /** \brief Generate HTML representation of current image. |
---|
1748 | * |
---|
1749 | * This function generates and returns the HTML representation of |
---|
1750 | * the current image. |
---|
1751 | * |
---|
1752 | */ |
---|
1753 | char* caca_get_html(void) |
---|
1754 | { |
---|
1755 | char *buffer; |
---|
1756 | unsigned int x,y; |
---|
1757 | int f,b; |
---|
1758 | |
---|
1759 | /* 13000 -> css palette |
---|
1760 | 40 -> max size used for a pixel (plus 10, never know)*/ |
---|
1761 | |
---|
1762 | buffer = malloc((13000 + ((_caca_width*_caca_height)*40))*sizeof(char)); |
---|
1763 | |
---|
1764 | /* HTML header */ |
---|
1765 | sprintf(buffer, "<html>\n<head>\n<title>Generated by libcaca "VERSION"</title>\n"); |
---|
1766 | /* CSS */ |
---|
1767 | sprintf(buffer, "%s<style>\n", buffer); |
---|
1768 | sprintf(buffer, "%s.caca { font-family: monospace, fixed; font-weight: bold; }\n", buffer); |
---|
1769 | |
---|
1770 | for(f=0;f<0x0f+1;f++) |
---|
1771 | { |
---|
1772 | for(b=0;b<0x0f+1;b++) |
---|
1773 | { |
---|
1774 | sprintf(buffer, |
---|
1775 | "%s.b%x%x { color:#%06x; background-color:#%06x;}\n",buffer, |
---|
1776 | b, f, html_palette[f], html_palette[b]); |
---|
1777 | |
---|
1778 | } |
---|
1779 | } |
---|
1780 | sprintf(buffer, "%s</style>\n</head>\n<body>\n",buffer); |
---|
1781 | |
---|
1782 | /* Table */ |
---|
1783 | sprintf(buffer, "%s<table class='caca' cols='%d' cellpadding='0' cellspacing='0'>\n", buffer,caca_get_height()); |
---|
1784 | |
---|
1785 | for(y=0;y<_caca_height;y++) |
---|
1786 | { |
---|
1787 | sprintf(buffer, |
---|
1788 | "%s<tr>",buffer); |
---|
1789 | |
---|
1790 | for(x=0;x<_caca_width;x++) |
---|
1791 | { |
---|
1792 | int len; |
---|
1793 | int i; |
---|
1794 | uint8_t *attr = cache_attr + x + y * _caca_width; |
---|
1795 | |
---|
1796 | /* Use colspan option to factorize cells with same attributes |
---|
1797 | (see below) */ |
---|
1798 | len=1; |
---|
1799 | while(x + len < _caca_width |
---|
1800 | && (attr[len]>>4) == (attr[0]>>4) && |
---|
1801 | (attr[len]&0x0f) == (attr[0]&0x0f)) |
---|
1802 | len++; |
---|
1803 | |
---|
1804 | if(len==1) |
---|
1805 | { |
---|
1806 | sprintf(buffer, |
---|
1807 | "%s<td class=b%x%x>%c</td>",buffer, |
---|
1808 | cache_attr[x+y*caca_get_width()]>>4, |
---|
1809 | cache_attr[x+y*caca_get_width()]&0x0f, |
---|
1810 | cache_char[x+y*caca_get_width()]); |
---|
1811 | } |
---|
1812 | else |
---|
1813 | { |
---|
1814 | sprintf(buffer, |
---|
1815 | "%s<td class=b%x%x colspan=%d>",buffer, |
---|
1816 | cache_attr[x+y*caca_get_width()]>> 4, |
---|
1817 | cache_attr[x+y*caca_get_width()]&0x0f, |
---|
1818 | len+1); |
---|
1819 | |
---|
1820 | for(i=0;i<len;i++) |
---|
1821 | { |
---|
1822 | if(cache_char[x+y*caca_get_width()]!=' ') |
---|
1823 | sprintf(buffer, "%s%c", buffer,cache_char[x+y*caca_get_width()]); |
---|
1824 | else |
---|
1825 | sprintf(buffer, "%s ",buffer); |
---|
1826 | x++; |
---|
1827 | } |
---|
1828 | sprintf(buffer, "%s</td>",buffer); |
---|
1829 | |
---|
1830 | } |
---|
1831 | |
---|
1832 | } |
---|
1833 | sprintf(buffer, "%s</tr>\n",buffer); |
---|
1834 | } |
---|
1835 | |
---|
1836 | /* Footer */ |
---|
1837 | sprintf(buffer, "%s</table>\n</body>\n</html>\n",buffer); |
---|
1838 | |
---|
1839 | /* Crop to really used size */ |
---|
1840 | buffer = realloc(buffer, (strlen(buffer)+1) * sizeof(char)); |
---|
1841 | |
---|
1842 | return buffer; |
---|
1843 | } |
---|
1844 | |
---|
1845 | |
---|
1846 | static int const irc_palette[] = |
---|
1847 | { |
---|
1848 | /* Dark */ |
---|
1849 | 1, |
---|
1850 | 2, |
---|
1851 | 3, |
---|
1852 | 10, |
---|
1853 | 5, |
---|
1854 | 6, |
---|
1855 | 7, |
---|
1856 | 14, |
---|
1857 | /* Light */ |
---|
1858 | 1, |
---|
1859 | 12, |
---|
1860 | 9, |
---|
1861 | 11, |
---|
1862 | 4, |
---|
1863 | 13, |
---|
1864 | 8, |
---|
1865 | 16, |
---|
1866 | }; |
---|
1867 | |
---|
1868 | |
---|
1869 | /** \brief Generate IRC representation of current image. |
---|
1870 | * |
---|
1871 | * This function generates and returns an IRC representation of |
---|
1872 | * the current image. |
---|
1873 | * This is XChat-like format, %Cf,b with f the foreground color, |
---|
1874 | * and b the background color. |
---|
1875 | * |
---|
1876 | */ |
---|
1877 | char* caca_get_irc(void) |
---|
1878 | { |
---|
1879 | char *buffer; |
---|
1880 | unsigned int x, y; |
---|
1881 | /* 15 bytes assumed for max length per pixel */ |
---|
1882 | buffer = malloc(((_caca_width*_caca_height*15)+1)*sizeof(char)); |
---|
1883 | sprintf(buffer,"%%O"); |
---|
1884 | |
---|
1885 | for(y=0;y<_caca_height;y++) |
---|
1886 | { |
---|
1887 | for(x=0;x<_caca_width;x++) |
---|
1888 | { |
---|
1889 | if(cache_char[x+y*caca_get_width()] == ' ') |
---|
1890 | { |
---|
1891 | sprintf(buffer, |
---|
1892 | "%s%%C%d,%d%c", buffer, |
---|
1893 | irc_palette[cache_attr[x+y*caca_get_width()]>>4], |
---|
1894 | irc_palette[cache_attr[x+y*caca_get_width()]>>4], |
---|
1895 | '#'); |
---|
1896 | } |
---|
1897 | else if(cache_char[x+y*caca_get_width()] == '%') |
---|
1898 | { |
---|
1899 | sprintf(buffer, |
---|
1900 | "%s%%C%d,%d%%%%", buffer, |
---|
1901 | irc_palette[cache_attr[x+y*caca_get_width()]&0x0f], |
---|
1902 | irc_palette[cache_attr[x+y*caca_get_width()]>> 4]); |
---|
1903 | } |
---|
1904 | else if(cache_char[x+y*caca_get_width()]>='0' && cache_char[x+y*caca_get_width()]<='9') |
---|
1905 | { |
---|
1906 | sprintf(buffer, |
---|
1907 | "%s%%C%d,%d%%B%%B%c", buffer, |
---|
1908 | irc_palette[cache_attr[x+y*caca_get_width()]&0x0f], |
---|
1909 | irc_palette[cache_attr[x+y*caca_get_width()]>> 4], |
---|
1910 | cache_char[x+y*caca_get_width()]); |
---|
1911 | } |
---|
1912 | else |
---|
1913 | { |
---|
1914 | sprintf(buffer, |
---|
1915 | "%s%%C%d,%d%c", buffer, |
---|
1916 | irc_palette[cache_attr[x+y*caca_get_width()]&0x0f], |
---|
1917 | irc_palette[cache_attr[x+y*caca_get_width()]>> 4], |
---|
1918 | cache_char[x+y*caca_get_width()]); |
---|
1919 | } |
---|
1920 | |
---|
1921 | } |
---|
1922 | sprintf(buffer, "%s\n", buffer); |
---|
1923 | } |
---|
1924 | |
---|
1925 | /* Crop to really used size */ |
---|
1926 | buffer = realloc(buffer, (strlen(buffer)+1) * sizeof(char)); |
---|
1927 | |
---|
1928 | return buffer; |
---|
1929 | } |
---|