From 34af2bb8adc7f1cfb91530bcdcc954d72af68aee Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Tue, 11 Jun 2024 08:34:45 +0200 Subject: [PATCH 01/42] 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 02/42] 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 03/42] 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 6454c6f0879add3ed018065eff073a75d45229b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20H=C3=B6ltermann?= Date: Tue, 11 Jun 2024 09:35:59 +0200 Subject: [PATCH 04/42] Added some missing functions to core/sys/windows --- core/sys/windows/kernel32.odin | 14 ++++++++++++++ core/sys/windows/types.odin | 9 +++++++++ core/sys/windows/user32.odin | 11 +++++++++++ core/sys/windows/winerror.odin | 2 +- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index eba275522..d3b5a148b 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -64,6 +64,7 @@ foreign kernel32 { RemoveVectoredContinueHandler :: proc(Handle: LPVOID) -> DWORD --- RaiseException :: proc(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! --- + SetUnhandledExceptionFilter :: proc(lpTopLevelExceptionFilter: LPTOP_LEVEL_EXCEPTION_FILTER) -> LPTOP_LEVEL_EXCEPTION_FILTER --- CreateHardLinkW :: proc(lpSymlinkFileName: LPCWSTR, lpTargetFileName: LPCWSTR, @@ -464,6 +465,8 @@ foreign kernel32 { GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL --- RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT --- + + GetSystemPowerStatus :: proc(lpSystemPowerStatus: ^SYSTEM_POWER_STATUS) -> BOOL --- } DEBUG_PROCESS :: 0x00000001 @@ -1210,6 +1213,15 @@ SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct { DummyUnion: DUMMYUNIONNAME_u, } +SYSTEM_POWER_STATUS :: struct { + ACLineStatus: BYTE, + BatteryFlag: BYTE, + BatteryLifePercent: BYTE, + SystemStatusFlag: BYTE, + BatteryLifeTime: DWORD, + BatteryFullLifeTime: DWORD, +} + /* Global Memory Flags */ GMEM_FIXED :: 0x0000 GMEM_MOVEABLE :: 0x0002 @@ -1228,3 +1240,5 @@ GMEM_INVALID_HANDLE :: 0x8000 GHND :: (GMEM_MOVEABLE | GMEM_ZEROINIT) GPTR :: (GMEM_FIXED | GMEM_ZEROINIT) + +LPTOP_LEVEL_EXCEPTION_FILTER :: PVECTORED_EXCEPTION_HANDLER diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 11d2774d6..7ed322169 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -34,6 +34,7 @@ HGDIOBJ :: distinct HANDLE HBITMAP :: distinct HANDLE HGLOBAL :: distinct HANDLE HHOOK :: distinct HANDLE +HWINEVENTHOOK :: distinct HANDLE HKEY :: distinct HANDLE HDESK :: distinct HANDLE HFONT :: distinct HANDLE @@ -703,6 +704,14 @@ WNDPROC :: #type proc "system" (HWND, UINT, WPARAM, LPARAM) -> LRESULT HOOKPROC :: #type proc "system" (code: c_int, wParam: WPARAM, lParam: LPARAM) -> LRESULT +WINEVENTPROC :: #type proc "system" ( + hWinEventHook: HWINEVENTHOOK, + event: DWORD, + hwnd: HWND, + idObject, idChild: LONG, + idEventThread, dwmsEventTime: DWORD, +) + CWPRETSTRUCT :: struct { lResult: LRESULT, lParam: LPARAM, diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 1fc0116f5..6c053fed0 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -17,6 +17,17 @@ foreign user32 { GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: c_int) -> c_int --- + GetParent :: proc(hWnd: HWND) -> HWND --- + IsWindowVisible :: proc(hWnd: HWND) -> BOOL --- + SetWinEventHook :: proc( + eventMin, eventMax: DWORD, + hmodWinEventProc: HMODULE, + pfnWinEvenProc: WINEVENTPROC, + idProcess, idThread, dwmFlags: DWORD, + ) -> HWINEVENTHOOK --- + + IsChild :: proc(hWndParent, hWnd: HWND) -> BOOL --- + RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL --- diff --git a/core/sys/windows/winerror.odin b/core/sys/windows/winerror.odin index 118327ffa..c66a22322 100644 --- a/core/sys/windows/winerror.odin +++ b/core/sys/windows/winerror.odin @@ -47,7 +47,7 @@ ERROR_PIPE_BUSY : DWORD : 231 E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001 -SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool { return result >= 0 } +SUCCEEDED :: #force_inline proc "contextless" (#any_int result: int) -> bool { return result >= 0 } System_Error :: enum DWORD { From ebadff555d70d5ef8faf91785696e5c5ea3605f8 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 12 Jun 2024 12:52:48 +0200 Subject: [PATCH 05/42] 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 06/42] 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 07/42] 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 08/42] 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 09/42] 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 10/42] 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 11/42] 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 12/42] 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 13/42] 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 14/42] 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 50564a301e0d70476db54c84d9835bd4a6c27bfd Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 13 Jun 2024 10:20:58 +0200 Subject: [PATCH 15/42] Update kernel32 struct DCB. --- core/sys/windows/kernel32.odin | 139 +++++++-------------------------- 1 file changed, 30 insertions(+), 109 deletions(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 3c60cfc43..28d63db8e 100755 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -1009,31 +1009,9 @@ foreign kernel32 { HandlerRoutine :: proc "system" (dwCtrlType: DWORD) -> BOOL PHANDLER_ROUTINE :: HandlerRoutine +// NOTE(Jeroen, 2024-06-13): As Odin now supports bit_fields, we no longer need +// a helper procedure. `init_dcb_with_config` and `get_dcb_config` have been removed. - - -DCB_Config :: struct { - fParity: bool, - fOutxCtsFlow: bool, - fOutxDsrFlow: bool, - fDtrControl: DTR_Control, - fDsrSensitivity: bool, - fTXContinueOnXoff: bool, - fOutX: bool, - fInX: bool, - fErrorChar: bool, - fNull: bool, - fRtsControl: RTS_Control, - fAbortOnError: bool, - BaudRate: DWORD, - ByteSize: BYTE, - Parity: Parity, - StopBits: Stop_Bits, - XonChar: byte, - XoffChar: byte, - ErrorChar: byte, - EvtChar: byte, -} DTR_Control :: enum byte { Disable = 0, Enable = 1, @@ -1058,92 +1036,35 @@ Stop_Bits :: enum byte { Two = 2, } -// A helper procedure to set the values of a DCB structure. -init_dcb_with_config :: proc "contextless" (dcb: ^DCB, config: DCB_Config) { - out: u32 - - // NOTE(tetra, 2022-09-21): On both Clang 14 on Windows, and MSVC, the bits in the bitfield - // appear to be defined from LSB to MSB order. - // i.e: `fBinary` (the first bitfield in the C source) is the LSB in the `settings` u32. - - out |= u32(1) << 0 // fBinary must always be true on Windows. - - out |= u32(config.fParity) << 1 - out |= u32(config.fOutxCtsFlow) << 2 - out |= u32(config.fOutxDsrFlow) << 3 - - out |= u32(config.fDtrControl) << 4 - - out |= u32(config.fDsrSensitivity) << 6 - out |= u32(config.fTXContinueOnXoff) << 7 - out |= u32(config.fOutX) << 8 - out |= u32(config.fInX) << 9 - out |= u32(config.fErrorChar) << 10 - out |= u32(config.fNull) << 11 - - out |= u32(config.fRtsControl) << 12 - - out |= u32(config.fAbortOnError) << 14 - - dcb.settings = out - - dcb.BaudRate = config.BaudRate - dcb.ByteSize = config.ByteSize - dcb.Parity = config.Parity - dcb.StopBits = config.StopBits - dcb.XonChar = config.XonChar - dcb.XoffChar = config.XoffChar - dcb.ErrorChar = config.ErrorChar - dcb.EvtChar = config.EvtChar - - dcb.DCBlength = size_of(DCB) -} -get_dcb_config :: proc "contextless" (dcb: DCB) -> (config: DCB_Config) { - config.fParity = bool((dcb.settings >> 1) & 0x01) - config.fOutxCtsFlow = bool((dcb.settings >> 2) & 0x01) - config.fOutxDsrFlow = bool((dcb.settings >> 3) & 0x01) - - config.fDtrControl = DTR_Control((dcb.settings >> 4) & 0x02) - - config.fDsrSensitivity = bool((dcb.settings >> 6) & 0x01) - config.fTXContinueOnXoff = bool((dcb.settings >> 7) & 0x01) - config.fOutX = bool((dcb.settings >> 8) & 0x01) - config.fInX = bool((dcb.settings >> 9) & 0x01) - config.fErrorChar = bool((dcb.settings >> 10) & 0x01) - config.fNull = bool((dcb.settings >> 11) & 0x01) - - config.fRtsControl = RTS_Control((dcb.settings >> 12) & 0x02) - - config.fAbortOnError = bool((dcb.settings >> 14) & 0x01) - - config.BaudRate = dcb.BaudRate - config.ByteSize = dcb.ByteSize - config.Parity = dcb.Parity - config.StopBits = dcb.StopBits - config.XonChar = dcb.XonChar - config.XoffChar = dcb.XoffChar - config.ErrorChar = dcb.ErrorChar - config.EvtChar = dcb.EvtChar - - return -} - -// NOTE(tetra): See get_dcb_config() and init_dcb_with_config() for help with initializing this. DCB :: struct { - DCBlength: DWORD, // NOTE(tetra): Must be set to size_of(DCB). - BaudRate: DWORD, - settings: u32, // NOTE(tetra): These are bitfields in the C struct. - wReserved: WORD, - XOnLim: WORD, - XOffLim: WORD, - ByteSize: BYTE, - Parity: Parity, - StopBits: Stop_Bits, - XonChar: byte, - XoffChar: byte, - ErrorChar: byte, - EofChar: byte, - EvtChar: byte, + DCBlength: DWORD, + BaudRate: DWORD, + using _: bit_field DWORD { + fBinary: bool | 1, + fParity: bool | 1, + fOutxCtsFlow: bool | 1, + fOutxDsrFlow: bool | 1, + fDtrControl: DTR_Control | 2, + fDsrSensitivity: bool | 1, + fTXContinueOnXoff: bool | 1, + fOutX: bool | 1, + fInX: bool | 1, + fErrorChar: bool | 1, + fNull: bool | 1, + fRtsControl: RTS_Control | 2, + fAbortOnError: bool | 1, + }, + wReserved: WORD, + XOnLim: WORD, + XOffLim: WORD, + ByteSize: BYTE, + Parity: Parity, + StopBits: Stop_Bits, + XonChar: byte, + XoffChar: byte, + ErrorChar: byte, + EofChar: byte, + EvtChar: byte, wReserved1: WORD, } 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/42] 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/42] =?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/42] 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/42] 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/42] 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("^"); } } From c560553c21b970d38a302a11e94181de5415d043 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:01:51 -0400 Subject: [PATCH 21/42] Fix compiler silently returning if `parse_packages` fails --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 70def5802..f4cd40fe9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2934,7 +2934,8 @@ int main(int arg_count, char const **arg_ptr) { // TODO(jeroen): Remove the `init_filename` param. // Let's put that on `build_context.build_paths[0]` instead. if (parse_packages(parser, init_filename) != ParseFile_None) { - return 1; + GB_ASSERT_MSG(any_errors(), "parse_packages failed but no error was reported."); + // We depend on the next conditional block to return 1, after printing errors. } if (any_errors()) { From ff4787070d9673a417f549f1b9452e675c96f992 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 14 Jun 2024 00:06:55 +0200 Subject: [PATCH 22/42] Revert "Merge pull request #3744 from Mango0x45/master" This reverts commit 45044de0b756f9ab018979abd5350533334a54ac, reversing changes made to 20c17ba6f971cf572da4fa5e9601e0df8d517112. --- src/error.cpp | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/src/error.cpp b/src/error.cpp index d0089c952..03d96219b 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); - i32 squiggle_extra = 0; + isize squiggle_extra = 0; if (line_len > MAX_LINE_LENGTH_PADDED) { i32 left = MAX_TAB_WIDTH; @@ -323,39 +323,23 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { } error_out("\n\t"); - 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, " "); - } + for (i32 i = 0; i < offset; i++) { + error_out(" "); } terminal_set_colours(TerminalStyle_Bold, TerminalColour_Green); error_out("^"); if (end.file_id == pos.file_id) { - i32 rune; - if (end.line > pos.line) { - 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) { - 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 = 1; i < columns; i++) { + for (i32 i = offset; i < line_len; i++) { error_out("~"); } - if (columns > 0 && squiggle_extra == 0) { + } else if (end.line == pos.line && end.column > pos.column) { + for (i32 i = 1; i < error_length-1+squiggle_extra; i++) { + error_out("~"); + } + if (error_length > 1 && squiggle_extra == 0) { error_out("^"); } } From ec7b77fc0f6ed20eecf25039c6acbe2050cef877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20H=C3=B6ltermann?= Date: Fri, 14 Jun 2024 16:32:41 +0200 Subject: [PATCH 23/42] Improved win32 bindings according to Kelimions suggestions with enums and bitsets --- core/sys/windows/kernel32.odin | 21 ++++++++++++++++++--- core/sys/windows/user32.odin | 12 +++++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index e50f18984..86f6b86f0 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -1214,13 +1214,28 @@ SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct { } SYSTEM_POWER_STATUS :: struct { - ACLineStatus: BYTE, - BatteryFlag: BYTE, + ACLineStatus: AC_Line_Status, + BatteryFlag: Battery_Flags, BatteryLifePercent: BYTE, SystemStatusFlag: BYTE, BatteryLifeTime: DWORD, BatteryFullLifeTime: DWORD, -} +} + +AC_Line_Status :: enum BYTE { + Offline = 0, + Online = 1, + Unknown = 255, +} + +Battery_Flag :: enum BYTE { + High = 0, + Low = 1, + Critical = 2, + Charging = 3, + No_Battery = 7, +} +Battery_Flags :: bit_set[Battery_Flag; BYTE] /* Global Memory Flags */ GMEM_FIXED :: 0x0000 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 6c053fed0..380c0ac56 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -23,7 +23,8 @@ foreign user32 { eventMin, eventMax: DWORD, hmodWinEventProc: HMODULE, pfnWinEvenProc: WINEVENTPROC, - idProcess, idThread, dwmFlags: DWORD, + idProcess, idThread: DWORD, + dwFlags: WinEventFlags, ) -> HWINEVENTHOOK --- IsChild :: proc(hWndParent, hWnd: HWND) -> BOOL --- @@ -579,3 +580,12 @@ RedrawWindowFlags :: enum UINT { RDW_FRAME = 0x0400, RDW_NOFRAME = 0x0800, } + +WinEventFlags :: bit_set[WinEventFlag; DWORD] + +WinEventFlag :: enum DWORD { + WINEVENT_OUTOFCONTEXT = 0, + WINEVENT_SKIPOWNTHREAD = 1, + WINEVENT_SKIPOWNPROCESS = 2, + WINEVENT_INCONTEXT = 4, +} From 3c3f0f90c2c8d063845cf0ecb61a23705749e445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20H=C3=B6ltermann?= Date: Fri, 14 Jun 2024 17:41:21 +0200 Subject: [PATCH 24/42] Fixed WinEventFlags --- core/sys/windows/user32.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 380c0ac56..3bc083acb 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -581,11 +581,11 @@ RedrawWindowFlags :: enum UINT { RDW_NOFRAME = 0x0800, } +// OUTOFCONTEXT is the zero value, use {} WinEventFlags :: bit_set[WinEventFlag; DWORD] WinEventFlag :: enum DWORD { - WINEVENT_OUTOFCONTEXT = 0, - WINEVENT_SKIPOWNTHREAD = 1, - WINEVENT_SKIPOWNPROCESS = 2, - WINEVENT_INCONTEXT = 4, + SKIPOWNTHREAD = 0, + SKIPOWNPROCESS = 1, + INCONTEXT = 2, } From 8ba644dd79ef878d619abbca9de8b52856ae96c1 Mon Sep 17 00:00:00 2001 From: Damian Tarnawski Date: Fri, 14 Jun 2024 19:45:54 +0200 Subject: [PATCH 25/42] Add `#no_bounds_check` to `slice.equal` --- core/slice/slice.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 3cab9189d..d8f4df88e 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -180,7 +180,7 @@ binary_search_by :: proc(array: $A/[]$T, key: T, f: proc(T, T) -> Ordering) -> ( } @(require_results) -equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) { +equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) #no_bounds_check { if len(a) != len(b) { return false } @@ -736,4 +736,4 @@ bitset_to_enum_slice_with_make :: proc(bs: $T, $E: typeid, allocator := context. return bitset_to_enum_slice(buf, bs) } -bitset_to_enum_slice :: proc{bitset_to_enum_slice_with_make, bitset_to_enum_slice_with_buffer} \ No newline at end of file +bitset_to_enum_slice :: proc{bitset_to_enum_slice_with_make, bitset_to_enum_slice_with_buffer} From 759139089fc38c59882a29bce7dee031fa6385b3 Mon Sep 17 00:00:00 2001 From: Josh Jones Date: Fri, 14 Jun 2024 19:58:13 +0200 Subject: [PATCH 26/42] Fix big.shrink not actually shrinking --- core/math/big/internal.odin | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index fa747e46a..360d063e9 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2178,15 +2178,20 @@ internal_int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator } /* - If not yet iniialized, initialize the `digit` backing with the allocator we were passed. + If not yet initialized, initialize the `digit` backing with the allocator we were passed. */ if cap == 0 { a.digit = make([dynamic]DIGIT, needed, allocator) - } else if cap != needed { + } else if cap < needed { /* `[dynamic]DIGIT` already knows what allocator was used for it, so resize will do the right thing. */ resize(&a.digit, needed) + } else if cap > needed && allow_shrink { + /* + Same applies to builtin.shrink here as resize above + */ + builtin.shrink(&a.digit, needed) } /* Let's see if the allocation/resize worked as expected. From 908a6ff2d487401b7e72cd1b7a3c1bd32c86c99a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 14 Jun 2024 21:34:05 +0200 Subject: [PATCH 27/42] Elide unnecessary condition --- core/math/big/internal.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 360d063e9..29bdf555c 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2187,7 +2187,7 @@ internal_int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator `[dynamic]DIGIT` already knows what allocator was used for it, so resize will do the right thing. */ resize(&a.digit, needed) - } else if cap > needed && allow_shrink { + } else if cap > needed { /* Same applies to builtin.shrink here as resize above */ From dc4ec8638c1b1dcf493c296b56b39afabe90098b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 14:45:57 +0100 Subject: [PATCH 28/42] Add `runtime.Random_Generator` interface --- base/runtime/core.odin | 19 +++++++++++++++++++ core/crypto/crypto.odin | 20 ++++++++++++++++++++ core/math/rand/rand.odin | 27 +++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 8671920f5..9669e86aa 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -397,11 +397,30 @@ Logger :: struct { options: Logger_Options, } + +Random_Generator_Mode :: enum { + Read, + Query_Info, +} + +Random_Generator_Query_Info_Flag :: enum u32 { + Cryptographic, + Uniform, + External_Entropy, +} +Random_Generator_Query_Info :: distinct bit_set[Random_Generator_Query_Info_Flag; u32] + +Random_Generator :: struct { + procedure: proc(data: rawptr, mode: Random_Generator_Mode, p: []byte), + data: rawptr, +} + Context :: struct { allocator: Allocator, temp_allocator: Allocator, assertion_failure_proc: Assertion_Failure_Proc, logger: Logger, + random_generator: Random_Generator, user_ptr: rawptr, user_index: int, diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin index f0874cc6d..99835e66f 100644 --- a/core/crypto/crypto.odin +++ b/core/crypto/crypto.odin @@ -4,6 +4,7 @@ helper routines. */ package crypto +import "base:runtime" import "core:mem" // compare_constant_time returns 1 iff a and b are equal, 0 otherwise. @@ -58,3 +59,22 @@ rand_bytes :: proc (dst: []byte) { _rand_bytes(dst) } + + +to_random_generator :: proc() -> runtime.Random_Generator { + return { + procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) { + switch mode { + case .Read: + rand_bytes(p) + case .Query_Info: + if len(p) != size_of(runtime.Random_Generator_Query_Info) { + return + } + info := (^runtime.Random_Generator_Query_Info)(raw_data(p)) + info^ += {.Uniform, .Cryptographic, .External_Entropy} + } + }, + data = nil, + } +} \ No newline at end of file diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 664d6abc9..552af6b8d 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -5,6 +5,7 @@ Package core:math/rand implements various random number generators package rand import "base:intrinsics" +import "base:runtime" import "core:crypto" import "core:math" import "core:mem" @@ -15,6 +16,28 @@ Rand :: struct { is_system: bool, } +to_random_generator :: proc(r: ^Rand) -> runtime.Random_Generator { + return { + procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) { + r := (^Rand)(data) + switch mode { + case .Read: + _ = read(p, r) + case .Query_Info: + if len(p) != size_of(runtime.Random_Generator_Query_Info) { + return + } + info := (^runtime.Random_Generator_Query_Info)(raw_data(p)) + info^ += {.Uniform} + if r.is_system { + info^ += {.External_Entropy} + } + } + }, + data = r, + } +} + @(private) global_rand := create(u64(intrinsics.read_cycle_counter())) @@ -150,6 +173,10 @@ _random_u64 :: proc(r: ^Rand) -> u64 { r := r switch { case r == nil: + if res: u64; runtime.random_generator_read_ptr(context.random_generator, &res, size_of(res)) { + return res + } + r = &global_rand case r.is_system: value: u64 From 827cb24023d38c5e14397bd50e363962528b4329 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 14:47:37 +0100 Subject: [PATCH 29/42] Add random_generator.odin --- base/runtime/random_generator.odin | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 base/runtime/random_generator.odin diff --git a/base/runtime/random_generator.odin b/base/runtime/random_generator.odin new file mode 100644 index 000000000..2b66b3e0b --- /dev/null +++ b/base/runtime/random_generator.odin @@ -0,0 +1,27 @@ +package runtime + +@(require_results) +random_generator_read_bytes :: proc(rg: Random_Generator, p: []byte) -> bool { + if rg.procedure != nil { + rg.procedure(rg.data, .Read, p) + return true + } + return false +} + +@(require_results) +random_generator_read_ptr :: proc(rg: Random_Generator, p: rawptr, len: uint) -> bool { + if rg.procedure != nil { + rg.procedure(rg.data, .Read, ([^]byte)(p)[:len]) + return true + } + return false +} + +@(require_results) +random_generator_query_info :: proc(rg: Random_Generator) -> (info: Random_Generator_Query_Info) { + if rg.procedure != nil { + rg.procedure(rg.data, .Query_Info, ([^]byte)(&info)[:size_of(info)]) + } + return +} \ No newline at end of file From c2a01096c4c83516c1bf966aa52f06f8d53a9d47 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 14:49:09 +0100 Subject: [PATCH 30/42] Remove unneeded reassignment of `r` --- core/math/rand/normal.odin | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core/math/rand/normal.odin b/core/math/rand/normal.odin index c8681db80..31b9a2387 100644 --- a/core/math/rand/normal.odin +++ b/core/math/rand/normal.odin @@ -115,13 +115,6 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 { 0.008624485, 0.005548995, 0.0026696292, } - r := r - if r == nil { - // NOTE(bill, 2020-09-07): Do this so that people can - // enforce the global random state if necessary with `nil` - r = &global_rand - } - for { j := i32(uint32(r)) i := j & 0x7f From eaec8a2bbf26c80f20aee10798236a4eb21dcf24 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 15:08:49 +0100 Subject: [PATCH 31/42] Add `runtime.default_random_generator` --- base/runtime/core.odin | 7 +++- base/runtime/random_generator.odin | 64 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 9669e86aa..a4a433d94 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -410,8 +410,10 @@ Random_Generator_Query_Info_Flag :: enum u32 { } Random_Generator_Query_Info :: distinct bit_set[Random_Generator_Query_Info_Flag; u32] +Random_Generator_Proc :: #type proc(data: rawptr, mode: Random_Generator_Mode, p: []byte) + Random_Generator :: struct { - procedure: proc(data: rawptr, mode: Random_Generator_Mode, p: []byte), + procedure: Random_Generator_Proc, data: rawptr, } @@ -727,6 +729,9 @@ __init_context :: proc "contextless" (c: ^Context) { c.logger.procedure = default_logger_proc c.logger.data = nil + + c.random_generator.procedure = default_random_generator_proc + c.random_generator.data = nil } default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! { diff --git a/base/runtime/random_generator.odin b/base/runtime/random_generator.odin index 2b66b3e0b..7746f1429 100644 --- a/base/runtime/random_generator.odin +++ b/base/runtime/random_generator.odin @@ -1,5 +1,7 @@ package runtime +import "base:intrinsics" + @(require_results) random_generator_read_bytes :: proc(rg: Random_Generator, p: []byte) -> bool { if rg.procedure != nil { @@ -24,4 +26,66 @@ random_generator_query_info :: proc(rg: Random_Generator) -> (info: Random_Gener rg.procedure(rg.data, .Query_Info, ([^]byte)(&info)[:size_of(info)]) } return +} + + +@(private="file") +Default_Random_State :: struct { + state: u64, + inc: u64, +} + +default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, p: []byte) { + @(require_results) + read_u64 :: proc "contextless" (r: ^Default_Random_State) -> u64 { + old_state := r.state + r.state = old_state * 6364136223846793005 + (r.inc|1) + xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081 + rot := (old_state >> 59) + return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63)) + } + + @(thread_local) + global_rand_seed: Default_Random_State + + switch mode { + case .Read: + r := &global_rand_seed + + if r.state == 0 && + r.inc == 0 { + seed := u64(intrinsics.read_cycle_counter()) + r.state = 0 + r.inc = (seed << 1) | 1 + _ = read_u64(r) + r.state += seed + _ = read_u64(r) + } + + pos := i8(0) + val := u64(0) + for &v in p { + if pos == 0 { + val = read_u64(r) + pos = 7 + } + v = byte(val) + val >>= 8 + pos -= 1 + } + return + case .Query_Info: + if len(p) != size_of(Random_Generator_Query_Info) { + return + } + info := (^Random_Generator_Query_Info)(raw_data(p)) + info^ += {.Uniform} + } +} + +default_random_generator :: proc "contextless" () -> Random_Generator { + return { + procedure = default_random_generator_proc, + data = nil, + } } \ No newline at end of file From 318d5e4a7eb25e2204ec04a1b0c4a82e75726d19 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 15:17:23 +0100 Subject: [PATCH 32/42] Add `Reset` mode --- base/runtime/core.odin | 2 ++ base/runtime/random_generator.odin | 36 +++++++++++++++++++----------- core/crypto/crypto.odin | 2 ++ core/math/rand/rand.odin | 12 ++++++++++ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/base/runtime/core.odin b/base/runtime/core.odin index a4a433d94..550daed3b 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -400,6 +400,7 @@ Logger :: struct { Random_Generator_Mode :: enum { Read, + Reset, Query_Info, } @@ -407,6 +408,7 @@ Random_Generator_Query_Info_Flag :: enum u32 { Cryptographic, Uniform, External_Entropy, + Resettable, } Random_Generator_Query_Info :: distinct bit_set[Random_Generator_Query_Info_Flag; u32] diff --git a/base/runtime/random_generator.odin b/base/runtime/random_generator.odin index 7746f1429..43d7ffd0c 100644 --- a/base/runtime/random_generator.odin +++ b/base/runtime/random_generator.odin @@ -29,7 +29,6 @@ random_generator_query_info :: proc(rg: Random_Generator) -> (info: Random_Gener } -@(private="file") Default_Random_State :: struct { state: u64, inc: u64, @@ -48,18 +47,24 @@ default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, @(thread_local) global_rand_seed: Default_Random_State + init :: proc "contextless" (r: ^Default_Random_State, seed: u64) { + seed := seed + if seed == 0 { + seed = u64(intrinsics.read_cycle_counter()) + } + r.state = 0 + r.inc = (seed << 1) | 1 + _ = read_u64(r) + r.state += seed + _ = read_u64(r) + } + + r := &global_rand_seed + switch mode { case .Read: - r := &global_rand_seed - - if r.state == 0 && - r.inc == 0 { - seed := u64(intrinsics.read_cycle_counter()) - r.state = 0 - r.inc = (seed << 1) | 1 - _ = read_u64(r) - r.state += seed - _ = read_u64(r) + if r.state == 0 && r.inc == 0 { + init(r, 0) } pos := i8(0) @@ -73,13 +78,18 @@ default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, val >>= 8 pos -= 1 } - return + + case .Reset: + seed: u64 + mem_copy_non_overlapping(&seed, raw_data(p), min(size_of(seed), len(p))) + init(r, seed) + case .Query_Info: if len(p) != size_of(Random_Generator_Query_Info) { return } info := (^Random_Generator_Query_Info)(raw_data(p)) - info^ += {.Uniform} + info^ += {.Uniform, .Resettable} } } diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin index 99835e66f..d995ecf7d 100644 --- a/core/crypto/crypto.odin +++ b/core/crypto/crypto.odin @@ -67,6 +67,8 @@ to_random_generator :: proc() -> runtime.Random_Generator { switch mode { case .Read: rand_bytes(p) + case .Reset: + // do nothing case .Query_Info: if len(p) != size_of(runtime.Random_Generator_Query_Info) { return diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 552af6b8d..3f85277e8 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -23,6 +23,16 @@ to_random_generator :: proc(r: ^Rand) -> runtime.Random_Generator { switch mode { case .Read: _ = read(p, r) + + case .Reset: + if r.is_system { + return + } + seed: u64 + runtime.mem_copy_non_overlapping(&seed, raw_data(p), min(size_of(seed), len(p))) + init(r, seed) + + case .Query_Info: if len(p) != size_of(runtime.Random_Generator_Query_Info) { return @@ -31,6 +41,8 @@ to_random_generator :: proc(r: ^Rand) -> runtime.Random_Generator { info^ += {.Uniform} if r.is_system { info^ += {.External_Entropy} + } else { + info^ += {.Resettable} } } }, From 7ec17ecf98c5151b31f7b0a3e090d6b5a4d12c54 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 15:33:24 +0100 Subject: [PATCH 33/42] Update `core:math/rand` to use `context.random_generator` and remove `rand.Rand` --- base/runtime/random_generator.odin | 18 +- core/math/rand/distributions.odin | 120 ++++----- core/math/rand/exp.odin | 8 +- core/math/rand/normal.odin | 10 +- core/math/rand/rand.odin | 351 +++++--------------------- tests/core/hash/test_core_hash.odin | 3 +- tests/core/slice/test_core_slice.odin | 12 +- tests/internal/test_map.odin | 62 +++-- 8 files changed, 197 insertions(+), 387 deletions(-) diff --git a/base/runtime/random_generator.odin b/base/runtime/random_generator.odin index 43d7ffd0c..205d7eb7e 100644 --- a/base/runtime/random_generator.odin +++ b/base/runtime/random_generator.odin @@ -29,6 +29,20 @@ random_generator_query_info :: proc(rg: Random_Generator) -> (info: Random_Gener } +random_generator_reset_bytes :: proc(rg: Random_Generator, p: []byte) { + if rg.procedure != nil { + rg.procedure(rg.data, .Reset, p) + } +} + +random_generator_reset_u64 :: proc(rg: Random_Generator, p: u64) { + if rg.procedure != nil { + p := p + rg.procedure(rg.data, .Reset, ([^]byte)(&p)[:size_of(p)]) + } +} + + Default_Random_State :: struct { state: u64, inc: u64, @@ -93,9 +107,9 @@ default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, } } -default_random_generator :: proc "contextless" () -> Random_Generator { +default_random_generator :: proc "contextless" (state: ^Default_Random_State = nil) -> Random_Generator { return { procedure = default_random_generator_proc, - data = nil, + data = state, } } \ No newline at end of file diff --git a/core/math/rand/distributions.odin b/core/math/rand/distributions.odin index 9365e8b76..a10ea3238 100644 --- a/core/math/rand/distributions.odin +++ b/core/math/rand/distributions.odin @@ -8,12 +8,12 @@ float32_uniform :: float32_range // Triangular Distribution // See: http://wikipedia.org/wiki/Triangular_distribution @(require_results) -float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 { +float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64)) -> f64 { if hi-lo == 0 { return lo } lo, hi := lo, hi - u := float64(r) + u := float64() c := f64(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1) if u > c { u = 1-u @@ -26,12 +26,12 @@ float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 // Triangular Distribution // See: http://wikipedia.org/wiki/Triangular_distribution @(require_results) -float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 { +float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32)) -> f32 { if hi-lo == 0 { return lo } lo, hi := lo, hi - u := float32(r) + u := float32() c := f32(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1) if u > c { u = 1-u @@ -44,25 +44,25 @@ float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 // Normal/Gaussian Distribution @(require_results) -float64_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 { - return norm_float64(r) * stddev + mean +float64_normal :: proc(mean, stddev: f64) -> f64 { + return norm_float64() * stddev + mean } // Normal/Gaussian Distribution @(require_results) -float32_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { - return f32(float64_normal(f64(mean), f64(stddev), r)) +float32_normal :: proc(mean, stddev: f32) -> f32 { + return f32(float64_normal(f64(mean), f64(stddev))) } // Log Normal Distribution @(require_results) -float64_log_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 { - return math.exp(float64_normal(mean, stddev, r)) +float64_log_normal :: proc(mean, stddev: f64) -> f64 { + return math.exp(float64_normal(mean, stddev)) } // Log Normal Distribution @(require_results) -float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { - return f32(float64_log_normal(f64(mean), f64(stddev), r)) +float32_log_normal :: proc(mean, stddev: f32) -> f32 { + return f32(float64_log_normal(f64(mean), f64(stddev))) } @@ -72,8 +72,8 @@ float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { // 0 to positive infinity if lambda > 0 // negative infinity to 0 if lambda <= 0 @(require_results) -float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 { - return - math.ln(1 - float64(r)) / lambda +float64_exponential :: proc(lambda: f64) -> f64 { + return - math.ln(1 - float64()) / lambda } // Exponential Distribution // `lambda` is 1.0/(desired mean). It should be non-zero. @@ -81,8 +81,8 @@ float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 { // 0 to positive infinity if lambda > 0 // negative infinity to 0 if lambda <= 0 @(require_results) -float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 { - return f32(float64_exponential(f64(lambda), r)) +float32_exponential :: proc(lambda: f32) -> f32 { + return f32(float64_exponential(f64(lambda))) } @@ -96,7 +96,7 @@ float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 { // // mean is alpha*beta, variance is math.pow(alpha*beta, 2) @(require_results) -float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { +float64_gamma :: proc(alpha, beta: f64) -> f64 { if alpha <= 0 || beta <= 0 { panic(#procedure + ": alpha and beta must be > 0.0") } @@ -112,11 +112,11 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { bbb := alpha - LOG4 ccc := alpha + ainv for { - u1 := float64(r) + u1 := float64() if !(1e-7 < u1 && u1 < 0.9999999) { continue } - u2 := 1 - float64(r) + u2 := 1 - float64() v := math.ln(u1 / (1 - u1)) / ainv x := alpha * math.exp(v) z := u1 * u1 * u2 @@ -127,12 +127,12 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { } case alpha == 1: // float64_exponential(1/beta) - return -math.ln(1 - float64(r)) * beta + return -math.ln(1 - float64()) * beta case: // ALGORITHM GS of Statistical Computing - Kennedy & Gentle x: f64 for { - u := float64(r) + u := float64() b := (math.e + alpha) / math.e p := b * u if p <= 1 { @@ -140,7 +140,7 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { } else { x = -math.ln((b - p) / alpha) } - u1 := float64(r) + u1 := float64() if p > 1 { if u1 <= math.pow(x, alpha-1) { break @@ -162,8 +162,8 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { // // mean is alpha*beta, variance is math.pow(alpha*beta, 2) @(require_results) -float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { - return f32(float64_gamma(f64(alpha), f64(beta), r)) +float32_gamma :: proc(alpha, beta: f32) -> f32 { + return f32(float64_gamma(f64(alpha), f64(beta))) } @@ -173,14 +173,14 @@ float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { // // Return values range between 0 and 1 @(require_results) -float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { +float64_beta :: proc(alpha, beta: f64) -> f64 { if alpha <= 0 || beta <= 0 { panic(#procedure + ": alpha and beta must be > 0.0") } // Knuth Vol 2 Ed 3 pg 134 "the beta distribution" - y := float64_gamma(alpha, 1.0, r) + y := float64_gamma(alpha, 1.0) if y != 0 { - return y / (y + float64_gamma(beta, 1.0, r)) + return y / (y + float64_gamma(beta, 1.0)) } return 0 } @@ -190,35 +190,35 @@ float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { // // Return values range between 0 and 1 @(require_results) -float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { - return f32(float64_beta(f64(alpha), f64(beta), r)) +float32_beta :: proc(alpha, beta: f32) -> f32 { + return f32(float64_beta(f64(alpha), f64(beta))) } // Pareto distribution, `alpha` is the shape parameter. // https://wikipedia.org/wiki/Pareto_distribution @(require_results) -float64_pareto :: proc(alpha: f64, r: ^Rand = nil) -> f64 { - return math.pow(1 - float64(r), -1.0 / alpha) +float64_pareto :: proc(alpha: f64) -> f64 { + return math.pow(1 - float64(), -1.0 / alpha) } // Pareto distribution, `alpha` is the shape parameter. // https://wikipedia.org/wiki/Pareto_distribution @(require_results) -float32_pareto :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { - return f32(float64_pareto(f64(alpha), r)) +float32_pareto :: proc(alpha, beta: f32) -> f32 { + return f32(float64_pareto(f64(alpha))) } // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter. @(require_results) -float64_weibull :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { - u := 1 - float64(r) +float64_weibull :: proc(alpha, beta: f64) -> f64 { + u := 1 - float64() return alpha * math.pow(-math.ln(u), 1.0/beta) } // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter. @(require_results) -float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { - return f32(float64_weibull(f64(alpha), f64(beta), r)) +float32_weibull :: proc(alpha, beta: f32) -> f32 { + return f32(float64_weibull(f64(alpha), f64(beta))) } @@ -227,23 +227,23 @@ float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { // `kappa` is the concentration parameter which must be >= 0 // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi @(require_results) -float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { +float64_von_mises :: proc(mean_angle, kappa: f64) -> f64 { // Fisher, N.I., "Statistical Analysis of Circular Data", Cambridge University Press, 1993. mu := mean_angle if kappa <= 1e-6 { - return math.TAU * float64(r) + return math.TAU * float64() } s := 0.5 / kappa t := s + math.sqrt(1 + s*s) z: f64 for { - u1 := float64(r) + u1 := float64() z = math.cos(math.TAU * 0.5 * u1) d := z / (t + z) - u2 := float64(r) + u2 := float64() if u2 < 1 - d*d || u2 <= (1-d)*math.exp(d) { break } @@ -251,7 +251,7 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { q := 1.0 / t f := (q + z) / (1 + q*z) - u3 := float64(r) + u3 := float64() if u3 > 0.5 { return math.mod(mu + math.acos(f), math.TAU) } else { @@ -263,57 +263,57 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { // `kappa` is the concentration parameter which must be >= 0 // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi @(require_results) -float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 { - return f32(float64_von_mises(f64(mean_angle), f64(kappa), r)) +float32_von_mises :: proc(mean_angle, kappa: f32) -> f32 { + return f32(float64_von_mises(f64(mean_angle), f64(kappa))) } // Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 @(require_results) -float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { +float64_cauchy_lorentz :: proc(x_0, gamma: f64) -> f64 { assert(gamma > 0) // Calculated from the inverse CDF - return math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0 + return math.tan(math.PI * (float64() - 0.5))*gamma + x_0 } // Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 @(require_results) -float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { - return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), r)) +float32_cauchy_lorentz :: proc(x_0, gamma: f32) -> f32 { + return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma))) } // Log Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 @(require_results) -float64_log_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { +float64_log_cauchy_lorentz :: proc(x_0, gamma: f64) -> f64 { assert(gamma > 0) - return math.exp(math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0) + return math.exp(math.tan(math.PI * (float64() - 0.5))*gamma + x_0) } // Log Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 @(require_results) -float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { - return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), r)) +float32_log_cauchy_lorentz :: proc(x_0, gamma: f32) -> f32 { + return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma))) } // Laplace Distribution // `b` is the scale where `b` > 0 @(require_results) -float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 { +float64_laplace :: proc(mean, b: f64) -> f64 { assert(b > 0) - p := float64(r)-0.5 + p := float64()-0.5 return -math.sign(p)*math.ln(1 - 2*abs(p))*b + mean } // Laplace Distribution // `b` is the scale where `b` > 0 @(require_results) -float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 { - return f32(float64_laplace(f64(mean), f64(b), r)) +float32_laplace :: proc(mean, b: f32) -> f32 { + return f32(float64_laplace(f64(mean), f64(b))) } @@ -321,18 +321,18 @@ float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 { // `eta` is the shape, `b` is the scale // Both `eta` and `b` must be > 0 @(require_results) -float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 { +float64_gompertz :: proc(eta, b: f64) -> f64 { if eta <= 0 || b <= 0 { panic(#procedure + ": eta and b must be > 0.0") } - p := float64(r) + p := float64() return math.ln(1 - math.ln(1 - p)/eta)/b } // Gompertz Distribution // `eta` is the shape, `b` is the scale // Both `eta` and `b` must be > 0 @(require_results) -float32_gompertz :: proc(eta, b: f32, r: ^Rand = nil) -> f32 { - return f32(float64_gompertz(f64(eta), f64(b), r)) +float32_gompertz :: proc(eta, b: f32) -> f32 { + return f32(float64_gompertz(f64(eta), f64(b))) } diff --git a/core/math/rand/exp.odin b/core/math/rand/exp.odin index ebc849b2f..f30f11f50 100644 --- a/core/math/rand/exp.odin +++ b/core/math/rand/exp.odin @@ -16,7 +16,7 @@ import "core:math" // https://www.jstatsoft.org/article/view/v005i08 [web page] // @(require_results) -exp_float64 :: proc(r: ^Rand = nil) -> f64 { +exp_float64 :: proc() -> f64 { re :: 7.69711747013104972 @(static, rodata) @@ -199,16 +199,16 @@ exp_float64 :: proc(r: ^Rand = nil) -> f64 { } for { - j := uint32(r) + j := uint32() i := j & 0xFF x := f64(j) * f64(we[i]) if j < ke[i] { return x } if i == 0 { - return re - math.ln(float64(r)) + return re - math.ln(float64()) } - if fe[i]+f32(float64(r))*(fe[i-1]-fe[i]) < f32(math.exp(-x)) { + if fe[i]+f32(float64())*(fe[i-1]-fe[i]) < f32(math.exp(-x)) { return x } } diff --git a/core/math/rand/normal.odin b/core/math/rand/normal.odin index 31b9a2387..eefa013df 100644 --- a/core/math/rand/normal.odin +++ b/core/math/rand/normal.odin @@ -18,7 +18,7 @@ import "core:math" // https://www.jstatsoft.org/article/view/v005i08 [web page] // @(require_results) -norm_float64 :: proc(r: ^Rand = nil) -> f64 { +norm_float64 :: proc() -> f64 { rn :: 3.442619855899 @(static, rodata) @@ -116,7 +116,7 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 { } for { - j := i32(uint32(r)) + j := i32(uint32()) i := j & 0x7f x := f64(j) * f64(wn[i]) if u32(abs(j)) < kn[i] { @@ -126,15 +126,15 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 { if i == 0 { for { - x = -math.ln(float64(r)) * (1.0/ rn) - y := -math.ln(float64(r)) + x = -math.ln(float64()) * (1.0/ rn) + y := -math.ln(float64()) if y+y >= x*x { break } } return j > 0 ? rn + x : -rn - x } - if fn[i]+f32(float64(r))*(fn[i-1]-fn[i]) < f32(math.exp(-0.5*x*x)) { + if fn[i]+f32(float64())*(fn[i-1]-fn[i]) < f32(math.exp(-0.5*x*x)) { return x } } diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 3f85277e8..7bb78cc1d 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -10,52 +10,18 @@ import "core:crypto" import "core:math" import "core:mem" -Rand :: struct { - state: u64, - inc: u64, - is_system: bool, +Default_Random_State :: runtime.Default_Random_State +default_random_generator :: runtime.default_random_generator + +create :: proc(seed: u64) -> (state: Default_Random_State) { + seed := seed + runtime.default_random_generator(&state) + runtime.default_random_generator_proc(&state, .Reset, ([^]byte)(&seed)[:size_of(seed)]) + return } -to_random_generator :: proc(r: ^Rand) -> runtime.Random_Generator { - return { - procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) { - r := (^Rand)(data) - switch mode { - case .Read: - _ = read(p, r) - - case .Reset: - if r.is_system { - return - } - seed: u64 - runtime.mem_copy_non_overlapping(&seed, raw_data(p), min(size_of(seed), len(p))) - init(r, seed) - - - case .Query_Info: - if len(p) != size_of(runtime.Random_Generator_Query_Info) { - return - } - info := (^runtime.Random_Generator_Query_Info)(raw_data(p)) - info^ += {.Uniform} - if r.is_system { - info^ += {.External_Entropy} - } else { - info^ += {.Resettable} - } - } - }, - data = r, - } -} - - -@(private) -global_rand := create(u64(intrinsics.read_cycle_counter())) - /* -Sets the seed used by the global random number generator. +Reset the seed used by the context.random_generator. Inputs: - seed: The seed value @@ -72,143 +38,46 @@ Example: Possible Output: 10 - */ +@(deprecated="Prefer `rand.reset`") set_global_seed :: proc(seed: u64) { - init(&global_rand, seed) + runtime.random_generator_reset_u64(context.random_generator, seed) } /* -Creates a new random number generator. +Reset the seed used by the context.random_generator. Inputs: -- seed: The seed value to create the random number generator with - -Returns: -- res: The created random number generator +- seed: The seed value Example: import "core:math/rand" import "core:fmt" - create_example :: proc() { - my_rand := rand.create(1) - fmt.println(rand.uint64(&my_rand)) + set_global_seed_example :: proc() { + rand.set_global_seed(1) + fmt.println(rand.uint64()) } Possible Output: 10 - */ -@(require_results) -create :: proc(seed: u64) -> (res: Rand) { - r: Rand - init(&r, seed) - return r +reset :: proc(seed: u64) { + runtime.random_generator_reset_u64(context.random_generator, seed) } -/* -Initialises a random number generator. - -Inputs: -- r: The random number generator to initialise -- seed: The seed value to initialise this random number generator - -Example: - import "core:math/rand" - import "core:fmt" - - init_example :: proc() { - my_rand: rand.Rand - rand.init(&my_rand, 1) - fmt.println(rand.uint64(&my_rand)) - } - -Possible Output: - - 10 - -*/ -init :: proc(r: ^Rand, seed: u64) { - r.state = 0 - r.inc = (seed << 1) | 1 - _random_u64(r) - r.state += seed - _random_u64(r) -} - -/* -Initialises a random number generator to use the system random number generator. -The system random number generator is platform specific, and not supported -on all targets. - -Inputs: -- r: The random number generator to use the system random number generator - -WARNING: Panics if the system random number generator is not supported. -Support can be determined via the `core:crypto.HAS_RAND_BYTES` constant. - -Example: - import "core:crypto" - import "core:math/rand" - import "core:fmt" - - init_as_system_example :: proc() { - my_rand: rand.Rand - switch crypto.HAS_RAND_BYTES { - case true: - rand.init_as_system(&my_rand) - fmt.println(rand.uint64(&my_rand)) - case false: - fmt.println("system random not supported!") - } - } - -Possible Output: - - 10 - -*/ -init_as_system :: proc(r: ^Rand) { - if !crypto.HAS_RAND_BYTES { - panic(#procedure + " is not supported on this platform yet") - } - r.state = 0 - r.inc = 0 - r.is_system = true -} - @(private) -_random_u64 :: proc(r: ^Rand) -> u64 { - r := r - switch { - case r == nil: - if res: u64; runtime.random_generator_read_ptr(context.random_generator, &res, size_of(res)) { - return res - } - - r = &global_rand - case r.is_system: - value: u64 - crypto.rand_bytes((cast([^]u8)&value)[:size_of(u64)]) - return value - } - - old_state := r.state - r.state = old_state * 6364136223846793005 + (r.inc|1) - xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081 - rot := (old_state >> 59) - return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63)) +_random_u64 :: proc() -> (res: u64) { + ok := runtime.random_generator_read_ptr(context.random_generator, &res, size_of(res)) + assert(ok, "uninitialized context.random_generator") + return } /* Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random unsigned 32 bit value @@ -217,11 +86,7 @@ Example: import "core:fmt" uint32_example :: proc() { - // Using the global random number generator fmt.println(rand.uint32()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.uint32(&my_rand)) } Possible Output: @@ -231,14 +96,11 @@ Possible Output: */ @(require_results) -uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return u32(_random_u64(r)) } +uint32 :: proc() -> (val: u32) { return u32(_random_u64()) } /* Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random unsigned 64 bit value @@ -247,11 +109,7 @@ Example: import "core:fmt" uint64_example :: proc() { - // Using the global random number generator fmt.println(rand.uint64()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.uint64(&my_rand)) } Possible Output: @@ -261,14 +119,11 @@ Possible Output: */ @(require_results) -uint64 :: proc(r: ^Rand = nil) -> (val: u64) { return _random_u64(r) } +uint64 :: proc() -> (val: u64) { return _random_u64() } /* Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random unsigned 128 bit value @@ -277,11 +132,7 @@ Example: import "core:fmt" uint128_example :: proc() { - // Using the global random number generator fmt.println(rand.uint128()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.uint128(&my_rand)) } Possible Output: @@ -291,9 +142,9 @@ Possible Output: */ @(require_results) -uint128 :: proc(r: ^Rand = nil) -> (val: u128) { - a := u128(_random_u64(r)) - b := u128(_random_u64(r)) +uint128 :: proc() -> (val: u128) { + a := u128(_random_u64()) + b := u128(_random_u64()) return (a<<64) | b } @@ -301,9 +152,6 @@ uint128 :: proc(r: ^Rand = nil) -> (val: u128) { Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random 31 bit value @@ -312,11 +160,7 @@ Example: import "core:fmt" int31_example :: proc() { - // Using the global random number generator fmt.println(rand.int31()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int31(&my_rand)) } Possible Output: @@ -325,15 +169,12 @@ Possible Output: 389 */ -@(require_results) int31 :: proc(r: ^Rand = nil) -> (val: i32) { return i32(uint32(r) << 1 >> 1) } +@(require_results) int31 :: proc() -> (val: i32) { return i32(uint32() << 1 >> 1) } /* Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random 63 bit value @@ -342,11 +183,7 @@ Example: import "core:fmt" int63_example :: proc() { - // Using the global random number generator fmt.println(rand.int63()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int63(&my_rand)) } Possible Output: @@ -355,15 +192,12 @@ Possible Output: 389 */ -@(require_results) int63 :: proc(r: ^Rand = nil) -> (val: i64) { return i64(uint64(r) << 1 >> 1) } +@(require_results) int63 :: proc() -> (val: i64) { return i64(uint64() << 1 >> 1) } /* Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random 127 bit value @@ -372,11 +206,7 @@ Example: import "core:fmt" int127_example :: proc() { - // Using the global random number generator fmt.println(rand.int127()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int127(&my_rand)) } Possible Output: @@ -385,14 +215,13 @@ Possible Output: 389 */ -@(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) } +@(require_results) int127 :: proc() -> (val: i128) { return i128(uint128() << 1 >> 1) } /* Generates a random 31 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used. Inputs: - n: The upper bound of the generated number, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random 31 bit value in the range `[0, n)` @@ -404,11 +233,7 @@ Example: import "core:fmt" int31_max_example :: proc() { - // Using the global random number generator fmt.println(rand.int31_max(16)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int31_max(1024, &my_rand)) } Possible Output: @@ -418,17 +243,17 @@ Possible Output: */ @(require_results) -int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) { +int31_max :: proc(n: i32) -> (val: i32) { if n <= 0 { panic("Invalid argument to int31_max") } if n&(n-1) == 0 { - return int31(r) & (n-1) + return int31() & (n-1) } max := i32((1<<31) - 1 - (1<<31)%u32(n)) - v := int31(r) + v := int31() for v > max { - v = int31(r) + v = int31() } return v % n } @@ -438,7 +263,6 @@ Generates a random 63 bit value in the range `[0, n)` using the provided random Inputs: - n: The upper bound of the generated number, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random 63 bit value in the range `[0, n)` @@ -450,11 +274,7 @@ Example: import "core:fmt" int63_max_example :: proc() { - // Using the global random number generator fmt.println(rand.int63_max(16)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int63_max(1024, &my_rand)) } Possible Output: @@ -464,17 +284,17 @@ Possible Output: */ @(require_results) -int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) { +int63_max :: proc(n: i64) -> (val: i64) { if n <= 0 { panic("Invalid argument to int63_max") } if n&(n-1) == 0 { - return int63(r) & (n-1) + return int63() & (n-1) } max := i64((1<<63) - 1 - (1<<63)%u64(n)) - v := int63(r) + v := int63() for v > max { - v = int63(r) + v = int63() } return v % n } @@ -484,7 +304,6 @@ Generates a random 127 bit value in the range `[0, n)` using the provided random Inputs: - n: The upper bound of the generated number, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random 127 bit value in the range `[0, n)` @@ -496,11 +315,7 @@ Example: import "core:fmt" int127_max_example :: proc() { - // Using the global random number generator fmt.println(rand.int127_max(16)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int127_max(1024, &my_rand)) } Possible Output: @@ -510,17 +325,17 @@ Possible Output: */ @(require_results) -int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) { +int127_max :: proc(n: i128) -> (val: i128) { if n <= 0 { panic("Invalid argument to int127_max") } if n&(n-1) == 0 { - return int127(r) & (n-1) + return int127() & (n-1) } max := i128((1<<127) - 1 - (1<<127)%u128(n)) - v := int127(r) + v := int127() for v > max { - v = int127(r) + v = int127() } return v % n } @@ -530,7 +345,6 @@ Generates a random integer value in the range `[0, n)` using the provided random Inputs: - n: The upper bound of the generated number, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random integer value in the range `[0, n)` @@ -542,11 +356,7 @@ Example: import "core:fmt" int_max_example :: proc() { - // Using the global random number generator fmt.println(rand.int_max(16)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int_max(1024, &my_rand)) } Possible Output: @@ -556,23 +366,20 @@ Possible Output: */ @(require_results) -int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) { +int_max :: proc(n: int) -> (val: int) { if n <= 0 { panic("Invalid argument to int_max") } when size_of(int) == 4 { - return int(int31_max(i32(n), r)) + return int(int31_max(i32(n))) } else { - return int(int63_max(i64(n), r)) + return int(int63_max(i64(n))) } } /* Generates a random double floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random double floating point value in the range `[0, 1)` @@ -581,11 +388,7 @@ Example: import "core:fmt" float64_example :: proc() { - // Using the global random number generator fmt.println(rand.float64()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.float64(&my_rand)) } Possible Output: @@ -594,14 +397,11 @@ Possible Output: 0.511 */ -@(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) } +@(require_results) float64 :: proc() -> (val: f64) { return f64(int63_max(1<<53)) / (1 << 53) } /* Generates a random single floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random single floating point value in the range `[0, 1)` @@ -610,11 +410,7 @@ Example: import "core:fmt" float32_example :: proc() { - // Using the global random number generator fmt.println(rand.float32()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.float32(&my_rand)) } Possible Output: @@ -623,7 +419,7 @@ Possible Output: 0.511 */ -@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(int31_max(1<<24, r)) / (1 << 24) } +@(require_results) float32 :: proc() -> (val: f32) { return f32(int31_max(1<<24)) / (1 << 24) } /* Generates a random double floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used. @@ -633,7 +429,6 @@ WARNING: Panics if `high < low` Inputs: - low: The lower bounds of the value, this value is inclusive - high: The upper bounds of the value, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random double floating point value in the range [low, high) @@ -643,11 +438,7 @@ Example: import "core:fmt" float64_range_example :: proc() { - // Using the global random number generator fmt.println(rand.float64_range(-10, 300)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.float64_range(600, 900, &my_rand)) } Possible Output: @@ -656,9 +447,9 @@ Possible Output: 673.130 */ -@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { +@(require_results) float64_range :: proc(low, high: f64) -> (val: f64) { assert(low <= high, "low must be lower than or equal to high") - val = (high-low)*float64(r) + low + val = (high-low)*float64() + low if val >= high { val = max(low, high * (1 - math.F64_EPSILON)) } @@ -671,7 +462,6 @@ Generates a random single floating point value in the range `[low, high)` using Inputs: - low: The lower bounds of the value, this value is inclusive - high: The upper bounds of the value, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random single floating point value in the range [low, high) @@ -683,11 +473,7 @@ Example: import "core:fmt" float32_range_example :: proc() { - // Using the global random number generator fmt.println(rand.float32_range(-10, 300)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.float32_range(600, 900, &my_rand)) } Possible Output: @@ -696,9 +482,9 @@ Possible Output: 673.130 */ -@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { +@(require_results) float32_range :: proc(low, high: f32) -> (val: f32) { assert(low <= high, "low must be lower than or equal to high") - val = (high-low)*float32(r) + low + val = (high-low)*float32() + low if val >= high { val = max(low, high * (1 - math.F32_EPSILON)) } @@ -711,7 +497,6 @@ Due to floating point precision there is no guarantee if the upper and lower bou Inputs: - p: The byte slice to fill -- r: The random number generator to use, or nil for the global generator Returns: - n: The number of bytes generated @@ -721,7 +506,6 @@ Example: import "core:fmt" read_example :: proc() { - // Using the global random number generator data: [8]byte n := rand.read(data[:]) fmt.println(n) @@ -735,12 +519,12 @@ Possible Output: */ @(require_results) -read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) { +read :: proc(p: []byte) -> (n: int) { pos := i8(0) val := i64(0) for n = 0; n < len(p); n += 1 { if pos == 0 { - val = int63(r) + val = int63() pos = 7 } p[n] = byte(val) @@ -757,7 +541,6 @@ Creates a slice of `int` filled with random values using the provided random num Inputs: - n: The size of the created slice -- r: The random number generator to use, or nil for the global generator - allocator: (default: context.allocator) Returns: @@ -770,16 +553,10 @@ Example: import "core:fmt" perm_example :: proc() -> (err: mem.Allocator_Error) { - // Using the global random number generator and using the context allocator data := rand.perm(4) or_return fmt.println(data) defer delete(data, context.allocator) - // Using local random number generator and temp allocator - my_rand := rand.create(1) - data_tmp := rand.perm(4, &my_rand, context.temp_allocator) or_return - fmt.println(data_tmp) - return } @@ -790,10 +567,10 @@ Possible Output: */ @(require_results) -perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error { +perm :: proc(n: int, allocator := context.allocator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error { m := make([]int, n, allocator) or_return for i := 0; i < n; i += 1 { - j := int_max(i+1, r) + j := int_max(i+1) m[i] = m[j] m[j] = i } @@ -805,14 +582,12 @@ Randomizes the ordering of elements for the provided slice. If no generator is p Inputs: - array: The slice to randomize -- r: The random number generator to use, or nil for the global generator Example: import "core:math/rand" import "core:fmt" shuffle_example :: proc() { - // Using the global random number generator data: [4]int = { 1, 2, 3, 4 } fmt.println(data) // the contents are in order rand.shuffle(data[:]) @@ -825,14 +600,14 @@ Possible Output: [2, 4, 3, 1] */ -shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) { +shuffle :: proc(array: $T/[]$E) { n := i64(len(array)) if n < 2 { return } for i := i64(n - 1); i > 0; i -= 1 { - j := int63_max(i + 1, r) + j := int63_max(i + 1) array[i], array[j] = array[j], array[i] } } @@ -842,7 +617,6 @@ Returns a random element from the provided slice. If no generator is provided th Inputs: - array: The slice to choose an element from -- r: The random number generator to use, or nil for the global generator Returns: - res: A random element from `array` @@ -852,7 +626,6 @@ Example: import "core:fmt" choice_example :: proc() { - // Using the global random number generator data: [4]int = { 1, 2, 3, 4 } fmt.println(rand.choice(data[:])) fmt.println(rand.choice(data[:])) @@ -869,17 +642,17 @@ Possible Output: */ @(require_results) -choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) { +choice :: proc(array: $T/[]$E) -> (res: E) { n := i64(len(array)) if n < 1 { return E{} } - return array[int63_max(n, r)] + return array[int63_max(n)] } @(require_results) -choice_enum :: proc($T: typeid, r: ^Rand = nil) -> T +choice_enum :: proc($T: typeid) -> T where intrinsics.type_is_enum(T), size_of(T) <= 8, @@ -887,11 +660,11 @@ choice_enum :: proc($T: typeid, r: ^Rand = nil) -> T { when intrinsics.type_is_unsigned(intrinsics.type_core_type(T)) && u64(max(T)) > u64(max(i64)) { - i := uint64(r) % u64(len(T)) + i := uint64() % u64(len(T)) i += u64(min(T)) return T(i) } else { - i := int63_max(i64(len(T)), r) + i := int63_max(i64(len(T))) i += i64(min(T)) return T(i) } diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index c332383e7..0255717a2 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -54,8 +54,9 @@ test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) { // XXH3_128_update random_seed := rand.create(t.seed) + context.random_generator = rand.default_random_generator(&random_seed) for len(b) > 0 { - update_size := min(len(b), rand.int_max(8192, &random_seed)) + update_size := min(len(b), rand.int_max(8192)) if update_size > 4096 { update_size %= 73 } diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 23de1b482..003021a8a 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -11,6 +11,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { for test_size in test_sizes { r := rand.create(t.seed) + context.random_generator = rand.default_random_generator(&r) vals := make([]u64, test_size) r_idx := make([]int, test_size) // Reverse index @@ -21,7 +22,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { // Set up test values for _, i in vals { - vals[i] = rand.uint64(&r) + vals[i] = rand.uint64() } // Sort @@ -29,7 +30,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { defer delete(f_idx) // Verify sorted test values - rand.init(&r, t.seed) + rand.reset(t.seed) for v, i in f_idx { r_idx[v] = i @@ -45,7 +46,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { } } - idx_pass := vals[r_idx[i]] == rand.uint64(&r) + idx_pass := vals[r_idx[i]] == rand.uint64() testing.expect(t, idx_pass, "Expected index to have been sorted") if !idx_pass { break @@ -62,6 +63,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { for test_size in test_sizes { r := rand.create(t.seed) + context.random_generator = rand.default_random_generator(&r) vals := make([]u64, test_size) r_idx := make([]int, test_size) // Reverse index @@ -72,7 +74,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { // Set up test values for _, i in vals { - vals[i] = rand.uint64(&r) + vals[i] = rand.uint64() } // Sort @@ -80,7 +82,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { defer delete(f_idx) // Verify sorted test values - rand.init(&r, t.seed) + rand.reset(t.seed) { indices := make([]int, test_size) diff --git a/tests/internal/test_map.odin b/tests/internal/test_map.odin index a9a8cf5d4..ab7e52f33 100644 --- a/tests/internal/test_map.odin +++ b/tests/internal/test_map.odin @@ -17,9 +17,10 @@ map_insert_random_key_value :: proc(t: ^testing.T) { unique_keys := 0 r := rand.create(t.seed + seed_incr) + context.random_generator = rand.default_random_generator(&r) for _ in 0.. Date: Sat, 15 Jun 2024 15:43:57 +0100 Subject: [PATCH 34/42] Remove the need for `rand` in `core:math/big` --- core/math/big/helpers.odin | 10 +++++----- core/math/big/internal.odin | 10 +++++----- core/math/big/prime.odin | 8 +++----- core/math/rand/rand.odin | 1 - 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 1969fac49..ee09bb2c7 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -362,11 +362,11 @@ platform_count_lsb :: #force_inline proc(a: $T) -> (count: int) count_lsb :: proc { int_count_lsb, platform_count_lsb, } -int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { +int_random_digit :: proc() -> (res: DIGIT) { when _DIGIT_BITS == 60 { // DIGIT = u64 - return DIGIT(rnd.uint64(r)) & _MASK + return DIGIT(rnd.uint64()) & _MASK } else when _DIGIT_BITS == 28 { // DIGIT = u32 - return DIGIT(rnd.uint32(r)) & _MASK + return DIGIT(rnd.uint32()) & _MASK } else { panic("Unsupported DIGIT size.") } @@ -374,12 +374,12 @@ int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { return 0 // We shouldn't get here. } -int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) { +int_random :: proc(dest: ^Int, bits: int, allocator := context.allocator) -> (err: Error) { /* Check that `a` is usable. */ assert_if_nil(dest) - return #force_inline internal_int_random(dest, bits, r, allocator) + return #force_inline internal_int_random(dest, bits, allocator) } random :: proc { int_random, } diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 29bdf555c..c9b331e55 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2817,11 +2817,11 @@ internal_platform_count_lsb :: #force_inline proc(a: $T) -> (count: int) internal_count_lsb :: proc { internal_int_count_lsb, internal_platform_count_lsb, } -internal_int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { +internal_int_random_digit :: proc() -> (res: DIGIT) { when _DIGIT_BITS == 60 { // DIGIT = u64 - return DIGIT(rnd.uint64(r)) & _MASK + return DIGIT(rnd.uint64()) & _MASK } else when _DIGIT_BITS == 28 { // DIGIT = u32 - return DIGIT(rnd.uint32(r)) & _MASK + return DIGIT(rnd.uint32()) & _MASK } else { panic("Unsupported DIGIT size.") } @@ -2829,7 +2829,7 @@ internal_int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { return 0 // We shouldn't get here. } -internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) { +internal_int_random :: proc(dest: ^Int, bits: int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator bits := bits @@ -2846,7 +2846,7 @@ internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator #force_inline internal_grow(dest, digits) or_return for i := 0; i < digits; i += 1 { - dest.digit[i] = int_random_digit(r) & _MASK + dest.digit[i] = int_random_digit() & _MASK } if bits > 0 { dest.digit[digits - 1] &= ((1 << uint(bits)) - 1) diff --git a/core/math/big/prime.odin b/core/math/big/prime.odin index 7fc78c7e5..832c75119 100644 --- a/core/math/big/prime.odin +++ b/core/math/big/prime.odin @@ -12,8 +12,6 @@ package math_big -import rnd "core:math/rand" - /* Determines if an Integer is divisible by one of the _PRIME_TABLE primes. Returns true if it is, false if not. @@ -315,7 +313,7 @@ internal_int_prime_miller_rabin :: proc(a, b: ^Int, allocator := context.allocat Assumes `a` not to be `nil` and to have been initialized. */ -internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_rabin_only := USE_MILLER_RABIN_ONLY, r: ^rnd.Rand = nil, allocator := context.allocator) -> (is_prime: bool, err: Error) { +internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_rabin_only := USE_MILLER_RABIN_ONLY, allocator := context.allocator) -> (is_prime: bool, err: Error) { context.allocator = allocator miller_rabin_trials := miller_rabin_trials @@ -461,7 +459,7 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra for ix := 0; ix < miller_rabin_trials; ix += 1 { // rand() guarantees the first digit to be non-zero - internal_random(b, _DIGIT_TYPE_BITS, r) or_return + internal_random(b, _DIGIT_TYPE_BITS) or_return // Reduce digit before casting because DIGIT might be bigger than // an unsigned int and "mask" on the other side is most probably not. @@ -1183,7 +1181,7 @@ internal_int_prime_next_prime :: proc(a: ^Int, trials: int, bbs_style: bool, all This is possibly the mother of all prime generation functions, muahahahahaha! */ -internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags := Primality_Flags{}, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) { +internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags := Primality_Flags{}, allocator := context.allocator) -> (err: Error) { context.allocator = allocator flags := flags trials := trials diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 7bb78cc1d..8e3c0264d 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -6,7 +6,6 @@ package rand import "base:intrinsics" import "base:runtime" -import "core:crypto" import "core:math" import "core:mem" From 784408358d39346b410df65b9f657007c467a010 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 15 Jun 2024 10:25:58 -0400 Subject: [PATCH 35/42] Call `cleanups` after test signal --- core/testing/runner.odin | 11 +++++++++-- core/testing/testing.odin | 12 +++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 328186c35..147c6d094 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -604,10 +604,10 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { }) fmt.assertf(alloc_error == nil, "Error appending to log messages: %v", alloc_error) - find_task_data: for &data in task_data_slots { + find_task_data_for_timeout: for &data in task_data_slots { if data.it.pkg == it.pkg && data.it.name == it.name { end_t(&data.t) - break find_task_data + break find_task_data_for_timeout } } } @@ -655,6 +655,13 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } + find_task_data_for_stop_signal: for &data in task_data_slots { + if data.it.pkg == it.pkg && data.it.name == it.name { + end_t(&data.t) + break find_task_data_for_stop_signal + } + } + when FANCY_OUTPUT { bypass_progress_overwrite = true signals_were_raised = true diff --git a/core/testing/testing.odin b/core/testing/testing.odin index 92b4d391d..07e2063ca 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -94,7 +94,17 @@ logf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { // cleanup registers a procedure and user_data, which will be called when the test, and all its subtests, complete. // Cleanup procedures will be called in LIFO (last added, first called) order. -// Each procedure will use a copy of the context at the time of registering. +// +// Each procedure will use a copy of the context at the time of registering, +// and if the test failed due to a timeout, failed assertion, panic, bounds-checking error, +// memory access violation, or any other signal-based fault, this procedure will +// run with greater privilege in the test runner's main thread. +// +// That means that any cleanup procedure absolutely must not fail in the same way, +// or it will take down the entire test runner with it. This is for when you +// need something to run no matter what, if a test failed. +// +// For almost every usual case, `defer` should be preferable and sufficient. cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) { append(&t.cleanups, Internal_Cleanup{procedure, user_data, context}) } From 2380720fa293bdc0eb2c564b232b5083d9742154 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 15:46:48 +0100 Subject: [PATCH 36/42] Fix `core:sync/chan` for rand --- core/sync/chan/chan.odin | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/sync/chan/chan.odin b/core/sync/chan/chan.odin index f4774e4f8..0c3f4a725 100644 --- a/core/sync/chan/chan.odin +++ b/core/sync/chan/chan.odin @@ -476,10 +476,7 @@ select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: [] return } - r: ^rand.Rand = nil - - - select_idx = rand.int_max(count, r) if count > 0 else 0 + select_idx = rand.int_max(count) if count > 0 else 0 sel := candidates[select_idx] if sel.is_recv { From c97ffbecbc80d29aaab5d257048aef5bfd28e4db Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 15:50:35 +0100 Subject: [PATCH 37/42] Fix `rand` in container tests --- tests/core/container/test_core_avl.odin | 7 ++++--- tests/core/container/test_core_rbtree.odin | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/core/container/test_core_avl.odin b/tests/core/container/test_core_avl.odin index 99dbba8b2..db4428905 100644 --- a/tests/core/container/test_core_avl.odin +++ b/tests/core/container/test_core_avl.odin @@ -21,14 +21,15 @@ test_avl :: proc(t: ^testing.T) { testing.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil") r: rand.Rand - rand.init(&r, t.seed) + r := rand.create(t.seed) + context.random_generator = rand.default_random_generator(&r) // Test insertion. NR_INSERTS :: 32 + 1 // Ensure at least 1 collision. inserted_map := make(map[int]^avl.Node(int)) defer delete(inserted_map) for i := 0; i < NR_INSERTS; i += 1 { - v := int(rand.uint32(&r) & 0x1f) + v := int(rand.uint32() & 0x1f) existing_node, in_map := inserted_map[v] n, ok, _ := avl.find_or_insert(&tree, v) @@ -78,7 +79,7 @@ test_avl :: proc(t: ^testing.T) { testing.expect(t, visited == nrEntries, "iterator/backward: visited") // Test removal. - rand.shuffle(inserted_values[:], &r) + rand.shuffle(inserted_values[:]) for v, i in inserted_values { node := avl.find(&tree, v) testing.expect(t, node != nil, "remove: find (pre)") diff --git a/tests/core/container/test_core_rbtree.odin b/tests/core/container/test_core_rbtree.odin index 8def8edb6..1aaad7372 100644 --- a/tests/core/container/test_core_rbtree.odin +++ b/tests/core/container/test_core_rbtree.odin @@ -15,7 +15,8 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { context.allocator = mem.tracking_allocator(&track) r: rand.Rand - rand.init(&r, t.seed) + r := rand.create(t.seed) + context.random_generator = rand.default_random_generator(&r) log.infof("Testing Red-Black Tree($Key=%v,$Value=%v) using random seed %v.", type_info_of(Key), type_info_of(Value), t.seed) tree: rb.Tree(Key, Value) @@ -35,9 +36,9 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { max_key := min(Key) for i := 0; i < NR_INSERTS; i += 1 { - k := Key(rand.uint32(&r)) & 0x1f + k := Key(rand.uint32()) & 0x1f min_key = min(min_key, k); max_key = max(max_key, k) - v := Value(rand.uint32(&r)) + v := Value(rand.uint32()) existing_node, in_map := inserted_map[k] n, inserted, _ := rb.find_or_insert(&tree, k, v) @@ -92,7 +93,7 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { testing.expect(t, visited == entry_count, "iterator/backward: visited") // Test removal (and on_remove callback) - rand.shuffle(inserted_keys[:], &r) + rand.shuffle(inserted_keys[:]) callback_count := entry_count tree.user_data = &callback_count tree.on_remove = proc(key: Key, value: Value, user_data: rawptr) { From 1c940e3968a210ba0f06d663c54d8135790e27c1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 15:53:16 +0100 Subject: [PATCH 38/42] Remove dead variable --- tests/core/container/test_core_avl.odin | 1 - tests/core/container/test_core_rbtree.odin | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/core/container/test_core_avl.odin b/tests/core/container/test_core_avl.odin index db4428905..556f371af 100644 --- a/tests/core/container/test_core_avl.odin +++ b/tests/core/container/test_core_avl.odin @@ -20,7 +20,6 @@ test_avl :: proc(t: ^testing.T) { iter := avl.iterator(&tree, avl.Direction.Forward) testing.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil") - r: rand.Rand r := rand.create(t.seed) context.random_generator = rand.default_random_generator(&r) diff --git a/tests/core/container/test_core_rbtree.odin b/tests/core/container/test_core_rbtree.odin index 1aaad7372..425a9b440 100644 --- a/tests/core/container/test_core_rbtree.odin +++ b/tests/core/container/test_core_rbtree.odin @@ -14,7 +14,6 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { defer mem.tracking_allocator_destroy(&track) context.allocator = mem.tracking_allocator(&track) - r: rand.Rand r := rand.create(t.seed) context.random_generator = rand.default_random_generator(&r) From bb823d5ba0aa412c40a0e23c9b27f00c734e9866 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 15 Jun 2024 10:36:05 -0400 Subject: [PATCH 39/42] Make `testing.fail_now` divergent This is in line with the old way it worked on Windows. --- core/testing/runner.odin | 37 +++++++++++++++++++++++-------------- core/testing/testing.odin | 15 ++++++++++----- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 147c6d094..6a33436f6 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -497,6 +497,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { data.it = it data.t.seed = shared_random_seed data.t.error_count = 0 + data.t._fail_now_called = false thread.pool_add_task(&pool, task.allocator, run_test_task, data, run_index) } @@ -645,28 +646,36 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { "A signal (%v) was raised to stop test #%i %s.%s, but it was unable to be found.", reason, test_index, it.pkg, it.name) - if test_index not_in failed_test_reason_map { - // We only write a new error message here if there wasn't one - // already, because the message we can provide based only on - // the signal won't be very useful, whereas asserts and panics - // will provide a user-written error message. - failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator) - pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason) - - } - + // The order this is handled in is a little particular. + task_data: ^Task_Data find_task_data_for_stop_signal: for &data in task_data_slots { if data.it.pkg == it.pkg && data.it.name == it.name { - end_t(&data.t) + task_data = &data break find_task_data_for_stop_signal } } - when FANCY_OUTPUT { - bypass_progress_overwrite = true - signals_were_raised = true + fmt.assertf(task_data != nil, "A signal (%v) was raised to stop test #%i %s.%s, but its task data is missing.", + reason, test_index, it.pkg, it.name) + + if !task_data.t._fail_now_called { + if test_index not_in failed_test_reason_map { + // We only write a new error message here if there wasn't one + // already, because the message we can provide based only on + // the signal won't be very useful, whereas asserts and panics + // will provide a user-written error message. + failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator) + pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason) + } + + when FANCY_OUTPUT { + bypass_progress_overwrite = true + signals_were_raised = true + } } + end_t(&task_data.t) + total_failure_count += 1 total_done_count += 1 } diff --git a/core/testing/testing.odin b/core/testing/testing.odin index 07e2063ca..29fe853ef 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -48,7 +48,7 @@ T :: struct { // tests during channel transmission. _log_allocator: runtime.Allocator, - _fail_now: proc() -> !, + _fail_now_called: bool, } @@ -66,15 +66,20 @@ fail :: proc(t: ^T, loc := #caller_location) { pkg_log.error("FAIL", location=loc) } -fail_now :: proc(t: ^T, msg := "", loc := #caller_location) { +// fail_now will cause a test to immediately fail and abort, much in the same +// way a failed assertion or panic call will stop a thread. +// +// It is for when you absolutely need a test to fail without calling any of its +// deferred statements. It will be cleaner than a regular assert or panic, +// as the test runner will know to expect the signal this procedure will raise. +fail_now :: proc(t: ^T, msg := "", loc := #caller_location) -> ! { + t._fail_now_called = true if msg != "" { pkg_log.error("FAIL:", msg, location=loc) } else { pkg_log.error("FAIL", location=loc) } - if t._fail_now != nil { - t._fail_now() - } + runtime.trap() } failed :: proc(t: ^T) -> bool { From f353adc7fbb9a185724e36fba1b8bb5ec1059913 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 15 Jun 2024 10:39:28 -0400 Subject: [PATCH 40/42] Prefer `log.error` over `fail_now` in this case --- tests/core/slice/test_core_slice.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 23de1b482..3a15ddaa0 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -3,6 +3,7 @@ package test_core_slice import "core:slice" import "core:testing" import "core:math/rand" +import "core:log" @test test_sort_with_indices :: proc(t: ^testing.T) { @@ -205,7 +206,7 @@ test_permutation_iterator :: proc(t: ^testing.T) { n += item } if n in seen { - testing.fail_now(t, "Permutation iterator made a duplicate permutation.") + log.error("Permutation iterator made a duplicate permutation.") return } seen[n] = true From 753516c3926766c51e78f8ff8933a4bef29affff Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 15 Jun 2024 11:18:40 -0400 Subject: [PATCH 41/42] Add `ODIN_TEST_SHORT_LOGS` define Strips out the procedure, date, and time information, for when you just need to know the file, line, and message. --- core/testing/logging.odin | 23 ++++++++++++++++------- core/testing/runner.odin | 2 ++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/core/testing/logging.odin b/core/testing/logging.odin index 5bbbffeae..f1e75d33c 100644 --- a/core/testing/logging.odin +++ b/core/testing/logging.odin @@ -8,13 +8,22 @@ import "core:strings" import "core:sync/chan" import "core:time" -Default_Test_Logger_Opts :: runtime.Logger_Options { - .Level, - .Terminal_Color, - .Short_File_Path, - .Line, - .Procedure, - .Date, .Time, +when USING_SHORT_LOGS { + Default_Test_Logger_Opts :: runtime.Logger_Options { + .Level, + .Terminal_Color, + .Short_File_Path, + .Line, + } +} else { + Default_Test_Logger_Opts :: runtime.Logger_Options { + .Level, + .Terminal_Color, + .Short_File_Path, + .Line, + .Procedure, + .Date, .Time, + } } Log_Message :: struct { diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 328186c35..134ef72fc 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -41,6 +41,8 @@ PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0) // Set the lowest log level for this test run. LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, "info") +// Show only the most necessary logging information. +USING_SHORT_LOGS : bool : #config(ODIN_TEST_SHORT_LOGS, false) get_log_level :: #force_inline proc() -> runtime.Logger_Level { From e41ad2bf16e2164328e3e6f912271c32f8eb5390 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jun 2024 16:24:01 +0100 Subject: [PATCH 42/42] `to_random_generator` -> `random_generator` --- core/crypto/crypto.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin index d995ecf7d..cd80567e2 100644 --- a/core/crypto/crypto.odin +++ b/core/crypto/crypto.odin @@ -61,7 +61,7 @@ rand_bytes :: proc (dst: []byte) { } -to_random_generator :: proc() -> runtime.Random_Generator { +random_generator :: proc() -> runtime.Random_Generator { return { procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) { switch mode {