Clean up. This dir is still on experimental branch
[sdlgit/SDL_perl.git] / test / OpenGL / tutorial / lesson08.pl
1 #!/usr/bin/perl -w
2 # This code was created by Jeff Molofee '99
3 # (ported to SDL by Sam Lantinga '2000)
4 # (ported to Perl/SDL by Wayne Keenan '2000)
5 #
6 # If you've found this code useful, please let me know.
7 #
8 # Visit me at www.demonews.com/hosted/nehe 
9
10 use strict;
11 use Getopt::Long;
12 use Data::Dumper;
13 use Benchmark;
14
15 use SDL;
16 use SDL::App;
17 use SDL::OpenGL;
18 use SDL::Event;
19 use SDL::Surface;
20 use SDL::Cursor;
21 use SDL::OpenGL;
22
23 my $arg_screen_width =640;
24 my $arg_screen_height=512;
25 my $arg_fullscreen=0;
26
27 GetOptions(
28            "width:i"        => \$arg_screen_width,
29            "height:i"       => \$arg_screen_height,
30            "fullscreen!"    => \$arg_fullscreen,
31
32           ) or die $!;
33
34 ############################################################
35
36 my  $light = 0;
37
38 my $xrot=0;   # x rotation 
39 my $yrot=0;   # y rotation 
40 my $xspeed=0; # x rotation speed
41 my $yspeed=0; # y rotation speed
42
43 my $z=-5.0; # depth into the screen.
44
45 my $filter = 1; # Which Filter To Use (nearest/linear/mipmapped) */
46 my $blend  = 1;
47
48
49 print STDERR "Use b to toggle blend, page up/down to zoom, and arrow keys to rotate\n";
50
51 main();
52 exit;
53
54
55 sub main
56   {  
57    my $done=0;
58    my $vidmode_flags= SDL_OPENGL;
59
60    $vidmode_flags|= SDL_FULLSCREEN if $arg_fullscreen;
61    
62    my $app = new SDL::App ( -title => "Jeff Molofee's GL Code Tutorial ... NeHe '99", 
63                             -icon => "icon.png",
64                             -flags => $vidmode_flags,                   
65                             -width => $arg_screen_width,
66                             -height =>$arg_screen_height,
67                             -opengl => 1,
68                           );
69    
70    SDL::ShowCursor(0);
71    
72    my $event = new SDL::Event;
73    $event->set(SDL_SYSWMEVENT,SDL_IGNORE);
74    
75    InitGL($arg_screen_width, $arg_screen_height);
76
77    glEnable(GL_BLEND);              # Turn Blending On
78    glEnable(GL_LIGHTING);
79    glDisable(GL_DEPTH_TEST);         # Turn Depth Testing Off
80
81    while ( not $done ) 
82      {
83       
84       DrawGLScene();
85
86       $app->sync();
87       
88       $event->pump;
89       $event->poll;
90       
91       $done = 1 if ( $event->type == SDL_QUIT ) ;
92       
93       if ( $event->type == SDL_KEYDOWN ) 
94         {
95          my $key= $event->key_sym;
96
97          $done = 1 if ( $key == SDLK_ESCAPE ) ;
98          
99          if ($key==SDLK_f)
100            {
101             printf("Filter was: %d\n", $filter);
102             $filter = 1+(($filter) % 3) ;
103             printf("Filter is now: %d\n", $filter);      
104             $app->delay(100);
105            } 
106          if ($key == SDLK_b)
107            {
108             printf("Blend was: %d\n", $blend);
109             $blend = $blend ? 0 : 1;              
110             printf("Blend is now: %d\n", $blend);
111                 $app->delay(100);
112             if ($blend) 
113               {
114                glEnable(GL_BLEND);                  # Turn Blending On
115                glEnable(GL_LIGHTING);
116                glDisable(GL_DEPTH_TEST);         # Turn Depth Testing Off
117               } 
118             else 
119               {
120                glDisable(GL_BLEND);              # Turn Blending Off
121                glDisable(GL_LIGHTING);
122                glEnable(GL_DEPTH_TEST);          # Turn Depth Testing On
123               }
124            }
125          #bit lax:
126          $z-=0.02      if ( $key == SDLK_PAGEUP );
127          $z+=0.02      if ( $key == SDLK_PAGEDOWN );
128          $xspeed+=0.02 if ( $key == SDLK_UP );
129          $xspeed-=0.02 if ( $key == SDLK_DOWN );         
130          $yspeed-=0.01 if ( $key == SDLK_LEFT );
131          $yspeed+=0.01 if ( $key == SDLK_RIGHT );
132          
133         }
134      }
135   }
136
137
138
139
140
141
142 #########################################################################
143 #Pretty much in original form, but 'Perlised' 
144
145
146
147
148 sub InitGL
149   {
150    my ($Width, $Height) = @_;
151
152    glViewport(0, 0, $Width, $Height);
153
154    LoadGLTextures();                            # Load The Texture(s) 
155
156    glEnable(GL_TEXTURE_2D);                     # Enable Texture Mapping
157
158    
159    glClearColor(0.0, 0.0, 0.0, 0.0);                            # This Will Clear The Background Color To Black
160    glClearDepth(1.0);                                           # Enables Clearing Of The Depth Buffer
161    glDepthFunc(GL_LESS);                                        # The Type Of Depth Test To Do
162    glEnable(GL_DEPTH_TEST);                                     # Enables Depth Testing
163    glShadeModel(GL_SMOOTH);                                     # Enables Smooth Color Shading
164    
165    glMatrixMode(GL_PROJECTION);
166    glLoadIdentity();                                            # Reset The Projection Matrix
167    
168    gluPerspective(45.0, $Width/$Height, 0.1, 100.0);            # Calculate The Aspect Ratio Of The Window
169    
170    glMatrixMode(GL_MODELVIEW);
171
172    
173    my $LightAmbient  = [ 0.5, 0.5, 0.5, 1.0 ];                   # white ambient light at half intensity (rgba) */
174
175    my $LightDiffuse  = [ 1.0, 1.0, 1.0, 1.0 ];                    # super bright, full intensity diffuse light. */
176
177    my $LightPosition = [ 0.0 , 0.0, 2.0, 1.0 ];                 # position of light (x, y, z, (position of light)) */
178
179
180
181    #setup light number 1
182    glLight(GL_LIGHT1, GL_AMBIENT, @$LightAmbient);  # add lighting. (ambient)
183    glLight(GL_LIGHT1, GL_DIFFUSE, @$LightDiffuse);  # add lighting. (diffuse).
184    glLight(GL_LIGHT1, GL_POSITION,@$LightPosition); # set light position.
185    glEnable(GL_LIGHT1);                             # turn light 1 on.  
186    #/* setup blending */
187    glBlendFunc(GL_SRC_ALPHA,GL_ONE);                    # Set The Blending Function For Translucency
188    glColor(1.0, 1.0, 1.0, 0.5);    
189
190
191   }
192
193
194
195 # The main drawing function.
196 sub DrawGLScene
197   {
198    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);          # Clear The Screen And The Depth Buffer
199    glLoadIdentity();                                            # Reset The View
200    
201    glTranslate(0.0,0.0,$z);                  # move z units out from the screen.
202     
203    glRotate($xrot,1.0,0.0,0.0);         # Rotate On The X Axis
204    glRotate($yrot,0.0,1.0,0.0);         # Rotate On The Y Axis
205    
206    glBindTexture(GL_TEXTURE_2D, $filter);                       # choose the texture to use.
207    
208    glBegin(GL_QUADS);                                           # begin drawing a cube
209    
210    # Front Face (note that the texture's corners have to match the quad's corners)
211    glNormal( 0.0, 0.0, 1.0);                                    # front face points out of the screen on z.
212    glTexCoord(0.0, 0.0); glVertex(-1.0, -1.0,  1.0);    # Bottom Left Of The Texture and Quad
213    glTexCoord(1.0, 0.0); glVertex( 1.0, -1.0,  1.0);    # Bottom Right Of The Texture and Quad
214    glTexCoord(1.0, 1.0); glVertex( 1.0,  1.0,  1.0);    # Top Right Of The Texture and Quad
215    glTexCoord(0.0, 1.0); glVertex(-1.0,  1.0,  1.0);    # Top Left Of The Texture and Quad
216    
217    # Back Face
218    glNormal( 0.0, 0.0,-1.0);                                    # back face points into the screen on z.
219    glTexCoord(1.0, 0.0); glVertex(-1.0, -1.0, -1.0);    # Bottom Right Of The Texture and Quad
220    glTexCoord(1.0, 1.0); glVertex(-1.0,  1.0, -1.0);    # Top Right Of The Texture and Quad
221    glTexCoord(0.0, 1.0); glVertex( 1.0,  1.0, -1.0);    # Top Left Of The Texture and Quad
222    glTexCoord(0.0, 0.0); glVertex( 1.0, -1.0, -1.0);    # Bottom Left Of The Texture and Quad
223    
224    # Top Face
225    glNormal( 0.0, 1.0, 0.0);                                    # top face points up on y.
226    glTexCoord(0.0, 1.0); glVertex(-1.0,  1.0, -1.0);    # Top Left Of The Texture and Quad
227    glTexCoord(0.0, 0.0); glVertex(-1.0,  1.0,  1.0);    # Bottom Left Of The Texture and Quad
228    glTexCoord(1.0, 0.0); glVertex( 1.0,  1.0,  1.0);    # Bottom Right Of The Texture and Quad
229    glTexCoord(1.0, 1.0); glVertex( 1.0,  1.0, -1.0);    # Top Right Of The Texture and Quad
230    
231    # Bottom Face       
232    glNormal( 0.0, -1.0, 0.0);                                   # bottom face points down on y. 
233    glTexCoord(1.0, 1.0); glVertex(-1.0, -1.0, -1.0);    # Top Right Of The Texture and Quad
234    glTexCoord(0.0, 1.0); glVertex( 1.0, -1.0, -1.0);    # Top Left Of The Texture and Quad
235    glTexCoord(0.0, 0.0); glVertex( 1.0, -1.0,  1.0);    # Bottom Left Of The Texture and Quad
236    glTexCoord(1.0, 0.0); glVertex(-1.0, -1.0,  1.0);    # Bottom Right Of The Texture and Quad
237    
238    # Right face
239    glNormal( 1.0, 0.0, 0.0);                                    # right face points right on x.
240    glTexCoord(1.0, 0.0); glVertex( 1.0, -1.0, -1.0);    # Bottom Right Of The Texture and Quad
241    glTexCoord(1.0, 1.0); glVertex( 1.0,  1.0, -1.0);    # Top Right Of The Texture and Quad
242    glTexCoord(0.0, 1.0); glVertex( 1.0,  1.0,  1.0);    # Top Left Of The Texture and Quad
243    glTexCoord(0.0, 0.0); glVertex( 1.0, -1.0,  1.0);    # Bottom Left Of The Texture and Quad
244    
245    # Left Face
246    glNormal(-1.0, 0.0, 0.0);                                    # left face points left on x.
247    glTexCoord(0.0, 0.0); glVertex(-1.0, -1.0, -1.0);    # Bottom Left Of The Texture and Quad
248    glTexCoord(1.0, 0.0); glVertex(-1.0, -1.0,  1.0);    # Bottom Right Of The Texture and Quad
249    glTexCoord(1.0, 1.0); glVertex(-1.0,  1.0,  1.0);    # Top Right Of The Texture and Quad
250    glTexCoord(0.0, 1.0); glVertex(-1.0,  1.0, -1.0);    # Top Left Of The Texture and Quad
251    
252    glEnd();                                                     # done with the polygon.
253    
254    $xrot+=$xspeed;                                              # X Axis Rotation       
255    $yrot+=$yspeed;                                              # Y Axis Rotation
256    
257    
258    
259   }
260
261
262
263
264 sub LoadGLTextures
265   {
266     # Load Texture
267
268    
269    my ($pixels, $width, $height, $size)=ImageLoad("Data/glass.bmp");
270    
271    # Create Texture     
272    
273    glGenTextures(3);
274    
275    # texture 1 (poor quality scaling)
276    glBindTexture(GL_TEXTURE_2D, 1);                     # 2d texture (x and y size)
277    
278    glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); # cheap scaling when image bigger than texture
279    glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); # cheap scaling when image smalled than texture
280    
281    # 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image, 
282    # border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
283    #glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);
284    
285    glTexImage2D(GL_TEXTURE_2D, 
286                   0,                                            #level (0 normal, heighr is form mip-mapping)
287                   3,                                            #internal format (3=GL_RGB)
288                   $width,$height,
289                   0,                                            # border 
290                   GL_RGB,                                       #format RGB color data
291                   GL_UNSIGNED_BYTE,                             #unsigned bye data
292                   $pixels);                             #ptr to texture data
293    
294
295
296    # texture 2 (linear scaling)
297    glBindTexture(GL_TEXTURE_2D, 2);                     # 2d texture (x and y size)
298    glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); # scale linearly when image bigger than texture
299    glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); # scale linearly when image smalled than texture
300    #glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);
301    
302    glTexImage2D(GL_TEXTURE_2D, 
303                   0,                                            #level (0 normal, heighr is form mip-mapping)
304                   3,                                            #internal format (3=GL_RGB)
305                   $width,$height,
306                   0,                                            # border 
307                   GL_RGB,                                       #format RGB color data
308                   GL_UNSIGNED_BYTE,                             #unsigned bye data
309                   $pixels);                             #ptr to texture data
310
311
312
313    
314    # texture 3 (mipmapped scaling)
315    glBindTexture(GL_TEXTURE_2D, 3);                     # 2d texture (x and y size)
316    glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); # scale linearly when image bigger than texture
317    glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); # scale linearly + mipmap when image smalled than texture
318    #glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);
319    
320    glTexImage2D(GL_TEXTURE_2D, 
321                   0,                                            #level (0 normal, heighr is form mip-mapping)
322                   3,                                            #internal format (3=GL_RGB)
323                   $width,$height,
324                   0,                                            # border 
325                   GL_RGB,                                       #format RGB color data
326                   GL_UNSIGNED_BYTE,                             #unsigned bye data
327                   $pixels);                             #ptr to texture data
328    
329    # 2d texture, 3 colors, width, height, RGB in that order, byte data, and the data.
330    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, $width, $height, GL_RGB, GL_UNSIGNED_BYTE, $pixels); 
331    
332    my $glerr=glGetError();
333    die "Problem setting up 2d Texture (dimensions not a power of 2?)):".gluErrorString($glerr)."\n" if $glerr;
334    
335   }
336
337
338
339
340
341
342
343
344
345
346
347 #somthing needs to keep the ref count alive for objects which represents data in C space (they have no ref count):
348 my @ref=();
349  
350 sub ImageLoad
351   {
352    my $filename=shift;
353
354    my $surface = new SDL::Surface( -name  => $filename); #makes use of SDL: BMP loader.
355    
356    
357    my $width=$surface->width();
358    my $height=$surface->height();
359    my $bytespp=  $surface->bytes_per_pixel();
360    my $size=   $width*$height*$bytespp;
361
362    my $surface_pixels=$surface->pixels();
363    my $surface_size=$width*$height*$surface->bytes_per_pixel();
364    my $raw_pixels = reverse $surface_pixels;   
365    
366
367    
368    #do a conversion (the pixel data is accessable as a simple string)
369
370    my $pixels=$raw_pixels;
371    my $pre_conv= $pixels;
372    my $new_pixels="";
373    for (my $y=0; $y< $height; $y++)
374      {
375       my $y_pos=$y*$width*$bytespp;              #calculate offset into the image (a string)
376       my $row=substr ($pre_conv, $y_pos, $width*$bytespp); #extract 1 pixel row
377       $row =~ s/\G(.)(.)(.)/$3$2$1/gms;                    #turn the BMP BGR order into OpenGL RGB order;  
378       $new_pixels.= reverse $row;       
379      }
380    
381    $raw_pixels = $new_pixels;                #put transformed data into C array.
382    push @ref, $raw_pixels, $surface;
383
384    #we could have created another SDL surface frm the '$raw_pixel's... oh well.
385    return ($raw_pixels, $width, $height, $size);
386   }