您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

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