From bd198aeada1ea94b69fed5a6c9a7acf0759c9884 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 10 Jun 2024 23:37:54 -0400 Subject: [PATCH 01/20] Fix #3460 --- core/time/datetime/datetime.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/time/datetime/datetime.odin b/core/time/datetime/datetime.odin index e15ced5a5..89fa2ce98 100644 --- a/core/time/datetime/datetime.odin +++ b/core/time/datetime/datetime.odin @@ -127,13 +127,13 @@ days_remaining :: proc "contextless" (date: Date) -> (days_remaining: i64, err: return delta.days, .None } -last_day_of_month :: proc "contextless" (#any_int year: i64, #any_int month: i8) -> (day: i64, err: Error) { +last_day_of_month :: proc "contextless" (#any_int year: i64, #any_int month: i8) -> (day: i8, err: Error) { // Not using formula 2.27 from the book. This is far simpler and gives the same answer. validate(Date{year, month, 1}) or_return month_days := MONTH_DAYS - day = i64(month_days[month]) + day = month_days[month] if month == 2 && is_leap_year(year) { day += 1 } From 34af2bb8adc7f1cfb91530bcdcc954d72af68aee Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Tue, 11 Jun 2024 08:34:45 +0200 Subject: [PATCH 02/20] Moved rlgl.odin to subpackage 'raylib/rlgl' --- vendor/raylib/{ => rlgl}/rlgl.odin | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename vendor/raylib/{ => rlgl}/rlgl.odin (100%) diff --git a/vendor/raylib/rlgl.odin b/vendor/raylib/rlgl/rlgl.odin similarity index 100% rename from vendor/raylib/rlgl.odin rename to vendor/raylib/rlgl/rlgl.odin From d2cd96c3c8bc271916ebaf189226ac84f23eed4d Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Tue, 11 Jun 2024 08:46:44 +0200 Subject: [PATCH 03/20] Made rlgl.odin work as a subpackage of raylib. So now you import vendor:raylib/rlgl. Instead of rl.rlBegin(rl.RL_TRIANGLES) you now type rlgl.Begin(rlgl.TRIANGLES). --- vendor/raylib/rlgl/rlgl.odin | 479 ++++++++++++++++++----------------- 1 file changed, 242 insertions(+), 237 deletions(-) diff --git a/vendor/raylib/rlgl/rlgl.odin b/vendor/raylib/rlgl/rlgl.odin index c9e8c28c2..4a4ab4b7f 100644 --- a/vendor/raylib/rlgl/rlgl.odin +++ b/vendor/raylib/rlgl/rlgl.odin @@ -105,25 +105,25 @@ **********************************************************************************************/ -package raylib +package rlgl import "core:c" -RLGL_VERSION :: "4.5" +RLGL_VERSION :: "5.0" when ODIN_OS == .Windows { foreign import lib { - "windows/raylib.lib", + "../windows/raylib.lib", "system:Winmm.lib", "system:Gdi32.lib", "system:User32.lib", "system:Shell32.lib", } } else when ODIN_OS == .Linux { - foreign import lib "linux/libraylib.a" + foreign import lib "../linux/libraylib.a" } else when ODIN_OS == .Darwin { foreign import lib { - "macos-arm64/libraylib.a" when ODIN_ARCH == .arm64 else "macos/libraylib.a", + "../macos-arm64/libraylib.a" when ODIN_ARCH == .arm64 else "../macos/libraylib.a", "system:Cocoa.framework", "system:OpenGL.framework", "system:IOKit.framework", @@ -132,122 +132,122 @@ when ODIN_OS == .Windows { foreign import lib "system:raylib" } -RL_GRAPHICS_API_OPENGL_11 :: false -RL_GRAPHICS_API_OPENGL_21 :: true -RL_GRAPHICS_API_OPENGL_33 :: RL_GRAPHICS_API_OPENGL_21 // default currently -RL_GRAPHICS_API_OPENGL_ES2 :: false -RL_GRAPHICS_API_OPENGL_43 :: false -RL_GRAPHICS_API_OPENGL_ES3 :: false +GRAPHICS_API_OPENGL_11 :: false +GRAPHICS_API_OPENGL_21 :: true +GRAPHICS_API_OPENGL_33 :: GRAPHICS_API_OPENGL_21 // default currently +GRAPHICS_API_OPENGL_ES2 :: false +GRAPHICS_API_OPENGL_43 :: false +GRAPHICS_API_OPENGL_ES3 :: false -when RL_GRAPHICS_API_OPENGL_ES3 { - RL_GRAPHICS_API_OPENGL_ES2 :: true +when GRAPHICS_API_OPENGL_ES3 { + GRAPHICS_API_OPENGL_ES2 :: true } -when !RL_GRAPHICS_API_OPENGL_ES2 { +when !GRAPHICS_API_OPENGL_ES2 { // This is the maximum amount of elements (quads) per batch // NOTE: Be careful with text, every letter maps to a quad - RL_DEFAULT_BATCH_BUFFER_ELEMENTS :: 8192 + DEFAULT_BATCH_BUFFER_ELEMENTS :: 8192 } else { // We reduce memory sizes for embedded systems (RPI and HTML5) // NOTE: On HTML5 (emscripten) this is allocated on heap, // by default it's only 16MB!...just take care... - RL_DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048 + DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048 } -RL_DEFAULT_BATCH_BUFFERS :: 1 // Default number of batch buffers (multi-buffering) -RL_DEFAULT_BATCH_DRAWCALLS :: 256 // Default number of batch draw calls (by state changes: mode, texture) -RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS :: 4 // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture()) +DEFAULT_BATCH_BUFFERS :: 1 // Default number of batch buffers (multi-buffering) +DEFAULT_BATCH_DRAWCALLS :: 256 // Default number of batch draw calls (by state changes: mode, texture) +DEFAULT_BATCH_MAX_TEXTURE_UNITS :: 4 // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture()) // Internal Matrix stack -RL_MAX_MATRIX_STACK_SIZE :: 32 // Maximum size of Matrix stack +MAX_MATRIX_STACK_SIZE :: 32 // Maximum size of Matrix stack // Shader limits -RL_MAX_SHADER_LOCATIONS :: 32 // Maximum number of shader locations supported +MAX_SHADER_LOCATIONS :: 32 // Maximum number of shader locations supported // Projection matrix culling -RL_CULL_DISTANCE_NEAR :: 0.01 // Default near cull distance -RL_CULL_DISTANCE_FAR :: 1000.0 // Default far cull distance +CULL_DISTANCE_NEAR :: 0.01 // Default near cull distance +CULL_DISTANCE_FAR :: 1000.0 // Default far cull distance // Texture parameters (equivalent to OpenGL defines) -RL_TEXTURE_WRAP_S :: 0x2802 // GL_TEXTURE_WRAP_S -RL_TEXTURE_WRAP_T :: 0x2803 // GL_TEXTURE_WRAP_T -RL_TEXTURE_MAG_FILTER :: 0x2800 // GL_TEXTURE_MAG_FILTER -RL_TEXTURE_MIN_FILTER :: 0x2801 // GL_TEXTURE_MIN_FILTER +TEXTURE_WRAP_S :: 0x2802 // GL_TEXTURE_WRAP_S +TEXTURE_WRAP_T :: 0x2803 // GL_TEXTURE_WRAP_T +TEXTURE_MAG_FILTER :: 0x2800 // GL_TEXTURE_MAG_FILTER +TEXTURE_MIN_FILTER :: 0x2801 // GL_TEXTURE_MIN_FILTER -RL_TEXTURE_FILTER_NEAREST :: 0x2600 // GL_NEAREST -RL_TEXTURE_FILTER_LINEAR :: 0x2601 // GL_LINEAR -RL_TEXTURE_FILTER_MIP_NEAREST :: 0x2700 // GL_NEAREST_MIPMAP_NEAREST -RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR :: 0x2702 // GL_NEAREST_MIPMAP_LINEAR -RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST :: 0x2701 // GL_LINEAR_MIPMAP_NEAREST -RL_TEXTURE_FILTER_MIP_LINEAR :: 0x2703 // GL_LINEAR_MIPMAP_LINEAR -RL_TEXTURE_FILTER_ANISOTROPIC :: 0x3000 // Anisotropic filter (custom identifier) +TEXTURE_FILTER_NEAREST :: 0x2600 // GL_NEAREST +TEXTURE_FILTER_LINEAR :: 0x2601 // GL_LINEAR +TEXTURE_FILTER_MIP_NEAREST :: 0x2700 // GL_NEAREST_MIPMAP_NEAREST +TEXTURE_FILTER_NEAREST_MIP_LINEAR :: 0x2702 // GL_NEAREST_MIPMAP_LINEAR +TEXTURE_FILTER_LINEAR_MIP_NEAREST :: 0x2701 // GL_LINEAR_MIPMAP_NEAREST +TEXTURE_FILTER_MIP_LINEAR :: 0x2703 // GL_LINEAR_MIPMAP_LINEAR +TEXTURE_FILTER_ANISOTROPIC :: 0x3000 // Anisotropic filter (custom identifier) -RL_TEXTURE_WRAP_REPEAT :: 0x2901 // GL_REPEAT -RL_TEXTURE_WRAP_CLAMP :: 0x812F // GL_CLAMP_TO_EDGE -RL_TEXTURE_WRAP_MIRROR_REPEAT :: 0x8370 // GL_MIRRORED_REPEAT -RL_TEXTURE_WRAP_MIRROR_CLAMP :: 0x8742 // GL_MIRROR_CLAMP_EXT +TEXTURE_WRAP_REPEAT :: 0x2901 // GL_REPEAT +TEXTURE_WRAP_CLAMP :: 0x812F // GL_CLAMP_TO_EDGE +TEXTURE_WRAP_MIRROR_REPEAT :: 0x8370 // GL_MIRRORED_REPEAT +TEXTURE_WRAP_MIRROR_CLAMP :: 0x8742 // GL_MIRROR_CLAMP_EXT // Matrix modes (equivalent to OpenGL) -RL_MODELVIEW :: 0x1700 // GL_MODELVIEW -RL_PROJECTION :: 0x1701 // GL_PROJECTION -RL_TEXTURE :: 0x1702 // GL_TEXTURE +MODELVIEW :: 0x1700 // GL_MODELVIEW +PROJECTION :: 0x1701 // GL_PROJECTION +TEXTURE :: 0x1702 // GL_TEXTURE // Primitive assembly draw modes -RL_LINES :: 0x0001 // GL_LINES -RL_TRIANGLES :: 0x0004 // GL_TRIANGLES -RL_QUADS :: 0x0007 // GL_QUADS +LINES :: 0x0001 // GL_LINES +TRIANGLES :: 0x0004 // GL_TRIANGLES +QUADS :: 0x0007 // GL_QUADS // GL equivalent data types -RL_UNSIGNED_BYTE :: 0x1401 // GL_UNSIGNED_BYTE -RL_FLOAT :: 0x1406 // GL_FLOAT +UNSIGNED_BYTE :: 0x1401 // GL_UNSIGNED_BYTE +FLOAT :: 0x1406 // GL_FLOAT // Buffer usage hint -RL_STREAM_DRAW :: 0x88E0 // GL_STREAM_DRAW -RL_STREAM_READ :: 0x88E1 // GL_STREAM_READ -RL_STREAM_COPY :: 0x88E2 // GL_STREAM_COPY -RL_STATIC_DRAW :: 0x88E4 // GL_STATIC_DRAW -RL_STATIC_READ :: 0x88E5 // GL_STATIC_READ -RL_STATIC_COPY :: 0x88E6 // GL_STATIC_COPY -RL_DYNAMIC_DRAW :: 0x88E8 // GL_DYNAMIC_DRAW -RL_DYNAMIC_READ :: 0x88E9 // GL_DYNAMIC_READ -RL_DYNAMIC_COPY :: 0x88EA // GL_DYNAMIC_COPY +STREAM_DRAW :: 0x88E0 // GL_STREAM_DRAW +STREAM_READ :: 0x88E1 // GL_STREAM_READ +STREAM_COPY :: 0x88E2 // GL_STREAM_COPY +STATIC_DRAW :: 0x88E4 // GL_STATIC_DRAW +STATIC_READ :: 0x88E5 // GL_STATIC_READ +STATIC_COPY :: 0x88E6 // GL_STATIC_COPY +DYNAMIC_DRAW :: 0x88E8 // GL_DYNAMIC_DRAW +DYNAMIC_READ :: 0x88E9 // GL_DYNAMIC_READ +DYNAMIC_COPY :: 0x88EA // GL_DYNAMIC_COPY // GL Shader type -RL_FRAGMENT_SHADER :: 0x8B30 // GL_FRAGMENT_SHADER -RL_VERTEX_SHADER :: 0x8B31 // GL_VERTEX_SHADER -RL_COMPUTE_SHADER :: 0x91B9 // GL_COMPUTE_SHADER +FRAGMENT_SHADER :: 0x8B30 // GL_FRAGMENT_SHADER +VERTEX_SHADER :: 0x8B31 // GL_VERTEX_SHADER +COMPUTE_SHADER :: 0x91B9 // GL_COMPUTE_SHADER // GL blending factors -RL_ZERO :: 0 // GL_ZERO -RL_ONE :: 1 // GL_ONE -RL_SRC_COLOR :: 0x0300 // GL_SRC_COLOR -RL_ONE_MINUS_SRC_COLOR :: 0x0301 // GL_ONE_MINUS_SRC_COLOR -RL_SRC_ALPHA :: 0x0302 // GL_SRC_ALPHA -RL_ONE_MINUS_SRC_ALPHA :: 0x0303 // GL_ONE_MINUS_SRC_ALPHA -RL_DST_ALPHA :: 0x0304 // GL_DST_ALPHA -RL_ONE_MINUS_DST_ALPHA :: 0x0305 // GL_ONE_MINUS_DST_ALPHA -RL_DST_COLOR :: 0x0306 // GL_DST_COLOR -RL_ONE_MINUS_DST_COLOR :: 0x0307 // GL_ONE_MINUS_DST_COLOR -RL_SRC_ALPHA_SATURATE :: 0x0308 // GL_SRC_ALPHA_SATURATE -RL_CONSTANT_COLOR :: 0x8001 // GL_CONSTANT_COLOR -RL_ONE_MINUS_CONSTANT_COLOR :: 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR -RL_CONSTANT_ALPHA :: 0x8003 // GL_CONSTANT_ALPHA -RL_ONE_MINUS_CONSTANT_ALPHA :: 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA +ZERO :: 0 // GL_ZERO +ONE :: 1 // GL_ONE +SRC_COLOR :: 0x0300 // GL_SRC_COLOR +ONE_MINUS_SRC_COLOR :: 0x0301 // GL_ONE_MINUS_SRC_COLOR +SRC_ALPHA :: 0x0302 // GL_SRC_ALPHA +ONE_MINUS_SRC_ALPHA :: 0x0303 // GL_ONE_MINUS_SRC_ALPHA +DST_ALPHA :: 0x0304 // GL_DST_ALPHA +ONE_MINUS_DST_ALPHA :: 0x0305 // GL_ONE_MINUS_DST_ALPHA +DST_COLOR :: 0x0306 // GL_DST_COLOR +ONE_MINUS_DST_COLOR :: 0x0307 // GL_ONE_MINUS_DST_COLOR +SRC_ALPHA_SATURATE :: 0x0308 // GL_SRC_ALPHA_SATURATE +CONSTANT_COLOR :: 0x8001 // GL_CONSTANT_COLOR +ONE_MINUS_CONSTANT_COLOR :: 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR +CONSTANT_ALPHA :: 0x8003 // GL_CONSTANT_ALPHA +ONE_MINUS_CONSTANT_ALPHA :: 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA // GL blending functions/equations -RL_FUNC_ADD :: 0x8006 // GL_FUNC_ADD -RL_MIN :: 0x8007 // GL_MIN -RL_MAX :: 0x8008 // GL_MAX -RL_FUNC_SUBTRACT :: 0x800A // GL_FUNC_SUBTRACT -RL_FUNC_REVERSE_SUBTRACT :: 0x800B // GL_FUNC_REVERSE_SUBTRACT -RL_BLEND_EQUATION :: 0x8009 // GL_BLEND_EQUATION -RL_BLEND_EQUATION_RGB :: 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) -RL_BLEND_EQUATION_ALPHA :: 0x883D // GL_BLEND_EQUATION_ALPHA -RL_BLEND_DST_RGB :: 0x80C8 // GL_BLEND_DST_RGB -RL_BLEND_SRC_RGB :: 0x80C9 // GL_BLEND_SRC_RGB -RL_BLEND_DST_ALPHA :: 0x80CA // GL_BLEND_DST_ALPHA -RL_BLEND_SRC_ALPHA :: 0x80CB // GL_BLEND_SRC_ALPHA -RL_BLEND_COLOR :: 0x8005 // GL_BLEND_COLOR +FUNC_ADD :: 0x8006 // GL_FUNC_ADD +MIN :: 0x8007 // GL_MIN +MAX :: 0x8008 // GL_MAX +FUNC_SUBTRACT :: 0x800A // GL_FUNC_SUBTRACT +FUNC_REVERSE_SUBTRACT :: 0x800B // GL_FUNC_REVERSE_SUBTRACT +BLEND_EQUATION :: 0x8009 // GL_BLEND_EQUATION +BLEND_EQUATION_RGB :: 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) +BLEND_EQUATION_ALPHA :: 0x883D // GL_BLEND_EQUATION_ALPHA +BLEND_DST_RGB :: 0x80C8 // GL_BLEND_DST_RGB +BLEND_SRC_RGB :: 0x80C9 // GL_BLEND_SRC_RGB +BLEND_DST_ALPHA :: 0x80CA // GL_BLEND_DST_ALPHA +BLEND_SRC_ALPHA :: 0x80CB // GL_BLEND_SRC_ALPHA +BLEND_COLOR :: 0x8005 // GL_BLEND_COLOR //---------------------------------------------------------------------------------- @@ -255,7 +255,7 @@ RL_BLEND_COLOR :: 0x8005 // GL_BLEND_COLOR //---------------------------------------------------------------------------------- -VertexBufferIndexType :: c.ushort when RL_GRAPHICS_API_OPENGL_ES2 else c.uint +VertexBufferIndexType :: c.ushort when GRAPHICS_API_OPENGL_ES2 else c.uint // Dynamic vertex buffers (position + texcoords + colors + indices arrays) VertexBuffer :: struct { @@ -343,36 +343,39 @@ CullMode :: enum c.int { BACK, } -@(default_calling_convention="c") +// Matrix type (right handed, stored row major) +Matrix :: #row_major matrix[4, 4]f32 + +@(default_calling_convention="c", link_prefix="rl") foreign lib { //------------------------------------------------------------------------------------ // Functions Declaration - Matrix operations //------------------------------------------------------------------------------------ - rlMatrixMode :: proc(mode: c.int) --- // Choose the current matrix to be transformed - rlPushMatrix :: proc() --- // Push the current matrix to stack - rlPopMatrix :: proc() --- // Pop lattest inserted matrix from stack - rlLoadIdentity :: proc() --- // Reset current matrix to identity matrix - rlTranslatef :: proc(x, y, z: f32) --- // Multiply the current matrix by a translation matrix - rlRotatef :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix - rlScalef :: proc(x, y, z: f32) --- // Multiply the current matrix by a scaling matrix - rlMultMatrixf :: proc(matf: [^]f32) --- // Multiply the current matrix by another matrix - rlFrustum :: proc(left, right, bottom, top, znear, zfar: f64) --- - rlOrtho :: proc(left, right, bottom, top, znear, zfar: f64) --- - rlViewport :: proc(x, y, width, height: c.int) --- // Set the viewport area + MatrixMode :: proc(mode: c.int) --- // Choose the current matrix to be transformed + PushMatrix :: proc() --- // Push the current matrix to stack + PopMatrix :: proc() --- // Pop lattest inserted matrix from stack + LoadIdentity :: proc() --- // Reset current matrix to identity matrix + Translatef :: proc(x, y, z: f32) --- // Multiply the current matrix by a translation matrix + Rotatef :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix + Scalef :: proc(x, y, z: f32) --- // Multiply the current matrix by a scaling matrix + MultMatrixf :: proc(matf: [^]f32) --- // Multiply the current matrix by another matrix + Frustum :: proc(left, right, bottom, top, znear, zfar: f64) --- + Ortho :: proc(left, right, bottom, top, znear, zfar: f64) --- + Viewport :: proc(x, y, width, height: c.int) --- // Set the viewport area //------------------------------------------------------------------------------------ // Functions Declaration - Vertex level operations //------------------------------------------------------------------------------------ - rlBegin :: proc(mode: c.int) --- // Initialize drawing mode (how to organize vertex) - rlEnd :: proc() --- // Finish vertex providing - rlVertex2i :: proc(x, y: c.int) --- // Define one vertex (position) - 2 int - rlVertex2f :: proc(x, y: f32) --- // Define one vertex (position) - 2 f32 - rlVertex3f :: proc(x, y, z: f32) --- // Define one vertex (position) - 3 f32 - rlTexCoord2f :: proc(x, y: f32) --- // Define one vertex (texture coordinate) - 2 f32 - rlNormal3f :: proc(x, y, z: f32) --- // Define one vertex (normal) - 3 f32 - rlColor4ub :: proc(r, g, b, a: u8) --- // Define one vertex (color) - 4 byte - rlColor3f :: proc(x, y, z: f32) --- // Define one vertex (color) - 3 f32 - rlColor4f :: proc(x, y, z, w: f32) --- // Define one vertex (color) - 4 f32 + Begin :: proc(mode: c.int) --- // Initialize drawing mode (how to organize vertex) + End :: proc() --- // Finish vertex providing + Vertex2i :: proc(x, y: c.int) --- // Define one vertex (position) - 2 int + Vertex2f :: proc(x, y: f32) --- // Define one vertex (position) - 2 f32 + Vertex3f :: proc(x, y, z: f32) --- // Define one vertex (position) - 3 f32 + TexCoord2f :: proc(x, y: f32) --- // Define one vertex (texture coordinate) - 2 f32 + Normal3f :: proc(x, y, z: f32) --- // Define one vertex (normal) - 3 f32 + Color4ub :: proc(r, g, b, a: u8) --- // Define one vertex (color) - 4 byte + Color3f :: proc(x, y, z: f32) --- // Define one vertex (color) - 3 f32 + Color4f :: proc(x, y, z, w: f32) --- // Define one vertex (color) - 4 f32 //------------------------------------------------------------------------------------ // Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2) @@ -381,175 +384,177 @@ foreign lib { //------------------------------------------------------------------------------------ // Vertex buffers state - rlEnableVertexArray :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported) - rlDisableVertexArray :: proc() --- // Disable vertex array (VAO, if supported) - rlEnableVertexBuffer :: proc(id: c.uint) --- // Enable vertex buffer (VBO) - rlDisableVertexBuffer :: proc() --- // Disable vertex buffer (VBO) - rlEnableVertexBufferElement :: proc(id: c.uint) --- // Enable vertex buffer element (VBO element) - rlDisableVertexBufferElement :: proc() --- // Disable vertex buffer element (VBO element) - rlEnableVertexAttribute :: proc(index: c.uint) --- // Enable vertex attribute index - rlDisableVertexAttribute :: proc(index: c.uint) --- // Disable vertex attribute index - when RL_GRAPHICS_API_OPENGL_11 { - rlEnableStatePointer :: proc(vertexAttribType: c.int, buffer: rawptr) --- - rlDisableStatePointer :: proc(vertexAttribType: c.int) --- + EnableVertexArray :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported) + DisableVertexArray :: proc() --- // Disable vertex array (VAO, if supported) + EnableVertexBuffer :: proc(id: c.uint) --- // Enable vertex buffer (VBO) + DisableVertexBuffer :: proc() --- // Disable vertex buffer (VBO) + EnableVertexBufferElement :: proc(id: c.uint) --- // Enable vertex buffer element (VBO element) + DisableVertexBufferElement :: proc() --- // Disable vertex buffer element (VBO element) + EnableVertexAttribute :: proc(index: c.uint) --- // Enable vertex attribute index + DisableVertexAttribute :: proc(index: c.uint) --- // Disable vertex attribute index + when GRAPHICS_API_OPENGL_11 { + EnableStatePointer :: proc(vertexAttribType: c.int, buffer: rawptr) --- + DisableStatePointer :: proc(vertexAttribType: c.int) --- } // Textures state - rlActiveTextureSlot :: proc(slot: c.int) --- // Select and active a texture slot - rlEnableTexture :: proc(id: c.uint) --- // Enable texture - rlDisableTexture :: proc() --- // Disable texture - rlEnableTextureCubemap :: proc(id: c.uint) --- // Enable texture cubemap - rlDisableTextureCubemap :: proc() --- // Disable texture cubemap - rlTextureParameters :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap) - rlCubemapParameters :: proc(id: i32, param: c.int, value: c.int) --- // Set cubemap parameters (filter, wrap) + ActiveTextureSlot :: proc(slot: c.int) --- // Select and active a texture slot + EnableTexture :: proc(id: c.uint) --- // Enable texture + DisableTexture :: proc() --- // Disable texture + EnableTextureCubemap :: proc(id: c.uint) --- // Enable texture cubemap + DisableTextureCubemap :: proc() --- // Disable texture cubemap + TextureParameters :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap) + CubemapParameters :: proc(id: i32, param: c.int, value: c.int) --- // Set cubemap parameters (filter, wrap) // Shader state - rlEnableShader :: proc(id: c.uint) --- // Enable shader program - rlDisableShader :: proc() --- // Disable shader program + EnableShader :: proc(id: c.uint) --- // Enable shader program + DisableShader :: proc() --- // Disable shader program // Framebuffer state - rlEnableFramebuffer :: proc(id: c.uint) --- // Enable render texture (fbo) - rlDisableFramebuffer :: proc() --- // Disable render texture (fbo), return to default framebuffer - rlActiveDrawBuffers :: proc(count: c.int) --- // Activate multiple draw color buffers - rlBlitFramebuffer :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer + EnableFramebuffer :: proc(id: c.uint) --- // Enable render texture (fbo) + DisableFramebuffer :: proc() --- // Disable render texture (fbo), return to default framebuffer + ActiveDrawBuffers :: proc(count: c.int) --- // Activate multiple draw color buffers + BlitFramebuffer :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer // General render state - rlDisableColorBlend :: proc() --- // Disable color blending - rlEnableDepthTest :: proc() --- // Enable depth test - rlDisableDepthTest :: proc() --- // Disable depth test - rlEnableDepthMask :: proc() --- // Enable depth write - rlDisableDepthMask :: proc() --- // Disable depth write - rlEnableBackfaceCulling :: proc() --- // Enable backface culling - rlDisableBackfaceCulling :: proc() --- // Disable backface culling - rlSetCullFace :: proc(mode: CullMode) --- // Set face culling mode - rlEnableScissorTest :: proc() --- // Enable scissor test - rlDisableScissorTest :: proc() --- // Disable scissor test - rlScissor :: proc(x, y, width, height: c.int) --- // Scissor test - rlEnableWireMode :: proc() --- // Enable wire mode - rlEnablePointMode :: proc() --- // Enable point mode - rlDisableWireMode :: proc() --- // Disable wire and point modes - rlSetLineWidth :: proc(width: f32) --- // Set the line drawing width - rlGetLineWidth :: proc() -> f32 --- // Get the line drawing width - rlEnableSmoothLines :: proc() --- // Enable line aliasing - rlDisableSmoothLines :: proc() --- // Disable line aliasing - rlEnableStereoRender :: proc() --- // Enable stereo rendering - rlDisableStereoRender :: proc() --- // Disable stereo rendering - rlIsStereoRenderEnabled :: proc() -> bool --- // Check if stereo render is enabled + DisableColorBlend :: proc() --- // Disable color blending + EnableDepthTest :: proc() --- // Enable depth test + DisableDepthTest :: proc() --- // Disable depth test + EnableDepthMask :: proc() --- // Enable depth write + DisableDepthMask :: proc() --- // Disable depth write + EnableBackfaceCulling :: proc() --- // Enable backface culling + DisableBackfaceCulling :: proc() --- // Disable backface culling + SetCullFace :: proc(mode: CullMode) --- // Set face culling mode + EnableScissorTest :: proc() --- // Enable scissor test + DisableScissorTest :: proc() --- // Disable scissor test + Scissor :: proc(x, y, width, height: c.int) --- // Scissor test + EnableWireMode :: proc() --- // Enable wire mode + EnablePointMode :: proc() --- // Enable point mode + DisableWireMode :: proc() --- // Disable wire and point modes + SetLineWidth :: proc(width: f32) --- // Set the line drawing width + GetLineWidth :: proc() -> f32 --- // Get the line drawing width + EnableSmoothLines :: proc() --- // Enable line aliasing + DisableSmoothLines :: proc() --- // Disable line aliasing + EnableStereoRender :: proc() --- // Enable stereo rendering + DisableStereoRender :: proc() --- // Disable stereo rendering + IsStereoRenderEnabled :: proc() -> bool --- // Check if stereo render is enabled - rlClearColor :: proc(r, g, b, a: u8) --- // Clear color buffer with color - rlClearScreenBuffers :: proc() --- // Clear used screen buffers (color and depth) - rlCheckErrors :: proc() --- // Check and log OpenGL error codes - rlSetBlendMode :: proc(mode: c.int) --- // Set blending mode - rlSetBlendFactors :: proc(glSrcFactor, glDstFactor, glEquation: c.int) --- // Set blending mode factor and equation (using OpenGL factors) - rlSetBlendFactorsSeparate :: proc(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha: c.int) --- // Set blending mode factors and equations separately (using OpenGL factors) + ClearColor :: proc(r, g, b, a: u8) --- // Clear color buffer with color + ClearScreenBuffers :: proc() --- // Clear used screen buffers (color and depth) + CheckErrors :: proc() --- // Check and log OpenGL error codes + SetBlendMode :: proc(mode: c.int) --- // Set blending mode + SetBlendFactors :: proc(glSrcFactor, glDstFactor, glEquation: c.int) --- // Set blending mode factor and equation (using OpenGL factors) + SetBlendFactorsSeparate :: proc(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha: c.int) --- // Set blending mode factors and equations separately (using OpenGL factors) //------------------------------------------------------------------------------------ // Functions Declaration - rlgl functionality //------------------------------------------------------------------------------------ // rlgl initialization functions - rlglInit :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states) - rlglClose :: proc() --- // De-initialize rlgl (buffers, shaders, textures) - rlLoadExtensions :: proc(loader: rawptr) --- // Load OpenGL extensions (loader function required) - rlGetVersion :: proc() -> GlVersion --- // Get current OpenGL version - rlSetFramebufferWidth :: proc(width: c.int) --- // Set current framebuffer width - rlGetFramebufferWidth :: proc() -> c.int --- // Get default framebuffer width - rlSetFramebufferHeight :: proc(height: c.int) --- // Set current framebuffer height - rlGetFramebufferHeight :: proc() -> c.int --- // Get default framebuffer height + @(link_prefix="rlgl") + Init :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states) + @(link_prefix="rlgl") + Close :: proc() --- // De-initialize rlgl (buffers, shaders, textures) + LoadExtensions :: proc(loader: rawptr) --- // Load OpenGL extensions (loader function required) + GetVersion :: proc() -> GlVersion --- // Get current OpenGL version + SetFramebufferWidth :: proc(width: c.int) --- // Set current framebuffer width + GetFramebufferWidth :: proc() -> c.int --- // Get default framebuffer width + SetFramebufferHeight :: proc(height: c.int) --- // Set current framebuffer height + GetFramebufferHeight :: proc() -> c.int --- // Get default framebuffer height - rlGetTextureIdDefault :: proc() -> c.uint --- // Get default texture id - rlGetShaderIdDefault :: proc() -> c.uint --- // Get default shader id - rlGetShaderLocsDefault :: proc() -> [^]c.int --- // Get default shader locations + GetTextureIdDefault :: proc() -> c.uint --- // Get default texture id + GetShaderIdDefault :: proc() -> c.uint --- // Get default shader id + GetShaderLocsDefault :: proc() -> [^]c.int --- // Get default shader locations // Render batch management // NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode // but this render batch API is exposed in case of custom batches are required - rlLoadRenderBatch :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system - rlUnloadRenderBatch :: proc(batch: RenderBatch) --- // Unload render batch system - rlDrawRenderBatch :: proc(batch: ^RenderBatch) --- // Draw render batch data (Update->Draw->Reset) - rlSetRenderBatchActive :: proc(batch: ^RenderBatch) --- // Set the active render batch for rlgl (NULL for default internal) - rlDrawRenderBatchActive :: proc() --- // Update and draw internal render batch - rlCheckRenderBatchLimit :: proc(vCount: c.int) -> c.int --- // Check internal buffer overflow for a given number of vertex + LoadRenderBatch :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system + UnloadRenderBatch :: proc(batch: RenderBatch) --- // Unload render batch system + DrawRenderBatch :: proc(batch: ^RenderBatch) --- // Draw render batch data (Update->Draw->Reset) + SetRenderBatchActive :: proc(batch: ^RenderBatch) --- // Set the active render batch for rlgl (NULL for default internal) + DrawRenderBatchActive :: proc() --- // Update and draw internal render batch + CheckRenderBatchLimit :: proc(vCount: c.int) -> c.int --- // Check internal buffer overflow for a given number of vertex - rlSetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits + SetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits //------------------------------------------------------------------------------------------------------------------------ // Vertex buffers management - rlLoadVertexArray :: proc() -> c.uint --- // Load vertex array (vao) if supported - rlLoadVertexBuffer :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a vertex buffer attribute - rlLoadVertexBufferElement :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a new attributes element buffer - rlUpdateVertexBuffer :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update GPU buffer with new data - rlUpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data - rlUnloadVertexArray :: proc(vaoId: c.uint) --- - rlUnloadVertexBuffer :: proc(vboId: c.uint) --- - rlSetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) --- - rlSetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) --- - rlSetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value - rlDrawVertexArray :: proc(offset: c.int, count: c.int) --- - rlDrawVertexArrayElements :: proc(offset: c.int, count: c.int, buffer: rawptr) --- - rlDrawVertexArrayInstanced :: proc(offset: c.int, count: c.int, instances: c.int) --- - rlDrawVertexArrayElementsInstanced :: proc(offset: c.int, count: c.int, buffer: rawptr, instances: c.int) --- + LoadVertexArray :: proc() -> c.uint --- // Load vertex array (vao) if supported + LoadVertexBuffer :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a vertex buffer attribute + LoadVertexBufferElement :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a new attributes element buffer + UpdateVertexBuffer :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update GPU buffer with new data + UpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data + UnloadVertexArray :: proc(vaoId: c.uint) --- + UnloadVertexBuffer :: proc(vboId: c.uint) --- + SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) --- + SetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) --- + SetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value + DrawVertexArray :: proc(offset: c.int, count: c.int) --- + DrawVertexArrayElements :: proc(offset: c.int, count: c.int, buffer: rawptr) --- + DrawVertexArrayInstanced :: proc(offset: c.int, count: c.int, instances: c.int) --- + DrawVertexArrayElementsInstanced :: proc(offset: c.int, count: c.int, buffer: rawptr, instances: c.int) --- // Textures management - rlLoadTexture :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint --- // Load texture in GPU - rlLoadTextureDepth :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint --- // Load depth texture/renderbuffer (to be attached to fbo) - rlLoadTextureCubemap :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint --- // Load texture cubemap - rlUpdateTexture :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data - rlGetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) --- // Get OpenGL internal formats - rlGetPixelFormatName :: proc(format: c.uint) -> cstring --- // Get name string for pixel format - rlUnloadTexture :: proc(id: c.uint) --- // Unload texture from GPU memory - rlGenTextureMipmaps :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) --- // Generate mipmap data for selected texture - rlReadTexturePixels :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr --- // Read texture pixel data - rlReadScreenPixels :: proc(width, height: c.int) -> [^]byte --- // Read screen pixel data (color buffer) + LoadTexture :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint --- // Load texture in GPU + LoadTextureDepth :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint --- // Load depth texture/renderbuffer (to be attached to fbo) + LoadTextureCubemap :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint --- // Load texture cubemap + UpdateTexture :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data + GetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) --- // Get OpenGL internal formats + GetPixelFormatName :: proc(format: c.uint) -> cstring --- // Get name string for pixel format + UnloadTexture :: proc(id: c.uint) --- // Unload texture from GPU memory + GenTextureMipmaps :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) --- // Generate mipmap data for selected texture + ReadTexturePixels :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr --- // Read texture pixel data + ReadScreenPixels :: proc(width, height: c.int) -> [^]byte --- // Read screen pixel data (color buffer) // Framebuffer management (fbo) - rlLoadFramebuffer :: proc(width, height: c.int) -> c.uint --- // Load an empty framebuffer - rlFramebufferAttach :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer - rlFramebufferComplete :: proc(id: c.uint) -> bool --- // Verify framebuffer is complete - rlUnloadFramebuffer :: proc(id: c.uint) --- // Delete framebuffer from GPU + LoadFramebuffer :: proc(width, height: c.int) -> c.uint --- // Load an empty framebuffer + FramebufferAttach :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer + FramebufferComplete :: proc(id: c.uint) -> bool --- // Verify framebuffer is complete + UnloadFramebuffer :: proc(id: c.uint) --- // Delete framebuffer from GPU // Shaders management - rlLoadShaderCode :: proc(vsCode, fsCode: cstring) -> c.uint --- // Load shader from code strings - rlCompileShader :: proc(shaderCode: cstring, type: c.int) -> c.uint --- // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) - rlLoadShaderProgram :: proc(vShaderId, fShaderId: c.uint) -> c.uint --- // Load custom shader program - rlUnloadShaderProgram :: proc(id: c.uint) --- // Unload shader program - rlGetLocationUniform :: proc(shaderId: c.uint, uniformName: cstring) -> c.int --- // Get shader location uniform - rlGetLocationAttrib :: proc(shaderId: c.uint, attribName: cstring) -> c.int --- // Get shader location attribute - rlSetUniform :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform - rlSetUniformMatrix :: proc(locIndex: c.int, mat: Matrix) --- // Set shader value matrix - rlSetUniformSampler :: proc(locIndex: c.int, textureId: c.uint) --- // Set shader value sampler - rlSetShader :: proc(id: c.uint, locs: [^]c.int) --- // Set shader currently active (id and locations) + LoadShaderCode :: proc(vsCode, fsCode: cstring) -> c.uint --- // Load shader from code strings + CompileShader :: proc(shaderCode: cstring, type: c.int) -> c.uint --- // Compile custom shader and return shader id (type: VERTEX_SHADER, FRAGMENT_SHADER, COMPUTE_SHADER) + LoadShaderProgram :: proc(vShaderId, fShaderId: c.uint) -> c.uint --- // Load custom shader program + UnloadShaderProgram :: proc(id: c.uint) --- // Unload shader program + GetLocationUniform :: proc(shaderId: c.uint, uniformName: cstring) -> c.int --- // Get shader location uniform + GetLocationAttrib :: proc(shaderId: c.uint, attribName: cstring) -> c.int --- // Get shader location attribute + SetUniform :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform + SetUniformMatrix :: proc(locIndex: c.int, mat: Matrix) --- // Set shader value matrix + SetUniformSampler :: proc(locIndex: c.int, textureId: c.uint) --- // Set shader value sampler + SetShader :: proc(id: c.uint, locs: [^]c.int) --- // Set shader currently active (id and locations) // Compute shader management - rlLoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint --- // Load compute shader program - rlComputeShaderDispatch :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline) + LoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint --- // Load compute shader program + ComputeShaderDispatch :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline) // Shader buffer storage object management (ssbo) - rlLoadShaderBuffer :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint --- // Load shader storage buffer object (SSBO) - rlUnloadShaderBuffer :: proc(ssboId: c.uint) --- // Unload shader storage buffer object (SSBO) - rlUpdateShaderBuffer :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) --- // Update SSBO buffer data - rlBindShaderBuffer :: proc(id: c.uint, index: c.uint) --- // Bind SSBO buffer - rlReadShaderBuffer :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) --- // Read SSBO buffer data (GPU->CPU) - rlCopyShaderBuffer :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers - rlGetShaderBufferSize :: proc(id: c.uint) -> c.uint --- // Get SSBO buffer size + LoadShaderBuffer :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint --- // Load shader storage buffer object (SSBO) + UnloadShaderBuffer :: proc(ssboId: c.uint) --- // Unload shader storage buffer object (SSBO) + UpdateShaderBuffer :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) --- // Update SSBO buffer data + BindShaderBuffer :: proc(id: c.uint, index: c.uint) --- // Bind SSBO buffer + ReadShaderBuffer :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) --- // Read SSBO buffer data (GPU->CPU) + CopyShaderBuffer :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers + GetShaderBufferSize :: proc(id: c.uint) -> c.uint --- // Get SSBO buffer size // Buffer management - rlBindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) --- // Bind image texture + BindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) --- // Bind image texture // Matrix state management - rlGetMatrixModelview :: proc() -> Matrix --- // Get internal modelview matrix - rlGetMatrixProjection :: proc() -> Matrix --- // Get internal projection matrix - rlGetMatrixTransform :: proc() -> Matrix --- // Get internal accumulated transform matrix - rlGetMatrixProjectionStereo :: proc(eye: c.int) -> Matrix --- // Get internal projection matrix for stereo render (selected eye) - rlGetMatrixViewOffsetStereo :: proc(eye: c.int) -> Matrix --- // Get internal view offset matrix for stereo render (selected eye) - rlSetMatrixProjection :: proc(proj: Matrix) --- // Set a custom projection matrix (replaces internal projection matrix) - rlSetMatrixModelview :: proc(view: Matrix) --- // Set a custom modelview matrix (replaces internal modelview matrix) - rlSetMatrixProjectionStereo :: proc(right, left: Matrix) --- // Set eyes projection matrices for stereo rendering - rlSetMatrixViewOffsetStereo :: proc(right, left: Matrix) --- // Set eyes view offsets matrices for stereo rendering + GetMatrixModelview :: proc() -> Matrix --- // Get internal modelview matrix + GetMatrixProjection :: proc() -> Matrix --- // Get internal projection matrix + GetMatrixTransform :: proc() -> Matrix --- // Get internal accumulated transform matrix + GetMatrixProjectionStereo :: proc(eye: c.int) -> Matrix --- // Get internal projection matrix for stereo render (selected eye) + GetMatrixViewOffsetStereo :: proc(eye: c.int) -> Matrix --- // Get internal view offset matrix for stereo render (selected eye) + SetMatrixProjection :: proc(proj: Matrix) --- // Set a custom projection matrix (replaces internal projection matrix) + SetMatrixModelview :: proc(view: Matrix) --- // Set a custom modelview matrix (replaces internal modelview matrix) + SetMatrixProjectionStereo :: proc(right, left: Matrix) --- // Set eyes projection matrices for stereo rendering + SetMatrixViewOffsetStereo :: proc(right, left: Matrix) --- // Set eyes view offsets matrices for stereo rendering // Quick and dirty cube/quad buffers load->draw->unload - rlLoadDrawCube :: proc() --- // Load and draw a cube - rlLoadDrawQuad :: proc() --- // Load and draw a quad + LoadDrawCube :: proc() --- // Load and draw a cube + LoadDrawQuad :: proc() --- // Load and draw a quad } From c9e732d14172f5bdd1c69befacd8e49343f0f6c2 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Tue, 11 Jun 2024 08:59:30 +0200 Subject: [PATCH 04/20] rlgl.RLGL_VERSION -> rlgl.VERSION --- vendor/raylib/rlgl/rlgl.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/raylib/rlgl/rlgl.odin b/vendor/raylib/rlgl/rlgl.odin index 4a4ab4b7f..b36764830 100644 --- a/vendor/raylib/rlgl/rlgl.odin +++ b/vendor/raylib/rlgl/rlgl.odin @@ -109,7 +109,7 @@ package rlgl import "core:c" -RLGL_VERSION :: "5.0" +VERSION :: "5.0" when ODIN_OS == .Windows { foreign import lib { From 1a22f82f94928e43bf3945cf43dc60d8daab0067 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Tue, 11 Jun 2024 18:03:20 +0200 Subject: [PATCH 05/20] Changed rl.SetShaderValue etc to take a c.int like in original raylib.h. You should be able to use other values than the ShaderLocationIndex enum, that enum is only for build in things in raylib. Added #any_int on those procs so you can pass both int and also a ShaderLocationIndex. --- vendor/raylib/raylib.odin | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index ebb1cdd27..3d1b74058 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -984,12 +984,14 @@ foreign lib { LoadShader :: proc(vsFileName, fsFileName: cstring) -> Shader --- // Load shader from files and bind default locations LoadShaderFromMemory :: proc(vsCode, fsCode: cstring) -> Shader --- // Load shader from code strings and bind default locations IsShaderReady :: proc(shader: Shader) -> bool --- // Check if a shader is ready - GetShaderLocation :: proc(shader: Shader, uniformName: cstring) -> ShaderLocationIndex --- // Get shader uniform location - GetShaderLocationAttrib :: proc(shader: Shader, attribName: cstring) -> ShaderLocationIndex --- // Get shader attribute location - SetShaderValue :: proc(shader: Shader, locIndex: ShaderLocationIndex, value: rawptr, uniformType: ShaderUniformDataType) --- // Set shader uniform value - SetShaderValueV :: proc(shader: Shader, locIndex: ShaderLocationIndex, value: rawptr, uniformType: ShaderUniformDataType, count: c.int) --- // Set shader uniform value vector - SetShaderValueMatrix :: proc(shader: Shader, locIndex: ShaderLocationIndex, mat: Matrix) --- // Set shader uniform value (matrix 4x4) - SetShaderValueTexture :: proc(shader: Shader, locIndex: ShaderLocationIndex, texture: Texture2D) --- // Set shader uniform value for texture (sampler2d) + GetShaderLocation :: proc(shader: Shader, uniformName: cstring) -> c.int --- // Get shader uniform location + GetShaderLocationAttrib :: proc(shader: Shader, attribName: cstring) -> c.int --- // Get shader attribute location + + // We use #any_int here so we can pass ShaderLocationIndex + SetShaderValue :: proc(shader: Shader, #any_int locIndex: c.int, value: rawptr, uniformType: ShaderUniformDataType) --- // Set shader uniform value + SetShaderValueV :: proc(shader: Shader, #any_int locIndex: c.int, value: rawptr, uniformType: ShaderUniformDataType, count: c.int) --- // Set shader uniform value vector + SetShaderValueMatrix :: proc(shader: Shader, #any_int locIndex: c.int, mat: Matrix) --- // Set shader uniform value (matrix 4x4) + SetShaderValueTexture :: proc(shader: Shader, #any_int locIndex: c.int, texture: Texture2D) --- // Set shader uniform value for texture (sampler2d) UnloadShader :: proc(shader: Shader) --- // Unload shader from GPU memory (VRAM) // Screen-space-related functions From ebadff555d70d5ef8faf91785696e5c5ea3605f8 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 12 Jun 2024 12:52:48 +0200 Subject: [PATCH 06/20] Update XML reader to normalize whitespace, part 1. --- core/encoding/entity/entity.odin | 109 ++++++++------------- core/encoding/xml/tokenizer.odin | 43 +++----- core/encoding/xml/xml_reader.odin | 24 +++-- tests/core/encoding/xml/test_core_xml.odin | 10 +- 4 files changed, 70 insertions(+), 116 deletions(-) diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin index cee6230ef..280be9377 100644 --- a/core/encoding/entity/entity.odin +++ b/core/encoding/entity/entity.odin @@ -56,38 +56,27 @@ CDATA_END :: "]]>" COMMENT_START :: "" -/* - Default: CDATA and comments are passed through unchanged. -*/ +// Default: CDATA and comments are passed through unchanged. XML_Decode_Option :: enum u8 { - /* - Do not decode & entities. It decodes by default. - If given, overrides `Decode_CDATA`. - */ + // Do not decode & entities. It decodes by default. If given, overrides `Decode_CDATA`. No_Entity_Decode, - /* - CDATA is unboxed. - */ + // CDATA is unboxed. Unbox_CDATA, - /* - Unboxed CDATA is decoded as well. - Ignored if `.Unbox_CDATA` is not given. - */ + // Unboxed CDATA is decoded as well. Ignored if `.Unbox_CDATA` is not given. Decode_CDATA, - /* - Comments are stripped. - */ + // Comments are stripped. Comment_Strip, + + // Normalize whitespace + Normalize_Whitespace, } XML_Decode_Options :: bit_set[XML_Decode_Option; u8] -/* - Decode a string that may include SGML/XML/HTML entities. - The caller has to free the result. -*/ +// Decode a string that may include SGML/XML/HTML entities. +// The caller has to free the result. decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) { context.allocator = allocator @@ -100,14 +89,14 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := t := Tokenizer{src=input} in_data := false + prev: rune + loop: for { advance(&t) or_return if t.r < 0 { break loop } - /* - Below here we're never inside a CDATA tag. - At most we'll see the start of one, but that doesn't affect the logic. - */ + // Below here we're never inside a CDATA tag. At most we'll see the start of one, + // but that doesn't affect the logic. switch t.r { case '<': /* @@ -126,9 +115,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := in_data = _handle_xml_special(&t, &builder, options) or_return case ']': - /* - If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag. - */ + // If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag. if in_data { if t.read_offset + len(CDATA_END) < len(t.src) { if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { @@ -143,22 +130,16 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := case: if in_data && .Decode_CDATA not_in options { - /* - Unboxed, but undecoded. - */ + // Unboxed, but undecoded. write_rune(&builder, t.r) continue } if t.r == '&' { if entity, entity_err := _extract_xml_entity(&t); entity_err != .None { - /* - We read to the end of the string without closing the entity. - Pass through as-is. - */ + // We read to the end of the string without closing the entity. Pass through as-is. write_string(&builder, entity) } else { - if .No_Entity_Decode not_in options { if decoded, ok := xml_decode_entity(entity); ok { write_rune(&builder, decoded) @@ -166,19 +147,27 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := } } - /* - Literal passthrough because the decode failed or we want entities not decoded. - */ + // Literal passthrough because the decode failed or we want entities not decoded. write_string(&builder, "&") write_string(&builder, entity) write_string(&builder, ";") } } else { - write_rune(&builder, t.r) + // https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-line-ends + switch t.r { + case '\n', 0x85, 0x2028: + write_rune(&builder, '\n') + case '\r': // Do nothing until next character + case: + if prev == '\r' { // Turn a single carriage return into a \n + write_rune(&builder, '\n') + } + write_rune(&builder, t.r) + } + prev = t.r } } } - return strings.clone(strings.to_string(builder), allocator), err } @@ -253,24 +242,18 @@ xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) { return rune(val), true case: - /* - Named entity. - */ + // Named entity. return named_xml_entity_to_rune(entity) } } -/* - Private XML helper to extract `&;` entity. -*/ +// Private XML helper to extract `&;` entity. @(private="file") _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) { assert(t != nil && t.r == '&') - /* - All of these would be in the ASCII range. - Even if one is not, it doesn't matter. All characters we need to compare to extract are. - */ + // All of these would be in the ASCII range. + // Even if one is not, it doesn't matter. All characters we need to compare to extract are. length := len(t.src) found := false @@ -292,9 +275,7 @@ _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) { return string(t.src[t.offset : t.read_offset]), .Invalid_Entity_Encoding } -/* - Private XML helper for CDATA and comments. -*/ +// Private XML helper for CDATA and comments. @(private="file") _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) { assert(t != nil && t.r == '<') @@ -304,20 +285,14 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X t.read_offset += len(CDATA_START) - 1 if .Unbox_CDATA in options && .Decode_CDATA in options { - /* - We're unboxing _and_ decoding CDATA - */ + // We're unboxing _and_ decoding CDATA return true, .None } - /* - CDATA is passed through. - */ + // CDATA is passed through. offset := t.offset - /* - Scan until end of CDATA. - */ + // Scan until end of CDATA. for { advance(t) or_return if t.r < 0 { return true, .CDATA_Not_Terminated } @@ -341,14 +316,10 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X } else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START { t.read_offset += len(COMMENT_START) - /* - Comment is passed through by default. - */ + // Comment is passed through by default. offset := t.offset - /* - Scan until end of Comment. - */ + // Scan until end of Comment. for { advance(t) or_return if t.r < 0 { return true, .Comment_Not_Terminated } diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 0f87c366b..2d06038b7 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -218,9 +218,7 @@ scan_identifier :: proc(t: ^Tokenizer) -> string { for is_valid_identifier_rune(t.ch) { advance_rune(t) if t.ch == ':' { - /* - A namespaced attr can have at most two parts, `namespace:ident`. - */ + // A namespaced attr can have at most two parts, `namespace:ident`. if namespaced { break } @@ -268,14 +266,10 @@ scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) { return string(t.src[offset : t.offset - 1]), .None } -/* - Skip CDATA -*/ +// Skip CDATA skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) { if t.read_offset + len(CDATA_START) >= len(t.src) { - /* - Can't be the start of a CDATA tag. - */ + // Can't be the start of a CDATA tag. return .None } @@ -290,9 +284,7 @@ skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) { return .Premature_EOF } - /* - Scan until the end of a CDATA tag. - */ + // Scan until the end of a CDATA tag. if t.read_offset + len(CDATA_END) < len(t.src) { if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { t.read_offset += len(CDATA_END) @@ -319,14 +311,10 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close case '<': if peek_byte(t) == '!' { if peek_byte(t, 1) == '[' { - /* - Might be the start of a CDATA tag. - */ + // Might be the start of a CDATA tag. skip_cdata(t) or_return } else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' { - /* - Comment start. Eat comment. - */ + // Comment start. Eat comment. t.read_offset += 3 _ = scan_comment(t) or_return } @@ -342,17 +330,13 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close } if t.ch == close { - /* - If it's not a CDATA or comment, it's the end of this body. - */ + // If it's not a CDATA or comment, it's the end of this body. break loop } advance_rune(t) } - /* - Strip trailing whitespace. - */ + // Strip trailing whitespace. lit := string(t.src[offset : t.offset]) end := len(lit) @@ -369,11 +353,6 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close if consume_close { advance_rune(t) } - - /* - TODO: Handle decoding escape characters and unboxing CDATA. - */ - return lit, err } @@ -384,7 +363,7 @@ peek :: proc(t: ^Tokenizer) -> (token: Token) { return token } -scan :: proc(t: ^Tokenizer) -> Token { +scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token { skip_whitespace(t) offset := t.offset @@ -418,7 +397,7 @@ scan :: proc(t: ^Tokenizer) -> Token { case '"', '\'': kind = .Invalid - lit, err = scan_string(t, t.offset, ch, true, false) + lit, err = scan_string(t, t.offset, ch, true, multiline_string) if err == .None { kind = .String } @@ -435,4 +414,4 @@ scan :: proc(t: ^Tokenizer) -> Token { lit = string(t.src[offset : t.offset]) } return Token{kind, lit, pos} -} +} \ No newline at end of file diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 5b4b12948..b9656900f 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -203,9 +203,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha doc.elements = make([dynamic]Element, 1024, 1024, allocator) - // strings.intern_init(&doc.intern, allocator, allocator) - - err = .Unexpected_Token + err = .Unexpected_Token element, parent: Element_ID open: Token @@ -259,8 +257,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha case .Slash: // Empty tag. Close it. expect(t, .Gt) or_return - parent = doc.elements[element].parent - element = parent + parent = doc.elements[element].parent + element = parent case: error(t, t.offset, "Expected close tag, got: %#v\n", end_token) @@ -276,8 +274,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", doc.elements[element].ident, ident.text) return doc, .Mismatched_Closing_Tag } - parent = doc.elements[element].parent - element = parent + parent = doc.elements[element].parent + element = parent } else if open.kind == .Exclaim { // (validated: Options, err: Error) { return validated, .None } -expect :: proc(t: ^Tokenizer, kind: Token_Kind) -> (tok: Token, err: Error) { - tok = scan(t) +expect :: proc(t: ^Tokenizer, kind: Token_Kind, multiline_string := false) -> (tok: Token, err: Error) { + tok = scan(t, multiline_string=multiline_string) if tok.kind == kind { return tok, .None } error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind) @@ -480,7 +478,13 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attribute, offset: int, err: E offset = t.offset - len(key.text) _ = expect(t, .Eq) or_return - value := expect(t, .String) or_return + value := expect(t, .String, multiline_string=true) or_return + + normalized, normalize_err := entity.decode_xml(value.text, {.Normalize_Whitespace}, doc.allocator) + if normalize_err == .None { + append(&doc.strings_to_free, normalized) + value.text = normalized + } attr.key = key.text attr.val = value.text diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 22852d1f3..09d1a4611 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -36,7 +36,7 @@ xml_test_utf8_normal :: proc(t: ^testing.T) { }, expected_doctype = "恥ずべきフクロウ", }, - crc32 = 0xe9b62f03, + crc32 = 0xefa55f27, }) } @@ -52,7 +52,7 @@ xml_test_utf8_unbox_cdata :: proc(t: ^testing.T) { }, expected_doctype = "恥ずべきフクロウ", }, - crc32 = 0x9c2643ed, + crc32 = 0x2dd27770, }) } @@ -128,7 +128,7 @@ xml_test_entities_unbox :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x3b6d4a90, + crc32 = 0x350ca83e, }) } @@ -142,7 +142,7 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x5be2ffdc, + crc32 = 0x7f58db7d, }) } @@ -172,7 +172,7 @@ xml_test_unicode :: proc(t: ^testing.T) { expected_doctype = "", }, err = .None, - crc32 = 0x0b6100ab, + crc32 = 0x73070b55, }) } From 2fe961cbcd05a558fd13cc5f4c506373e7047a6b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 12 Jun 2024 13:30:00 +0200 Subject: [PATCH 07/20] Fold XML attribute whitespace. --- core/encoding/entity/entity.odin | 36 +++++++++++++------ .../core/assets/XML/attribute-whitespace.xml | 8 +++++ tests/core/encoding/xml/test_core_xml.odin | 14 ++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 tests/core/assets/XML/attribute-whitespace.xml diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin index 280be9377..f5208ad6f 100644 --- a/core/encoding/entity/entity.odin +++ b/core/encoding/entity/entity.odin @@ -89,7 +89,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := t := Tokenizer{src=input} in_data := false - prev: rune + prev: rune = ' ' loop: for { advance(&t) or_return @@ -153,18 +153,32 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := write_string(&builder, ";") } } else { - // https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-line-ends - switch t.r { - case '\n', 0x85, 0x2028: - write_rune(&builder, '\n') - case '\r': // Do nothing until next character - case: - if prev == '\r' { // Turn a single carriage return into a \n - write_rune(&builder, '\n') + // Handle AV Normalization: https://www.w3.org/TR/2006/REC-xml11-20060816/#AVNormalize + if .Normalize_Whitespace in options { + switch t.r { + case ' ', '\r', '\n', '\t': + if prev != ' ' { + write_rune(&builder, ' ') + prev = ' ' + } + case: + write_rune(&builder, t.r) + prev = t.r } - write_rune(&builder, t.r) + } else { + // https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-line-ends + switch t.r { + case '\n', 0x85, 0x2028: + write_rune(&builder, '\n') + case '\r': // Do nothing until next character + case: + if prev == '\r' { // Turn a single carriage return into a \n + write_rune(&builder, '\n') + } + write_rune(&builder, t.r) + } + prev = t.r } - prev = t.r } } } diff --git a/tests/core/assets/XML/attribute-whitespace.xml b/tests/core/assets/XML/attribute-whitespace.xml new file mode 100644 index 000000000..6381225d5 --- /dev/null +++ b/tests/core/assets/XML/attribute-whitespace.xml @@ -0,0 +1,8 @@ + + +Barzle +<부끄러운:barzle> + Indeed! + \ No newline at end of file diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 09d1a4611..b29431e10 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -146,6 +146,20 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) { }) } +@(test) +xml_test_attribute_whitespace :: proc(t: ^testing.T) { + run_test(t, { + // Same as above. + // Unbox CDATA in data tag. + filename = "XML/attribute-whitespace.xml", + options = { + flags = {}, + expected_doctype = "foozle", + }, + crc32 = 0x8f5fd6c1, + }) +} + @(test) xml_test_invalid_doctype :: proc(t: ^testing.T) { run_test(t, { From f57c03c1707f48608bcb3bc87aeee91af60e6d63 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jun 2024 12:40:29 +0100 Subject: [PATCH 08/20] Improve matrix type hinting rules a little --- src/check_expr.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 01cba881e..742909701 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3568,6 +3568,8 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand // prefer the named type x->type = y->type; } + // finish + return; } else { bool is_row_major = xt->Matrix.is_row_major && yt->Matrix.is_row_major; x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count, nullptr, nullptr, is_row_major); From c5f7788652c6f46ae9b1588c8e3638d58c49c92b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jun 2024 12:54:57 +0100 Subject: [PATCH 09/20] Check to see if matrices are exactly the same type --- src/check_expr.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 742909701..0f9bb781e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3564,12 +3564,13 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand x->mode = Addressing_Value; if (are_types_identical(xt, yt)) { + if (are_types_identical(x->type, y->type)) { + return; + } if (!is_type_named(x->type) && is_type_named(y->type)) { // prefer the named type x->type = y->type; } - // finish - return; } else { bool is_row_major = xt->Matrix.is_row_major && yt->Matrix.is_row_major; x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count, nullptr, nullptr, is_row_major); From d37b5a7b67e5886c3361a81287e077505eed80b5 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 12 Jun 2024 19:54:14 +0200 Subject: [PATCH 10/20] Make rl.MatrixToFloatV transpose the matrix before transmuting it to [16]f32, so it does the same thing as the raymath version implemented in C. --- vendor/raylib/raymath.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/raylib/raymath.odin b/vendor/raylib/raymath.odin index 9682ffe4f..eef5c2fcd 100644 --- a/vendor/raylib/raymath.odin +++ b/vendor/raylib/raymath.odin @@ -668,7 +668,7 @@ MatrixLookAt :: proc "c" (eye, target, up: Vector3) -> Matrix { // Get float array of matrix data @(require_results) MatrixToFloatV :: proc "c" (mat: Matrix) -> [16]f32 { - return transmute([16]f32)mat + return transmute([16]f32)linalg.transpose(mat) } From c7ea4ec71c8aaac234e1882a02be9ee42175ff4e Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 12 Jun 2024 21:13:12 +0200 Subject: [PATCH 11/20] rlgl: Pull in raylib and expose missing types, so it is the same as rlgl.h. This makes rlgl less stand-alone, but I left some notes in rlgl.odin how to easily make it stand-alone if one really wants to. --- vendor/raylib/rlgl/rlgl.odin | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/vendor/raylib/rlgl/rlgl.odin b/vendor/raylib/rlgl/rlgl.odin index b36764830..cef31c238 100644 --- a/vendor/raylib/rlgl/rlgl.odin +++ b/vendor/raylib/rlgl/rlgl.odin @@ -108,22 +108,41 @@ package rlgl import "core:c" +import rl "../." VERSION :: "5.0" +RAYLIB_SHARED :: #config(RAYLIB_SHARED, false) + +// Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then: +// - Compile a separate rlgl library and use that in the foreign import blocks below. +// - Remove the `import rl "../."` line +// - Copy the code from raylib.odin for any types we alias from that package (see PixelFormat etc) + when ODIN_OS == .Windows { + @(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt")) foreign import lib { - "../windows/raylib.lib", + "../windows/raylibdll.lib" when RAYLIB_SHARED else "../windows/raylib.lib" , "system:Winmm.lib", "system:Gdi32.lib", "system:User32.lib", "system:Shell32.lib", } } else when ODIN_OS == .Linux { - foreign import lib "../linux/libraylib.a" + foreign import lib { + // Note(bumbread): I'm not sure why in `linux/` folder there are + // multiple copies of raylib.so, but since these bindings are for + // particular version of the library, I better specify it. Ideally, + // though, it's best specified in terms of major (.so.4) + "../linux/libraylib.so.500" when RAYLIB_SHARED else "../linux/libraylib.a", + "system:dl", + "system:pthread", + } } else when ODIN_OS == .Darwin { foreign import lib { - "../macos-arm64/libraylib.a" when ODIN_ARCH == .arm64 else "../macos/libraylib.a", + "../macos" + + ("-arm64" when ODIN_ARCH == .arm64 else "") + + "/libraylib" + (".500.dylib" when RAYLIB_SHARED else ".a"), "system:Cocoa.framework", "system:OpenGL.framework", "system:IOKit.framework", @@ -249,7 +268,6 @@ BLEND_DST_ALPHA :: 0x80CA // GL_BLEND_DST_ALPHA BLEND_SRC_ALPHA :: 0x80CB // GL_BLEND_SRC_ALPHA BLEND_COLOR :: 0x8005 // GL_BLEND_COLOR - //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -291,7 +309,6 @@ RenderBatch :: struct { currentDepth: f32, // Current depth value for next draw } - // OpenGL version GlVersion :: enum c.int { OPENGL_11 = 1, // OpenGL 1.1 @@ -302,6 +319,11 @@ GlVersion :: enum c.int { OPENGL_ES_30, // OpenGL ES 3.0 (GLSL 300 es) } +PixelFormat :: rl.PixelFormat +TextureFilter :: rl.TextureFilter +BlendMode :: rl.BlendMode +ShaderLocationIndex :: rl.ShaderLocationIndex +ShaderUniformDataType :: rl.ShaderUniformDataType // Shader attribute data types ShaderAttributeDataType :: enum c.int { @@ -343,8 +365,7 @@ CullMode :: enum c.int { BACK, } -// Matrix type (right handed, stored row major) -Matrix :: #row_major matrix[4, 4]f32 +Matrix :: rl.Matrix @(default_calling_convention="c", link_prefix="rl") foreign lib { From 33270f14a41a61137351907ccaa5317afbe47ad5 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 12 Jun 2024 15:31:43 -0400 Subject: [PATCH 12/20] Fix #3739 --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0f9bb781e..359b30276 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2550,7 +2550,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n"); } - if (is_type_map(parent_type)) { + if (parent_type != nullptr && is_type_map(parent_type)) { error_line("\t Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string)); } else { error_line("\t Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string)); From a804463a575b2b543d8494402a3cdb9621a3bcc6 Mon Sep 17 00:00:00 2001 From: jasonkercher Date: Wed, 12 Jun 2024 15:31:59 -0400 Subject: [PATCH 13/20] add COMMTIMEOUTS, get/setCommTimeouts --- core/sys/windows/kernel32.odin | 13 +++++++++++++ 1 file changed, 13 insertions(+) mode change 100644 => 100755 core/sys/windows/kernel32.odin diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin old mode 100644 new mode 100755 index 16b6fa244..3c60cfc43 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -1153,6 +1153,19 @@ foreign kernel32 { SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- } +COMMTIMEOUTS :: struct { + ReadIntervalTimeout: DWORD, + ReadTotalTimeoutMultiplier: DWORD, + ReadTotalTimeoutConstant: DWORD, + WriteTotalTimeoutMultiplier: DWORD, + WriteTotalTimeoutConstant: DWORD, +} + +@(default_calling_convention="system") +foreign kernel32 { + GetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- + SetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- +} LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID) From 0c9f487783227a894fe08fdf51bbef0dc2f0dbc3 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 12 Jun 2024 18:48:01 -0400 Subject: [PATCH 14/20] Fix and document `%w` verb for `core:fmt` --- core/fmt/doc.odin | 1 + core/fmt/fmt.odin | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/core/fmt/doc.odin b/core/fmt/doc.odin index be666dcc4..d45e6c796 100644 --- a/core/fmt/doc.odin +++ b/core/fmt/doc.odin @@ -9,6 +9,7 @@ The verbs: General: %v the value in a default format %#v an expanded format of %v with newlines and indentation + %w an Odin-syntax representation of the value %T an Odin-syntax representation of the type of the value %% a literal percent sign; consumes no value {{ a literal open brace; consumes no value diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index f9113a7a7..4c65dd01f 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1726,10 +1726,12 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') { et := runtime.type_info_base(info.elem) - if name != "" { - io.write_string(fi.writer, name, &fi.n) - } else { - reflect.write_type(fi.writer, type_info, &fi.n) + if verb != 'w' { + if name != "" { + io.write_string(fi.writer, name, &fi.n) + } else { + reflect.write_type(fi.writer, type_info, &fi.n) + } } io.write_byte(fi.writer, '{', &fi.n) defer io.write_byte(fi.writer, '}', &fi.n) @@ -1746,9 +1748,17 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') { } if is_enum { + enum_name: string + if ti_named, is_named := info.elem.variant.(runtime.Type_Info_Named); is_named { + enum_name = ti_named.name + } for ev, evi in e.values { v := u64(ev) if v == u64(i) { + if verb == 'w' { + io.write_string(fi.writer, enum_name, &fi.n) + io.write_byte(fi.writer, '.', &fi.n) + } io.write_string(fi.writer, e.names[evi], &fi.n) commas += 1 continue loop @@ -2391,7 +2401,6 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named) runtime.Type_Info_Dynamic_Array, runtime.Type_Info_Slice, runtime.Type_Info_Struct, - runtime.Type_Info_Union, runtime.Type_Info_Enum, runtime.Type_Info_Map, runtime.Type_Info_Bit_Set, @@ -2498,8 +2507,9 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix } } else { // Printed in Row-Major layout to match text layout + row_separator := ", " if verb == 'w' else "; " for row in 0.. 0 { io.write_string(fi.writer, "; ", &fi.n) } + if row > 0 { io.write_string(fi.writer, row_separator, &fi.n) } for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } From abe5c2ca83c8c893fa98626448d43c63d9d23a6f Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:04:47 -0400 Subject: [PATCH 15/20] Add test for `%w` --- tests/core/fmt/test_core_fmt.odin | 114 ++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/tests/core/fmt/test_core_fmt.odin b/tests/core/fmt/test_core_fmt.odin index 507e0f433..49142e24d 100644 --- a/tests/core/fmt/test_core_fmt.odin +++ b/tests/core/fmt/test_core_fmt.odin @@ -258,6 +258,120 @@ test_pointers :: proc(t: ^testing.T) { check(t, "0xFFFF", "%#4p", d) } +@(test) +test_odin_value_export :: proc(t: ^testing.T) { + E :: enum u32 { + A, B, C, + } + + F :: enum i16 { + A, B, F, + } + + S :: struct { + j, k: int, + } + + ST :: struct { + x: int `fmt:"-"`, + y: u8 `fmt:"r,0"`, + z: string `fmt:"s,0"`, + } + + U :: union { + i8, + i16, + } + + UEF :: union { E, F } + + A :: [2]int + + BSE :: distinct bit_set[E] + + i : int = 64 + f : f64 = 3.14 + c : complex128 = 7+3i + q : quaternion256 = 1+2i+3j+4k + mat : matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8} + matc : #column_major matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8} + e : enum {A, B, C} = .B + en : E = E.C + ena : [2]E = {E.A, E.C} + s : struct { j: int, k: int } = { j = 16, k = 8 } + sn : S = S{ j = 24, k = 12 } + st : ST = { 32768, 57, "Hellope" } + str : string = "Hellope" + strc : cstring = "Hellope" + bsu : bit_set[0..<32; u32] = {0, 1} + bs : bit_set[4..<16] = {5, 7} + bse : bit_set[E] = { .B, .A } + bsE : BSE = { .A, .C } + arr : [3]int = {1, 2, 3} + ars : [3]S = {S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}} + darr : [dynamic]u8 = { 128, 64, 32 } + dars : [dynamic]S = {S{j = 1, k = 2}, S{j = 3, k = 4}} + na : A = {7, 5} + may0 : Maybe(int) + may1 : Maybe(int) = 1 + uz : union {i8, i16} = i8(-33) + u0 : U = U(nil) + u1 : U = i16(42) + uef0 : UEF = E.A + uefa : [3]UEF = { E.A, F.A, F.F } + map_ : map[string]u8 = {"foo" = 8, "bar" = 4} + + bf : bit_field int { + a: int | 4, + b: int | 4, + e: E | 4, + } = {a = 1, b = 2, e = .A} + + defer { + delete(darr) + delete(dars) + delete(map_) + } + + check(t, "64", "%w", i) + check(t, "3.14", "%w", f) + check(t, "7+3i", "%w", c) + check(t, "1+2i+3j+4k", "%w", q) + check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}", "%w", mat) + check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}", "%w", matc) + check(t, ".B", "%w", e) + check(t, "E.C", "%w", en) + check(t, "{E.A, E.C}", "%w", ena) + check(t, "{j = 16, k = 8}", "%w", s) + check(t, "S{j = 24, k = 12}", "%w", sn) + check(t, `ST{y = 57, z = "Hellope"}`, "%w", st) + check(t, `"Hellope"`, "%w", str) + check(t, `"Hellope"`, "%w", strc) + check(t, "{0, 1}", "%w", bsu) + check(t, "{5, 7}", "%w", bs) + check(t, "{E.A, E.B}", "%w", bse) + check(t, "{E.A, E.C}", "%w", bsE) + check(t, "{1, 2, 3}", "%w", arr) + check(t, "{S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}", "%w", ars) + check(t, "{128, 64, 32}", "%w", darr) + check(t, "{S{j = 1, k = 2}, S{j = 3, k = 4}}", "%w", dars) + check(t, "{7, 5}", "%w", na) + check(t, "nil", "%w", may0) + check(t, "1", "%w", may1) + check(t, "-33", "%w", uz) + check(t, "nil", "%w", u0) + check(t, "42", "%w", u1) + check(t, "E.A", "%w", uef0) + check(t, "{E.A, F.A, F.F}", "%w", uefa) + check(t, "{a = 1, b = 2, e = E.A}", "%w", bf) + // Check this manually due to the non-deterministic ordering of map keys. + switch fmt.tprintf("%w", map_) { + case `{"foo"=8, "bar"=4}`: break + case `{"bar"=4, "foo"=8}`: break + case: testing.fail(t) + } +} + @(private) check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) { got := fmt.tprintf(format, ..args) From 3d4e23d741b4031572ce5350fe51870e050ca297 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 13 Jun 2024 11:33:37 +0200 Subject: [PATCH 16/20] Add example of a custom formatter. --- core/fmt/example.odin | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 core/fmt/example.odin diff --git a/core/fmt/example.odin b/core/fmt/example.odin new file mode 100644 index 000000000..503e64f2b --- /dev/null +++ b/core/fmt/example.odin @@ -0,0 +1,57 @@ +//+build ignore +package custom_formatter_example +import "core:fmt" +import "core:io" + +SomeType :: struct { + value: int, +} + +My_Custom_Base_Type :: distinct u32 + +main :: proc() { + // Ensure the fmt._user_formatters map is initialized + fmt.set_user_formatters(new(map[typeid]fmt.User_Formatter)) + + // Register custom formatters for my favorite types + err := fmt.register_user_formatter(type_info_of(SomeType).id, SomeType_Formatter) + assert(err == .None) + err = fmt.register_user_formatter(type_info_of(My_Custom_Base_Type).id, My_Custom_Base_Formatter) + assert(err == .None) + + // Use the custom formatters. + fmt.printfln("SomeType{{42}}: '%v'", SomeType{42}) + fmt.printfln("My_Custom_Base_Type(0xdeadbeef): '%v'", My_Custom_Base_Type(0xdeadbeef)) +} + +SomeType_Formatter :: proc(fi: ^fmt.Info, arg: any, verb: rune) -> bool { + m := cast(^SomeType)arg.data + switch verb { + case 'v', 'd': // We handle `%v` and `%d` + fmt.fmt_int(fi, u64(m.value), true, 8 * size_of(SomeType), verb) + case: + return false + } + return true +} + +My_Custom_Base_Formatter :: proc(fi: ^fmt.Info, arg: any, verb: rune) -> bool { + m := cast(^My_Custom_Base_Type)arg.data + switch verb { + case 'v', 'b': + value := u64(m^) + for value > 0 { + if value & 1 == 1 { + io.write_string(fi.writer, "Hellope!", &fi.n) + } else { + io.write_string(fi.writer, "Hellope?", &fi.n) + } + value >>= 1 + } + + case: + return false + } + return true +} + From 657c51636080e9b3c9c2215d05b08f3cccf68e70 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Wed, 12 Jun 2024 20:58:28 +0200 Subject: [PATCH 17/20] =?UTF-8?q?Pad=20=E2=80=98^~~~^=E2=80=99-style=20dia?= =?UTF-8?q?gnostic=20ranges=20properly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/error.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/error.cpp b/src/error.cpp index 03d96219b..5a4cb6a0c 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -323,8 +323,13 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { } error_out("\n\t"); - for (i32 i = 0; i < offset; i++) { - error_out(" "); + for (i32 rune_width, off = 0; off < offset; off += rune_width) { + i32 rune; + rune_width = cast(i32)utf8proc_iterate((u8 const *)line_text + off, line_len - off, &rune); + int w = utf8proc_charwidth(rune); + if (w > 0) { + error_out("%.*s", w, " "); + } } terminal_set_colours(TerminalStyle_Bold, TerminalColour_Green); From 9f190f3937628595ecd8f6c784b85d7be6e0254a Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Thu, 13 Jun 2024 16:42:04 +0200 Subject: [PATCH 18/20] Generate ranges of the correct length --- src/error.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/error.cpp b/src/error.cpp index 5a4cb6a0c..cdf3b806a 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -336,15 +336,27 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { error_out("^"); if (end.file_id == pos.file_id) { + i32 rune; + if (end.line > pos.line) { - for (i32 i = offset; i < line_len; i++) { - error_out("~"); + for (i32 rune, rune_width, off = offset; off < line_len; off += rune_width) { + rune_width = cast(i32)utf8proc_iterate((u8 const *)line_text + off, line_len - off, &rune); + int w = utf8proc_charwidth(rune); + if (w > 0) { + error_out("%.*s", w, "~~~~"); + } } } else if (end.line == pos.line && end.column > pos.column) { - for (i32 i = 1; i < error_length-1+squiggle_extra; i++) { + i32 columns = squiggle_extra; + for (i32 rune, rune_width, off = offset; off < offset + error_length - 1; off += rune_width) { + rune_width = cast(i32)utf8proc_iterate((u8 const *)line_text + off, line_len - off, &rune); + columns += utf8proc_charwidth(rune); + } + + for (i32 i = 0; i < columns - 1; i++) { error_out("~"); } - if (error_length > 1 && squiggle_extra == 0) { + if (columns > 0 && squiggle_extra == 0) { error_out("^"); } } From ca9d1f940d4118f0652d11cbcd50dc4209d54720 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 13 Jun 2024 17:23:30 +0200 Subject: [PATCH 19/20] Just change squiggle_extra type to i32. --- src/error.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.cpp b/src/error.cpp index cdf3b806a..a63dec43a 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -296,7 +296,7 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { terminal_set_colours(TerminalStyle_Bold, TerminalColour_White); - isize squiggle_extra = 0; + i32 squiggle_extra = 0; if (line_len > MAX_LINE_LENGTH_PADDED) { i32 left = MAX_TAB_WIDTH; From 9f7ac1469fc364330ada811032d295ba36f6e078 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Thu, 13 Jun 2024 16:42:04 +0200 Subject: [PATCH 20/20] Generate ranges of the correct length --- src/error.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/error.cpp b/src/error.cpp index 5a4cb6a0c..1e24325c5 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -336,15 +336,27 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { error_out("^"); if (end.file_id == pos.file_id) { + i32 rune; + if (end.line > pos.line) { - for (i32 i = offset; i < line_len; i++) { - error_out("~"); + for (i32 rune, rune_width, off = offset; off < line_len; off += rune_width) { + rune_width = cast(i32)utf8proc_iterate((u8 const *)line_text + off, line_len - off, &rune); + int w = utf8proc_charwidth(rune); + if (w > 0) { + error_out("%.*s", w, "~~~~"); + } } } else if (end.line == pos.line && end.column > pos.column) { - for (i32 i = 1; i < error_length-1+squiggle_extra; i++) { + isize columns = squiggle_extra; + for (i32 rune, rune_width, off = offset; off < offset + error_length - 1; off += rune_width) { + rune_width = cast(i32)utf8proc_iterate((u8 const *)line_text + off, line_len - off, &rune); + columns += utf8proc_charwidth(rune); + } + + for (isize i = 1; i < columns; i++) { error_out("~"); } - if (error_length > 1 && squiggle_extra == 0) { + if (columns > 0 && squiggle_extra == 0) { error_out("^"); } }