FireAndSprites.pp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. program FireAndSprites;
  2. {$L build/ball.pcx.o}
  3. {$mode objfpc}
  4. uses
  5. ctypes, nds9;
  6. {$include inc/ball.pcx.inc}
  7. const
  8. NUM_SPRITES = 128;
  9. var
  10. OAMCopySub: array [0..127] of SpriteEntry;
  11. type
  12. TSprite = record
  13. x, y: cint; //location
  14. dx, dy: cint; //speed
  15. oam: PSpriteEntry;
  16. gfxID: integer; //graphics location
  17. end;
  18. PSprite = ^TSprite;
  19. procedure MoveSprite(var sp: TSprite);
  20. var
  21. x, y: integer;
  22. begin
  23. x := sp.x shr 8;
  24. y := sp.y shr 8;
  25. sp.oam^.y := y;
  26. sp.oam^.x := x;
  27. end;
  28. procedure initOAM();
  29. var
  30. i: integer;
  31. begin
  32. for i := 0 to 127 do
  33. OAMCopySub[i].attribute[0] := ATTR0_DISABLED;
  34. end;
  35. procedure updateOAM();
  36. begin
  37. memcpy(OAM_SUB, @OAMCopySub, 128 * sizeof(SpriteEntry));
  38. //dmaCopy(@OAMCopySub, OAM_SUB, 128 * sizeof(SpriteEntry));
  39. end;
  40. // HSV to RGB conversion function with only integer math
  41. function hsl2rgb(hue, sat, lum: cuint8): cuint16;
  42. var
  43. v: cint;
  44. m: cint;
  45. sextant: cint;
  46. fract, vsf, mid1, mid2: cint;
  47. begin
  48. if lum < 128 then
  49. v := lum * (256 + sat) shr 8
  50. else
  51. v := (((lum + sat) shl 8) - lum * sat) shr 8;
  52. if (v <= 0) then
  53. hsl2rgb := RGB8(0,0,0)
  54. else
  55. begin
  56. m := lum + lum - v;
  57. hue := hue * 6;
  58. sextant := hue shr 8;
  59. fract := hue - (sextant shl 8);
  60. vsf := v * fract * (v - m) div v shr 8;
  61. mid1 := m + vsf;
  62. mid2 := v - vsf;
  63. case sextant of
  64. 0: hsl2rgb := RGB8(v,mid1,m);
  65. 1: hsl2rgb := RGB8(mid2,v,m);
  66. 2: hsl2rgb := RGB8(m,v,mid1);
  67. 3: hsl2rgb := RGB8(m,mid2,v);
  68. 4: hsl2rgb := RGB8(mid1,m,v);
  69. else hsl2rgb := RGB8(v,m,mid2);
  70. end;
  71. end;
  72. end;
  73. const
  74. WIDTH = 256;
  75. HEIGHT = 196;
  76. var
  77. fire: array [0..HEIGHT, 0..WIDTH - 1] of cuint8;
  78. x, y: integer;
  79. w: integer = WIDTH;
  80. h: integer = HEIGHT;
  81. sprites: array [0..NUM_SPRITES - 1] of TSprite;
  82. i, delta: integer;
  83. ix, iy: integer;
  84. temp: cint;
  85. pressed: integer;
  86. map0, map1: pcuint16;
  87. red: cuint16;
  88. ball: sImage;
  89. begin
  90. randomize;
  91. i := 0;
  92. delta := 0;
  93. ix := 0;
  94. iy := 0;
  95. map0 := pcuint16(SCREEN_BASE_BLOCK_SUB(1));
  96. map1 := pcuint16(SCREEN_BASE_BLOCK_SUB(2));
  97. //set main display to render 256 color bitmap
  98. videoSetMode(MODE_5_2D or DISPLAY_BG3_ACTIVE);
  99. //set up the sub display
  100. videoSetModeSub(MODE_0_2D or
  101. DISPLAY_SPR_1D_LAYOUT or
  102. DISPLAY_SPR_ACTIVE or
  103. DISPLAY_BG0_ACTIVE or
  104. DISPLAY_BG1_ACTIVE );
  105. //vram banks are somewhat complex
  106. vramSetPrimaryBanks(VRAM_A_MAIN_BG_0x06000000, VRAM_B_MAIN_SPRITE, VRAM_C_SUB_BG, VRAM_D_SUB_SPRITE);
  107. //load our ball pcx file into an image
  108. loadPCX(pcuint8(ball_pcx), @ball);
  109. //tile it so it is useful as sprite data
  110. imageTileData(@ball);
  111. // Sprite initialisation
  112. for i := 0 to 255 do
  113. SPRITE_PALETTE_SUB[i] := cuint32(ball.palette[i]);
  114. for i := 0 to 32*16 - 1 do
  115. SPRITE_GFX_SUB[i] := cuint32(ball.image.data16[i]);
  116. //turn off sprites
  117. initOAM();
  118. for i := 0 to NUM_SPRITES - 1 do
  119. begin
  120. //random place and speed
  121. sprites[i].x := random($FFFF);
  122. sprites[i].y := random($7FFF);
  123. sprites[i].dx := (random($FF)) + $100;
  124. sprites[i].dy := (random($FF)) + $100;
  125. if random(2) = 1 then
  126. sprites[i].dx := -sprites[i].dx;
  127. if random(2) = 1 then
  128. sprites[i].dy := -sprites[i].dy;
  129. sprites[i].oam := @OAMCopySub[i];
  130. sprites[i].gfxID := 0;
  131. //set up our sprites OAM entry attributes
  132. sprites[i].oam^.attribute[0] := ATTR0_COLOR_256 or ATTR0_SQUARE;
  133. sprites[i].oam^.attribute[1] := ATTR1_SIZE_32;
  134. sprites[i].oam^.attribute[2] := sprites[i].gfxID;
  135. end;
  136. //set up two backgrounds to scroll around
  137. REG_BG0CNT_SUB^ := BG_COLOR_256 or (1 shl MAP_BASE_SHIFT);
  138. REG_BG1CNT_SUB^ := BG_COLOR_256 or (2 shl MAP_BASE_SHIFT);
  139. BG_PALETTE_SUB[0] := RGB15(10,10,10);
  140. BG_PALETTE_SUB[1] := RGB15(0,16,0);
  141. BG_PALETTE_SUB[2] := RGB15(0,0,31);
  142. //load the maps with alternating tiles (0,1 for bg0 and 0,2 for bg1)
  143. for iy := 0 to 31 do
  144. for ix := 0 to 31 do
  145. begin
  146. map0[iy * 32 + ix] := (ix xor iy) and 1;
  147. map1[iy * 32 + ix] := ((ix xor iy) and 1) shl 1;
  148. end;
  149. //fill 2 tiles with different colors
  150. for i := 0 to (64 div 2) - 1 do
  151. begin
  152. BG_GFX_SUB[i+32] := $0101;
  153. BG_GFX_SUB[i+32+32] := $0202;
  154. end;
  155. FillChar(fire, 256*192, 0);
  156. // Set up palette for fire effect
  157. for x := 0 to 256 do
  158. begin
  159. if x * 2 > 255 then
  160. BG_PALETTE[x] := hsl2rgb(x div 3,255, 255)
  161. else
  162. BG_PALETTE[x] := hsl2rgb(x div 3, 255, x * 2);
  163. end;
  164. // Set up background for 8bit bitmap
  165. REG_BG3CNT^ := BG_BMP8_256x256;
  166. // and 1:1 scaling
  167. REG_BG3PA^ := 1 shl 8;
  168. REG_BG3PB^ := 0; // BG SCALING X
  169. REG_BG3PC^ := 0; // BG SCALING Y
  170. REG_BG3PD^ := 1 shl 8;
  171. REG_BG3X^ := 0;
  172. REG_BG3Y^ := 0;
  173. while (true) do
  174. begin
  175. //scroll the background
  176. REG_BG0HOFS_SUB^ := delta;
  177. inc(delta);
  178. REG_BG0VOFS_SUB^ := delta;
  179. //move the sprites
  180. for i := 0 to NUM_SPRITES - 1 do
  181. begin
  182. sprites[i].x := sprites[i].x + sprites[i].dx;
  183. sprites[i].y := sprites[i].y + sprites[i].dy;
  184. //check for collision with the screen boundries
  185. if (sprites[i].x < (1 shl 8)) or (sprites[i].x > (247 shl 8)) then
  186. sprites[i].dx := -sprites[i].dx;
  187. if (sprites[i].y < (1 shl 8)) or (sprites[i].y > (182 shl 8)) then
  188. sprites[i].dy := -sprites[i].dy;
  189. //reposition the sprites
  190. MoveSprite(sprites[i]);
  191. end;
  192. //do the plasma/fire
  193. //randomize the bottom row of the fire buffer
  194. for x := 0 to w - 1 do
  195. //fire[h-1, x] := abs(32768 + random(high(cint))) mod 256;
  196. fire[h-1, x] := abs(32768 + random(32767)) mod 256;
  197. //do the fire calculations for every pixel, from top to bottom
  198. for y := 0 to h - 2 do
  199. for x := 0 to w - 1 do
  200. begin
  201. temp := fire[y + 1, (x - 1) mod w] + fire[y + 2, (x) mod w] + fire[y + 1, (x + 1) mod w] + fire[y + 3, (x) mod w];
  202. end;
  203. dmaCopy(@fire, pointer($06000000), 256 * 192);
  204. swiWaitForVBlank();
  205. scanKeys();
  206. pressed := keysDown();
  207. if (pressed and KEY_START) <> 0 then break;
  208. updateOAM();
  209. end;
  210. end.