1: #line 2942 "./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: /* general OpenGL initialization function */
84: proc initGL()
85: {
86: /* Enable smooth shading */
87: glShadeModel( GL_SMOOTH );
88:
89: /* Set the background black */
90: glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
91:
92: /* Depth buffer setup */
93: glClearDepth( 1.0 );
94:
95: /* Enables Depth Testing */
96: glEnable( GL_DEPTH_TEST );
97:
98: /* The Type Of Depth Test To Do */
99: glDepthFunc( GL_LEQUAL );
100:
101: /* Really Nice Perspective Calculations */
102: glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
103: }
104:
105: /* These are to calculate our fps */
106: var T0 = 0;
107: var Frames = 0;
108:
109:
110: /* Here goes our drawing code */
111: proc drawGLScene(drawing:1->0)
112: {
113: block_sdl_events event_lock;
114: drawing();
115: unblock_sdl_events event_lock;
116:
117: /* Gather our frames per second */
118: Frames++;
119: {
120: var t = SDL_GetTicks();
121: if t - T0 >= 5000 do
122: val seconds = double_of (t - T0) / 1000.0;
123: val fps = double_of Frames / seconds;
124: print Frames; print " frames in "; print seconds;
125: print " seconds = "; print fps; print " FPS"; endl;
126: T0 = t;
127: Frames = 0;
128: done;
129: };
130: }
131:
132: /* whether or not the window is active */
133: var isActive = true;
134:
135: if SDL_Init(SDL_INIT_AUDIO \| SDL_INIT_VIDEO) < 0 do
136: print "Unable to init SDL"; endl;
137: System::exit(1);
138: done;
139:
140: var event_lock = SDL_CreateMutex();
141:
142:
143: proc Quit(n:int)
144: {
145: SDL_Quit;
146: System::exit 0;
147: }
148:
149: /* Fetch the video info */
150: var videoInfo = SDL_GetVideoInfo();
151:
152: if isNULL videoInfo do
153: print "Video query failed"; endl;
154: Quit 1;
155: done;
156:
157: /* the flags to pass to SDL_SetVideoMode */
158: var
159: videoFlags = SDL_OPENGL; /* Enable OpenGL in SDL */
160: videoFlags |= cast[uint] SDL_GL_DOUBLEBUFFER; /* Enable double buffering */
161: videoFlags |= SDL_HWPALETTE; /* Store the palette in hardware */
162: videoFlags |= SDL_RESIZABLE; /* Enable window resizing */
163:
164: /* This checks to see if surfaces can be stored in memory */
165: if videoInfo.->hw_available != 0 do
166: videoFlags |= SDL_HWSURFACE;
167: else
168: videoFlags |= SDL_SWSURFACE;
169: done;
170:
171: /* This checks if hardware blits can be done */
172: if videoInfo.->blit_hw != 0 do
173: videoFlags |= SDL_HWACCEL;
174: done;
175:
176: /* Sets up OpenGL double buffering */
177: ignore$ SDL_GL_SetAttribute( cast[SDL_GLattr] SDL_GL_DOUBLEBUFFER, 1 );
178:
179: /* get a SDL surface */
180: var surface = SDL_SetVideoMode
181: (SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags )
182: ;
183:
184: /* Verify there is a surface */
185: if isNULL surface do
186: print "Video mode set failed"; endl;
187: Quit 1;
188: done;
189:
190: /* initialize OpenGL */
191: initGL();
192: var gl_vendor = str$ glGetString(GL_VENDOR);
193: var gl_renderer = str$ glGetString(GL_RENDERER);
194: var gl_version = str$ glGetString(GL_VERSION);
195: var gl_extensions = str$ glGetString(GL_EXTENSIONS);
196:
197: print$ "GL vendor = " + gl_vendor; endl;
198: print$ "GL renderer = " + gl_renderer; endl;
199: print$ "GL version = " + gl_version; endl;
200: print$ "GL extensions = " + gl_extensions; endl;
201:
202: /* resize the initial window */
203: resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );
204:
205:
206: proc handle_active (e:SDL_ActiveEvent)
207: {
208: isActive = e.gain != 0;
209: }
210:
211: proc handle_resize(e:SDL_ResizeEvent)
212: {
213: block_sdl_events event_lock;
214: surface = SDL_SetVideoMode(
215: e.w,
216: e.h,
217: 16, videoFlags
218: );
219: if isNULL surface do
220: print "Could not get a surface after resize"; endl;
221: done;
222: resizeWindow( e.w, e.h );
223: unblock_sdl_events event_lock;
224: }
225:
226: /* function to handle key press events */
227: proc handle_key( keysym : SDL_keysym)
228: {
229: match keysym.sym with
230: | ?k when k == SDLK_ESCAPE => { Quit 0; }
231: | ?k when k == SDLK_F1 =>
232: {
233: block_sdl_events event_lock;
234: ignore$ SDL_WM_ToggleFullScreen( surface );
235: unblock_sdl_events event_lock;
236: }
237: | _ => {}
238: endmatch;
239: }
240:
241: /* draw the scene */
242: proc draw(drawing: 1->0) {
243: if isActive call drawGLScene( drawing );
244: }
245:
246: proc keychan(x:schannel[SDL_keysym])
247: {
248: whilst true do
249: var &k : SDL_keysym <- read x;
250: handle_key k;
251: done;
252: }
253:
254: proc activechan(x:schannel[SDL_ActiveEvent])
255: {
256: whilst true do
257: var &k : SDL_ActiveEvent <- read x;
258: handle_active k;
259: done;
260: }
261:
262: proc resizechan(x:schannel[SDL_ResizeEvent])
263: {
264: whilst true do
265: var &k : SDL_ResizeEvent <- read x;
266: handle_resize k;
267: done;
268: }
269:
270: proc drawchan(x:schannel[int], drawing:1->0)
271: {
272: whilst true do
273: var &k : int <- read x;
274: draw drawing;
275: done;
276: }
277:
278: val clock = Faio::mk_alarm_clock();
279: proc poll_event(e: &SDL_Event)
280: {
281: tryagain:>
282:
283: var result = SDL_PollEvent(unref e);
284: if result > 0 do
285:
286: return;
287: done;
288: Faio::sleep$ clock, 0.1;
289: goto tryagain;
290: }
291:
292: proc dispatch_event(
293: keyboard:schannel[SDL_keysym],
294: active:schannel[SDL_ActiveEvent],
295: resize:schannel[SDL_ResizeEvent]
296: )
297: {
298: whilst true do
299:
300: var e : SDL_Event;
301: poll_event(&e);
302:
303: match e.type_ with
304: | ?et when et == SDL_ACTIVEEVENT =>
305: { write (active, e.active); }
306:
307: | ?et when et == SDL_VIDEORESIZE =>
308: { write (resize, e.resize); }
309:
310: | ?et when et == SDL_KEYDOWN =>
311: { write (keyboard, e.key.keysym); }
312:
313: | ?et when et == SDL_QUIT =>
314: { Quit 0; }
315:
316: | _ => {}
317: endmatch;
318: done;
319: }
320:
321: /* write ticks at the desired framerate */
322: proc framerate (x:schannel[int], framerate:double)
323: {
324: whilst true do
325: Faio::sleep$ clock, framerate;
326: write (x,1);
327: done;
328: }
329:
330: /* LINEAR CONTROL MODEL: CANNOT DEADLOCK
331: ~~> async/sync connection
332: --> sync/sync connection
333:
334: SDL_event ~~> dispatcher
335: --> resize handler
336: --> active handler
337: --> key handler
338: timer ~~> framerate --> draw
339: */
340:
341: /* make our communication channels */
342: var keyboard = mk_schannel[SDL_keysym] ();
343: var active = mk_schannel[SDL_ActiveEvent] ();
344: var resize = mk_schannel[SDL_ResizeEvent] ();
345: var clicks = mk_schannel[int] ();
346:
347: /* start up the fthreads and plug them together */
348: spawn_fthread { dispatch_event (keyboard, active, resize); };
349: spawn_fthread { resizechan resize; };
350: spawn_fthread { activechan active; };
351: spawn_fthread { keychan keyboard; };
352:
353: spawn_fthread { drawchan (clicks, the Drawing); };
354: spawn_fthread { framerate (clicks, 0.1); };
355:
356:
357:
358:
359: proc Drawing()
360: {
361: /* Clear The Screen And The Depth Buffer */
362: glClear( GL_COLOR_BUFFER_BIT \| GL_DEPTH_BUFFER_BIT );
363:
364: /* Move Left 1.5 Units And Into The Screen 6.0 */
365: glLoadIdentity();
366: glTranslatef( -1.5f, 0.0f, -6.0f );
367:
368: glBegin( GL_TRIANGLES ); /* Drawing Using Triangles */
369: glVertex3f( 0.0f, 1.0f, 0.0f ); /* Top */
370: glVertex3f( -1.0f, -1.0f, 0.0f ); /* Bottom Left */
371: glVertex3f( 1.0f, -1.0f, 0.0f ); /* Bottom Right */
372: glEnd( ); /* Finished Drawing The Triangle */
373:
374: /* Move Right 3 Units */
375: glTranslatef( 3.0f, 0.0f, 0.0f );
376:
377: glBegin( GL_QUADS ); /* Draw A Quad */
378: glVertex3f( -1.0f, 1.0f, 0.0f ); /* Top Left */
379: glVertex3f( 1.0f, 1.0f, 0.0f ); /* Top Right */
380: glVertex3f( 1.0f, -1.0f, 0.0f ); /* Bottom Right */
381: glVertex3f( -1.0f, -1.0f, 0.0f ); /* Bottom Left */
382: glEnd( ); /* Done Drawing The Quad */
383:
384: /* Draw it to the screen */
385: SDL_GL_SwapBuffers( );
386: }