diff --git a/examples/resources/gol.glsl b/examples/resources/gol.glsl new file mode 100644 index 0000000..1066e27 --- /dev/null +++ b/examples/resources/gol.glsl @@ -0,0 +1,57 @@ +#version 430 + +#define GOL_WIDTH 1024 + +layout (local_size_x = 16, local_size_y = 16, local_size_x = 1) in; + +layout(std430, binding = 1) readonly restrict buffer golLayout { + int golBuffer[]; // golBuffer[x, y] = golBuffer[x + gl_NumWorkGroups.x * y] +}; + +layout(std430, set = 1, binding = 2) writeonly restrict buffer golLayout2 { + int golBufferDest[]; // golBufferDest[x, y] = golBufferDest[x + gl_NumWorkGroups.x * y] +}; + +#define fetchGol(x, y) ((((x) < 0) || ((y) < 0) || ((x) > GOL_WIDTH) || ((y) > GOL_WIDTH)) \ + ? (0) \ + : golBuffer[(x) + GOL_WIDTH * (y)]) + +#define setGol(x, y, value) golBufferDest[(x) + GOL_WIDTH * (y)] = value + +void main() +{ + uint neighbour_count = 0; + uint x = gl_GlobalInvocationID.x; + uint y = gl_GlobalInvocationID.y; + + // Top left + neighbour_count += fetchGol(x - 1, y - 1); + + // Top middle + neighbour_count += fetchGol(x, y - 1); + + // Top right + neighbour_count += fetchGol(x + 1, y - 1); + + // Left + neighbour_count += fetchGol(x - 1, y); + + // Right + neighbour_count += fetchGol(x + 1, y); + + // Bottom left + neighbour_count += fetchGol(x - 1, y + 1); + + // Bottom middle + neighbour_count += fetchGol(x, y + 1); + + // Bottom right + neighbour_count += fetchGol(x + 1, y + 1); + + if (neighbour_count == 3) + setGol(x, y, 1); + else if (neighbour_count == 2) + setGol(x, y, fetchGol(x, y)); + else + setGol(x, y, 0); +} \ No newline at end of file diff --git a/examples/shaders_compute_shader.lua b/examples/shaders_compute_shader.lua new file mode 100644 index 0000000..1918bb1 --- /dev/null +++ b/examples/shaders_compute_shader.lua @@ -0,0 +1,105 @@ +local ffi = require "ffi" +local width, height = 1024, 1024 +rl.InitWindow(width, height, "raylib-lua [core] example - compute shader") +local computeShaderCode +do + local f = io.open("resources/gol.glsl", "rb") + assert(f, "Can't read resources/gol.glsl file") + computeShaderCode = f:read "*a" + f:close() +end + +local computeShader = rl.rlCompileShader(computeShaderCode, rl.RL_COMPUTE_SHADER) +local csProgram = rl.rlLoadComputeShaderProgram(computeShader) +print(csProgram) + +local ssbo_size = ffi.sizeof("int32_t[?]", width * height) +local ssbo_baseBuffer = ffi.new("int32_t[?]", width * height) +for i=0,width * height - 1 do + ssbo_baseBuffer[i] = 0 +end + +local shader_framebuffer = rl.new("Color[?]", width * height) +local ssbo_image = rl.new "Image" ---@type Image + +ssbo_image.data = shader_framebuffer +ssbo_image.width = width +ssbo_image.height = height +ssbo_image.format = rl.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 +ssbo_image.mipmaps = 1 + +local ssboA = rl.rlLoadShaderBuffer(ssbo_size, ssbo_baseBuffer, rl.RL_STREAM_COPY) +local ssboB = rl.rlLoadShaderBuffer(ssbo_size, ssbo_baseBuffer, rl.RL_STREAM_COPY) + +-- Create a texture to apply shader +local renderTexture = rl.LoadRenderTexture(width, height) + +local renderShader = rl.LoadShaderFromMemory(nil, [[ +#version 430 +out vec4 finalColor; +in vec2 fragTexCoord; + +layout(std430, binding = 1) readonly buffer golLayout { + int golBuffer[]; +}; + +uniform vec2 res; + +void main() +{ + ivec2 coords = ivec2(fragTexCoord * res); + + if (golBuffer[coords.x + coords.y * uint(res.x)] == 1) + finalColor = vec4(1.0); + else + finalColor = vec4(0.0, 0.0, 0.0, 1.0); +} +]]) + +local resolution = ffi.new("float[2]", width, height) +local res_uniform = rl.GetShaderLocation(renderShader, "res") + +while not rl.WindowShouldClose() do + rl.BeginDrawing() + + if rl.IsMouseButtonDown(rl.MOUSE_BUTTON_LEFT) then + rl.rlReadShaderBufferElements(ssboB, ssbo_baseBuffer, ssbo_size, 0) + + -- Correct colors + for i=0,(width * height)-1 do + local toggled = ssbo_baseBuffer[i] + + shader_framebuffer[i].r = toggled * 255 + shader_framebuffer[i].g = toggled * 255 + shader_framebuffer[i].b = toggled * 255 + shader_framebuffer[i].a = toggled * 255 + end + + rl.ImageDrawRectangleV(ssbo_image, rl.GetMousePosition(), rl.new("Vector2", 25, 25), rl.WHITE) + + for x=0,ssbo_image.width-1 do + for y=0,ssbo_image.height-1 do + ssbo_baseBuffer[x + y * width] = (shader_framebuffer[x + y * width].r > 0) + end + end + rl.rlUpdateShaderBufferElements(ssboB, ssbo_baseBuffer, ssbo_size, 0) + else + rl.rlEnableShader(csProgram) + rl.rlBindShaderBuffer(ssboA, 1) + rl.rlBindShaderBuffer(ssboB, 2) + rl.rlComputeShaderDispatch(width / 16, height / 16, 1) + rl.rlDisableShader() + end + + rl.ClearBackground(rl.BLANK) + rl.SetShaderValue(renderShader, res_uniform, resolution, rl.SHADER_UNIFORM_VEC2) + rl.BeginShaderMode(renderShader) + rl.DrawTexture(renderTexture.texture, 0, 0, rl.WHITE) + rl.EndShaderMode() + rl.DrawFPS(0, 0) + rl.EndDrawing() + + ssboA, ssboB = ssboB, ssboA +end + +rl.CloseWindow() diff --git a/makefile b/makefile index 43c7cae..fb4cb1e 100644 --- a/makefile +++ b/makefile @@ -6,7 +6,7 @@ LUA ?= luajit/src/luajit WINDRES ?= windres -CFLAGS += -Iluajit/src -Iraylib/src -Iraygui/src +CFLAGS += -Iluajit/src -Iraylib/src -Iraygui/src -DSUPPORT_COMPUTE_SHADERS LDFLAGS += luajit/src/libluajit.a raylib/src/libraylib.a MODULES := raymath rlgl easings gestures physac raygui diff --git a/src/raylib.lua b/src/raylib.lua index 99402a4..fd5cb6f 100644 --- a/src/raylib.lua +++ b/src/raylib.lua @@ -809,6 +809,47 @@ ffi.cdef [[ } rlRenderBatch; ]] +-- rlgl defines +rl.RL_TEXTURE_WRAP_S = 0x2802 +rl.RL_TEXTURE_WRAP_T = 0x2803 +rl.RL_TEXTURE_MAG_FILTER = 0x2800 +rl.RL_TEXTURE_MIN_FILTER = 0x2801 +rl.RL_TEXTURE_FILTER_NEAREST = 0x2600 +rl.RL_TEXTURE_FILTER_LINEAR = 0x2601 +rl.RL_TEXTURE_FILTER_MIP_NEAREST = 0x2700 +rl.RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR = 0x2702 +rl.RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST = 0x2701 +rl.RL_TEXTURE_FILTER_MIP_LINEAR = 0x2703 +rl.RL_TEXTURE_FILTER_ANISOTROPIC = 0x3000 +rl.RL_TEXTURE_WRAP_REPEAT = 0x2901 +rl.RL_TEXTURE_WRAP_CLAMP = 0x812F +rl.RL_TEXTURE_WRAP_MIRROR_REPEAT = 0x8370 +rl.RL_TEXTURE_WRAP_MIRROR_CLAMP = 0x8742 + +rl.RL_MODELVIEW = 0x1700 +rl.RL_PROJECTION = 0x1701 +rl.RL_TEXTURE = 0x1702 +rl.RL_LINES = 0x0001 +rl.RL_TRIANGLES = 0x0004 +rl.RL_QUADS = 0x0007 + +rl.RL_UNSIGNED_BYTE = 0x1401 +rl.RL_FLOAT = 0x1406 + +rl.RL_STREAM_DRAW = 0x88E0 +rl.RL_STREAM_READ = 0x88E1 +rl.RL_STREAM_COPY = 0x88E2 +rl.RL_STATIC_DRAW = 0x88E4 +rl.RL_STATIC_READ = 0x88E5 +rl.RL_STATIC_COPY = 0x88E6 +rl.RL_DYNAMIC_DRAW = 0x88E8 +rl.RL_DYNAMIC_READ = 0x88E9 +rl.RL_DYNAMIC_COPY = 0x88EA + +rl.RL_FRAGMENT_SHADER = 0x8B30 +rl.RL_VERTEX_SHADER = 0x8B31 +rl.RL_COMPUTE_SHADER = 0x91B9 + -- Physac cdef ffi.cdef [[ typedef enum PhysicsShapeType { PHYSICS_CIRCLE = 0, PHYSICS_POLYGON } PhysicsShapeType; diff --git a/tools/rlgl.h b/tools/rlgl.h index a5b9dbc..3665918 100644 --- a/tools/rlgl.h +++ b/tools/rlgl.h @@ -116,6 +116,16 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count) void rlSetUniformMatrix(int locIndex, Matrix mat) void rlSetUniformSampler(int locIndex, unsigned int textureId) void rlSetShader(unsigned int id, int *locs) +unsigned int rlLoadComputeShaderProgram(int shaderId) +void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ) +unsigned int rlLoadShaderBuffer(unsigned long long size, const void *data, int usageHint) +void rlUnloadShaderBuffer(unsigned int ssboId) +void rlUpdateShaderBufferElements(unsigned int id, const void *data, unsigned long long dataSize, unsigned long long offset) +unsigned long long rlGetShaderBufferSize(unsigned int id) +void rlReadShaderBufferElements(unsigned int id, void *dest, unsigned long long count, unsigned long long offset) +void rlBindShaderBuffer(unsigned int id, unsigned int index) +void rlCopyBuffersElements(unsigned int destId, unsigned int srcId, unsigned long long destOffset, unsigned long long srcOffset, unsigned long long count) +void rlBindImageTexture(unsigned int id, unsigned int index, unsigned int format, int readonly) Matrix rlGetMatrixModelview(void) Matrix rlGetMatrixProjection(void) Matrix rlGetMatrixTransform(void)