summaryrefslogtreecommitdiff
path: root/packages/libndsfpc/examples/gl2d/2Dplus3D/2Dplus3D.pp
blob: bb6a526bd396c0a738137dbb2571cb9cbcd50b9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
(*
  Easy GL2D
  Relminator 2011 
  Richard Eric M. Lope BSN RN
  Http://Rel.Phatcode.Net
  A very small, simple, yet very fast DS 2D rendering lib using the DS' 3D core.
  --
  Translated in Object Pascal by Francesco Lombardi - 2012
  http://itaprogaming.free.fr
*)
program TwoDplusThreeD;

{$mode objfpc}
{$H+}

{$L build/flyer.o}
{$L build/shuttle.o}
{$L build/enemies.o}
{$L build/organ16.o}

uses
  ctypes, nds9, gl2d, cearn_atan, vbuffer, uvcoord_enemies;
 
const
  flyerBitmapLen = 2048;
  flyerPalLen = 512;
  shuttleBitmapLen = 2048;
  shuttlePalLen = 32;
  enemiesBitmapLen = 65536;
  enemiesPalLen = 512;
  organ16BitmapLen = 32768;

var
  flyerBitmap: array [0..0] of cuint; cvar; external;
  flyerPal: array [0..0] of cushort; cvar; external;
  shuttleBitmap: array [0..0] of cuint; cvar; external;
  shuttlePal: array [0..0] of cushort; cvar; external;
  enemiesBitmap: array [0..0] of cuint; cvar; external;
  enemiesPal: array [0..0] of cushort; cvar; external;
  organ16Bitmap: array [0..0] of cuint; cvar; external;

const
  // Mode7-like 3D effect parameters
  GRID_RINGS: cint = 2;
  GRID_BANDS: cint = 2;
  GRID_WIDTH: cint = 15;
  GRID_HEIGHT: cint = 12;

  // PI for our binary radian measure
  BRAD_PI = 1 shl 14;

var
// Our sprites
  Enemies: array [0..ENEMIES_NUM_IMAGES-1] of glImage;  // spriteset
  Shuttle: array [0..0] of glImage;         // single image 
  Flyer: array [0..0] of glImage;           // single image

  vb: PVertexBuffer;

  EnemiesTextureID: cint; 
  ShuttleTextureID: cint; 
  FlyerTextureID: cint;

  TextureSize: cint;
  ox, oy: cint32;
  Frame, PhoenixFrame, BeeFrame, Rotation: cint;      // rotation value of the rotating sprites
  x, y: cint;
  sx, sy, angle: cint32;


// function to draw our mode7 fx
// draws 2 planes
// for a fake mode7 effect
procedure draw_grid();
const
  text_off_u: cint32 = 0;
  text_off_v: cint32 = 0;
  frame: cint = 0;
begin
  inc(frame);
  
  glPushMatrix();
    
    glLoadIdentity();
    
    glTranslate3f32( 0, 0, floattof32(3.0) );
    glScalef32(floattof32(1),floattof32(1.5),floattof32(1.5));
  
    // floor
    glPushMatrix();

      glTranslate3f32( 0, -1 shl 12, -2 shl 12 );   
      glRotateXi( inttof32(244) );
      
      vb^.render( text_off_u, text_off_v, true );
      
    glPopMatrix( 1 );
    
    // ceiling
    glPushMatrix();

      glTranslate3f32( 0, 1 shl 12, -2 shl 12 );
      glRotateXi( inttof32(180) );
      
      vb^.render( text_off_u ,text_off_v, true );
    
    glPopMatrix( 1 );
  
  glPopMatrix( 1 );
    

  // "move" the floor and ceiling
  text_off_u := (sinLerp(frame*30)*2) and 4095;
  text_off_v := (sinLerp(-frame*50)*3) and 4095;

end;



