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