You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

graphics.c 55 KiB

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