Added SDL_Pallete Capability
[sdlgit/SDL_perl.git] / test / OpenGL / tutorial / lesson18.pl
1 #!/usr/bin/perl 
2 # This code was created by Jeff Molofee '99
3 # (ported to SDL by Sam Lantinga '2000)
4 # (ported to Linux/SDL by Ti Leggett '01)
5
6 # Lesson18 adapted by JusTiCe8 @2007 from others lesson and
7 #       ported to new Perl SDL, comments stripped (see Nehe lessons)
8
9 # If you've found this code useful, please let me know.
10
11 # Visit Jeff at http://nehe.gamedev.net/
12  
13 # or for port-specific comments, questions, bugreports etc. 
14 # email to leggett@eecs.tulane.edu (C/SDL)
15 # or justice8@wanadoo.fr (SDL-Perl)
16
17 use strict;
18 use Getopt::Long;
19
20 use SDL::Constants;
21 use SDL::App;
22 use SDL::OpenGL::Constants;
23 use SDL::OpenGL;
24 use SDL::Event;
25 use SDL::Cursor;     
26
27 use constant NUM_TEXTURES => 3;
28
29 my $arg_screen_width = 640;
30 my $arg_screen_height = 480;
31 my $arg_fullscreen = 0;
32 my $delay = 5;
33
34 my $light = 0;
35
36 my ($part1, $part2);
37 my ($p1, $p2) = (0, 1);
38
39 my ($xrot, $yrot, $xspeed, $yspeed);
40 my $z = -5.0;
41
42 my $LightAmbient = [ 0.5, 0.5, 0.5, 1.0 ];
43 my $LightDiffuse = [ 1.0, 1.0, 1.0, 1.0 ];
44 my $LightPosition = [ 0.0, 0.0, 2.0, 1.0 ];
45
46 my $quadratic;
47 my $object = 5;
48 my $filter = 1;
49
50 # this flag is used to limit key strokes event
51 my $pressed = 0;
52
53 GetOptions
54         (
55                 "width:i"       => \$arg_screen_width,
56                 "height:i"      => \$arg_screen_height,
57                 "fullscreen!"   => \$arg_fullscreen,
58                 "delay:i"       => \$delay,
59           )
60           or die $!;
61
62 main();
63 exit;
64
65 sub main
66
67         my $done = 0;
68         my $fps = 0.0;
69         my $frames_drawn = 0;
70    
71         my $app = new SDL::App 
72                                 (
73                                         -title  => "Jeff Molofee's lesson18: Quadratic",
74                                         -icon   => "icon.png",
75                                         -width  => $arg_screen_width,
76                                         -height => $arg_screen_height,
77                                         -opengl => 1,
78                                 );
79
80         $app->fullscreen if ($arg_fullscreen);
81    
82         SDL::ShowCursor (0);
83    
84         my $event = new SDL::Event;
85         $event->set (SDL_SYSWMEVENT (), SDL_IGNORE ());
86
87         InitGL ($arg_screen_width, $arg_screen_height);
88
89         my $prev_ticks = $app->ticks ();
90         my $fps_counter = 0.0;
91
92         while ( !$done )
93         {
94                 DrawGLScene ();
95
96                 $app->sync ();
97                 $app->delay ($delay) if ($delay > 0);
98                 $frames_drawn++;
99
100                 my $ticks_now = $app->ticks ();
101                 $fps_counter += $ticks_now - $prev_ticks;
102                 $prev_ticks = $ticks_now;
103
104                 if( $fps_counter >= 5000.0)
105                 {
106                         $fps = $frames_drawn / ($fps_counter / 1000.0);
107                         printf("%d frames in %.2f seconds = %.3f FPS\n", $frames_drawn, $fps_counter / 1000.0, $fps);
108                         $frames_drawn = 0;
109                         $fps_counter = 0.0;
110                 }
111
112                 $event->pump;
113                 $event->poll;
114     
115                 $done = 1 if ($event->type == &SDL_QUIT );
116                 
117                 if ($event->type == &SDL_KEYDOWN )
118                 {
119                         $done = 1 if ($event->key_sym == &SDLK_ESCAPE );
120
121                         if ($event->key_sym == &SDLK_f and !$pressed)
122                         {
123                                 $filter = 1 + $filter % 3;
124                                 #print "Filter = $filter\n";
125                                 $pressed = 1;
126                         }
127                         elsif ($event->key_sym == &SDLK_l and !$pressed)
128                         {
129                                 $light = !$light;
130                                 if (!$light)
131                                 {
132                                         glDisable ( &GL_LIGHTING );
133                                 } else {
134                                         glEnable ( &GL_LIGHTING );
135                                 }
136                                 $pressed = 1;
137                         }
138                         elsif ($event->key_sym == &SDLK_SPACE and !$pressed)
139                         {
140                                 $object = ++$object % 6;
141                                 $pressed = 1;
142                         }
143                         elsif ($event->key_sym == &SDLK_PAGEUP)
144                         {
145                                 $z -= 0.02;
146                         }
147                         elsif ($event->key_sym == &SDLK_PAGEDOWN)
148                         {
149                                 $z += 0.02;
150                         }
151                         elsif ($event->key_sym == &SDLK_UP)
152                         {
153                                 $xspeed -= 0.01;
154                         }
155                         elsif ($event->key_sym == &SDLK_DOWN)
156                         {
157                                 $xspeed += 0.01;
158                         }
159                         elsif ($event->key_sym == &SDLK_RIGHT)
160                         {
161                                 $yspeed += 0.01;
162                         }
163                         elsif ($event->key_sym == &SDLK_LEFT)
164                         {
165                                 $yspeed -= 0.01;
166                         }
167                 }
168                 elsif ($event->type == &SDL_KEYUP)
169                 {
170                         $pressed = 0;
171                 }
172         }
173 }
174
175
176 sub InitGL
177 {
178         my ($Width, $Height) = @_;
179         ($xrot, $yrot) = (0.0, 0.0);
180
181         glViewport (0, 0, $Width, $Height);
182
183         LoadGLTexture ();
184         glEnable (&GL_TEXTURE_2D);
185         glShadeModel (&GL_SMOOTH);
186
187         glClearColor (0.0, 0.0, 0.0, 0.0);
188         glClearDepth (1.0);
189
190         glEnable (&GL_DEPTH_TEST);
191         glDepthFunc (&GL_LESS);         # GL_EQUAL as source tutorial don't work (?)
192         glHint ( &GL_PERSPECTIVE_CORRECTION_HINT, &GL_NICEST );
193    
194     glLight ( &GL_LIGHT1, &GL_AMBIENT, @$LightAmbient );
195     glLight ( &GL_LIGHT1, &GL_DIFFUSE, @{$LightDiffuse} );
196     glLight ( &GL_LIGHT1, &GL_POSITION, @{$LightPosition} );
197
198     glEnable ( &GL_LIGHT1 );
199
200         $quadratic = gluNewQuadric ();
201         #gluQuadricNormals ( $quadratic, &GLU_SMOOTH );
202         gluQuadricTexture ( $quadratic, &GL_TRUE );
203
204         glMatrixMode (&GL_PROJECTION);
205         glLoadIdentity ();
206    
207         gluPerspective (45.0, $Width/$Height, 0.1, 100.0);
208    
209         glMatrixMode (&GL_MODELVIEW);
210 }
211
212
213 sub drawGLCube
214 {
215         glBegin (&GL_QUADS);
216   
217         glNormal ( 0.0, 0.0, 1.0);
218         glTexCoord (1.0, 0.0); glVertex (-1.0, -1.0,  1.0);
219         glTexCoord (0.0, 0.0); glVertex ( 1.0, -1.0,  1.0);
220         glTexCoord (0.0, 1.0); glVertex ( 1.0,  1.0,  1.0);
221         glTexCoord (1.0, 1.0); glVertex (-1.0,  1.0,  1.0);
222    
223         glNormal ( 0.0, 0.0,-1.0);
224         glTexCoord (0.0, 0.0); glVertex (-1.0, -1.0, -1.0);
225         glTexCoord (0.0, 1.0); glVertex (-1.0,  1.0, -1.0);
226         glTexCoord (1.0, 1.0); glVertex ( 1.0,  1.0, -1.0);
227         glTexCoord (1.0, 0.0); glVertex ( 1.0, -1.0, -1.0);
228    
229         glNormal ( 0.0, 1.0, 0.0);
230         glTexCoord( 1.0, 1.0); glVertex (-1.0,  1.0, -1.0);
231         glTexCoord (1.0, 0.0); glVertex (-1.0,  1.0,  1.0);
232         glTexCoord (0.0, 0.0); glVertex ( 1.0,  1.0,  1.0);
233         glTexCoord (0.0, 1.0); glVertex ( 1.0,  1.0, -1.0);
234    
235         glNormal ( 0.0, -1.0, 0.0);
236         glTexCoord (0.0, 1.0); glVertex (-1.0, -1.0, -1.0);
237         glTexCoord (1.0, 1.0); glVertex ( 1.0, -1.0, -1.0);
238         glTexCoord (1.0, 0.0); glVertex ( 1.0, -1.0,  1.0);
239         glTexCoord (0.0, 0.0); glVertex (-1.0, -1.0,  1.0);
240     
241         glNormal ( 1.0, 0.0, 0.0);
242         glTexCoord (0.0, 0.0); glVertex ( 1.0, -1.0, -1.0);
243         glTexCoord (0.0, 1.0); glVertex ( 1.0,  1.0, -1.0);
244         glTexCoord (1.0, 1.0); glVertex ( 1.0,  1.0,  1.0);
245         glTexCoord (1.0, 0.0); glVertex ( 1.0, -1.0,  1.0);
246    
247         glNormal (-1.0, 0.0, 0.0);
248         glTexCoord (1.0, 0.0); glVertex (-1.0, -1.0, -1.0);
249         glTexCoord (0.0, 0.0); glVertex (-1.0, -1.0,  1.0);
250         glTexCoord (0.0, 1.0); glVertex (-1.0,  1.0,  1.0);
251         glTexCoord (1.0, 1.0); glVertex (-1.0,  1.0, -1.0);
252
253         glEnd();
254 }
255
256
257 sub DrawGLScene
258 {
259         glClear(&GL_COLOR_BUFFER_BIT | &GL_DEPTH_BUFFER_BIT);
260         glLoadIdentity();
261    
262         glTranslate ( 0.0, 0.0, $z);
263
264         glRotate ($xrot, 1.0, 0.0, 0.0);
265         glRotate ($yrot, 0.0, 1.0, 0.0);
266
267         glBindTexture(&GL_TEXTURE_2D, $filter);
268
269         if ($object == 0)
270         {
271                 drawGLCube ();
272         }
273         elsif ($object == 1)
274         {
275                 glTranslate ( 0.0, 0.0, -1.5 );
276                 gluCylinder ( $quadratic, 1.0, 1.0, 3.0, 32, 32 );
277         }
278         elsif ($object == 2)
279         {
280                 gluDisk ( $quadratic, 0.5, 1.5, 32, 32 );
281         }
282         elsif ($object == 3)
283         {
284                 gluSphere ( $quadratic, 1.3, 32, 32 );
285         }
286         elsif ($object == 4)
287         {
288                 glTranslate ( 0.0, 0.0, -1.5 );
289                 gluCylinder ( $quadratic, 1.0, 0.0, 3.0, 32, 32 );
290         }
291         elsif ($object == 5)
292         {
293                 $part1 += $p1;
294                 $part2 += $p2;
295                 if ( $part1 > 359 )
296                 {
297                         $p1 = 0;
298                         $part1 = 0;
299                         $p2 = 1;
300                         $part2 = 0;
301                 }
302                 if ( $part2 > 359 )
303                 {
304                         $p1 = 1;
305                         $p2 = 0;
306                 }
307
308                 gluPartialDisk ( $quadratic, 0.5, 1.5, 32, 32, $part1, $part2 - $part1 );
309         }
310
311         $xrot += $xspeed;
312         $yrot += $yspeed;
313 }
314
315
316 sub LoadGLTexture
317 {
318         my ($pixels, $width, $height, $size) = ImageLoad ('data/wall.bmp');
319         #print "LoadGLTexture: w:$width h:$height s:$size\n";
320    
321         my $textures = glGenTextures (NUM_TEXTURES);
322         unless ($$textures[0])
323         {
324                 print "Could not generate textures\n";
325                 return 0;
326         }
327
328         glBindTexture (&GL_TEXTURE_2D, 1); #$$textures[0]);
329
330         glTexImage2D 
331                                 (
332                                         &GL_TEXTURE_2D,
333                                         0,
334                                         3,
335                                         $width, $height,
336                                         0,
337                                         &GL_BGR,
338                                         &GL_UNSIGNED_BYTE,
339                                         $pixels
340                                 );
341    
342         glTexParameter(&GL_TEXTURE_2D, &GL_TEXTURE_MAG_FILTER, &GL_NEAREST);
343         glTexParameter(&GL_TEXTURE_2D, &GL_TEXTURE_MIN_FILTER, &GL_NEAREST);
344    
345
346         glBindTexture (&GL_TEXTURE_2D, 2);
347
348         glTexImage2D 
349                                 (
350                                         &GL_TEXTURE_2D,
351                                         0,
352                                         3,
353                                         $width, $height,
354                                         0,
355                                         &GL_BGR,
356                                         &GL_UNSIGNED_BYTE,
357                                         $pixels
358                                 );
359   
360         glTexParameter (&GL_TEXTURE_2D, &GL_TEXTURE_MIN_FILTER, &GL_LINEAR);
361         glTexParameter (&GL_TEXTURE_2D, &GL_TEXTURE_MAG_FILTER, &GL_LINEAR); 
362
363
364         glBindTexture (&GL_TEXTURE_2D, 3);
365
366         glTexParameter (&GL_TEXTURE_2D, &GL_TEXTURE_MIN_FILTER, &GL_LINEAR_MIPMAP_NEAREST);
367         glTexParameter (&GL_TEXTURE_2D, &GL_TEXTURE_MAG_FILTER, &GL_LINEAR); 
368
369         gluBuild2DMipmaps 
370                                 (
371                                         &GL_TEXTURE_2D,
372                                         3,
373                                         $width, $height,
374                                         &GL_BGR,
375                                         &GL_UNSIGNED_BYTE,
376                                         $pixels
377                                 );
378   
379         my $glerr = glGetError ();
380         if ($glerr)
381         {
382                 print "Problem setting up 2d Texture (dimensions not a power of 2?)): ".gluErrorString ($glerr)."\n";
383                 return 0;
384         }
385 }
386
387  
388 sub ImageLoad
389 {
390         my $filename = shift;
391         return unless (defined $filename and -e $filename);
392
393         #somthing needs to keep the ref count alive for objects which represents data in C space (they have no ref count):
394         my @ref = ();
395
396         #makes use of SDL: BMP loader.
397         my $surface = new SDL::Surface (-name  => $filename);
398    
399         my $width = $surface->width ();
400         my $height = $surface->height ();
401         my $bytespp = $surface->bytes_per_pixel ();
402         my $size = $width * $height * $bytespp;
403
404         return ($surface->pixels (), $width, $height, $size);
405
406
407         my $surface_pixels = $surface->pixels ();
408         my $surface_size = $width * $height * $surface->bytes_per_pixel ();
409         my $raw_pixels = reverse $surface_pixels;
410    
411         #do a conversion (the pixel data is accessable as a simple string)
412         my $pixels = $raw_pixels;
413         my $pre_conv = $pixels;
414         my $new_pixels = '';
415
416         for (my $y = 0; $y< $height; $y++)
417         {
418                 # calculate offset into the image (a string)
419                 my $y_pos = $y * $width * $bytespp;
420
421                 # extract 1 pixel row
422                 my $row = substr ($pre_conv, $y_pos, $width*$bytespp);
423
424                 # turn the BMP BGR order into OpenGL RGB order;
425                 $row =~ s/\G(.)(.)(.)/$3$2$1/gms;
426                 $new_pixels .= reverse $row;       
427         }
428    
429         $raw_pixels = $new_pixels;
430         push @ref, $raw_pixels, $surface;
431
432         # we could have created another SDL surface frm the '$raw_pixel's... oh well.
433         return ($raw_pixels, $width, $height, $size);
434 }
435
436
437 END
438 {
439         gluDeleteQuadric ($quadratic);
440         $quadratic = undef;
441 =item rem
442         use Devel::Peek;
443         print "Q=$quadratic\n";
444         mstat;
445         Dump ($quadratic, 5);
446         gluDeleteQuadric ($quadratic);
447         Dump ($quadratic, 5);
448         $quadratic = undef;
449         print "Q=$quadratic\n";
450         Dump ($quadratic, 5);
451 =cut
452 }