main.pp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. program main;
  2. {$L ball.pcx.o}
  3. {$apptype arm9}
  4. {$define ARM9}
  5. {$mode objfpc}
  6. uses
  7. ctypes, nds9;
  8. var
  9. ball_pcx_end: array [0..0] of u8; cvar; external;
  10. ball_pcx: array [0..0] of u8; cvar; external;
  11. ball_pcx_size: u32; cvar; external;
  12. const
  13. NUM_SPRITES = 128;
  14. var
  15. OAMCopySub: array [0..127] of SpriteEntry;
  16. type
  17. //simple sprite struct
  18. TSprite = record
  19. x, y: integer; //location
  20. dx, dy: integer; //speed
  21. oam: PSpriteEntry;
  22. gfxID: integer; //graphics lovation
  23. end;
  24. PSprite = ^TSprite;
  25. procedure MoveSprite(sp: PSprite);
  26. var
  27. x, y: integer;
  28. begin
  29. x := sp^.x shr 8;
  30. y := sp^.y shr 8;
  31. sp^.oam^.st.attribute[1] := sp^.oam^.st.attribute[1] and $FE00;
  32. sp^.oam^.st.attribute[1] := sp^.oam^.st.attribute[1] or (x and $01FF);
  33. sp^.oam^.st.attribute[0] := sp^.oam^.st.attribute[0] and $FF00;
  34. sp^.oam^.st.attribute[0] := sp^.oam^.st.attribute[0] or (y and $00FF);
  35. end;
  36. procedure initOAM();
  37. var
  38. i: integer;
  39. begin
  40. for i := 0 to 127 do
  41. OAMCopySub[i].st.attribute[0] := ATTR0_DISABLED;
  42. end;
  43. procedure updateOAM();
  44. begin
  45. dmaCopy(@OAMCopySub, OAM_SUB, sizeof(OAMCopySub));
  46. end;
  47. function irqVBlank(): pointer;
  48. begin
  49. end;
  50. var
  51. back, front: pcuint16;
  52. sprites: array [0..NUM_SPRITES - 1] of TSprite;
  53. i, delta: integer;
  54. ix, iy: integer;
  55. screen: integer;
  56. map0, map1: pcuint16;
  57. red: cuint16;
  58. ball: sImage;
  59. begin
  60. back := VRAM_A;
  61. front := VRAM_B;
  62. i := 0;
  63. delta := 0;
  64. ix := 0;
  65. iy := 0;
  66. screen := 1;
  67. map0 := pcuint16(SCREEN_BASE_BLOCK_SUB(1));
  68. map1 := pcuint16(SCREEN_BASE_BLOCK_SUB(2));
  69. //turn on the power to the system
  70. powerON(POWER_ALL);
  71. //set main display to render directly from the frame buffer
  72. videoSetMode(MODE_FB1);
  73. //set up the sub display
  74. videoSetModeSub(MODE_0_2D or DISPLAY_SPR_1D_LAYOUT or DISPLAY_SPR_ACTIVE or
  75. DISPLAY_BG0_ACTIVE or DISPLAY_BG1_ACTIVE );
  76. //vram banks are somewhat complex
  77. vramSetMainBanks(VRAM_A_LCD, VRAM_B_LCD, VRAM_C_SUB_BG, VRAM_D_SUB_SPRITE);
  78. // a vblank interrupt is needed to use swiWaitForVBlank()
  79. // since the dispatcher handles the flags no handler is required
  80. irqInit();
  81. irqSet(IRQ_VBLANK, @irqVBlank);
  82. //load our ball pcx file into an image
  83. loadPCX(pu8(ball_pcx), @ball);
  84. //tile it so it is usefull as sprite data
  85. imageTileData(@ball);
  86. // Sprite initialisation
  87. for i := 0 to 255 do
  88. SPRITE_PALETTE_SUB[i] := u32(ball.palette[i]);
  89. for i := 0 to 32*16 - 1 do
  90. SPRITE_GFX_SUB[i] := u32(ball.image.data16[i]);
  91. //turn off sprites
  92. initOAM();
  93. for i := 0 to NUM_SPRITES - 1 do
  94. begin
  95. //random place and speed
  96. sprites[i].x := rand() and $FFFF;
  97. sprites[i].y := rand() and $7FFF;
  98. sprites[i].dx := (rand() and $FF) + $100;
  99. sprites[i].dy := (rand() and $FF) + $100;
  100. if (rand() and 1) <> 0 then
  101. sprites[i].dx := -sprites[i].dx;
  102. if (rand() and 1) <> 0 then
  103. sprites[i].dy := -sprites[i].dy;
  104. sprites[i].oam := @OAMCopySub[i];
  105. sprites[i].gfxID := 0;
  106. //set up our sprites OAM entry attributes
  107. sprites[i].oam^.st.attribute[0] := ATTR0_COLOR_256 or ATTR0_SQUARE;
  108. sprites[i].oam^.st.attribute[1] := ATTR1_SIZE_32;
  109. sprites[i].oam^.st.attribute[2] := sprites[i].gfxID;
  110. end;
  111. //set up two backgrounds to scroll around
  112. SUB_BG0_CR^ := BG_COLOR_256 or (1 shl SCREEN_SHIFT);
  113. SUB_BG1_CR^ := BG_COLOR_256 or (2 shl SCREEN_SHIFT);
  114. BG_PALETTE_SUB[0] := u32(RGB15(10,10,10));
  115. BG_PALETTE_SUB[1] := u32(RGB15(0,16,0));
  116. BG_PALETTE_SUB[2] := u32(RGB15(0,0,31));
  117. //load the maps with alternating tiles (0,1 for bg0 and 0,2 for bg1)
  118. for iy := 0 to 31 do
  119. for ix := 0 to 31 do
  120. begin
  121. map0[iy * 32 + ix] := (ix xor iy) and 1;
  122. map1[iy * 32 + ix] := ((ix xor iy) and 1) shl 1;
  123. end;
  124. //fill 2 tiles with different colors
  125. for i := 0 to (64 div 2) - 1 do
  126. begin
  127. BG_GFX_SUB[i+32] := $0101;
  128. BG_GFX_SUB[i+32+32] := $0202;
  129. end;
  130. while (true) do
  131. begin
  132. //scroll the background
  133. SUB_BG0_X0^ := delta;
  134. inc(delta);
  135. SUB_BG0_Y0^ := delta;
  136. //move the sprites
  137. for i := 0 to NUM_SPRITES - 1 do
  138. begin
  139. sprites[i].x := sprites[i].x + sprites[i].dx;
  140. sprites[i].y := sprites[i].y + sprites[i].dy;
  141. //check for collision with the screen boundries
  142. if (sprites[i].x < (1 shl 8)) or (sprites[i].x > (247 shl 8)) then
  143. sprites[i].dx := -sprites[i].dx;
  144. if (sprites[i].y < (1 shl 8)) or (sprites[i].y > (182 shl 8)) then
  145. sprites[i].dy := -sprites[i].dy;
  146. //reposition the sprites
  147. MoveSprite(@sprites[i]);
  148. end;
  149. //do the plasma/fire
  150. for ix := 0 to SCREEN_WIDTH - 1 do
  151. begin
  152. back[ix + SCREEN_WIDTH * (SCREEN_HEIGHT - 1)] := rand() and $FFFF;
  153. back[ix + SCREEN_WIDTH * (SCREEN_HEIGHT - 2)] := rand() and $FFFF;
  154. end;
  155. inc(back);
  156. for iy := 1 to SCREEN_HEIGHT - 3 do
  157. begin
  158. for ix := 1 to SCREEN_WIDTH - 2 do
  159. begin
  160. red := 0;
  161. red := red + front[0];
  162. red := red + front[2];
  163. front := front + SCREEN_WIDTH;
  164. red := red + front[0];
  165. red := red + front[1];
  166. red := red + front[2];
  167. front := front + SCREEN_WIDTH;
  168. red := red + front[0];
  169. red := red + front[1];
  170. red := red + front[2];
  171. front := front - ((2 * SCREEN_WIDTH) - 1);
  172. back[0] := (red shr 3);
  173. inc(back);
  174. end;
  175. inc(back,2);
  176. inc(front,2);
  177. end;
  178. swiWaitForVBlank();
  179. updateOAM();
  180. //flip screens
  181. if (screen) <> 0 then
  182. begin
  183. videoSetMode(MODE_FB1);
  184. front := VRAM_B;
  185. back := VRAM_A;
  186. screen := 0;
  187. end else
  188. begin
  189. videoSetMode(MODE_FB0);
  190. front := VRAM_A;
  191. back := VRAM_B;
  192. screen := 1;
  193. end;
  194. end;
  195. end.