fix deprecation warnings from latest dmd
[SmugglerRL.git] / src / graphix0.d
blobe79295e0045d8b951398559868a01a6f2555e0bb
1 import colour;
2 import logging;
3 import util;
4 import constants;
7 interface CharGfx0 {
8 void refresh();
9 uint maxx();
10 uint maxy();
11 dchar getch();
12 void settitle(string title);
13 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);
14 void close();
16 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) {
17 import std.conv: dtext;
18 foreach (ch; dtext(text)) {
19 mvaddch(ch, y, x++ /* no wrapping, just go off the edge of the screen */, fg, bg, bold, italic, underline, reverse);
25 class SDL0: CharGfx0 {
26 import derelict.sdl2.image, derelict.sdl2.sdl, derelict.sdl2.ttf, derelict.sdl2.mixer;
28 SDL_Renderer *renderer;
29 SDL_Window *sdl_window;
31 SDL_Texture*[] tileset;
32 SDL_Texture*[] tileset_italic;
33 SDL_Texture*[] tileset_italicbold;
34 SDL_Texture*[] tileset_bold;
36 private struct CoordChar {
37 dchar ch = ' ';
38 RGBColour fg = RGBColour(0xffffff), bg = RGBColour(0x0);
39 bool bold, italic, underline, reverse = false;
42 CoordChar[][] screen;
44 enum tile_width = 12;
45 enum tile_height = tile_width * 2;
47 private void sdlerror() {
48 import std.string: fromStringz;
49 throw new Exception(cast(string)("Error from SDL. SDL says: " ~ fromStringz(SDL_GetError())));
53 private bool loadfont(string fpath, ushort height, ref SDL_Texture*[] target) {
54 import std.string: toStringz;
56 TTF_Font *font = TTF_OpenFont(toStringz(fpath), height);
58 SDL_Surface *surface;
59 SDL_Color white = SDL_Color(255, 255, 255, 0);
61 if (!font) {
62 return false;
65 TTF_SetFontKerning(font, 0);
67 ushort[2] text;
69 target = new SDL_Texture*[65536];
71 foreach (ushort i; 0 .. 65536) {
72 if (TTF_GlyphIsProvided(font, i)) {
73 text[0] = i;
74 surface = TTF_RenderUNICODE_Blended(font, text.ptr, white);
75 target[i] = SDL_CreateTextureFromSurface(renderer, surface);
76 SDL_FreeSurface(surface);
77 } else {
78 target[i] = null;
83 TTF_CloseFont(font);
85 return true;
89 this() {
90 version (dynamic_sdl2) {
91 DerelictSDL2.load();
92 DerelictSDL2Image.load();
93 DerelictSDL2TTF.load();
94 DerelictSDL2Mixer.load();
97 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_AUDIO) < 0) {
98 sdlerror();
101 if (TTF_Init() == -1) {
102 sdlerror();
107 int mix_flags = MIX_INIT_FLAC | MIX_INIT_MP3 | MIX_INIT_OGG;
109 if ((Mix_Init(mix_flags) & mix_flags) != mix_flags)
110 sdlerror();
112 // thanks lazy foo
113 if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
114 sdlerror();
116 // no thanks for the formatting, though, you lazy foo!
120 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
122 // Title, bunch of stuff, resolution, borderless fullscreen
123 // SDL_WINDOW_FULLSCREEN actually changes the video mode
124 sdl_window = SDL_CreateWindow(null, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, min_x * tile_width, min_y * tile_height, cast(SDL_WindowFlags)0);
125 if (!sdl_window) { sdlerror(); }
126 // sdl_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP);
127 renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
129 if (!loadfont("assets/font/dvsm.ttf", tile_height, tileset)) { sdlerror(); }
130 if (!loadfont("assets/font/dvsm-italic.ttf", tile_height, tileset_italic)) { sdlerror(); }
131 if (!loadfont("assets/font/dvsm-bolditalic.ttf", tile_height, tileset_italicbold)) { sdlerror(); }
132 if (!loadfont("assets/font/dvsm-bold.ttf", tile_height, tileset_bold)) { sdlerror(); }
134 screen = new CoordChar[][](maxx(), maxy());
137 void refresh() {
138 // clear the screen
139 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
140 SDL_RenderClear(renderer);
142 // draw the characters onto it
143 foreach (y; 0 .. maxy()) {
144 foreach (x; 0 .. maxx()) {
145 actual_mvaddch(screen[y][x], y, x);
150 // Blit it to the screen. No magic happening here, just some x11 (or win32 or cocoa or what-have-you) calls
151 SDL_RenderPresent(renderer);
154 uint maxx() {
155 int w;
156 SDL_GetWindowSize(sdl_window, &w, null);
157 return w / tile_width;
160 uint maxy() {
161 int h;
162 SDL_GetWindowSize(sdl_window, null, &h);
163 return h / tile_height;
166 dchar getch() {
167 import std.string: fromStringz;
169 SDL_Event e;
171 SDL_StartTextInput();
172 while (true) {
173 if (SDL_WaitEvent(&e) == 1) {
174 if (e.type == SDL_TEXTINPUT) {
175 //return to!dchar(e.text.text);
176 return e.text.text[0];
177 // gained focus, so we need to redraw. IDK why
178 } else if (e.type == SDL_WINDOWEVENT) {
179 refresh();
181 } else {
182 sdlerror();
187 void settitle(string title) {
188 import std.string: toStringz;
189 SDL_SetWindowTitle(sdl_window, toStringz(title));
192 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) {
193 if (y >= screen.length) {
194 screen.length = maxy();
196 foreach (ref col; screen) {
197 col.length = maxx();
200 screen[y][x] = CoordChar(ch, fg, bg, bold, italic, underline, reverse);
203 private void actual_mvaddch(CoordChar character, uint y, uint x) { with (character) {
204 if (reverse) {
205 RGBColour tmp = fg;
206 fg = bg;
207 bg = tmp;
210 SDL_Texture *renderedchar;
212 if (ch > wchar.max) {
213 log("Character %s large, must fit into a wchar (this is an SDL limitation)", ch);
214 ch = '?';
218 SDL_Texture*[][][] tilesetset = [[tileset, tileset_italic], [tileset_bold, tileset_italicbold]];
219 SDL_Texture*[] tiles = tilesetset[bold][italic];
221 SDL_Texture*[] tiles;
222 if (bold) {
223 if (italic) {
224 tiles = tileset_italicbold;
225 } else {
226 tiles = tileset_bold;
228 } else if (italic) {
229 tiles = tileset_italic;
230 } else {
231 tiles = tileset;
234 // NULL means there's no glyph so fall back to '?'
235 if (tiles[ch] is null) {
236 renderedchar = tiles['?'];
237 } else {
238 renderedchar = tiles[ch];
241 // We just draw a square with colour bg, then draw the char on top of
242 // it, but with transparency so we see the bg.
243 SDL_Rect tile;
246 tile.y = y * tile_height;
247 tile.x = x * tile_width;
248 tile.w = tile_width;
249 tile.h = tile_height;
251 // Set the colour to draw with
252 SDL_SetRenderDrawColor(renderer, bg.r, bg.g, bg.b, 255);
254 // Actually draw it
255 SDL_RenderFillRect(renderer, &tile);
257 // Colourize the letter itself. The parts that aren't the letter will
258 // also get colourized, but that doesn't matter because they have alpha
259 // 256
260 SDL_SetTextureColorMod(renderedchar, fg.r, fg.g, fg.b);
262 // And finally, copy everything over to the actual renderer
263 SDL_RenderCopy(renderer, renderedchar, null, &tile);
266 void close() {
267 foreach (tilesets; [tileset, tileset_bold, tileset_italic, tileset_italicbold]) {
268 foreach (ref texture; tilesets) {
269 SDL_DestroyTexture(texture);
273 SDL_DestroyRenderer(renderer);
274 SDL_DestroyWindow(sdl_window);
275 SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_AUDIO);
276 SDL_Quit();
283 class NCurses0: CharGfx0 {
284 import deimos.ncurses;
285 this() {
286 import core.stdc.locale: setlocale, LC_ALL;
288 setlocale(LC_ALL, "en_US.UTF-8");
289 initscr();
291 clear();
292 noecho();
293 cbreak();
294 keypad(stdscr, true);
295 curs_set(0);
296 start_color();
298 void close() { endwin(); }
300 void refresh() {
301 static import deimos.ncurses;
302 deimos.ncurses.refresh();
305 dchar getch() {
306 static import deimos.ncurses;
307 return deimos.ncurses.getch();
310 uint maxx() { return COLS; }
311 uint maxy() { return LINES; }
312 void settitle(string title) {}
314 void mvaddch(dchar ch, uint y, uint x, RGBColour fg, RGBColour bg, bool bold, bool italic, bool underline, bool reverse) {
315 import std.conv: text;
316 import std.string: toStringz;
318 static ushort[ubyte[2]] clrmap;
319 static ushort maxclrindex;
321 ubyte[2] clrs = [get256colour(fg), get256colour(bg)];
322 if (clrs !in clrmap) {
323 init_pair(maxclrindex, clrs[0], clrs[1]);
324 clrmap[clrs] = maxclrindex++;
327 uint attrs() {
328 return (bold ? A_BOLD : 0) | /*(italic ? A_ITALIC : 0) | */ (underline ? A_UNDERLINE : 0) | (reverse ? A_REVERSE : 0);
331 attron(attrs() | COLOR_PAIR(*(clrs in clrmap)));
333 mvprintw(y, x, toStringz(text(ch))); // TODO
335 attroff(attrs() | COLOR_PAIR(*(clrs in clrmap)));
342 class BLT0: CharGfx0 {
343 import BearLibTerminal;
344 this() {
345 terminal.open();
346 terminal.set("input.cursor-blink-rate=2147483647");
347 terminal.set("input.cursor-symbol=0x2588");
349 terminal.set("font: assets/font/dvsm.ttf, size=12");
350 terminal.set("default font: assets/font/dvsm.ttf, size=12");
351 terminal.set("italic font: assets/font/dvsm-italic.ttf, size=12");
352 terminal.set("bold font: assets/font/dvsm-bold.ttf, size=12");
353 terminal.set("bolditalic font: assets/font/dvsm-bolditalic.ttf, size=12");
355 // terminal.set("font: use-box-drawing=false, use-block-elements=false");
356 terminal.set("window.resizeable=true");
358 void close() { terminal.close(); }
360 void refresh() { terminal.refresh(); }
362 uint maxx() { return terminal.state(terminal.keycode.width); }
363 uint maxy() { return terminal.state(terminal.keycode.height); }
365 void settitle(string title) {
366 terminal.setf("window.title=%s", title);
369 void mvaddch(dchar ch, uint y, uint x, RGBColour fg, RGBColour bg, bool bold, bool italic, bool underline, bool reverse) {
370 if (reverse) {
371 RGBColour tmp = fg;
372 fg = bg;
373 bg = tmp;
375 terminal.colour(fg);
376 terminal.bkcolour(bg);
379 // it's not beautiful, and it's unclear there even exists an
380 // idiomatic way. But this is the most performant way, and this
381 // is a function that gets called thousands of times per refresh
382 static immutable string[2][2] fontab = [["default", "italic"], ["bold", "bolditalic"]];
383 terminal.font(fontab[bold][italic]);
385 // TODO implement bold and italic (have to load alternate fonts)
386 terminal.put(x, y, ch);
388 terminal.layer(1);
389 if (underline) {
390 terminal.put(x, y, '▁');
391 } else {
392 terminal.put(x, y, ' ');
394 terminal.layer(0);
396 terminal.font("default");
400 dchar getch() {
401 dchar[terminal.keycode] keycode2char = [terminal.keycode.a: 'a',
402 terminal.keycode.b: 'b',
403 terminal.keycode.c: 'c',
404 terminal.keycode.d: 'd',
405 terminal.keycode.e: 'e',
406 terminal.keycode.f: 'f',
407 terminal.keycode.g: 'g',
408 terminal.keycode.h: 'h',
409 terminal.keycode.i: 'i',
410 terminal.keycode.j: 'j',
411 terminal.keycode.k: 'k',
412 terminal.keycode.l: 'l',
413 terminal.keycode.m: 'm',
414 terminal.keycode.n: 'n',
415 terminal.keycode.o: 'o',
416 terminal.keycode.p: 'p',
417 terminal.keycode.q: 'q',
418 terminal.keycode.r: 'r',
419 terminal.keycode.s: 's',
420 terminal.keycode.t: 't',
421 terminal.keycode.u: 'u',
422 terminal.keycode.v: 'v',
423 terminal.keycode.w: 'w',
424 terminal.keycode.x: 'x',
425 terminal.keycode.y: 'y',
426 terminal.keycode.z: 'z',
427 terminal.keycode.KP_1: '1',
428 terminal.keycode.KP_2: '2',
429 terminal.keycode.KP_3: '3',
430 terminal.keycode.KP_4: '4',
431 terminal.keycode.KP_5: '5',
432 terminal.keycode.KP_6: '6',
433 terminal.keycode.KP_7: '7',
434 terminal.keycode.KP_8: '8',
435 terminal.keycode.KP_9: '9',
436 terminal.keycode.KP_0: '0',
437 terminal.keycode.enter: '\n',
438 terminal.keycode.escape: '\033',
439 terminal.keycode.backspace: '\b',
440 terminal.keycode.tab: '\t',
441 terminal.keycode.space: ' ',
442 terminal.keycode.minus: '-',
443 terminal.keycode.equals: '=',
444 terminal.keycode.lbracket: '[',
445 terminal.keycode.rbracket: ']',
446 terminal.keycode.backslash: '\\',
447 terminal.keycode.semicolon: ';',
448 terminal.keycode.apostrophe: '\'',
449 terminal.keycode.grave: '`',
450 terminal.keycode.comma: ',',
451 terminal.keycode.period: '.',
452 terminal.keycode.slash: '/',
453 /+F1 =
454 F2 =
455 F3 =
456 F4 =
457 F5 =
458 F6 =
459 F7 =
460 F8 =
461 F9 =
462 F10 =
463 F11 =
464 F12 =
465 pause = 0x48 /* Pause/Break */,
466 insert = 0x49,
467 home = 0x4a,
468 pageup = 0x4b,
469 K_delete = 0x4c,
470 end = 0x4d,
471 pagedown = 0x4e,
472 right = 0x4F /* Right arrow */,
473 left = 0x50 /* Left arrow */,
474 down = 0x51 /* Down arrow */,
475 up = 0x52 /* Up arrow */,
477 terminal.keycode.KP_divide: '/',
478 terminal.keycode.KP_multiply: '*',
479 terminal.keycode.KP_minus: '-',
480 terminal.keycode.KP_plus: '+',
481 terminal.keycode.KP_enter: '\n',
482 terminal.keycode.KP_1: '1',
483 terminal.keycode.KP_2: '2',
484 terminal.keycode.KP_3: '3',
485 terminal.keycode.KP_4: '4',
486 terminal.keycode.KP_5: '5',
487 terminal.keycode.KP_6: '6',
488 terminal.keycode.KP_7: '7',
489 terminal.keycode.KP_8: '8',
490 terminal.keycode.KP_9: '9',
491 terminal.keycode.KP_0: '0',
492 terminal.keycode.KP_period: '.',
494 /+shift = 0x70,
495 control = 0x71,
496 alt = 0x72,
498 mouse_left = 0x80 /* Buttons */,
499 mouse_right = 0x81,
500 mouse_middle = 0x82,
501 mouse_x1 = 0x83,
502 mouse_x2 = 0x84,
503 mouse_move = 0x85 /* Movement event */,
504 mouse_scroll = 0x86 /* Mouse scroll event */,
505 mouse_x = 0x87 /* Cusor position in cells */,
506 mouse_y = 0x88,
507 mouse_pixel_x = 0x89 /* Cursor position in pixels */,
508 mouse_pixel_y = 0x8A,
509 mouse_wheel = 0x8B /* Scroll direction and amount */,
510 mouse_clicks = 0x8C /* Number of consecutive clicks */,
513 terminal.keycode k;
514 while ((k = terminal.read()) !in keycode2char) {}
515 return keycode2char[k];