• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Graphics library for Mercury, including OpenGL bindings, TGA image reading, and X11, Win32, and SDL2 windowing and input.


Commit MetaInfo

Revision1d825675170ef4cc80eaf3c9b1b3b174501aae6e (tree)
Time2023-06-30 08:39:39
AuthorAlaskanEmily <emily@alas...>
CommiterAlaskanEmily

Log Message

Add Java support to core and GL components

Change Summary

Incremental Difference

--- a/saffron.geometry.m
+++ b/saffron.geometry.m
@@ -197,24 +197,40 @@
197197 vertex(in, in, in, in) = (out),
198198 "SaffronGeometry_CreateVertex2D").
199199
200+:- pragma foreign_export("C",
201+ vertex(in, in, in, in) = (out),
202+ "CreateVertex").
203+
200204 %-----------------------------------------------------------------------------%
201205
202206 :- pragma foreign_export("C",
203207 vertex(out, out, out, out, in),
204208 "SaffronGeometry_GetVertex2D").
205209
210+:- pragma foreign_export("Java",
211+ vertex(out, out, out, out, in),
212+ "GetVertex").
213+
206214 %-----------------------------------------------------------------------------%
207215
208216 :- pragma foreign_export("C",
209217 vertex(in, in, in, in, in) = (out),
210218 "SaffronGeometry_CreateVertex3D").
211219
220+:- pragma foreign_export("Java",
221+ vertex(in, in, in, in, in) = (out),
222+ "CreateVertex").
223+
212224 %-----------------------------------------------------------------------------%
213225
214226 :- pragma foreign_export("C",
215227 vertex(out, out, out, out, out, in),
216228 "SaffronGeometry_GetVertex3D").
217229
230+:- pragma foreign_export("Java",
231+ vertex(out, out, out, out, out, in),
232+ "GetVertex").
233+
218234 %-----------------------------------------------------------------------------%
219235
220236 vertex(X, Y, U, V) = vertex(mmath.vector.vector2.vector(X, Y), U, V).
--- a/saffron.gl.buffer.m
+++ b/saffron.gl.buffer.m
@@ -124,6 +124,19 @@
124124 #undef SAFFRON_GL_IMPL
125125 ").
126126
127+% Imports for the Java grade.
128+:- pragma foreign_decl("Java", "
129+import org.lwjgl.opengl.ARBVertexBufferObject;
130+import org.lwjgl.opengl.GLCapabilities;
131+import org.lwjgl.opengl.GL;
132+import org.lwjgl.opengl.GL11; // Base constants
133+import org.lwjgl.opengl.GL20;
134+import jmercury.list;
135+import jmercury.list.List_1;
136+import jmercury.maybe.Maybe_error_2;
137+import jmercury.saffron__geometry.Vertex_1;
138+ ").
139+
127140 %-----------------------------------------------------------------------------%
128141
129142 :- pragma foreign_enum("C", buffer_type/0, [
@@ -131,13 +144,222 @@
131144 element_array_buffer - "GL_ELEMENT_ARRAY_BUFFER"
132145 ]).
133146
147+:- pragma foreign_export_enum(
148+ "Java",
149+ buffer_type/0,
150+ [prefix("BUFFER_TYPE_")|[uppercase|[]]]).
151+
152+:- pragma foreign_code("Java", "
153+public static int BufferTypeToGL(Buffer_type_0 t, boolean ARB){
154+ if(t.equals(BUFFER_TYPE_ARRAY_BUFFER)){
155+ return ARB ?
156+ ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB :
157+ GL20.GL_ARRAY_BUFFER;
158+ }
159+ else if(t.equals(BUFFER_TYPE_ELEMENT_ARRAY_BUFFER)){
160+ return ARB ?
161+ ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB :
162+ GL20.GL_ELEMENT_ARRAY_BUFFER;
163+ }
164+ else{
165+ throw new IllegalStateException(""Unknown buffer type"");
166+ }
167+}
168+
169+///////////////////////////////////////////////////////////////////////////////
170+/// \brief Base class for a Buffer context.
171+///
172+/// This is a base class so that we can have either a context of sufficient
173+/// version to have vertex buffers, or use ARB extensions.
174+///
175+/// This uses the bufferType method to convert from Buffer_type_0 to an int, so
176+/// that no other subclass-implemented method needs to deal with Buffer_type_0.
177+///
178+/// Derived classes only need to implement primitive array versions of
179+/// bufferData, all mercury types and Object-ified arrays will be unwrapped
180+/// and placed into primitive arrays by the base methods.
181+public static abstract class Context{
182+ protected abstract int bufferType(Buffer_type_0 t);
183+ public abstract int createBuffer();
184+ public abstract void destroyBuffer(int buffer);
185+ protected abstract void bindBuffer(int buffer, int t);
186+
187+ protected abstract void bufferData(int t, int[] data);
188+ public void bufferData(Buffer_type_0 t, int[] data){
189+ bufferData(bufferType(t), data);
190+ }
191+ public void bufferData(Buffer_type_0 t, Integer[] data){
192+ int[] l_data = new int[data.length];
193+ for(int i = 0; i < data.length; i++)
194+ l_data[i] = data[i].intValue();
195+ bufferData(bufferType(t), l_data);
196+ }
197+ public void bufferDataI(Buffer_type_0 t, List_1<Integer> data){
198+ final int length = jmercury.saffron.ListLength(data);
199+ int[] l_data = new int[length];
200+ for(int i = 0; i < length; i++){
201+ l_data[i] = list.det_head(data).intValue();
202+ data = list.det_tail(data);
203+ }
204+ bufferData(bufferType(t), l_data);
205+ }
206+
207+ protected abstract void bufferData(int t, double[] data);
208+ public void bufferData(Buffer_type_0 t, double[] data){
209+ bufferData(bufferType(t), data);
210+ }
211+ public void bufferData(Buffer_type_0 t, Double[] data){
212+ double[] l_data = new double[data.length];
213+ for(int i = 0; i < data.length; i++)
214+ l_data[i] = data[i].doubleValue();
215+ bufferData(bufferType(t), l_data);
216+ }
217+ public void bufferDataD(Buffer_type_0 t, list.List_1<Double> data){
218+ final int length = jmercury.saffron.ListLength(data);
219+ double[] l_data = new double[length];
220+ for(int i = 0; i < length; i++){
221+ l_data[i] = list.det_head(data).doubleValue();
222+ data = list.det_tail(data);
223+ }
224+ bufferData(bufferType(t), l_data);
225+ }
226+
227+ public void bufferData2(
228+ Buffer_type_0 t,
229+ Vertex_1<jmercury.mmath__vector__vector2.Vector_0>[] data){
230+ double[] l_data = new double[data.length * 4];
231+ int i = 0;
232+ for(Vertex_1<jmercury.mmath__vector__vector2.Vector_0> vertex : data)
233+ i = jmercury.saffron.WriteVertex2(l_data, vertex, i);
234+ bufferData(bufferType(t), l_data);
235+ }
236+
237+ public void bufferData2(
238+ Buffer_type_0 t,
239+ List_1<Vertex_1<jmercury.mmath__vector__vector2.Vector_0>> data){
240+ final int length = jmercury.saffron.ListLength(data);
241+ double[] l_data = new double[length * 4];
242+ int i = 0;
243+ for(int n = 0; n < length; n++){
244+ i = jmercury.saffron.WriteVertex2(l_data, list.det_head(data), i);
245+ data = list.det_tail(data);
246+ }
247+ bufferData(bufferType(t), l_data);
248+ }
249+
250+ public void bufferData3(
251+ Buffer_type_0 t,
252+ Vertex_1<jmercury.mmath__vector__vector3.Vector_0>[] data){
253+ double[] l_data = new double[data.length * 5];
254+ int i = 0;
255+ for(Vertex_1<jmercury.mmath__vector__vector3.Vector_0> vertex : data){
256+ i = jmercury.saffron.WriteVertex3(l_data, vertex, i);
257+ }
258+ bufferData(bufferType(t), l_data);
259+ }
260+
261+ public void bufferData3(
262+ Buffer_type_0 t,
263+ List_1<Vertex_1<jmercury.mmath__vector__vector3.Vector_0>> data){
264+ final int length = jmercury.saffron.ListLength(data);
265+ double[] l_data = new double[length * 5];
266+ int i = 0;
267+ for(int n = 0; n < length; n++){
268+ i = jmercury.saffron.WriteVertex3(l_data, list.det_head(data), i);
269+ data = list.det_tail(data);
270+ }
271+ bufferData(bufferType(t), l_data);
272+ }
273+
274+ public void bindBuffer(int buffer, Buffer_type_0 t){
275+ bindBuffer(buffer, bufferType(t));
276+ }
277+}
278+
279+///////////////////////////////////////////////////////////////////////////////
280+/// \brief Implements a buffer context using core OpenGL functions.
281+public static class GL20Context extends Context{
282+ protected int bufferType(Buffer_type_0 t){
283+ if(t.equals(BUFFER_TYPE_ARRAY_BUFFER))
284+ return GL20.GL_ARRAY_BUFFER;
285+ else if(t.equals(BUFFER_TYPE_ELEMENT_ARRAY_BUFFER))
286+ return GL20.GL_ELEMENT_ARRAY_BUFFER;
287+ else
288+ throw new IllegalStateException(""Unknown buffer type"");
289+ }
290+ public int createBuffer(){
291+ return GL20.glGenBuffers();
292+ }
293+ public void destroyBuffer(int buffer){
294+ GL20.glDeleteBuffers(buffer);
295+ }
296+ protected void bindBuffer(int buffer, int t){
297+ GL20.glBindBuffer(t, buffer);
298+ }
299+ protected void bufferData(int t, int[] data){
300+ GL20.glBufferData(t, data, GL20.GL_STATIC_DRAW);
301+ }
302+ protected void bufferData(int t, double[] data){
303+ GL20.glBufferData(t, data, GL20.GL_STATIC_DRAW);
304+ }
305+}
306+
307+///////////////////////////////////////////////////////////////////////////////
308+/// \brief Implements a buffer context using GL_ARB_vertex_buffer_object
309+public static class ARBContext extends Context{
310+ protected int bufferType(Buffer_type_0 t){
311+ if(t.equals(BUFFER_TYPE_ARRAY_BUFFER))
312+ return ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB;
313+ else if(t.equals(BUFFER_TYPE_ELEMENT_ARRAY_BUFFER))
314+ return ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB;
315+ else
316+ throw new IllegalStateException(""Unknown buffer type"");
317+ }
318+ public int createBuffer(){
319+ return ARBVertexBufferObject.glGenBuffersARB();
320+ }
321+ public void destroyBuffer(int buffer){
322+ ARBVertexBufferObject.glDeleteBuffersARB(buffer);
323+ }
324+ protected void bindBuffer(int buffer, int t){
325+ ARBVertexBufferObject.glBindBufferARB(t, buffer);
326+ }
327+ protected void bufferData(int t, int[] data){
328+ ARBVertexBufferObject.glBufferDataARB(t, data, ARBVertexBufferObject.GL_STATIC_DRAW_ARB);
329+ }
330+ protected void bufferData(int t, double[] data){
331+ ARBVertexBufferObject.glBufferDataARB(t, data, ARBVertexBufferObject.GL_STATIC_DRAW_ARB);
332+ }
333+}
334+
335+///////////////////////////////////////////////////////////////////////////////
336+/// \brief Creates a shader context, using OpenGL capabilities to determine
337+///
338+/// if a GL2.0 or an ARB context is appropriate.
339+/// May return null if no context can be created.
340+public static Context CreateContext(){
341+ final GLCapabilities caps = GL.getCapabilities();
342+ if(caps.OpenGL20){
343+ return new GL20Context();
344+ }
345+ else if(caps.GL_ARB_vertex_buffer_object){
346+ return new ARBContext();
347+ }
348+ else{
349+ return null;
350+ }
351+}
352+ ").
353+
134354 %-----------------------------------------------------------------------------%
135355
136356 :- pragma foreign_type("C", buffer_ctx, "SAFFRON_GL_BUFFER_CTX").
357+:- pragma foreign_type("Java", buffer_ctx, "jmercury.saffron__gl__buffer.Context").
137358
138359 %-----------------------------------------------------------------------------%
139360
140361 :- pragma foreign_type("C", buffer, "GLuint").
362+:- pragma foreign_type("Java", buffer, "int").
141363
142364 %-----------------------------------------------------------------------------%
143365
@@ -157,6 +379,12 @@ create_buffer_ctx_error(E) = maybe.error(E).
157379
158380 %-----------------------------------------------------------------------------%
159381
382+:- pragma foreign_code("Java", "
383+final public static Maybe_error_2<Context, String> create_context_error =
384+ new Maybe_error_2.Error_1(
385+ ""Buffers require OpenGL 2.0 or GL_ARB_vertex_buffer_objects"");
386+ ").
387+
160388 :- pred create_buffer_ctx_internal(
161389 gl_load_func_ctx,
162390 maybe.maybe_error(buffer_ctx),
@@ -181,6 +409,18 @@ create_buffer_ctx_error(E) = maybe.error(E).
181409 IOo = IOi;
182410 ").
183411
412+:- pragma foreign_proc("Java",
413+ create_buffer_ctx_internal(Ctx::in, MaybeBufferCtx::out, IOi::di, IOo::uo),
414+ [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
415+ "
416+ final jmercury.saffron__gl__buffer.Context ctx =
417+ jmercury.saffron__gl__buffer.CreateContext();
418+ MaybeBufferCtx = (ctx == null) ?
419+ jmercury.saffron__gl__buffer.create_context_error :
420+ new jmercury.maybe.Maybe_error_2.Ok_1(ctx);
421+ IOo = IOi;
422+ ").
423+
184424 %-----------------------------------------------------------------------------%
185425
186426 create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :-
@@ -201,6 +441,14 @@ create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :-
201441 IOo = IOi;
202442 ").
203443
444+:- pragma foreign_proc("Java",
445+ create_buffer(Ctx::in, Buffer::uo, IOi::di, IOo::uo),
446+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
447+ "
448+ Buffer = Ctx.createBuffer();
449+ IOo = IOi;
450+ ").
451+
204452 %-----------------------------------------------------------------------------%
205453
206454 :- pragma foreign_proc("C",
@@ -213,6 +461,14 @@ create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :-
213461 IOo = IOi;
214462 ").
215463
464+:- pragma foreign_proc("Java",
465+ destroy_buffer(Ctx::in, Buffer::in, IOi::di, IOo::uo),
466+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
467+ "
468+ Ctx.destroyBuffer(Buffer);
469+ IOo = IOi;
470+ ").
471+
216472 %-----------------------------------------------------------------------------%
217473
218474 :- instance saffron.destroy(buffer_ctx, buffer) where [
@@ -230,6 +486,14 @@ create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :-
230486 IOo = IOi;
231487 ").
232488
489+:- pragma foreign_proc("Java",
490+ bind_buffer(Ctx::in, Buffer::in, Type::in, IOi::di, IOo::uo),
491+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
492+ "
493+ Ctx.bindBuffer(Buffer, Type);
494+ IOo = IOi;
495+ ").
496+
233497 %-----------------------------------------------------------------------------%
234498
235499 :- pragma foreign_proc("C",
@@ -263,6 +527,14 @@ create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :-
263527 IOo = IOi;
264528 ").
265529
530+:- pragma foreign_proc("Java",
531+ buffer_data_float_array(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
532+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
533+ "
534+ Ctx.bufferData(Type, T);
535+ IOo = IOi;
536+ ").
537+
266538 %-----------------------------------------------------------------------------%
267539
268540 :- pragma foreign_proc("C",
@@ -297,6 +569,14 @@ create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :-
297569 IOo = IOi;
298570 ").
299571
572+:- pragma foreign_proc("Java",
573+ buffer_data_int_array(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
574+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
575+ "
576+ Ctx.bufferData(Type, T);
577+ IOo = IOi;
578+ ").
579+
300580 %-----------------------------------------------------------------------------%
301581 % TODO: This should work, and is optimal when we have unboxed floats, but
302582 % we should eventually implement a better C version for when we have boxed
@@ -304,11 +584,31 @@ create_buffer_ctx(Ctx, MaybeBufferCtx, !IO) :-
304584 buffer_data_float_list(Ctx, Type, List, !IO) :-
305585 buffer_data_float_array(Ctx, Type, array.from_list(List), !IO).
306586
587+% Java will always have boxed/Object-ified values in lists.
588+% Convert from that to a primitive array in one go.
589+:- pragma foreign_proc("Java",
590+ buffer_data_float_list(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
591+ [may_call_mercury, promise_pure, thread_safe, may_duplicate],
592+ "
593+ Ctx.bufferDataD(Type, T);
594+ IOo = IOi;
595+ ").
596+
307597 %-----------------------------------------------------------------------------%
308598 % As integers are always unboxed, this actually is optimal.
309599 buffer_data_int_list(Ctx, Type, List, !IO) :-
310600 buffer_data_int_array(Ctx, Type, array.from_list(List), !IO).
311601
602+% Java will always have boxed/Object-ified values in lists.
603+% Convert from that to a primitive array in one go.
604+:- pragma foreign_proc("Java",
605+ buffer_data_int_list(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
606+ [may_call_mercury, promise_pure, thread_safe, may_duplicate],
607+ "
608+ Ctx.bufferDataI(Type, T);
609+ IOo = IOi;
610+ ").
611+
312612 %-----------------------------------------------------------------------------%
313613
314614 :- pragma foreign_proc("C",
@@ -337,6 +637,14 @@ buffer_data_int_list(Ctx, Type, List, !IO) :-
337637 IOo = IOi;
338638 ").
339639
640+:- pragma foreign_proc("Java",
641+ buffer_data_vertex2d_array(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
642+ [may_call_mercury, promise_pure, thread_safe, may_duplicate],
643+ "
644+ Ctx.bufferData2(Type, (Vertex_1[])T);
645+ IOo = IOi;
646+ ").
647+
340648 :- pragma foreign_proc("C",
341649 buffer_data_vertex2d_list(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
342650 [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
@@ -369,6 +677,14 @@ buffer_data_int_list(Ctx, Type, List, !IO) :-
369677 IOo = IOi;
370678 ").
371679
680+:- pragma foreign_proc("Java",
681+ buffer_data_vertex2d_list(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
682+ [may_call_mercury, promise_pure, thread_safe, may_duplicate],
683+ "
684+ Ctx.bufferData2(Type, T);
685+ IOo = IOi;
686+ ").
687+
372688 %-----------------------------------------------------------------------------%
373689
374690 :- pragma foreign_proc("C",
@@ -400,6 +716,14 @@ buffer_data_int_list(Ctx, Type, List, !IO) :-
400716 IOo = IOi;
401717 ").
402718
719+:- pragma foreign_proc("Java",
720+ buffer_data_vertex3d_array(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
721+ [may_call_mercury, promise_pure, thread_safe, may_duplicate],
722+ "
723+ Ctx.bufferData3(Type, (Vertex_1[])T);
724+ IOo = IOi;
725+ ").
726+
403727 :- pragma foreign_proc("C",
404728 buffer_data_vertex3d_list(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
405729 [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
@@ -432,3 +756,11 @@ buffer_data_int_list(Ctx, Type, List, !IO) :-
432756 IOo = IOi;
433757 ").
434758
759+:- pragma foreign_proc("Java",
760+ buffer_data_vertex3d_list(Ctx::in, Type::in, T::in, IOi::di, IOo::uo),
761+ [may_call_mercury, promise_pure, thread_safe, may_duplicate],
762+ "
763+ Ctx.bufferData3(Type, T);
764+ IOo = IOi;
765+ ").
766+
--- a/saffron.gl.m
+++ b/saffron.gl.m
@@ -221,6 +221,39 @@ typedef char SaffronGLchar;
221221
222222 ").
223223
224+% Imports for the Java grade.
225+:- pragma foreign_decl("Java", "
226+import org.lwjgl.opengl.GL;
227+import org.lwjgl.opengl.GL11; // Base constants
228+import org.lwjgl.opengl.GL20;
229+import java.nio.ByteBuffer;
230+import jmercury.maybe.Maybe_1; // Used in MaybeInteger.
231+ ").
232+
233+:- pragma foreign_code("Java", "
234+///////////////////////////////////////////////////////////////////////////////
235+/// \brief Shorthand to create a maybe(int).
236+public static Maybe_1<Integer> MaybeInteger(int i, boolean b){
237+ return b ? new Maybe_1.Yes_1(new Integer(i)) : new Maybe_1.No_0();
238+}
239+
240+public static jmercury.maybe.Maybe_1<Integer> MaybeInteger(int i){
241+ return MaybeInteger(i, i >= 0);
242+}
243+public static ByteBuffer BufferFromBitmap(
244+ int w,
245+ int h,
246+ jmercury.runtime.MercuryBitmap bmp){
247+ if(w * h * 4 < bmp.elements.length)
248+ throw new IndexOutOfBoundsException(""Bitmap is too small"");
249+ final ByteBuffer buffer = ByteBuffer.allocateDirect(w * h * 4);
250+ buffer.put(bmp.elements, 0, w * h * 4);
251+ buffer.rewind();
252+ buffer.mark();
253+ return buffer;
254+}
255+ ").
256+
224257 %-----------------------------------------------------------------------------%
225258
226259 :- pragma foreign_enum("C", data_type/0, [
@@ -230,6 +263,26 @@ typedef char SaffronGLchar;
230263 short - "GL_UNSIGNED_SHORT"
231264 ]).
232265
266+:- pragma foreign_export_enum(
267+ "Java",
268+ data_type/0,
269+ [prefix("DATA_TYPE_")|[uppercase|[]]]).
270+
271+:- pragma foreign_code("Java", "
272+public static int DataTypeToGL(Data_type_0 t){
273+ if(t.equals(DATA_TYPE_INT))
274+ return org.lwjgl.opengl.GL11.GL_INT;
275+ else if(t.equals(DATA_TYPE_FLOAT))
276+ return org.lwjgl.opengl.GL11.GL_DOUBLE;
277+ else if(t.equals(DATA_TYPE_BYTE))
278+ return org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
279+ else if(t.equals(DATA_TYPE_SHORT))
280+ return org.lwjgl.opengl.GL11.GL_UNSIGNED_SHORT;
281+ else
282+ throw new IllegalStateException(""Unknown data type"");
283+}
284+ ").
285+
233286 %-----------------------------------------------------------------------------%
234287
235288 :- pragma foreign_enum("C", primitive_type/0, [
@@ -239,9 +292,30 @@ typedef char SaffronGLchar;
239292 triangle_fan - "GL_TRIANGLE_FAN"
240293 ]).
241294
295+:- pragma foreign_export_enum(
296+ "Java",
297+ primitive_type/0,
298+ [prefix("PRIMITIVE_TYPE_")|[uppercase|[]]]).
299+
300+:- pragma foreign_code("Java", "
301+public static int PrimitiveTypeToGL(Primitive_type_0 t){
302+ if(t.equals(PRIMITIVE_TYPE_LINE_STRIP))
303+ return org.lwjgl.opengl.GL11.GL_LINE_STRIP;
304+ if(t.equals(PRIMITIVE_TYPE_LINE_LOOP))
305+ return org.lwjgl.opengl.GL11.GL_LINE_LOOP;
306+ if(t.equals(PRIMITIVE_TYPE_TRIANGLE_STRIP))
307+ return org.lwjgl.opengl.GL11.GL_TRIANGLE_STRIP;
308+ if(t.equals(PRIMITIVE_TYPE_TRIANGLE_FAN))
309+ return org.lwjgl.opengl.GL11.GL_TRIANGLE_FAN;
310+ else
311+ throw new IllegalStateException(""Unknown primitive type"");
312+}
313+ ").
314+
242315 %-----------------------------------------------------------------------------%
243316
244317 :- pragma foreign_type("C", texture, "GLuint").
318+:- pragma foreign_type("Java", texture, "int").
245319
246320 %-----------------------------------------------------------------------------%
247321
@@ -256,6 +330,7 @@ primitive_type(saffron.geometry.triangle_fan, saffron.gl.triangle_fan).
256330 :- mode supports_extension_inner(in, uo, di, uo) is det.
257331
258332 supports_extension_inner(_, bool.no, !IO).
333+
259334 :- pragma foreign_proc("C",
260335 supports_extension_inner(Ext::in, Supports::uo, IOi::di, IOo::uo),
261336 [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
@@ -306,6 +381,13 @@ float_bytes = 8.
306381 glGenTextures(1, &Tex);
307382 ").
308383
384+:- pragma foreign_proc("Java", create_texture(Tex::out, IOi::di, IOo::uo),
385+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
386+ "
387+ IOo = IOi;
388+ Tex = org.lwjgl.opengl.GL11.glGenTextures();
389+ ").
390+
309391 %-----------------------------------------------------------------------------%
310392
311393 :- pred tex_parameters(io.io::di, io.io::uo) is det.
@@ -319,6 +401,14 @@ float_bytes = 8.
319401 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
320402 ").
321403
404+:- pragma foreign_proc("Java", tex_parameters(IOi::di, IOo::uo),
405+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
406+ "
407+ IOo = IOi;
408+ org.lwjgl.opengl.GL11.glTexParameteri(org.lwjgl.opengl.GL11.GL_TEXTURE_2D, org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER, org.lwjgl.opengl.GL11.GL_NEAREST);
409+ org.lwjgl.opengl.GL11.glTexParameteri(org.lwjgl.opengl.GL11.GL_TEXTURE_2D, org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER, org.lwjgl.opengl.GL11.GL_NEAREST);
410+ ").
411+
322412 %-----------------------------------------------------------------------------%
323413
324414 :- pragma foreign_proc("C", bind_texture(Tex::in, IOi::di, IOo::uo),
@@ -329,6 +419,13 @@ float_bytes = 8.
329419 glBindTexture(GL_TEXTURE_2D, Tex);
330420 ").
331421
422+:- pragma foreign_proc("Java", bind_texture(Tex::in, IOi::di, IOo::uo),
423+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
424+ "
425+ IOo = IOi;
426+ org.lwjgl.opengl.GL11.glBindTexture(org.lwjgl.opengl.GL11.GL_TEXTURE_2D, Tex);
427+ ").
428+
332429 %-----------------------------------------------------------------------------%
333430
334431 :- pred tex_image(int::in, int::in, io.io::di, io.io::uo) is det.
@@ -342,6 +439,22 @@ float_bytes = 8.
342439 GL_TEXTURE_2D, 0, GL_RGBA, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
343440 ").
344441
442+:- pragma foreign_proc("Java", tex_image(W::in, H::in, IOi::di, IOo::uo),
443+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
444+ "
445+ IOo = IOi;
446+ org.lwjgl.opengl.GL11.nglTexImage2D(
447+ org.lwjgl.opengl.GL11.GL_TEXTURE_2D,
448+ 0,
449+ org.lwjgl.opengl.GL11.GL_RGBA,
450+ W,
451+ H,
452+ 0,
453+ org.lwjgl.opengl.GL11.GL_RGBA,
454+ org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE,
455+ 0);
456+ ").
457+
345458 %-----------------------------------------------------------------------------%
346459
347460 :- pred tex_image(bitmap.bitmap, int, int, io.io, io.io).
@@ -357,12 +470,30 @@ float_bytes = 8.
357470 GL_TEXTURE_2D, 0, GL_RGBA, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, B->elements);
358471 ").
359472
473+:- pragma foreign_proc("Java", tex_image(B::in, W::in, H::in, IOi::di, IOo::uo),
474+ [will_not_call_mercury, promise_pure, thread_safe],
475+ "
476+ final java.nio.ByteBuffer buffer = jmercury.saffron__gl.BufferFromBitmap(W, H, B);
477+ org.lwjgl.opengl.GL11.glTexImage2D(
478+ org.lwjgl.opengl.GL11.GL_TEXTURE_2D,
479+ 0,
480+ org.lwjgl.opengl.GL11.GL_RGBA,
481+ W,
482+ H,
483+ 0,
484+ org.lwjgl.opengl.GL11.GL_RGBA,
485+ org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE,
486+ buffer);
487+ IOo = IOi;
488+ ").
489+
360490 %-----------------------------------------------------------------------------%
361491
362492 :- pred tex_sub_image(bitmap.bitmap, int, int, int, int, io.io, io.io).
363493 :- mode tex_sub_image(in, in, in, in, in, di, uo) is det.
364494
365-:- pragma foreign_proc("C", tex_sub_image(B::in, X::in, Y::in, W::in, H::in, IOi::di, IOo::uo),
495+:- pragma foreign_proc("C",
496+ tex_sub_image(B::in, X::in, Y::in, W::in, H::in, IOi::di, IOo::uo),
366497 [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
367498 may_duplicate, does_not_affect_liveness],
368499 "
@@ -372,6 +503,24 @@ float_bytes = 8.
372503 GL_TEXTURE_2D, 0, X, Y, W, H, GL_RGBA, GL_UNSIGNED_BYTE, B->elements);
373504 ").
374505
506+:- pragma foreign_proc("Java",
507+ tex_sub_image(B::in, X::in, Y::in, W::in, H::in, IOi::di, IOo::uo),
508+ [will_not_call_mercury, promise_pure, thread_safe],
509+ "
510+ final java.nio.ByteBuffer buffer = jmercury.saffron__gl.BufferFromBitmap(W, H, B);
511+ org.lwjgl.opengl.GL11.glTexImage2D(
512+ org.lwjgl.opengl.GL11.GL_TEXTURE_2D,
513+ 0,
514+ X,
515+ Y,
516+ W,
517+ H,
518+ org.lwjgl.opengl.GL11.GL_RGBA,
519+ org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE,
520+ buffer);
521+ IOo = IOi;
522+ ").
523+
375524 %-----------------------------------------------------------------------------%
376525
377526 :- pred destroy_texture(texture::in, io.io::di, io.io::uo) is det.
@@ -384,6 +533,13 @@ float_bytes = 8.
384533 glDeleteTextures(1, &Tex);
385534 ").
386535
536+:- pragma foreign_proc("Java", destroy_texture(Tex::in, IOi::di, IOo::uo),
537+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
538+ "
539+ IOo = IOi;
540+ org.lwjgl.opengl.GL11.glDeleteTextures(Tex);
541+ ").
542+
387543 %-----------------------------------------------------------------------------%
388544
389545 destroy_texture(_Ctx, Tex, !IO) :-
@@ -510,6 +666,8 @@ gl_supports_extension(gl_load_func_ctx(Ctx), Ext, Supports, !IO) :-
510666 :- pred version_string(version_type, string, io.io, io.io).
511667 :- mode version_string(in, out, di, uo) is det.
512668
669+version_string(_, "0.0", !IO).
670+
513671 :- pragma foreign_proc("C",
514672 version_string(Type::in, Str::out, IOi::di, IOo::uo),
515673 [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
@@ -532,9 +690,21 @@ gl_supports_extension(gl_load_func_ctx(Ctx), Ext, Supports, !IO) :-
532690
533691 %-----------------------------------------------------------------------------%
534692
693+:- pred opengl_version_string(string::uo, io.io::di, io.io::uo) is det.
694+opengl_version_string(Str, !IO) :-
695+ version_string(gl, Str, !IO).
696+
697+:- pragma foreign_proc("Java",
698+ opengl_version_string(Str::uo, IOi::di, IOo::uo),
699+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
700+ "
701+ IOo = IOi;
702+ Str = org.lwjgl.opengl.GL11.glGetString(org.lwjgl.opengl.GL11.GL_VERSION);
703+ ").
704+
535705 opengl_version_string(Ctx, Str, !IO) :-
536706 saffron.make_current(Ctx, !IO),
537- version_string(gl, Str, !IO).
707+ opengl_version_string(Str, !IO).
538708
539709 %-----------------------------------------------------------------------------%
540710
@@ -543,9 +713,22 @@ opengl_version(Ctx, saffron.parse_sem_ver(Version), !IO) :-
543713
544714 %-----------------------------------------------------------------------------%
545715
716+:- pred shader_model_version_string(string::uo, io.io::di, io.io::uo) is det.
717+shader_model_version_string(Str, !IO) :-
718+ version_string(glsl, Str, !IO).
719+
720+:- pragma foreign_proc("Java",
721+ shader_model_version_string(Str::uo, IOi::di, IOo::uo),
722+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
723+ "
724+ IOo = IOi;
725+ Str = org.lwjgl.opengl.GL20.glGetString(
726+ org.lwjgl.opengl.GL20.GL_SHADING_LANGUAGE_VERSION);
727+ ").
728+
546729 shader_model_version_string(Ctx, Str, !IO) :-
547730 saffron.make_current(Ctx, !IO),
548- version_string(glsl, Str, !IO).
731+ shader_model_version_string(Str, !IO).
549732
550733 %-----------------------------------------------------------------------------%
551734
--- a/saffron.gl.shader.m
+++ b/saffron.gl.shader.m
@@ -287,6 +287,310 @@
287287
288288 :- pragma foreign_import_module("C", saffron.gl).
289289
290+% Imports for the Java grade.
291+:- pragma foreign_decl("Java", "
292+import org.lwjgl.opengl.ARBShaderObjects;
293+import org.lwjgl.opengl.ARBFragmentShader;
294+import org.lwjgl.opengl.ARBVertexShader;
295+import org.lwjgl.opengl.GLCapabilities;
296+import org.lwjgl.opengl.GL;
297+import org.lwjgl.opengl.GL11; // Base constants
298+import org.lwjgl.opengl.GL20;
299+import org.lwjgl.opengl.GL32; // Geometry shaders
300+import org.lwjgl.opengl.GLCapabilities;
301+import jmercury.maybe.Maybe_error_2;
302+ ").
303+
304+:- pragma foreign_export_enum(
305+ "Java",
306+ shader_type/0,
307+ [prefix("SHADER_TYPE_")|[uppercase|[]]]).
308+
309+:- pragma foreign_code("Java", "
310+///////////////////////////////////////////////////////////////////////////////
311+/// \brief Base class for a Shader context.
312+///
313+/// This is a base class so that we can have either a context of sufficient
314+/// version to have shaders, or use ARB extensions to implement shaders.
315+public static abstract class Context{
316+ public final boolean supports_geometry_shaders;
317+ protected Context(boolean l_supports_geometry_shaders){
318+ supports_geometry_shaders = l_supports_geometry_shaders;
319+ }
320+ public abstract int createProgram();
321+ public int createShader(Shader_type_0 type){
322+ if(type.equals(SHADER_TYPE_FRAGMENT)){
323+ return createFragmentShader();
324+ }
325+ else if(type.equals(SHADER_TYPE_VERTEX)){
326+ return createVertexShader();
327+ }
328+ else if(type.equals(SHADER_TYPE_GEOMETRY)){
329+ if(supports_geometry_shaders)
330+ return createGeometryShader();
331+ // Otherwise, fallthrough below to be unsupported rather than
332+ // unknown shader type.
333+ }
334+ else{
335+ throw new IllegalStateException(""Unknown shader type"");
336+ }
337+ throw new UnsupportedOperationException(""Unsupported shader type"");
338+ }
339+ protected abstract int createFragmentShader();
340+ protected abstract int createVertexShader();
341+ protected int createGeometryShader(){
342+ throw new UnsupportedOperationException(
343+ ""Cannot create geometry shaders"");
344+ }
345+ public abstract void deleteShader(int shader);
346+ public abstract void deleteProgram(int program);
347+ public abstract void useProgram(int program);
348+ public abstract void shaderSource(int shader, String src);
349+ public abstract void compileShader(int shader);
350+ public abstract void linkProgram(int program);
351+ public abstract void attachShader(int program, int shader);
352+ public abstract boolean shaderCompileStatus(int shader);
353+ public abstract boolean programLinkStatus(int program);
354+ public abstract String shaderInfoLog(int shader);
355+ public abstract String programInfoLog(int program);
356+ public abstract int getUniformLocation(int program, String name);
357+ public abstract void uniform(int location, float f1);
358+ public abstract void uniform(int location, float f1, float f2);
359+ public abstract void uniform(int location, float f1, float f2, float f3);
360+ public abstract void uniform(int location, float f1, float f2, float f3, float f4);
361+ public abstract void uniformMat3x3(int location, float[] matrix);
362+ public abstract void uniformMat4x4(int location, float[] matrix);
363+ public abstract void bindAttribLocation(int program, int loc, String name);
364+ public abstract int getAttribLocation(int program, String name);
365+ public void vertexAttribPointer(int attrib, int n, jmercury.saffron__gl.Data_type_0 t, int stride, long ptr){
366+ final int type = jmercury.saffron__gl.DataTypeToGL(t);
367+ vertexAttribPointer(attrib, n, type, stride, ptr);
368+ }
369+ public abstract void vertexAttribPointer(int attrib, int n, int type, int stride, long ptr);
370+ public void uniform(int location, double f1){
371+ uniform(location, (float)f1);
372+ }
373+ public void uniform(int location, double f1, double f2){
374+ uniform(location, (float)f1, (float)f2);
375+ }
376+ public void uniform(int location, double f1, double f2, double f3){
377+ uniform(location, (float)f1, (float)f2, (float)f3);
378+ }
379+ public void uniform(int location, double f1, double f2, double f3, double f4){
380+ uniform(location, (float)f1, (float)f2, (float)f3, (float)f4);
381+ }
382+ public void uniform(int location, Double f1){
383+ uniform(location, f1.floatValue());
384+ }
385+ public void uniform(int location, Double f1, Double f2){
386+ uniform(location, f1.floatValue(), f2.floatValue());
387+ }
388+ public void uniform(int location, Double f1, Double f2, Double f3){
389+ uniform(location, f1.floatValue(), f2.floatValue(), f3.floatValue());
390+ }
391+ public void uniform(int location, Double f1, Double f2, Double f3, Double f4){
392+ uniform(location, f1.floatValue(), f2.floatValue(), f3.floatValue(), f4.floatValue());
393+ }
394+}
395+
396+///////////////////////////////////////////////////////////////////////////////
397+/// Shader context that uses OpenGL core features.
398+private static class GL20Context extends Context{
399+ public GL20Context(){
400+ this(GL.getCapabilities());
401+ }
402+ public GL20Context(GLCapabilities caps){
403+ super(caps.OpenGL32);
404+ }
405+ public int createProgram(){
406+ return GL20.glCreateProgram();
407+ }
408+ protected int createFragmentShader(){
409+ return GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
410+ }
411+ protected int createVertexShader(){
412+ return GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
413+ }
414+ protected int createGeometryShader(){
415+ return GL32.glCreateShader(GL32.GL_FRAGMENT_SHADER);
416+ }
417+ public void deleteShader(int shader){
418+ GL20.glDeleteShader(shader);
419+ }
420+ public void deleteProgram(int program){
421+ GL20.glDeleteProgram(program);
422+ }
423+ public void useProgram(int program){
424+ GL20.glUseProgram(program);
425+ }
426+ public void shaderSource(int shader, String src){
427+ GL20.glShaderSource(shader, src);
428+ }
429+ public void compileShader(int shader){
430+ GL20.glCompileShader(shader);
431+ }
432+ public void linkProgram(int program){
433+ GL20.glLinkProgram(program);
434+ }
435+ public void attachShader(int program, int shader){
436+ GL20.glAttachShader(program, shader);
437+ }
438+ public boolean shaderCompileStatus(int shader){
439+ final int status = GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS);
440+ return status == GL20.GL_TRUE;
441+ }
442+ public boolean programLinkStatus(int program){
443+ final int status = GL20.glGetProgrami(program, GL20.GL_LINK_STATUS);
444+ return status == GL20.GL_TRUE;
445+ }
446+ public String shaderInfoLog(int shader){
447+ return GL20.glGetShaderInfoLog(shader);
448+ }
449+ public String programInfoLog(int program){
450+ return GL20.glGetProgramInfoLog(program);
451+ }
452+ public int getUniformLocation(int program, String name){
453+ return GL20.glGetUniformLocation(program, name);
454+ }
455+ public void uniform(int location, float f1){
456+ GL20.glUniform1f(location, f1);
457+ }
458+ public void uniform(int location, float f1, float f2){
459+ GL20.glUniform2f(location, f1, f2);
460+ }
461+ public void uniform(int location, float f1, float f2, float f3){
462+ GL20.glUniform3f(location, f1, f2, f3);
463+ }
464+ public void uniform(int location, float f1, float f2, float f3, float f4){
465+ GL20.glUniform4f(location, f1, f2, f3, f4);
466+ }
467+ public void uniformMat3x3(int location, float[] matrix){
468+ GL20.glUniformMatrix3fv(location, false, matrix);
469+ }
470+ public void uniformMat4x4(int location, float[] matrix){
471+ GL20.glUniformMatrix4fv(location, false, matrix);
472+ }
473+ public void bindAttribLocation(int program, int loc, String name){
474+ GL20.glBindAttribLocation(program, loc, name);
475+ }
476+ public int getAttribLocation(int program, String name){
477+ return GL20.glGetAttribLocation(program, name);
478+ }
479+ public void vertexAttribPointer(int attrib, int n, int type, int stride, long ptr){
480+ GL20.nglVertexAttribPointer(attrib, n, type, false, stride, ptr);
481+ }
482+}
483+
484+///////////////////////////////////////////////////////////////////////////////
485+// A shader context that uses ARB extensions.
486+private static class ARBContext extends Context{
487+ public ARBContext(){
488+ super(false);
489+ }
490+ public int createProgram(){
491+ return ARBShaderObjects.glCreateProgramObjectARB();
492+ }
493+ protected int createFragmentShader(){
494+ return ARBShaderObjects.glCreateShaderObjectARB(
495+ ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);
496+ }
497+ protected int createVertexShader(){
498+ return ARBShaderObjects.glCreateShaderObjectARB(
499+ ARBVertexShader.GL_VERTEX_SHADER_ARB);
500+ }
501+ public void deleteShader(int shader){
502+ ARBShaderObjects.glDeleteObjectARB(shader);
503+ }
504+ public void deleteProgram(int program){
505+ ARBShaderObjects.glDeleteObjectARB(program);
506+ }
507+ public void useProgram(int program){
508+ ARBShaderObjects.glUseProgramObjectARB(program);
509+ }
510+ public void shaderSource(int shader, String src){
511+ ARBShaderObjects.glShaderSourceARB(shader, src);
512+ }
513+ public void compileShader(int shader){
514+ ARBShaderObjects.glCompileShaderARB(shader);
515+ }
516+ public void linkProgram(int program){
517+ ARBShaderObjects.glLinkProgramARB(program);
518+ }
519+ public void attachShader(int program, int shader){
520+ ARBShaderObjects.glAttachObjectARB(program, shader);
521+ }
522+ public boolean shaderCompileStatus(int shader){
523+ final int status = ARBShaderObjects.glGetObjectParameteriARB(
524+ shader,
525+ ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB);
526+ return status == GL11.GL_TRUE;
527+ }
528+ public boolean programLinkStatus(int program){
529+ final int status = ARBShaderObjects.glGetObjectParameteriARB(
530+ program,
531+ ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB);
532+ return status == GL11.GL_TRUE;
533+ }
534+ public String shaderInfoLog(int shader){
535+ return ARBShaderObjects.glGetInfoLogARB(shader);
536+ }
537+ public String programInfoLog(int program){
538+ return ARBShaderObjects.glGetInfoLogARB(program);
539+ }
540+ public int getUniformLocation(int program, String name){
541+ return ARBShaderObjects.glGetUniformLocationARB(program, name);
542+ }
543+ public void uniform(int location, float f1){
544+ ARBShaderObjects.glUniform1fARB(location, f1);
545+ }
546+ public void uniform(int location, float f1, float f2){
547+ ARBShaderObjects.glUniform2fARB(location, f1, f2);
548+ }
549+ public void uniform(int location, float f1, float f2, float f3){
550+ ARBShaderObjects.glUniform3fARB(location, f1, f2, f3);
551+ }
552+ public void uniform(int location, float f1, float f2, float f3, float f4){
553+ ARBShaderObjects.glUniform4fARB(location, f1, f2, f3, f4);
554+ }
555+ public void uniformMat3x3(int location, float[] matrix){
556+ ARBShaderObjects.glUniformMatrix3fvARB(location, false, matrix);
557+ }
558+ public void uniformMat4x4(int location, float[] matrix){
559+ ARBShaderObjects.glUniformMatrix4fvARB(location, false, matrix);
560+ }
561+ public void bindAttribLocation(int program, int loc, String name){
562+ ARBVertexShader.glBindAttribLocationARB(program, loc, name);
563+ }
564+ public int getAttribLocation(int program, String name){
565+ return ARBVertexShader.glGetAttribLocationARB(program, name);
566+ }
567+ public void vertexAttribPointer(int attrib, int n, int type, int stride, long ptr){
568+ ARBVertexShader.nglVertexAttribPointerARB(attrib, n, type, false, stride, ptr);
569+ }
570+}
571+
572+///////////////////////////////////////////////////////////////////////////////
573+/// \brief Creates a shader context, using OpenGL capabilities to determine
574+///
575+/// if a GL2.0 or an ARB context is appropriate.
576+/// May return null if no context can be created.
577+public static Context CreateContext(){
578+ final GLCapabilities caps = GL.getCapabilities();
579+ if(caps.OpenGL20){
580+ return new GL20Context();
581+ }
582+ else if(caps.GL_ARB_shader_objects &&
583+ caps.GL_ARB_fragment_shader &&
584+ caps.GL_ARB_vertex_shader){
585+
586+ return new ARBContext();
587+ }
588+ else{
589+ return null;
590+ }
591+}
592+ ").
593+
290594 % Define the native prototypes to handle shaders.
291595 :- pragma foreign_decl("C", "
292596 #include ""saffron.gl.shader.inc""
@@ -368,25 +672,32 @@ struct SaffronGL_ShaderCtx{
368672 geometry - "GL_GEOMETRY_SHADER"
369673 ]).
370674
675+:- pragma foreign_export_enum("Java", shader_type/0).
676+
371677 %-----------------------------------------------------------------------------%
372678
373679 :- pragma foreign_type("C", shader_ctx, "struct SaffronGL_ShaderCtx*").
680+:- pragma foreign_type("Java", shader_ctx, "jmercury.saffron__gl__shader.Context").
374681
375682 %-----------------------------------------------------------------------------%
376683
377684 :- pragma foreign_type("C", shader_program, "GLuint").
685+:- pragma foreign_type("Java", shader_program, "int").
378686
379687 %-----------------------------------------------------------------------------%
380688
381689 :- pragma foreign_type("C", shader, "GLuint").
690+:- pragma foreign_type("Java", shader, "int").
382691
383692 %-----------------------------------------------------------------------------%
384693
385694 :- pragma foreign_type("C", uniform, "GLuint").
695+:- pragma foreign_type("Java", uniform, "int").
386696
387697 %-----------------------------------------------------------------------------%
388698
389699 :- pragma foreign_type("C", vertex_attrib, "GLuint").
700+:- pragma foreign_type("Java", vertex_attrib, "int").
390701
391702 %-----------------------------------------------------------------------------%
392703
@@ -419,6 +730,12 @@ create_shader_ctx_error(E) = maybe.error(E).
419730
420731 %-----------------------------------------------------------------------------%
421732
733+:- pragma foreign_code("Java", "
734+final public static Maybe_error_2<Context, String> create_context_error =
735+ new Maybe_error_2.Error_1(""Shaders require OpenGL 2.0 or \
736+GL_ARB_shader_objects, GL_ARB_vertex_shader, and GL_ARB_fragment_shader"");
737+ ").
738+
422739 :- pred create_shader_ctx_internal(
423740 gl_load_func_ctx,
424741 maybe.maybe_error(shader_ctx),
@@ -458,6 +775,19 @@ create_shader_ctx_error(E) = maybe.error(E).
458775 IOo = IOi;
459776 ").
460777
778+
779+:- pragma foreign_proc("Java",
780+ create_shader_ctx_internal(Ctx::in, MaybeShaderCtx::out, IOi::di, IOo::uo),
781+ [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
782+ "
783+ final jmercury.saffron__gl__shader.Context ctx =
784+ jmercury.saffron__gl__shader.CreateContext();
785+ MaybeShaderCtx = (ctx == null) ?
786+ jmercury.saffron__gl__shader.create_context_error :
787+ new jmercury.maybe.Maybe_error_2.Ok_1(ctx);
788+ IOo = IOi;
789+ ").
790+
461791 create_shader_ctx(Ctx, MaybeShaderCtx, !IO) :-
462792 create_shader_ctx_internal('new gl_load_func_ctx'(Ctx), MaybeShaderCtx, !IO).
463793
@@ -472,6 +802,14 @@ create_shader_ctx(Ctx, MaybeShaderCtx, !IO) :-
472802 IOo = IOi;
473803 ").
474804
805+:- pragma foreign_proc("Java",
806+ destroy_shader_program(Ctx::in, Program::in, IOi::di, IOo::uo),
807+ [promise_pure, thread_safe, will_not_throw_exception, may_duplicate],
808+ "
809+ Ctx.deleteProgram(Program);
810+ IOo = IOi;
811+ ").
812+
475813 %-----------------------------------------------------------------------------%
476814
477815 :- pred create_program_inner(
@@ -484,8 +822,6 @@ create_shader_ctx(Ctx, MaybeShaderCtx, !IO) :-
484822 io.io, io.io).
485823 :- mode create_program_inner(in, in, in, uo, uo, uo, di, uo) is det.
486824
487-%-----------------------------------------------------------------------------%
488-
489825 :- pragma foreign_proc("C",
490826 create_program_inner(Ctx::in, S2::in, S1::in, Prog::uo, OK::uo, Err::uo, IOi::di, IOo::uo),
491827 [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
@@ -506,6 +842,28 @@ create_shader_ctx(Ctx, MaybeShaderCtx, !IO) :-
506842 IOo = IOi;
507843 ").
508844
845+:- pragma foreign_proc("Java",
846+ create_program_inner(Ctx::in, S2::in, S1::in, Prog::uo, OK::uo, Err::uo, IOi::di, IOo::uo),
847+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
848+ "
849+ Prog = Ctx.createProgram();
850+ OK = jmercury.bool.NO;
851+ Err = """";
852+ if(Prog == 0){
853+ Err = ""Error creating shader program"";
854+ }
855+ else{
856+ Ctx.attachShader(Prog, S1);
857+ Ctx.attachShader(Prog, S2);
858+ Ctx.linkProgram(Prog);
859+ if(Ctx.programLinkStatus(Prog))
860+ OK = jmercury.bool.YES;
861+ else
862+ Err = Ctx.programInfoLog(Prog);
863+ }
864+ IOo = IOi;
865+ ").
866+
509867 %-----------------------------------------------------------------------------%
510868
511869 :- pred create_program_inner(
@@ -538,6 +896,31 @@ create_shader_ctx(Ctx, MaybeShaderCtx, !IO) :-
538896 IOo = IOi;
539897 ").
540898
899+:- pragma foreign_proc("Java",
900+ create_program_inner(Ctx::in, Shaders::in, Prog::uo, OK::uo, Err::uo, IOi::di, IOo::uo),
901+ [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
902+ "
903+ Prog = Ctx.createProgram();
904+ OK = jmercury.bool.NO;
905+ Err = """";
906+ if(Prog == 0){
907+ Err = ""Error creating shader program"";
908+ OK = jmercury.bool.NO;
909+ }
910+ else{
911+ while(!jmercury.list.is_empty(Shaders)){
912+ Ctx.attachShader(Prog, jmercury.list.det_head(Shaders));
913+ Shaders = jmercury.list.det_tail(Shaders);
914+ }
915+ Ctx.linkProgram(Prog);
916+ if(Ctx.programLinkStatus(Prog))
917+ OK = jmercury.bool.YES;
918+ else
919+ Err = Ctx.programInfoLog(Prog);
920+ }
921+ IOo = IOi;
922+ ").
923+
541924 %-----------------------------------------------------------------------------%
542925
543926 :- pred create_program_inner_array(
@@ -573,6 +956,28 @@ create_program_inner_array(ShaderCtx, Shaders, Program, OK, Err, !IO) :-
573956 IOo = IOi;
574957 ").
575958
959+:- pragma foreign_proc("Java",
960+ create_program_inner_array(Ctx::in, Shaders::in, Prog::uo, OK::uo, Err::uo, IOi::di, IOo::uo),
961+ [may_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
962+ "
963+ Prog = Ctx.createProgram();
964+ OK = jmercury.bool.NO;
965+ Err = """";
966+ if(Prog == 0){
967+ Err = ""Error creating shader program"";
968+ }
969+ else{
970+ for(int shader : Shaders)
971+ Ctx.attachShader(Prog, shader);
972+ Ctx.linkProgram(Prog);
973+ if(Ctx.programLinkStatus(Prog))
974+ OK = jmercury.bool.YES;
975+ else
976+ Err = Ctx.programInfoLog(Prog);
977+ }
978+ IOo = IOi;
979+ ").
980+
576981 %-----------------------------------------------------------------------------%
577982
578983 create_program(ShaderCtx, S1, S2, MaybeProgram, !IO) :-
@@ -621,15 +1026,26 @@ create_program_array(ShaderCtx, Shaders, MaybeProgram, !IO) :-
6211026 [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
6221027 may_duplicate, does_not_affect_liveness],
6231028 " Prog = 0; ").
1029+
1030+:- pragma foreign_proc("Java", no_shader_program = (Prog::out),
1031+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1032+ " Prog = 0; ").
6241033 :- pragma inline(no_shader_program/0).
6251034
6261035 %-----------------------------------------------------------------------------%
6271036
628-:- pragma foreign_proc("C", use_program(Ctx::in, Program::in, IOi::di, IOo::uo),
1037+:- pragma foreign_proc("C", use_program(Ctx::in, Prog::in, IOi::di, IOo::uo),
6291038 [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
6301039 tabled_for_io, may_duplicate, does_not_affect_liveness],
6311040 "
632- SAFFRON_GL_SHADERCORE_FUNC(Ctx->core, UseProgram)(Program);
1041+ SAFFRON_GL_SHADERCORE_FUNC(Ctx->core, UseProgram)(Prog);
1042+ IOo = IOi;
1043+ ").
1044+
1045+:- pragma foreign_proc("Java", use_program(Ctx::in, Prog::in, IOi::di, IOo::uo),
1046+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1047+ "
1048+ Ctx.useProgram(Prog);
6331049 IOo = IOi;
6341050 ").
6351051 :- pragma inline(use_program/4).
@@ -644,6 +1060,14 @@ create_program_array(ShaderCtx, Shaders, MaybeProgram, !IO) :-
6441060 IOo = IOi;
6451061 ").
6461062
1063+:- pragma foreign_proc("Java",
1064+ destroy_shader(Ctx::in, Shader::in, IOi::di, IOo::uo),
1065+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1066+ "
1067+ Ctx.deleteShader(Shader);
1068+ IOo = IOi;
1069+ ").
1070+
6471071 %-----------------------------------------------------------------------------%
6481072
6491073 :- pred create_shader(
@@ -678,6 +1102,24 @@ create_program_array(ShaderCtx, Shaders, MaybeProgram, !IO) :-
6781102 IOo = IOi;
6791103 ").
6801104
1105+:- pragma foreign_proc("Java",
1106+ create_shader(Ctx::in, Type::in, Src::in, Shader::uo, OK::uo, Err::out, IOi::di, IOo::uo),
1107+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1108+ "
1109+ Shader = Ctx.createShader(Type);
1110+ Ctx.shaderSource(Shader, Src);
1111+ Ctx.compileShader(Shader);
1112+ if(Ctx.shaderCompileStatus(Shader)){
1113+ OK = jmercury.bool.NO;
1114+ Err = """";
1115+ }
1116+ else{
1117+ OK = jmercury.bool.YES;
1118+ Err = Ctx.shaderInfoLog(Shader);
1119+ }
1120+ IOo = IOi;
1121+ ").
1122+
6811123 create_shader(Ctx, Type, Src, MaybeShader, !IO) :-
6821124 create_shader(Ctx, Type, Src, Shader, OK, Err, !IO),
6831125 (
@@ -730,6 +1172,15 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
7301172 IOo = IOi;
7311173 ").
7321174
1175+:- pragma foreign_proc("Java",
1176+ get_uniform_location(Ctx::in, Prog::in, Name::in, MaybeUniform::uo, IOi::di, IOo::uo),
1177+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1178+ "
1179+ int i = Ctx.getUniformLocation(Prog, Name);
1180+ MaybeUniform = jmercury.saffron__gl.MaybeInteger(i);
1181+ IOo = IOi;
1182+ ").
1183+
7331184 %-----------------------------------------------------------------------------%
7341185
7351186 :- pragma foreign_proc("C",
@@ -741,6 +1192,14 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
7411192 IOo = IOi;
7421193 ").
7431194
1195+:- pragma foreign_proc("Java",
1196+ uniform(Ctx::in, U::in, F1::in, IOi::di, IOo::uo),
1197+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1198+ "
1199+ Ctx.uniform(U, F1);
1200+ IOo = IOi;
1201+ ").
1202+
7441203 %-----------------------------------------------------------------------------%
7451204
7461205 :- pragma foreign_proc("C",
@@ -752,6 +1211,14 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
7521211 IOo = IOi;
7531212 ").
7541213
1214+:- pragma foreign_proc("Java",
1215+ uniform(Ctx::in, U::in, F1::in, F2::in, IOi::di, IOo::uo),
1216+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1217+ "
1218+ Ctx.uniform(U, F1, F2);
1219+ IOo = IOi;
1220+ ").
1221+
7551222 %-----------------------------------------------------------------------------%
7561223
7571224 :- pragma foreign_proc("C",
@@ -763,6 +1230,14 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
7631230 IOo = IOi;
7641231 ").
7651232
1233+:- pragma foreign_proc("Java",
1234+ uniform(Ctx::in, U::in, F1::in, F2::in, F3::in, IOi::di, IOo::uo),
1235+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1236+ "
1237+ Ctx.uniform(U, F1, F2, F3);
1238+ IOo = IOi;
1239+ ").
1240+
7661241 %-----------------------------------------------------------------------------%
7671242
7681243 :- pragma foreign_proc("C",
@@ -774,6 +1249,14 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
7741249 IOo = IOi;
7751250 ").
7761251
1252+:- pragma foreign_proc("Java",
1253+ uniform(Ctx::in, U::in, F1::in, F2::in, F3::in, F4::in, IOi::di, IOo::uo),
1254+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1255+ "
1256+ Ctx.uniform(U, F1, F2, F3, F4);
1257+ IOo = IOi;
1258+ ").
1259+
7771260 %-----------------------------------------------------------------------------%
7781261
7791262 :- pragma foreign_proc("C",
@@ -792,6 +1275,14 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
7921275 IOo = IOi;
7931276 ").
7941277
1278+:- pragma foreign_proc("Java",
1279+ uniform1(Ctx::in, U::in, FV::in, IOi::di, IOo::uo),
1280+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1281+ "
1282+ Ctx.uniform(U, FV[0]);
1283+ IOo = IOi;
1284+ ").
1285+
7951286 %-----------------------------------------------------------------------------%
7961287
7971288 :- pragma foreign_proc("C",
@@ -811,6 +1302,14 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
8111302 IOo = IOi;
8121303 ").
8131304
1305+:- pragma foreign_proc("Java",
1306+ uniform2(Ctx::in, U::in, FV::in, IOi::di, IOo::uo),
1307+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1308+ "
1309+ Ctx.uniform(U, FV[0], FV[1]);
1310+ IOo = IOi;
1311+ ").
1312+
8141313 %-----------------------------------------------------------------------------%
8151314
8161315 :- pragma foreign_proc("C",
@@ -831,6 +1330,14 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
8311330 IOo = IOi;
8321331 ").
8331332
1333+:- pragma foreign_proc("Java",
1334+ uniform3(Ctx::in, U::in, FV::in, IOi::di, IOo::uo),
1335+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1336+ "
1337+ Ctx.uniform(U, FV[0], FV[1], FV[2]);
1338+ IOo = IOi;
1339+ ").
1340+
8341341 %-----------------------------------------------------------------------------%
8351342
8361343 :- pragma foreign_proc("C",
@@ -852,6 +1359,14 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
8521359 IOo = IOi;
8531360 ").
8541361
1362+:- pragma foreign_proc("Java",
1363+ uniform4(Ctx::in, U::in, FV::in, IOi::di, IOo::uo),
1364+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1365+ "
1366+ Ctx.uniform(U, FV[0], FV[1], FV[2], FV[4]);
1367+ IOo = IOi;
1368+ ").
1369+
8551370 %-----------------------------------------------------------------------------%
8561371
8571372 :- pragma foreign_proc("C",
@@ -877,6 +1392,23 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
8771392 IOo = IOi;
8781393 ").
8791394
1395+:- pragma foreign_proc("Java",
1396+ uniform(Ctx::in, U::in,
1397+ A1::in, A2::in, A3::in,
1398+ B1::in, B2::in, B3::in,
1399+ C1::in, C2::in, C3::in,
1400+ IOi::di, IOo::uo),
1401+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1402+ "
1403+ float[] matrix = {
1404+ (float)A1, (float)A2, (float)A3,
1405+ (float)B1, (float)B2, (float)B3,
1406+ (float)C1, (float)C2, (float)C3
1407+ };
1408+ Ctx.uniformMat3x3(U, matrix);
1409+ IOo = IOi;
1410+ ").
1411+
8801412 %-----------------------------------------------------------------------------%
8811413
8821414 :- pragma foreign_proc("C",
@@ -897,6 +1429,17 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
8971429 IOo = IOi;
8981430 ").
8991431
1432+:- pragma foreign_proc("Java",
1433+ uniform3x3(Ctx::in, U::in, FV::in, IOi::di, IOo::uo),
1434+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1435+ "
1436+ float[] matrix = new float[9];
1437+ for(int i = 0; i < 9; i++)
1438+ matrix[i] = (float)FV[i];
1439+ Ctx.uniformMat3x3(U, matrix);
1440+ IOo = IOi;
1441+ ").
1442+
9001443 %-----------------------------------------------------------------------------%
9011444
9021445 :- pragma foreign_proc("C",
@@ -930,6 +1473,25 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
9301473 IOo = IOi;
9311474 ").
9321475
1476+:- pragma foreign_proc("Java",
1477+ uniform(Ctx::in, U::in,
1478+ A1::in, A2::in, A3::in, A4::in,
1479+ B1::in, B2::in, B3::in, B4::in,
1480+ C1::in, C2::in, C3::in, C4::in,
1481+ D1::in, D2::in, D3::in, D4::in,
1482+ IOi::di, IOo::uo),
1483+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1484+ "
1485+ float[] matrix = {
1486+ (float)A1, (float)A2, (float)A3, (float)A4,
1487+ (float)B1, (float)B2, (float)B3, (float)B4,
1488+ (float)C1, (float)C2, (float)C3, (float)C4,
1489+ (float)D1, (float)D2, (float)D3, (float)D4
1490+ };
1491+ Ctx.uniformMat4x4(U, matrix);
1492+ IOo = IOi;
1493+ ").
1494+
9331495 %-----------------------------------------------------------------------------%
9341496
9351497 :- pragma foreign_proc("C",
@@ -950,6 +1512,16 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
9501512 IOo = IOi;
9511513 ").
9521514
1515+:- pragma foreign_proc("Java",
1516+ uniform4x4(Ctx::in, U::in, FV::in, IOi::di, IOo::uo),
1517+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1518+ "
1519+ float[] matrix = new float[16];
1520+ for(int i = 0; i < 16; i++)
1521+ matrix[i] = (float)FV[i];
1522+ Ctx.uniformMat4x4(U, matrix);
1523+ IOo = IOi;
1524+ ").
9531525
9541526 %-----------------------------------------------------------------------------%
9551527
@@ -966,6 +1538,15 @@ maybe_uniform_yes(Uniform) = maybe.yes(Uniform).
9661538 IOo = IOi;
9671539 ").
9681540
1541+:- pragma foreign_proc("Java",
1542+ bind_attrib_location(Ctx::in, Program::in, Name::in, I::in, Attrib::uo, IOi::di, IOo::uo),
1543+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1544+ "
1545+ Ctx.bindAttribLocation(Program, I, Name);
1546+ Attrib = I;
1547+ IOo = IOi;
1548+ ").
1549+
9691550 %-----------------------------------------------------------------------------%
9701551
9711552 :- func maybe_vertex_attrib_no = (maybe.maybe(vertex_attrib)::uo) is det.
@@ -994,10 +1575,19 @@ maybe_vertex_attrib_yes(Attrib) = maybe.yes(Attrib).
9941575 IOo = IOi;
9951576 ").
9961577
1578+:- pragma foreign_proc("Java",
1579+ get_attrib_location(Ctx::in, Program::in, Name::in, MaybeAttrib::uo, IOi::di, IOo::uo),
1580+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1581+ "
1582+ int i = Ctx.getAttribLocation(Program, Name);
1583+ MaybeAttrib = jmercury.saffron__gl.MaybeInteger(i);
1584+ IOo = IOi;
1585+ ").
1586+
9971587 %-----------------------------------------------------------------------------%
9981588
9991589 :- pragma foreign_proc("C",
1000- vertex_attrib_pointer(Ctx::in, Attrib::in, Type::in, N::in, Stride::in, Offset::in, IOi::di, IOo::uo),
1590+ vertex_attrib_pointer(Ctx::in, Attrib::in, N::in, Type::in, Stride::in, Offset::in, IOi::di, IOo::uo),
10011591 [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
10021592 may_duplicate, does_not_affect_liveness],
10031593 "
@@ -1011,3 +1601,11 @@ maybe_vertex_attrib_yes(Attrib) = maybe.yes(Attrib).
10111601 IOo = IOi;
10121602 ").
10131603
1604+:- pragma foreign_proc("Java",
1605+ vertex_attrib_pointer(Ctx::in, Attrib::in, N::in, Type::in, Stride::in, Offset::in, IOi::di, IOo::uo),
1606+ [will_not_call_mercury, promise_pure, thread_safe, may_duplicate],
1607+ "
1608+ Ctx.vertexAttribPointer(Attrib, N, Type, Stride, Offset);
1609+ IOo = IOi;
1610+ ").
1611+
--- a/saffron.gl2.m
+++ b/saffron.gl2.m
@@ -239,6 +239,12 @@
239239
240240 %-----------------------------------------------------------------------------%
241241
242+:- pragma foreign_decl("Java", "
243+import org.lwjgl.opengl.GL11; // The name saffron.gl2 a lie, it's really 1.1
244+ ").
245+
246+%-----------------------------------------------------------------------------%
247+
242248 :- pragma foreign_decl("C", "
243249 // #define SAFFRON_GL2_DEBUG
244250 #ifdef SAFFRON_GL2_DEBUG
@@ -292,6 +298,10 @@ const char *Saffron_GL2_DebugError(void){
292298 saffron.draw.raise_matrix_stack_error,
293299 "Saffron_GL2_RaiseMatrixStackError").
294300
301+:- pragma foreign_export("Java",
302+ saffron.draw.raise_matrix_stack_error,
303+ "RaiseMatrixStackError").
304+
295305 %-----------------------------------------------------------------------------%
296306
297307 :- pragma foreign_decl("C",
@@ -366,6 +376,26 @@ const char *Saffron_GL2_DebugError(void){
366376 IOo = IOi;
367377 ").
368378
379+:- pragma foreign_proc("Java",
380+ set_matrix(
381+ V0::in, V1::in, V2::in, V3::in,
382+ V4::in, V5::in, V6::in, V7::in,
383+ V8::in, V9::in, V10::in, V11::in,
384+ V12::in, V13::in, V14::in, V15::in,
385+ IOi::di, IOo::uo),
386+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
387+ may_duplicate],
388+ "
389+ double[] matrix = {
390+ V0, V4, V8,V12,
391+ V1, V5, V9,V13,
392+ V2, V6,V10,V14,
393+ V3, V7,V11,V15
394+ };
395+ org.lwjgl.opengl.GL11.glLoadMatrixd(matrix);
396+ IOo = IOi;
397+ ").
398+
369399 %-----------------------------------------------------------------------------%
370400
371401 :- pred transform `with_type` matrix_pred `with_inst` matrix_pred.
@@ -401,6 +431,26 @@ const char *Saffron_GL2_DebugError(void){
401431 IOo = IOi;
402432 ").
403433
434+:- pragma foreign_proc("Java",
435+ transform(
436+ V0::in, V1::in, V2::in, V3::in,
437+ V4::in, V5::in, V6::in, V7::in,
438+ V8::in, V9::in, V10::in, V11::in,
439+ V12::in, V13::in, V14::in, V15::in,
440+ IOi::di, IOo::uo),
441+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception,
442+ may_duplicate],
443+ "
444+ double[] matrix = {
445+ V0, V4, V8,V12,
446+ V1, V5, V9,V13,
447+ V2, V6,V10,V14,
448+ V3, V7,V11,V15
449+ };
450+ org.lwjgl.opengl.GL11.glMultMatrixd(matrix);
451+ IOo = IOi;
452+ ").
453+
404454 %-----------------------------------------------------------------------------%
405455
406456 :- pred transform(mmath.matrix.matrix::in, io.io::di, io.io::uo) is det.
@@ -430,6 +480,13 @@ transform(Matrix, !IO) :-
430480 IOo = IOi;
431481 ").
432482
483+:- pragma foreign_proc("Java", identity(IOi::di, IOo::uo),
484+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
485+ "
486+ org.lwjgl.opengl.GL11.glLoadIdentity();
487+ IOo = IOi;
488+ ").
489+
433490 %-----------------------------------------------------------------------------%
434491
435492 :- pred push_matrix(io.io::di, io.io::uo) is det.
@@ -442,6 +499,13 @@ transform(Matrix, !IO) :-
442499 IOo = IOi;
443500 ").
444501
502+:- pragma foreign_proc("Java", push_matrix(IOi::di, IOo::uo),
503+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
504+ "
505+ org.lwjgl.opengl.GL11.glPushMatrix();
506+ IOo = IOi;
507+ ").
508+
445509 %-----------------------------------------------------------------------------%
446510
447511 :- pred pop_matrix(io.io::di, io.io::uo) is det.
@@ -455,6 +519,15 @@ transform(Matrix, !IO) :-
455519 IOo = IOi;
456520 ").
457521
522+:- pragma foreign_proc("Java", pop_matrix(IOi::di, IOo::uo),
523+ [may_call_mercury, promise_pure, thread_safe, may_duplicate],
524+ "
525+ org.lwjgl.opengl.GL11.glPopMatrix();
526+ if(GL11.glGetError() == org.lwjgl.opengl.GL11.GL_STACK_UNDERFLOW)
527+ RaiseMatrixStackError();
528+ IOo = IOi;
529+ ").
530+
458531 %-----------------------------------------------------------------------------%
459532
460533 :- instance saffron.draw.basic_transform(context(Ctx))
@@ -761,6 +834,13 @@ generate_attrib_tree(Ctx, Shader, !:Tree, !IO) :-
761834 IOo = IOi;
762835 ").
763836
837+:- pragma foreign_proc("Java", vertex(X::in, Y::in, Z::in, IOi::di, IOo::uo),
838+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
839+ "
840+ org.lwjgl.opengl.GL11.glVertex3d(X, Y, Z);
841+ IOo = IOi;
842+ ").
843+
764844 %-----------------------------------------------------------------------------%
765845
766846 :- pred tex_coord(float::in, float::in, io.io::di, io.io::uo) is det.
@@ -774,6 +854,13 @@ generate_attrib_tree(Ctx, Shader, !:Tree, !IO) :-
774854 IOo = IOi;
775855 ").
776856
857+:- pragma foreign_proc("Java", tex_coord(U::in, V::in, IOi::di, IOo::uo),
858+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
859+ "
860+ org.lwjgl.opengl.GL11.glTexCoord2d(U, V);
861+ IOo = IOi;
862+ ").
863+
777864 %-----------------------------------------------------------------------------%
778865
779866 :- pred tex_coord_i(int::in, int::in, io.io::di, io.io::uo) is det.
@@ -787,6 +874,13 @@ generate_attrib_tree(Ctx, Shader, !:Tree, !IO) :-
787874 IOo = IOi;
788875 ").
789876
877+:- pragma foreign_proc("Java", tex_coord_i(U::in, V::in, IOi::di, IOo::uo),
878+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
879+ "
880+ org.lwjgl.opengl.GL11.glTexCoord2i(U, V);
881+ IOo = IOi;
882+ ").
883+
790884 %-----------------------------------------------------------------------------%
791885
792886 :- pred color(int::in, int::in, int::in, int::in, io.io::di, io.io::uo) is det.
@@ -800,6 +894,14 @@ generate_attrib_tree(Ctx, Shader, !:Tree, !IO) :-
800894 IOo = IOi;
801895 ").
802896
897+:- pragma foreign_proc("Java",
898+ color(R::in, G::in, B::in, A::in, IOi::di, IOo::uo),
899+ [will_not_call_mercury, promise_pure, thread_safe, will_not_throw_exception],
900+ "
901+ org.lwjgl.opengl.GL11.glColor4ub((byte)R, (byte)G, (byte)B, (byte)A);
902+ IOo = IOi;
903+ ").
904+
803905 %-----------------------------------------------------------------------------%
804906
805907 :- pred color(color::in, io.io::di, io.io::uo) is det.
@@ -849,6 +951,13 @@ draw_vertex3d(saffron.geometry.vertex(vector(X, Y, Z), U, V), C, !IO) :-
849951 IOo = IOi;
850952 ").
851953
954+:- pragma foreign_proc("Java", begin(Type::in, IOi::di, IOo::uo),
955+ [promise_pure, thread_safe, will_not_throw_exception],
956+ "
957+ org.lwjgl.opengl.GL11.glBegin(jmercury.saffron__gl.PrimitiveTypeToGL(Type));
958+ IOo = IOi;
959+ ").
960+
852961 %-----------------------------------------------------------------------------%
853962
854963 :- pred end(io.io::di, io.io::uo) is det.
@@ -862,6 +971,13 @@ draw_vertex3d(saffron.geometry.vertex(vector(X, Y, Z), U, V), C, !IO) :-
862971 IOo = IOi;
863972 ").
864973
974+:- pragma foreign_proc("Java", end(IOi::di, IOo::uo),
975+ [promise_pure, thread_safe, will_not_throw_exception],
976+ "
977+ org.lwjgl.opengl.GL11.glEnd();
978+ IOo = IOi;
979+ ").
980+
865981 %-----------------------------------------------------------------------------%
866982
867983 :- pred draw_shape2d(shape(mmath.vector.vector2)::in, io.io::di, io.io::uo) is det.
@@ -980,6 +1096,24 @@ draw_shape3d(Shape, !IO) :-
9801096 */
9811097 ").
9821098
1099+:- pragma foreign_proc("Java", init(IOi::di, IOo::uo),
1100+ [promise_pure, thread_safe, will_not_throw_exception, no_sharing],
1101+ "
1102+ IOo = IOi;
1103+ GL11.glEnable(GL11.GL_BLEND);
1104+ GL11.glBlendFunc(GL11.GL_SRC_ALPHA, org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA);
1105+ GL11.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
1106+ GL11.glColor4d(1.0, 1.0, 1.0, 1.0);
1107+ GL11.glLineWidth(2.0f); // This is legacy for the Z2 engine (editor for Java)
1108+ GL11.glEnable(GL11.GL_TEXTURE_2D);
1109+ GL11.glEnable(GL11.GL_DEPTH_TEST);
1110+ GL11.glLoadIdentity();
1111+ GL11.glMatrixMode(GL11.GL_PROJECTION);
1112+ GL11.glLoadIdentity();
1113+ GL11.glMatrixMode(GL11.GL_MODELVIEW);
1114+ GL11.glLoadIdentity();
1115+ ").
1116+
9831117 %-----------------------------------------------------------------------------%
9841118
9851119 :- func complete_load_ctx(string, maybe.maybe_error(T)) = maybe.maybe(T).
--- a/saffron.m
+++ b/saffron.m
@@ -140,6 +140,50 @@
140140 :- use_module string.
141141
142142 %-----------------------------------------------------------------------------%
143+% Utilities used by Java code.
144+:- pragma foreign_decl("Java", "
145+import jmercury.list.List_1;
146+import jmercury.saffron__geometry.Vertex_1;
147+ ").
148+
149+:- pragma foreign_code("Java", "
150+public static int ListLength(List_1<?> l){
151+ int i = 0;
152+ while(!jmercury.list.is_empty(l)){
153+ i++;
154+ l = jmercury.list.det_tail(l);
155+ }
156+ return i;
157+}
158+public static int WriteVector(double[] to, jmercury.mmath__vector__vector2.Vector_0 vector, int i){
159+ to[i++] = vector.x;
160+ to[i++] = vector.y;
161+ return i;
162+}
163+public static int WriteVector(double[] to, jmercury.mmath__vector__vector3.Vector_0 vector, int i){
164+ to[i++] = vector.x;
165+ to[i++] = vector.y;
166+ to[i++] = vector.z;
167+ return i;
168+}
169+public static int WriteVertexUV(double[] to, Vertex_1<?> vertex, int i){
170+ to[i++] = vertex.u;
171+ to[i++] = vertex.v;
172+ return i;
173+}
174+public static int WriteVertex2(double[] to, Vertex_1<jmercury.mmath__vector__vector2.Vector_0> vertex, int i){
175+ i = WriteVector(to, vertex.vec, i);
176+ i = WriteVertexUV(to, vertex, i);
177+ return i;
178+}
179+public static int WriteVertex3(double[] to, Vertex_1<jmercury.mmath__vector__vector3.Vector_0> vertex, int i){
180+ i = WriteVector(to, vertex.vec, i);
181+ i = WriteVertexUV(to, vertex, i);
182+ return i;
183+}
184+ ").
185+
186+%-----------------------------------------------------------------------------%
143187
144188 default_load_function(_, _, maybe.error("load_function not supported"), !IO).
145189