Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

20 лет назад
19 лет назад
20 лет назад
20 лет назад
20 лет назад
20 лет назад
20 лет назад
19 лет назад
20 лет назад
20 лет назад
19 лет назад
19 лет назад
20 лет назад
20 лет назад
20 лет назад
19 лет назад
20 лет назад
20 лет назад
19 лет назад
19 лет назад
19 лет назад
20 лет назад
19 лет назад
20 лет назад
19 лет назад
20 лет назад
19 лет назад
20 лет назад
19 лет назад
20 лет назад
20 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
20 лет назад
20 лет назад
19 лет назад
19 лет назад
20 лет назад
19 лет назад
20 лет назад
19 лет назад
19 лет назад
20 лет назад
19 лет назад
19 лет назад
20 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
20 лет назад
20 лет назад
20 лет назад
20 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377
  1. /*
  2. * libcaca ASCII-Art library
  3. * Copyright (c) 2002-2006 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 Do What The Fuck You Want To
  8. * Public License, Version 2, as published by Sam Hocevar. See
  9. * http://sam.zoy.org/wtfpl/COPYING for more details.
  10. */
  11. /** \file graphics.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Character drawing
  15. *
  16. * This file contains character and string drawing functions.
  17. */
  18. #include "config.h"
  19. #if defined(USE_SLANG)
  20. # if defined(HAVE_SLANG_SLANG_H)
  21. # include <slang/slang.h>
  22. # else
  23. # include <slang.h>
  24. # endif
  25. #endif
  26. #if defined(USE_NCURSES)
  27. # if defined(HAVE_NCURSES_H)
  28. # include <ncurses.h>
  29. # else
  30. # include <curses.h>
  31. # endif
  32. #endif
  33. #if defined(USE_CONIO)
  34. # include <conio.h>
  35. # if defined(SCREENUPDATE_IN_PC_H)
  36. # include <pc.h>
  37. # endif
  38. #endif
  39. #if defined(USE_X11)
  40. # include <X11/Xlib.h>
  41. # if defined(HAVE_X11_XKBLIB_H)
  42. # include <X11/XKBlib.h>
  43. # endif
  44. #endif
  45. #if defined(USE_WIN32)
  46. # include <windows.h>
  47. #endif
  48. #if defined(USE_GL)
  49. # include <GL/gl.h>
  50. # include <GL/glut.h>
  51. # include <GL/freeglut_ext.h>
  52. #endif
  53. #if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
  54. # include <inttypes.h>
  55. #else
  56. typedef unsigned int uint32_t;
  57. typedef unsigned char uint8_t;
  58. #endif
  59. #include <stdio.h> /* BUFSIZ */
  60. #include <string.h>
  61. #include <stdlib.h>
  62. #if defined(HAVE_UNISTD_H)
  63. # include <unistd.h>
  64. #endif
  65. #include <stdarg.h>
  66. #if defined(HAVE_SIGNAL_H)
  67. # include <signal.h>
  68. #endif
  69. #if defined(HAVE_SYS_IOCTL_H)
  70. # include <sys/ioctl.h>
  71. #endif
  72. #include "caca.h"
  73. #include "caca_internals.h"
  74. #include "cucul.h"
  75. #include "cucul_internals.h"
  76. /*
  77. * Global variables
  78. */
  79. #if defined(USE_SLANG)
  80. /* Tables generated by test/optipal.c */
  81. static int const slang_palette[2*16*16] =
  82. {
  83. 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0,
  84. 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 0, 8,
  85. 8, 7, 7, 8, 15, 7, 7, 15, 15, 9, 9, 15, 1, 9, 9, 1,
  86. 7, 9, 9, 7, 8, 1, 1, 8, 0, 1, 15, 10, 10, 15, 2, 10,
  87. 10, 2, 7, 10, 10, 7, 8, 2, 2, 8, 0, 2, 15, 11, 11, 15,
  88. 3, 11, 11, 3, 7, 11, 11, 7, 8, 3, 3, 8, 0, 3, 15, 12,
  89. 12, 15, 4, 12, 12, 4, 7, 12, 12, 7, 8, 4, 4, 8, 0, 4,
  90. 15, 13, 13, 15, 5, 13, 13, 5, 7, 13, 13, 7, 8, 5, 5, 8,
  91. 0, 5, 15, 14, 14, 15, 6, 14, 14, 6, 7, 14, 14, 7, 8, 6,
  92. 6, 8, 0, 6, 4, 6, 6, 4, 12, 14, 14, 12, 6, 2, 2, 6,
  93. 14, 10, 10, 14, 2, 3, 3, 2, 10, 11, 11, 10, 3, 1, 1, 3,
  94. 11, 9, 9, 11, 1, 5, 5, 1, 9, 13, 13, 9, 5, 4, 4, 5,
  95. 13, 12, 12, 13, 4, 14, 6, 12, 12, 6, 14, 4, 6, 10, 2, 14,
  96. 14, 2, 10, 6, 2, 11, 3, 10, 10, 3, 11, 2, 3, 9, 1, 11,
  97. 11, 1, 9, 3, 1, 13, 5, 9, 9, 5, 13, 1, 5, 12, 4, 13,
  98. 13, 4, 12, 5, 0, 7, 0, 15, 15, 8, 8, 15, 15, 1, 7, 1,
  99. 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 0, 0, 1, 1,
  100. 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 2, 2, 3, 3,
  101. 4, 4, 5, 5, 6, 6, 7, 7, 14, 9, 1, 15, 8, 9, 8, 8,
  102. 9, 9, 1, 7, 0, 9, 9, 8, 6, 9, 13, 10, 2, 15, 8, 10,
  103. 7, 2, 15, 2, 2, 7, 0, 10, 10, 8, 5, 10, 12, 11, 3, 15,
  104. 8, 11, 7, 3, 15, 3, 3, 7, 0, 11, 11, 8, 4, 11, 11, 12,
  105. 4, 15, 8, 12, 7, 4, 15, 4, 4, 7, 0, 12, 12, 8, 3, 12,
  106. 10, 13, 5, 15, 8, 13, 7, 5, 15, 5, 5, 7, 0, 13, 13, 8,
  107. 2, 13, 9, 14, 6, 15, 8, 14, 7, 6, 15, 6, 6, 7, 0, 14,
  108. 14, 8, 1, 14, 5, 6, 2, 4, 13, 14, 10, 12, 4, 2, 3, 6,
  109. 12, 10, 11, 14, 6, 3, 1, 2, 14, 11, 9, 10, 2, 1, 5, 3,
  110. 10, 9, 13, 11, 3, 5, 4, 1, 11, 13, 12, 9, 1, 4, 6, 5,
  111. 9, 12, 14, 13, 5, 14, 2, 12, 13, 6, 10, 4, 4, 10, 3, 14,
  112. 12, 2, 11, 6, 6, 11, 1, 10, 14, 3, 9, 2, 2, 9, 5, 11,
  113. 10, 1, 13, 3, 3, 13, 4, 9, 11, 5, 12, 1, 1, 12, 6, 13,
  114. 9, 4, 14, 5, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15,
  115. };
  116. static int const slang_assoc[16*16] =
  117. {
  118. 134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  119. 28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126,
  120. 37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161,
  121. 46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170,
  122. 55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179,
  123. 64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188,
  124. 73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197,
  125. 122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18,
  126. 15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124,
  127. 154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20,
  128. 163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29,
  129. 172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38,
  130. 181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47,
  131. 190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56,
  132. 199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65,
  133. 123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255,
  134. };
  135. #endif
  136. #if defined(USE_WIN32)
  137. static int const win32_fg_palette[] =
  138. {
  139. 0,
  140. FOREGROUND_BLUE,
  141. FOREGROUND_GREEN,
  142. FOREGROUND_GREEN | FOREGROUND_BLUE,
  143. FOREGROUND_RED,
  144. FOREGROUND_RED | FOREGROUND_BLUE,
  145. FOREGROUND_RED | FOREGROUND_GREEN,
  146. FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
  147. FOREGROUND_INTENSITY,
  148. FOREGROUND_INTENSITY | FOREGROUND_BLUE,
  149. FOREGROUND_INTENSITY | FOREGROUND_GREEN,
  150. FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
  151. FOREGROUND_INTENSITY | FOREGROUND_RED,
  152. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
  153. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
  154. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
  155. };
  156. static int const win32_bg_palette[] =
  157. {
  158. 0,
  159. BACKGROUND_BLUE,
  160. BACKGROUND_GREEN,
  161. BACKGROUND_GREEN | BACKGROUND_BLUE,
  162. BACKGROUND_RED,
  163. BACKGROUND_RED | BACKGROUND_BLUE,
  164. BACKGROUND_RED | BACKGROUND_GREEN,
  165. BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
  166. BACKGROUND_INTENSITY,
  167. BACKGROUND_INTENSITY | BACKGROUND_BLUE,
  168. BACKGROUND_INTENSITY | BACKGROUND_GREEN,
  169. BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
  170. BACKGROUND_INTENSITY | BACKGROUND_RED,
  171. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
  172. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
  173. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
  174. };
  175. #endif
  176. #if defined(USE_GL)
  177. /* Ok, I just suck. */
  178. static GLbyte const gl_bgpal[][4] =
  179. {
  180. { 0x00, 0x00, 0x00, 0x7f },
  181. { 0x00, 0x00, 0x3f, 0x7f },
  182. { 0x00, 0x3f, 0x00, 0x7f },
  183. { 0x00, 0x3f, 0x3f, 0x7f },
  184. { 0x3f, 0x00, 0x00, 0x7f },
  185. { 0x3f, 0x00, 0x3f, 0x7f },
  186. { 0x3f, 0x3f, 0x00, 0x7f },
  187. { 0x3f, 0x3f, 0x3f, 0x7f },
  188. // + intensity
  189. { 0x00, 0x00, 0x00, 0x7f },
  190. { 0x00, 0x00, 0x7f, 0x7f },
  191. { 0x00, 0x7f, 0x00, 0x7f },
  192. { 0x00, 0x7f, 0x7f, 0x7f },
  193. { 0x7f, 0x00, 0x00, 0x7f },
  194. { 0x7f, 0x00, 0x7f, 0x7f },
  195. { 0x7f, 0x7f, 0x00, 0x7f },
  196. { 0x7f, 0x7f, 0x7f, 0x7f }
  197. };
  198. static caca_t *gl_kk; /* FIXME: we ought to get rid of this */
  199. #endif
  200. /*
  201. * Local functions
  202. */
  203. static void caca_handle_resize(caca_t *kk);
  204. #if defined(USE_SLANG)
  205. static void slang_init_palette(void);
  206. #endif
  207. #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
  208. static RETSIGTYPE sigwinch_handler(int);
  209. static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
  210. #endif
  211. #if defined(USE_X11)
  212. static int x11_error_handler(Display *, XErrorEvent *);
  213. #endif
  214. #if defined(USE_GL)
  215. static void gl_handle_keyboard(unsigned char, int, int);
  216. static void gl_handle_special_key(int, int, int);
  217. static void gl_handle_reshape(int, int);
  218. static void gl_handle_mouse(int, int, int, int);
  219. static void gl_handle_mouse_motion(int, int);
  220. #endif
  221. #if !defined(_DOXYGEN_SKIP_ME)
  222. int _caca_init_graphics(caca_t *kk)
  223. {
  224. #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
  225. sigwinch_kk = kk;
  226. signal(SIGWINCH, sigwinch_handler);
  227. #endif
  228. #if defined(USE_SLANG)
  229. if(kk->driver == CACA_DRIVER_SLANG)
  230. {
  231. slang_init_palette();
  232. /* Disable alt charset support so that we get a chance to have all
  233. * 256 colour pairs */
  234. SLtt_Has_Alt_Charset = 0;
  235. cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows);
  236. }
  237. else
  238. #endif
  239. #if defined(USE_NCURSES)
  240. if(kk->driver == CACA_DRIVER_NCURSES)
  241. {
  242. static int curses_colors[] =
  243. {
  244. /* Standard curses colours */
  245. COLOR_BLACK,
  246. COLOR_BLUE,
  247. COLOR_GREEN,
  248. COLOR_CYAN,
  249. COLOR_RED,
  250. COLOR_MAGENTA,
  251. COLOR_YELLOW,
  252. COLOR_WHITE,
  253. /* Extra values for xterm-16color */
  254. COLOR_BLACK + 8,
  255. COLOR_BLUE + 8,
  256. COLOR_GREEN + 8,
  257. COLOR_CYAN + 8,
  258. COLOR_RED + 8,
  259. COLOR_MAGENTA + 8,
  260. COLOR_YELLOW + 8,
  261. COLOR_WHITE + 8
  262. };
  263. int fg, bg, max;
  264. /* Activate colour */
  265. start_color();
  266. /* If COLORS == 16, it means the terminal supports full bright colours
  267. * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
  268. * we can build 16*16 colour pairs.
  269. * If COLORS == 8, it means the terminal does not know about bright
  270. * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
  271. * and \e[5m). We can only build 8*8 colour pairs. */
  272. max = COLORS >= 16 ? 16 : 8;
  273. for(bg = 0; bg < max; bg++)
  274. for(fg = 0; fg < max; fg++)
  275. {
  276. /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
  277. * is light gray on black. Some terminals don't like this
  278. * colour pair to be redefined. */
  279. int col = ((max + 7 - fg) % max) + max * bg;
  280. init_pair(col, curses_colors[fg], curses_colors[bg]);
  281. kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col);
  282. if(max == 8)
  283. {
  284. /* Bright fg on simple bg */
  285. kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
  286. /* Simple fg on bright bg */
  287. kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK
  288. | COLOR_PAIR(col);
  289. /* Bright fg on bright bg */
  290. kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
  291. | COLOR_PAIR(col);
  292. }
  293. }
  294. cucul_set_size(kk->qq, COLS, LINES);
  295. }
  296. else
  297. #endif
  298. #if defined(USE_CONIO)
  299. if(kk->driver == CACA_DRIVER_CONIO)
  300. {
  301. gettextinfo(&kk->conio.ti);
  302. kk->conio.screen = malloc(2 * kk->conio.ti.screenwidth
  303. * kk->conio.ti.screenheight * sizeof(char));
  304. if(kk->conio.screen == NULL)
  305. return -1;
  306. # if defined(SCREENUPDATE_IN_PC_H)
  307. ScreenRetrieve(kk->conio.screen);
  308. # else
  309. /* FIXME */
  310. # endif
  311. cucul_set_size(kk->qq, kk->conio.ti.screenwidth,
  312. kk->conio.ti.screenheight);
  313. }
  314. else
  315. #endif
  316. #if defined(USE_X11)
  317. if(kk->driver == CACA_DRIVER_X11)
  318. {
  319. static int const x11_palette[] =
  320. {
  321. /* Standard curses colours */
  322. 0x0, 0x0, 0x0,
  323. 0x0, 0x0, 0x8000,
  324. 0x0, 0x8000, 0x0,
  325. 0x0, 0x8000, 0x8000,
  326. 0x8000, 0x0, 0x0,
  327. 0x8000, 0x0, 0x8000,
  328. 0x8000, 0x8000, 0x0,
  329. 0x8000, 0x8000, 0x8000,
  330. /* Extra values for xterm-16color */
  331. 0x4000, 0x4000, 0x4000,
  332. 0x4000, 0x4000, 0xffff,
  333. 0x4000, 0xffff, 0x4000,
  334. 0x4000, 0xffff, 0xffff,
  335. 0xffff, 0x4000, 0x4000,
  336. 0xffff, 0x4000, 0xffff,
  337. 0xffff, 0xffff, 0x4000,
  338. 0xffff, 0xffff, 0xffff,
  339. };
  340. Colormap colormap;
  341. XSetWindowAttributes x11_winattr;
  342. int (*old_error_handler)(Display *, XErrorEvent *);
  343. char const *fonts[] = { NULL, "8x13bold", "fixed" }, **parser;
  344. char const *geometry;
  345. unsigned int width = 0, height = 0;
  346. int i;
  347. geometry = getenv("CACA_GEOMETRY");
  348. if(geometry && *(geometry))
  349. sscanf(geometry, "%ux%u", &width, &height);
  350. if(width && height)
  351. cucul_set_size(kk->qq, width, height);
  352. kk->x11.dpy = XOpenDisplay(NULL);
  353. if(kk->x11.dpy == NULL)
  354. return -1;
  355. fonts[0] = getenv("CACA_FONT");
  356. if(fonts[0] && *fonts[0])
  357. parser = fonts;
  358. else
  359. parser = fonts + 1;
  360. /* Ignore font errors */
  361. old_error_handler = XSetErrorHandler(x11_error_handler);
  362. /* Parse our font list */
  363. for( ; ; parser++)
  364. {
  365. if(!*parser)
  366. {
  367. XSetErrorHandler(old_error_handler);
  368. XCloseDisplay(kk->x11.dpy);
  369. return -1;
  370. }
  371. kk->x11.font = XLoadFont(kk->x11.dpy, *parser);
  372. if(!kk->x11.font)
  373. continue;
  374. kk->x11.font_struct = XQueryFont(kk->x11.dpy, kk->x11.font);
  375. if(!kk->x11.font_struct)
  376. {
  377. XUnloadFont(kk->x11.dpy, kk->x11.font);
  378. continue;
  379. }
  380. break;
  381. }
  382. /* Reset the default X11 error handler */
  383. XSetErrorHandler(old_error_handler);
  384. kk->x11.font_width = kk->x11.font_struct->max_bounds.width;
  385. kk->x11.font_height = kk->x11.font_struct->max_bounds.ascent
  386. + kk->x11.font_struct->max_bounds.descent;
  387. kk->x11.font_offset = kk->x11.font_struct->max_bounds.descent;
  388. colormap = DefaultColormap(kk->x11.dpy, DefaultScreen(kk->x11.dpy));
  389. for(i = 0; i < 16; i++)
  390. {
  391. XColor color;
  392. color.red = x11_palette[i * 3];
  393. color.green = x11_palette[i * 3 + 1];
  394. color.blue = x11_palette[i * 3 + 2];
  395. XAllocColor(kk->x11.dpy, colormap, &color);
  396. kk->x11.colors[i] = color.pixel;
  397. }
  398. x11_winattr.backing_store = Always;
  399. x11_winattr.background_pixel = kk->x11.colors[0];
  400. x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
  401. kk->x11.window =
  402. XCreateWindow(kk->x11.dpy, DefaultRootWindow(kk->x11.dpy), 0, 0,
  403. kk->qq->width * kk->x11.font_width,
  404. kk->qq->height * kk->x11.font_height,
  405. 0, 0, InputOutput, 0,
  406. CWBackingStore | CWBackPixel | CWEventMask,
  407. &x11_winattr);
  408. XStoreName(kk->x11.dpy, kk->x11.window, "caca for X");
  409. XSelectInput(kk->x11.dpy, kk->x11.window, StructureNotifyMask);
  410. XMapWindow(kk->x11.dpy, kk->x11.window);
  411. kk->x11.gc = XCreateGC(kk->x11.dpy, kk->x11.window, 0, NULL);
  412. XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[15]);
  413. XSetFont(kk->x11.dpy, kk->x11.gc, kk->x11.font);
  414. for(;;)
  415. {
  416. XEvent event;
  417. XNextEvent(kk->x11.dpy, &event);
  418. if (event.type == MapNotify)
  419. break;
  420. }
  421. #if defined(HAVE_X11_XKBLIB_H)
  422. /* Disable autorepeat */
  423. XkbSetDetectableAutoRepeat(kk->x11.dpy, True, &kk->x11.autorepeat);
  424. if(!kk->x11.autorepeat)
  425. XAutoRepeatOff(kk->x11.dpy);
  426. #endif
  427. XSelectInput(kk->x11.dpy, kk->x11.window, kk->x11.event_mask);
  428. XSync(kk->x11.dpy, False);
  429. kk->x11.pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
  430. kk->qq->width * kk->x11.font_width,
  431. kk->qq->height * kk->x11.font_height,
  432. DefaultDepth(kk->x11.dpy,
  433. DefaultScreen(kk->x11.dpy)));
  434. kk->x11.new_width = kk->x11.new_height = 0;
  435. }
  436. else
  437. #endif
  438. #if defined(USE_WIN32)
  439. if(kk->driver == CACA_DRIVER_WIN32)
  440. {
  441. CONSOLE_CURSOR_INFO cci;
  442. CONSOLE_SCREEN_BUFFER_INFO csbi;
  443. COORD size;
  444. kk->win32.front =
  445. CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  446. 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
  447. if(!kk->win32.front || kk->win32.front == INVALID_HANDLE_VALUE)
  448. return -1;
  449. kk->win32.back =
  450. CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  451. 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
  452. if(!kk->win32.back || kk->win32.back == INVALID_HANDLE_VALUE)
  453. return -1;
  454. if(!GetConsoleScreenBufferInfo(kk->win32.hout, &csbi))
  455. return -1;
  456. /* Sample code to get the biggest possible window */
  457. //size = GetLargestConsoleWindowSize(kk->win32.hout);
  458. cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1,
  459. csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
  460. size.X = kk->qq->width;
  461. size.Y = kk->qq->height;
  462. SetConsoleScreenBufferSize(kk->win32.front, size);
  463. SetConsoleScreenBufferSize(kk->win32.back, size);
  464. SetConsoleMode(kk->win32.front, 0);
  465. SetConsoleMode(kk->win32.back, 0);
  466. GetConsoleCursorInfo(kk->win32.front, &cci);
  467. cci.dwSize = 0;
  468. cci.bVisible = FALSE;
  469. SetConsoleCursorInfo(kk->win32.front, &cci);
  470. SetConsoleCursorInfo(kk->win32.back, &cci);
  471. SetConsoleActiveScreenBuffer(kk->win32.front);
  472. kk->win32.buffer = malloc(kk->qq->width * kk->qq->height
  473. * sizeof(CHAR_INFO));
  474. if(kk->win32.buffer == NULL)
  475. return -1;
  476. }
  477. else
  478. #endif
  479. #if defined(USE_GL)
  480. if(kk->driver == CACA_DRIVER_GL)
  481. {
  482. char *empty_texture;
  483. char const *geometry;
  484. char *argv[2] = { "", NULL };
  485. unsigned int width = 0, height = 0;
  486. int argc = 1;
  487. int i;
  488. gl_kk = kk;
  489. geometry = getenv("CACA_GEOMETRY");
  490. if(geometry && *(geometry))
  491. sscanf(geometry, "%ux%u", &width, &height);
  492. if(width && height)
  493. cucul_set_size(kk->qq, width, height);
  494. kk->gl.font_width = 9;
  495. kk->gl.font_height = 15;
  496. kk->gl.width = kk->qq->width * kk->gl.font_width;
  497. kk->gl.height = kk->qq->height * kk->gl.font_height;
  498. kk->gl.resized = 0;
  499. kk->gl.bit = 0;
  500. kk->gl.mouse_changed = kk->gl.mouse_clicked = 0;
  501. kk->gl.mouse_button = kk->gl.mouse_state = 0;
  502. kk->gl.key = 0;
  503. kk->gl.special_key = 0;
  504. kk->gl.sw = 9.0f / 16.0f;
  505. kk->gl.sh = 15.0f / 16.0f;
  506. glutInit(&argc, argv);
  507. glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
  508. glutInitWindowSize(kk->gl.width, kk->gl.height);
  509. kk->gl.window = glutCreateWindow("caca for GL");
  510. gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
  511. glDisable(GL_CULL_FACE);
  512. glDisable(GL_DEPTH_TEST);
  513. glutKeyboardFunc(gl_handle_keyboard);
  514. glutSpecialFunc(gl_handle_special_key);
  515. glutReshapeFunc(gl_handle_reshape);
  516. glutMouseFunc(gl_handle_mouse);
  517. glutMotionFunc(gl_handle_mouse_motion);
  518. glutPassiveMotionFunc(gl_handle_mouse_motion);
  519. glLoadIdentity();
  520. glMatrixMode(GL_PROJECTION);
  521. glPushMatrix();
  522. glLoadIdentity();
  523. gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
  524. glMatrixMode(GL_MODELVIEW);
  525. glClear(GL_COLOR_BUFFER_BIT);
  526. empty_texture = malloc(16 * 16 * 4);
  527. if(empty_texture == NULL)
  528. return -1;
  529. memset(empty_texture, 0xff, 16 * 16 * 4);
  530. glEnable(GL_TEXTURE_2D);
  531. for(i = 0; i < 94; i++)
  532. {
  533. glGenTextures(1, (GLuint*)&kk->gl.id[i]);
  534. glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
  535. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  536. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  537. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
  538. 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture);
  539. }
  540. for(i = 0; i < 94; i++)
  541. {
  542. glDisable(GL_TEXTURE_2D);
  543. glClear(GL_COLOR_BUFFER_BIT);
  544. glColor3f(1, 1, 1);
  545. glRasterPos2f(0, 15);
  546. glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32);
  547. glEnable(GL_TEXTURE_2D);
  548. glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
  549. glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
  550. 0, kk->gl.height - 16, 16, 16, 0);
  551. glutMainLoopEvent();
  552. glutPostRedisplay();
  553. }
  554. }
  555. else
  556. #endif
  557. {
  558. /* Dummy */
  559. }
  560. kk->delay = 0;
  561. kk->rendertime = 0;
  562. return 0;
  563. }
  564. int _caca_end_graphics(caca_t *kk)
  565. {
  566. #if defined(USE_SLANG)
  567. /* Nothing to do */
  568. #endif
  569. #if defined(USE_NCURSES)
  570. /* Nothing to do */
  571. #endif
  572. #if defined(USE_CONIO)
  573. if(kk->driver == CACA_DRIVER_CONIO)
  574. {
  575. free(kk->conio.screen);
  576. }
  577. else
  578. #endif
  579. #if defined(USE_X11)
  580. if(kk->driver == CACA_DRIVER_X11)
  581. {
  582. XSync(kk->x11.dpy, False);
  583. #if defined(HAVE_X11_XKBLIB_H)
  584. if(!kk->x11.autorepeat)
  585. XAutoRepeatOn(kk->x11.dpy);
  586. #endif
  587. XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
  588. XFreeFont(kk->x11.dpy, kk->x11.font_struct);
  589. XFreeGC(kk->x11.dpy, kk->x11.gc);
  590. XUnmapWindow(kk->x11.dpy, kk->x11.window);
  591. XDestroyWindow(kk->x11.dpy, kk->x11.window);
  592. XCloseDisplay(kk->x11.dpy);
  593. }
  594. else
  595. #endif
  596. #if defined(USE_WIN32)
  597. if(kk->driver == CACA_DRIVER_WIN32)
  598. {
  599. SetConsoleActiveScreenBuffer(kk->win32.hout);
  600. CloseHandle(kk->win32.back);
  601. CloseHandle(kk->win32.front);
  602. }
  603. else
  604. #endif
  605. #if defined(USE_GL)
  606. if(kk->driver == CACA_DRIVER_GL)
  607. {
  608. glutDestroyWindow(kk->gl.window);
  609. }
  610. else
  611. #endif
  612. {
  613. /* Dummy */
  614. }
  615. return 0;
  616. }
  617. #endif /* _DOXYGEN_SKIP_ME */
  618. /** \brief Set the window title.
  619. *
  620. * If libcaca runs in a window, try to change its title. This works with
  621. * the X11 and Win32 drivers.
  622. *
  623. * \param title The desired window title.
  624. * \return 0 upon success, a non-zero value if an error occurs.
  625. */
  626. int caca_set_window_title(caca_t *kk, char const *title)
  627. {
  628. #if defined(USE_X11)
  629. if(kk->driver == CACA_DRIVER_X11)
  630. {
  631. XStoreName(kk->x11.dpy, kk->x11.window, title);
  632. }
  633. else
  634. #endif
  635. #if defined(USE_WIN32)
  636. if(kk->driver == CACA_DRIVER_WIN32)
  637. {
  638. SetConsoleTitle(title);
  639. }
  640. else
  641. #endif
  642. #if defined(USE_GL)
  643. if(kk->driver == CACA_DRIVER_GL)
  644. {
  645. glutSetWindowTitle(title);
  646. }
  647. else
  648. #endif
  649. {
  650. /* Not supported */
  651. return -1;
  652. }
  653. return 0;
  654. }
  655. /** \brief Get the window width.
  656. *
  657. * If libcaca runs in a window, get the usable window width. This value can
  658. * be used for aspect ratio calculation. If libcaca does not run in a window
  659. * or if there is no way to know the font size, assume a 6x10 font is being
  660. * used. Note that the units are not necessarily pixels.
  661. *
  662. * \return The window width.
  663. */
  664. unsigned int caca_get_window_width(caca_t *kk)
  665. {
  666. #if defined(USE_X11)
  667. if(kk->driver == CACA_DRIVER_X11)
  668. {
  669. return kk->qq->width * kk->x11.font_width;
  670. }
  671. else
  672. #endif
  673. #if defined(USE_WIN32)
  674. if(kk->driver == CACA_DRIVER_WIN32)
  675. {
  676. /* FIXME */
  677. }
  678. else
  679. #endif
  680. #if defined(USE_GL)
  681. if(kk->driver == CACA_DRIVER_GL)
  682. {
  683. return kk->gl.width;
  684. }
  685. else
  686. #endif
  687. {
  688. /* Dummy */
  689. }
  690. /* Fallback to a 6x10 font */
  691. return kk->qq->width * 6;
  692. }
  693. /** \brief Get the window height.
  694. *
  695. * If libcaca runs in a window, get the usable window height. This value can
  696. * be used for aspect ratio calculation. If libcaca does not run in a window
  697. * or if there is no way to know the font size, assume a 6x10 font is being
  698. * used. Note that the units are not necessarily pixels.
  699. *
  700. * \return The window height.
  701. */
  702. unsigned int caca_get_window_height(caca_t *kk)
  703. {
  704. #if defined(USE_X11)
  705. if(kk->driver == CACA_DRIVER_X11)
  706. {
  707. return kk->qq->height * kk->x11.font_height;
  708. }
  709. else
  710. #endif
  711. #if defined(USE_WIN32)
  712. if(kk->driver == CACA_DRIVER_WIN32)
  713. {
  714. /* FIXME */
  715. }
  716. else
  717. #endif
  718. #if defined(USE_GL)
  719. if(kk->driver == CACA_DRIVER_GL)
  720. {
  721. return kk->gl.height;
  722. }
  723. else
  724. #endif
  725. {
  726. /* Dummy */
  727. }
  728. /* Fallback to a 6x10 font */
  729. return kk->qq->height * 10;
  730. }
  731. /** \brief Set the refresh delay.
  732. *
  733. * This function sets the refresh delay in microseconds. The refresh delay
  734. * is used by caca_display() to achieve constant framerate. See the
  735. * caca_display() documentation for more details.
  736. *
  737. * If the argument is zero, constant framerate is disabled. This is the
  738. * default behaviour.
  739. *
  740. * \param usec The refresh delay in microseconds.
  741. */
  742. void caca_set_delay(caca_t *kk, unsigned int usec)
  743. {
  744. kk->delay = usec;
  745. }
  746. /** \brief Get the average rendering time.
  747. *
  748. * This function returns the average rendering time, which is the average
  749. * measured time between two caca_display() calls, in microseconds. If
  750. * constant framerate was activated by calling caca_set_delay(), the average
  751. * rendering time will not be considerably shorter than the requested delay
  752. * even if the real rendering time was shorter.
  753. *
  754. * \return The render time in microseconds.
  755. */
  756. unsigned int caca_get_rendertime(caca_t *kk)
  757. {
  758. return kk->rendertime;
  759. }
  760. /** \brief Flush pending changes and redraw the screen.
  761. *
  762. * This function flushes all graphical operations and prints them to the
  763. * screen. Nothing will show on the screen until caca_display() is
  764. * called.
  765. *
  766. * If caca_set_delay() was called with a non-zero value, caca_display()
  767. * will use that value to achieve constant framerate: if two consecutive
  768. * calls to caca_display() are within a time range shorter than the value
  769. * set with caca_set_delay(), the second call will wait a bit before
  770. * performing the screen refresh.
  771. */
  772. void caca_display(caca_t *kk)
  773. {
  774. #if !defined(_DOXYGEN_SKIP_ME)
  775. #define IDLE_USEC 10000
  776. #endif
  777. int ticks = kk->lastticks + _caca_getticks(&kk->timer);
  778. #if defined(USE_SLANG)
  779. if(kk->driver == CACA_DRIVER_SLANG)
  780. {
  781. int x, y;
  782. uint8_t *attr = kk->qq->attr;
  783. uint32_t *chars = kk->qq->chars;
  784. for(y = 0; y < (int)kk->qq->height; y++)
  785. {
  786. SLsmg_gotorc(y, 0);
  787. for(x = kk->qq->width; x--; )
  788. {
  789. #if defined(OPTIMISE_SLANG_PALETTE)
  790. /* If foreground == background, just don't use this colour
  791. * pair, and print a space instead of the real character. */
  792. uint8_t fgcolor = *attr & 0xf;
  793. uint8_t bgcolor = *attr >> 4;
  794. if(fgcolor != bgcolor)
  795. {
  796. SLsmg_set_color(slang_assoc[*attr++]);
  797. SLsmg_write_char(*chars++ & 0x7f);
  798. }
  799. else
  800. {
  801. if(fgcolor == CUCUL_COLOR_BLACK)
  802. fgcolor = CUCUL_COLOR_WHITE;
  803. else if(fgcolor == CUCUL_COLOR_WHITE
  804. || fgcolor <= CUCUL_COLOR_LIGHTGRAY)
  805. fgcolor = CUCUL_COLOR_BLACK;
  806. else
  807. fgcolor = CUCUL_COLOR_WHITE;
  808. SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
  809. SLsmg_write_char(' ');
  810. chars++;
  811. attr++;
  812. }
  813. #else
  814. SLsmg_set_color(*attr++);
  815. SLsmg_write_char(*chars++ & 0x7f);
  816. #endif
  817. }
  818. }
  819. SLsmg_refresh();
  820. }
  821. else
  822. #endif
  823. #if defined(USE_NCURSES)
  824. if(kk->driver == CACA_DRIVER_NCURSES)
  825. {
  826. int x, y;
  827. uint8_t *attr = kk->qq->attr;
  828. uint32_t *chars = kk->qq->chars;
  829. for(y = 0; y < (int)kk->qq->height; y++)
  830. {
  831. move(y, 0);
  832. for(x = kk->qq->width; x--; )
  833. {
  834. attrset(kk->ncurses.attr[*attr++]);
  835. addch(*chars++ & 0x7f);
  836. }
  837. }
  838. refresh();
  839. }
  840. else
  841. #endif
  842. #if defined(USE_CONIO)
  843. if(kk->driver == CACA_DRIVER_CONIO)
  844. {
  845. int n;
  846. char *screen = kk->conio.screen;
  847. uint8_t *attr = kk->qq->attr;
  848. uint32_t *chars = kk->qq->chars;
  849. for(n = kk->qq->height * kk->qq->width; n--; )
  850. {
  851. *screen++ = *chars++ & 0x7f;
  852. *screen++ = *attr++;
  853. }
  854. # if defined(SCREENUPDATE_IN_PC_H)
  855. ScreenUpdate(kk->conio.screen);
  856. # else
  857. /* FIXME */
  858. # endif
  859. }
  860. else
  861. #endif
  862. #if defined(USE_X11)
  863. if(kk->driver == CACA_DRIVER_X11)
  864. {
  865. unsigned int x, y, len;
  866. /* First draw the background colours. Splitting the process in two
  867. * loops like this is actually slightly faster. */
  868. for(y = 0; y < kk->qq->height; y++)
  869. {
  870. for(x = 0; x < kk->qq->width; x += len)
  871. {
  872. uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
  873. len = 1;
  874. while(x + len < kk->qq->width
  875. && (attr[len] >> 4) == (attr[0] >> 4))
  876. len++;
  877. XSetForeground(kk->x11.dpy, kk->x11.gc,
  878. kk->x11.colors[attr[0] >> 4]);
  879. XFillRectangle(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
  880. x * kk->x11.font_width, y * kk->x11.font_height,
  881. len * kk->x11.font_width, kk->x11.font_height);
  882. }
  883. }
  884. /* Then print the foreground characters */
  885. for(y = 0; y < kk->qq->height; y++)
  886. {
  887. for(x = 0; x < kk->qq->width; x += len)
  888. {
  889. char buffer[BUFSIZ]; /* FIXME: use a smaller buffer */
  890. uint32_t *chars = kk->qq->chars + x + y * kk->qq->width;
  891. uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
  892. len = 1;
  893. /* Skip spaces */
  894. if(chars[0] == ' ')
  895. continue;
  896. buffer[0] = chars[0] & 0x7f;
  897. while(x + len < kk->qq->width
  898. && (attr[len] & 0xf) == (attr[0] & 0xf))
  899. {
  900. buffer[len] = chars[len] & 0x7f;
  901. len++;
  902. }
  903. XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[attr[0] & 0xf]);
  904. XDrawString(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
  905. x * kk->x11.font_width,
  906. (y + 1) * kk->x11.font_height - kk->x11.font_offset,
  907. buffer, len);
  908. }
  909. }
  910. XCopyArea(kk->x11.dpy, kk->x11.pixmap, kk->x11.window, kk->x11.gc, 0, 0,
  911. kk->qq->width * kk->x11.font_width, kk->qq->height * kk->x11.font_height,
  912. 0, 0);
  913. XFlush(kk->x11.dpy);
  914. }
  915. else
  916. #endif
  917. #if defined(USE_WIN32)
  918. if(kk->driver == CACA_DRIVER_WIN32)
  919. {
  920. COORD size, pos;
  921. SMALL_RECT rect;
  922. unsigned int i;
  923. /* Render everything to our back buffer */
  924. for(i = 0; i < kk->qq->width * kk->qq->height; i++)
  925. {
  926. kk->win32.buffer[i].Char.AsciiChar = kk->qq->chars[i] & 0x7f;
  927. kk->win32.buffer[i].Attributes =
  928. win32_fg_palette[kk->qq->attr[i] & 0xf]
  929. | win32_bg_palette[kk->qq->attr[i] >> 4];
  930. }
  931. /* Blit the back buffer to the front buffer */
  932. size.X = kk->qq->width;
  933. size.Y = kk->qq->height;
  934. pos.X = pos.Y = 0;
  935. rect.Left = rect.Top = 0;
  936. rect.Right = kk->qq->width - 1;
  937. rect.Bottom = kk->qq->height - 1;
  938. WriteConsoleOutput(kk->win32.front, kk->win32.buffer, size, pos, &rect);
  939. }
  940. else
  941. #endif
  942. #if defined(USE_GL)
  943. if(kk->driver == CACA_DRIVER_GL)
  944. {
  945. unsigned int x, y, line;
  946. glClear(GL_COLOR_BUFFER_BIT);
  947. line = 0;
  948. for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
  949. {
  950. uint8_t *attr = kk->qq->attr + line * kk->qq->width;
  951. for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
  952. {
  953. glDisable(GL_TEXTURE_2D);
  954. glColor4bv(gl_bgpal[attr[0] >> 4]);
  955. glBegin(GL_QUADS);
  956. glVertex2f(x, y);
  957. glVertex2f(x + kk->gl.font_width, y);
  958. glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
  959. glVertex2f(x, y + kk->gl.font_height);
  960. glEnd();
  961. attr++;
  962. }
  963. line++;
  964. }
  965. /* 2nd pass, avoids changing render state too much */
  966. glEnable(GL_BLEND);
  967. glEnable(GL_TEXTURE_2D);
  968. glBlendFunc(GL_ONE, GL_ONE);
  969. line = 0;
  970. for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
  971. {
  972. uint8_t *attr = kk->qq->attr + line * kk->qq->width;
  973. uint32_t *chars = kk->qq->chars + line * kk->qq->width;
  974. for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
  975. {
  976. if(*chars != (uint32_t)' ')
  977. {
  978. char ch = *chars & 0x7f;
  979. /* FIXME: check ch bounds */
  980. glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]);
  981. glColor4bv(gl_bgpal[attr[0] & 0xf]);
  982. glBegin(GL_QUADS);
  983. glTexCoord2f(0, kk->gl.sh);
  984. glVertex2f(x, y);
  985. glTexCoord2f(kk->gl.sw, kk->gl.sh);
  986. glVertex2f(x + kk->gl.font_width, y);
  987. glTexCoord2f(kk->gl.sw, 0);
  988. glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
  989. glTexCoord2f(0, 0);
  990. glVertex2f(x, y + kk->gl.font_height);
  991. glEnd();
  992. }
  993. attr++;
  994. chars++;
  995. }
  996. line++;
  997. }
  998. glDisable(GL_BLEND);
  999. glDisable(GL_TEXTURE_2D);
  1000. glutMainLoopEvent();
  1001. glutSwapBuffers();
  1002. glutPostRedisplay();
  1003. }
  1004. else
  1005. #endif
  1006. {
  1007. /* Dummy */
  1008. }
  1009. /* FIXME handle this somewhere else */
  1010. if(kk->resize)
  1011. {
  1012. kk->resize = 0;
  1013. caca_handle_resize(kk);
  1014. }
  1015. /* Wait until kk->delay + time of last call */
  1016. ticks += _caca_getticks(&kk->timer);
  1017. for(ticks += _caca_getticks(&kk->timer);
  1018. ticks + IDLE_USEC < (int)kk->delay;
  1019. ticks += _caca_getticks(&kk->timer))
  1020. {
  1021. _caca_sleep(IDLE_USEC);
  1022. }
  1023. /* Update the sliding mean of the render time */
  1024. kk->rendertime = (7 * kk->rendertime + ticks) / 8;
  1025. kk->lastticks = ticks - kk->delay;
  1026. /* If we drifted too much, it's bad, bad, bad. */
  1027. if(kk->lastticks > (int)kk->delay)
  1028. kk->lastticks = 0;
  1029. }
  1030. /*
  1031. * XXX: following functions are local
  1032. */
  1033. static void caca_handle_resize(caca_t *kk)
  1034. {
  1035. unsigned int new_width, new_height;
  1036. new_width = kk->qq->width;
  1037. new_height = kk->qq->height;
  1038. #if defined(USE_SLANG)
  1039. if(kk->driver == CACA_DRIVER_SLANG)
  1040. {
  1041. SLtt_get_screen_size();
  1042. new_width = SLtt_Screen_Cols;
  1043. new_height = SLtt_Screen_Rows;
  1044. if(new_width != kk->qq->width || new_height != kk->qq->height)
  1045. SLsmg_reinit_smg();
  1046. }
  1047. else
  1048. #endif
  1049. #if defined(USE_NCURSES)
  1050. if(kk->driver == CACA_DRIVER_NCURSES)
  1051. {
  1052. struct winsize size;
  1053. if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
  1054. {
  1055. new_width = size.ws_col;
  1056. new_height = size.ws_row;
  1057. #if defined(HAVE_RESIZE_TERM)
  1058. resize_term(new_height, new_width);
  1059. #else
  1060. resizeterm(new_height, new_width);
  1061. #endif
  1062. wrefresh(curscr);
  1063. }
  1064. }
  1065. else
  1066. #endif
  1067. #if defined(USE_CONIO)
  1068. if(kk->driver == CACA_DRIVER_CONIO)
  1069. {
  1070. /* Nothing to do here. */
  1071. }
  1072. else
  1073. #endif
  1074. #if defined(USE_X11)
  1075. if(kk->driver == CACA_DRIVER_X11)
  1076. {
  1077. Pixmap new_pixmap;
  1078. new_width = kk->x11.new_width;
  1079. new_height = kk->x11.new_height;
  1080. new_pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
  1081. kk->qq->width * kk->x11.font_width,
  1082. kk->qq->height * kk->x11.font_height,
  1083. DefaultDepth(kk->x11.dpy,
  1084. DefaultScreen(kk->x11.dpy)));
  1085. XCopyArea(kk->x11.dpy, kk->x11.pixmap, new_pixmap, kk->x11.gc, 0, 0,
  1086. kk->qq->width * kk->x11.font_width,
  1087. kk->qq->height * kk->x11.font_height, 0, 0);
  1088. XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
  1089. kk->x11.pixmap = new_pixmap;
  1090. }
  1091. else
  1092. #endif
  1093. #if defined(USE_WIN32)
  1094. if(kk->driver == CACA_DRIVER_WIN32)
  1095. {
  1096. /* Nothing to do here. */
  1097. }
  1098. else
  1099. #endif
  1100. #if defined(USE_GL)
  1101. if(kk->driver == CACA_DRIVER_GL)
  1102. {
  1103. kk->gl.width = kk->gl.new_width;
  1104. kk->gl.height = kk->gl.new_height;
  1105. new_width = kk->gl.width / kk->gl.font_width;
  1106. new_height = (kk->gl.height / kk->gl.font_height) + 1;
  1107. glMatrixMode(GL_PROJECTION);
  1108. glPushMatrix();
  1109. glLoadIdentity();
  1110. glViewport(0, 0, kk->gl.width, kk->gl.height);
  1111. gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
  1112. glMatrixMode(GL_MODELVIEW);
  1113. }
  1114. else
  1115. #endif
  1116. {
  1117. /* Dummy */
  1118. }
  1119. /* Tell libcucul we changed size */
  1120. if(new_width != kk->qq->width || new_height != kk->qq->height)
  1121. cucul_set_size(kk->qq, new_width, new_height);
  1122. }
  1123. #if defined(USE_SLANG)
  1124. static void slang_init_palette(void)
  1125. {
  1126. /* See SLang ref., 5.4.4. */
  1127. static char *slang_colors[16] =
  1128. {
  1129. /* Standard colours */
  1130. "black",
  1131. "blue",
  1132. "green",
  1133. "cyan",
  1134. "red",
  1135. "magenta",
  1136. "brown",
  1137. "lightgray",
  1138. /* Bright colours */
  1139. "gray",
  1140. "brightblue",
  1141. "brightgreen",
  1142. "brightcyan",
  1143. "brightred",
  1144. "brightmagenta",
  1145. "yellow",
  1146. "white",
  1147. };
  1148. #if defined(OPTIMISE_SLANG_PALETTE)
  1149. int i;
  1150. for(i = 0; i < 16 * 16; i++)
  1151. SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]],
  1152. slang_colors[slang_palette[i * 2 + 1]]);
  1153. #else
  1154. int fg, bg;
  1155. for(bg = 0; bg < 16; bg++)
  1156. for(fg = 0; fg < 16; fg++)
  1157. {
  1158. int i = fg + 16 * bg;
  1159. SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
  1160. }
  1161. #endif
  1162. }
  1163. #endif /* USE_SLANG */
  1164. #if defined(USE_X11)
  1165. static int x11_error_handler(Display *dpy, XErrorEvent *event)
  1166. {
  1167. /* Ignore the error */
  1168. return 0;
  1169. }
  1170. #endif
  1171. #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
  1172. static RETSIGTYPE sigwinch_handler(int sig)
  1173. {
  1174. sigwinch_kk->resize_event = 1;
  1175. signal(SIGWINCH, sigwinch_handler);;
  1176. }
  1177. #endif
  1178. #if defined(USE_GL)
  1179. static void gl_handle_keyboard(unsigned char key, int x, int y)
  1180. {
  1181. caca_t *kk = gl_kk;
  1182. kk->gl.key = key;
  1183. }
  1184. static void gl_handle_special_key(int key, int x, int y)
  1185. {
  1186. caca_t *kk = gl_kk;
  1187. kk->gl.special_key = key;
  1188. }
  1189. static void gl_handle_reshape(int w, int h)
  1190. {
  1191. caca_t *kk = gl_kk;
  1192. if(kk->gl.bit) /* Do not handle reshaping at the first time */
  1193. {
  1194. kk->gl.new_width = w;
  1195. kk->gl.new_height = h;
  1196. kk->gl.resized = 1;
  1197. }
  1198. else
  1199. kk->gl.bit = 1;
  1200. }
  1201. static void gl_handle_mouse(int button, int state, int x, int y)
  1202. {
  1203. caca_t *kk = gl_kk;
  1204. kk->gl.mouse_clicked = 1;
  1205. kk->gl.mouse_button = button;
  1206. kk->gl.mouse_state = state;
  1207. kk->gl.mouse_x = x / kk->gl.font_width;
  1208. kk->gl.mouse_y = y / kk->gl.font_height;
  1209. kk->gl.mouse_changed = 1;
  1210. }
  1211. static void gl_handle_mouse_motion(int x, int y)
  1212. {
  1213. caca_t *kk = gl_kk;
  1214. kk->gl.mouse_x = x / kk->gl.font_width;
  1215. kk->gl.mouse_y = y / kk->gl.font_height;
  1216. kk->gl.mouse_changed = 1;
  1217. }
  1218. #endif