Add non-working sdl chargfx0, getch returns dchar, improved html dumping (new! No...
[SmugglerRL.git] / src / graphix0.d
blob7b3fe6d78f711eaad45a6e986edcaab6f766544b
1 import colour;
2 import util;
5 interface CharGfx0 {
6 void refresh();
7 uint maxx();
8 uint maxy();
9 dchar getch();
10 void settitle(string title);
11 void mvaddch(dchar ch, uint y, uint x, RGBColour fg = RGBColour(0xffffff), RGBColour bg = RGBColour(0x000000), bool bold = false, bool italic = false, bool underline = false, bool reverse = false);
12 void close();
14 final void printext(string text, uint y, uint x, RGBColour fg = RGBColour(0xffffff), RGBColour bg = RGBColour(0x000000), bool bold = false, bool italic = false, bool underline = false, bool reverse = false) {
15 import std.conv: dtext;
16 foreach (ch; dtext(text)) {
17 mvaddch(ch, y, x++ /* no wrapping, just go off the edge of the screen */, fg, bg, bold, italic, underline, reverse);
23 class SDL0: CharGfx0 {
24 import derelict.sdl2.image, derelict.sdl2.sdl, derelict.sdl2.ttf, derelict.sdl2.mixer;
26 SDL_Renderer *renderer;
27 SDL_Window *sdl_window;
29 SDL_Texture*[] tileset;
30 SDL_Texture*[] tileset_italic;
31 SDL_Texture*[] tileset_italicbold;
32 SDL_Texture*[] tileset_bold;
34 enum tile_width = 12;
35 enum tile_height = tile_width * 2;
37 private void sdlerror() {
38 import std.string: fromStringz;
39 throw new Exception(cast(string)("Error from SDL. SDL says: " ~ fromStringz(SDL_GetError())));
43 private bool loadfont(string fpath, ushort height, ref SDL_Texture*[] target) {
44 import std.string: toStringz;
46 TTF_Font *font = TTF_OpenFont(toStringz(fpath), height);
48 SDL_Surface *surface;
49 SDL_Color white = SDL_Color(255, 255, 255, 0);
51 if (!font) {
52 return false;
55 TTF_SetFontHinting(font, TTF_HINTING_NONE);
56 TTF_SetFontKerning(font, 0);
58 ushort[2] text;
60 target = new SDL_Texture*[65536];
62 foreach (ushort i; 0 .. 65536) {
63 if (TTF_GlyphIsProvided(font, i)) {
64 text[0] = i;
65 surface = TTF_RenderUNICODE_Blended(font, text.ptr, white);
66 target[i] = SDL_CreateTextureFromSurface(renderer, surface);
67 SDL_FreeSurface(surface);
68 } else {
69 target[i] = null;
74 TTF_CloseFont(font);
76 return true;
80 this() {
81 version (dynamic_sdl2) {
82 DerelictSDL2.load();
83 DerelictSDL2Image.load();
84 DerelictSDL2TTF.load();
85 DerelictSDL2Mixer.load();
88 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_AUDIO) == -1) {
89 sdlerror();
92 if (TTF_Init() == -1) {
93 sdlerror();
96 // Title, bunch of stuff, resolution, borderless fullscreen
97 // SDL_WINDOW_FULLSCREEN actually changes the video mode
98 sdl_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP);
99 // sdl_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP);
100 renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_ACCELERATED);
102 if (!loadfont("assets/font/dvsm.ttf", 36, tileset)) { sdlerror(); }
103 if (!loadfont("assets/font/dvsm-italic.ttf", 36, tileset_italic)) { sdlerror(); }
104 if (!loadfont("assets/font/dvsm-bolditalic.ttf", 36, tileset_italicbold)) { sdlerror(); }
105 if (!loadfont("assets/font/dvsm-bold.ttf", 36, tileset_bold)) { sdlerror(); }
107 // thanks lazy foo
108 if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
109 sdlerror();
111 // no thanks for the formatting, though, you lazy foo!
114 void refresh() {
115 // Blit it to the screen. No magic happening here, just some x11 (or win32 or cocoa or what-have-you) calls
116 SDL_RenderPresent(renderer);
119 uint maxx() {
120 SDL_DisplayMode dm;
121 SDL_GetCurrentDisplayMode(0, &dm);
122 return dm.w;
125 uint maxy() {
126 SDL_DisplayMode dm;
127 SDL_GetCurrentDisplayMode(0, &dm);
128 return dm.h;
131 dchar getch() {
132 import std.conv: to;
133 import std.string: fromStringz;
135 SDL_Event e;
137 SDL_StartTextInput();
138 while (true) {
139 if (SDL_WaitEvent(&e) == 1) {
140 if (e.type == SDL_TEXTINPUT) {
141 //return to!dchar(e.text.text);
142 return e.text.text[0];
143 // gained focus, so we need to redraw. IDK why
144 } else if (e.type == SDL_WINDOWEVENT) {
145 refresh();
147 } else {
148 sdlerror();
153 void settitle(string title) { } // TODO
154 void mvaddch(dchar ch, uint y, uint x, RGBColour fg = RGBColour(0xffffff), RGBColour bg = RGBColour(0x000000), bool bold = false, bool italic = false, bool underline = false, bool reverse = false) {
155 SDL_Texture *renderedchar;
157 if (ch > wchar.max) {
158 import std.stdio;
160 writefln("Character %s large, must fit into a wchar (this is an SDL limitation)", ch);
161 ch = '?';
164 SDL_Texture*[][][] tilesetset = [[tileset, tileset_italic], [tileset_bold, tileset_italicbold]];
165 SDL_Texture*[] tiles = tilesetset[bold][italic];
167 // NULL means there's no glyph so fall back to '?'
168 if (tileset[ch] is null) {
169 renderedchar = tileset['?'];
170 } else {
171 renderedchar = tileset[ch];
174 // We just draw a square with colour bg, then draw the char on top of
175 // it, but with transparency so we see the bg.
176 SDL_Rect tile;
179 tile.y = y * tile_height;
180 tile.x = x * tile_width;
181 tile.w = tile_width;
182 tile.h = tile_height;
184 // Set the colour to draw with
185 SDL_SetRenderDrawColor(renderer, bg.r, bg.g, bg.b, 255);
187 // Actually draw it
188 SDL_RenderFillRect(renderer, &tile);
190 // Colourize the letter itself. The parts that aren't the letter will
191 // also get colourized, but that doesn't matter because they have alpha
192 // 256
193 SDL_SetTextureColorMod(renderedchar, fg.r, fg.g, fg.b);
195 // And finally, copy everything over to the actual renderer
196 SDL_RenderCopy(renderer, renderedchar, null, &tile);
199 void close() {
200 foreach (tilesets; [tileset, tileset_bold, tileset_italic, tileset_italicbold]) {
201 foreach (ref texture; tilesets) {
202 SDL_DestroyTexture(texture);
206 SDL_DestroyRenderer(renderer);
207 SDL_DestroyWindow(sdl_window);
208 SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_AUDIO);
209 SDL_Quit();
216 class NCurses0: CharGfx0 {
217 import deimos.ncurses;
218 this() {
219 import core.stdc.locale: setlocale, LC_ALL;
221 setlocale(LC_ALL, "en_US.UTF-8");
222 initscr();
224 clear();
225 noecho();
226 cbreak();
227 keypad(stdscr, true);
228 curs_set(0);
229 start_color();
231 void close() { endwin(); }
233 void refresh() { refresh(); }
235 dchar getch() {
236 return getch();
239 uint maxx() { return COLS; }
240 uint maxy() { return LINES; }
241 void settitle(string title) {}
243 void mvaddch(dchar ch, uint y, uint x, RGBColour fg, RGBColour bg, bool bold, bool italic, bool underline, bool reverse) {
244 import std.conv: text;
245 import std.string: toStringz;
247 static ushort[ubyte[2]] clrmap;
248 static ushort maxclrindex;
250 ubyte[2] clrs = [get256colour(fg), get256colour(bg)];
251 if (clrs !in clrmap) {
252 init_pair(maxclrindex, clrs[0], clrs[1]);
253 clrmap[clrs] = maxclrindex++;
256 uint attrs() {
257 return (bold ? A_BOLD : 0) | /*(italic ? A_ITALIC : 0) | */ (underline ? A_UNDERLINE : 0) | (reverse ? A_REVERSE : 0);
260 attron(attrs() | COLOR_PAIR(*(clrs in clrmap)));
262 mvprintw(y, x, toStringz(text(ch))); // TODO
264 attroff(attrs() | COLOR_PAIR(*(clrs in clrmap)));
271 class BLT0: CharGfx0 {
272 import BearLibTerminal;
273 this() {
274 terminal.open();
275 terminal.set("input.cursor-blink-rate=2147483647");
276 terminal.set("input.cursor-symbol=0x2588");
278 terminal.set("font: assets/font/dvsm.ttf, size=12");
279 terminal.set("default font: assets/font/dvsm.ttf, size=12");
280 terminal.set("italic font: assets/font/dvsm-italic.ttf, size=12");
281 terminal.set("bold font: assets/font/dvsm-bold.ttf, size=12");
282 terminal.set("bolditalic font: assets/font/dvsm-bolditalic.ttf, size=12");
284 // terminal.set("font: use-box-drawing=false, use-block-elements=false");
285 terminal.set("window.resizeable=true");
287 void close() { terminal.close(); }
289 void refresh() { terminal.refresh(); }
291 uint maxx() { return terminal.state(terminal.keycode.width); }
292 uint maxy() { return terminal.state(terminal.keycode.height); }
294 void settitle(string title) {
295 terminal.setf("window.title=%s", title);
298 void mvaddch(dchar ch, uint y, uint x, RGBColour fg, RGBColour bg, bool bold, bool italic, bool underline, bool reverse) {
299 if (reverse) {
300 RGBColour tmp = fg;
301 fg = bg;
302 bg = tmp;
304 terminal.colour(fg.toint);
305 terminal.bkcolour(bg.toint);
308 // it's not beautiful, and it's unclear there even exists an
309 // idiomatic way. But this is the most performant way, and this
310 // is a function that gets called thousands of times per refresh
311 static immutable string[2][2] fontab = [["default", "italic"], ["bold", "bolditalic"]];
312 terminal.font(fontab[bold][italic]);
314 // TODO implement bold and italic (have to load alternate fonts)
315 terminal.put(x, y, ch);
317 terminal.layer(1);
318 if (underline) {
319 terminal.put(x, y, '▁');
320 } else {
321 terminal.put(x, y, ' ');
323 terminal.layer(0);
325 terminal.font("default");
329 dchar getch() {
330 dchar[terminal.keycode] keycode2char = [terminal.keycode.a: 'a',
331 terminal.keycode.b: 'b',
332 terminal.keycode.c: 'c',
333 terminal.keycode.d: 'd',
334 terminal.keycode.e: 'e',
335 terminal.keycode.f: 'f',
336 terminal.keycode.g: 'g',
337 terminal.keycode.h: 'h',
338 terminal.keycode.i: 'i',
339 terminal.keycode.j: 'j',
340 terminal.keycode.k: 'k',
341 terminal.keycode.l: 'l',
342 terminal.keycode.m: 'm',
343 terminal.keycode.n: 'n',
344 terminal.keycode.o: 'o',
345 terminal.keycode.p: 'p',
346 terminal.keycode.q: 'q',
347 terminal.keycode.r: 'r',
348 terminal.keycode.s: 's',
349 terminal.keycode.t: 't',
350 terminal.keycode.u: 'u',
351 terminal.keycode.v: 'v',
352 terminal.keycode.w: 'w',
353 terminal.keycode.x: 'x',
354 terminal.keycode.y: 'y',
355 terminal.keycode.z: 'z',
356 terminal.keycode.KP_1: '1',
357 terminal.keycode.KP_2: '2',
358 terminal.keycode.KP_3: '3',
359 terminal.keycode.KP_4: '4',
360 terminal.keycode.KP_5: '5',
361 terminal.keycode.KP_6: '6',
362 terminal.keycode.KP_7: '7',
363 terminal.keycode.KP_8: '8',
364 terminal.keycode.KP_9: '9',
365 terminal.keycode.KP_0: '0',
366 terminal.keycode.enter: '\n',
367 terminal.keycode.escape: '\033',
368 terminal.keycode.backspace: '\b',
369 terminal.keycode.tab: '\t',
370 terminal.keycode.space: ' ',
371 terminal.keycode.minus: '-',
372 terminal.keycode.equals: '=',
373 terminal.keycode.lbracket: '[',
374 terminal.keycode.rbracket: ']',
375 terminal.keycode.backslash: '\\',
376 terminal.keycode.semicolon: ';',
377 terminal.keycode.apostrophe: '\'',
378 terminal.keycode.grave: '`',
379 terminal.keycode.comma: ',',
380 terminal.keycode.period: '.',
381 terminal.keycode.slash: '/',
382 /+F1 =
383 F2 =
384 F3 =
385 F4 =
386 F5 =
387 F6 =
388 F7 =
389 F8 =
390 F9 =
391 F10 =
392 F11 =
393 F12 =
394 pause = 0x48 /* Pause/Break */,
395 insert = 0x49,
396 home = 0x4a,
397 pageup = 0x4b,
398 K_delete = 0x4c,
399 end = 0x4d,
400 pagedown = 0x4e,
401 right = 0x4F /* Right arrow */,
402 left = 0x50 /* Left arrow */,
403 down = 0x51 /* Down arrow */,
404 up = 0x52 /* Up arrow */,
406 terminal.keycode.KP_divide: '/',
407 terminal.keycode.KP_multiply: '*',
408 terminal.keycode.KP_minus: '-',
409 terminal.keycode.KP_plus: '+',
410 terminal.keycode.KP_enter: '\n',
411 terminal.keycode.KP_1: '1',
412 terminal.keycode.KP_2: '2',
413 terminal.keycode.KP_3: '3',
414 terminal.keycode.KP_4: '4',
415 terminal.keycode.KP_5: '5',
416 terminal.keycode.KP_6: '6',
417 terminal.keycode.KP_7: '7',
418 terminal.keycode.KP_8: '8',
419 terminal.keycode.KP_9: '9',
420 terminal.keycode.KP_0: '0',
421 terminal.keycode.KP_period: '.',
423 /+shift = 0x70,
424 control = 0x71,
425 alt = 0x72,
427 mouse_left = 0x80 /* Buttons */,
428 mouse_right = 0x81,
429 mouse_middle = 0x82,
430 mouse_x1 = 0x83,
431 mouse_x2 = 0x84,
432 mouse_move = 0x85 /* Movement event */,
433 mouse_scroll = 0x86 /* Mouse scroll event */,
434 mouse_x = 0x87 /* Cusor position in cells */,
435 mouse_y = 0x88,
436 mouse_pixel_x = 0x89 /* Cursor position in pixels */,
437 mouse_pixel_y = 0x8A,
438 mouse_wheel = 0x8B /* Scroll direction and amount */,
439 mouse_clicks = 0x8C /* Number of consecutive clicks */,
442 terminal.keycode k;
443 while ((k = terminal.read()) !in keycode2char) {}
444 return keycode2char[k];