Mercurial > projects > mde
comparison mde/setup/Screen.d @ 85:56c0ddd90193
Intermediate commit (not stable). Changes to init system.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Thu, 11 Sep 2008 11:33:51 +0100 |
parents | mde/setup/sdl.d@ea58f277f487 |
children | 79d816b3e2d2 |
comparison
equal
deleted
inserted
replaced
84:e0f1ec7fe73a | 85:56c0ddd90193 |
---|---|
1 /* LICENSE BLOCK | |
2 Part of mde: a Modular D game-oriented Engine | |
3 Copyright © 2007-2008 Diggory Hardy | |
4 | |
5 This program is free software: you can redistribute it and/or modify it under the terms | |
6 of the GNU General Public License as published by the Free Software Foundation, either | |
7 version 2 of the License, or (at your option) any later version. | |
8 | |
9 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | |
10 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
11 See the GNU General Public License for more details. | |
12 | |
13 You should have received a copy of the GNU General Public License | |
14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
15 | |
16 /** Screen: SDL & OpenGL setup/cleanup, drawing. | |
17 * | |
18 * Has an interface by which other code can hook in for drawing and resize notifications. */ | |
19 module mde.setup.Screen; | |
20 | |
21 import mde.setup.exception; | |
22 import mde.lookup.Options; | |
23 import imde = mde.imde; | |
24 debug (drawGlyphCache) import mde.font.font; | |
25 | |
26 import tango.util.log.Log : Log, Logger; | |
27 import tango.stdc.stringz; | |
28 import tango.time.Time; // TimeSpan (type only; unused) | |
29 | |
30 import derelict.sdl.sdl; | |
31 import derelict.opengl.gl; // for loading a later gl version | |
32 import derelict.util.exception; | |
33 | |
34 /** Currently just used as a namespace. Potential for multiple screen support later? */ | |
35 struct Screen { | |
36 // TYPES (these mustn't be static): | |
37 /** Interface for anything hooking into the screen for drawing, etc. */ | |
38 interface Drawable { | |
39 /** Called on window creation and whenever the window manager resizes the window, before | |
40 * the new size is set. The new size is passed. | |
41 * | |
42 * The parameters were passed as ref to allow the called function to change them, but SDL | |
43 * didn't appear able to resize the window (on X11), so this was dropped. */ | |
44 void sizeEvent (int w, int h); | |
45 | |
46 /** Called you guess when :-) */ | |
47 void draw (); | |
48 } | |
49 | |
50 /** All video options. */ | |
51 class OptionsVideo : Options { | |
52 mixin (impl!("bool fullscreen,hardware,resizable,noFrame; int screenW,screenH,windowW,windowH;")); | |
53 } | |
54 | |
55 static: | |
56 /** Init function to initialize SDL. */ | |
57 StageState init () { // init func | |
58 // Initialise SDL | |
59 if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK /+| SDL_INIT_EVENTTHREAD+/)) { | |
60 logger.fatal ("SDL initialisation failed:"); | |
61 char* msg = SDL_GetError (); | |
62 logger.fatal (msg ? fromStringz(msg) : "no reason available"); | |
63 | |
64 throw new InitException ("SDL Initialization failed"); | |
65 } | |
66 debug logger.trace ("SDL initialised"); | |
67 return StageState.ACTIVE; | |
68 } | |
69 /** SDL shutdown */ | |
70 StageState cleanup () { | |
71 SDL_Quit(); | |
72 return StageState.INACTIVE; | |
73 } | |
74 /** Init function to set up a window with OpenGL support. */ | |
75 StageState initWindow () { | |
76 //BEGIN Create window and initialize OpenGL | |
77 // Window creation flags and size | |
78 flags = SDL_OPENGL; | |
79 if (vidOpts.hardware) flags |= SDL_HWSURFACE | SDL_DOUBLEBUF; | |
80 else flags |= SDL_SWSURFACE; | |
81 int w, h; | |
82 if (vidOpts.fullscreen) { | |
83 flags |= SDL_FULLSCREEN; | |
84 w = vidOpts.screenW; | |
85 h = vidOpts.screenH; | |
86 } | |
87 else { | |
88 if (vidOpts.resizable) flags |= SDL_RESIZABLE; | |
89 if (vidOpts.noFrame) flags |= SDL_NOFRAME; | |
90 w = vidOpts.windowW; | |
91 h = vidOpts.windowH; | |
92 } | |
93 | |
94 // OpenGL attributes | |
95 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); | |
96 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); | |
97 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); | |
98 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); | |
99 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); | |
100 | |
101 // Open a window | |
102 debug logger.trace ("Opening a window (this can crash if the libraries are messed up)"); | |
103 if (setWindow (w, h)) { | |
104 throw new InitException ("Failed to open a window"); | |
105 } | |
106 | |
107 /* Now (must be done after GL context is created) we can try to load later version. | |
108 * The initial loading provides opengl 1.1 features. | |
109 * | |
110 * 1.4 is now used for glBlendColor (coloured text). | |
111 * | |
112 * Currently the latest version used is 1.3; adjust this as necessary. However, before using | |
113 * features from any OpenGL version > 1.1 a check must be made on what was loaded by calling | |
114 * DerelictGL.availableVersion(). Note that availableVersion() could be used instead to load | |
115 * the highest supported version but this way we know what we're getting. */ | |
116 if (DerelictGL.availableVersion < GLVersion.Version13) { | |
117 throw new InitException ("Required at least OpenGL 1.3; didn't get this."); | |
118 } | |
119 /+try { | |
120 DerelictGL.loadVersions(GLVersion.Version14); | |
121 } catch (SharedLibProcLoadException e) { | |
122 logger.warn ("Loading OpenGL version 1.4 failed:"); | |
123 logger.warn (e.msg); | |
124 | |
125 setInitFailure (); | |
126 return; | |
127 }+/ | |
128 | |
129 // OpenGL stuff: | |
130 glDisable(GL_LIGHTING); | |
131 glDisable(GL_DEPTH_TEST); | |
132 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); | |
133 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); | |
134 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
135 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
136 glEnable(GL_TEXTURE_2D); | |
137 glShadeModel(GL_SMOOTH); | |
138 | |
139 glClearColor (0.0f, 0.0f, 0.0f, 0.0f); | |
140 | |
141 glMatrixMode(GL_MODELVIEW); | |
142 glLoadIdentity(); | |
143 | |
144 // Used for font rendering: | |
145 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
146 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
147 //NOTE: wrap mode may have an effect, but shouldn't be noticed... | |
148 | |
149 // Window-manager settings | |
150 SDL_WM_SetCaption (toStringz ("mde"), null); | |
151 // SDL_WM_GrabInput (use later) | |
152 //END Create window and initialize OpenGL | |
153 return StageState.ACTIVE; | |
154 } | |
155 | |
156 | |
157 /** Called when a resize event occurs (when the window manager resizes the window). */ | |
158 void resizeEvent (int w, int h) { | |
159 // Save new size to config | |
160 if (vidOpts.fullscreen) { // probably resizeEvent only called when not fullscreen | |
161 vidOpts.set!(int) ("screenW", w); | |
162 vidOpts.set!(int) ("screenH", h); | |
163 } else { | |
164 vidOpts.set!(int) ("windowW", w); | |
165 vidOpts.set!(int) ("windowH", h); | |
166 } | |
167 | |
168 if (setWindow (w,h)) | |
169 imde.run = false; | |
170 } | |
171 | |
172 /** Add a drawable element to the screen (see Drawable interface). | |
173 * | |
174 * Should be called before Init to get initial size. Currently no means to remove drawables, | |
175 * and not really designed for more than one. */ | |
176 void addDrawable (Drawable d) { | |
177 drawables ~= d; | |
178 } | |
179 | |
180 /** Drawing function */ | |
181 void draw (TimeSpan) { | |
182 glClear(GL_COLOR_BUFFER_BIT); | |
183 | |
184 foreach (Drawable d; drawables) | |
185 d.draw; | |
186 | |
187 debug (drawGlyphCache) { | |
188 logger.trace ("Drawing font texture"); | |
189 FontStyle.drawTexture; | |
190 } | |
191 | |
192 // Error check: | |
193 GLenum err = glGetError(); | |
194 while (err != GL_NO_ERROR) { | |
195 logger.error ("GL error: {}", err); | |
196 err = glGetError(); | |
197 } | |
198 | |
199 glFinish(); // Use Finish rather than Flush to make sure gl is ready to swap buffers | |
200 SDL_GL_SwapBuffers(); | |
201 } | |
202 | |
203 /** Set a new window size. Returns true on failure due to the different ways this must be | |
204 * handled. */ | |
205 private bool setWindow (int w, int h) { | |
206 foreach (d; drawables) // Tell all drawables the new window size. | |
207 d.sizeEvent (w,h); | |
208 | |
209 debug logger.trace ("Setting video mode {}x{}, 32-bit, flags: {}", w,h,flags); | |
210 if (SDL_SetVideoMode (w, h, 32, flags) is null) { | |
211 logger.fatal ("Unable to set video mode:"); | |
212 char* msg = SDL_GetError (); | |
213 logger.fatal (msg ? fromStringz(msg) : "no reason available"); | |
214 | |
215 // Print a load of info: | |
216 logger.info ("Available video modes:"); | |
217 SDL_Rect** modes = SDL_ListModes (null, SDL_FULLSCREEN); | |
218 if (modes is null) logger.info ("None!"); | |
219 else if (modes is cast(SDL_Rect**) -1) logger.info ("All modes are available"); | |
220 else { | |
221 for (uint i = 0; modes[i] !is null; ++i) { | |
222 logger.info ("\t{}x{}", modes[i].w, modes[i].h); | |
223 } | |
224 } | |
225 | |
226 SDL_VideoInfo* vi = SDL_GetVideoInfo (); | |
227 if (vi !is null) { | |
228 logger.info ("Video info:"); | |
229 logger.info ("Hardware surface support: "~ (vi.flags & SDL_HWSURFACE ? "yes" : "no")); | |
230 logger.info ("Video memory: {}", vi.video_mem); | |
231 | |
232 if (vi.vfmt !is null) { | |
233 logger.info ("Best video mode:"); | |
234 logger.info ("Bits per pixel: {}", vi.vfmt.BitsPerPixel); | |
235 } | |
236 } | |
237 | |
238 return true; | |
239 } | |
240 | |
241 // Reset the projection and viewport | |
242 glMatrixMode (GL_PROJECTION); | |
243 glLoadIdentity (); | |
244 | |
245 glViewport (0,0,w,h); | |
246 | |
247 // Make the top-left the origin (see gui/GUI notes.txt): | |
248 // Note that this only affects vertex operations − direct rasterisation operations are | |
249 // unaffected! | |
250 glOrtho (0.0,w, h,0.0, -1.0, 1.0); | |
251 | |
252 glMatrixMode(GL_MODELVIEW); | |
253 return false; | |
254 } | |
255 | |
256 static this() { | |
257 logger = Log.getLogger ("mde.setup.Screen"); | |
258 | |
259 vidOpts = new OptionsVideo; | |
260 Options.addOptionsClass (vidOpts, "video"); | |
261 } | |
262 | |
263 // DATA: | |
264 private: | |
265 uint flags = 0; | |
266 Drawable[] drawables; | |
267 Logger logger; | |
268 OptionsVideo vidOpts; | |
269 } |