gfx.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /*
  2. * Graphics library
  3. * Mostly Assembly code, because efficiency in both space and time
  4. * More complex functions are written in C
  5. * Int arguments from C are stored in order of r4, r5, r6, r7
  6. * Return value in r2, but should be written on stack using write -4 r14 r2 (add variable in C)
  7. */
  8. // uses math.c
  9. #define GFX_WINDOW_PATTERN_ADDR 0xC01420
  10. #define GFX_WINDOW_PALETTE_ADDR 0xC01C20
  11. #define GFX_CURSOR_ASCII 219
  12. word GFX_cursor = 0;
  13. word GFX_disable_cursor = 0;
  14. // Workaround to allow for defines in asm functions
  15. void GFX_asmDefines()
  16. {
  17. asm(
  18. "define GFX_PATTERN_TABLE_SIZE = 1024 ; size of pattern table\n"
  19. "define GFX_PALETTE_TABLE_SIZE = 32 ; size of palette table\n"
  20. "define GFX_WINDOW_TILES = 1920 ; number of tiles in window plane\n"
  21. "define GFX_BG_TILES = 2048 ; number of tiles in bg plane\n"
  22. "define GFX_SPRITES = 64 ; number of sprites in spriteVRAM\n"
  23. "define DATAOFFSET_TO_VOID = 3 ; offset to assembly data when placed in void\n"
  24. );
  25. }
  26. // Prints to screen in window plane, with color, data is accessed in words
  27. // INPUT:
  28. // r4 = address of data to print
  29. // r5 = length of data
  30. // r6 = position on screen
  31. // r7 = palette index
  32. void GFX_printWindowColored(word addr, word len, word pos, word palette)
  33. {
  34. asm(
  35. "; backup registers\n"
  36. "push r1\n"
  37. "push r2\n"
  38. "push r3\n"
  39. "push r4\n"
  40. "push r5\n"
  41. "push r6\n"
  42. "push r7\n"
  43. "push r8\n"
  44. "push r9\n"
  45. );
  46. asm(
  47. "; vram address\n"
  48. "load32 0xC01420 r9 ; r9 = vram addr 1056+4096 0xC01420\n"
  49. "; loop variables\n"
  50. "load 0 r1 ; r1 = loopvar\n"
  51. "or r9 r0 r3 ; r3 = vram addr with offset\n"
  52. "or r4 r0 r2 ; r2 = data addr with offset\n"
  53. "add r6 r3 r3 ; apply offset from r6\n"
  54. "; copy loop\n"
  55. "GFX_printWindowColoredLoop:\n"
  56. " read 0 r2 r8 ; read 32 bits\n"
  57. " write 0 r3 r8 ; write char to vram\n"
  58. " write 2048 r3 r7 ; write palette index to vram\n"
  59. " add r3 1 r3 ; incr vram address\n"
  60. " add r2 1 r2 ; incr data address\n"
  61. " add r1 1 r1 ; incr counter\n"
  62. " bge r1 r5 2 ; keep looping until all data is copied\n"
  63. " jump GFX_printWindowColoredLoop\n"
  64. );
  65. asm(
  66. "; restore registers\n"
  67. "pop r9\n"
  68. "pop r8\n"
  69. "pop r7\n"
  70. "pop r6\n"
  71. "pop r5\n"
  72. "pop r4\n"
  73. "pop r3\n"
  74. "pop r2\n"
  75. "pop r1\n"
  76. );
  77. }
  78. // Prints to screen in background plane, with color, data is accessed in words
  79. // INPUT:
  80. // r4 = address of data to print
  81. // r5 = length of data
  82. // r6 = position on screen
  83. // r7 = palette index
  84. void GFX_printBGColored(word addr, word len, word pos, word palette)
  85. {
  86. asm(
  87. "; backup registers\n"
  88. "push r1\n"
  89. "push r2\n"
  90. "push r3\n"
  91. "push r4\n"
  92. "push r5\n"
  93. "push r6\n"
  94. "push r7\n"
  95. "push r8\n"
  96. "push r9\n"
  97. );
  98. asm(
  99. "; vram address\n"
  100. "load32 0xC00420 r9 ; r9 = vram addr 1056 0xC00420\n"
  101. "; loop variables\n"
  102. "load 0 r1 ; r1 = loopvar\n"
  103. "or r9 r0 r3 ; r3 = vram addr with offset\n"
  104. "or r4 r0 r2 ; r2 = data addr with offset\n"
  105. "add r6 r3 r3 ; apply offset from r6\n"
  106. "; copy loop\n"
  107. "GFX_printBGColoredLoop:\n"
  108. " read 0 r2 r8 ; read 32 bits\n"
  109. " write 0 r3 r8 ; write char to vram\n"
  110. " write 2048 r3 r7 ; write palette index to vram\n"
  111. " add r3 1 r3 ; incr vram address\n"
  112. " add r2 1 r2 ; incr data address\n"
  113. " add r1 1 r1 ; incr counter\n"
  114. " bge r1 r5 2 ; keep looping until all data is copied\n"
  115. " jump GFX_printBGColoredLoop\n"
  116. );
  117. asm(
  118. "; restore registers\n"
  119. "pop r9\n"
  120. "pop r8\n"
  121. "pop r7\n"
  122. "pop r6\n"
  123. "pop r5\n"
  124. "pop r4\n"
  125. "pop r3\n"
  126. "pop r2\n"
  127. "pop r1\n"
  128. );
  129. }
  130. // Loads entire pattern table
  131. // INPUT:
  132. // r4 = address of pattern table to copy
  133. void GFX_copyPatternTable(word addr)
  134. {
  135. asm(
  136. "; backup registers\n"
  137. "push r1\n"
  138. "push r2\n"
  139. "push r3\n"
  140. "push r4\n"
  141. "push r5\n"
  142. "push r6\n"
  143. "push r7\n"
  144. "; vram address\n"
  145. "load32 0xC00000 r2 ; r2 = vram addr 0 0xC00000\n"
  146. "; loop variables\n"
  147. "load 0 r3 ; r3 = loopvar\n"
  148. "load GFX_PATTERN_TABLE_SIZE r5 ; r5 = loopmax\n"
  149. "or r2 r0 r1 ; r1 = vram addr with offset\n"
  150. "add r4 DATAOFFSET_TO_VOID r6 ; r6 = ascii addr with offset\n"
  151. "; copy loop\n"
  152. "GFX_initPatternTableLoop:\n"
  153. " read 0 r6 r7 ; copy ascii to vram\n"
  154. " write 0 r1 r7 ;\n"
  155. " add r1 1 r1 ; incr vram address\n"
  156. " add r6 1 r6 ; incr ascii address\n"
  157. " add r3 1 r3 ; incr counter\n"
  158. " beq r3 r5 2 ; keep looping until all data is copied\n"
  159. " jump GFX_initPatternTableLoop\n"
  160. "; restore registers\n"
  161. "pop r7\n"
  162. "pop r6\n"
  163. "pop r5\n"
  164. "pop r4\n"
  165. "pop r3\n"
  166. "pop r2\n"
  167. "pop r1\n"
  168. );
  169. }
  170. // Loads entire palette table
  171. // INPUT:
  172. // r4 = address of palette table to copy
  173. void GFX_copyPaletteTable(word addr)
  174. {
  175. asm(
  176. "; backup registers\n"
  177. "push r1\n"
  178. "push r2\n"
  179. "push r3\n"
  180. "push r4\n"
  181. "push r5\n"
  182. "push r6\n"
  183. "push r7\n"
  184. "; vram address\n"
  185. "load32 0xC00400 r2 ; r2 = vram addr 1024 0xC00400\n"
  186. "; loop variables\n"
  187. "load 0 r3 ; r3 = loopvar\n"
  188. "load GFX_PALETTE_TABLE_SIZE r5 ; r5 = loopmax\n"
  189. "or r2 r0 r1 ; r1 = vram addr with offset\n"
  190. "add r4 DATAOFFSET_TO_VOID r6 ; r6 = palette addr with offset\n"
  191. "; copy loop\n"
  192. "GFX_initPaletteTableLoop:\n"
  193. " read 0 r6 r7 ; copy ascii to vram\n"
  194. " write 0 r1 r7 ;\n"
  195. " add r1 1 r1 ; incr vram address\n"
  196. " add r6 1 r6 ; incr palette address\n"
  197. " add r3 1 r3 ; incr counter\n"
  198. " beq r3 r5 2 ; keep looping until all data is copied\n"
  199. " jump GFX_initPaletteTableLoop\n"
  200. "; restore registers\n"
  201. "pop r7\n"
  202. "pop r6\n"
  203. "pop r5\n"
  204. "pop r4\n"
  205. "pop r3\n"
  206. "pop r2\n"
  207. "pop r1\n"
  208. );
  209. }
  210. // Clear BG tile table
  211. void GFX_clearBGtileTable()
  212. {
  213. asm(
  214. "; backup registers\n"
  215. "push r1\n"
  216. "push r2\n"
  217. "push r3\n"
  218. "push r4\n"
  219. "push r5\n"
  220. "; vram address\n"
  221. "load32 0xC00420 r1 ; r1 = vram addr 1056 0xC00420\n"
  222. "; loop variables\n"
  223. "load 0 r3 ; r3 = loopvar\n"
  224. "load GFX_BG_TILES r4 ; r4 = loopmax\n"
  225. "or r1 r0 r5 ; r5 = vram addr with offset\n"
  226. "; copy loop\n"
  227. "GFX_clearBGtileTableLoop:\n"
  228. " write 0 r5 r0 ; clear tile\n"
  229. " add r5 1 r5 ; incr vram address\n"
  230. " add r3 1 r3 ; incr counter\n"
  231. " beq r3 r4 2 ; keep looping until all tiles are cleared\n"
  232. " jump GFX_clearBGtileTableLoop\n"
  233. "; restore registers\n"
  234. "pop r5\n"
  235. "pop r4\n"
  236. "pop r3\n"
  237. "pop r2\n"
  238. "pop r1\n"
  239. );
  240. }
  241. // Clear BG palette table
  242. void GFX_clearBGpaletteTable()
  243. {
  244. asm(
  245. "; backup registers\n"
  246. "push r1\n"
  247. "push r2\n"
  248. "push r3\n"
  249. "push r4\n"
  250. "push r5\n"
  251. "; vram address\n"
  252. "load32 0xC00C20 r1 ; r1 = vram addr 1056+2048 0xC00C20\n"
  253. "; loop variables\n"
  254. "load 0 r3 ; r3 = loopvar\n"
  255. "load GFX_BG_TILES r4 ; r4 = loopmax\n"
  256. "or r1 r0 r5 ; r5 = vram addr with offset\n"
  257. "; copy loop\n"
  258. "GFX_clearBGpaletteTableLoop:\n"
  259. " write 0 r5 r0 ; clear tile\n"
  260. " add r5 1 r5 ; incr vram address\n"
  261. " add r3 1 r3 ; incr counter\n"
  262. " beq r3 r4 2 ; keep looping until all tiles are cleared\n"
  263. " jump GFX_clearBGpaletteTableLoop\n"
  264. "; restore registers\n"
  265. "pop r5\n"
  266. "pop r4\n"
  267. "pop r3\n"
  268. "pop r2\n"
  269. "pop r1\n"
  270. );
  271. }
  272. // Clear Window tile table
  273. void GFX_clearWindowtileTable()
  274. {
  275. asm(
  276. "; backup registers\n"
  277. "push r1\n"
  278. "push r2\n"
  279. "push r3\n"
  280. "push r4\n"
  281. "push r5\n"
  282. "; vram address\n"
  283. "load32 0xC01420 r1 ; r1 = vram addr 1056+2048 0xC01420\n"
  284. "; loop variables\n"
  285. "load 0 r3 ; r3 = loopvar\n"
  286. "load GFX_WINDOW_TILES r4 ; r4 = loopmax\n"
  287. "or r1 r0 r5 ; r5 = vram addr with offset\n"
  288. "; copy loop\n"
  289. "GFX_clearWindowtileTableLoop:\n"
  290. " write 0 r5 r0 ; clear tile\n"
  291. " add r5 1 r5 ; incr vram address\n"
  292. " add r3 1 r3 ; incr counter\n"
  293. " beq r3 r4 2 ; keep looping until all tiles are cleared\n"
  294. " jump GFX_clearWindowtileTableLoop\n"
  295. "; restore registers\n"
  296. "pop r5\n"
  297. "pop r4\n"
  298. "pop r3\n"
  299. "pop r2\n"
  300. "pop r1\n"
  301. );
  302. }
  303. // Clear Window palette table
  304. void GFX_clearWindowpaletteTable()
  305. {
  306. asm(
  307. "; backup registers\n"
  308. "push r1\n"
  309. "push r2\n"
  310. "push r3\n"
  311. "push r4\n"
  312. "push r5\n"
  313. "; vram address\n"
  314. "load32 0xC01C20 r1 ; r1 = vram addr 1056+2048 0xC01C20\n"
  315. "; loop variables\n"
  316. "load 0 r3 ; r3 = loopvar\n"
  317. "load GFX_WINDOW_TILES r4 ; r4 = loopmax\n"
  318. "or r1 r0 r5 ; r5 = vram addr with offset\n"
  319. "; copy loop\n"
  320. "GFX_clearWindowpaletteTableLoop:\n"
  321. " write 0 r5 r0 ; clear tile\n"
  322. " add r5 1 r5 ; incr vram address\n"
  323. " add r3 1 r3 ; incr counter\n"
  324. " beq r3 r4 2 ; keep looping until all tiles are cleared\n"
  325. " jump GFX_clearWindowpaletteTableLoop\n"
  326. "; restore registers\n"
  327. "pop r5\n"
  328. "pop r4\n"
  329. "pop r3\n"
  330. "pop r2\n"
  331. "pop r1\n"
  332. );
  333. }
  334. // Clear Sprites
  335. void GFX_clearSprites()
  336. {
  337. asm(
  338. "; backup registers\n"
  339. "push r1\n"
  340. "push r2\n"
  341. "push r3\n"
  342. "push r4\n"
  343. "push r5\n"
  344. "; vram address\n"
  345. "load32 0xC02422 r1 ; r1 = vram addr 0xC02422\n"
  346. "; loop variables\n"
  347. "load 0 r3 ; r3 = loopvar\n"
  348. "load GFX_SPRITES r4 ; r4 = loopmax\n"
  349. "or r1 r0 r5 ; r5 = vram addr with offset\n"
  350. "; copy loop\n"
  351. "GFX_clearSpritesLoop:\n"
  352. " write 0 r5 r0 ; clear x\n"
  353. " write 1 r5 r0 ; clear y\n"
  354. " write 2 r5 r0 ; clear tile\n"
  355. " write 3 r5 r0 ; clear color+attrib\n"
  356. " add r5 4 r5 ; incr vram address by 4\n"
  357. " add r3 1 r3 ; incr counter\n"
  358. " beq r3 r4 2 ; keep looping until all tiles are cleared\n"
  359. " jump GFX_clearSpritesLoop\n"
  360. "; restore registers\n"
  361. "pop r5\n"
  362. "pop r4\n"
  363. "pop r3\n"
  364. "pop r2\n"
  365. "pop r1\n"
  366. );
  367. }
  368. // Clear parameters
  369. void GFX_clearParameters()
  370. {
  371. asm(
  372. "; backup registers\n"
  373. "push r1\n"
  374. "; vram address\n"
  375. "load32 0xC02420 r1 ; r1 = vram addr 0xC02420\n"
  376. "write 0 r1 r0 ; clear tile scroll\n"
  377. "write 1 r1 r0 ; clear fine scroll\n"
  378. "; restore registers\n"
  379. "pop r1\n"
  380. );
  381. }
  382. // clears and initializes VRAM (excluding pattern and palette data table)
  383. void GFX_initVram()
  384. {
  385. GFX_asmDefines(); // workaround to prevent deletion of function by optimizer
  386. GFX_clearBGtileTable();
  387. GFX_clearBGpaletteTable();
  388. GFX_clearWindowtileTable();
  389. GFX_clearWindowpaletteTable();
  390. GFX_clearSprites();
  391. GFX_clearParameters();
  392. }
  393. // convert x and y to position for window table
  394. word GFX_WindowPosFromXY(word x, word y)
  395. {
  396. return y*40 + x;
  397. }
  398. // convert x and y to position for background table
  399. word GFX_BackgroundPosFromXY(word x, word y)
  400. {
  401. return y*64 + x;
  402. }
  403. // scrolls up screen, clearing last line
  404. void GFX_ScrollUp()
  405. {
  406. asm(
  407. "; backup registers\n"
  408. "push r1\n"
  409. "push r2\n"
  410. "push r3\n"
  411. "push r4\n"
  412. "; GFX_WINDOW_PATTERN_ADDR address\n"
  413. "load32 0xC01420 r1 ; r1 = window pattern addr 0xC01420\n"
  414. "load32 0 r2 ; r2 = loopvar\n"
  415. "load32 960 r3 ; r3 = loopmax\n"
  416. "GFX_scrollUpLoop:\n"
  417. " read 40 r1 r4 ; read r1+40 to tmp r4\n"
  418. " write 0 r1 r4 ; write tmp r4 to r1\n"
  419. " add r1 1 r1 ; incr addr r1\n"
  420. " add r2 1 r2 ; incr loopvar r2\n"
  421. " beq r2 r3 2 ; keep looping for r3 times\n"
  422. " jump GFX_scrollUpLoop\n"
  423. "load32 0 r2 ; r2 = loopvar\n"
  424. "load32 40 r3 ; r3 = loopmax\n"
  425. "GFX_clearLastLineLoop:\n"
  426. " write 0 r1 r0 ; clear at r1\n"
  427. " add r1 1 r1 ; incr addr r1\n"
  428. " add r2 1 r2 ; incr loopvar r2\n"
  429. " beq r2 r3 2 ; keep looping for r3 times\n"
  430. " jump GFX_clearLastLineLoop\n"
  431. "; restore registers\n"
  432. "pop r4\n"
  433. "pop r3\n"
  434. "pop r2\n"
  435. "pop r1\n"
  436. );
  437. }
  438. // Prints cursor character at cursor
  439. void GFX_printCursor()
  440. {
  441. if (!GFX_disable_cursor)
  442. {
  443. // print character at cursor
  444. word *v = (word *) GFX_WINDOW_PATTERN_ADDR;
  445. *(v+GFX_cursor) = GFX_CURSOR_ASCII;
  446. }
  447. }
  448. // Prints character to console
  449. // Handles scrolling, newline and backspace
  450. // Uses cursor from memory
  451. // TODO: could convert this to assembly for speed
  452. void GFX_PrintcConsole(char c)
  453. {
  454. // if newline
  455. if (c == 0xa)
  456. {
  457. // remove current cursor
  458. word *v = (word *) GFX_WINDOW_PATTERN_ADDR;
  459. *(v+GFX_cursor) = 0;
  460. // get next line number
  461. word nl = MATH_divU(GFX_cursor, 40) + 1;
  462. // multiply by 40 to get the correct line
  463. GFX_cursor = nl * 40;
  464. }
  465. // if backspace
  466. else if (c == 0x8)
  467. {
  468. // NOTE: by commenting this out it now is allowed to backspace to the previous line
  469. // This is done since the shell checks for valid backspaces now,
  470. // so we can remove multiline arguments
  471. // if we are not at the start of a line
  472. //if (MATH_mod(GFX_cursor, 40) != 0)
  473. // if we are not at the first character
  474. if ((unsigned int) GFX_cursor > 0)
  475. {
  476. // set current and previous character to 0
  477. word *v = (word *) GFX_WINDOW_PATTERN_ADDR;
  478. *(v+GFX_cursor) = 0;
  479. *(v+GFX_cursor-1) = 0;
  480. // decrement cursor
  481. GFX_cursor--;
  482. }
  483. }
  484. // if\r
  485. else if (c == '\r')
  486. {
  487. // ignore
  488. }
  489. // else (character)
  490. else
  491. {
  492. // print character at cursor
  493. word *v = (word *) GFX_WINDOW_PATTERN_ADDR;
  494. *(v+GFX_cursor) = (word) c;
  495. // increment cursor
  496. GFX_cursor++;
  497. }
  498. // if we went offscreen, scroll screen up and set cursor to last line
  499. if ((unsigned int) GFX_cursor >= 1000)
  500. {
  501. GFX_ScrollUp();
  502. // set cursor to 960
  503. GFX_cursor = 960;
  504. }
  505. // add cursor at end
  506. GFX_printCursor();
  507. }
  508. // Prints string on console untill terminator
  509. // Does not add newline at end
  510. // TODO: could convert this to assembly for speed
  511. void GFX_PrintConsole(char* str)
  512. {
  513. char chr = *str; // first character of str
  514. while (chr != 0) // continue until null value
  515. {
  516. GFX_PrintcConsole((word)chr);
  517. str++; // go to next character address
  518. chr = *str; // get character from address
  519. }
  520. }
  521. void GFX_PrintDecConsole(word i)
  522. {
  523. char buffer[20];
  524. itoa(i, buffer);
  525. GFX_PrintConsole(buffer);
  526. }
  527. // Just for funny memory dumping
  528. void GFX_DumpcConsole(char c)
  529. {
  530. // print character at cursor
  531. word *v = (word *) GFX_WINDOW_PATTERN_ADDR;
  532. *(v+GFX_cursor) = (word) c;
  533. // increment cursor
  534. GFX_cursor++;
  535. // if we went offscreen, scroll screen up and set cursor to last line
  536. if ((unsigned int) GFX_cursor >= 1000)
  537. {
  538. GFX_ScrollUp();
  539. // set cursor to 960
  540. GFX_cursor = 960;
  541. }
  542. // add cursor at end
  543. //GFX_printCursor();
  544. }