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