gfx.c 16 KB

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