1program gxsprites;
2
3{$J+}
4{$macro on}
5{$mode objfpc}
6
7uses
8  cmem, ctypes, gctypes, gccore;
9
10{$include inc/textures.tpl.inc}
11{$link build/textures.tpl.o}
12
13const
14  ballsprites = 0;
15
16const
17  DEFAULT_FIFO_SIZE = (256 * 1024);
18const
19  RAND_MAX = 2147483647;
20var
21  frameBuffer: array [0..1] of pcuint32 = (nil, nil);
22  rmode: PGXRModeObj = nil;
23
24const
25  NUM_SPRITES = 1024;
26
27  //simple sprite struct
28type
29  TSprite = record
30    x, y: cint;     // screen co-ordinates
31    dx, dy: cint;     // velocity
32    image: cint;
33  end;
34
35var
36  sprites: array [0..NUM_SPRITES - 1] of TSprite;
37  texObj: GXTexObj;
38
39  fb: cuint32;  // initial framebuffer index
40  first_frame: cuint32;
41  yscale: f32;
42  xfbHeight: cuint32;
43  perspective: Mtx44;
44  GXmodelView2D: Mtx;
45  gp_fifo: pointer = nil;
46
47  background: GXColor = (r: 0; g: 0; b: 0; a: $ff; );
48
49  i: cint;
50  spriteTPL: TPLFile;
51
52  texCoords: array[0..31] of f32 = (
53    0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.0, 0.5,
54    0.5, 0.0, 1.0, 0.0, 1.0, 0.5, 0.5, 0.5,
55    0.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.0, 1.0,
56    0.5, 0.5, 1.0, 0.5, 1.0, 1.0, 0.5, 1.0);
57
58
59  procedure drawSpriteTex(x, y, Width, Height, image: cint);
60  var
61    texIndex: cint;
62  begin
63    texIndex := image * 8;
64
65    GX_Begin(GX_QUADS, GX_VTXFMT0, 4);      // Draw A Quad
66    GX_Position2f32(x, y);          // Top Left
67    GX_TexCoord2f32(texCoords[texIndex], texCoords[texIndex + 1]);
68    texIndex := texIndex + 2;
69    GX_Position2f32(x + Width - 1, y);      // Top Right
70    GX_TexCoord2f32(texCoords[texIndex], texCoords[texIndex + 1]);
71    texIndex := texIndex + 2;
72    GX_Position2f32(x + Width - 1, y + Height - 1);  // Bottom Right
73    GX_TexCoord2f32(texCoords[texIndex], texCoords[texIndex + 1]);
74    texIndex := texIndex + 2;
75    GX_Position2f32(x, y + Height - 1);      // Bottom Left
76    GX_TexCoord2f32(texCoords[texIndex], texCoords[texIndex + 1]);
77    GX_End();                 // Done Drawing The Quad
78  end;
79
80
81
82begin
83  VIDEO_Init();
84
85  rmode := VIDEO_GetPreferredMode(nil);
86
87  fb := 0;
88  first_frame := 1;
89  // allocate 2 framebuffers for double buffering
90  frameBuffer[0] := (SYS_AllocateFramebuffer(rmode));
91  frameBuffer[1] := (SYS_AllocateFramebuffer(rmode));
92
93
94  VIDEO_Configure(rmode);
95  VIDEO_SetNextFramebuffer(frameBuffer[fb]);
96  VIDEO_SetBlack(False);
97  VIDEO_Flush();
98  VIDEO_WaitVSync();
99  if (rmode^.viTVMode and VI_NON_INTERLACE) <> 0 then
100    VIDEO_WaitVSync();
101
102  // setup the fifo and then init the flipper
103  gp_fifo := memalign(32, DEFAULT_FIFO_SIZE);
104  memset(gp_fifo, 0, DEFAULT_FIFO_SIZE);
105
106  fb := fb xor 1;
107
108  GX_Init(gp_fifo, DEFAULT_FIFO_SIZE);
109
110  // clears the bg to color and clears the z buffer
111  GX_SetCopyClear(background, $00ffffff);
112
113  // other gx setup
114  GX_SetViewport(0, 0, rmode^.fbWidth, rmode^.efbHeight, 0, 1);
115  yscale := GX_GetYScaleFactor(rmode^.efbHeight, rmode^.xfbHeight);
116  xfbHeight := GX_SetDispCopyYScale(yscale);
117  GX_SetScissor(0, 0, rmode^.fbWidth, rmode^.efbHeight);
118  GX_SetDispCopySrc(0, 0, rmode^.fbWidth, rmode^.efbHeight);
119  GX_SetDispCopyDst(rmode^.fbWidth, xfbHeight);
120  GX_SetCopyFilter(rmode^.aa, rmode^.sample_pattern, GX_TRUE, rmode^.vfilter);
121
122  if rmode^.viHeight = 2 * rmode^.xfbHeight then
123    GX_SetFieldMode(rmode^.field_rendering, GX_ENABLE)
124  else
125    GX_SetFieldMode(rmode^.field_rendering, GX_DISABLE);
126
127  if (rmode^.aa) <> 0 then
128    GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR)
129  else
130    GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
131
132  GX_SetCullMode(GX_CULL_NONE);
133  GX_CopyDisp(frameBuffer[fb], GX_TRUE);
134  GX_SetDispCopyGamma(GX_GM_1_0);
135
136  // setup the vertex descriptor
137  // tells the flipper to expect direct data
138  GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0);
139  GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
140
141
142  GX_SetNumChans(1);
143  GX_SetNumTexGens(1);
144  GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE);
145  GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
146  GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
147
148  GX_InvalidateTexAll();
149
150  TPL_OpenTPLFromMemory(@spriteTPL, @textures_tpl, textures_tpl_size);
151  TPL_GetTexture(@spriteTPL, ballsprites, @texObj);
152  GX_LoadTexObj(@texObj, GX_TEXMAP0);
153
154  guOrtho(perspective, 0, 479, 0, 639, 0, 300);
155  GX_LoadProjectionMtx(perspective, GX_ORTHOGRAPHIC);
156
157  WPAD_Init();
158
159  randomize();
160
161  for i := 0 to NUM_SPRITES - 1 do
162  begin
163    //random place and speed
164    sprites[i].x := random(640 - 32 + 1) shl 8;
165    sprites[i].y := random(480 - 32 + 1) shl 8;
166    sprites[i].dx := random($FF + 1) + $100;
167    sprites[i].dy := random($FF + 1) + $100;
168    sprites[i].image := random(4);
169
170    if random(2) <> 0 then
171      sprites[i].dx := -sprites[i].dx;
172    if random(2) <> 0 then
173      sprites[i].dy := -sprites[i].dy;
174  end;
175
176  while True do
177  begin
178
179    WPAD_ScanPads();
180
181    if (WPAD_ButtonsDown(0) and WPAD_BUTTON_HOME) <> 0 then
182      exit;
183
184    GX_SetViewport(0, 0, rmode^.fbWidth, rmode^.efbHeight, 0, 1);
185    GX_InvVtxCache();
186    GX_InvalidateTexAll();
187
188    GX_ClearVtxDesc();
189    GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
190    GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
191
192    guMtxIdentity(GXmodelView2D);
193    guMtxTransApply(GXmodelView2D, GXmodelView2D, 0.0, 0.0, -5.0);
194    GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
195
196    for i := 0 to NUM_SPRITES - 1 do
197    begin
198      sprites[i].x := sprites[i].x + sprites[i].dx;
199      sprites[i].y := sprites[i].y + sprites[i].dy;
200
201      //check for collision with the screen boundaries
202      if (sprites[i].x < (1 shl 8)) or (sprites[i].x > ((640 - 32) shl 8)) then
203        sprites[i].dx := -sprites[i].dx;
204
205      if (sprites[i].y < (1 shl 8)) or (sprites[i].y > ((480 - 32) shl 8)) then
206        sprites[i].dy := -sprites[i].dy;
207
208      drawSpriteTex(sprites[i].x shr 8, sprites[i].y shr 8, 32, 32, sprites[i].image);
209    end;
210
211    GX_DrawDone();
212
213    GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
214    GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
215    GX_SetAlphaUpdate(GX_TRUE);
216    GX_SetColorUpdate(GX_TRUE);
217    GX_CopyDisp(frameBuffer[fb], GX_TRUE);
218
219    VIDEO_SetNextFramebuffer(frameBuffer[fb]);
220    if (first_frame) <> 0 then
221    begin
222      VIDEO_SetBlack(False);
223      first_frame := 0;
224    end;
225    VIDEO_Flush();
226    VIDEO_WaitVSync();
227    fb := fb xor 1;   // flip framebuffer
228  end;
229
230end.
231
232