begin
  
  // Initialize fake mode7 planes
  vb := init_grid (GRID_RINGS, GRID_BANDS, GRID_WIDTH, GRID_HEIGHT, 8, 8);
  
  //set mode 5, enable BG0 and set it to 3D
  videoSetMode(MODE_5_3D);
  
  consoleDemoInit();

  // initialize gl2d
  glScreen2D();
  
  //set up enough texture memory for our textures
  vramSetBankA( VRAM_A_TEXTURE );
  
  // Very Important!!! Or you get black sprites
  vramSetBankE(VRAM_E_TEX_PALETTE);  // Allocate VRAM bank for all the palettes
  
  // Load our texture for our mode7 effect
  vb^.load_texture( @organ16Bitmap );
  
  // Load our Enemies texture
  // We used glLoadSpriteSet since the texture was made
  // with my texture packer.
  EnemiesTextureID := glLoadSpriteSet( 
             Enemies,       // pointer to glImage array
             ENEMIES_NUM_IMAGES,  // Texture packer auto-generated #define
             @enemies_texcoords,    // Texture packer auto-generated array
             GL_RGB256,       // texture type for glTexImage2D() in videoGL.h 
             TEXTURE_SIZE_256,    // sizeX for glTexImage2D() in videoGL.h
             TEXTURE_SIZE_256,    // sizeY for glTexImage2D() in videoGL.h
             GL_TEXTURE_WRAP_S or GL_TEXTURE_WRAP_T or TEXGEN_OFF or GL_TEXTURE_COLOR0_TRANSPARENT, // param for glTexImage2D() in videoGL.h
             256,         // Length of the palette to use (256 colors)
             @enemiesPal,   // Load our 256 color enemies palette
             @enemiesBitmap   // image data generated by GRIT
             );
  
  
  
  // Shuttle
  // Since the shuttle is just a single 64x64 image,
  // We use glLoadTileSet() giving the right dimensions.
  ShuttleTextureID := glLoadTileSet(
            Shuttle,      // pointer to glImage array
             64,        // sprite width
             64,        // sprite height
             64,        // bitmap image width
             64,        // bitmap image height
             GL_RGB16,    // texture type for glTexImage2D() in videoGL.h
             TEXTURE_SIZE_64, // sizeX for glTexImage2D() in videoGL.h
             TEXTURE_SIZE_64, // sizeY for glTexImage2D() in videoGL.h
             GL_TEXTURE_WRAP_S or GL_TEXTURE_WRAP_T or TEXGEN_OFF or GL_TEXTURE_COLOR0_TRANSPARENT,
             16,          // Length of the palette to use (16 colors)
             @shuttlePal, // Load our 16 color Shuttle palette
             @shuttleBitmap  // image data generated by GRIT
           );

  
  // Flyer
  FlyerTextureID := glLoadTileSet(
            Flyer,
             64,
             64,
             64,
             64,
             GL_RGB16,
             TEXTURE_SIZE_64,
             TEXTURE_SIZE_64,
             GL_TEXTURE_WRAP_S or GL_TEXTURE_WRAP_T or TEXGEN_OFF or GL_TEXTURE_COLOR0_TRANSPARENT,
             16,          // Length of the palette to use (16 colors)
             @flyerPal,     // Load our 16 color Flyer palette
             @flyerBitmap
           );

  
  

  // Print some console stuff
  
  iprintf(#$1b'[1;1HEasy GL2D + 3D');
  iprintf(#$1b'[2;1HRelminator');
  iprintf(#$1b'[4;1HHttp://Rel.Phatcode.Net');
  
  iprintf(#$1b'[6;1HA demo showing a very easy');
  iprintf(#$1b'[7;1Hway to combine 3D and 2D');
  
  iprintf(#$1b'[ 9;1HSprites by:');
  iprintf(#$1b'[10;1H  Adigun A. Polack and Patater');
  iprintf(#$1b'[11;1HFixed Point atan2Lerp By Cearn');
  
  iprintf(#$1b'[13;1HEnemiesTextureID = %i', EnemiesTextureID);
  iprintf(#$1b'[14;1HFlyerTextureID = %i', FlyerTextureID);
  iprintf(#$1b'[15;1HShuttleTextureID = %i', ShuttleTextureID);
  
  
  iprintf(#$1b'[17;1HEnemies use a 256 color pal');
  iprintf(#$1b'[18;1HShuttle uses a 16 color pal');
  iprintf(#$1b'[19;1HFlyer uses a 16 color pal');
  iprintf(#$1b'[20;1H3D plane is a 16 bit image');
  
  TextureSize := enemiesBitmapLen + flyerBitmapLen + organ16BitmapLen + shuttleBitmapLen;
            
  iprintf(#$1b'[22;1HTotal Texture size= %i kb', TextureSize div 1024);
  
  // some variables for our demo
  ox := 0; oy := 0;     // needed for shuttle angle calculation
  Frame := 0;       // just the standard frame counter
  PhoenixFrame := 0;    // animation frame for our firebird
  BeeFrame := 0;      // animation frame for the bee
  Rotation := 0;      // rotation value of the rotating sprites
  
  while true do 
  begin
    inc(frame);
    
    rotation := frame * 240;    // speed up our rotation
    
    // animate some of our animated sprites
    // every 8th frame
    if ( (Frame and 7) = 0 ) then
    begin
      BeeFrame := (BeeFrame + 1) and 1;
      inc(PhoenixFrame);
      if (PhoenixFrame > 2) then 
        PhoenixFrame := 0;
    end;
    
    
    // calculate positions for our rotating sprites
    x := 128 + SarLongint((cosLerp(Frame) + sinLerp(BRAD_PI + Rotation) * 70), 12);
    y := 96 + SarLongint((cosLerp(Frame) + cosLerp(-Rotation) * 50), 12);
      
    
    // Calculate moving shuttle position
    // Get new ship position in f32 format for accuracy since
    // shifting here by >> 12 looses accuracy
    sx := (cosLerp(Frame * 150) + sinLerp(Frame * 70)) * (SCREEN_WIDTH div 4) ;
    sy := (sinLerp(-(Frame * 80)) + sinLerp(Frame * 190)) * (SCREEN_HEIGHT div 4) ;   
    
    // get angle(binary radian) to draw the rotated shuttle
    angle := atan2Lerp(ox - sx, oy - sy);    
    
    // save positions for use on the nexgt frame to get the new angle
    ox := sx;
    oy := sy;
    
     
    // Get new shuttle position
    // Shifting by >> 12 so that we can screen coordinates to draw
    sx := SCREEN_WIDTH div 2 + SarLongint(sx, 12);
    sy := SCREEN_HEIGHT div 2 + SarLongint(sy, 12);   
    
    
    
    
    // Drawing the fake mode7 FX in 3D mode
    
    draw_grid();  
      
    // End drawing in 3D mode
    
    // Start 2D mode
    glBegin2D();
      // Draw our enemies
      // draw some rotated and/or animated sprites
      glSpriteRotate(    x,     y,      Rotation,          GL_FLIP_NONE, @Enemies[30+BeeFrame]);
      glSpriteRotate(255-x, 191-y,  Rotation * 4,             GL_FLIP_H, @Enemies[84]);
      glSpriteRotate(255-x,     y,     -Rotation,             GL_FLIP_V, @Enemies[32]);
      glSpriteRotate(    x, 191-y, -Rotation * 3, GL_FLIP_H  or  GL_FLIP_V, @Enemies[81]);
      
      // Some phoenix enemies on the right
      // Note the flipmodes 
      // Also shows how we can draw in "color mode" and shadow mode
      glSprite(200, 30,  GL_FLIP_NONE,           @Enemies[87 + PhoenixFrame]);
      glColor( RGB15(31,0,0) );
      glSprite(200, 60,  GL_FLIP_H,              @Enemies[87 + PhoenixFrame]);
      
      // Make the last two sprites translucent
      glPolyFmt(POLY_ALPHA(20)  or  POLY_CULL_NONE  or  POLY_ID(1));
      glColor( RGB15(0,31,20) );
      glSprite(200, 90,  GL_FLIP_V,              @Enemies[87 + PhoenixFrame]);
      glColor( RGB15(0,0,0) );
      glSprite(200, 130, GL_FLIP_V  or  GL_FLIP_H , @Enemies[87 + PhoenixFrame]);
      
      //Restore color and translucency to normal 
      glColor( RGB15(31,31,31) );
      glPolyFmt(POLY_ALPHA(31)  or  POLY_CULL_NONE );
  
  
     
      // Offset the angle by -PI/2 since Patater's
      // Original sprite faces upwards
      glSpriteRotate( sx, sy, angle - (BRAD_PI div 2), GL_FLIP_NONE, @Shuttle);
      
      // Make the flyer translucent just for kicks
      glPolyFmt(POLY_ALPHA(20)  or  POLY_CULL_NONE  or  POLY_ID(2));
      glSpriteRotateScaleXY(SCREEN_WIDTH div 2, SCREEN_HEIGHT div 2, Frame * 140, sinLerp(Frame * 120) * 3, sinLerp(Frame * 210) * 2,  GL_FLIP_NONE, @Flyer);
      
      // Restore to normal rendering just to be safe
      glPolyFmt(POLY_ALPHA(31)  or  POLY_CULL_NONE );
      
    glEnd2D();
    glFlush( 0 );

    swiWaitForVBlank();
  
    
  end;

end.