Commit | Line | Data |
8fde61e3 |
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 | } |