Graphics library for Mercury, including OpenGL bindings, TGA image reading, and X11, Win32, and SDL2 windowing and input.
リビジョン | 26403b7ea308694b661777edacfef806d318d7a3 (tree) |
---|---|
日時 | 2022-03-14 14:08:38 |
作者 | AlaskanEmily <emily@alas...> |
コミッター | AlaskanEmily |
Add OpenGL buffer function bindings
@@ -36,6 +36,15 @@ | ||
36 | 36 | :- mode vertex(muo, muo, muo, muo) = (mdi) is det. |
37 | 37 | :- mode vertex(in, in, in, in) = (in) is semidet. % Implied. |
38 | 38 | |
39 | +:- pred vertex(float, float, float, float, vertex2d). | |
40 | +:- mode vertex(in, in, in, in, out) is det. | |
41 | +:- mode vertex(di, di, di, di, uo) is det. | |
42 | +:- mode vertex(mdi, mdi, mdi, mdi, muo) is det. | |
43 | +:- mode vertex(out, out, out, out, in) is det. | |
44 | +:- mode vertex(uo, uo, uo, uo, di) is det. | |
45 | +:- mode vertex(muo, muo, muo, muo, mdi) is det. | |
46 | +:- mode vertex(in, in, in, in, in) is semidet. % Implied. | |
47 | + | |
39 | 48 | %-----------------------------------------------------------------------------% |
40 | 49 | % This is intended to be used as if it was a functor for vertex, to construct |
41 | 50 | % or destructure the vector so that the vector's fields appear directly in the |
@@ -49,6 +58,15 @@ | ||
49 | 58 | :- mode vertex(muo, muo, muo, muo, muo) = (mdi) is det. |
50 | 59 | :- mode vertex(in, in, in, in, in) = (in) is semidet. % Implied. |
51 | 60 | |
61 | +:- pred vertex(float, float, float, float, float, vertex3d). | |
62 | +:- mode vertex(in, in, in, in, in, out) is det. | |
63 | +:- mode vertex(di, di, di, di, di, uo) is det. | |
64 | +:- mode vertex(mdi, mdi, mdi, mdi, mdi, muo) is det. | |
65 | +:- mode vertex(out, out, out, out, out, in) is det. | |
66 | +:- mode vertex(uo, uo, uo, uo, uo, di) is det. | |
67 | +:- mode vertex(muo, muo, muo, muo, muo, mdi) is det. | |
68 | +:- mode vertex(in, in, in, in, in, in) is semidet. % Implied. | |
69 | + | |
52 | 70 | %-----------------------------------------------------------------------------% |
53 | 71 | |
54 | 72 | :- type primitive_type ---> |
@@ -174,11 +192,37 @@ | ||
174 | 192 | |
175 | 193 | %-----------------------------------------------------------------------------% |
176 | 194 | |
195 | +:- pragma foreign_export("C", | |
196 | + vertex(in, in, in, in) = (out), | |
197 | + "SaffronGeometry_CreateVertex2D"). | |
198 | + | |
199 | +%-----------------------------------------------------------------------------% | |
200 | + | |
201 | +:- pragma foreign_export("C", | |
202 | + vertex(out, out, out, out, in), | |
203 | + "SaffronGeometry_GetVertex2D"). | |
204 | + | |
205 | +%-----------------------------------------------------------------------------% | |
206 | + | |
207 | +:- pragma foreign_export("C", | |
208 | + vertex(in, in, in, in, in) = (out), | |
209 | + "SaffronGeometry_CreateVertex3D"). | |
210 | + | |
211 | +%-----------------------------------------------------------------------------% | |
212 | + | |
213 | +:- pragma foreign_export("C", | |
214 | + vertex(out, out, out, out, out, in), | |
215 | + "SaffronGeometry_GetVertex3D"). | |
216 | + | |
217 | +%-----------------------------------------------------------------------------% | |
218 | + | |
177 | 219 | vertex(X, Y, U, V) = vertex(vector.vector2.vector(X, Y), U, V). |
220 | +vertex(X, Y, U, V, vertex(vector.vector2.vector(X, Y), U, V)). | |
178 | 221 | |
179 | 222 | %-----------------------------------------------------------------------------% |
180 | 223 | |
181 | 224 | vertex(X, Y, Z, U, V) = vertex(vector.vector3.vector(X, Y, Z), U, V). |
225 | +vertex(X, Y, Z, U, V, vertex(vector.vector3.vector(X, Y, Z), U, V)). | |
182 | 226 | |
183 | 227 | %-----------------------------------------------------------------------------% |
184 | 228 |
@@ -19,6 +19,11 @@ | ||
19 | 19 | :- interface. |
20 | 20 | %=============================================================================% |
21 | 21 | |
22 | +:- use_module array. | |
23 | +:- use_module list. | |
24 | + | |
25 | +:- use_module saffron.geometry. | |
26 | + | |
22 | 27 | %-----------------------------------------------------------------------------% |
23 | 28 | % The function pointers to let us create buffers. |
24 | 29 | :- type buffer_ctx. |
@@ -39,11 +44,68 @@ | ||
39 | 44 | <= saffron.gl.context(Ctx). |
40 | 45 | :- mode create_buffer_ctx(in, out, di, uo) is det. |
41 | 46 | |
47 | +%-----------------------------------------------------------------------------% | |
48 | + | |
49 | +:- pred destroy_buffer(buffer_ctx::in, buffer::in, io.io::di, io.io::uo) is det. | |
50 | + | |
51 | +%-----------------------------------------------------------------------------% | |
52 | + | |
53 | +:- pred create_buffer(buffer_ctx::in, buffer::uo, io.io::di, io.io::uo) is det. | |
54 | + | |
55 | +%-----------------------------------------------------------------------------% | |
56 | + | |
57 | +:- instance saffron.destroy(buffer_ctx, buffer). | |
58 | + | |
59 | +%-----------------------------------------------------------------------------% | |
60 | + | |
61 | +:- pred bind_buffer(buffer_ctx, buffer, buffer_type, io.io, io.io). | |
62 | +:- mode bind_buffer(in, in, in, di, uo) is det. | |
63 | + | |
64 | +%-----------------------------------------------------------------------------% | |
65 | + | |
66 | +:- type buffer_data(T) == (pred(buffer_ctx, buffer_type, T, io.io, io.io)). | |
67 | +:- inst buffer_data == (pred(in, in, in, di, uo) is det). | |
68 | + | |
69 | +:- pred buffer_data_float_array | |
70 | + `with_type` buffer_data(array.array(float)) | |
71 | + `with_inst` buffer_data. | |
72 | + | |
73 | +:- pred buffer_data_float_list | |
74 | + `with_type` buffer_data(list.list(float)) | |
75 | + `with_inst` buffer_data. | |
76 | + | |
77 | +:- pred buffer_data_int_array | |
78 | + `with_type` buffer_data(array.array(int)) | |
79 | + `with_inst` buffer_data. | |
80 | + | |
81 | +:- pred buffer_data_int_list | |
82 | + `with_type` buffer_data(list.list(int)) | |
83 | + `with_inst` buffer_data. | |
84 | + | |
85 | +:- pred buffer_data_vertex2d_array | |
86 | + `with_type` buffer_data(array.array(saffron.geometry.vertex2d)) | |
87 | + `with_inst` buffer_data. | |
88 | + | |
89 | +:- pred buffer_data_vertex2d_list | |
90 | + `with_type` buffer_data(list.list(saffron.geometry.vertex2d)) | |
91 | + `with_inst` buffer_data. | |
92 | + | |
93 | +:- pred buffer_data_vertex3d_array | |
94 | + `with_type` buffer_data(array.array(saffron.geometry.vertex3d)) | |
95 | + `with_inst` buffer_data. | |
96 | + | |
97 | +:- pred buffer_data_vertex3d_list | |
98 | + `with_type` buffer_data(list.list(saffron.geometry.vertex3d)) | |
99 | + `with_inst` buffer_data. | |
100 | + | |
42 | 101 | %=============================================================================% |
43 | 102 | :- implementation. |
44 | 103 | %=============================================================================% |
45 | 104 | |
46 | -:- use_module array. | |
105 | +:- use_module vector. | |
106 | +:- use_module vector.vector2. | |
107 | +:- use_module vector.vector3. | |
108 | + | |
47 | 109 | :- pragma foreign_import_module("C", saffron.gl). |
48 | 110 | |
49 | 111 | % Define the native prototypes to handle buffers. |
@@ -256,7 +318,6 @@ saffron_gl_create_buffer_ctx_internal: | ||
256 | 318 | IOo = IOi; |
257 | 319 | "). |
258 | 320 | |
259 | - | |
260 | 321 | %-----------------------------------------------------------------------------% |
261 | 322 | |
262 | 323 | create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :- |
@@ -283,4 +344,235 @@ create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :- | ||
283 | 344 | LoadFuncCtx = 'new gl_load_func_ctx'(Ctx), |
284 | 345 | create_buffer_ctx_internal(LoadFuncCtx, Old, MaybeBufferCtx, !IO). |
285 | 346 | |
347 | +%-----------------------------------------------------------------------------% | |
348 | + | |
349 | +:- pragma foreign_proc("C", | |
350 | + create_buffer(Ctx::in, Buffer::uo, IOi::di, IOo::uo), | |
351 | + [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
352 | + tabled_for_io, may_duplicate, does_not_affect_liveness], | |
353 | + " | |
354 | + GLuint b; | |
355 | + SAFFRON_GL_BUFFER_FUNC(Ctx, GenBuffers)(1, &b); | |
356 | + Buffer = b; | |
357 | + IOo = IOi; | |
358 | + "). | |
359 | + | |
360 | +%-----------------------------------------------------------------------------% | |
361 | + | |
362 | +:- pragma foreign_proc("C", | |
363 | + destroy_buffer(Ctx::in, Buffer::in, IOi::di, IOo::uo), | |
364 | + [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
365 | + tabled_for_io, may_duplicate, does_not_affect_liveness], | |
366 | + " | |
367 | + GLuint b = Buffer; | |
368 | + SAFFRON_GL_BUFFER_FUNC(Ctx, DeleteBuffers)(1, &b); | |
369 | + IOo = IOi; | |
370 | + "). | |
371 | + | |
372 | +%-----------------------------------------------------------------------------% | |
373 | + | |
374 | +:- instance saffron.destroy(buffer_ctx, buffer) where [ | |
375 | + pred(saffron.destroy/4) is saffron.gl.buffer.destroy_buffer | |
376 | +]. | |
377 | + | |
378 | +%-----------------------------------------------------------------------------% | |
379 | + | |
380 | +:- pragma foreign_proc("C", | |
381 | + bind_buffer(Ctx::in, Buffer::in, Type::in, IOi::di, IOo::uo), | |
382 | + [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
383 | + may_duplicate, does_not_affect_liveness], | |
384 | + " | |
385 | + SAFFRON_GL_BUFFER_FUNC(Ctx, BindBuffer)(Type, Buffer); | |
386 | + IOo = IOi; | |
387 | + "). | |
388 | + | |
389 | +%-----------------------------------------------------------------------------% | |
390 | + | |
391 | +:- pragma foreign_proc("C", | |
392 | + buffer_data_float_array(Ctx::in, Type::in, T::in, IOi::di, IOo::uo), | |
393 | + [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
394 | + may_duplicate, does_not_affect_liveness], | |
395 | + " | |
396 | + const MR_Integer len = T->size; | |
397 | + MR_Float *array; | |
398 | +#ifdef MR_UNBOXED_FLOAT | |
399 | + array = (void*)(T->elements); | |
400 | +#else | |
401 | + MR_Integer i; | |
402 | + | |
403 | + /* Attempt to avoid allocations if necessary. */ | |
404 | + MR_Float small_array[32]; | |
405 | + const int do_alloc = (len >= sizeof(small_array) / sizeof(MR_Float)); | |
406 | + array = (do_alloc) ? MR_malloc(sizeof(MR_Float) * len) : small_array; | |
407 | + | |
408 | + /* Copy the data. */ | |
409 | + for(i = 0; i < len; i++){ | |
410 | + array[i] = MR_word_to_float(T->elements[i]); | |
411 | + } | |
412 | +#endif | |
413 | + | |
414 | + SAFFRON_GL_BUFFER_FUNC(Ctx, BufferData)( | |
415 | + Type, | |
416 | + sizeof(MR_Float) * len, | |
417 | + array, | |
418 | + GL_STATIC_DRAW); | |
419 | + | |
420 | +#ifndef MR_UNBOXED_FLOAT | |
421 | + if(do_alloc) | |
422 | + MR_free(array); | |
423 | +#endif | |
424 | + IOo = IOi; | |
425 | + "). | |
426 | + | |
427 | +%-----------------------------------------------------------------------------% | |
428 | + | |
429 | +:- pragma foreign_proc("C", | |
430 | + buffer_data_int_array(Ctx::in, Type::in, T::in, IOi::di, IOo::uo), | |
431 | + [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
432 | + may_duplicate, does_not_affect_liveness], | |
433 | + " | |
434 | + /* MR_Integer is guaranteed to be unboxed. */ | |
435 | + SAFFRON_GL_BUFFER_FUNC(Ctx, BufferData)( | |
436 | + Type, | |
437 | + sizeof(MR_Integer) * T->size, | |
438 | + T->elements, | |
439 | + GL_STATIC_DRAW); | |
440 | + IOo = IOi; | |
441 | + "). | |
442 | + | |
443 | +%-----------------------------------------------------------------------------% | |
444 | +% TODO: This should work, and is optimal when we have unboxed floats, but | |
445 | +% we should eventually implement a better C version for when we have boxed | |
446 | +% floats. | |
447 | +buffer_data_float_list(Ctx, Type, List, !IO) :- | |
448 | + buffer_data_float_array(Ctx, Type, array.from_list(List), !IO). | |
449 | + | |
450 | +%-----------------------------------------------------------------------------% | |
451 | +% As integers are always unboxed, this actually is optimal. | |
452 | +buffer_data_int_list(Ctx, Type, List, !IO) :- | |
453 | + buffer_data_int_array(Ctx, Type, array.from_list(List), !IO). | |
454 | + | |
455 | +%-----------------------------------------------------------------------------% | |
456 | + | |
457 | +:- pragma foreign_proc("C", | |
458 | + buffer_data_vertex2d_array(Ctx::in, Type::in, T::in, IOi::di, IOo::uo), | |
459 | + [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
460 | + may_duplicate], | |
461 | + " | |
462 | + MR_Word X, Y, U, V; | |
463 | + const MR_Integer len = T->size; | |
464 | + const MR_Integer buffer_size = len * sizeof(MR_Float) * 4; | |
465 | + MR_Float *const buffer = MR_malloc(buffer_size); | |
466 | + MR_Integer i; | |
467 | + | |
468 | + for(i = 0; i < len; i++){ | |
469 | + SaffronGeometry_GetVertex2D(&X, &Y, &U, &V, T->elements[i]); | |
470 | + buffer[(i * 4) + 0] = MR_word_to_float(X); | |
471 | + buffer[(i * 4) + 1] = MR_word_to_float(Y); | |
472 | + buffer[(i * 4) + 2] = MR_word_to_float(U); | |
473 | + buffer[(i * 4) + 3] = MR_word_to_float(V); | |
474 | + } | |
475 | + | |
476 | + SAFFRON_GL_BUFFER_FUNC(Ctx, BufferData)( | |
477 | + Type, | |
478 | + buffer_size, | |
479 | + buffer, | |
480 | + GL_STATIC_DRAW); | |
481 | + MR_free(buffer); | |
482 | + IOo = IOi; | |
483 | + "). | |
484 | + | |
485 | +:- pragma foreign_proc("C", | |
486 | + buffer_data_vertex2d_list(Ctx::in, Type::in, T::in, IOi::di, IOo::uo), | |
487 | + [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
488 | + may_duplicate], | |
489 | + " | |
490 | + MR_Word X, Y, U, V; | |
491 | + MR_Integer i = 0, alloc_size = 32; | |
492 | + MR_Float *buffer = MR_malloc(alloc_size * sizeof(MR_Float)); | |
493 | + | |
494 | + while(!MR_list_is_empty(T)){ | |
495 | + SaffronGeometry_GetVertex2D(&X, &Y, &U, &V, MR_list_head(T)); | |
496 | + T = MR_list_tail(T); | |
497 | + if(i + 5 >= alloc_size){ | |
498 | + alloc_size <<= 1; | |
499 | + buffer = MR_realloc(buffer, alloc_size * sizeof(MR_Float)); | |
500 | + } | |
501 | + buffer[i++] = MR_word_to_float(X); | |
502 | + buffer[i++] = MR_word_to_float(Y); | |
503 | + buffer[i++] = MR_word_to_float(U); | |
504 | + buffer[i++] = MR_word_to_float(V); | |
505 | + | |
506 | + } | |
507 | + SAFFRON_GL_BUFFER_FUNC(Ctx, BufferData)( | |
508 | + Type, | |
509 | + i * sizeof(MR_Float), | |
510 | + buffer, | |
511 | + GL_STATIC_DRAW); | |
512 | + MR_free(buffer); | |
513 | + IOo = IOi; | |
514 | + "). | |
515 | + | |
516 | +%-----------------------------------------------------------------------------% | |
517 | + | |
518 | +:- pragma foreign_proc("C", | |
519 | + buffer_data_vertex3d_array(Ctx::in, Type::in, T::in, IOi::di, IOo::uo), | |
520 | + [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
521 | + may_duplicate], | |
522 | + " | |
523 | + MR_Word X, Y, Z, U, V; | |
524 | + const MR_Integer len = T->size; | |
525 | + const MR_Integer buffer_size = len * sizeof(MR_Float) * 5; | |
526 | + MR_Float *const buffer = MR_malloc(buffer_size); | |
527 | + MR_Integer i; | |
528 | + | |
529 | + for(i = 0; i < len; i++){ | |
530 | + SaffronGeometry_GetVertex3D(&X, &Y, &Z, &U, &V, T->elements[i]); | |
531 | + buffer[(i * 5) + 0] = MR_word_to_float(X); | |
532 | + buffer[(i * 5) + 1] = MR_word_to_float(Y); | |
533 | + buffer[(i * 5) + 2] = MR_word_to_float(Z); | |
534 | + buffer[(i * 5) + 3] = MR_word_to_float(U); | |
535 | + buffer[(i * 5) + 4] = MR_word_to_float(V); | |
536 | + } | |
537 | + | |
538 | + SAFFRON_GL_BUFFER_FUNC(Ctx, BufferData)( | |
539 | + Type, | |
540 | + buffer_size, | |
541 | + buffer, | |
542 | + GL_STATIC_DRAW); | |
543 | + MR_free(buffer); | |
544 | + IOo = IOi; | |
545 | + "). | |
546 | + | |
547 | +:- pragma foreign_proc("C", | |
548 | + buffer_data_vertex3d_list(Ctx::in, Type::in, T::in, IOi::di, IOo::uo), | |
549 | + [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception, | |
550 | + may_duplicate], | |
551 | + " | |
552 | + MR_Word X, Y, Z, U, V; | |
553 | + MR_Integer i = 0, alloc_size = 32; | |
554 | + MR_Float *buffer = MR_malloc(alloc_size * sizeof(MR_Float)); | |
555 | + | |
556 | + while(!MR_list_is_empty(T)){ | |
557 | + SaffronGeometry_GetVertex3D(&X, &Y, &Z, &U, &V, MR_list_head(T)); | |
558 | + T = MR_list_tail(T); | |
559 | + if(i + 5 >= alloc_size){ | |
560 | + alloc_size <<= 1; | |
561 | + buffer = MR_realloc(buffer, alloc_size * sizeof(MR_Float)); | |
562 | + } | |
563 | + buffer[i++] = MR_word_to_float(X); | |
564 | + buffer[i++] = MR_word_to_float(Y); | |
565 | + buffer[i++] = MR_word_to_float(Z); | |
566 | + buffer[i++] = MR_word_to_float(U); | |
567 | + buffer[i++] = MR_word_to_float(V); | |
568 | + | |
569 | + } | |
570 | + SAFFRON_GL_BUFFER_FUNC(Ctx, BufferData)( | |
571 | + Type, | |
572 | + i * sizeof(MR_Float), | |
573 | + buffer, | |
574 | + GL_STATIC_DRAW); | |
575 | + MR_free(buffer); | |
576 | + IOo = IOi; | |
577 | + "). | |
286 | 578 |