From e7ab53310e6233aefc59ef9dfc73eee33f026d58 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Fri, 23 Jan 2026 09:47:27 +0000 Subject: [PATCH] ffi progress --- build-unix-debug.sh | 1 - ffi/gles3-export.c | 99 ----------------------- ffi/gles3-import.sml | 2 +- ffi/glfw-export.c | 99 +++++++++++++++++++++++ ffi/glfw-import.sml | 1 + ffi/rgfw-export.c | 94 +++++++++++++++++++++ ffi/{rgfw-export.sml => rgfw-import.sml} | 0 shell/glfw-loop.sml | 3 +- shf-rgfw | Bin 243680 -> 245656 bytes shf-rgfw.mlb | 3 +- 10 files changed, 199 insertions(+), 103 deletions(-) delete mode 100644 ffi/gles3-export.c rename ffi/{rgfw-export.sml => rgfw-import.sml} (100%) diff --git a/build-unix-debug.sh b/build-unix-debug.sh index 642b991..9ddbd60 100755 --- a/build-unix-debug.sh +++ b/build-unix-debug.sh @@ -4,5 +4,4 @@ mlton -const 'Exn.keepHistory true' -link-opt "$(pkg-config --cflags glfw3) $(pk shf.mlb \ ffi/glad.c \ ffi/glfw-export.c \ - ffi/gles3-export.c \ ffi/glfw-input.c diff --git a/ffi/gles3-export.c b/ffi/gles3-export.c deleted file mode 100644 index 4515f05..0000000 --- a/ffi/gles3-export.c +++ /dev/null @@ -1,99 +0,0 @@ -#include "export.h" -#include "glad.h" -#include -#include - -// OpenGL constants used below -unsigned int VERTEX_SHADER = GL_VERTEX_SHADER; -unsigned int FRAGMENT_SHADER = GL_FRAGMENT_SHADER; -unsigned int TRIANGLES = GL_TRIANGLES; -unsigned int STATIC_DRAW = GL_STATIC_DRAW; -unsigned int DYNAMIC_DRAW = GL_DYNAMIC_DRAW; - -// OpenGL functions used below -void loadGlad() { - gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); - glEnable(GL_DEPTH_TEST); -} - -void viewport(int width, int height) { - glViewport(0, 0, width, height); -} - -void clearColor(float r, float g, float b, float a) { - glClearColor(r, g, b, a); -} - -void clear() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -unsigned int createBuffer() { - unsigned int buffer; - glGenBuffers(1, &buffer); - return buffer; -} - -void bindBuffer(unsigned int buffer) { - glBindBuffer(GL_ARRAY_BUFFER, buffer); -} - -void bufferData(float* vector, int vectorLength, unsigned int updateMode) { - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vectorLength, vector, updateMode); -} - -unsigned int createShader(unsigned int shaderType) { - return glCreateShader(shaderType); -} - -void shaderSource(unsigned int shader, const char *sourceString) { - glShaderSource(shader, 1, &sourceString, NULL); -} - -void compileShader(unsigned int shader) { - glCompileShader(shader); -} - -void deleteShader(unsigned int shader) { - glDeleteShader(shader); -} - -void vertexAttribPointer(int location, int numVecComponents, int stride, int offset) { - glVertexAttribPointer(location, numVecComponents, GL_FLOAT, GL_FALSE, stride * sizeof(float), (void*)offset); -} - -void enableVertexAttribArray(int location) { - glEnableVertexAttribArray(location); -} - -unsigned int createProgram() { - return glCreateProgram(); -} - -void attachShader(unsigned int program, unsigned int shader) { - glAttachShader(program, shader); -} - -void linkProgram(unsigned int program) { - glLinkProgram(program); -} - -void useProgram(unsigned int program) { - glUseProgram(program); -} - -void deleteProgram(unsigned int program) { - glDeleteProgram(program); -} - -void drawArrays(unsigned int drawMode, int startIndex, int numVertices) { - glDrawArrays(drawMode, startIndex, numVertices); -} - -int getUniformLocation(unsigned int program, const char *uniformName) { - glGetUniformLocation(program, uniformName); -} - -void uniform4f(int uniformLocation, float a, float b, float c, float d) { - glUniform4f(uniformLocation, a, b, c, d); -} diff --git a/ffi/gles3-import.sml b/ffi/gles3-import.sml index 1afc329..357977a 100644 --- a/ffi/gles3-import.sml +++ b/ffi/gles3-import.sml @@ -29,8 +29,8 @@ struct val DYNAMIC_DRAW = DYNAMIC_DRAW () (* OpenGL functions used. *) - val loadGlad = _import "loadGlad" public : unit -> unit; val viewport = _import "viewport" public : int * int -> unit; + val enableDepthTest = _import "enableDepthTest" : unit -> unit; val createBuffer = _import "createBuffer" public : unit -> buffer; val bindBuffer = _import "bindBuffer" public : buffer -> unit; diff --git a/ffi/glfw-export.c b/ffi/glfw-export.c index 648bfff..d1334f5 100644 --- a/ffi/glfw-export.c +++ b/ffi/glfw-export.c @@ -1,6 +1,8 @@ #include #define GLFW_INCLUDE_NONE +#include "glad.h" #include +#include // GLFW constants used below int CONTEXT_VERSION_MAJOR = GLFW_CONTEXT_VERSION_MAJOR; @@ -44,3 +46,100 @@ void setClipboardString (GLFWwindow *window, const char *copyString) { glfwSetClipboardString(window, copyString); } +void loadGlad() { + gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); +} + +// OpenGL constants used below +unsigned int VERTEX_SHADER = GL_VERTEX_SHADER; +unsigned int FRAGMENT_SHADER = GL_FRAGMENT_SHADER; +unsigned int TRIANGLES = GL_TRIANGLES; +unsigned int STATIC_DRAW = GL_STATIC_DRAW; +unsigned int DYNAMIC_DRAW = GL_DYNAMIC_DRAW; + +// OpenGL functions used below +void enableDepthTest() { + glEnable(GL_DEPTH_TEST); +} + +void viewport(int width, int height) { + glViewport(0, 0, width, height); +} + +void clearColor(float r, float g, float b, float a) { + glClearColor(r, g, b, a); +} + +void clear() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +unsigned int createBuffer() { + unsigned int buffer; + glGenBuffers(1, &buffer); + return buffer; +} + +void bindBuffer(unsigned int buffer) { + glBindBuffer(GL_ARRAY_BUFFER, buffer); +} + +void bufferData(float* vector, int vectorLength, unsigned int updateMode) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vectorLength, vector, updateMode); +} + +unsigned int createShader(unsigned int shaderType) { + return glCreateShader(shaderType); +} + +void shaderSource(unsigned int shader, const char *sourceString) { + glShaderSource(shader, 1, &sourceString, NULL); +} + +void compileShader(unsigned int shader) { + glCompileShader(shader); +} + +void deleteShader(unsigned int shader) { + glDeleteShader(shader); +} + +void vertexAttribPointer(int location, int numVecComponents, int stride, int offset) { + glVertexAttribPointer(location, numVecComponents, GL_FLOAT, GL_FALSE, stride * sizeof(float), (void*)offset); +} + +void enableVertexAttribArray(int location) { + glEnableVertexAttribArray(location); +} + +unsigned int createProgram() { + return glCreateProgram(); +} + +void attachShader(unsigned int program, unsigned int shader) { + glAttachShader(program, shader); +} + +void linkProgram(unsigned int program) { + glLinkProgram(program); +} + +void useProgram(unsigned int program) { + glUseProgram(program); +} + +void deleteProgram(unsigned int program) { + glDeleteProgram(program); +} + +void drawArrays(unsigned int drawMode, int startIndex, int numVertices) { + glDrawArrays(drawMode, startIndex, numVertices); +} + +int getUniformLocation(unsigned int program, const char *uniformName) { + glGetUniformLocation(program, uniformName); +} + +void uniform4f(int uniformLocation, float a, float b, float c, float d) { + glUniform4f(uniformLocation, a, b, c, d); +} diff --git a/ffi/glfw-import.sml b/ffi/glfw-import.sml index 44ece82..b8ff24a 100644 --- a/ffi/glfw-import.sml +++ b/ffi/glfw-import.sml @@ -21,4 +21,5 @@ struct val waitEvents = _import "waitEvents" public reentrant : unit -> unit; val swapBuffers = _import "swapBuffers" public : window -> unit; val setClipboardString = _import "setClipboardString" public : window * string -> unit; + val loadGlad = _import "loadGlad" public : unit -> unit; end diff --git a/ffi/rgfw-export.c b/ffi/rgfw-export.c index 69c728d..35ee9b1 100644 --- a/ffi/rgfw-export.c +++ b/ffi/rgfw-export.c @@ -27,3 +27,97 @@ bool shouldCloseWindow(RGFW_window* window) { void swapBuffers(RGFW_window* window) { RGFW_window_swapBuffers_OpenGL(window); } + +// OpenGL constants used below +unsigned int VERTEX_SHADER = GL_VERTEX_SHADER; +unsigned int FRAGMENT_SHADER = GL_FRAGMENT_SHADER; +unsigned int TRIANGLES = GL_TRIANGLES; +unsigned int STATIC_DRAW = GL_STATIC_DRAW; +unsigned int DYNAMIC_DRAW = GL_DYNAMIC_DRAW; + +// OpenGL functions used below +void enableDepthTest() { + glEnable(GL_DEPTH_TEST); +} + +void viewport(int width, int height) { + glViewport(0, 0, width, height); +} + +void clearColor(float r, float g, float b, float a) { + glClearColor(r, g, b, a); +} + +void clear() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +unsigned int createBuffer() { + unsigned int buffer; + glGenBuffers(1, &buffer); + return buffer; +} + +void bindBuffer(unsigned int buffer) { + glBindBuffer(GL_ARRAY_BUFFER, buffer); +} + +void bufferData(float* vector, int vectorLength, unsigned int updateMode) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vectorLength, vector, updateMode); +} + +unsigned int createShader(unsigned int shaderType) { + return glCreateShader(shaderType); +} + +void shaderSource(unsigned int shader, const char *sourceString) { + glShaderSource(shader, 1, &sourceString, NULL); +} + +void compileShader(unsigned int shader) { + glCompileShader(shader); +} + +void deleteShader(unsigned int shader) { + glDeleteShader(shader); +} + +void vertexAttribPointer(int location, int numVecComponents, int stride, int offset) { + glVertexAttribPointer(location, numVecComponents, GL_FLOAT, GL_FALSE, stride * sizeof(float), (void*)offset); +} + +void enableVertexAttribArray(int location) { + glEnableVertexAttribArray(location); +} + +unsigned int createProgram() { + return glCreateProgram(); +} + +void attachShader(unsigned int program, unsigned int shader) { + glAttachShader(program, shader); +} + +void linkProgram(unsigned int program) { + glLinkProgram(program); +} + +void useProgram(unsigned int program) { + glUseProgram(program); +} + +void deleteProgram(unsigned int program) { + glDeleteProgram(program); +} + +void drawArrays(unsigned int drawMode, int startIndex, int numVertices) { + glDrawArrays(drawMode, startIndex, numVertices); +} + +int getUniformLocation(unsigned int program, const char *uniformName) { + glGetUniformLocation(program, uniformName); +} + +void uniform4f(int uniformLocation, float a, float b, float c, float d) { + glUniform4f(uniformLocation, a, b, c, d); +} diff --git a/ffi/rgfw-export.sml b/ffi/rgfw-import.sml similarity index 100% rename from ffi/rgfw-export.sml rename to ffi/rgfw-import.sml diff --git a/shell/glfw-loop.sml b/shell/glfw-loop.sml index 504ed9f..64a8807 100644 --- a/shell/glfw-loop.sml +++ b/shell/glfw-loop.sml @@ -170,7 +170,8 @@ struct val _ = Glfw.windowHint (Glfw.DEPRECATED (), Glfw.FALSE ()) val window = Glfw.createWindow (1920, 1080, "shf") val _ = Glfw.makeContextCurrent window - val _ = Gles3.loadGlad () + val _ = Glfw.loadGlad () + val _ = Gles3.enableDepthTest () (* load file intol gap buffer and create initial app *) val io = TextIO.openIn "temp.txt" diff --git a/shf-rgfw b/shf-rgfw index 7565d3a94e81fb74d5841c6186b6715c79bcce4e..1df92f1086f66859003437579313b80aa924e522 100755 GIT binary patch delta 79336 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