Graphics library for Mercury, including OpenGL bindings, TGA image reading, and X11, Win32, and SDL2 windowing and input.
リビジョン | 4e6c5240a2e1bc4f3cdfa265efc31e302364d2a9 (tree) |
---|---|
日時 | 2022-04-01 11:53:57 |
作者 | AlaskanEmily <emily@alas...> |
コミッター | AlaskanEmily |
Handle Glow failures
@@ -238,81 +238,98 @@ cube_geometry = [ | ||
238 | 238 | main(!IO) :- |
239 | 239 | % Load the demo image |
240 | 240 | saffron_tga.load_path("res/crate.tga", ImageResult, !IO), |
241 | + | |
242 | + % The Mercury compiler is smart enough to see that the error branch will | |
243 | + % throw, and will unify the result outside that disjunction. | |
241 | 244 | ( |
242 | 245 | ImageResult = io.error(Err), |
243 | 246 | exception.throw(exception.software_error(io.error_message(Err))) |
244 | 247 | ; |
245 | - ImageResult = io.ok({BMP, TexW, TexH}), | |
246 | - | |
247 | - W = 640, | |
248 | - H = 480, | |
249 | - Title = "Saffron Cube Demo", | |
250 | - | |
251 | - % Create the window and OpenGL context | |
252 | - saffron_glow.viewport_size(W, H, WinW, WinH), | |
253 | - saffron_glow.create_window(WinW, WinH, Title, Win, !IO), | |
254 | - saffron_glow.create_context(Win, 1, 3, GlowCtx, !IO), | |
255 | - | |
256 | - % Show the window. | |
257 | - % Depending on the Glow backend, this *might* need to happen after | |
258 | - % creating the OpenGL context. | |
259 | - saffron_glow.show_window(Win, !IO), | |
260 | - | |
261 | - % Using the backend-specific type is what determines what backend we | |
262 | - % will use. | |
263 | - saffron.gl2.init(GlowCtx, Ctx, !IO), | |
264 | - | |
265 | - saffron.gl.shader_model_version_string(Ctx, VersionString, !IO), | |
266 | - io.write_string("GLSL Version: ", !IO), | |
267 | - io.write_string(VersionString, !IO), | |
268 | - io.nl(!IO), | |
269 | - | |
270 | - % Set the ortho mode | |
271 | - AR = float(W) / float(H), | |
272 | - | |
273 | - Matrix = matrix.ortho(-AR, AR, 1.0, -1.0, -1000.0, 1000.0), | |
274 | - saffron.draw.set_matrix(Ctx, Matrix, !IO), | |
275 | - | |
276 | - saffron.draw.transform(Ctx, matrix.scale(0.4, 0.4, 0.4), !IO), | |
277 | - | |
278 | - % foo(!IO), | |
279 | - | |
280 | - % Upload the image to create a texture. | |
281 | - saffron.gl.create_texture_from_bitmap(Ctx, BMP, TexW, TexH, Texture, !IO), | |
282 | - Faces = cube_geometry, | |
283 | - | |
284 | - % Upload geometry to buffers. | |
285 | - % Most programs would probably want to use index buffers for a shape | |
286 | - % like this with mostly shared geometry. | |
287 | - list.map_foldl( | |
288 | - saffron.geometry.create_buffer_list(Ctx), | |
289 | - % list.map(list.reverse, Faces), FaceBuffers, | |
290 | - Faces, FaceBuffers, | |
291 | - !IO), | |
292 | - | |
293 | - % Construct the faces. | |
294 | - % This *could* be done as one large, wound shape, but a majority of | |
295 | - % programs will be loading meshes that will contain individual hulls/ | |
296 | - % faces that will need to be constructed in this way. | |
297 | - list.map_foldl( | |
298 | - saffron.geometry.create_shape2(Ctx, saffron.geometry.triangle_strip, Texture), | |
299 | - FaceBuffers, Shapes, | |
300 | - !IO), | |
301 | - | |
302 | - % Construct the shape. | |
303 | - saffron.draw.create_group_list(Ctx, Shapes, Group, !IO), | |
304 | - | |
305 | - % Run the engine. | |
306 | - run(Ctx, Win, Group, !IO), | |
307 | - | |
308 | - % Cleanup | |
309 | - saffron.destroy(Ctx, Group, !IO), | |
310 | - list.foldl(saffron.destroy(Ctx), Shapes, !IO), | |
311 | - list.foldl(saffron.destroy(Ctx), FaceBuffers, !IO), | |
312 | - saffron.destroy(Ctx, Texture, !IO), | |
313 | - | |
314 | - % The window and context will be garbage-collected? | |
315 | - % I wrote the bindings years ago, I don't remember the intention :( | |
316 | - saffron_glow.hide_window(Win, !IO) | |
317 | - ). | |
248 | + ImageResult = io.ok({BMP, TexW, TexH}) | |
249 | + ), | |
250 | + W = 640, | |
251 | + H = 480, | |
252 | + Title = "Saffron Cube Demo", | |
253 | + | |
254 | + % Create the window and OpenGL context | |
255 | + saffron_glow.viewport_size(W, H, WinW, WinH), | |
256 | + saffron_glow.create_window(WinW, WinH, Title, WinRes, !IO), | |
257 | + ( | |
258 | + WinRes = io.error(Err), | |
259 | + exception.throw(exception.software_error(io.error_message(Err))) | |
260 | + ; | |
261 | + WinRes = io.ok(Win) | |
262 | + ), | |
263 | + saffron_glow.create_context(Win, 1, 3, GlowCtxRes, !IO), | |
264 | + ( | |
265 | + GlowCtxRes = io.error(Err), | |
266 | + exception.throw(exception.software_error(io.error_message(Err))) | |
267 | + ; | |
268 | + GlowCtxRes = io.ok(GlowCtx) | |
269 | + ), | |
270 | + | |
271 | + % Show the window. | |
272 | + % Depending on the Glow backend, this *might* need to happen after creating | |
273 | + % the OpenGL context, but not necessarily. | |
274 | + saffron_glow.show_window(Win, !IO), | |
275 | + | |
276 | + % Using the backend-specific type is what determines what backend Glow is | |
277 | + % using. | |
278 | + saffron.gl2.init(GlowCtx, Ctx, !IO), | |
279 | + | |
280 | + saffron.gl.opengl_version_string(Ctx, GLVersion, !IO), | |
281 | + io.write_string("OpenGL Version: ", !IO), | |
282 | + io.write_string(GLVersion, !IO), | |
283 | + io.nl(!IO), | |
284 | + | |
285 | + saffron.gl.shader_model_version_string(Ctx, GLSLVersion, !IO), | |
286 | + io.write_string("GLSL Version: ", !IO), | |
287 | + io.write_string(GLSLVersion, !IO), | |
288 | + io.nl(!IO), | |
289 | + | |
290 | + % Set the ortho mode | |
291 | + AR = float(W) / float(H), | |
292 | + | |
293 | + Matrix = matrix.ortho(-AR, AR, 1.0, -1.0, -1000.0, 1000.0), | |
294 | + saffron.draw.set_matrix(Ctx, Matrix, !IO), | |
295 | + | |
296 | + saffron.draw.transform(Ctx, matrix.scale(0.4, 0.4, 0.4), !IO), | |
297 | + | |
298 | + % Upload the image to create a texture. | |
299 | + saffron.gl.create_texture_from_bitmap(Ctx, BMP, TexW, TexH, Texture, !IO), | |
300 | + Faces = cube_geometry, | |
301 | + | |
302 | + % Upload geometry to buffers. | |
303 | + % Most programs would probably want to use index buffers for a shape like | |
304 | + % this with mostly shared geometry. | |
305 | + list.map_foldl( | |
306 | + saffron.geometry.create_buffer_list(Ctx), | |
307 | + Faces, FaceBuffers, | |
308 | + !IO), | |
309 | + | |
310 | + % Construct the faces. | |
311 | + % This *could* be done as one large, wound shape, but the majority of | |
312 | + % programs will be loading meshes that will contain individual hulls/faces | |
313 | + % that will need to be constructed in this way. | |
314 | + list.map_foldl( | |
315 | + saffron.geometry.create_shape2(Ctx, saffron.geometry.triangle_strip, Texture), | |
316 | + FaceBuffers, | |
317 | + Shapes, | |
318 | + !IO), | |
319 | + | |
320 | + % Construct the shape. | |
321 | + saffron.draw.create_group_list(Ctx, Shapes, Group, !IO), | |
322 | + | |
323 | + % Run the engine. | |
324 | + run(Ctx, Win, Group, !IO), | |
325 | + | |
326 | + % Cleanup | |
327 | + saffron.destroy(Ctx, Group, !IO), | |
328 | + list.foldl(saffron.destroy(Ctx), Shapes, !IO), | |
329 | + list.foldl(saffron.destroy(Ctx), FaceBuffers, !IO), | |
330 | + saffron.destroy(Ctx, Texture, !IO), | |
331 | + | |
332 | + % The window and context will be garbage-collected? | |
333 | + % I wrote the bindings years ago, I don't remember the intention :( | |
334 | + saffron_glow.hide_window(Win, !IO). | |
318 | 335 |
@@ -1 +1 @@ | ||
1 | -Subproject commit 95e81a9a328299d5c8193ec1cd5180bc4e2a015d | |
1 | +Subproject commit e4dad582e2f58b9ae1e55247257c97c25a9f12bb |
@@ -21,6 +21,11 @@ | ||
21 | 21 | |
22 | 22 | %-----------------------------------------------------------------------------% |
23 | 23 | |
24 | +:- inst io_res_uniq == unique(io.ok(unique) ; io.error(ground)). | |
25 | +:- mode io_res_uo == (free >> io_res_uniq). | |
26 | + | |
27 | +%-----------------------------------------------------------------------------% | |
28 | + | |
24 | 29 | :- type window. |
25 | 30 | |
26 | 31 | %-----------------------------------------------------------------------------% |
@@ -32,9 +37,9 @@ | ||
32 | 37 | :- pred viewport_size(int::in, int::in, int::uo, int::uo) is det. |
33 | 38 | |
34 | 39 | %-----------------------------------------------------------------------------% |
35 | -% create_window(Width, Height, Title, Win, !IO) | |
36 | -:- pred create_window(int, int, string, window, io.io, io.io). | |
37 | -:- mode create_window(in, in, in, uo, di, uo) is det. | |
40 | +% create_window(Width, Height, Title, WinRes, !IO) | |
41 | +:- pred create_window(int, int, string, io.res(window), io.io, io.io). | |
42 | +:- mode create_window(in, in, in, io_res_uo, di, uo) is det. | |
38 | 43 | |
39 | 44 | %-----------------------------------------------------------------------------% |
40 | 45 |
@@ -52,9 +57,9 @@ | ||
52 | 57 | :- mode get_window_event(in, uo, di, uo) is det. |
53 | 58 | |
54 | 59 | %-----------------------------------------------------------------------------% |
55 | -% create_context(Win, GLMajor, GLMinor, Ctx, !IO) | |
56 | -:- pred create_context(window, int, int, context, io.io, io.io). | |
57 | -:- mode create_context(in, in, in, uo, di, uo) is det. | |
60 | +% create_context(Win, GLMajor, GLMinor, CtxRes, !IO) | |
61 | +:- pred create_context(window, int, int, io.res(context), io.io, io.io). | |
62 | +:- mode create_context(in, in, in, io_res_uo, di, uo) is det. | |
58 | 63 | |
59 | 64 | %-----------------------------------------------------------------------------% |
60 | 65 |
@@ -197,13 +202,35 @@ SAFFRON_GLOW_SPECIAL_KEY_CASE_EX(GLOW_ ## NAME, SAFFRON_KEY_ ## NAME) | ||
197 | 202 | |
198 | 203 | %-----------------------------------------------------------------------------% |
199 | 204 | |
205 | +:- func create_window_ok(window::di) = (io.res(window)::uo) is det. | |
206 | +create_window_ok(Win) = io.ok(Win). | |
207 | +:- pragma foreign_export("C", | |
208 | + create_window_ok(di) = (uo), | |
209 | + "SaffronGlow_CreateWindowOK"). | |
210 | + | |
211 | +%-----------------------------------------------------------------------------% | |
212 | + | |
213 | +:- func create_window_error = (io.res(window)::io_res_uo) is det. | |
214 | +create_window_error = io.error(io.make_io_error("Could not create Glow window")). | |
215 | +:- pragma foreign_export("C", | |
216 | + create_window_error = (io_res_uo), | |
217 | + "SaffronGlow_CreateWindowError"). | |
218 | + | |
219 | +%-----------------------------------------------------------------------------% | |
220 | + | |
200 | 221 | :- pragma foreign_proc("C", |
201 | - create_window(W::in, H::in, Title::in, Win::uo, IOi::di, IOo::uo), | |
222 | + create_window(W::in, H::in, Title::in, WinRes::io_res_uo, IOi::di, IOo::uo), | |
202 | 223 | [promise_pure, will_not_call_mercury, will_not_throw_exception, thread_safe, |
203 | 224 | tabled_for_io, may_duplicate], |
204 | 225 | " |
205 | - Win = MR_GC_malloc_atomic(Glow_WindowStructSize()); | |
206 | - Glow_CreateWindow(Win, W, H, Title, 0); | |
226 | + struct Glow_Window *win = MR_GC_malloc_atomic(Glow_WindowStructSize()); | |
227 | + if(Glow_CreateWindow(win, W, H, Title, 0) == 0){ | |
228 | + WinRes = SaffronGlow_CreateWindowOK(win); | |
229 | + } | |
230 | + else{ | |
231 | + MR_GC_free(win); | |
232 | + WinRes = SaffronGlow_CreateWindowError(); | |
233 | + } | |
207 | 234 | IOo = IOi; |
208 | 235 | "). |
209 | 236 |
@@ -326,13 +353,37 @@ SAFFRON_GLOW_SPECIAL_KEY_CASE_EX(GLOW_ ## NAME, SAFFRON_KEY_ ## NAME) | ||
326 | 353 | |
327 | 354 | %-----------------------------------------------------------------------------% |
328 | 355 | |
356 | +:- func create_context_ok(context::di) = (io.res(context)::uo) is det. | |
357 | +create_context_ok(Ctx) = io.ok(Ctx). | |
358 | +:- pragma foreign_export("C", | |
359 | + create_context_ok(di) = (uo), | |
360 | + "SaffronGlow_CreateContextOK"). | |
361 | + | |
362 | +%-----------------------------------------------------------------------------% | |
363 | + | |
364 | +:- func create_context_error = (io.res(context)::io_res_uo) is det. | |
365 | +create_context_error = io.error(io.make_io_error("Could not create Glow context")). | |
366 | +:- pragma foreign_export("C", | |
367 | + create_context_error = (io_res_uo), | |
368 | + "SaffronGlow_CreateContextError"). | |
369 | + | |
370 | +%-----------------------------------------------------------------------------% | |
371 | + | |
329 | 372 | :- pragma foreign_proc("C", |
330 | - create_context(Win::in, Major::in, Minor::in, Ctx::uo, IOi::di, IOo::uo), | |
373 | + create_context(Win::in, Major::in, Minor::in, CtxRes::io_res_uo, IOi::di, IOo::uo), | |
331 | 374 | [promise_pure, will_not_call_mercury, will_not_throw_exception, thread_safe, |
332 | 375 | tabled_for_io, may_duplicate], |
333 | 376 | " |
334 | - Ctx = MR_GC_malloc_atomic(Glow_ContextStructSize()); | |
335 | - Glow_CreateContext(Win, NULL, Major, Minor, Ctx); | |
377 | + struct Glow_Context *ctx = | |
378 | + MR_GC_malloc_atomic(Glow_ContextStructSize()); | |
379 | + if(Glow_CreateContext(Win, NULL, Major, Minor, ctx) == 0){ | |
380 | + CtxRes = SaffronGlow_CreateContextOK(ctx); | |
381 | + } | |
382 | + else{ | |
383 | + MR_GC_free(ctx); | |
384 | + CtxRes = SaffronGlow_CreateContextError(); | |
385 | + } | |
386 | + | |
336 | 387 | IOo = IOi; |
337 | 388 | "). |
338 | 389 |