1: #line 3796 "./lpsrc/flx_sdl.pak"
2:
3: /*
4: * This code was created by Jeff Molofee '99
5: * (ported to Linux/SDL by Ti Leggett '01)
6: *
7: * If you've found this code useful, please let me know.
8: *
9: * Visit Jeff at http:
10: *
11: * or for port-specific comments, questions, bugreports etc.
12: * email to leggett@eecs.tulane.edu
13: */
14:
15:
16: include "SDL/SDL";
17: include "SDL/SDL_keyboard";
18: include "SDL/SDL_keysym";
19: include "SDL/SDL_video";
20: include "SDL/SDL_events";
21: include "SDL/SDL_timer";
22: include "SDL/SDL_mutex";
23: include "SDL/SDL_opengl";
24:
25: include "flx_faio";
26: include "flx_faio_sdl";
27:
28:
29: open C_hack;
30: open Carray;
31: open MixedInt;
32: open Uint32;
33: open Uint8;
34: open Float;
35:
36: open SDL_h;
37: open SDL_video_h;
38: open SDL_keyboard_h;
39: open SDL_events_h;
40: open SDL_keysym_h;
41: open SDL_timer_h;
42: open SDL_mutex_h;
43:
44:
45: open SDL_events;
46:
47: open SDL_opengl_h;
48:
49: /* screen width, height, and bit depth */
50: val SCREEN_WIDTH = 640;
51: val SCREEN_HEIGHT = 480;
52: val SCREEN_BPP = 16;
53:
54: /* function to reset our viewport after a window resize */
55: proc resizeWindow( wwidth : int, hheight :int)
56: {
57: var height = hheight;
58: var width = wwidth;
59:
60: /* Protect against a divide by zero */
61: if height == 0 do height = 1; done;
62: var ratio = double_of width / double_of height;
63:
64: block_sdl_events event_lock;
65: /* Setup our viewport. */
66: glViewport( 0, 0, width, height );
67:
68: /* change to the projection matrix and set our viewing volume. */
69: glMatrixMode( GL_PROJECTION );
70: glLoadIdentity( );
71:
72: /* Set our perspective */
73: gluPerspective( 45.0, ratio, 0.1, 100.0 );
74:
75: /* Make sure we're chaning the model view and not the projection */
76: glMatrixMode( GL_MODELVIEW );
77:
78: /* Reset The View */
79: glLoadIdentity( );
80: unblock_sdl_events event_lock;
81: }
82:
83: /* function to load in bitmap as a GL texture */
84: proc LoadGLTextures( )
85: {
86: /* Create storage space for the texture */
87: var TextureImage = SDL_LoadBMP(enconst c"media/textures/sdl206.bmp");
88: if isNULL TextureImage do
89: print "Can't load texture file media/textures/sdl206.bmp";
90: Quit 1;
91: done;
92:
93: /* Create The Texture */
94: glGenTextures( 1, texture );
95:
96: /* Typical Texture Generation Using Data From The Bitmap */
97: glBindTexture( GL_TEXTURE_2D, texture.[0] );
98:
99: /* Generate The Texture */
100: glTexImage2D( GL_TEXTURE_2D, 0, 3, TextureImage.->w,
101: TextureImage.->h, 0, GL_RGB,
102: GL_UNSIGNED_BYTE, TextureImage.->pixels
103: );
104:
105: /* Linear Filtering */
106: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
107: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
108:
109: /* Free up any memory we may have used */
110: SDL_FreeSurface( TextureImage );
111: }
112:
113: /* general OpenGL initialization function */
114: proc initGL()
115: {
116: /* Enable Texture Mapping ( NEW ) */
117: glEnable( GL_TEXTURE_2D );
118:
119: /* Enable smooth shading */
120: glShadeModel( GL_SMOOTH );
121:
122: /* Set the background black */
123: glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
124:
125: /* Depth buffer setup */
126: glClearDepth( 1.0 );
127:
128: /* Enables Depth Testing */
129: glEnable( GL_DEPTH_TEST );
130:
131: /* The Type Of Depth Test To Do */
132: glDepthFunc( GL_LEQUAL );
133:
134: /* Really Nice Perspective Calculations */
135: glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
136: }
137:
138: /* These are to calculate our fps */
139: var T0 = 0;
140: var Frames = 0;
141:
142: var xrot = 0.0f; /* X Rotation ( NEW ) */
143: var yrot = 0.0f; /* Y Rotation ( NEW ) */
144: var zrot = 0.0f; /* Z Rotation ( NEW ) */
145:
146: proc rotate()
147: {
148: xrot += 0.3f; /* X Axis Rotation */
149: yrot += 0.2f; /* Y Axis Rotation */
150: zrot += 0.4f; /* Z Axis Rotation */
151: }
152:
153: var f_texture : uint ^ 2; /* Storage For One Texture ( NEW ) */
154: var texture : carray[uint] = carray f_texture;
155:
156:
157: /* Here goes our drawing code */
158: proc drawGLScene(drawing:1->0)
159: {
160: block_sdl_events event_lock;
161: drawing();
162: unblock_sdl_events event_lock;
163:
164: /* Gather our frames per second */
165: Frames++;
166: {
167: var t = SDL_GetTicks();
168: if t - T0 >= 5000 do
169: val seconds = double_of (t - T0) / 1000.0;
170: val fps = double_of Frames / seconds;
171: print Frames; print " frames in "; print seconds;
172: print " seconds = "; print fps; print " FPS"; endl;
173: T0 = t;
174: Frames = 0;
175: done;
176: };
177: rotate();
178: }
179:
180: /* whether or not the window is active */
181: var isActive = true;
182:
183: if SDL_Init(SDL_INIT_AUDIO \| SDL_INIT_VIDEO) < 0 do
184: print "Unable to init SDL"; endl;
185: System::exit(1);
186: done;
187:
188: var event_lock = SDL_CreateMutex();
189:
190:
191: proc Quit(n:int)
192: {
193: SDL_Quit;
194: System::exit 0;
195: }
196:
197: /* Fetch the video info */
198: var videoInfo = SDL_GetVideoInfo();
199:
200: if isNULL videoInfo do
201: print "Video query failed"; endl;
202: Quit 1;
203: done;
204:
205: /* the flags to pass to SDL_SetVideoMode */
206: var
207: videoFlags = SDL_OPENGL; /* Enable OpenGL in SDL */
208: videoFlags |= cast[uint] SDL_GL_DOUBLEBUFFER; /* Enable double buffering */
209: videoFlags |= SDL_HWPALETTE; /* Store the palette in hardware */
210: videoFlags |= SDL_RESIZABLE; /* Enable window resizing */
211:
212: /* This checks to see if surfaces can be stored in memory */
213: if videoInfo.->hw_available != 0 do
214: videoFlags |= SDL_HWSURFACE;
215: else
216: videoFlags |= SDL_SWSURFACE;
217: done;
218:
219: /* This checks if hardware blits can be done */
220: if videoInfo.->blit_hw != 0 do
221: videoFlags |= SDL_HWACCEL;
222: done;
223:
224: /* Sets up OpenGL double buffering */
225: ignore$ SDL_GL_SetAttribute( cast[SDL_GLattr] SDL_GL_DOUBLEBUFFER, 1 );
226:
227: /* get a SDL surface */
228: var surface = SDL_SetVideoMode
229: (SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags )
230: ;
231:
232: /* Verify there is a surface */
233: if isNULL surface do
234: print "Video mode set failed"; endl;
235: Quit 1;
236: done;
237:
238: /* initialize OpenGL */
239: initGL();
240: LoadGLTextures();
241:
242: /* resize the initial window */
243: resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );
244:
245:
246: proc handle_active (e:SDL_ActiveEvent)
247: {
248: isActive = e.gain != 0;
249: }
250:
251: proc handle_resize(e:SDL_ResizeEvent)
252: {
253: block_sdl_events event_lock;
254: surface = SDL_SetVideoMode(
255: e.w,
256: e.h,
257: 16, videoFlags
258: );
259: if isNULL surface do
260: print "Could not get a surface after resize"; endl;
261: done;
262: resizeWindow( e.w, e.h );
263: unblock_sdl_events event_lock;
264: }
265:
266: /* function to handle key press events */
267: proc handle_key( keysym : SDL_keysym)
268: {
269: match keysym.sym with
270: | ?k when k == SDLK_ESCAPE => { Quit 0; }
271: | ?k when k == SDLK_F1 =>
272: {
273: block_sdl_events event_lock;
274: ignore$ SDL_WM_ToggleFullScreen( surface );
275: unblock_sdl_events event_lock;
276: }
277: | _ => {}
278: endmatch;
279: }
280:
281: /* draw the scene */
282: proc draw(drawing: 1->0) {
283: if isActive call drawGLScene( drawing );
284: }
285:
286: proc keychan(x:schannel[SDL_keysym])
287: {
288: whilst true do
289: var &k : SDL_keysym <- read x;
290: handle_key k;
291: done;
292: }
293:
294: proc activechan(x:schannel[SDL_ActiveEvent])
295: {
296: whilst true do
297: var &k : SDL_ActiveEvent <- read x;
298: handle_active k;
299: done;
300: }
301:
302: proc resizechan(x:schannel[SDL_ResizeEvent])
303: {
304: whilst true do
305: var &k : SDL_ResizeEvent <- read x;
306: handle_resize k;
307: done;
308: }
309:
310: proc drawchan(x:schannel[int], drawing:1->0)
311: {
312: whilst true do
313: var &k : int <- read x;
314: draw drawing;
315: done;
316: }
317:
318: proc execute(x:schannel[int], something:1->0)
319: {
320: whilst true do
321: var &k : int <- read x;
322: something();
323: done;
324: }
325:
326: val clock = Faio::mk_alarm_clock();
327: proc poll_event(e: &SDL_Event)
328: {
329: tryagain:>
330:
331: var result = SDL_PollEvent(unref e);
332: if result > 0 do
333:
334: return;
335: done;
336: Faio::sleep$ clock, 0.1;
337: goto tryagain;
338: }
339:
340:
341: proc dispatch_event(
342: keyboard:schannel[SDL_keysym],
343: active:schannel[SDL_ActiveEvent],
344: resize:schannel[SDL_ResizeEvent]
345: )
346: {
347: whilst true do
348:
349: var e : SDL_Event;
350: poll_event(&e);
351: match e.type_ with
352: | ?et when et == SDL_ACTIVEEVENT =>
353: { write (active, e.active); }
354:
355: | ?et when et == SDL_VIDEORESIZE =>
356: { write (resize, e.resize); }
357:
358: | ?et when et == SDL_KEYDOWN =>
359: { write (keyboard, e.key.keysym); }
360:
361: | ?et when et == SDL_QUIT =>
362: { Quit 0; }
363:
364: | _ => {}
365: endmatch;
366: done;
367: }
368:
369: /* write ticks at the desired framerate */
370: proc framerate (x:schannel[int], framerate:double)
371: {
372: whilst true do
373: Faio::sleep $ clock,framerate;
374: write (x,1);
375: done;
376: }
377:
378: /* LINEAR CONTROL MODEL: CANNOT DEADLOCK
379: ~~> async/sync connection
380: --> sync/sync connection
381:
382: SDL_event ~~> dispatcher
383: --> resize handler
384: --> active handler
385: --> key handler
386: timer ~~> framerate --> draw
387: */
388:
389: /* make our communication channels */
390: var keyboard = mk_schannel[SDL_keysym] ();
391: var active = mk_schannel[SDL_ActiveEvent] ();
392: var resize = mk_schannel[SDL_ResizeEvent] ();
393: var clicks = mk_schannel[int] ();
394: var rotation = mk_schannel[int] ();
395:
396: /* start up the fthreads and plug them together */
397: spawn_fthread { dispatch_event (keyboard, active, resize); };
398: spawn_fthread { resizechan resize; };
399: spawn_fthread { activechan active; };
400: spawn_fthread { keychan keyboard; };
401:
402: spawn_fthread { drawchan (clicks, the Drawing); };
403: spawn_fthread { framerate (clicks, 0.1); };
404: spawn_fthread { execute (rotation, the rotate); };
405: spawn_fthread { framerate (rotation, 0.1); };
406:
407:
408:
409:
410: /* Here goes our drawing code */
411: proc Drawing()
412: {
413: /* Clear The Screen And The Depth Buffer */
414: glClear( GL_COLOR_BUFFER_BIT \| GL_DEPTH_BUFFER_BIT );
415:
416: /* Move Into The Screen 5 Units */
417: glLoadIdentity( );
418: glTranslatef( 0.0f, 0.0f, -5.0f );
419:
420: glRotatef( xrot, 1.0f, 0.0f, 0.0f); /* Rotate On The X Axis */
421: glRotatef( yrot, 0.0f, 1.0f, 0.0f); /* Rotate On The Y Axis */
422: glRotatef( zrot, 0.0f, 0.0f, 1.0f); /* Rotate On The Z Axis */
423:
424: /* Select Our Texture */
425: glBindTexture( GL_TEXTURE_2D, texture.[0] );
426:
427: /* NOTE:
428: * The x coordinates of the glTexCoord2f function need to inverted
429: * for SDL because of the way SDL_LoadBmp loads the data. So where
430: * in the tutorial it has glTexCoord2f( 1.0f, 0.0f ); it should
431: * now read glTexCoord2f( 0.0f, 0.0f );
432: */
433: glBegin(GL_QUADS);
434: /* Front Face */
435: /* Bottom Left Of The Texture and Quad */
436: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.0f, 1.0f );
437: /* Bottom Right Of The Texture and Quad */
438: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, 1.0f );
439: /* Top Right Of The Texture and Quad */
440: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f );
441: /* Top Left Of The Texture and Quad */
442: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, 1.0f );
443:
444: /* Back Face */
445: /* Bottom Right Of The Texture and Quad */
446: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.0f );
447: /* Top Right Of The Texture and Quad */
448: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f );
449: /* Top Left Of The Texture and Quad */
450: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f );
451: /* Bottom Left Of The Texture and Quad */
452: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, -1.0f );
453:
454: /* Top Face */
455: /* Top Left Of The Texture and Quad */
456: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f );
457: /* Bottom Left Of The Texture and Quad */
458: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, 1.0f );
459: /* Bottom Right Of The Texture and Quad */
460: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f );
461: /* Top Right Of The Texture and Quad */
462: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f );
463:
464: /* Bottom Face */
465: /* Top Right Of The Texture and Quad */
466: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.0f, -1.0f );
467: /* Top Left Of The Texture and Quad */
468: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, -1.0f );
469: /* Bottom Left Of The Texture and Quad */
470: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, 1.0f );
471: /* Bottom Right Of The Texture and Quad */
472: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f );
473:
474: /* Right face */
475: /* Bottom Right Of The Texture and Quad */
476: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, -1.0f );
477: /* Top Right Of The Texture and Quad */
478: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f );
479: /* Top Left Of The Texture and Quad */
480: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, 1.0f );
481: /* Bottom Left Of The Texture and Quad */
482: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, 1.0f );
483:
484: /* Left Face */
485: /* Bottom Left Of The Texture and Quad */
486: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.0f );
487: /* Bottom Right Of The Texture and Quad */
488: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f );
489: /* Top Right Of The Texture and Quad */
490: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, 1.0f );
491: /* Top Left Of The Texture and Quad */
492: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f );
493: glEnd( );
494:
495: /* Draw it to the screen */
496: SDL_GL_SwapBuffers( );
497: }