Emulator core geared towards emulating ZZT and Super ZZT.
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.

frontend_sdl.c 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /**
  2. * Copyright (c) 2018 Adrian Siekierka
  3. *
  4. * This file is part of Zeta.
  5. *
  6. * Zeta is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Zeta 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
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Zeta. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <SDL2/SDL.h>
  23. #include "zzt.h"
  24. static int def_palette[] = {
  25. 0x000000, 0x0000aa, 0x00aa00, 0x00aaaa,
  26. 0xaa0000, 0xaa00aa, 0xaa5500, 0xaaaaaa,
  27. 0x555555, 0x5555ff, 0x55ff55, 0x55ffff,
  28. 0xff5555, 0xff55ff, 0xffff55, 0xffffff
  29. };
  30. static const u8 sdl_to_pc_scancode[] = {
  31. /* 0*/ 0,
  32. /* 1*/ 0, 0, 0,
  33. /* 4*/ 0x1E, 0x30, 0x2E, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, /* A-I */
  34. /* 13*/ 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, /* J-R */
  35. /* 22*/ 0x1F, 0x14, 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, /* S-Z */
  36. /* 30*/ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* 1-0 */
  37. /* 40*/ 0x1C, 0x01, 0x0E, 0x0F, 0x39,
  38. /* 45*/ 0x0C, 0x0D, 0x1A, 0x1B, 0x2B,
  39. /* 50*/ 0x2B, 0x27, 0x28, 0x29,
  40. /* 54*/ 0x33, 0x34, 0x35, 0x3A,
  41. 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x57, 0x58,
  42. 0x37, 0x46, 0, 0x52, 0x47, 0x49, 0x53, 0x4F, 0x51,
  43. 0x4D, 0x4B, 0x50, 0x48, 0x45
  44. };
  45. static const int sdl_to_pc_scancode_max = sizeof(sdl_to_pc_scancode) - 1;
  46. extern unsigned char res_8x14_bin[];
  47. static SDL_Texture *create_texture_from_array(SDL_Renderer *renderer, unsigned char *data, int height) {
  48. SDL_Texture *texture;
  49. SDL_Rect rect;
  50. Uint32 texdata[8 * height];
  51. Uint32* tptr;
  52. int ch, cx, cy, ctmp;
  53. rect.w = 8;
  54. rect.h = height;
  55. texture = SDL_CreateTexture(renderer,
  56. SDL_PIXELFORMAT_RGBA32,
  57. SDL_TEXTUREACCESS_STATIC,
  58. 16*rect.w, 16*rect.h);
  59. for (ch = 0; ch < 256; ch++) {
  60. rect.x = (ch & 0x0F) * rect.w;
  61. rect.y = (ch >> 4) * rect.h;
  62. tptr = texdata;
  63. for (cy = 0; cy < height; cy++, data++) {
  64. ctmp = data[0];
  65. for (cx = 0; cx < 8; cx++, tptr++, ctmp <<= 1) {
  66. *tptr = ((ctmp >> 7) & 1) * 0xFFFFFFFF;
  67. }
  68. }
  69. SDL_UpdateTexture(texture, &rect, texdata, 32);
  70. }
  71. return texture;
  72. }
  73. long zeta_time_ms() {
  74. return SDL_GetTicks();
  75. }
  76. void cpu_ext_log(const char *s) {
  77. fprintf(stderr, "%s\n", s);
  78. }
  79. void init_posix_vfs(const char *path);
  80. void speaker_on(double freq) {}
  81. void speaker_off() {}
  82. int zeta_has_feature(int feature) {
  83. return 1;
  84. }
  85. static SDL_mutex *zzt_thread_lock;
  86. static u8 zzt_vram_copy[80*25*2];
  87. static u8 zzt_thread_running;
  88. static u8 video_blink = 1;
  89. static int zzt_thread_func(void *ptr) {
  90. while (zzt_thread_running) {
  91. if (SDL_LockMutex(zzt_thread_lock) == 0) {
  92. if (!zzt_execute(40000)) zzt_thread_running = 0;
  93. SDL_UnlockMutex(zzt_thread_lock);
  94. }
  95. SDL_Delay(1);
  96. }
  97. return 0;
  98. }
  99. int main(int argc, char **argv) {
  100. SDL_Window *window;
  101. SDL_Renderer *renderer;
  102. SDL_Rect rectSrc, rectDst;
  103. SDL_Texture *chartex;
  104. int charw, charh;
  105. SDL_Event event;
  106. int scode, kcode;
  107. SDL_Thread* zzt_thread;
  108. if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  109. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init failed! %s", SDL_GetError());
  110. return 1;
  111. }
  112. charw = 8;
  113. charh = 14;
  114. window = SDL_CreateWindow("Zeta", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
  115. 80*charw, 25*charh, 0);
  116. renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
  117. SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, 0);
  118. chartex = create_texture_from_array(renderer, res_8x14_bin, charh);
  119. rectSrc.w = rectDst.w = charw;
  120. rectSrc.h = rectDst.h = charh;
  121. SDL_SetTextureBlendMode(chartex, SDL_BLENDMODE_BLEND);
  122. init_posix_vfs("");
  123. zzt_init();
  124. zzt_thread_lock = SDL_CreateMutex();
  125. if (!zzt_thread_lock) {
  126. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create ZZT thread mutex! %s", SDL_GetError());
  127. return 1;
  128. }
  129. long last_timer_call = zeta_time_ms();
  130. u8 cont_loop = 1;
  131. zzt_thread_running = 1;
  132. zzt_thread = SDL_CreateThread(zzt_thread_func, "ZZT Executor", (void*)NULL);
  133. if (zzt_thread == NULL) {
  134. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create ZZT thread! %s", SDL_GetError());
  135. return 1;
  136. }
  137. while (cont_loop) {
  138. if (SDL_LockMutex(zzt_thread_lock) != 0) {
  139. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not lock ZZT thread mutex! %s", SDL_GetError());
  140. cont_loop = 0;
  141. break;
  142. }
  143. u8* ram = zzt_get_ram();
  144. memcpy(zzt_vram_copy, ram + 0xB8000, 80*25*2);
  145. zzt_mark_frame();
  146. while (SDL_PollEvent(&event)) {
  147. switch (event.type) {
  148. case SDL_KEYDOWN:
  149. scode = event.key.keysym.scancode;
  150. kcode = event.key.keysym.sym;
  151. if (kcode < 0 || kcode >= 127) kcode = 0;
  152. if (scode >= 0 && scode <= sdl_to_pc_scancode_max) {
  153. zzt_key(kcode, sdl_to_pc_scancode[scode]);
  154. }
  155. break;
  156. case SDL_KEYUP:
  157. scode = event.key.keysym.scancode;
  158. if (scode >= 0 && scode <= sdl_to_pc_scancode_max) {
  159. zzt_keyup(sdl_to_pc_scancode[scode]);
  160. }
  161. break;
  162. case SDL_QUIT:
  163. cont_loop = 0;
  164. break;
  165. }
  166. }
  167. long curr_timer_call = zeta_time_ms();
  168. if ((curr_timer_call - last_timer_call) >= 55) {
  169. zzt_mark_timer();
  170. last_timer_call = curr_timer_call;
  171. }
  172. SDL_UnlockMutex(zzt_thread_lock);
  173. int vpos = 0;
  174. for (int y = 0; y < 25; y++) {
  175. for (int x = 0; x < 80; x++, vpos += 2) {
  176. u8 chr = zzt_vram_copy[vpos];
  177. u8 col = zzt_vram_copy[vpos + 1];
  178. rectSrc.x = (chr & 0xF)*charw;
  179. rectSrc.y = (chr >> 4)*charh;
  180. rectDst.x = x*charw;
  181. rectDst.y = y*charh;
  182. if (video_blink && col >= 0x80) {
  183. col &= 0x7f;
  184. if ((curr_timer_call % 466) >= 233) {
  185. col = (col >> 4) * 0x11;
  186. }
  187. }
  188. u8 render_fg = ((col >> 4) ^ (col & 0xF));
  189. SDL_SetRenderDrawColor(renderer,
  190. (def_palette[col >> 4] >> 16) & 0xFF,
  191. (def_palette[col >> 4] >> 8) & 0xFF,
  192. (def_palette[col >> 4] >> 0) & 0xFF,
  193. 255);
  194. SDL_RenderFillRect(renderer, &rectDst);
  195. if (render_fg) {
  196. SDL_SetTextureColorMod(chartex,
  197. (def_palette[col & 0xF] >> 16) & 0xFF,
  198. (def_palette[col & 0xF] >> 8) & 0xFF,
  199. (def_palette[col & 0xF] >> 0) & 0xFF);
  200. SDL_RenderCopy(renderer, chartex, &rectSrc, &rectDst);
  201. }
  202. }
  203. }
  204. SDL_RenderPresent(renderer);
  205. }
  206. zzt_thread_running = 0;
  207. SDL_DestroyRenderer(renderer);
  208. SDL_Quit();
  209. }