├── arena_allocator ├── file1.txt ├── file2.txt ├── file3.txt └── arena_allocator.odin ├── orca ├── breakout │ └── data │ │ ├── test_read.txt │ │ ├── ball.png │ │ ├── brick.png │ │ ├── underwater.jpg │ │ └── Literata-SemiBoldItalic.ttf ├── clock │ ├── icon.png │ ├── data │ │ └── segoeui.ttf │ └── main.odin └── ui │ └── data │ ├── OpenSans-Bold.ttf │ └── OpenSans-Regular.ttf ├── wasm └── js_wasm32 │ ├── .gitignore │ ├── build.sh │ ├── build.bat │ ├── main.odin │ ├── web │ ├── index.html │ └── index.js │ └── README.md ├── sdl2 └── hellope │ ├── build.bat │ ├── SDL2.dll │ ├── Makefile │ ├── logo-slim.png │ ├── SDL2_image.dll │ ├── libpng16-16.dll │ ├── LICENSE.SDL2.txt │ ├── LICENSE.SDL2_image.txt │ └── LICENSE.png.txt ├── win32 ├── emblem.ico ├── open_window │ └── main.odin └── game_of_life │ └── game_of_life.rc ├── raylib ├── box2d │ ├── box.png │ ├── ground.png │ ├── LICENSE │ └── main.odin ├── ports │ ├── text │ │ ├── resources │ │ │ ├── KAISG.ttf │ │ │ ├── dejavu.png │ │ │ ├── noto_cjk.png │ │ │ ├── symbola.png │ │ │ ├── fonts │ │ │ │ ├── mecha.png │ │ │ │ ├── alagard.png │ │ │ │ ├── romulus.png │ │ │ │ ├── setback.png │ │ │ │ ├── alpha_beta.png │ │ │ │ ├── pixantiqua.png │ │ │ │ ├── pixelplay.png │ │ │ │ └── jupiter_crash.png │ │ │ ├── pixantiqua.png │ │ │ ├── pixantiqua.ttf │ │ │ ├── custom_alagard.png │ │ │ ├── custom_mecha.png │ │ │ ├── DotGothic16-Regular.ttf │ │ │ ├── anonymous_pro_bold.ttf │ │ │ ├── custom_jupiter_crash.png │ │ │ ├── shaders │ │ │ │ ├── glsl100 │ │ │ │ │ ├── alpha_discard.fs │ │ │ │ │ └── sdf.fs │ │ │ │ └── glsl330 │ │ │ │ │ ├── alpha_discard.fs │ │ │ │ │ └── sdf.fs │ │ │ ├── LICENSE.md │ │ │ └── DotGothic16-Regular_OFL.txt │ │ ├── text_codepoints_loading.png │ │ └── text_codepoints_loading.odin │ ├── shapes │ │ ├── shapes_basic_shapes.png │ │ ├── shapes_bouncing_ball.png │ │ ├── shapes_colors_palette.png │ │ ├── shapes_logo_raylib_anim.png │ │ ├── shapes_bouncing_ball.odin │ │ ├── shapes_basic_shapes.odin │ │ ├── shapes_colors_palette.odin │ │ └── shapes_logo_raylib_anim.odin │ ├── textures │ │ ├── resources │ │ │ └── scarfy_run.gif │ │ └── textures_gif_player.odin │ ├── README.md │ ├── LICENSE │ └── shaders │ │ ├── resources │ │ └── shaders │ │ │ ├── lighting_instancing.vs │ │ │ └── lighting.fs │ │ ├── rlights │ │ └── rlights.odin │ │ └── shaders_mesh_instancing.odin └── log │ └── main.odin ├── nanovg ├── fonts │ ├── entypo.ttf │ ├── Roboto-Bold.ttf │ ├── Roboto-Regular.ttf │ └── NotoEmoji-Regular.ttf ├── images │ ├── image1.jpg │ ├── image10.jpg │ ├── image11.jpg │ ├── image12.jpg │ ├── image2.jpg │ ├── image3.jpg │ ├── image4.jpg │ ├── image5.jpg │ ├── image6.jpg │ ├── image7.jpg │ ├── image8.jpg │ └── image9.jpg └── fbo.odin ├── code_generation ├── images │ ├── tuna.png │ ├── long_cat.png │ └── round_cat.png ├── images.odin ├── README.md ├── main.odin └── generate_image_info │ └── generate_image_info.odin ├── vulkan └── triangle_glfw │ ├── frag.spv │ ├── vert.spv │ ├── shader.frag │ ├── shader.vert │ └── README.md ├── directx └── d3d11_minimal_sdl2 │ └── SDL2.dll ├── .editorconfig ├── .gitignore ├── math ├── noise │ └── draw_texture │ │ ├── shader.frag │ │ └── shader.vert └── rand │ └── markov │ └── simple_markov.odin ├── command_line_arguments └── main.odin ├── json ├── load_json │ ├── game_settings.json │ └── load_json.odin ├── load_json_unmarshal │ ├── game_settings.json │ └── load_json_unmarshal.odin └── write_json_marshal │ └── odin_info.odin ├── console ├── read_console_input │ └── read_console_input.odin └── raw_console │ ├── raw_posix.odin │ ├── raw_windows.odin │ └── main.odin ├── absolute_beginners ├── README.md ├── 6_pointers.odin ├── 4_if_statements.odin ├── 5_structs.odin ├── 3_loops.odin ├── 1_main.odin └── 2_variables.odin ├── wgpu ├── microui │ ├── build_web.bat │ ├── build_web.sh │ ├── web │ │ └── index.html │ ├── shader.wgsl │ ├── os_glfw.odin │ └── os_js.odin ├── glfw-triangle │ ├── build_web.bat │ ├── build_web.sh │ ├── web │ │ └── index.html │ ├── os_glfw.odin │ ├── os_js.odin │ └── main.odin └── sdl3-triangle │ ├── build_web.bat │ ├── build_web.sh │ ├── web │ └── index.html │ ├── os_js.odin │ ├── os_sdl3.odin │ └── main.odin ├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── check.yml ├── net └── tcp_echo_server │ ├── README.md │ ├── client │ └── client.odin │ └── server │ └── server.odin ├── glfw └── window │ └── simple_window.odin ├── thread └── basics │ └── thread_basics.odin ├── dynamic_arrays └── dynamic_arrays.odin ├── README.md ├── dir_info └── main.odin ├── strings └── basic_string_example.odin ├── metal ├── learn_metal │ ├── 00-window │ │ └── 00-window.odin │ ├── README.md │ └── 01-primitive │ │ └── 01-primitive.odin └── minimal_sdl2 │ └── objc_metal_with_sdl.odin ├── slices └── prefer_to_pass_slices │ └── prefer_to_pass_slices.odin └── opengl └── minimal_sdl2 └── sdl2_opengl_demo.odin /arena_allocator/file1.txt: -------------------------------------------------------------------------------- 1 | This is from file1.txt -------------------------------------------------------------------------------- /arena_allocator/file2.txt: -------------------------------------------------------------------------------- 1 | This is from file2.txt -------------------------------------------------------------------------------- /arena_allocator/file3.txt: -------------------------------------------------------------------------------- 1 | This is from file3.txt -------------------------------------------------------------------------------- /orca/breakout/data/test_read.txt: -------------------------------------------------------------------------------- 1 | Hello, ressource file 2 | -------------------------------------------------------------------------------- /wasm/js_wasm32/.gitignore: -------------------------------------------------------------------------------- 1 | web/index.wasm 2 | web/odin.js -------------------------------------------------------------------------------- /sdl2/hellope/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | odin run . -show-timings -vet -------------------------------------------------------------------------------- /win32/emblem.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/win32/emblem.ico -------------------------------------------------------------------------------- /orca/clock/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/orca/clock/icon.png -------------------------------------------------------------------------------- /raylib/box2d/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/box2d/box.png -------------------------------------------------------------------------------- /sdl2/hellope/SDL2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/sdl2/hellope/SDL2.dll -------------------------------------------------------------------------------- /nanovg/fonts/entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/fonts/entypo.ttf -------------------------------------------------------------------------------- /raylib/box2d/ground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/box2d/ground.png -------------------------------------------------------------------------------- /sdl2/hellope/Makefile: -------------------------------------------------------------------------------- 1 | all: run 2 | 3 | run: 4 | odin run . -show-timings -vet -out:hellope 5 | -------------------------------------------------------------------------------- /nanovg/images/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image1.jpg -------------------------------------------------------------------------------- /nanovg/images/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image10.jpg -------------------------------------------------------------------------------- /nanovg/images/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image11.jpg -------------------------------------------------------------------------------- /nanovg/images/image12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image12.jpg -------------------------------------------------------------------------------- /nanovg/images/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image2.jpg -------------------------------------------------------------------------------- /nanovg/images/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image3.jpg -------------------------------------------------------------------------------- /nanovg/images/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image4.jpg -------------------------------------------------------------------------------- /nanovg/images/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image5.jpg -------------------------------------------------------------------------------- /nanovg/images/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image6.jpg -------------------------------------------------------------------------------- /nanovg/images/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image7.jpg -------------------------------------------------------------------------------- /nanovg/images/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image8.jpg -------------------------------------------------------------------------------- /nanovg/images/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/images/image9.jpg -------------------------------------------------------------------------------- /sdl2/hellope/logo-slim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/sdl2/hellope/logo-slim.png -------------------------------------------------------------------------------- /nanovg/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /orca/breakout/data/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/orca/breakout/data/ball.png -------------------------------------------------------------------------------- /orca/breakout/data/brick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/orca/breakout/data/brick.png -------------------------------------------------------------------------------- /orca/clock/data/segoeui.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/orca/clock/data/segoeui.ttf -------------------------------------------------------------------------------- /sdl2/hellope/SDL2_image.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/sdl2/hellope/SDL2_image.dll -------------------------------------------------------------------------------- /sdl2/hellope/libpng16-16.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/sdl2/hellope/libpng16-16.dll -------------------------------------------------------------------------------- /code_generation/images/tuna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/code_generation/images/tuna.png -------------------------------------------------------------------------------- /nanovg/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /orca/ui/data/OpenSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/orca/ui/data/OpenSans-Bold.ttf -------------------------------------------------------------------------------- /vulkan/triangle_glfw/frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/vulkan/triangle_glfw/frag.spv -------------------------------------------------------------------------------- /vulkan/triangle_glfw/vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/vulkan/triangle_glfw/vert.spv -------------------------------------------------------------------------------- /orca/breakout/data/underwater.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/orca/breakout/data/underwater.jpg -------------------------------------------------------------------------------- /orca/ui/data/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/orca/ui/data/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /code_generation/images/long_cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/code_generation/images/long_cat.png -------------------------------------------------------------------------------- /code_generation/images/round_cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/code_generation/images/round_cat.png -------------------------------------------------------------------------------- /directx/d3d11_minimal_sdl2/SDL2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/directx/d3d11_minimal_sdl2/SDL2.dll -------------------------------------------------------------------------------- /nanovg/fonts/NotoEmoji-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/nanovg/fonts/NotoEmoji-Regular.ttf -------------------------------------------------------------------------------- /raylib/ports/text/resources/KAISG.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/KAISG.ttf -------------------------------------------------------------------------------- /raylib/ports/text/resources/dejavu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/dejavu.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/noto_cjk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/noto_cjk.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/symbola.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/symbola.png -------------------------------------------------------------------------------- /raylib/ports/shapes/shapes_basic_shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/shapes/shapes_basic_shapes.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/fonts/mecha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/fonts/mecha.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/pixantiqua.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/pixantiqua.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/pixantiqua.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/pixantiqua.ttf -------------------------------------------------------------------------------- /orca/breakout/data/Literata-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/orca/breakout/data/Literata-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /raylib/ports/shapes/shapes_bouncing_ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/shapes/shapes_bouncing_ball.png -------------------------------------------------------------------------------- /raylib/ports/shapes/shapes_colors_palette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/shapes/shapes_colors_palette.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/custom_alagard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/custom_alagard.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/custom_mecha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/custom_mecha.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/fonts/alagard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/fonts/alagard.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/fonts/romulus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/fonts/romulus.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/fonts/setback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/fonts/setback.png -------------------------------------------------------------------------------- /raylib/ports/text/text_codepoints_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/text_codepoints_loading.png -------------------------------------------------------------------------------- /raylib/ports/textures/resources/scarfy_run.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/textures/resources/scarfy_run.gif -------------------------------------------------------------------------------- /raylib/ports/shapes/shapes_logo_raylib_anim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/shapes/shapes_logo_raylib_anim.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/fonts/alpha_beta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/fonts/alpha_beta.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/fonts/pixantiqua.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/fonts/pixantiqua.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/fonts/pixelplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/fonts/pixelplay.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/DotGothic16-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/DotGothic16-Regular.ttf -------------------------------------------------------------------------------- /raylib/ports/text/resources/anonymous_pro_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/anonymous_pro_bold.ttf -------------------------------------------------------------------------------- /raylib/ports/text/resources/fonts/jupiter_crash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/fonts/jupiter_crash.png -------------------------------------------------------------------------------- /raylib/ports/text/resources/custom_jupiter_crash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cj1128/examples/HEAD/raylib/ports/text/resources/custom_jupiter_crash.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | 7 | [*.y{,a}ml] 8 | indent_size = 2 9 | indent_style = space 10 | tab_width = 2 11 | -------------------------------------------------------------------------------- /wasm/js_wasm32/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | odin_js=$(odin root)/core/sys/wasm/js/odin.js 4 | cp "$odin_js" web/odin.js 5 | 6 | odin build . -target:js_wasm32 -out:web/index.wasm 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.ll 3 | *.obj 4 | *.pdb 5 | 6 | **.exp 7 | tetroid.lib 8 | ols.json 9 | 10 | .vscode 11 | .idea 12 | 13 | # orca samples 14 | 15 | orca_output 16 | module.wasm -------------------------------------------------------------------------------- /vulkan/triangle_glfw/shader.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 fragColor; 4 | 5 | layout(location = 0) out vec4 outColor; 6 | 7 | void main() { 8 | outColor = vec4(fragColor, 1.0); 9 | } -------------------------------------------------------------------------------- /wasm/js_wasm32/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | for /f "delims=" %%i in ('odin.exe root') do set "ODIN_PATH=%%i" 4 | copy "%ODIN_PATH%\core\sys\wasm\js\odin.js" "web\odin.js" 5 | 6 | call odin.exe build . -target:js_wasm32 -out:web\index.wasm 7 | -------------------------------------------------------------------------------- /math/noise/draw_texture/shader.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(location = 0) out vec4 color; 4 | 5 | in vec2 texture_coords; 6 | uniform sampler2D u_texture; 7 | 8 | void main() { 9 | color = texture(u_texture, texture_coords); 10 | } -------------------------------------------------------------------------------- /command_line_arguments/main.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "core:fmt" 4 | import "core:os" 5 | 6 | main :: proc() { 7 | // os.args is a []string 8 | fmt.println(os.args[0]) // executable name 9 | fmt.println(os.args[1:]) // the rest of the arguments 10 | } 11 | -------------------------------------------------------------------------------- /json/load_json/game_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "window_width": 1920, 4 | "window_height": 1080, 5 | "window_title": "My Game!", 6 | 7 | "rendering_api": "opengl", 8 | "renderer_settings": { 9 | "msaa": false, 10 | "depth_testing": true 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /json/load_json_unmarshal/game_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "window_width": 1920, 4 | "window_height": 1080, 5 | "window_title": "My Game!", 6 | 7 | "rendering_api": "opengl", 8 | "renderer_settings": { 9 | "msaa": false, 10 | "depth_testing": true 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /console/read_console_input/read_console_input.odin: -------------------------------------------------------------------------------- 1 | package read_console_input 2 | 3 | import "core:fmt" 4 | import "core:os" 5 | 6 | main :: proc() { 7 | buf: [256]byte 8 | fmt.println("Please enter some text:") 9 | n, err := os.read(os.stdin, buf[:]) 10 | if err != nil { 11 | fmt.eprintln("Error reading: ", err) 12 | return 13 | } 14 | str := string(buf[:n]) 15 | fmt.println("Outputted text:", str) 16 | } 17 | -------------------------------------------------------------------------------- /wasm/js_wasm32/main.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // The build will fail without the required `main` function, 4 | // though we won't use it at all in this example. 5 | main :: proc() {} 6 | 7 | // This is the function we'll use in the browser. 8 | // Add the @export() attribute to ensure that the function is 9 | // available in our WASM module. 10 | @(export) 11 | add_numbers :: proc(a: i32, b: i32) -> i32 { 12 | return a + b 13 | } 14 | -------------------------------------------------------------------------------- /math/noise/draw_texture/shader.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(location = 0) in vec2 xy; 4 | layout(location = 1) in vec2 passed_texture_coords; 5 | 6 | uniform mat4 u_projection; 7 | out vec2 texture_coords; 8 | 9 | void main() { 10 | // Get rid of the z dimension. 11 | vec4 xy_copy = u_projection * vec4(xy, 1.0, 1.0); 12 | xy_copy.z = 1.0; 13 | gl_Position = xy_copy; 14 | texture_coords = passed_texture_coords; 15 | } -------------------------------------------------------------------------------- /vulkan/triangle_glfw/shader.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) out vec3 fragColor; 4 | 5 | vec2 positions[3] = vec2[]( 6 | vec2(0.0, -0.5), 7 | vec2(0.5, 0.5), 8 | vec2(-0.5, 0.5) 9 | ); 10 | 11 | vec3 colors[3] = vec3[]( 12 | vec3(1.0, 0.0, 0.0), 13 | vec3(0.0, 1.0, 0.0), 14 | vec3(0.0, 0.0, 1.0) 15 | ); 16 | 17 | void main() { 18 | gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); 19 | fragColor = colors[gl_VertexIndex]; 20 | } -------------------------------------------------------------------------------- /raylib/ports/README.md: -------------------------------------------------------------------------------- 1 | These are ports of the official Raylib examples found [here](https://www.raylib.com/examples.html). 2 | 3 | Because we mirror the structure of the original examples, they need to be run with `-file`, and for correct resource loading they need to be run from the same directory that they are in. 4 | 5 | For example, to run the `shaders/shaders_mesh_instancing.odin` example: 6 | 7 | 1. `cd shaders` 8 | 2. `odin run shaders_mesh_instancing.odin -file` 9 | -------------------------------------------------------------------------------- /raylib/ports/text/resources/shaders/glsl100/alpha_discard.fs: -------------------------------------------------------------------------------- 1 | #version 100 2 | 3 | precision mediump float; 4 | 5 | // Input vertex attributes (from vertex shader) 6 | varying vec2 fragTexCoord; 7 | varying vec4 fragColor; 8 | 9 | // Input uniform values 10 | uniform sampler2D texture0; 11 | uniform vec4 colDiffuse; 12 | 13 | void main() 14 | { 15 | vec4 texelColor = texture2D(texture0, fragTexCoord); 16 | 17 | if (texelColor.a == 0.0) discard; 18 | 19 | gl_FragColor = texelColor*fragColor*colDiffuse; 20 | } 21 | -------------------------------------------------------------------------------- /raylib/ports/text/resources/shaders/glsl330/alpha_discard.fs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes (from vertex shader) 4 | in vec2 fragTexCoord; 5 | in vec4 fragColor; 6 | 7 | // Input uniform values 8 | uniform sampler2D texture0; 9 | uniform vec4 colDiffuse; 10 | 11 | // Output fragment color 12 | out vec4 finalColor; 13 | 14 | void main() 15 | { 16 | vec4 texelColor = texture(texture0, fragTexCoord); 17 | if (texelColor.a == 0.0) discard; 18 | finalColor = texelColor * fragColor * colDiffuse; 19 | } 20 | -------------------------------------------------------------------------------- /absolute_beginners/README.md: -------------------------------------------------------------------------------- 1 | # Odin for Absolute Beginners 2 | 3 | This program shows the most basic features of Odin. It is meant for total beginners with very little programming experience. 4 | 5 | To start learning, open `1_main.odin` and read from the top. 6 | 7 | You can run the example by navigating to this folder in a command-prompt or terminal and typing: 8 | 9 | ``` 10 | odin run . 11 | ``` 12 | 13 | However, the output might not make much sense without reading the code. 14 | 15 | See https://odin-lang.org/docs/ for additional Odin learning material. -------------------------------------------------------------------------------- /code_generation/images.odin: -------------------------------------------------------------------------------- 1 | // This file is generated. Re-generate it by running: 2 | // odin run generate_image_info 3 | package image_viewer 4 | 5 | Image :: struct { 6 | width: int, 7 | height: int, 8 | data: []u8, 9 | } 10 | 11 | Image_Name :: enum { 12 | Long_Cat, 13 | Round_Cat, 14 | Tuna, 15 | } 16 | 17 | images := [Image_Name]Image { 18 | .Long_Cat = { data = #load("images/long_cat.png"), width = 9, height = 46 }, 19 | .Round_Cat = { data = #load("images/round_cat.png"), width = 20, height = 24 }, 20 | .Tuna = { data = #load("images/tuna.png"), width = 24, height = 20 }, 21 | } 22 | -------------------------------------------------------------------------------- /wasm/js_wasm32/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Odin js_wasm32 example 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Result will appear here
16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /wgpu/microui/build_web.bat: -------------------------------------------------------------------------------- 1 | REM NOTE: changing this requires changing the same values in the `web/index.html`. 2 | set INITIAL_MEMORY_PAGES=2000 3 | set MAX_MEMORY_PAGES=65536 4 | 5 | set PAGE_SIZE=65536 6 | set /a INITIAL_MEMORY_BYTES=%INITIAL_MEMORY_PAGES% * %PAGE_SIZE% 7 | set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE% 8 | 9 | call odin.exe build . -target:js_wasm32 -out:web/microui.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%" 10 | 11 | for /f "delims=" %%i in ('odin.exe root') do set "ODIN_ROOT=%%i" 12 | copy "%ODIN_ROOT%\vendor\wgpu\wgpu.js" "web\wgpu.js" 13 | copy "%ODIN_ROOT%\core\sys\wasm\js\odin.js" "web\odin.js" 14 | -------------------------------------------------------------------------------- /wgpu/glfw-triangle/build_web.bat: -------------------------------------------------------------------------------- 1 | REM NOTE: changing this requires changing the same values in the `web/index.html`. 2 | set INITIAL_MEMORY_PAGES=2000 3 | set MAX_MEMORY_PAGES=65536 4 | 5 | set PAGE_SIZE=65536 6 | set /a INITIAL_MEMORY_BYTES=%INITIAL_MEMORY_PAGES% * %PAGE_SIZE% 7 | set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE% 8 | 9 | call odin.exe build . -target:js_wasm32 -out:web/triangle.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%" 10 | 11 | for /f "delims=" %%i in ('odin.exe root') do set "ODIN_ROOT=%%i" 12 | copy "%ODIN_ROOT%\vendor\wgpu\wgpu.js" "web\wgpu.js" 13 | copy "%ODIN_ROOT%\core\sys\wasm\js\odin.js" "web\odin.js" 14 | -------------------------------------------------------------------------------- /wgpu/sdl3-triangle/build_web.bat: -------------------------------------------------------------------------------- 1 | REM NOTE: changing this requires changing the same values in the `web/index.html`. 2 | set INITIAL_MEMORY_PAGES=2000 3 | set MAX_MEMORY_PAGES=65536 4 | 5 | set PAGE_SIZE=65536 6 | set /a INITIAL_MEMORY_BYTES=%INITIAL_MEMORY_PAGES% * %PAGE_SIZE% 7 | set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE% 8 | 9 | call odin.exe build . -target:js_wasm32 -out:web/triangle.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%" 10 | 11 | for /f "delims=" %%i in ('odin.exe root') do set "ODIN_ROOT=%%i" 12 | copy "%ODIN_ROOT%\vendor\wgpu\wgpu.js" "web\wgpu.js" 13 | copy "%ODIN_ROOT%\core\sys\wasm\js\odin.js" "web\odin.js" 14 | -------------------------------------------------------------------------------- /wgpu/microui/build_web.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | # NOTE: changing this requires changing the same values in the `web/index.html`. 6 | INITIAL_MEMORY_PAGES=2000 7 | MAX_MEMORY_PAGES=65536 8 | 9 | INITIAL_MEMORY_BYTES=$(expr $INITIAL_MEMORY_PAGES \* $MAX_MEMORY_PAGES) 10 | MAX_MEMORY_BYTES=$(expr $MAX_MEMORY_PAGES \* $MAX_MEMORY_PAGES) 11 | 12 | ODIN_ROOT=$(odin root) 13 | ODIN_JS="$ODIN_ROOT/core/sys/wasm/js/odin.js" 14 | WGPU_JS="$ODIN_ROOT/vendor/wgpu/wgpu.js" 15 | 16 | odin build . -target:js_wasm32 -out:web/microui.wasm -o:size \ 17 | -extra-linker-flags:"--export-table --import-memory --initial-memory=$INITIAL_MEMORY_BYTES --max-memory=$MAX_MEMORY_BYTES" 18 | 19 | cp $ODIN_JS web/odin.js 20 | cp $WGPU_JS web/wgpu.js 21 | -------------------------------------------------------------------------------- /wgpu/glfw-triangle/build_web.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | # NOTE: changing this requires changing the same values in the `web/index.html`. 6 | INITIAL_MEMORY_PAGES=2000 7 | MAX_MEMORY_PAGES=65536 8 | 9 | INITIAL_MEMORY_BYTES=$(expr $INITIAL_MEMORY_PAGES \* $MAX_MEMORY_PAGES) 10 | MAX_MEMORY_BYTES=$(expr $MAX_MEMORY_PAGES \* $MAX_MEMORY_PAGES) 11 | 12 | ODIN_ROOT=$(odin root) 13 | ODIN_JS="$ODIN_ROOT/core/sys/wasm/js/odin.js" 14 | WGPU_JS="$ODIN_ROOT/vendor/wgpu/wgpu.js" 15 | 16 | odin build . -target:js_wasm32 -out:web/triangle.wasm -o:size \ 17 | -extra-linker-flags:"--export-table --import-memory --initial-memory=$INITIAL_MEMORY_BYTES --max-memory=$MAX_MEMORY_BYTES" 18 | 19 | cp $ODIN_JS web/odin.js 20 | cp $WGPU_JS web/wgpu.js 21 | -------------------------------------------------------------------------------- /wgpu/sdl3-triangle/build_web.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | # NOTE: changing this requires changing the same values in the `web/index.html`. 6 | INITIAL_MEMORY_PAGES=2000 7 | MAX_MEMORY_PAGES=65536 8 | 9 | INITIAL_MEMORY_BYTES=$(expr $INITIAL_MEMORY_PAGES \* $MAX_MEMORY_PAGES) 10 | MAX_MEMORY_BYTES=$(expr $MAX_MEMORY_PAGES \* $MAX_MEMORY_PAGES) 11 | 12 | ODIN_ROOT=$(odin root) 13 | ODIN_JS="$ODIN_ROOT/core/sys/wasm/js/odin.js" 14 | WGPU_JS="$ODIN_ROOT/vendor/wgpu/wgpu.js" 15 | 16 | odin build . -target:js_wasm32 -out:web/triangle.wasm -o:size \ 17 | -extra-linker-flags:"--export-table --import-memory --initial-memory=$INITIAL_MEMORY_BYTES --max-memory=$MAX_MEMORY_BYTES" 18 | 19 | cp $ODIN_JS web/odin.js 20 | cp $WGPU_JS web/wgpu.js 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Checklist before submitting: 4 | - [ ] This example has been added to `.github/workflows/check.yml` (for automatic testing) 5 | - [ ] This example compiles cleanly with flags `-vet -strict-style -vet-tabs -disallow-do -warnings-as-errors` 6 | - [ ] This example follows the `core` naming convention: https://github.com/odin-lang/Odin/wiki/Naming-Convention (exception can be made for ports of examples that need to match 1:1 to the original source). 7 | - [ ] By submitting, I understand that this example is made available under these licenses: [Public Domain](https://unlicense.org) and [Odin's BSD-3 license](https://github.com/odin-lang/Odin/blob/master/LICENSE). Only for third-party dependencies are other licenses allowed. 8 | -------------------------------------------------------------------------------- /code_generation/README.md: -------------------------------------------------------------------------------- 1 | This shows some basic code generation / meta programming. 2 | 3 | The code generation is done by running a separate program that generates some Odin code. 4 | 5 | Generate `images.odin` by running: 6 | 7 | ``` 8 | odin run generate_image_info 9 | ``` 10 | 11 | The following will build the program that actually uses `images.odin`: 12 | 13 | ``` 14 | odin run . 15 | ``` 16 | 17 | It will print: 18 | 19 | ``` 20 | Long_Cat is 9 x 46 pixels and 183 bytes large 21 | 22 | Round_Cat is 20 x 24 pixels and 317 bytes large 23 | Round_Cat has width > 15, so we loaded it! 24 | The loaded PNG image is indeed 20 pixels wide! 25 | 26 | Tuna is 24 x 20 pixels and 318 bytes large 27 | Tuna has width > 15, so we loaded it! 28 | The loaded PNG image is indeed 24 pixels wide! 29 | ``` -------------------------------------------------------------------------------- /net/tcp_echo_server/README.md: -------------------------------------------------------------------------------- 1 | # Echo Server in Odin 2 | 3 | An Echo Server is a simple network server that sends back to the client whatever data it receives. It is often used as a basic example to test networking functionality. 4 | 5 | ## Requirements 6 | 7 | - [Odin Compiler](https://odin-lang.org/download/) (latest stable version). 8 | - A terminal or command prompt to run the application. 9 | 10 | ## Installation and Usage 11 | 12 | 1. Run the server: 13 | ```bash 14 | odin run server 15 | ``` 16 | 2. Run one or more clients: 17 | ```bash 18 | odin run client 19 | ``` 20 | 3. Or use `telnet`: 21 | ```bash 22 | telnet 127.0.0.1 8080 23 | ``` 24 | 25 | To terminate the client send `Ctrl-D` or `Ctrl-C` or an empty line pressing *Enter* (`\r\n`, `\n`). 26 | -------------------------------------------------------------------------------- /raylib/ports/text/resources/shaders/glsl100/sdf.fs: -------------------------------------------------------------------------------- 1 | #version 100 2 | 3 | precision mediump float; 4 | 5 | // Input vertex attributes (from vertex shader) 6 | varying vec2 fragTexCoord; 7 | varying vec4 fragColor; 8 | 9 | // Input uniform values 10 | uniform sampler2D texture0; 11 | uniform vec4 colDiffuse; 12 | 13 | // NOTE: Add here your custom variables 14 | const float smoothing = 1.0/16.0; 15 | 16 | void main() 17 | { 18 | // Texel color fetching from texture sampler 19 | // NOTE: Calculate alpha using signed distance field (SDF) 20 | float distance = texture2D(texture0, fragTexCoord).a; 21 | float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance); 22 | 23 | // Calculate final fragment color 24 | gl_FragColor = vec4(fragColor.rgb, fragColor.a*alpha); 25 | } 26 | -------------------------------------------------------------------------------- /vulkan/triangle_glfw/README.md: -------------------------------------------------------------------------------- 1 | # Vulkan triangle example 2 | 3 | By laytan, source: https://gist.github.com/laytan/ba57af3e5a59ab5cb2fca9e25bcfe262 4 | 5 | Compile and run using: 6 | ``` 7 | odin run . 8 | ``` 9 | 10 | This example comes with pre-compiled shaders. During compilation the shaders will be loaded from `vert.spv` and `frag.spv`. 11 | 12 | If you make any changes to the shader source files (`shader.vert` or `shader.frag`), then you must recompile them using `glslc`: 13 | ``` 14 | glslc shader.vert -o vert.spv 15 | glslc shader.frag -o frag.spv 16 | ``` 17 | 18 | `glslc` is part of the Vulkan SDK, which you can find here: https://vulkan.lunarg.com/sdk/home 19 | 20 | This example uses glfw for window management. 21 | 22 | ![image](https://github.com/user-attachments/assets/c87b957c-8b1c-4c07-8b3e-b31fa4a98a53) 23 | -------------------------------------------------------------------------------- /console/raw_console/raw_posix.odin: -------------------------------------------------------------------------------- 1 | #+build !windows 2 | package main 3 | 4 | import psx "core:sys/posix" 5 | 6 | @(private="file") 7 | orig_mode: psx.termios 8 | 9 | _enable_raw_mode :: proc() { 10 | // Get the original terminal attributes. 11 | res := psx.tcgetattr(psx.STDIN_FILENO, &orig_mode) 12 | assert(res == .OK) 13 | 14 | // Reset to the original attributes at the end of the program. 15 | psx.atexit(disable_raw_mode) 16 | 17 | // Copy, and remove the 18 | // ECHO (so what is typed is not shown) and 19 | // ICANON (so we get each input instead of an entire line at once) flags. 20 | raw := orig_mode 21 | raw.c_lflag -= {.ECHO, .ICANON} 22 | res = psx.tcsetattr(psx.STDIN_FILENO, .TCSANOW, &raw) 23 | assert(res == .OK) 24 | } 25 | 26 | _disable_raw_mode :: proc "c" () { 27 | psx.tcsetattr(psx.STDIN_FILENO, .TCSANOW, &orig_mode) 28 | } 29 | 30 | _set_utf8_terminal :: proc() {} 31 | -------------------------------------------------------------------------------- /raylib/ports/text/resources/shaders/glsl330/sdf.fs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes (from vertex shader) 4 | in vec2 fragTexCoord; 5 | in vec4 fragColor; 6 | 7 | // Input uniform values 8 | uniform sampler2D texture0; 9 | uniform vec4 colDiffuse; 10 | 11 | // Output fragment color 12 | out vec4 finalColor; 13 | 14 | // NOTE: Add here your custom variables 15 | 16 | void main() 17 | { 18 | // Texel color fetching from texture sampler 19 | // NOTE: Calculate alpha using signed distance field (SDF) 20 | float distanceFromOutline = texture(texture0, fragTexCoord).a - 0.5; 21 | float distanceChangePerFragment = length(vec2(dFdx(distanceFromOutline), dFdy(distanceFromOutline))); 22 | float alpha = smoothstep(-distanceChangePerFragment, distanceChangePerFragment, distanceFromOutline); 23 | 24 | // Calculate final fragment color 25 | finalColor = vec4(fragColor.rgb, fragColor.a*alpha); 26 | } 27 | -------------------------------------------------------------------------------- /wasm/js_wasm32/web/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | (async () => { 4 | // Create our memory interface. While we don't specify any specific memory 5 | // configuration, we'll use the interface to reference our exported Odin function. 6 | const memInterface = new odin.WasmMemoryInterface(); 7 | await odin.runWasm("index.wasm", null, null, memInterface); 8 | // Now after the WASM module is loaded, we can access our exported functions. 9 | const exports = memInterface.exports; 10 | 11 | const button = document.getElementById("add"); 12 | const number1 = document.getElementById("number1"); 13 | const number2 = document.getElementById("number2"); 14 | const result = document.getElementById("result"); 15 | 16 | button.addEventListener("click", () => { 17 | // Call our exported function and show the result! 18 | const total = exports.add_numbers(number1.value, number2.value); 19 | result.innerText = total; 20 | }); 21 | })(); 22 | -------------------------------------------------------------------------------- /sdl2/hellope/LICENSE.SDL2.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 1997-2021 Sam Lantinga 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /absolute_beginners/6_pointers.odin: -------------------------------------------------------------------------------- 1 | package basics 2 | 3 | import "core:fmt" 4 | 5 | // This procedure has a parameter that is of type `^Cat`. Read that as: 6 | // "pointer to Cat". The `^Cat` type contains a memory address. We can go 7 | // through that pointer in order to modify the memory that lives there. 8 | pointers :: proc(cat: ^Cat) { 9 | // Printing a pointer shows the value at that memory address. 10 | fmt.println(cat) // &Cat{name = "Klucke", age = 5} 11 | 12 | // But we can also use the format string "%p" to directly print the memory 13 | // address it contains. This is not super-important, but interesting to see 14 | // that the pointer is just a number! 15 | fmt.printfln("%p", cat) // 0x52EF52F878 16 | 17 | // This will go through the pointer `cat` and modify the `age` field. The 18 | // procedure that called this procedure (main) will be able to see these 19 | // changes as well. 20 | cat.age = 11 21 | 22 | fmt.println(cat) // &Cat{name = "Klucke", age = 11} 23 | } -------------------------------------------------------------------------------- /sdl2/hellope/LICENSE.SDL2_image.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 1997-2021 Sam Lantinga 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /wasm/js_wasm32/README.md: -------------------------------------------------------------------------------- 1 | # Odin js_wasm32 example 2 | 3 | This is an example of how to build an Odin program using the `js_wasm32` target. The example features a website that can call an Odin procedure. 4 | 5 | ## Building 6 | 7 | Run `build.bat` (Windows) or `build.sh` (mac / Linux). 8 | 9 | This builds the WASM module and also copies `odin.js` from the [core Odin library](https://github.com/odin-lang/Odin/blob/master/core/sys/wasm/js/odin.js) as it's required for a `js_wasm32` build. 10 | 11 | ## Running 12 | 13 | You need to run a local webserver in the `web` directory in order to serve the site. There are few, simple options for this. 14 | 15 | - Navigate to the `web` directory. 16 | 17 | ```bash 18 | cd web 19 | ``` 20 | 21 | - Run a webserver. 22 | 23 | ```bash 24 | # If you have Python installed. 25 | python -m http.server 26 | ``` 27 | 28 | ```bash 29 | # If you have Node.js installed. 30 | npx http-server -p 8000 . 31 | ``` 32 | 33 | - Visit [http://localhost:8000](http://localhost:8000) 34 | -------------------------------------------------------------------------------- /wgpu/glfw-triangle/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WGPU WASM Triangle 7 | 8 | 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /wgpu/microui/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Odin / MicroUI / WGPU 7 | 8 | 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /wgpu/sdl3-triangle/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WGPU WASM Triangle 7 | 8 | 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /raylib/ports/LICENSE: -------------------------------------------------------------------------------- 1 | These are ported Raylib examples, and as such, they are subject to Raylib's license. 2 | 3 | Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) 4 | 5 | This software is provided "as-is", without any express or implied warranty. In no event 6 | will the authors be held liable for any damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, including commercial 9 | applications, and to alter it and redistribute it freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not claim that you 12 | wrote the original software. If you use this software in a product, an acknowledgment 13 | in the product documentation would be appreciated but is not required. 14 | 15 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented 16 | as being the original software. 17 | 18 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /json/load_json_unmarshal/load_json_unmarshal.odin: -------------------------------------------------------------------------------- 1 | package load_json_unmarshal 2 | 3 | import "core:os" 4 | import "core:fmt" 5 | import "core:encoding/json" 6 | 7 | Game_Settings :: struct { 8 | window_width: i32, 9 | window_height: i32, 10 | window_title: string, 11 | rendering_api: string, 12 | renderer_settings: struct{ 13 | msaa: bool, 14 | depth_testing: bool, 15 | }, 16 | } 17 | 18 | main :: proc(){ 19 | // Load in your json file! 20 | data, ok := os.read_entire_file_from_filename("game_settings.json") 21 | if !ok { 22 | fmt.eprintln("Failed to load the file!") 23 | return 24 | } 25 | defer delete(data) // Free the memory at the end 26 | 27 | // Load data from the json bytes directly to the struct 28 | settings: Game_Settings 29 | unmarshal_err := json.unmarshal(data, &settings) 30 | if unmarshal_err != nil { 31 | fmt.eprintln("Failed to unmarshal the file!") 32 | return 33 | } 34 | fmt.eprintf("Result %v\n", settings) 35 | 36 | // Clear allocated strings 37 | delete(settings.window_title) 38 | delete(settings.rendering_api) 39 | } -------------------------------------------------------------------------------- /raylib/ports/shaders/resources/shaders/lighting_instancing.vs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes 4 | in vec3 vertexPosition; 5 | in vec2 vertexTexCoord; 6 | in vec3 vertexNormal; 7 | //in vec4 vertexColor; // Not required 8 | 9 | in mat4 instanceTransform; 10 | 11 | // Input uniform values 12 | uniform mat4 mvp; 13 | uniform mat4 matNormal; 14 | 15 | // Output vertex attributes (to fragment shader) 16 | out vec3 fragPosition; 17 | out vec2 fragTexCoord; 18 | out vec4 fragColor; 19 | out vec3 fragNormal; 20 | 21 | // NOTE: Add here your custom variables 22 | 23 | void main() 24 | { 25 | // Compute MVP for current instance 26 | mat4 mvpi = mvp*instanceTransform; 27 | 28 | // Send vertex attributes to fragment shader 29 | fragPosition = vec3(mvpi*vec4(vertexPosition, 1.0)); 30 | fragTexCoord = vertexTexCoord; 31 | //fragColor = vertexColor; 32 | fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); 33 | 34 | // Calculate final vertex position 35 | gl_Position = mvpi*vec4(vertexPosition, 1.0); 36 | } 37 | -------------------------------------------------------------------------------- /raylib/box2d/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Erin Catto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /win32/open_window/main.odin: -------------------------------------------------------------------------------- 1 | package open_win32_window 2 | 3 | import win "core:sys/windows" 4 | 5 | main :: proc() { 6 | instance := win.HINSTANCE(win.GetModuleHandleW(nil)) 7 | assert(instance != nil, "Failed to fetch current instance") 8 | class_name := win.L("Windows Window") 9 | 10 | cls := win.WNDCLASSW { 11 | lpfnWndProc = win_proc, 12 | lpszClassName = class_name, 13 | hInstance = instance, 14 | hCursor = win.LoadCursorA(nil, win.IDC_ARROW), 15 | } 16 | 17 | class := win.RegisterClassW(&cls) 18 | assert(class != 0, "Class creation failed") 19 | 20 | hwnd := win.CreateWindowW(class_name, 21 | win.L("Windows Window"), 22 | win.WS_OVERLAPPEDWINDOW | win.WS_VISIBLE, 23 | 100, 100, 1280, 720, 24 | nil, nil, instance, nil) 25 | 26 | assert(hwnd != nil, "Window creation Failed") 27 | msg: win.MSG 28 | 29 | for win.GetMessageW(&msg, nil, 0, 0) > 0 { 30 | win.TranslateMessage(&msg) 31 | win.DispatchMessageW(&msg) 32 | } 33 | } 34 | 35 | win_proc :: proc "stdcall" (hwnd: win.HWND, msg: win.UINT, wparam: win.WPARAM, lparam: win.LPARAM) -> win.LRESULT { 36 | switch(msg) { 37 | case win.WM_DESTROY: 38 | win.PostQuitMessage(0) 39 | } 40 | 41 | return win.DefWindowProcW(hwnd, msg, wparam, lparam) 42 | } -------------------------------------------------------------------------------- /console/raw_console/raw_windows.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "core:c/libc" 4 | import win32 "core:sys/windows" 5 | 6 | @(private="file") 7 | orig_mode: win32.DWORD 8 | 9 | _enable_raw_mode :: proc() { 10 | // Get a handle to the standard input. 11 | stdin := win32.GetStdHandle(win32.STD_INPUT_HANDLE) 12 | assert(stdin != win32.INVALID_HANDLE_VALUE) 13 | 14 | // Get the original terminal mode. 15 | ok := win32.GetConsoleMode(stdin, &orig_mode) 16 | assert(ok == true) 17 | 18 | // Reset to the original attributes at the end of the program. 19 | libc.atexit(disable_raw_mode) 20 | 21 | // Copy, and remove the 22 | // ENABLE_ECHO_INPUT (so what is typed is not shown) and 23 | // ENABLE_LINE_INPUT (so we get each input instead of an entire line at once) flags. 24 | raw := orig_mode 25 | raw &= ~win32.ENABLE_ECHO_INPUT 26 | raw &= ~win32.ENABLE_LINE_INPUT 27 | ok = win32.SetConsoleMode(stdin, raw) 28 | assert(ok == true) 29 | } 30 | 31 | _disable_raw_mode :: proc "c" () { 32 | stdin := win32.GetStdHandle(win32.STD_INPUT_HANDLE) 33 | assert_contextless(stdin != win32.INVALID_HANDLE_VALUE) 34 | 35 | win32.SetConsoleMode(stdin, orig_mode) 36 | } 37 | 38 | _set_utf8_terminal :: proc() { 39 | win32.SetConsoleOutputCP(.UTF8) 40 | win32.SetConsoleCP(.UTF8) 41 | } 42 | -------------------------------------------------------------------------------- /wgpu/microui/shader.wgsl: -------------------------------------------------------------------------------- 1 | struct VertexOutput { 2 | @builtin(position) position: vec4, 3 | @location(0) texCoord: vec2, 4 | @location(1) @interpolate(flat) color: u32, 5 | }; 6 | 7 | @vertex 8 | fn vs_main( 9 | @location(0) pos: vec2, 10 | @location(1) texCoord: vec2, 11 | @location(2) color: u32 12 | ) -> VertexOutput { 13 | var output: VertexOutput; 14 | output.position = transform * vec4(pos, 0, 1); 15 | output.texCoord = texCoord; 16 | output.color = color; 17 | return output; 18 | } 19 | 20 | @group(0) @binding(0) var samp: sampler; 21 | @group(0) @binding(1) var text: texture_2d; 22 | @group(0) @binding(2) var transform: mat4x4; 23 | 24 | @fragment 25 | fn fs_main(@location(0) texCoord: vec2, @location(1) @interpolate(flat) color: u32) -> @location(0) vec4 { 26 | // NOTE: this samples rgba, but the texture just contains the alpha channel, 27 | // so in practice `r` is the alpha, and the rest is junk. 28 | let texColor = textureSample(text, samp, texCoord); 29 | let a = texColor.r * f32((color >> 24) & 0xffu) / 255; 30 | let b = f32((color >> 16) & 0xffu) / 255; 31 | let g = f32((color >> 8) & 0xffu) / 255; 32 | let r = f32(color & 0xffu) / 255; 33 | return vec4(r, g, b, a); 34 | } 35 | -------------------------------------------------------------------------------- /glfw/window/simple_window.odin: -------------------------------------------------------------------------------- 1 | package glfw_window 2 | 3 | import "core:fmt" 4 | import "vendor:glfw" 5 | import gl "vendor:OpenGL" 6 | 7 | WIDTH :: 1600 8 | HEIGHT :: 900 9 | TITLE :: "My Window!" 10 | 11 | // @note You might need to lower this to 3.3 depending on how old your graphics card is. 12 | GL_MAJOR_VERSION :: 4 13 | GL_MINOR_VERSION :: 5 14 | 15 | main :: proc() { 16 | if !bool(glfw.Init()) { 17 | fmt.eprintln("GLFW has failed to load.") 18 | return 19 | } 20 | 21 | window_handle := glfw.CreateWindow(WIDTH, HEIGHT, TITLE, nil, nil) 22 | 23 | defer glfw.Terminate() 24 | defer glfw.DestroyWindow(window_handle) 25 | 26 | if window_handle == nil { 27 | fmt.eprintln("GLFW has failed to load the window.") 28 | return 29 | } 30 | 31 | // Load OpenGL context or the "state" of OpenGL. 32 | glfw.MakeContextCurrent(window_handle) 33 | // Load OpenGL function pointers with the specficed OpenGL major and minor version. 34 | gl.load_up_to(GL_MAJOR_VERSION, GL_MINOR_VERSION, glfw.gl_set_proc_address) 35 | 36 | for !glfw.WindowShouldClose(window_handle) { 37 | // Process all incoming events like keyboard press, window resize, and etc. 38 | glfw.PollEvents() 39 | 40 | gl.ClearColor(0.5, 0.0, 1.0, 1.0) 41 | gl.Clear(gl.COLOR_BUFFER_BIT) 42 | 43 | glfw.SwapBuffers(window_handle) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /wgpu/glfw-triangle/os_glfw.odin: -------------------------------------------------------------------------------- 1 | #+build !js 2 | package vendor_wgpu_example_triangle 3 | 4 | import "core:time" 5 | 6 | import "vendor:glfw" 7 | import "vendor:wgpu" 8 | import "vendor:wgpu/glfwglue" 9 | 10 | OS :: struct { 11 | window: glfw.WindowHandle, 12 | } 13 | 14 | os_init :: proc() { 15 | if !glfw.Init() { 16 | panic("[glfw] init failure") 17 | } 18 | 19 | glfw.WindowHint(glfw.CLIENT_API, glfw.NO_API) 20 | state.os.window = glfw.CreateWindow(960, 540, "WGPU Native Triangle", nil, nil) 21 | 22 | glfw.SetFramebufferSizeCallback(state.os.window, size_callback) 23 | } 24 | 25 | os_run :: proc() { 26 | dt: f32 27 | 28 | for !glfw.WindowShouldClose(state.os.window) { 29 | start := time.tick_now() 30 | 31 | glfw.PollEvents() 32 | frame(dt) 33 | 34 | dt = f32(time.duration_seconds(time.tick_since(start))) 35 | } 36 | 37 | finish() 38 | 39 | glfw.DestroyWindow(state.os.window) 40 | glfw.Terminate() 41 | } 42 | 43 | os_get_framebuffer_size :: proc() -> (width, height: u32) { 44 | iw, ih := glfw.GetFramebufferSize(state.os.window) 45 | return u32(iw), u32(ih) 46 | } 47 | 48 | os_get_surface :: proc(instance: wgpu.Instance) -> wgpu.Surface { 49 | return glfwglue.GetSurface(instance, state.os.window) 50 | } 51 | 52 | @(private="file") 53 | size_callback :: proc "c" (window: glfw.WindowHandle, width, height: i32) { 54 | resize() 55 | } 56 | -------------------------------------------------------------------------------- /net/tcp_echo_server/client/client.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "core:fmt" 4 | import "core:net" 5 | import "core:os" 6 | 7 | tcp_echo_client :: proc(ip: string, port: int) { 8 | local_addr, ok := net.parse_ip4_address(ip) 9 | if !ok { 10 | fmt.println("Failed to parse IP address") 11 | return 12 | } 13 | sock, err := net.dial_tcp_from_address_and_port(local_addr, port) 14 | if err != nil { 15 | fmt.println("Failed to connect to server") 16 | return 17 | } 18 | buffer: [256]u8 19 | for { 20 | n, err_read := os.read(os.stdin, buffer[:]) 21 | if err_read != nil { 22 | fmt.println("Failed to read data") 23 | break 24 | } 25 | if n == 0 || (n == 1 && buffer[0] == '\n') { 26 | break 27 | } 28 | data := buffer[:n] 29 | bytes_sent, err_send := net.send_tcp(sock, data) 30 | if err_send != nil { 31 | fmt.println("Failed to send data") 32 | break 33 | } 34 | sent := data[:bytes_sent] 35 | fmt.printfln("Client sent [ %d bytes ]: %s", len(sent), sent) 36 | bytes_recv, err_recv := net.recv_tcp(sock, buffer[:]) 37 | if err_recv != nil { 38 | fmt.println("Failed to receive data") 39 | break 40 | } 41 | received := buffer[:bytes_recv] 42 | fmt.printfln("Client received [ %d bytes ]: %s", len(received), received) 43 | } 44 | net.close(sock) 45 | } 46 | 47 | main :: proc() { 48 | tcp_echo_client("127.0.0.1", 8080) 49 | } 50 | -------------------------------------------------------------------------------- /json/load_json/load_json.odin: -------------------------------------------------------------------------------- 1 | package load_json 2 | 3 | import "core:fmt" 4 | import "core:encoding/json" 5 | 6 | import "core:os" 7 | 8 | main :: proc() { 9 | // Load in your json file! 10 | data, ok := os.read_entire_file_from_filename("game_settings.json") 11 | if !ok { 12 | fmt.eprintln("Failed to load the file!") 13 | return 14 | } 15 | defer delete(data) // Free the memory at the end 16 | 17 | // Parse the json file. 18 | json_data, err := json.parse(data) 19 | if err != .None { 20 | fmt.eprintln("Failed to parse the json file.") 21 | fmt.eprintln("Error:", err) 22 | return 23 | } 24 | defer json.destroy_value(json_data) 25 | 26 | // Access the Root Level Object 27 | root := json_data.(json.Object) 28 | 29 | fmt.println("Root:") 30 | fmt.println( 31 | "window_width:", 32 | root["window_width"], 33 | "window_height:", 34 | root["window_height"], 35 | "window_title:", 36 | root["window_title"], 37 | ) 38 | fmt.println("rendering_api:", root["rendering_api"]) 39 | 40 | // Store the value. 41 | window_width := root["window_width"].(json.Float) 42 | fmt.println("window_width:", window_width) 43 | 44 | fmt.println("") 45 | 46 | fmt.println("Renderer Settings:") 47 | renderer_settings := root["renderer_settings"].(json.Object) 48 | fmt.println("msaa:", renderer_settings["msaa"]) 49 | fmt.println("depth_testing:", renderer_settings["depth_testing"]) 50 | } 51 | -------------------------------------------------------------------------------- /wgpu/glfw-triangle/os_js.odin: -------------------------------------------------------------------------------- 1 | package vendor_wgpu_example_triangle 2 | 3 | import "core:sys/wasm/js" 4 | 5 | import "vendor:wgpu" 6 | 7 | OS :: struct { 8 | initialized: bool, 9 | } 10 | 11 | os_init :: proc() { 12 | ok := js.add_window_event_listener(.Resize, nil, size_callback) 13 | assert(ok) 14 | } 15 | 16 | // NOTE: frame loop is done by the runtime.js repeatedly calling `step`. 17 | os_run :: proc() { 18 | state.os.initialized = true 19 | } 20 | 21 | @(private="file", export) 22 | step :: proc(dt: f32) -> bool { 23 | if !state.os.initialized { 24 | return true 25 | } 26 | 27 | frame(dt) 28 | return true 29 | } 30 | 31 | os_get_framebuffer_size :: proc() -> (width, height: u32) { 32 | rect := js.get_bounding_client_rect("body") 33 | dpi := js.device_pixel_ratio() 34 | return u32(f64(rect.width) * dpi), u32(f64(rect.height) * dpi) 35 | } 36 | 37 | os_get_surface :: proc(instance: wgpu.Instance) -> wgpu.Surface { 38 | return wgpu.InstanceCreateSurface( 39 | instance, 40 | &wgpu.SurfaceDescriptor{ 41 | nextInChain = &wgpu.SurfaceSourceCanvasHTMLSelector{ 42 | sType = .SurfaceSourceCanvasHTMLSelector, 43 | selector = "#wgpu-canvas", 44 | }, 45 | }, 46 | ) 47 | } 48 | 49 | @(private="file", fini) 50 | os_fini :: proc() { 51 | js.remove_window_event_listener(.Resize, nil, size_callback) 52 | 53 | finish() 54 | } 55 | 56 | @(private="file") 57 | size_callback :: proc(e: js.Event) { 58 | resize() 59 | } 60 | -------------------------------------------------------------------------------- /wgpu/sdl3-triangle/os_js.odin: -------------------------------------------------------------------------------- 1 | package vendor_wgpu_example_triangle 2 | 3 | import "core:sys/wasm/js" 4 | 5 | import "vendor:wgpu" 6 | 7 | OS :: struct { 8 | initialized: bool, 9 | } 10 | 11 | os_init :: proc() { 12 | ok := js.add_window_event_listener(.Resize, nil, size_callback) 13 | assert(ok) 14 | } 15 | 16 | // NOTE: frame loop is done by the runtime.js repeatedly calling `step`. 17 | os_run :: proc() { 18 | state.os.initialized = true 19 | } 20 | 21 | @(private="file", export) 22 | step :: proc(dt: f32) -> bool { 23 | if !state.os.initialized { 24 | return true 25 | } 26 | 27 | frame(dt) 28 | return true 29 | } 30 | 31 | os_get_framebuffer_size :: proc() -> (width, height: u32) { 32 | rect := js.get_bounding_client_rect("body") 33 | dpi := js.device_pixel_ratio() 34 | return u32(f64(rect.width) * dpi), u32(f64(rect.height) * dpi) 35 | } 36 | 37 | os_get_surface :: proc(instance: wgpu.Instance) -> wgpu.Surface { 38 | return wgpu.InstanceCreateSurface( 39 | instance, 40 | &wgpu.SurfaceDescriptor{ 41 | nextInChain = &wgpu.SurfaceSourceCanvasHTMLSelector{ 42 | sType = .SurfaceSourceCanvasHTMLSelector, 43 | selector = "#wgpu-canvas", 44 | }, 45 | }, 46 | ) 47 | } 48 | 49 | @(private="file", fini) 50 | os_fini :: proc() { 51 | js.remove_window_event_listener(.Resize, nil, size_callback) 52 | 53 | finish() 54 | } 55 | 56 | @(private="file") 57 | size_callback :: proc(e: js.Event) { 58 | resize() 59 | } 60 | -------------------------------------------------------------------------------- /win32/game_of_life/game_of_life.rc: -------------------------------------------------------------------------------- 1 | 2 | #include "winres.h" 3 | 4 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK 5 | #pragma code_page(1252) 6 | 7 | #define IDI_ICON1 101 8 | 9 | #define Q(x) #x 10 | #define QUOTE(x) Q(x) 11 | 12 | VS_VERSION_INFO VERSIONINFO 13 | FILEVERSION 0,1,0,0 14 | PRODUCTVERSION 0,1,0,0 15 | FILEFLAGSMASK 0x3fL 16 | #ifdef _DEBUG 17 | FILEFLAGS 0x1L 18 | #else 19 | FILEFLAGS 0x0L 20 | #endif 21 | FILEOS 0x40004L 22 | FILETYPE 0x1L 23 | FILESUBTYPE 0x0L 24 | BEGIN 25 | BLOCK "StringFileInfo" 26 | BEGIN 27 | BLOCK "080904b0" 28 | BEGIN 29 | VALUE "CompanyName", "https://github.com/odin-lang/examples/" 30 | VALUE "FileDescription", "Game of Life" 31 | VALUE "FileVersion", "0.1.0.0" 32 | VALUE "InternalName", "game_of_life.exe" 33 | VALUE "LegalCopyright", "Copyright (c) 2024" 34 | VALUE "OriginalFilename", "game_of_life.exe" 35 | VALUE "ProductName", "Odin Examples - Game of Life" 36 | VALUE "ProductVersion", "0.1.0.0" 37 | VALUE "Comments", "This example shows a simple setup for a game with Input processing, updating game state and drawing game state to the screen using Win32." 38 | END 39 | END 40 | BLOCK "VarFileInfo" 41 | BEGIN 42 | VALUE "Translation", 0x809, 1200 43 | END 44 | END 45 | 46 | IDI_ICON1 ICON "..\\emblem.ico" 47 | -------------------------------------------------------------------------------- /wgpu/sdl3-triangle/os_sdl3.odin: -------------------------------------------------------------------------------- 1 | #+build !js 2 | package vendor_wgpu_example_triangle 3 | 4 | import "core:fmt" 5 | 6 | import "vendor:wgpu" 7 | import "vendor:wgpu/sdl3glue" 8 | import SDL "vendor:sdl3" 9 | 10 | OS :: struct { 11 | window: ^SDL.Window, 12 | } 13 | 14 | os_init :: proc() { 15 | if !SDL.Init({.VIDEO}) { 16 | fmt.panicf("SDL.Init error: ", SDL.GetError()) 17 | } 18 | 19 | state.os.window = SDL.CreateWindow("WGPU Native Triangle", 960, 540, {.RESIZABLE, .HIGH_PIXEL_DENSITY}) 20 | if state.os.window == nil { 21 | fmt.panicf("SDL.CreateWindow error: ", SDL.GetError()) 22 | } 23 | } 24 | 25 | os_run :: proc() { 26 | now := SDL.GetPerformanceCounter() 27 | last : u64 28 | dt: f32 29 | main_loop: for { 30 | last = now 31 | now = SDL.GetPerformanceCounter() 32 | dt = f32((now - last) * 1000) / f32(SDL.GetPerformanceFrequency()) 33 | 34 | e: SDL.Event 35 | for SDL.PollEvent(&e) { 36 | #partial switch (e.type) { 37 | case .QUIT: 38 | break main_loop 39 | case .WINDOW_RESIZED, .WINDOW_PIXEL_SIZE_CHANGED: 40 | resize() 41 | } 42 | } 43 | 44 | frame(dt) 45 | } 46 | 47 | finish() 48 | 49 | SDL.DestroyWindow(state.os.window) 50 | SDL.Quit() 51 | } 52 | 53 | 54 | os_get_framebuffer_size :: proc() -> (width, height: u32) { 55 | w, h: i32 56 | SDL.GetWindowSizeInPixels(state.os.window, &w, &h) 57 | return u32(w), u32(h) 58 | } 59 | 60 | os_get_surface :: proc(instance: wgpu.Instance) -> wgpu.Surface { 61 | return sdl3glue.GetSurface(instance, state.os.window) 62 | } 63 | -------------------------------------------------------------------------------- /arena_allocator/arena_allocator.odin: -------------------------------------------------------------------------------- 1 | package arena_allocator 2 | 3 | import "core:fmt" 4 | import "core:os" 5 | 6 | // virtual package implements a multi-purpose arena allocator. If you are on a 7 | // platform that does not support virtual memory, then there is also a similar 8 | // arena in `core:mem`. 9 | import vmem "core:mem/virtual" 10 | 11 | load_files :: proc() -> ([]string, vmem.Arena) { 12 | // This creates a growing virtual memory arena. It uses virtual memory and 13 | // can grow as things are added to it. 14 | arena: vmem.Arena 15 | arena_err := vmem.arena_init_growing(&arena) 16 | ensure(arena_err == nil) 17 | arena_alloc := vmem.arena_allocator(&arena) 18 | 19 | // See arena_init_static for an arena that uses virtual memory, but cannot grow. 20 | 21 | // See arena_init_buffer for an arena that does not use virtual memory, 22 | // instead it relies on you feeding it a buffer. 23 | 24 | f1, f1_ok := os.read_entire_file("file1.txt", arena_alloc) 25 | ensure(f1_ok) 26 | 27 | f2, f2_ok := os.read_entire_file("file2.txt", arena_alloc) 28 | ensure(f2_ok) 29 | 30 | f3, f3_ok := os.read_entire_file("file3.txt", arena_alloc) 31 | ensure(f3_ok) 32 | 33 | res := make([]string, 3, arena_alloc) 34 | res[0] = string(f1) 35 | res[1] = string(f2) 36 | res[2] = string(f3) 37 | 38 | return res, arena 39 | } 40 | 41 | main :: proc() { 42 | files, arena := load_files() 43 | 44 | for f in files { 45 | fmt.println(f) 46 | } 47 | 48 | // This deallocates everything that was allocated on the arena: 49 | // The loaded content of the files as well as the `files` slice. 50 | vmem.arena_destroy(&arena) 51 | } -------------------------------------------------------------------------------- /raylib/log/main.odin: -------------------------------------------------------------------------------- 1 | package raylib_example_log 2 | 3 | import "base:runtime" 4 | 5 | import "core:log" 6 | import "core:c" 7 | 8 | import rl "vendor:raylib" 9 | import stbsp "vendor:stb/sprintf" 10 | 11 | SCREEN_WIDTH :: 800 12 | SCREEN_HEIGHT :: 450 13 | 14 | g_ctx: runtime.Context 15 | 16 | main :: proc() { 17 | context.logger = log.create_console_logger(.Debug) 18 | g_ctx = context 19 | 20 | rl.SetTraceLogLevel(.ALL) 21 | rl.SetTraceLogCallback(proc "c" (rl_level: rl.TraceLogLevel, message: cstring, args: ^c.va_list) { 22 | context = g_ctx 23 | 24 | level: log.Level 25 | switch rl_level { 26 | case .TRACE, .DEBUG: level = .Debug 27 | case .INFO: level = .Info 28 | case .WARNING: level = .Warning 29 | case .ERROR: level = .Error 30 | case .FATAL: level = .Fatal 31 | case .ALL, .NONE: fallthrough 32 | case: log.panicf("unexpected log level %v", rl_level) 33 | } 34 | 35 | @static buf: [dynamic]byte 36 | log_len: i32 37 | for { 38 | buf_len := i32(len(buf)) 39 | log_len = stbsp.vsnprintf(raw_data(buf), buf_len, message, args) 40 | if log_len <= buf_len { 41 | break 42 | } 43 | 44 | non_zero_resize(&buf, max(128, len(buf)*2)) 45 | } 46 | 47 | context.logger.procedure(context.logger.data, level, string(buf[:log_len]), context.logger.options) 48 | }) 49 | 50 | rl.InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib log callback") 51 | defer rl.CloseWindow() 52 | 53 | for !rl.WindowShouldClose() { 54 | rl.BeginDrawing() 55 | rl.ClearBackground(rl.RAYWHITE) 56 | rl.EndDrawing() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /thread/basics/thread_basics.odin: -------------------------------------------------------------------------------- 1 | /* 2 | Shows how to start a thread and let it do some calculations while the main 3 | thead also does some calculations. 4 | */ 5 | 6 | package basic_thread_example 7 | 8 | import "core:thread" 9 | import "core:fmt" 10 | 11 | Thread_Data :: struct { 12 | // thread input: 13 | num_integers_to_sum: int, 14 | 15 | // thread output (don't touch until thread is done!): 16 | sum: int, 17 | } 18 | 19 | thread_proc :: proc(t: ^thread.Thread) { 20 | fmt.println("Thread starting") 21 | d := (^Thread_Data)(t.data) 22 | 23 | for i in 0..` to check if a value is bigger than another value. 15 | if some_number > 10 { 16 | fmt.printfln("some_number is %v, which is bigger than 10!", some_number) 17 | } 18 | 19 | // Unless you changed something in the example, then `some_number` will be 20 | // `210`. So the following call to `println` will not run! 21 | if some_number > 300 { 22 | fmt.println("some_number is bigger than 300!") 23 | } 24 | 25 | // This `>` thing is called a comparison operator. Odin has a bunch of 26 | // comparison operators. All of them result in a value of type `bool`, short 27 | // for 'boolean'. A bool can only have the value true or false. 28 | // 29 | // There's a list of all comparison operators here: 30 | // https://odin-lang.org/docs/overview/#comparison-operators 31 | // 32 | // You can assign the result of the comparison operator to a variable. Note 33 | // how we don't write any type: It's inferred to being of type `bool`: 34 | a_condition := some_number < 500 35 | 36 | // This will print. 37 | if a_condition { 38 | fmt.println("some_number is less than 500") 39 | } 40 | 41 | // Use ! to invert a boolean. This will not print anything. 42 | if !a_condition { 43 | fmt.println("some_number is equal to 500, or larger") 44 | } 45 | } -------------------------------------------------------------------------------- /code_generation/main.odin: -------------------------------------------------------------------------------- 1 | package image_viewer 2 | 3 | import "core:image" 4 | import "core:image/png" 5 | 6 | // Avoids 'unused import' error: "core:image/png" needs to be imported in order 7 | // to make `img.load_from_bytes` understand PNG format. 8 | _ :: png 9 | 10 | import "core:fmt" 11 | 12 | /* 13 | This program prints: 14 | 15 | Long_Cat is 9 x 46 pixels and 183 bytes large 16 | 17 | Round_Cat is 20 x 24 pixels and 317 bytes large 18 | Round_Cat has width > 15 we loaded it! 19 | It is indeed 20 pixels wide! 20 | 21 | Tuna is 24 x 20 pixels and 318 bytes large 22 | Tuna has width > 15 we loaded it! 23 | It is indeed 24 pixels wide! 24 | 25 | Note how it knows width and height before it loads the file. That was written 26 | into `images.odin` by the code generation program in the `generate_image_info` 27 | folder. It also knows the file size: `img.data` contains the data (i.e. the file 28 | contents) for that image. That data is put into the executable at compile time 29 | using the built-in `#load` procedure. The path of the image send into `#load` 30 | is written by the code generation program. 31 | */ 32 | main :: proc() { 33 | for &img, name in images { 34 | fmt.printfln("%v is %v x %v pixels and %v bytes large", name, img.width, img.height, len(img.data)) 35 | 36 | // Make decisions based pre-computed data before actually loading the image 37 | if img.width > 15 { 38 | loaded_img, loaded_img_err := image.load_from_bytes(img.data) 39 | 40 | if loaded_img_err == nil { 41 | fmt.printfln("%v has width > 15, so we loaded it!", name) 42 | fmt.printfln("The loaded PNG image is indeed %v pixels wide!", loaded_img.width) 43 | } 44 | } 45 | 46 | fmt.println() 47 | } 48 | } -------------------------------------------------------------------------------- /json/write_json_marshal/odin_info.odin: -------------------------------------------------------------------------------- 1 | /* 2 | Demonstrates how you can turn a struct into JSON and then write that JSON out 3 | to a file. 4 | */ 5 | package main 6 | 7 | import "base:builtin" 8 | import "base:runtime" 9 | import "core:encoding/json" 10 | import "core:fmt" 11 | import "core:os" 12 | 13 | main :: proc() { 14 | fmt.println("Some of Odin's builtin constants") 15 | path := len(os.args) > 1 ? os.args[1] : "odin_info.json" 16 | 17 | // This uses an "anonymous struct type". You could equally well do 18 | // 19 | // info := Odin_Info { ODIN_OS, ODIN_ARCH, ... } 20 | // 21 | // where you make a struct type `Odin_Info` that contains the same fields. 22 | info: struct { 23 | ODIN_OS: runtime.Odin_OS_Type, 24 | ODIN_ARCH: runtime.Odin_Arch_Type, 25 | ODIN_ENDIAN: runtime.Odin_Endian_Type, 26 | ODIN_VENDOR: string, 27 | ODIN_VERSION: string, 28 | ODIN_ROOT: string, 29 | ODIN_DEBUG: bool, 30 | } = {ODIN_OS, ODIN_ARCH, ODIN_ENDIAN, ODIN_VENDOR, ODIN_VERSION, ODIN_ROOT, ODIN_DEBUG} 31 | 32 | fmt.println("Odin:") 33 | fmt.printfln("%#v", info) 34 | 35 | json_data, err := json.marshal(info, { 36 | // Adds indentation etc 37 | pretty = true, 38 | 39 | // Output enum member names instead of numeric value. 40 | use_enum_names = true, 41 | }) 42 | 43 | if err != nil { 44 | fmt.eprintfln("Unable to marshal JSON: %v", err) 45 | os.exit(1) 46 | } 47 | 48 | fmt.println("JSON:") 49 | fmt.printfln("%s", json_data) 50 | fmt.printfln("Writing: %s", path) 51 | werr := os.write_entire_file_or_err(path, json_data) 52 | 53 | if werr != nil { 54 | fmt.eprintfln("Unable to write file: %v", werr) 55 | os.exit(1) 56 | } 57 | 58 | fmt.println("Done") 59 | } 60 | -------------------------------------------------------------------------------- /absolute_beginners/5_structs.odin: -------------------------------------------------------------------------------- 1 | package basics 2 | 3 | import "core:fmt" 4 | 5 | // This defines a new type that we can use in our code. A struct is essentially 6 | // like a group of several variables. You can send a struct into a procedure and 7 | // treat it like a single thing. That way you don't have to juggle a million 8 | // variables. Handy! 9 | Cat :: struct { 10 | // These are called the fields of the struct. The `name` field if of type 11 | // string, it can store text. Note how the fields look like variables, but 12 | // with a comma at the end. 13 | name: string, 14 | age: int, 15 | } 16 | 17 | // This procedure returns a whole struct! 18 | structs :: proc() -> Cat { 19 | // This makes a new variable of type `Cat`. Since we don't provide a value, 20 | // it is zero-initialized. This means that the `name` and the `age` fields 21 | // are all zeroed. 22 | cat1: Cat 23 | 24 | // This prints the whole struct! Note how the age is zero and the name is 25 | // "" (empty string) 26 | fmt.println(cat1) // Cat{name = "", age = 0} 27 | 28 | // Let's give cat1 a name and an age: 29 | cat1.name = "Pontus" 30 | cat1.age = 7 31 | 32 | fmt.println(cat1) // Cat{name = "Pontus", age = 7} 33 | 34 | // Just like with other types, you can create and initialize a type on a 35 | // single line: 36 | cat2 := Cat { 37 | name = "Klucke", 38 | age = 5, 39 | } 40 | 41 | fmt.println(cat2) // Cat{name = "Klucke", age = 5} 42 | 43 | // You can re-initialize a struct by assigning to it (note: We only use `=`, 44 | // not `:=`): 45 | 46 | cat1 = { 47 | name = "Tom", 48 | age = 23, 49 | } 50 | 51 | fmt.println(cat1) // Cat{name = "Tom", age = 23} 52 | 53 | // Let's return the whole `cat2` struct! 54 | return cat2 55 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Odin Examples 2 | 3 | Learn [Odin](https://github.com/odin-lang/Odin) through idiomatic examples that show you how to: 4 | - Use the language 5 | - Use `core` libraries 6 | - Use `vendor` libraries 7 | 8 | The examples are meant to be well written while following Odin best practices. 9 | 10 | Also check out [demo.odin](https://github.com/odin-lang/Odin/blob/master/examples/demo/demo.odin) and the [overview](https://odin-lang.org/docs/overview/). 11 | 12 | ## Running the examples 13 | 14 | Clone this repository. Most examples can be run by navigating into the folder and executing: `odin run .` 15 | 16 | Some examples have a `README` with additional information and instructions. 17 | 18 | ## License 19 | The contents of this repository is available under two licenses. Choose the one that you prefer: 20 | 21 | - [Public Domain](https://unlicense.org) 22 | or 23 | - [Odin's BSD-3 license](https://github.com/odin-lang/Odin/blob/master/LICENSE) 24 | 25 | Assets and third-party libraries are provided under their own license. If in doubt, check the `LICENSE*` and `COPYING*` file(s) in a particular directory for clarification. 26 | 27 | ## Example suggestions 28 | Add example suggestions [here](https://github.com/odin-lang/examples/issues/73). 29 | 30 | ## Contributions 31 | Contributions via Pull Requests are warmly welcome. Before submitting your Pull Request, make sure of the following: 32 | 33 | - The example compiles with flags `-vet -strict-style -vet-tabs -disallow-do -warnings-as-errors` 34 | - Add the example to `.github/workflows/check.yml` 35 | - Your code follows the Odin naming convention: https://github.com/odin-lang/Odin/wiki/Naming-Convention (exception can be made for direct ports of examples that need to match 1:1 to the source of the port). 36 | - Note that your code will fall under the licenses listed above. Only for third-party dependencies are other licenses allowed. 37 | -------------------------------------------------------------------------------- /dir_info/main.odin: -------------------------------------------------------------------------------- 1 | /* 2 | How to get information about a directory, including which files and directories 3 | it contains. 4 | */ 5 | package dir_info 6 | 7 | import "core:fmt" 8 | import "core:os" 9 | import "core:path/filepath" 10 | 11 | main :: proc() { 12 | cwd := os.get_current_directory() 13 | 14 | // Swap `cwd` for some other string to change which folder you're looking at 15 | f, err := os.open(cwd) 16 | 17 | defer os.close(f) 18 | 19 | if err != os.ERROR_NONE { 20 | fmt.eprintln("Could not open directory for reading", err) 21 | os.exit(1) 22 | } 23 | 24 | /* 25 | File_Info :: struct { 26 | fullpath: string, // allocated 27 | name: string, // uses `fullpath` as underlying data 28 | size: i64, 29 | mode: File_Mode, 30 | is_dir: bool, 31 | creation_time: time.Time, 32 | modification_time: time.Time, 33 | access_time: time.Time, 34 | } 35 | 36 | (from /core/os/stat.odin) 37 | */ 38 | fis: []os.File_Info 39 | 40 | /* 41 | This will deallocate `fis` at the end of this scope. 42 | 43 | It's not allocated yet, but `fis` is assigned a return value from 44 | `os.read_dir`. That's a dynamically allocated slice. 45 | 46 | It doesn't matter that `fis` hasn't been assigned yet: `defer` will fetch 47 | the variable `fis` at the end of this scope. It does not fetch the value of 48 | that variable now. 49 | 50 | Note that each `File_Info` contains an allocated `fullpath` field. That's 51 | why this uses `os.file_info_slice_delete(fis)` instead of `delete(fis)`: 52 | It needs to go through the slice and deallocate those strings. 53 | */ 54 | defer os.file_info_slice_delete(fis) 55 | 56 | fis, err = os.read_dir(f, -1) // -1 reads all file infos 57 | if err != os.ERROR_NONE { 58 | fmt.eprintln("Could not read directory", err) 59 | os.exit(2) 60 | } 61 | 62 | fmt.printfln("Current working directory %v contains:", cwd) 63 | 64 | for fi in fis { 65 | _, name := filepath.split(fi.fullpath) 66 | 67 | if fi.is_dir { 68 | fmt.printfln("%v (directory)", name) 69 | } else { 70 | fmt.printfln("%v (%v bytes)", name, fi.size) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /absolute_beginners/3_loops.odin: -------------------------------------------------------------------------------- 1 | package basics 2 | 3 | import "core:fmt" 4 | 5 | // This procedure has a parameter. Note the `(n: int)` just after `:: proc`. 6 | // 7 | // When `main` called this procedure it supplied the value `21` as a procedure 8 | // argument. That argument will be available within the procedure parameter `n`. 9 | // 10 | // Note how `n: int` looks like a variable declaration! `n` is used near the end 11 | // of the procdure. 12 | // 13 | // Also note something else: It says `-> int` on the next line. This means that 14 | // this procedure will return an integer number back to the whoever ran it. 15 | loops :: proc(n: int) -> int { 16 | fmt.println(n) // prints "21" because it says `loops(21)` in `1_main.odin`. 17 | 18 | // Let's make a loop that runs 5 times! You can do that in several ways. 19 | 20 | // This loops from 0 to 5 and for each lap of the loop the number is 21 | // availble in the loop variable `i`. 22 | for i in 0..<5 { 23 | fmt.println(i) // 0, 1, 2, 3, 4 24 | } 25 | 26 | // Same thing, but different kind of loop: 27 | for i := 0; i < 5; i += 1 { 28 | fmt.println(i) // 0, 1, 2, 3, 4 29 | } 30 | 31 | // This loop lives inside some extra curly braces. That makes `i` not exist 32 | // outside those curly braces. Handy, so I don't get collisions with other 33 | // variables called `i` later in this procedure! 34 | { 35 | // This looks like the previous loop, but I've moved out the `i := 0` 36 | // and I put the `i += 1` inside the loop. It has the same effect. 37 | i := 0 38 | for i < 5 { 39 | fmt.println(i) // 0, 1, 2, 3, 4 40 | i += 1 41 | } 42 | } 43 | 44 | // Note how all the loops above use the word `for`. All loops in Odin use 45 | // `for`. There is no `while` or `foreach` keyword like in some languages. 46 | 47 | // We can use the procedure parameter `n` to loop that many times. 48 | res := 0 49 | 50 | for i in 0.. %v", i, prev_state, cur_state) 26 | } 27 | 28 | for i in 1..=10 { 29 | prev_state = cur_state 30 | cur_state = next_state_equal() 31 | fmt.printfln("Equal weight state transition %v: %v -> %v", i, prev_state, cur_state) 32 | } 33 | 34 | for s, i in state_list(10) { 35 | prev_state = cur_state 36 | cur_state = s 37 | fmt.printfln("List state transition: %v: %v -> %v", i, prev_state, cur_state) 38 | } 39 | } 40 | 41 | // Using transition matrix 42 | next_state :: proc(cur_state: State) -> State { 43 | chance := rand.float64() 44 | accumulate: f64 45 | 46 | for s in State { 47 | accumulate += Transition_Matrix[cur_state][s] 48 | 49 | if chance < accumulate { 50 | return s 51 | } 52 | } 53 | 54 | return cur_state 55 | } 56 | 57 | // Equal weighting 58 | next_state_equal :: proc() -> State { 59 | return rand.choice_enum(State) 60 | } 61 | 62 | // A list of equally weighted transitions 63 | state_list :: proc(size: int) -> []State { 64 | seq := make([]State, size) 65 | 66 | for i in 0.. (light: Light) { 30 | if lightsCount < MAX_LIGHTS { 31 | light.enabled = true 32 | light.type = type 33 | light.position = position 34 | light.target = target 35 | light.color = color 36 | 37 | light.enabledLoc = i32(rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].enabled", lightsCount))) 38 | light.typeLoc = i32(rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].type", lightsCount))) 39 | light.positionLoc = i32(rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].position", lightsCount))) 40 | light.targetLoc = i32(rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].target", lightsCount))) 41 | light.colorLoc = i32(rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].color", lightsCount))) 42 | 43 | UpdateLightValues(shader, light) 44 | 45 | lightsCount += 1 46 | } 47 | 48 | return 49 | } 50 | 51 | UpdateLightValues :: proc(shader: rl.Shader, light: Light) { 52 | light := light 53 | 54 | rl.SetShaderValue(shader, rl.ShaderLocationIndex(light.enabledLoc), &light.enabled, .INT) 55 | rl.SetShaderValue(shader, rl.ShaderLocationIndex(light.typeLoc), &light.type, .INT) 56 | 57 | rl.SetShaderValue(shader, rl.ShaderLocationIndex(light.positionLoc), &light.position, .VEC3) 58 | 59 | rl.SetShaderValue(shader, rl.ShaderLocationIndex(light.targetLoc), &light.target, .VEC3) 60 | 61 | color := [4]f32{ f32(light.color.r)/255, f32(light.color.g)/255, f32(light.color.b)/255, f32(light.color.a)/255 } 62 | rl.SetShaderValue(shader, rl.ShaderLocationIndex(light.colorLoc), &color, .VEC4) 63 | } 64 | -------------------------------------------------------------------------------- /console/raw_console/main.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "core:fmt" 4 | import "core:io" 5 | import "core:os" 6 | import "core:time" 7 | import "core:unicode/utf8" 8 | 9 | get_password :: proc(allocator := context.allocator) -> string { 10 | enable_raw_mode() 11 | defer disable_raw_mode() 12 | 13 | fmt.print("Enter password: ") 14 | 15 | buf := make([dynamic]byte, allocator) 16 | in_stream := os.stream_from_handle(os.stdin) 17 | 18 | for { 19 | // Read a single character at a time. 20 | ch, sz, err := io.read_rune(in_stream) 21 | switch { 22 | case err != nil: 23 | fmt.eprintfln("\nError: %v", err) 24 | os.exit(1) 25 | 26 | // End line 27 | case ch == '\n': // Posix 28 | fallthrough 29 | case ch == '\r': // Windows 30 | fmt.println() 31 | return string(buf[:]) 32 | 33 | // Backspace 34 | case ch == '\u007f': // Posix 35 | fallthrough 36 | case ch == '\b': // Windows 37 | _, bs_sz := utf8.decode_last_rune(buf[:]) 38 | if bs_sz > 0 { 39 | resize(&buf, len(buf)-bs_sz) 40 | // Replace last star with a space. 41 | fmt.print("\b \b") 42 | } 43 | case: 44 | bytes, _ := utf8.encode_rune(ch) 45 | append(&buf, ..bytes[:sz]) 46 | 47 | fmt.print('*') 48 | } 49 | } 50 | } 51 | 52 | draw_progress_bar :: proc(title: string, percent: int, width := 25) { 53 | fmt.printf("\r%v[", title, flush=false) // Put cursor back at the start of the line 54 | 55 | done := percent * width / 100 56 | left := width - done 57 | for _ in 0.. 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine 67 | specular += specCo; 68 | } 69 | } 70 | 71 | finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); 72 | finalColor += texelColor*(ambient/10.0)*colDiffuse; 73 | 74 | // Gamma correction 75 | finalColor = pow(finalColor, vec4(1.0/2.2)); 76 | } 77 | -------------------------------------------------------------------------------- /code_generation/generate_image_info/generate_image_info.odin: -------------------------------------------------------------------------------- 1 | /* 2 | This program generates `images.odin` by going through the `images` folder and 3 | opening each file. From each PNG file in there it will: 4 | 5 | - Generate a pretty enum name for it 6 | - Make a list of images where it maps each pretty enum name to an Image struct 7 | - The Image struct contains the width and the height. This is determined by 8 | opening the PNG files. 9 | - The Image struct also contains a `data = #load(THE_FILENAME)` field. That will 10 | make the compiler that later tries to compile `images.odin` load the file 11 | data at compile-time. 12 | */ 13 | package generate_image_info 14 | 15 | import "core:os" 16 | import "core:strings" 17 | import "core:fmt" 18 | import "core:path/slashpath" 19 | import "core:image/png" 20 | import "core:image" 21 | 22 | // Avoids 'unused import' error: "core:image/png" needs to be imported in order 23 | // to make `img.load_from_bytes` understand PNG format. 24 | _ :: png 25 | 26 | INPUT_DIR :: "images" 27 | OUTPUT_FILE :: "images.odin" 28 | 29 | main :: proc() { 30 | d, d_err := os.open(INPUT_DIR, os.O_RDONLY) 31 | assert(d_err == nil, "Failed opening '" + INPUT_DIR + "' folder") 32 | defer os.close(d) 33 | 34 | input_files, _ := os.read_dir(d, -1) 35 | 36 | f, _ := os.open(OUTPUT_FILE, os.O_WRONLY | os.O_CREATE | os.O_TRUNC) 37 | defer os.close(f) 38 | 39 | images: [dynamic]os.File_Info 40 | 41 | for i in input_files { 42 | if !strings.has_suffix(i.name, ".png") { 43 | continue 44 | } 45 | 46 | append(&images, i) 47 | } 48 | 49 | fmt.fprintln(f, 50 | `// This file is generated. Re-generate it by running: 51 | // odin run generate_image_info 52 | package image_viewer 53 | 54 | Image :: struct { 55 | width: int, 56 | height: int, 57 | data: []u8, 58 | } 59 | 60 | Image_Name :: enum {`, 61 | ) 62 | 63 | for i in images { 64 | fmt.fprintfln(f, " %v,", strings.to_ada_case(slashpath.name(i.name))) 65 | } 66 | 67 | fmt.fprintln(f, 68 | `} 69 | 70 | images := [Image_Name]Image {`, 71 | ) 72 | 73 | for i in images { 74 | img, img_err := image.load_from_file(i.fullpath) 75 | 76 | if img_err == nil { 77 | enum_name := strings.to_ada_case(slashpath.name(i.name)) 78 | fmt.fprintfln(f, " .%v = {{ data = #load(\"images/%v\"), width = %v, height = %v }},", enum_name, i.name, img.width, img.height) 79 | } 80 | } 81 | 82 | fmt.fprintln(f, "}") 83 | } -------------------------------------------------------------------------------- /net/tcp_echo_server/server/server.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "core:fmt" 4 | import "core:net" 5 | import "core:thread" 6 | 7 | is_ctrl_d :: proc(bytes: []u8) -> bool { 8 | return len(bytes) == 1 && bytes[0] == 4 9 | } 10 | 11 | is_empty :: proc(bytes: []u8) -> bool { 12 | return( 13 | (len(bytes) == 2 && bytes[0] == '\r' && bytes[1] == '\n') || 14 | (len(bytes) == 1 && bytes[0] == '\n') \ 15 | ) 16 | } 17 | 18 | is_telnet_ctrl_c :: proc(bytes: []u8) -> bool { 19 | return( 20 | (len(bytes) == 3 && bytes[0] == 255 && bytes[1] == 251 && bytes[2] == 6) || 21 | (len(bytes) == 5 && 22 | bytes[0] == 255 && 23 | bytes[1] == 244 && 24 | bytes[2] == 255 && 25 | bytes[3] == 253 && 26 | bytes[4] == 6) \ 27 | ) 28 | } 29 | 30 | handle_msg :: proc(sock: net.TCP_Socket) { 31 | buffer: [256]u8 32 | for { 33 | bytes_recv, err_recv := net.recv_tcp(sock, buffer[:]) 34 | if err_recv != nil { 35 | fmt.println("Failed to receive data") 36 | } 37 | received := buffer[:bytes_recv] 38 | if len(received) == 0 || 39 | is_ctrl_d(received) || 40 | is_empty(received) || 41 | is_telnet_ctrl_c(received) { 42 | fmt.println("Disconnecting client") 43 | break 44 | } 45 | fmt.printfln("Server received [ %d bytes ]: %s", len(received), received) 46 | bytes_sent, err_send := net.send_tcp(sock, received) 47 | if err_send != nil { 48 | fmt.println("Failed to send data") 49 | } 50 | sent := received[:bytes_sent] 51 | fmt.printfln("Server sent [ %d bytes ]: %s", len(sent), sent) 52 | } 53 | net.close(sock) 54 | } 55 | 56 | tcp_echo_server :: proc(ip: string, port: int) { 57 | local_addr, ok := net.parse_ip4_address(ip) 58 | if !ok { 59 | fmt.println("Failed to parse IP address") 60 | return 61 | } 62 | endpoint := net.Endpoint { 63 | address = local_addr, 64 | port = port, 65 | } 66 | sock, err := net.listen_tcp(endpoint) 67 | if err != nil { 68 | fmt.println("Failed to listen on TCP") 69 | return 70 | } 71 | fmt.printfln("Listening on TCP: %s", net.endpoint_to_string(endpoint)) 72 | for { 73 | cli, _, err_accept := net.accept_tcp(sock) 74 | if err_accept != nil { 75 | fmt.println("Failed to accept TCP connection") 76 | } 77 | thread.create_and_start_with_poly_data(cli, handle_msg) 78 | } 79 | net.close(sock) 80 | fmt.println("Closed socket") 81 | } 82 | 83 | main :: proc() { 84 | tcp_echo_server("127.0.0.1", 8080) 85 | } 86 | -------------------------------------------------------------------------------- /raylib/ports/textures/textures_gif_player.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import rl "vendor:raylib" 4 | 5 | MAX_FRAME_DELAY :: 20 6 | MIN_FRAME_DELAY :: 1 7 | 8 | main :: proc() { 9 | screen_width := i32(800) 10 | screen_height := i32(450) 11 | 12 | rl.InitWindow(screen_width, screen_height, "raylib [textures] example - gif playing") 13 | defer rl.CloseWindow() 14 | 15 | anim_frames: i32 16 | im_scarfy_anim := rl.LoadImageAnim("resources/scarfy_run.gif", &anim_frames) 17 | defer rl.UnloadImage(im_scarfy_anim) 18 | 19 | tex_scarfy_anim := rl.LoadTextureFromImage(im_scarfy_anim) 20 | defer rl.UnloadTexture(tex_scarfy_anim) 21 | 22 | next_frame_data_offset, current_anim_frame, frame_counter: i32 23 | frame_delay := i32(MAX_FRAME_DELAY/2) 24 | 25 | rl.SetTargetFPS(60) 26 | 27 | for !rl.WindowShouldClose() { 28 | frame_counter += 1 29 | if frame_counter >= frame_delay { 30 | current_anim_frame = (current_anim_frame + 1) % anim_frames 31 | 32 | next_frame_data_offset = im_scarfy_anim.width * im_scarfy_anim.height * 4 * current_anim_frame 33 | 34 | rl.UpdateTexture(tex_scarfy_anim, ([^]byte)(im_scarfy_anim.data)[next_frame_data_offset:]) 35 | 36 | frame_counter = 0 37 | } 38 | 39 | if rl.IsKeyPressed(.RIGHT) { 40 | frame_delay = min(frame_delay + 1, MAX_FRAME_DELAY) 41 | } else if rl.IsKeyPressed(.LEFT) { 42 | frame_delay = max(frame_delay - 1, MIN_FRAME_DELAY) 43 | } 44 | 45 | { 46 | rl.BeginDrawing() 47 | defer rl.EndDrawing() 48 | 49 | rl.ClearBackground(rl.RAYWHITE) 50 | 51 | rl.DrawText(rl.TextFormat("TOTAL GIF FRAMES: %02i", anim_frames), 50, 30, 20, rl.LIGHTGRAY) 52 | rl.DrawText(rl.TextFormat("CURRENT FRAME: %02i", current_anim_frame), 50, 60, 20, rl.GRAY) 53 | rl.DrawText(rl.TextFormat("CURRENT FRAME IMAGE.DATA OFFSET: %02i", next_frame_data_offset), 50, 90, 20, rl.GRAY) 54 | 55 | rl.DrawText("FRAMES DELAY: ", 100, 305, 10, rl.DARKGRAY) 56 | rl.DrawText(rl.TextFormat("%02i frames", frame_delay), 620, 305, 10, rl.DARKGRAY) 57 | rl.DrawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 350, 10, rl.DARKGRAY) 58 | 59 | for i in i32(0).. (err: ^NS.Error) { 13 | SDL.SetHint(SDL.HINT_RENDER_DRIVER, "metal") 14 | SDL.setenv("METAL_DEVICE_WRAPPER_TYPE", "1", 0) 15 | SDL.Init({.VIDEO}) 16 | defer SDL.Quit() 17 | 18 | window := SDL.CreateWindow("Metal in Odin - 00 window", 19 | SDL.WINDOWPOS_CENTERED, SDL.WINDOWPOS_CENTERED, 20 | 854, 480, 21 | {.ALLOW_HIGHDPI, .HIDDEN, .RESIZABLE}, 22 | ) 23 | defer SDL.DestroyWindow(window) 24 | 25 | window_system_info: SDL.SysWMinfo 26 | SDL.GetVersion(&window_system_info.version) 27 | SDL.GetWindowWMInfo(window, &window_system_info) 28 | assert(window_system_info.subsystem == .COCOA) 29 | 30 | native_window := (^NS.Window)(window_system_info.info.cocoa.window) 31 | 32 | device := MTL.CreateSystemDefaultDevice() 33 | defer device->release() 34 | 35 | fmt.println(device->name()->odinString()) 36 | 37 | swapchain := CA.MetalLayer.layer() 38 | defer swapchain->release() 39 | 40 | swapchain->setDevice(device) 41 | swapchain->setPixelFormat(.BGRA8Unorm_sRGB) 42 | swapchain->setFramebufferOnly(true) 43 | swapchain->setFrame(native_window->frame()) 44 | 45 | native_window->contentView()->setLayer(swapchain) 46 | native_window->setOpaque(true) 47 | native_window->setBackgroundColor(nil) 48 | 49 | command_queue := device->newCommandQueue() 50 | defer command_queue->release() 51 | 52 | SDL.ShowWindow(window) 53 | for quit := false; !quit; { 54 | for e: SDL.Event; SDL.PollEvent(&e); { 55 | #partial switch e.type { 56 | case .QUIT: 57 | quit = true 58 | case .KEYDOWN: 59 | if e.key.keysym.sym == .ESCAPE { 60 | quit = true 61 | } 62 | } 63 | } 64 | 65 | 66 | drawable := swapchain->nextDrawable() 67 | assert(drawable != nil) 68 | defer drawable->release() 69 | 70 | pass := MTL.RenderPassDescriptor.renderPassDescriptor() 71 | defer pass->release() 72 | 73 | color_attachment := pass->colorAttachments()->object(0) 74 | assert(color_attachment != nil) 75 | color_attachment->setClearColor(MTL.ClearColor{0.25, 0.5, 1.0, 1.0}) 76 | color_attachment->setLoadAction(.Clear) 77 | color_attachment->setStoreAction(.Store) 78 | color_attachment->setTexture(drawable->texture()) 79 | 80 | 81 | command_buffer := command_queue->commandBuffer() 82 | defer command_buffer->release() 83 | 84 | render_encoder := command_buffer->renderCommandEncoderWithDescriptor(pass) 85 | defer render_encoder->release() 86 | 87 | render_encoder->endEncoding() 88 | 89 | command_buffer->presentDrawable(drawable) 90 | command_buffer->commit() 91 | } 92 | 93 | return nil 94 | } 95 | 96 | main :: proc() { 97 | err := metal_main() 98 | if err != nil { 99 | fmt.eprintln(err->localizedDescription()->odinString()) 100 | os.exit(1) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /metal/minimal_sdl2/objc_metal_with_sdl.odin: -------------------------------------------------------------------------------- 1 | package objc_test 2 | 3 | import NS "core:sys/darwin/Foundation" 4 | import MTL "vendor:darwin/Metal" 5 | import CA "vendor:darwin/QuartzCore" 6 | 7 | import SDL "vendor:sdl2" 8 | 9 | import "core:fmt" 10 | 11 | main :: proc() { 12 | SDL.SetHint(SDL.HINT_RENDER_DRIVER, "metal") 13 | SDL.setenv("METAL_DEVICE_WRAPPER_TYPE", "1", 0) 14 | SDL.Init({.VIDEO}) 15 | defer SDL.Quit() 16 | 17 | window := SDL.CreateWindow("SDL Metal", 18 | SDL.WINDOWPOS_CENTERED, SDL.WINDOWPOS_CENTERED, 19 | 854, 480, 20 | SDL.WINDOW_ALLOW_HIGHDPI|SDL.WINDOW_HIDDEN, 21 | ) 22 | defer SDL.DestroyWindow(window) 23 | 24 | window_system_info: SDL.SysWMinfo 25 | SDL.GetVersion(&window_system_info.version) 26 | SDL.GetWindowWMInfo(window, &window_system_info) 27 | assert(window_system_info.subsystem == .COCOA) 28 | fmt.println(window_system_info) 29 | 30 | swapchain: ^CA.MetalLayer 31 | device: ^MTL.Device 32 | when true { 33 | native_window := (^NS.Window)(window_system_info.info.cocoa.window) 34 | 35 | device = MTL.CreateSystemDefaultDevice() 36 | 37 | name := device->name()->odinString() 38 | fmt.println(name) 39 | 40 | swapchain = CA.MetalLayer.layer() 41 | swapchain->setDevice(device) 42 | swapchain->setPixelFormat(.BGRA8Unorm_sRGB) 43 | swapchain->setFramebufferOnly(true) 44 | swapchain->setFrame(native_window->frame()) 45 | 46 | // native_window->addSublayer(swapchain) 47 | native_window->contentView()->setLayer(swapchain) 48 | native_window->setOpaque(true) 49 | native_window->setBackgroundColor(nil) 50 | } else { 51 | renderer := SDL.CreateRenderer(window, -1, SDL.RENDERER_PRESENTVSYNC) 52 | defer SDL.DestroyRenderer(renderer) 53 | 54 | swapchain = (^CA.MetalLayer)(SDL.RenderGetMetalLayer(renderer)) 55 | device = swapchain->device() 56 | } 57 | 58 | command_queue := device->newCommandQueue() 59 | 60 | SDL.ShowWindow(window) 61 | 62 | color := MTL.ClearColor{0.5, 0.7, 1.0, 1.0} 63 | 64 | quit := false 65 | 66 | for !quit { 67 | for e: SDL.Event; SDL.PollEvent(&e); { 68 | #partial switch e.type { 69 | case .QUIT: quit = true 70 | case .KEYDOWN: 71 | if e.key.keysym.sym == .ESCAPE { 72 | quit = true 73 | } 74 | } 75 | } 76 | 77 | NS.scoped_autoreleasepool() 78 | 79 | drawable := swapchain->nextDrawable() 80 | assert(drawable != nil) 81 | 82 | pass := MTL.RenderPassDescriptor.renderPassDescriptor() 83 | color_attachment := pass->colorAttachments()->object(0) 84 | assert(color_attachment != nil) 85 | color_attachment->setClearColor(color) 86 | color_attachment->setLoadAction(.Clear) 87 | color_attachment->setStoreAction(.Store) 88 | color_attachment->setTexture(drawable->texture()) 89 | 90 | 91 | command_buffer := command_queue->commandBuffer() 92 | encoder := command_buffer->renderCommandEncoderWithDescriptor(pass) 93 | // ... 94 | encoder->endEncoding() 95 | 96 | command_buffer->presentDrawable(drawable) 97 | command_buffer->commit() 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /raylib/ports/shapes/shapes_bouncing_ball.odin: -------------------------------------------------------------------------------- 1 | package raylib_examples 2 | 3 | /******************************************************************************************* 4 | * 5 | * raylib [shapes] example - bouncing ball 6 | * 7 | * This example was originally created in C with raylib 2.5 before being translated to Odin. 8 | * 9 | * The original example in C can be found on raylib.com at: 10 | * 11 | * https://www.raylib.com/examples/shapes/loader.html?name=shapes_bouncing_ball 12 | * 13 | * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, 14 | * BSD-like license that allows static linking with closed source software. The license 15 | * can be found in its entirety as part of the standard Odin distribution at: 16 | * 17 | * /vendor/raylib/LICENSE 18 | * 19 | * or online at: 20 | * 21 | * https://www.raylib.com/license.html 22 | * 23 | * This example is licensed under an unmodified zlib/libpng license, which is an 24 | * OSI-certified, BSD-like license that allows static linking with closed source software. 25 | * 26 | * Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) 27 | * Copyright (c) 2023 Benjamin G. Thompson (@bg-thompson) 28 | * 29 | ********************************************************************************************/ 30 | 31 | import rl "vendor:raylib" 32 | 33 | SCREEN_WIDTH :: 800 34 | SCREEN_HEIGHT :: 450 35 | 36 | main :: proc() { 37 | rl.SetConfigFlags(rl.ConfigFlags{.MSAA_4X_HINT}) // Try to enable MSAA 4X. 38 | rl.InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [shapes] example - bouncing ball") 39 | defer rl.CloseWindow() // Close window and OpenGL context when leaving main. 40 | 41 | // Ball position, velocity, radius, and color. 42 | ball_pos := rl.Vector2{f32(rl.GetScreenWidth() / 2), f32(rl.GetScreenHeight() / 2)} 43 | ball_vel := rl.Vector2{5,4} 44 | ball_rad :: 20 45 | ball_color :: rl.MAROON 46 | 47 | pause := true 48 | framesCounter := 0 49 | rl.SetTargetFPS(60) // Set frames-per-second. 50 | 51 | // The primary loop. 52 | for !rl.WindowShouldClose() { // Detect window close button or ESC key press. 53 | if rl.IsKeyPressed(rl.KeyboardKey.SPACE) { 54 | pause = ! pause 55 | } 56 | if ! pause { 57 | ball_pos.x += ball_vel.x 58 | ball_pos.y += ball_vel.y 59 | 60 | // Check walls collision for bouncing. 61 | if ball_pos.x >= f32(rl.GetScreenWidth() - ball_rad) || ball_pos.x <= ball_rad { 62 | ball_vel.x *= -1 63 | } 64 | if ball_pos.y >= f32(rl.GetScreenHeight() - ball_rad) || ball_pos.y <= ball_rad { 65 | ball_vel.y *= -1 66 | } 67 | } else { 68 | framesCounter += 1 69 | } 70 | 71 | // Start drawing. 72 | rl.BeginDrawing() 73 | 74 | rl.ClearBackground(rl.RAYWHITE) 75 | rl.DrawCircleV(ball_pos, ball_rad, ball_color) 76 | rl.DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, rl.GetScreenHeight() - 25, 20, rl.LIGHTGRAY) 77 | rl.DrawFPS(10, 10) 78 | 79 | // On pause, we draw a blinking message 80 | if pause && (framesCounter / 30) % 2 != 0 { 81 | rl.DrawText("PAUSED", 350, 200, 30, rl.GRAY) 82 | } 83 | 84 | rl.EndDrawing() 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /absolute_beginners/1_main.odin: -------------------------------------------------------------------------------- 1 | // This example shows a few basic Odin features. It's targeted at people with 2 | // very little programming experience. 3 | 4 | // When you ran `odin run .`, then all the `.odin` files in this folder were 5 | // compiled into a single package. That package was turned into an executable 6 | // and then started. 7 | 8 | // This is the package name. All files in a package must use the same package 9 | // name. The package name must be unique project-wide (no other imported package 10 | // may use the same name). 11 | package basics 12 | 13 | // This imports the `fmt` package from the core collection. You find the core 14 | // collection in `/core`, where `` is the folder where you installed 15 | // Odin. `fmt` is just a subfolder of `core`. Again, packages are just folders! 16 | import "core:fmt" 17 | 18 | // This is a procedure. A procedure contains code that can be executed. This 19 | // procedure is special: By default, the program starts in the procedure called 20 | // `main`. 21 | main :: proc() { 22 | // The `fmt.println` procedure is part of the `core:fmt` package. It prints 23 | // text to the "standard output stream", which could mean: 24 | // - Terminal 25 | // - Command prompt 26 | // - Code editor output window 27 | fmt.println("Hellope!") // Prints "Hellope!" to the console 28 | 29 | // This runs another procedure called `variables`. But there is no such 30 | // procedure in this file! Where is it? All files within this folder are 31 | // part of the same package. So this procedure can be in any of the `.odin` 32 | // files in this folder. In this case it is in `2_variables.odin`. Open that 33 | // one to see what it does! 34 | variables() 35 | 36 | // When the `variables` procedure finishes running, then the program will 37 | // continue with the next line. This runs a procedure called `loops`. Note 38 | // that we feed the value `21` into it. You'll find `loops` in `3_loops.odin`. 39 | loops_result := loops(21) 40 | 41 | // `loops` returned a value. We've put that in a new variable called 42 | // `loops_result`. We can send that value into the next procedure: 43 | // `if_statements`. You'll find that procedure in (you guessed it!) 44 | // `4_if_statements.odin`. 45 | if_statements(loops_result) 46 | 47 | // Let's move on and read about what structs are! Continue in `5_structs.odin` 48 | cat := structs() 49 | 50 | // That procedure returned a whole struct of type `Cat`! We can print the 51 | // contents of it: 52 | fmt.println(cat) // Cat{name = "Klucke", age = 5} 53 | 54 | // We are nearing the end of this program. Let's finish with looking at what 55 | // pointers are. Note how we write `&cat` when running the `pointers` 56 | // procedure. That fetches the memory address of `cat` and sends it into the 57 | // `pointers` procedure. More about that in `6_pointers.odin`! 58 | pointers(&cat) 59 | 60 | // `pointers` modified the age of `cat` from `5` to `11`. It did so by 61 | // writing to the age field through the pointer we sent into `pointers`. 62 | fmt.println(cat) // Cat{name = "Klucke", age = 11} 63 | 64 | // One note before we end: This example is split into a bunch of files, with 65 | // just a single procedure in each. Usually you'll have much bigger files 66 | // in Odin, where each file has lots of procedures, structs and all that. 67 | 68 | // That's it for this example! There is A LOT more to discover. Have a look 69 | // at the resources available here: https://odin-lang.org/docs/ 70 | } -------------------------------------------------------------------------------- /raylib/ports/shapes/shapes_basic_shapes.odin: -------------------------------------------------------------------------------- 1 | package raylib_examples 2 | 3 | /******************************************************************************************* 4 | * 5 | * raylib [shapes] example - Draw basic shapes 2d (rectangle, circle, line...) 6 | * 7 | * This example was originally created in C with raylib 1.0, and updated with raylib 4.2 8 | * before being translated to Odin. 9 | * 10 | * The original example in C can be found on raylib.com at: 11 | * 12 | * https://www.raylib.com/examples/shapes/loader.html?name=shapes_basic_shapes 13 | * 14 | * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, 15 | * BSD-like license that allows static linking with closed source software. The license 16 | * can be found in its entirety as part of the standard Odin distribution at: 17 | * 18 | * /vendor/raylib/LICENSE 19 | * 20 | * or online at: 21 | * 22 | * https://www.raylib.com/license.html 23 | * 24 | * This example is licensed under an unmodified zlib/libpng license, which is an 25 | * OSI-certified, BSD-like license that allows static linking with closed source software. 26 | * 27 | * Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) 28 | * Copyright (c) 2023 Benjamin G. Thompson (@bg-thompson) 29 | * 30 | ********************************************************************************************/ 31 | 32 | import rl "vendor:raylib" 33 | 34 | SCREEN_WIDTH :: 800 35 | SCREEN_HEIGHT :: 450 36 | 37 | main :: proc() { 38 | rl.InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [shapes] example - basic shapes drawing") 39 | defer rl.CloseWindow() // Close window and OpenGL context when leaving main. 40 | 41 | rotation: f32 = 0 42 | rl.SetTargetFPS(60) // Set frames per second. 43 | 44 | // The primary loop. 45 | for !rl.WindowShouldClose() { // Detect window close button or ESC key press. 46 | rotation += 0.2 47 | 48 | // Start drawing. 49 | rl.BeginDrawing() 50 | 51 | // Draw background and text. 52 | rl.ClearBackground(rl.RAYWHITE) 53 | rl.DrawText("some basic shapes available on raylib", 20, 20, 20, rl.DARKGRAY) 54 | 55 | // Draw circle shapes and lines. 56 | rl.DrawCircle(SCREEN_WIDTH / 5, 120, 35, rl.DARKBLUE) 57 | rl.DrawCircleGradient(SCREEN_WIDTH / 5, 220, 60, rl.GREEN, rl.SKYBLUE) 58 | rl.DrawCircleLines(SCREEN_WIDTH / 5, 340, 80, rl.DARKBLUE) 59 | 60 | // Draw rectangle shapes and lines. 61 | rl.DrawRectangle(SCREEN_WIDTH / 4 * 2 - 60, 100, 120, 60, rl.RED) 62 | rl.DrawRectangleGradientH(SCREEN_WIDTH /4 * 2 - 90, 170, 180, 130, rl.MAROON, rl.GOLD) 63 | rl.DrawRectangleLines(SCREEN_WIDTH / 4 * 2 - 40, 320, 80, 60, rl.ORANGE) // NOTE: Uses QUADS internally, not lines. 64 | 65 | // Draw triangle shapes and lines. 66 | rl.DrawTriangle({SCREEN_WIDTH / 4 * 3, 80}, 67 | {SCREEN_WIDTH / 4 * 3 - 60, 150}, 68 | {SCREEN_WIDTH / 4 * 3 + 60, 150}, 69 | rl.VIOLET) 70 | 71 | rl.DrawTriangleLines({SCREEN_WIDTH / 4 * 3, 160}, 72 | {SCREEN_WIDTH / 4 * 3 - 20, 230}, 73 | {SCREEN_WIDTH / 4 * 3 + 20, 230}, 74 | rl.DARKBLUE) 75 | 76 | // Draw polygon shapes and lines. 77 | rl.DrawPoly({ SCREEN_WIDTH / 4 * 3, 330}, 6, 80, rotation, rl.BROWN) 78 | rl.DrawPolyLines({SCREEN_WIDTH / 4 * 3, 330}, 6, 90, rotation, rl.BROWN) 79 | rl.DrawPolyLinesEx({SCREEN_WIDTH / 4 * 3, 330}, 6, 85, rotation, 6, rl.BEIGE) 80 | 81 | // NOTE: We draw all LINES based shapes together to optimize internal drawing, 82 | // this way, all LINES are rendered in a single draw pass. 83 | rl.DrawLine(18, 42, SCREEN_WIDTH - 18, 42, rl.BLACK) 84 | rl.EndDrawing() 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /metal/learn_metal/README.md: -------------------------------------------------------------------------------- 1 | # Getting started with Metal in Odin 2 | 3 | Odin officially bundles with a low-overhead Odin interface for Metal that helps developers add Metal functionality to graphical applications, games, game engines, and GPU workload in Odin directly. 4 | 5 | ## Highlights 6 | 7 | * Odin native drop interface as an alternative to the Metal in Objective-C or Swift 8 | * Direct mapping of all Metal Objective-C classes, constants, and enumerations in Odin in `vendor:darwin/Metal` 9 | * No measurable overhead compared to calling Metal in Objective-C, due to built-in compiler support for Objective-C operations 10 | * No wrappers which do hidden memory allocations 11 | * String `ErrorDomain` constants have weak linkage and are automatically set to `nil` if not available 12 | 13 | ## How to use 14 | 15 | ```odin 16 | import NS "vendor:darwin/Foundation" 17 | import MTL "vendor:darwin/Metal" 18 | import CA "vendor:darwin/QuartzCore" 19 | ``` 20 | 21 | If you are using libraries for SDL2 from Homebrew, you may require adding some extra linker flags: 22 | ``` 23 | odin build . -extra-linker-flags:"-L/opt/homebrew/lib" 24 | ``` 25 | 26 | ## Package Documentation 27 | 28 | * https://pkg.odin-lang.org/vendor/darwin/Metal/ 29 | * https://pkg.odin-lang.org/vendor/darwin/Foundation/ 30 | * https://pkg.odin-lang.org/vendor/darwin/QuartzCore/ 31 | 32 | ## Examples 33 | 34 | ### [00-window](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/00-window) 35 | 36 | ![00-window](https://user-images.githubusercontent.com/3338141/163404425-9e41168c-8f7f-4fd7-b7d9-c1c44a1d3870.png) 37 | 38 | ### [01-primitive](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/01-primitive) 39 | 40 | ![01-primitive](https://user-images.githubusercontent.com/3338141/163404549-0ece2502-1890-4bf6-b816-c0de3bfff303.png) 41 | 42 | ### [02-argbuffers](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/02-argbuffers) 43 | 44 | ![02-argbuffers](https://user-images.githubusercontent.com/3338141/163404646-bbb50869-303a-44d3-b039-1cc2d14b976e.png) 45 | 46 | ### [03-animation](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/03-animation) 47 | 48 | ![03-animation](https://user-images.githubusercontent.com/3338141/163406377-9bffb411-b0e5-4c8f-b50f-a2fc20abfa55.mp4) 49 | 50 | ### [04-instancing](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/04-instancing) 51 | 52 | ![04-instancing](https://user-images.githubusercontent.com/3338141/163406745-e9e965a9-f187-4dbe-915e-096766a30e17.mp4) 53 | 54 | ### [05-perspective](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/05-perspective) 55 | 56 | ![05-perspective](https://user-images.githubusercontent.com/3338141/163406890-b6e96463-4754-4f7f-b223-95e4dde73be3.mp4) 57 | 58 | ### [06-lighting](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/06-lighting) 59 | 60 | ![06-lighting](https://user-images.githubusercontent.com/3338141/163407030-43389d2f-e4d7-4387-936f-c671722ee1cd.png) 61 | 62 | ### [07-texturing](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/07-texturing) 63 | 64 | ![07-texturing](https://user-images.githubusercontent.com/3338141/163419029-d4b86185-74e3-487e-b22b-68cc676320ed.png) 65 | 66 | ### [08-compute](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/08-compute) 67 | 68 | ![08-compute](https://user-images.githubusercontent.com/3338141/163422465-329f7530-df4f-4fd0-9a68-cc58ab855179.png) 69 | 70 | ### [09-compute-to-render](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/09-compute-to-render) 71 | -------------------------------------------------------------------------------- /raylib/ports/text/resources/LICENSE.md: -------------------------------------------------------------------------------- 1 | | resource | author | licence | notes | 2 | | :----------------------------- | :---------: | :------ | :---- | 3 | | fonts/alagard.png | Hewett Tsoi | [Freeware](https://www.dafont.com/es/alagard.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 4 | | fonts/romulus.png | Hewett Tsoi | [Freeware](https://www.dafont.com/es/romulus.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 5 | | fonts/alpha_beta.png | [Brian Kent (AEnigma)](https://www.dafont.com/es/aenigma.d188) | [Freeware](https://www.dafont.com/es/alpha-beta.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 6 | | fonts/setback.png | [Brian Kent (AEnigma)](https://www.dafont.com/es/aenigma.d188) | [Freeware](https://www.dafont.com/es/setback.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 7 | | fonts/jupiter_crash.png | [Brian Kent (AEnigma)](https://www.dafont.com/es/aenigma.d188) | [Freeware](https://www.dafont.com/es/jupiter-crash.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 8 | | fonts/mecha.png | Captain Falcon | [Freeware](https://www.dafont.com/es/mecha-cf.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 9 | | fonts/pixelplay.png | Aleksander Shevchuk | [Freeware](https://www.dafont.com/es/pixelplay.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 10 | | fonts/pixantiqua.ttf | Gerhard Großmann | [Freeware](https://www.dafont.com/es/pixantiqua.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 11 | | anonymous_pro_bold.ttf | [Mark Simonson](https://fonts.google.com/specimen/Anonymous+Pro) | [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) | - | 12 | | custom_alagard.png | [Brian Kent (AEnigma)](https://www.dafont.com/es/aenigma.d188) | [Freeware](https://www.dafont.com/es/jupiter-crash.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 13 | | custom_jupiter_crash.png | [Brian Kent (AEnigma)](https://www.dafont.com/es/aenigma.d188) | [Freeware](https://www.dafont.com/es/jupiter-crash.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 14 | | custom_mecha.png | [Brian Kent (AEnigma)](https://www.dafont.com/es/aenigma.d188) | [Freeware](https://www.dafont.com/es/jupiter-crash.font) | Atlas created by [@raysan5](https://github.com/raysan5) | 15 | | dejavu.fnt, dejavu.png | [DejaVu Fonts](https://dejavu-fonts.github.io/) | [Free](https://dejavu-fonts.github.io/License.html) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) by [@raysan5](https://github.com/raysan5) | 16 | | KAISG.ttf | [Dieter Steffmann](http://www.steffmann.de/wordpress/) | [Freeware](https://www.1001fonts.com/users/steffmann/) | [Kaiserzeit Gotisch](https://www.dafont.com/es/kaiserzeit-gotisch.font) font | 17 | | noto_cjk.fnt, noto_cjk.png | [Google Fonts](https://www.google.com/get/noto/help/cjk/) | [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) by [@raysan5](https://github.com/raysan5) | 18 | | pixantiqua.fnt, pixantiqua.png | Gerhard Großmann | [Freeware](https://www.dafont.com/es/pixantiqua.font) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) by [@raysan5](https://github.com/raysan5) | 19 | | pixantiqua.ttf | Gerhard Großmann | [Freeware](https://www.dafont.com/es/pixantiqua.font) | - | 20 | | symbola.fnt, symbola.png | George Douros | [Freeware](https://fontlibrary.org/en/font/symbola) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) by [@raysan5](https://github.com/raysan5) | 21 | -------------------------------------------------------------------------------- /nanovg/fbo.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | Original Source: https://github.com/memononen/nanovg/blob/master/example/example_fbo.c 5 | Can be run using: odin.exe run main.odin -file 6 | */ 7 | 8 | import "core:fmt" 9 | import "core:math" 10 | import gl "vendor:OpenGL" 11 | import glfw "vendor:glfw" 12 | import nvg "vendor:nanovg" 13 | import nvg_gl "vendor:nanovg/gl" 14 | 15 | renderPattern :: proc(ctx: ^nvg.Context, fb: ^nvg_gl.framebuffer, t: f32, pxRatio: f32) { 16 | s := f32(20) 17 | sr := (math.cos(t) + 1) * 0.5 18 | r := s * 0.6 * (0.2 + 0.8 * sr) 19 | 20 | if fb == nil { 21 | return 22 | } 23 | 24 | fboWidth, fboHeight := nvg.ImageSize(ctx, fb.image) 25 | winWidth := int(f32(fboWidth) / pxRatio) 26 | winHeight := int(f32(fboHeight) / pxRatio) 27 | 28 | // Draw some stuff to an FBO as a test 29 | nvg_gl.BindFramebuffer(fb) 30 | gl.Viewport(0, 0, i32(fboWidth), i32(fboHeight)) 31 | gl.ClearColor(0, 0, 0, 0) 32 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) 33 | nvg.BeginFrame(ctx, f32(winWidth), f32(winHeight), pxRatio) 34 | 35 | pw := math.ceil(f32(winWidth) / s) 36 | ph := math.ceil(f32(winHeight) / s) 37 | 38 | nvg.BeginPath(ctx) 39 | for y in 0 ..< ph { 40 | for x in 0 ..< pw { 41 | cx := (x + 0.5) * s 42 | cy := (y + 0.5) * s 43 | nvg.Circle(ctx, cx, cy, r) 44 | } 45 | } 46 | nvg.FillColor(ctx, nvg.RGBA(220, 160, 0, 200)) 47 | nvg.Fill(ctx) 48 | 49 | nvg.EndFrame(ctx) 50 | nvg_gl.BindFramebuffer(nil) 51 | } 52 | 53 | loadFonts :: proc(ctx: ^nvg.Context) -> bool { 54 | font: int 55 | font = nvg.CreateFont(ctx, "sans", "fonts/Roboto-Regular.ttf") 56 | if font == -1 { 57 | fmt.printf("Could not add font regular.\n") 58 | return false 59 | } 60 | font = nvg.CreateFont(ctx, "sans-bold", "fonts/Roboto-Bold.ttf") 61 | if font == -1 { 62 | fmt.printf("Could not add font bold.\n") 63 | return false 64 | } 65 | return true 66 | } 67 | 68 | main :: proc() { 69 | if !glfw.Init() { 70 | panic("glfw failed") 71 | } 72 | 73 | glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 4) 74 | glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 5) 75 | glfw.WindowHint(glfw.OPENGL_FORWARD_COMPAT, 1) 76 | glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) 77 | glfw.WindowHint(glfw.OPENGL_DEBUG_CONTEXT, 1) 78 | 79 | window := glfw.CreateWindow(1000, 600, "NanoVG", nil, nil) 80 | 81 | if window == nil { 82 | glfw.Terminate() 83 | panic("glfw window failed") 84 | } 85 | 86 | glfw.MakeContextCurrent(window) 87 | gl.load_up_to(4, 5, glfw.gl_set_proc_address) 88 | 89 | ctx := nvg_gl.Create({.ANTI_ALIAS, .STENCIL_STROKES, .DEBUG}) 90 | defer nvg_gl.Destroy(ctx) 91 | 92 | glfw.SetTime(0) 93 | prevt := glfw.GetTime() 94 | 95 | fw, fh := glfw.GetFramebufferSize(window) 96 | w, h := glfw.GetWindowSize(window) 97 | px_ratio := f32(fw) / f32(fw) 98 | fb := nvg_gl.CreateFramebuffer( 99 | ctx, 100 | int(100 * px_ratio), 101 | int(100 * px_ratio), 102 | {.REPEAT_X, .REPEAT_Y}, 103 | ) 104 | 105 | if !loadFonts(ctx) { 106 | panic("Could not load fonts") 107 | } 108 | 109 | for !glfw.WindowShouldClose(window) { 110 | t := glfw.GetTime() 111 | prevt = t 112 | 113 | fw, fh = glfw.GetFramebufferSize(window) 114 | w, h = glfw.GetWindowSize(window) 115 | px_ratio = f32(fw) / f32(fw) 116 | 117 | renderPattern(ctx, &fb, f32(t), px_ratio) 118 | 119 | gl.Viewport(0, 0, fw, fh) 120 | gl.ClearColor(0.3, 0.3, 0.32, 1.0) 121 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) 122 | 123 | { 124 | nvg.FrameScoped(ctx, f32(w), f32(h), px_ratio) 125 | 126 | img := nvg.ImagePattern(0, 0, 100, 100, 0, fb.image, 1.0) 127 | nvg.SaveScoped(ctx) 128 | 129 | for i in 0 ..< 20 { 130 | nvg.FillScoped(ctx) 131 | nvg.Rect(ctx, 10 + f32(i) * 30, 10, 10, f32(w) - 20) 132 | nvg.FillColor(ctx, nvg.HSLA(f32(i) / 19.0, 0.5, 0.5, 255)) 133 | } 134 | 135 | nvg.BeginPath(ctx) 136 | nvg.RoundedRect( 137 | ctx, 138 | 140 + math.sin(f32(t) * 1.3) * 100, 139 | 140 + math.cos(f32(t) * 1.71244) * 100, 140 | 250, 141 | 250, 142 | 20, 143 | ) 144 | nvg.FillPaint(ctx, img) 145 | nvg.Fill(ctx) 146 | nvg.StrokeColor(ctx, nvg.RGBA(220, 160, 0, 255)) 147 | nvg.StrokeWidth(ctx, 3.0) 148 | nvg.Stroke(ctx) 149 | } 150 | 151 | glfw.SwapBuffers(window) 152 | glfw.PollEvents() 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /slices/prefer_to_pass_slices/prefer_to_pass_slices.odin: -------------------------------------------------------------------------------- 1 | /* 2 | This example shows why one might prefer procedure parameters that are slices 3 | whenever possible. Within `main` a dynamic array is created. The program uses 4 | three different procedures to interact with the array. Two out of three 5 | procedures take a slice parameter rather than a dynamic array parameter. There 6 | are comments that motivate the choice of parameter type. 7 | 8 | The code is from "Understanding the Odin Programming Language" 9 | (https://odinbook.com/). It is used with permssion from the author. 10 | */ 11 | 12 | package prefer_to_pass_slices 13 | 14 | import "core:fmt" 15 | import "core:math/rand" 16 | 17 | Cat :: struct { 18 | name: string, 19 | age: int, 20 | } 21 | 22 | /* 23 | Note how `add_cat_of_random_age` is fed a pointer to the dynamic array. 24 | `print_cats` and `mutate_cats` are fed a slice that looks at the whole dynamic 25 | array. See those procedures to understand why. 26 | */ 27 | main :: proc() { 28 | all_the_cats: [dynamic]Cat 29 | add_cat_of_random_age(&all_the_cats, "Klucke") 30 | add_cat_of_random_age(&all_the_cats, "Pontus") 31 | 32 | print_cats(all_the_cats[:]) 33 | mutate_cats(all_the_cats[:]) 34 | print_cats(all_the_cats[:]) 35 | 36 | /* 37 | Output of program (the numbers will be different on each run): 38 | 39 | Klucke is 8 years old 40 | Pontus is 13 years old 41 | Klucke is 10 years old 42 | Pontus is 2 years old 43 | */ 44 | } 45 | 46 | /* 47 | This procedure makes changes to a dynamic array (appends items). So we must pass 48 | a pointer to the dynamic array. After all, the only way to use `append` is if 49 | you have something of type `^[dynamic]Element_Type`. 50 | */ 51 | add_cat_of_random_age :: proc(cats: ^[dynamic]Cat, name: string) { 52 | random_age := rand.int_max(12) + 2 53 | append(cats, Cat { 54 | name = name, 55 | age = random_age, 56 | }) 57 | } 58 | 59 | /* 60 | This procedure loops over the parameter `cats: []Cat` and prints some info about 61 | each element. Note how the slice operator `[:]` is used in `main`: 62 | 63 | print_cats(all_the_cats[:]) 64 | 65 | It feeds this procedure a slice that looks at the whole dynamic array. 66 | 67 | Creating slices is very cheap. Here's what a slice looks like internally: 68 | 69 | // From `/base/runtime/core.odin` 70 | Raw_Slice :: struct { 71 | data: rawptr, 72 | len: int, 73 | } 74 | 75 | So when you do `print_cats(all_the_cats[:])`, then a slice is created with the 76 | `data` field pointing to the first element of `all_the_cats` and `len` is set to 77 | the length of the dynamic array. 78 | 79 | This means that slicing is very cheap: There are no extra allocations. 80 | 81 | Because this procedure uses a slice, we can also use it with any array type that 82 | supports slicing. A fixed array would work fine: 83 | 84 | fixed_array_of_cats := [3]Cat { bla bla } 85 | print_cats(fixed_array_of_cats[:]) 86 | 87 | This makes the procedure more generally useful compared to if it accepted an 88 | array of type `[dynamic]Cat`. 89 | */ 90 | print_cats :: proc(cats: []Cat) { 91 | for cat in cats { 92 | fmt.printfln("%v is %v years old", cat.name, cat.age) 93 | } 94 | } 95 | 96 | /* 97 | This procedure loops over the parameter `cats: []Cat` and modifies each element. 98 | 99 | This may surprise some people: The parameter type isn't `^[]Cat`. So how can it 100 | modify the elements? 101 | 102 | All procedure parameters in Odin are immutable, but it's just the fields of the 103 | `Raw_Slice` that are immutable: 104 | 105 | Raw_Slice :: struct { 106 | data: rawptr, 107 | len: int, 108 | } 109 | 110 | We can't change what address `data` contains or the value of `len`. But the loop 111 | in this procedure doesn't do any of that. It just goes to the memory that the 112 | pointer `data` refers to and modifies the memory that lives at there, which is 113 | allowed! 114 | 115 | Passing a slice here makes this procedure more generally useful compared to if 116 | it used a parameter of type `[dynamic]Cat`. 117 | 118 | We could for example create a fixed array of 100 cats and give them all a 119 | random age using this procedure: 120 | 121 | lots_of_cats: [100]Cat 122 | mutate_cats(lots_of_cats[:]) 123 | */ 124 | mutate_cats :: proc(cats: []Cat) { 125 | for &cat in cats { 126 | cat.age = rand.int_max(12) + 2 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /absolute_beginners/2_variables.odin: -------------------------------------------------------------------------------- 1 | // As you can see, this is the same package name as in `1_main.odin`. Which is 2 | // required. Also: The filename `2_variables.odin` and `1_main.odin` are 3 | // numbered like that just to make you look in `1_main.odin` first. The file 4 | // names don't matter at all: By default, any file within a package can use 5 | // anything from any other file within that package. 6 | package basics 7 | 8 | import "core:fmt" 9 | 10 | // This procedure contains some examples on how to use variables. Variables are 11 | // like the name hints possible to vary. You can change their value and read 12 | // their contents. 13 | variables :: proc() { 14 | // This creates an integer variable. It's called `number`. It is of type 15 | // `int`, short for integer. It can only store whole numbers. 16 | // 17 | // We didn't supply any value, so it has the value `0` by default. 18 | number: int 19 | 20 | fmt.println(number) // 0 21 | 22 | // This gives `number` a new value. If there was no pre-existing variable 23 | // with the name `number`, then this would not compile. 24 | number = 7 25 | 26 | fmt.println(number) // 7 27 | 28 | // However, you can create variable and give it a value in one line! This 29 | // looks like `number: int`, but we tucked on `= 10` at the end. 30 | another_number: int = 10 31 | 32 | fmt.println(another_number) // 10 33 | 34 | // This line also creates a new variable. But it doesn't say which type it 35 | // should have. Instead, the compiler uses "type inference": It figures out 36 | // the type by looking at the value on the right side of `:=`. In this case 37 | // the type is inferred to `int`. 38 | yet_another_number := 42 39 | 40 | fmt.println(yet_another_number) // 42 41 | 42 | // Let's use another type: This variable has the type `f32`. That's short 43 | // for "floating point 32 bit". Such a type can store a number with both 44 | // a whole part and also a fractional part. 45 | // 46 | // Just like before, the default value is `0`. 47 | float_number: f32 48 | 49 | fmt.println(float_number) // 0 50 | 51 | // It's possible to assign numbers that contain a fractional part to 52 | // variables of type `f32`. Note that this would not work if the type was `int`. 53 | float_number = 7.2 54 | 55 | // This might actually print something like `7.1999998`. Floating point 56 | // numbers have a limited precision, trying to print a lot of decimals can 57 | // make that limited precision apparent. 58 | fmt.println(float_number) // 7.1999998 59 | 60 | // To limit the number of printed decimals, you can use `printfln` instead 61 | // of `println`. That procedure accepts two arguments: The first one is 62 | // a format string: It describes how to print the variable we feed into it. 63 | // The format string we use is `%.1f`. It says that we want to print a 64 | // floating point number with a single decimal. 65 | fmt.printfln("%.1f", float_number) // 7.2 66 | 67 | // Here we again create a new variable and try to infer the type. But the 68 | // inferred type will not be `f32`. It will be `f64`. The default inferred 69 | // type for numbers with a fractional part is `f64`. 70 | another_float_number := 7.2 71 | 72 | // This prints the type of a variable! We can use it to verify that the type 73 | // of `another_float_number` is indeed f64 74 | fmt.println(typeid_of(type_of(another_float_number))) // f64 75 | 76 | // So if you want to declare an f32 and give it a value on a single line, 77 | // then you must say what type it should have. You can do this in two ways. 78 | // 79 | // 1) This creates a variable of type `f32` and assign `123.4` to it. 80 | i_want_a_f32: f32 = 123.4 81 | 82 | fmt.printfln("%.1f", i_want_a_f32) // 123.4 83 | fmt.println(typeid_of(type_of(i_want_a_f32))) // f32 84 | 85 | // 2) This creates a variable and infers the type from the right-hand side. 86 | // `f32(2025.1)` casts the value `2025.1` to the type `f32`. So the 87 | // right-hand side has type `f32`. 88 | i_want_another_f32 := f32(2025.1) 89 | 90 | fmt.printfln("%.1f", i_want_another_f32) // 2025.1 91 | fmt.println(typeid_of(type_of(i_want_another_f32))) // f32 92 | 93 | // There's a list of all available so-called 'basic types' (int, f32 etc) in 94 | // the overview: https://odin-lang.org/docs/overview/#basic-types 95 | 96 | // That's it for this procedure! It ends here, which means that the program 97 | // will continue with the next line after `variables()` in `1_main.odin`. 98 | } -------------------------------------------------------------------------------- /raylib/box2d/main.odin: -------------------------------------------------------------------------------- 1 | package box2d 2 | 3 | import b2 "vendor:box2d" 4 | import rl "vendor:raylib" 5 | 6 | // Original: https://github.com/erincatto/box2d-raylib 7 | 8 | Entity :: struct { 9 | body_id: b2.BodyId, 10 | extent: b2.Vec2, 11 | texture: rl.Texture, 12 | } 13 | 14 | draw_entity :: proc(entity: Entity) { 15 | // The boxes were created centered on the bodies, but raylib draws textures starting at the top left corner. 16 | // Body_GetWorldPoint gets the top left corner of the box accounting for rotation. 17 | p := b2.Body_GetWorldPoint(entity.body_id, -entity.extent) 18 | rotation := b2.Body_GetRotation(entity.body_id) 19 | radians := b2.Rot_GetAngle(rotation) 20 | 21 | rl.DrawTextureEx(entity.texture, p, rl.RAD2DEG * radians, 1., rl.WHITE) 22 | 23 | // I used these circles to ensure the coordinates are correct 24 | // rl.DrawCircleV(p, 5., rl.BLACK) 25 | // p = b2.Body_GetWorldPoint(entity.body_id, 0) 26 | // rl.DrawCircleV(p, 5., rl.BLUE) 27 | // p = b2.Body_GetWorldPoint(entity.body_id, entity.extent) 28 | // rl.DrawCircleV(p, 5., rl.RED) 29 | } 30 | 31 | GROUND_COUNT :: 14 32 | BOX_COUNT :: 10 33 | 34 | main :: proc() { 35 | width := i32(1920) 36 | height := i32(1080) 37 | rl.InitWindow(width, height, "box2d-raylib") 38 | defer rl.CloseWindow() 39 | 40 | rl.SetTargetFPS(60) 41 | 42 | // 128 pixels per meter is appropriate for this scene. The boxes are 128 pixels wide. 43 | length_units_per_meter := f32(128.) 44 | b2.SetLengthUnitsPerMeter(length_units_per_meter) 45 | 46 | world_def := b2.DefaultWorldDef() 47 | 48 | // Realistic gravity is achieved by multiplying gravity by the length unit. 49 | world_def.gravity.y = 9.8 * length_units_per_meter 50 | world_id := b2.CreateWorld(world_def) 51 | 52 | ground_texture := rl.LoadTexture("ground.png") 53 | defer rl.UnloadTexture(ground_texture) 54 | 55 | box_texture := rl.LoadTexture("box.png") 56 | defer rl.UnloadTexture(box_texture) 57 | 58 | ground_extent := b2.Vec2{.5 * f32(ground_texture.width), .5 * f32(ground_texture.height)} 59 | box_extent := b2.Vec2{.5 * f32(box_texture.width), .5 * f32(box_texture.height)} 60 | 61 | // These polygons are centered on the origin and when they are added to a body they 62 | // will be centered on the body position. 63 | ground_polygon := b2.MakeBox(ground_extent.x, ground_extent.y) 64 | box_polygon := b2.MakeBox(box_extent.x, box_extent.y) 65 | 66 | ground_entities: [GROUND_COUNT]Entity 67 | for &entity, i in ground_entities { 68 | body_def := b2.DefaultBodyDef() 69 | body_def.position = {(2. * f32(i) + 2.) * ground_extent.x, f32(height) - ground_extent.y - 100.} 70 | 71 | // I used this rotation to test the world to screen transformation 72 | // body_def.rotation = b2.MakeRot(.25 * b2.PI * f32(i)) 73 | 74 | entity.body_id = b2.CreateBody(world_id, body_def) 75 | entity.extent = ground_extent 76 | entity.texture = ground_texture 77 | shape_def := b2.DefaultShapeDef() 78 | _ = b2.CreatePolygonShape(entity.body_id, shape_def, ground_polygon) 79 | } 80 | 81 | box_entities: [BOX_COUNT]Entity 82 | box_index: int 83 | for i in 1..=4 { 84 | y := f32(height) - box_extent.y - 100. - (2.5 * f32(i) + 2.) * box_extent.y - 20. 85 | 86 | for j in i..=4 { 87 | x := .5 * f32(width) + (3. * f32(j) - f32(i) - 3.) * box_extent.x 88 | 89 | body_def := b2.DefaultBodyDef() 90 | body_def.type = .dynamicBody 91 | body_def.position = {x, y} 92 | 93 | entity := &box_entities[box_index] 94 | entity.body_id = b2.CreateBody(world_id, body_def) 95 | entity.texture = box_texture 96 | entity.extent = box_extent 97 | shape_def := b2.DefaultShapeDef() 98 | _ = b2.CreatePolygonShape(entity.body_id, shape_def, box_polygon) 99 | 100 | box_index += 1 101 | } 102 | } 103 | assert(box_index == BOX_COUNT) 104 | 105 | pause: bool 106 | for !rl.WindowShouldClose() { 107 | if rl.IsKeyPressed(.P) { 108 | pause = !pause 109 | } 110 | 111 | if !pause { 112 | delta_time := rl.GetFrameTime() 113 | b2.World_Step(world_id, delta_time, 4) 114 | } 115 | 116 | rl.BeginDrawing() 117 | defer rl.EndDrawing() 118 | 119 | rl.ClearBackground(rl.DARKGRAY) 120 | 121 | message :: "Hello Box2D!" 122 | font_size := i32(36) 123 | text_width := rl.MeasureText(message, font_size) 124 | rl.DrawText(message, (width - text_width) / 2, 50, font_size, rl.LIGHTGRAY) 125 | 126 | for entity in ground_entities { 127 | draw_entity(entity) 128 | } 129 | 130 | for entity in box_entities { 131 | draw_entity(entity) 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /raylib/ports/shapes/shapes_colors_palette.odin: -------------------------------------------------------------------------------- 1 | package raylib_examples 2 | 3 | /******************************************************************************************* 4 | * 5 | * raylib [shapes] example - Colors palette 6 | * 7 | * This example was originally created in C with raylib 1.0, and updated with raylib 2.5 8 | * before being translated to Odin. 9 | * 10 | * The original example in C can be found on raylib.com at: 11 | * 12 | * https://www.raylib.com/examples/shapes/loader.html?name=shapes_colors_palette 13 | * 14 | * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, 15 | * BSD-like license that allows static linking with closed source software. The license 16 | * can be found in its entirety as part of the standard Odin distribution at: 17 | * 18 | * /vendor/raylib/LICENSE 19 | * 20 | * or online at: 21 | * 22 | * https://www.raylib.com/license.html 23 | * 24 | * This example is licensed under an unmodified zlib/libpng license, which is an 25 | * OSI-certified, BSD-like license that allows static linking with closed source software. 26 | * 27 | * Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) 28 | * Copyright (c) 2023 Benjamin G. Thompson (@bg-thompson) 29 | * 30 | ********************************************************************************************/ 31 | 32 | import rl "vendor:raylib" 33 | 34 | Color_And_Name :: struct{ 35 | color: rl.Color, 36 | name: cstring, 37 | } 38 | 39 | COLORS_AND_NAMES :: [?]Color_And_Name { 40 | {rl.DARKGRAY, "DARKGRAY"}, 41 | {rl.MAROON, "MAROON"}, 42 | {rl.ORANGE, "ORANGE"}, 43 | {rl.DARKGREEN, "DARKGREEN"}, 44 | {rl.DARKBLUE, "DARKBLUE"}, 45 | {rl.DARKPURPLE, "DARKPURPLE"}, 46 | {rl.DARKBROWN, "DARKBROWN"}, 47 | {rl.GRAY, "GRAY"}, 48 | {rl.RED, "RED"}, 49 | {rl.GOLD, "GOLD"}, 50 | {rl.LIME, "LIME"}, 51 | {rl.BLUE, "BLUE"}, 52 | {rl.VIOLET, "VIOLET"}, 53 | {rl.BROWN, "BROWN"}, 54 | {rl.LIGHTGRAY, "LIGHTGRAY"}, 55 | {rl.PINK, "PINK"}, 56 | {rl.YELLOW, "YELLOW"}, 57 | {rl.GREEN, "GREEN"}, 58 | {rl.SKYBLUE, "SKYBLUE"}, 59 | {rl.PURPLE, "PURPLE"}, 60 | {rl.BEIGE, "BEIGE"}, 61 | } 62 | 63 | NUMBER_OF_COLORS :: len(COLORS_AND_NAMES) 64 | 65 | SCREEN_WIDTH :: 800 66 | SCREEN_HEIGHT :: 450 67 | 68 | color_rects: [NUMBER_OF_COLORS]rl.Rectangle 69 | 70 | @(init) // Calls this proc once before main. 71 | initialize_colors_rects :: proc() { 72 | // Initial rectangle geometry data in colors_rects. 73 | for i in 0.. (deduplicated: []rune) { 112 | deduplicated = slice.clone(codepoints) 113 | slice.sort(deduplicated) 114 | return slice.unique(deduplicated) 115 | } -------------------------------------------------------------------------------- /orca/clock/main.odin: -------------------------------------------------------------------------------- 1 | package src 2 | 3 | /* 4 | Original Source: https://github.com/orca-app/orca/blob/main/samples/clock/src/main.c 5 | 6 | Can be run using in the local folder 7 | 1. odin.exe build main.odin -file -target:orca_wasm32 -out:module.wasm 8 | 2. orca bundle --name orca_output --resource-dir data module.wasm 9 | 3. orca_output\bin\orca_output.exe 10 | */ 11 | 12 | import "core:math" 13 | import oc "core:sys/orca" 14 | 15 | clockNumberStrings := [?]string{"12", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"} 16 | 17 | surface: oc.surface = {} 18 | renderer: oc.canvas_renderer = {} 19 | canvas: oc.canvas_context = {} 20 | font: oc.font = {} 21 | frameSize: oc.vec2 = {100, 100} 22 | lastSeconds: f64 = 0 23 | 24 | mat_transform :: proc "contextless" (x, y, radians: f32) -> oc.mat2x3 { 25 | rotation := oc.mat2x3_rotate(radians) 26 | translation := oc.mat2x3_translate(x, y) 27 | return oc.mat2x3_mul_m(translation, rotation) 28 | } 29 | 30 | main :: proc() { 31 | oc.window_set_title("clock") 32 | oc.window_set_size({400, 400}) 33 | 34 | renderer = oc.canvas_renderer_create() 35 | surface = oc.canvas_surface_create(renderer) 36 | canvas = oc.canvas_context_create() 37 | 38 | ranges := [?]oc.unicode_range { 39 | oc.UNICODE_BASIC_LATIN, 40 | oc.UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, 41 | oc.UNICODE_LATIN_EXTENDED_A, 42 | oc.UNICODE_LATIN_EXTENDED_B, 43 | oc.UNICODE_SPECIALS, 44 | } 45 | 46 | oc.font_create_from_path("segoeui.ttf", 5, &ranges[0]) 47 | } 48 | 49 | @(export) 50 | oc_on_resize :: proc "c" (width, height: u32) { 51 | frameSize.x = f32(width) 52 | frameSize.y = f32(height) 53 | } 54 | 55 | // TODO replace this after round_f64 is fixed: https://github.com/odin-lang/Odin/issues/3856 56 | remainder_f64 :: proc "contextless" (x, y: f64) -> f64 { 57 | return x - round_slow(x / y) * y 58 | } 59 | 60 | round_slow :: proc "contextless" (x: f64) -> f64 { 61 | t := math.trunc(x) 62 | if abs(x - t) >= 0.5 { 63 | return t + math.copy_sign(1, x) 64 | } 65 | return t 66 | } 67 | 68 | mod_f64 :: proc "contextless" (x, y: f64) -> (n: f64) { 69 | z := abs(y) 70 | n = remainder_f64(abs(x), z) 71 | if math.sign(n) < 0 { 72 | n += z 73 | } 74 | return math.copy_sign(n, x) 75 | } 76 | 77 | @(export) 78 | oc_on_frame_refresh :: proc "c" () { 79 | // context = runtime.default_context() 80 | 81 | oc.canvas_context_select(canvas) 82 | oc.set_color_rgba(.05, .05, .05, 1) 83 | oc.clear() 84 | 85 | timestampSecs := f64(oc.clock_time(.DATE)) 86 | secs := mod_f64(timestampSecs, 60.0) 87 | minutes := mod_f64(timestampSecs, 60.0 * 60.0) / 60.0 88 | hours := mod_f64(timestampSecs, 60.0 * 60.0 * 24) / (60.0 * 60.0) 89 | hoursAs12Format := mod_f64(hours, 12.0) 90 | 91 | if lastSeconds != math.floor(secs) { 92 | lastSeconds = math.floor(secs) 93 | 94 | // oc.log_infof( 95 | // "current time: %.0f:%.0f:%.0f", 96 | // math.floor(hours), 97 | // math.floor(minutes), 98 | // math.floor(secs), 99 | // ) 100 | } 101 | 102 | secondsRotation := (math.PI * 2) * (secs / 60.0) - (math.PI / 2) 103 | minutesRotation := (math.PI * 2) * (minutes / 60.0) - (math.PI / 2) 104 | hoursRotation := (math.PI * 2) * (hoursAs12Format / 12.0) - (math.PI / 2) 105 | 106 | centerX := frameSize.x / 2 107 | centerY := frameSize.y / 2 108 | clockRadius := min(frameSize.x, frameSize.y) * 0.5 * 0.85 109 | 110 | DEFAULT_CLOCK_RADIUS :: 260 111 | uiScale := clockRadius / DEFAULT_CLOCK_RADIUS 112 | 113 | fontSize := 26 * uiScale 114 | oc.set_font(font) 115 | oc.set_font_size(fontSize) 116 | 117 | // clock backing 118 | oc.set_color_rgba(1, 1, 1, 1) 119 | oc.circle_fill(centerX, centerY, clockRadius) 120 | 121 | // clock face 122 | for i in 0 ..< len(clockNumberStrings) { 123 | str := clockNumberStrings[i] 124 | textRect := oc.font_text_metrics(font, fontSize, str).ink 125 | 126 | angle := f32(i) * ((math.PI * 2) / f32(12.0)) - (math.PI / 2) 127 | transform := mat_transform( 128 | centerX - (textRect.w / 2) - textRect.x, 129 | centerY - (textRect.h / 2) - textRect.y, 130 | angle, 131 | ) 132 | 133 | pos := oc.mat2x3_mul(transform, {clockRadius * 0.8, 0}) 134 | 135 | oc.set_color_rgba(0.2, 0.2, 0.2, 1) 136 | oc.text_fill(pos.x, pos.y, str) 137 | } 138 | 139 | // hours hand 140 | oc.matrix_multiply_push(mat_transform(centerX, centerY, f32(hoursRotation))) 141 | { 142 | oc.set_color_rgba(.2, 0.2, 0.2, 1) 143 | oc.rounded_rectangle_fill(0, -7.5 * uiScale, clockRadius * 0.5, 15 * uiScale, 5 * uiScale) 144 | } 145 | oc.matrix_pop() 146 | 147 | // minutes hand 148 | oc.matrix_multiply_push(mat_transform(centerX, centerY, f32(minutesRotation))) 149 | { 150 | oc.set_color_rgba(.2, 0.2, 0.2, 1) 151 | oc.rounded_rectangle_fill(0, -5 * uiScale, clockRadius * 0.7, 10 * uiScale, 5 * uiScale) 152 | } 153 | oc.matrix_pop() 154 | 155 | // seconds hand 156 | oc.matrix_multiply_push(mat_transform(centerX, centerY, f32(secondsRotation))) 157 | { 158 | oc.set_color_rgba(1, 0.2, 0.2, 1) 159 | oc.rounded_rectangle_fill(0, -2.5 * uiScale, clockRadius * 0.8, 5 * uiScale, 5 * uiScale) 160 | } 161 | oc.matrix_pop() 162 | 163 | oc.set_color_srgba(.2, 0.2, 0.2, 1) 164 | oc.circle_fill(centerX, centerY, 10 * uiScale) 165 | 166 | oc.canvas_render(renderer, canvas, surface) 167 | oc.canvas_present(renderer, surface) 168 | } 169 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Check everything 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | schedule: 8 | - cron: 0 20 * * * 9 | 10 | env: 11 | FORCE_COLOR: "1" 12 | 13 | jobs: 14 | checks: 15 | runs-on: macos-14 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Dependencies 20 | run: | 21 | brew install llvm@18 22 | echo "/opt/homebrew/opt/llvm@18/bin" >> "$GITHUB_PATH" 23 | 24 | - name: Set up Odin 25 | run: | 26 | git clone https://github.com/odin-lang/Odin.git --depth 1 --single-branch --branch=master 27 | cd Odin 28 | make 29 | echo "$(pwd)" >> "$GITHUB_PATH" 30 | ./odin report 31 | 32 | - name: Check everything 33 | run: | 34 | FLAGS="-vet -strict-style -vet-tabs -disallow-do -warnings-as-errors" 35 | 36 | odin check absolute_beginners $FLAGS 37 | 38 | odin check command_line_arguments $FLAGS 39 | odin check dir_info $FLAGS 40 | odin check dynamic_arrays $FLAGS 41 | odin check strings $FLAGS 42 | 43 | odin check console/raw_console $FLAGS 44 | odin check console/raw_console -target:windows_amd64 $FLAGS 45 | odin check console/read_console_input $FLAGS 46 | 47 | odin check code_generation $FLAGS 48 | odin check code_generation/generate_image_info $FLAGS 49 | 50 | odin check arena_allocator $FLAGS 51 | 52 | odin check directx/d3d12_triangle_sdl2 -target:windows_amd64 $FLAGS 53 | 54 | odin check glfw/window $FLAGS 55 | 56 | odin check json/load_json $FLAGS 57 | odin check json/load_json_unmarshal $FLAGS 58 | odin check json/write_json_marshal $FLAGS 59 | 60 | odin check thread/basics $FLAGS 61 | odin check thread/sync_mutex $FLAGS 62 | 63 | odin check math/noise/draw_texture $FLAGS 64 | odin check math/rand/markov $FLAGS 65 | 66 | odin check raylib/game_of_life $FLAGS 67 | odin check raylib/log $FLAGS 68 | odin check raylib/microui $FLAGS 69 | odin check raylib/ports/shaders/shaders_mesh_instancing.odin -file $FLAGS 70 | odin check raylib/ports/shapes/shapes_basic_shapes.odin -file $FLAGS 71 | odin check raylib/ports/shapes/shapes_bouncing_ball.odin -file $FLAGS 72 | odin check raylib/ports/shapes/shapes_colors_palette.odin -file $FLAGS 73 | odin check raylib/ports/shapes/shapes_logo_raylib_anim.odin -file $FLAGS 74 | odin check raylib/ports/text/text_codepoints_loading.odin -file $FLAGS 75 | odin check raylib/ports/textures/textures_gif_player.odin -file $FLAGS 76 | odin check raylib/tetroid $FLAGS 77 | odin check raylib/box2d $FLAGS 78 | 79 | odin check directx/d3d11_minimal_sdl2 -target:windows_amd64 $FLAGS 80 | 81 | odin check opengl/minimal_sdl2 $FLAGS 82 | 83 | odin check vulkan/triangle_glfw $FLAGS 84 | 85 | odin check metal/minimal_sdl2 $FLAGS 86 | 87 | odin check metal/learn_metal/00-window $FLAGS 88 | odin check metal/learn_metal/01-primitive $FLAGS 89 | odin check metal/learn_metal/02-argbuffers $FLAGS 90 | odin check metal/learn_metal/02-argbuffers-no-sdl $FLAGS 91 | odin check metal/learn_metal/03-animation $FLAGS 92 | odin check metal/learn_metal/04-instancing $FLAGS 93 | odin check metal/learn_metal/05-perspective $FLAGS 94 | odin check metal/learn_metal/06-lighting $FLAGS 95 | odin check metal/learn_metal/07-texturing $FLAGS 96 | odin check metal/learn_metal/08-compute $FLAGS 97 | odin check metal/learn_metal/09-compute-to-render $FLAGS 98 | 99 | odin check sdl2/chase_in_space $FLAGS 100 | odin check sdl2/hellope $FLAGS 101 | odin check sdl2/microui $FLAGS 102 | 103 | odin check simd/approaches $FLAGS 104 | odin check simd/basic-sum $FLAGS 105 | odin check simd/motion $FLAGS 106 | 107 | odin check slices/prefer_to_pass_slices $FLAGS 108 | 109 | odin check wasm/js_wasm32 $FLAGS 110 | 111 | odin check wgpu/microui -target:windows_amd64 $FLAGS 112 | odin check wgpu/microui -target:js_wasm32 $FLAGS 113 | 114 | odin check wgpu/glfw-triangle -target:windows_amd64 $FLAGS 115 | odin check wgpu/glfw-triangle -target:js_wasm32 $FLAGS 116 | 117 | odin check wgpu/sdl3-triangle -target:windows_amd64 $FLAGS 118 | odin check wgpu/sdl3-triangle -target:js_wasm32 $FLAGS 119 | 120 | odin check win32/game_of_life -target:windows_amd64 $FLAGS 121 | odin check win32/open_window -target:windows_amd64 $FLAGS 122 | 123 | odin check nanovg/example.odin -file $FLAGS 124 | odin check nanovg/fbo.odin -file $FLAGS 125 | 126 | # TODO: fix orca examples after update. 127 | # odin check orca/breakout -target:orca_wasm32 $FLAGS 128 | # odin check orca/clock -target:orca_wasm32 $FLAGS 129 | # odin check orca/ui -target:orca_wasm32 $FLAGS 130 | 131 | odin check net/tcp_echo_server/client $FLAGS 132 | odin check net/tcp_echo_server/server $FLAGS 133 | -------------------------------------------------------------------------------- /opengl/minimal_sdl2/sdl2_opengl_demo.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "core:fmt" 4 | import glm "core:math/linalg/glsl" 5 | import "core:time" 6 | 7 | import SDL "vendor:sdl2" 8 | import gl "vendor:OpenGL" 9 | 10 | GL_VERSION_MAJOR :: 3 11 | GL_VERSION_MINOR :: 3 12 | 13 | main :: proc() { 14 | WINDOW_WIDTH :: 854 15 | WINDOW_HEIGHT :: 480 16 | 17 | SDL.Init({.VIDEO}) 18 | defer SDL.Quit() 19 | 20 | window := SDL.CreateWindow("Odin SDL2 Demo", SDL.WINDOWPOS_UNDEFINED, SDL.WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, {.OPENGL}) 21 | if window == nil { 22 | fmt.eprintln("Failed to create window") 23 | return 24 | } 25 | defer SDL.DestroyWindow(window) 26 | 27 | SDL.GL_SetAttribute(.CONTEXT_PROFILE_MASK, i32(SDL.GLprofile.CORE)) 28 | SDL.GL_SetAttribute(.CONTEXT_MAJOR_VERSION, GL_VERSION_MAJOR) 29 | SDL.GL_SetAttribute(.CONTEXT_MINOR_VERSION, GL_VERSION_MINOR) 30 | 31 | gl_context := SDL.GL_CreateContext(window) 32 | defer SDL.GL_DeleteContext(gl_context) 33 | 34 | // load the OpenGL procedures once an OpenGL context has been established 35 | gl.load_up_to(GL_VERSION_MAJOR, GL_VERSION_MINOR, SDL.gl_set_proc_address) 36 | 37 | // useful utility procedures that are part of vendor:OpenGl 38 | program, program_ok := gl.load_shaders_source(vertex_source, fragment_source) 39 | if !program_ok { 40 | fmt.eprintln("Failed to create GLSL program") 41 | return 42 | } 43 | defer gl.DeleteProgram(program) 44 | 45 | gl.UseProgram(program) 46 | 47 | uniforms := gl.get_uniforms_from_program(program) 48 | defer delete(uniforms) 49 | 50 | vao: u32 51 | gl.GenVertexArrays(1, &vao); defer gl.DeleteVertexArrays(1, &vao) 52 | gl.BindVertexArray(vao) 53 | 54 | // initialization of OpenGL buffers 55 | vbo, ebo: u32 56 | gl.GenBuffers(1, &vbo); defer gl.DeleteBuffers(1, &vbo) 57 | gl.GenBuffers(1, &ebo); defer gl.DeleteBuffers(1, &ebo) 58 | 59 | // struct declaration 60 | Vertex :: struct { 61 | pos: glm.vec3, 62 | col: glm.vec4, 63 | } 64 | 65 | vertices := []Vertex{ 66 | {{-0.5, +0.5, 0}, {1.0, 0.0, 0.0, 0.75}}, 67 | {{-0.5, -0.5, 0}, {1.0, 1.0, 0.0, 0.75}}, 68 | {{+0.5, -0.5, 0}, {0.0, 1.0, 0.0, 0.75}}, 69 | {{+0.5, +0.5, 0}, {0.0, 0.0, 1.0, 0.75}}, 70 | } 71 | 72 | indices := []u16{ 73 | 0, 1, 2, 74 | 2, 3, 0, 75 | } 76 | 77 | gl.BindBuffer(gl.ARRAY_BUFFER, vbo) 78 | gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*size_of(vertices[0]), raw_data(vertices), gl.STATIC_DRAW) 79 | gl.EnableVertexAttribArray(0) 80 | gl.EnableVertexAttribArray(1) 81 | gl.VertexAttribPointer(0, 3, gl.FLOAT, false, size_of(Vertex), offset_of(Vertex, pos)) 82 | gl.VertexAttribPointer(1, 4, gl.FLOAT, false, size_of(Vertex), offset_of(Vertex, col)) 83 | 84 | gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo) 85 | gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices)*size_of(indices[0]), raw_data(indices), gl.STATIC_DRAW) 86 | 87 | // high precision timer 88 | start_tick := time.tick_now() 89 | 90 | loop: for { 91 | duration := time.tick_since(start_tick) 92 | t := f32(time.duration_seconds(duration)) 93 | 94 | // event polling 95 | event: SDL.Event 96 | for SDL.PollEvent(&event) { 97 | // #partial switch tells the compiler not to error if every case is not present 98 | #partial switch event.type { 99 | case .KEYDOWN: 100 | #partial switch event.key.keysym.sym { 101 | case .ESCAPE: 102 | // labelled control flow 103 | break loop 104 | } 105 | case .QUIT: 106 | // labelled control flow 107 | break loop 108 | } 109 | } 110 | 111 | // Native support for GLSL-like functionality 112 | pos := glm.vec3{ 113 | glm.cos(t*2), 114 | glm.sin(t*2), 115 | 0, 116 | } 117 | 118 | // array programming support 119 | pos *= 0.3 120 | 121 | // matrix support 122 | // model matrix which a default scale of 0.5 123 | model := glm.mat4{ 124 | 0.5, 0, 0, 0, 125 | 0, 0.5, 0, 0, 126 | 0, 0, 0.5, 0, 127 | 0, 0, 0, 1, 128 | } 129 | 130 | // matrix indexing and array short with `.x` 131 | model[0, 3] = -pos.x 132 | model[1, 3] = -pos.y 133 | model[2, 3] = -pos.z 134 | 135 | // native swizzling support for arrays 136 | model[3].yzx = pos.yzx 137 | 138 | model = model * glm.mat4Rotate({0, 1, 1}, t) 139 | 140 | view := glm.mat4LookAt({0, -1, +1}, {0, 0, 0}, {0, 0, 1}) 141 | proj := glm.mat4Perspective(45, 1.3, 0.1, 100.0) 142 | 143 | // matrix multiplication 144 | u_transform := proj * view * model 145 | 146 | // matrix types in Odin are stored in column-major format but written as you'd normal write them 147 | gl.UniformMatrix4fv(uniforms["u_transform"].location, 1, false, &u_transform[0, 0]) 148 | 149 | gl.Viewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT) 150 | gl.ClearColor(0.5, 0.7, 1.0, 1.0) 151 | gl.Clear(gl.COLOR_BUFFER_BIT) 152 | 153 | gl.DrawElements(gl.TRIANGLES, i32(len(indices)), gl.UNSIGNED_SHORT, nil) 154 | 155 | SDL.GL_SwapWindow(window) 156 | } 157 | } 158 | 159 | 160 | vertex_source := `#version 330 core 161 | 162 | layout(location=0) in vec3 a_position; 163 | layout(location=1) in vec4 a_color; 164 | 165 | out vec4 v_color; 166 | 167 | uniform mat4 u_transform; 168 | 169 | void main() { 170 | gl_Position = u_transform * vec4(a_position, 1.0); 171 | v_color = a_color; 172 | } 173 | ` 174 | 175 | fragment_source := `#version 330 core 176 | 177 | in vec4 v_color; 178 | 179 | out vec4 o_color; 180 | 181 | void main() { 182 | o_color = v_color; 183 | } 184 | ` 185 | -------------------------------------------------------------------------------- /raylib/ports/shapes/shapes_logo_raylib_anim.odin: -------------------------------------------------------------------------------- 1 | package raylib_examples 2 | 3 | /******************************************************************************************* 4 | * 5 | * raylib [shapes] example - raylib logo animation 6 | * 7 | * This example was originally created in C with raylib 1.0, and updated with raylib 4.0 8 | * before being translated to Odin. 9 | * 10 | * The original example in C can be found on raylib.com at: 11 | * 12 | * https://www.raylib.com/examples/shapes/loader.html?name=shapes_logo_raylib_anim 13 | * 14 | * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, 15 | * BSD-like license that allows static linking with closed source software. The license 16 | * can be found in its entirety as part of the standard Odin distribution at: 17 | * 18 | * /vendor/raylib/LICENSE 19 | * 20 | * or online at: 21 | * 22 | * https://www.raylib.com/license.html 23 | * 24 | * This example is licensed under an unmodified zlib/libpng license, which is an 25 | * OSI-certified, BSD-like license that allows static linking with closed source software. 26 | * 27 | * Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) 28 | * Copyright (c) 2023 Benjamin G. Thompson (@bg-thompson) 29 | * 30 | ********************************************************************************************/ 31 | 32 | import rl "vendor:raylib" 33 | 34 | SCREEN_WIDTH :: 800 35 | SCREEN_HEIGHT :: 450 36 | 37 | State :: enum u8 { 38 | STATE_0, 39 | STATE_1, 40 | STATE_2, 41 | STATE_3, 42 | STATE_4, 43 | } 44 | 45 | main :: proc() { 46 | rl.InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [shapes] example - raylib logo animation") 47 | defer rl.CloseWindow() // Close window and OpenGL context when leaving main. 48 | 49 | logoPosX: i32 = SCREEN_WIDTH / 2 - 128 50 | logoPosY: i32 = SCREEN_HEIGHT / 2 - 128 51 | 52 | framesCounter := 0 53 | lettersCount: i32 = 0 54 | 55 | topSideRecWidth: i32 = 16 56 | leftSideRecHeight: i32 = 16 57 | bottomSideRecWidth: i32 = 16 58 | rightSideRecHeight: i32 = 16 59 | 60 | 61 | state := State.STATE_0 // Track animation states. 62 | alpha: f32 = 1.0 // Useful for fading. 63 | rl.SetTargetFPS(60) // Set frames per second. 64 | 65 | // The primary loop. 66 | for !rl.WindowShouldClose() { // Detect window close button or ESC key press. 67 | switch state { 68 | case .STATE_0: // State 0: Small box blinking. 69 | framesCounter += 1 70 | if framesCounter == 120 { 71 | state = .STATE_1 72 | framesCounter = 0 // Reset counter... will be used later... 73 | } 74 | 75 | case .STATE_1: // State 1: Top and left bars growing. 76 | topSideRecWidth += 4 77 | leftSideRecHeight += 4 78 | if topSideRecWidth == 256 { 79 | state = .STATE_2 80 | } 81 | 82 | case .STATE_2: // State 2: Bottom and right bars growing. 83 | bottomSideRecWidth += 4 84 | rightSideRecHeight += 4 85 | if bottomSideRecWidth == 256 { 86 | state = .STATE_3 87 | } 88 | 89 | case .STATE_3: // State 3: Letters appearing (one by one). 90 | framesCounter += 1 91 | if framesCounter / 12 == 1 { // Every 12 frames, one more letter! 92 | lettersCount += 1 93 | framesCounter = 0 94 | } 95 | 96 | if lettersCount >= 10 { // When all letters have appeared, fade out everything. 97 | alpha -= 0.02 98 | if alpha <= 0 { 99 | alpha = 0 100 | state = .STATE_4 101 | } 102 | } 103 | 104 | case .STATE_4: 105 | if rl.IsKeyPressed(rl.KeyboardKey.R) { 106 | framesCounter = 0 107 | lettersCount = 0 108 | topSideRecWidth = 16 109 | leftSideRecHeight = 16 110 | bottomSideRecWidth = 16 111 | rightSideRecHeight = 16 112 | alpha = 1.0 113 | state = .STATE_0 // Return to State 0 114 | } 115 | } 116 | 117 | // Start drawing. 118 | rl.BeginDrawing() 119 | 120 | rl.ClearBackground(rl.RAYWHITE) 121 | 122 | switch state { 123 | case .STATE_0: 124 | if (framesCounter / 15) % 2 != 0 { 125 | rl.DrawRectangle(logoPosX, logoPosY, 16, 16, rl.BLACK) 126 | } 127 | 128 | case .STATE_1: 129 | rl.DrawRectangle(logoPosX, logoPosY, topSideRecWidth, 16, rl.BLACK) 130 | rl.DrawRectangle(logoPosX, logoPosY, 16, leftSideRecHeight, rl.BLACK) 131 | 132 | case .STATE_2: 133 | rl.DrawRectangle(logoPosX, logoPosY, topSideRecWidth, 16, rl.BLACK) 134 | rl.DrawRectangle(logoPosX, logoPosY, 16, leftSideRecHeight, rl.BLACK) 135 | 136 | rl.DrawRectangle(logoPosX + 240, logoPosY, 16, rightSideRecHeight, rl.BLACK) 137 | rl.DrawRectangle(logoPosX, logoPosY + 240, bottomSideRecWidth, 16, rl.BLACK) 138 | 139 | case .STATE_3: 140 | rl.DrawRectangle(logoPosX, logoPosY, topSideRecWidth, 16, rl.Fade(rl.BLACK, alpha)) 141 | rl.DrawRectangle(logoPosX, logoPosY + 16, 16, leftSideRecHeight - 32, rl.Fade(rl.BLACK, alpha)) 142 | 143 | rl.DrawRectangle(logoPosX + 240, logoPosY + 16, 16, rightSideRecHeight - 32, rl.Fade(rl.BLACK, alpha)) 144 | rl.DrawRectangle(logoPosX, logoPosY + 240, bottomSideRecWidth, 16, rl.Fade(rl.BLACK, alpha)) 145 | 146 | rl.DrawRectangle(rl.GetScreenWidth() / 2 - 112, rl.GetScreenHeight() / 2 - 112, 224, 224, rl.Fade(rl.RAYWHITE, alpha)) 147 | 148 | rl.DrawText(rl.TextSubtext("raylib", 0, lettersCount), rl.GetScreenWidth()/2 - 44, rl.GetScreenHeight() / 2 + 48, 50, rl.Fade(rl.BLACK, alpha)) 149 | 150 | case .STATE_4: 151 | rl.DrawText("[R] REPLAY", 340, 200, 20, rl.GRAY) 152 | } 153 | rl.EndDrawing() 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /wgpu/microui/os_glfw.odin: -------------------------------------------------------------------------------- 1 | #+build !js 2 | package vendor_wgpu_example_microui 3 | 4 | import "core:log" 5 | import "core:math" 6 | import "core:strings" 7 | import "core:time" 8 | import "core:unicode/utf8" 9 | 10 | import "vendor:glfw" 11 | import "vendor:wgpu" 12 | import "vendor:wgpu/glfwglue" 13 | import mu "vendor:microui" 14 | 15 | OS :: struct { 16 | window: glfw.WindowHandle, 17 | } 18 | 19 | os_init :: proc() { 20 | if !glfw.Init() { 21 | panic("[glfw] init failure") 22 | } 23 | 24 | glfw.WindowHint(glfw.CLIENT_API, glfw.NO_API) 25 | state.os.window = glfw.CreateWindow(960, 540, "ODIN / GLFW / MICROUI / WGPU", nil, nil) 26 | assert(state.os.window != nil) 27 | 28 | glfw.SetKeyCallback(state.os.window, key_callback) 29 | glfw.SetMouseButtonCallback(state.os.window, mouse_button_callback) 30 | glfw.SetCursorPosCallback(state.os.window, cursor_pos_callback) 31 | glfw.SetScrollCallback(state.os.window, scroll_callback) 32 | glfw.SetCharCallback(state.os.window, char_callback) 33 | glfw.SetFramebufferSizeCallback(state.os.window, size_callback) 34 | } 35 | 36 | os_run :: proc() { 37 | for !glfw.WindowShouldClose(state.os.window) { 38 | glfw.PollEvents() 39 | do_frame() 40 | } 41 | 42 | glfw.DestroyWindow(state.os.window) 43 | glfw.Terminate() 44 | } 45 | 46 | @(private="file") 47 | do_frame :: proc() { 48 | @static frame_time: time.Tick 49 | if frame_time == {} { 50 | frame_time = time.tick_now() 51 | } 52 | 53 | new_frame_time := time.tick_now() 54 | dt := time.tick_diff(frame_time, new_frame_time) 55 | frame_time = new_frame_time 56 | 57 | frame(f32(time.duration_seconds(dt))) 58 | } 59 | 60 | os_get_render_bounds :: proc() -> (width, height: u32) { 61 | iw, ih := glfw.GetFramebufferSize(state.os.window) 62 | return u32(iw), u32(ih) 63 | } 64 | 65 | os_get_dpi :: proc() -> f32 { 66 | sw, sh := glfw.GetWindowContentScale(state.os.window) 67 | if sw != sh { 68 | log.warnf("dpi x (%v) and y (%v) not the same", sw, sh) 69 | } 70 | return sw 71 | } 72 | 73 | os_get_surface :: proc(instance: wgpu.Instance) -> wgpu.Surface { 74 | return glfwglue.GetSurface(instance, state.os.window) 75 | } 76 | 77 | os_set_clipboard :: proc(_: rawptr, text: string) -> bool { 78 | glfw.SetClipboardString(state.os.window, strings.clone_to_cstring(text, context.temp_allocator)) 79 | return true 80 | } 81 | 82 | os_get_clipboard :: proc(_: rawptr) -> (string, bool) { 83 | clipboard := glfw.GetClipboardString(state.os.window) 84 | return clipboard, true 85 | } 86 | 87 | @(private="file") 88 | key_callback :: proc "c" (window: glfw.WindowHandle, key, scancode, action, mods: i32) { 89 | context = state.ctx 90 | 91 | mu_key: mu.Key; switch key { 92 | case glfw.KEY_LEFT_SHIFT, glfw.KEY_RIGHT_SHIFT: mu_key = .ALT 93 | case glfw.KEY_LEFT_CONTROL, glfw.KEY_RIGHT_CONTROL, 94 | glfw.KEY_LEFT_SUPER, glfw.KEY_RIGHT_SUPER: mu_key = .CTRL 95 | case glfw.KEY_LEFT_ALT, glfw.KEY_RIGHT_ALT: mu_key = .ALT 96 | case glfw.KEY_BACKSPACE: mu_key = .BACKSPACE 97 | case glfw.KEY_DELETE: mu_key = .DELETE 98 | case glfw.KEY_ENTER: mu_key = .RETURN 99 | case glfw.KEY_LEFT: mu_key = .LEFT 100 | case glfw.KEY_RIGHT: mu_key = .RIGHT 101 | case glfw.KEY_HOME: mu_key = .HOME 102 | case glfw.KEY_END: mu_key = .END 103 | case glfw.KEY_A: mu_key = .A 104 | case glfw.KEY_X: mu_key = .X 105 | case glfw.KEY_C: mu_key = .C 106 | case glfw.KEY_V: mu_key = .V 107 | case: return 108 | } 109 | 110 | switch action { 111 | case glfw.PRESS, glfw.REPEAT: mu.input_key_down(&state.mu_ctx, mu_key) 112 | case glfw.RELEASE: mu.input_key_up (&state.mu_ctx, mu_key) 113 | case: return 114 | } 115 | } 116 | 117 | @(private="file") 118 | mouse_button_callback :: proc "c" (window: glfw.WindowHandle, key, action, mods: i32) { 119 | context = state.ctx 120 | 121 | mu_key: mu.Mouse; switch key { 122 | case glfw.MOUSE_BUTTON_MIDDLE: mu_key = .MIDDLE 123 | case glfw.MOUSE_BUTTON_LEFT: mu_key = .LEFT 124 | case glfw.MOUSE_BUTTON_RIGHT: mu_key = .RIGHT 125 | } 126 | 127 | switch action { 128 | case glfw.PRESS, glfw.REPEAT: mu.input_mouse_down(&state.mu_ctx, state.cursor.x, state.cursor.y, mu_key) 129 | case glfw.RELEASE: mu.input_mouse_up (&state.mu_ctx, state.cursor.x, state.cursor.y, mu_key) 130 | } 131 | } 132 | 133 | @(private="file") 134 | cursor_pos_callback :: proc "c" (window: glfw.WindowHandle, x, y: f64) { 135 | context = state.ctx 136 | state.cursor = {i32(math.round(x)), i32(math.round(y))} 137 | mu.input_mouse_move(&state.mu_ctx, state.cursor.x, state.cursor.y) 138 | } 139 | 140 | @(private="file") 141 | scroll_callback :: proc "c" (window: glfw.WindowHandle, x, y: f64) { 142 | context = state.ctx 143 | mu.input_scroll(&state.mu_ctx, -i32(math.round(x)), -i32(math.round(y))) 144 | } 145 | 146 | @(private="file") 147 | char_callback :: proc "c" (window: glfw.WindowHandle, ch: rune) { 148 | context = state.ctx 149 | bytes, size := utf8.encode_rune(ch) 150 | mu.input_text(&state.mu_ctx, string(bytes[:size])) 151 | } 152 | 153 | @(private="file") 154 | size_callback :: proc "c" (window: glfw.WindowHandle, width, height: i32) { 155 | context = state.ctx 156 | r_resize() 157 | do_frame() 158 | } 159 | -------------------------------------------------------------------------------- /metal/learn_metal/01-primitive/01-primitive.odin: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import NS "core:sys/darwin/Foundation" 4 | import MTL "vendor:darwin/Metal" 5 | import CA "vendor:darwin/QuartzCore" 6 | 7 | import SDL "vendor:sdl2" 8 | 9 | import "core:fmt" 10 | import "core:os" 11 | 12 | build_shaders :: proc(device: ^MTL.Device) -> (library: ^MTL.Library, pso: ^MTL.RenderPipelineState, err: ^NS.Error) { 13 | shader_src := ` 14 | #include 15 | using namespace metal; 16 | 17 | struct v2f { 18 | float4 position [[position]]; 19 | half3 color; 20 | }; 21 | 22 | v2f vertex vertex_main(uint vertex_id [[vertex_id]], 23 | device const packed_float3* positions [[buffer(0)]], 24 | device const packed_float3* colors [[buffer(1)]]) { 25 | v2f o; 26 | o.position = float4(positions[vertex_id], 1.0); 27 | o.color = half3(colors[vertex_id]); 28 | return o; 29 | } 30 | 31 | half4 fragment fragment_main(v2f in [[stage_in]]) { 32 | return half4(in.color, 1.0); 33 | } 34 | ` 35 | shader_src_str := NS.String.alloc()->initWithOdinString(shader_src) 36 | defer shader_src_str->release() 37 | 38 | library = device->newLibraryWithSource(shader_src_str, nil) or_return 39 | 40 | vertex_function := library->newFunctionWithName(NS.AT("vertex_main")) 41 | fragment_function := library->newFunctionWithName(NS.AT("fragment_main")) 42 | defer vertex_function->release() 43 | defer fragment_function->release() 44 | 45 | desc := MTL.RenderPipelineDescriptor.alloc()->init() 46 | defer desc->release() 47 | 48 | desc->setVertexFunction(vertex_function) 49 | desc->setFragmentFunction(fragment_function) 50 | desc->colorAttachments()->object(0)->setPixelFormat(.BGRA8Unorm_sRGB) 51 | 52 | pso = device->newRenderPipelineStateWithDescriptor(desc) or_return 53 | return 54 | } 55 | 56 | build_buffers :: proc(device: ^MTL.Device) -> (vertex_positions_buffer, vertex_colors_buffer: ^MTL.Buffer) { 57 | NUM_VERTICES :: 3 58 | positions := [NUM_VERTICES][3]f32{ 59 | {-0.8, 0.8, 0.0}, 60 | { 0.0, -0.8, 0.0}, 61 | {+0.8, 0.8, 0.0}, 62 | } 63 | colors := [NUM_VERTICES][3]f32{ 64 | {1.0, 0.3, 0.2}, 65 | {0.8, 1.0, 0.0}, 66 | {0.8, 0.0, 1.0}, 67 | } 68 | 69 | vertex_positions_buffer = device->newBufferWithSlice(positions[:], {.StorageModeManaged}) 70 | vertex_colors_buffer = device->newBufferWithSlice(colors[:], {.StorageModeManaged}) 71 | return 72 | } 73 | 74 | metal_main :: proc() -> (err: ^NS.Error) { 75 | SDL.SetHint(SDL.HINT_RENDER_DRIVER, "metal") 76 | SDL.setenv("METAL_DEVICE_WRAPPER_TYPE", "1", 0) 77 | SDL.Init({.VIDEO}) 78 | defer SDL.Quit() 79 | 80 | window := SDL.CreateWindow("Metal in Odin - 01 primitive", 81 | SDL.WINDOWPOS_CENTERED, SDL.WINDOWPOS_CENTERED, 82 | 854, 480, 83 | {.ALLOW_HIGHDPI, .HIDDEN, .RESIZABLE}, 84 | ) 85 | defer SDL.DestroyWindow(window) 86 | 87 | window_system_info: SDL.SysWMinfo 88 | SDL.GetVersion(&window_system_info.version) 89 | SDL.GetWindowWMInfo(window, &window_system_info) 90 | assert(window_system_info.subsystem == .COCOA) 91 | 92 | native_window := (^NS.Window)(window_system_info.info.cocoa.window) 93 | 94 | device := MTL.CreateSystemDefaultDevice() 95 | defer device->release() 96 | 97 | fmt.println(device->name()->odinString()) 98 | 99 | swapchain := CA.MetalLayer.layer() 100 | defer swapchain->release() 101 | 102 | swapchain->setDevice(device) 103 | swapchain->setPixelFormat(.BGRA8Unorm_sRGB) 104 | swapchain->setFramebufferOnly(true) 105 | swapchain->setFrame(native_window->frame()) 106 | 107 | native_window->contentView()->setLayer(swapchain) 108 | native_window->setOpaque(true) 109 | native_window->setBackgroundColor(nil) 110 | 111 | library, pso := build_shaders(device) or_return 112 | defer library->release() 113 | defer pso->release() 114 | 115 | vertex_positions_buffer, vertex_colors_buffer := build_buffers(device) 116 | defer vertex_positions_buffer->release() 117 | defer vertex_colors_buffer->release() 118 | 119 | command_queue := device->newCommandQueue() 120 | defer command_queue->release() 121 | 122 | SDL.ShowWindow(window) 123 | for quit := false; !quit; { 124 | for e: SDL.Event; SDL.PollEvent(&e); { 125 | #partial switch e.type { 126 | case .QUIT: 127 | quit = true 128 | case .KEYDOWN: 129 | if e.key.keysym.sym == .ESCAPE { 130 | quit = true 131 | } 132 | } 133 | } 134 | 135 | drawable := swapchain->nextDrawable() 136 | assert(drawable != nil) 137 | defer drawable->release() 138 | 139 | pass := MTL.RenderPassDescriptor.renderPassDescriptor() 140 | defer pass->release() 141 | 142 | color_attachment := pass->colorAttachments()->object(0) 143 | assert(color_attachment != nil) 144 | color_attachment->setClearColor(MTL.ClearColor{0.25, 0.5, 1.0, 1.0}) 145 | color_attachment->setLoadAction(.Clear) 146 | color_attachment->setStoreAction(.Store) 147 | color_attachment->setTexture(drawable->texture()) 148 | 149 | 150 | command_buffer := command_queue->commandBuffer() 151 | defer command_buffer->release() 152 | 153 | render_encoder := command_buffer->renderCommandEncoderWithDescriptor(pass) 154 | defer render_encoder->release() 155 | 156 | render_encoder->setRenderPipelineState(pso) 157 | render_encoder->setVertexBuffer(vertex_positions_buffer, 0, 0) 158 | render_encoder->setVertexBuffer(vertex_colors_buffer, 0, 1) 159 | render_encoder->drawPrimitives(.Triangle, 0, 3) 160 | 161 | render_encoder->endEncoding() 162 | 163 | command_buffer->presentDrawable(drawable) 164 | command_buffer->commit() 165 | } 166 | 167 | return nil 168 | } 169 | 170 | main :: proc() { 171 | err := metal_main() 172 | if err != nil { 173 | fmt.eprintln(err->localizedDescription()->odinString()) 174 | os.exit(1) 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /wgpu/microui/os_js.odin: -------------------------------------------------------------------------------- 1 | #+feature dynamic-literals 2 | package vendor_wgpu_example_microui 3 | 4 | import "core:sys/wasm/js" 5 | import "core:unicode" 6 | import "core:unicode/utf8" 7 | 8 | import "vendor:wgpu" 9 | import mu "vendor:microui" 10 | 11 | OS :: struct { 12 | initialized: bool, 13 | clipboard: [dynamic]byte, 14 | } 15 | 16 | os_init :: proc() { 17 | state.os.clipboard.allocator = context.allocator 18 | assert(js.add_window_event_listener(.Key_Down, nil, key_down_callback)) 19 | assert(js.add_window_event_listener(.Key_Up, nil, key_up_callback)) 20 | assert(js.add_window_event_listener(.Mouse_Down, nil, mouse_down_callback)) 21 | assert(js.add_window_event_listener(.Mouse_Up, nil, mouse_up_callback)) 22 | assert(js.add_event_listener("wgpu-canvas", .Mouse_Move, nil, mouse_move_callback)) 23 | assert(js.add_window_event_listener(.Wheel, nil, scroll_callback)) 24 | assert(js.add_window_event_listener(.Resize, nil, size_callback)) 25 | } 26 | 27 | // NOTE: frame loop is done by the runtime.js repeatedly calling `step`. 28 | os_run :: proc() { 29 | state.os.initialized = true 30 | } 31 | 32 | @(private="file", export) 33 | step :: proc(dt: f32) -> bool { 34 | context = state.ctx 35 | 36 | if !state.os.initialized { 37 | return true 38 | } 39 | 40 | frame(dt) 41 | return true 42 | } 43 | 44 | 45 | os_fini :: proc() { 46 | js.remove_window_event_listener(.Key_Down, nil, key_down_callback) 47 | js.remove_window_event_listener(.Key_Up, nil, key_up_callback) 48 | js.remove_window_event_listener(.Mouse_Down, nil, mouse_down_callback) 49 | js.remove_window_event_listener(.Mouse_Up, nil, mouse_up_callback) 50 | js.remove_event_listener("wgpu-canvas", .Mouse_Move, nil, mouse_move_callback) 51 | js.remove_window_event_listener(.Wheel, nil, scroll_callback) 52 | js.remove_window_event_listener(.Resize, nil, size_callback) 53 | } 54 | 55 | os_get_render_bounds :: proc() -> (width, height: u32) { 56 | rect := js.get_bounding_client_rect("body") 57 | dpi := os_get_dpi() 58 | return u32(f32(rect.width) * dpi), u32(f32(rect.height) * dpi) 59 | } 60 | 61 | os_get_dpi :: proc() -> f32 { 62 | ratio := f32(js.device_pixel_ratio()) 63 | return ratio 64 | } 65 | 66 | os_get_surface :: proc(instance: wgpu.Instance) -> wgpu.Surface { 67 | return wgpu.InstanceCreateSurface( 68 | instance, 69 | &wgpu.SurfaceDescriptor{ 70 | nextInChain = &wgpu.SurfaceSourceCanvasHTMLSelector{ 71 | sType = .SurfaceSourceCanvasHTMLSelector, 72 | selector = "#wgpu-canvas", 73 | }, 74 | }, 75 | ) 76 | } 77 | 78 | os_set_clipboard :: proc(_: rawptr, text: string) -> bool { 79 | // TODO: Use browser APIs 80 | clear(&state.os.clipboard) 81 | append(&state.os.clipboard, text) 82 | return true 83 | } 84 | 85 | os_get_clipboard :: proc(_: rawptr) -> (string, bool) { 86 | // TODO: Use browser APIs 87 | return string(state.os.clipboard[:]), true 88 | } 89 | 90 | @(private="file") 91 | KEY_MAP := map[string]mu.Key{ 92 | "ShiftLeft" = .SHIFT, 93 | "ShiftRight" = .SHIFT, 94 | "ControlLeft" = .CTRL, 95 | "ControlRight" = .CTRL, 96 | "MetaLeft" = .CTRL, 97 | "MetaRight" = .CTRL, 98 | "AltLeft" = .ALT, 99 | "AltRight" = .ALT, 100 | "Backspace" = .BACKSPACE, 101 | "Delete" = .DELETE, 102 | "Enter" = .RETURN, 103 | "ArrowLeft" = .LEFT, 104 | "ArrowRight" = .RIGHT, 105 | "Home" = .HOME, 106 | "End" = .END, 107 | "KeyA" = .A, 108 | "KeyX" = .X, 109 | "KeyC" = .C, 110 | "KeyV" = .V, 111 | } 112 | 113 | @(private="file") 114 | key_down_callback :: proc(e: js.Event) { 115 | context = state.ctx 116 | 117 | js.event_prevent_default() 118 | 119 | if k, ok := KEY_MAP[e.data.key.code]; ok { 120 | mu.input_key_down(&state.mu_ctx, k) 121 | } 122 | 123 | if .CTRL in state.mu_ctx.key_down_bits { 124 | return 125 | } 126 | 127 | ch, size := utf8.decode_rune(e.data.key.key) 128 | if len(e.data.key.key) == size && unicode.is_print(ch) { 129 | mu.input_text(&state.mu_ctx, e.data.key.key) 130 | } 131 | } 132 | 133 | @(private="file") 134 | key_up_callback :: proc(e: js.Event) { 135 | context = state.ctx 136 | 137 | if k, ok := KEY_MAP[e.data.key.code]; ok { 138 | mu.input_key_up(&state.mu_ctx, k) 139 | } 140 | 141 | js.event_prevent_default() 142 | } 143 | 144 | @(private="file") 145 | mouse_down_callback :: proc(e: js.Event) { 146 | context = state.ctx 147 | 148 | switch e.data.mouse.button { 149 | case 0: mu.input_mouse_down(&state.mu_ctx, state.cursor.x, state.cursor.y, .LEFT) 150 | case 1: mu.input_mouse_down(&state.mu_ctx, state.cursor.x, state.cursor.y, .MIDDLE) 151 | case 2: mu.input_mouse_down(&state.mu_ctx, state.cursor.x, state.cursor.y, .RIGHT) 152 | } 153 | 154 | js.event_prevent_default() 155 | } 156 | 157 | @(private="file") 158 | mouse_up_callback :: proc(e: js.Event) { 159 | context = state.ctx 160 | 161 | switch e.data.mouse.button { 162 | case 0: mu.input_mouse_up(&state.mu_ctx, state.cursor.x, state.cursor.y, .LEFT) 163 | case 1: mu.input_mouse_up(&state.mu_ctx, state.cursor.x, state.cursor.y, .MIDDLE) 164 | case 2: mu.input_mouse_up(&state.mu_ctx, state.cursor.x, state.cursor.y, .RIGHT) 165 | } 166 | 167 | js.event_prevent_default() 168 | } 169 | 170 | @(private="file") 171 | mouse_move_callback :: proc(e: js.Event) { 172 | context = state.ctx 173 | state.cursor = {i32(e.data.mouse.offset.x), i32(e.data.mouse.offset.y)} 174 | mu.input_mouse_move(&state.mu_ctx, state.cursor.x, state.cursor.y) 175 | } 176 | 177 | @(private="file") 178 | scroll_callback :: proc(e: js.Event) { 179 | context = state.ctx 180 | mu.input_scroll(&state.mu_ctx, i32(e.data.wheel.delta.x), i32(e.data.wheel.delta.y)) 181 | } 182 | 183 | @(private="file") 184 | size_callback :: proc(e: js.Event) { 185 | context = state.ctx 186 | r_resize() 187 | } 188 | -------------------------------------------------------------------------------- /sdl2/hellope/LICENSE.png.txt: -------------------------------------------------------------------------------- 1 | The source code to this library used with SDL_image can be found here: 2 | https://hg.libsdl.org/SDL_image/file/default/external 3 | --- 4 | COPYRIGHT NOTICE, DISCLAIMER, and LICENSE 5 | ========================================= 6 | 7 | PNG Reference Library License version 2 8 | --------------------------------------- 9 | 10 | * Copyright (c) 1995-2019 The PNG Reference Library Authors. 11 | * Copyright (c) 2018-2019 Cosmin Truta. 12 | * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. 13 | * Copyright (c) 1996-1997 Andreas Dilger. 14 | * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. 15 | 16 | The software is supplied "as is", without warranty of any kind, 17 | express or implied, including, without limitation, the warranties 18 | of merchantability, fitness for a particular purpose, title, and 19 | non-infringement. In no event shall the Copyright owners, or 20 | anyone distributing the software, be liable for any damages or 21 | other liability, whether in contract, tort or otherwise, arising 22 | from, out of, or in connection with the software, or the use or 23 | other dealings in the software, even if advised of the possibility 24 | of such damage. 25 | 26 | Permission is hereby granted to use, copy, modify, and distribute 27 | this software, or portions hereof, for any purpose, without fee, 28 | subject to the following restrictions: 29 | 30 | 1. The origin of this software must not be misrepresented; you 31 | must not claim that you wrote the original software. If you 32 | use this software in a product, an acknowledgment in the product 33 | documentation would be appreciated, but is not required. 34 | 35 | 2. Altered source versions must be plainly marked as such, and must 36 | not be misrepresented as being the original software. 37 | 38 | 3. This Copyright notice may not be removed or altered from any 39 | source or altered source distribution. 40 | 41 | 42 | PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) 43 | ----------------------------------------------------------------------- 44 | 45 | libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are 46 | Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are 47 | derived from libpng-1.0.6, and are distributed according to the same 48 | disclaimer and license as libpng-1.0.6 with the following individuals 49 | added to the list of Contributing Authors: 50 | 51 | Simon-Pierre Cadieux 52 | Eric S. Raymond 53 | Mans Rullgard 54 | Cosmin Truta 55 | Gilles Vollant 56 | James Yu 57 | Mandar Sahastrabuddhe 58 | Google Inc. 59 | Vadim Barkov 60 | 61 | and with the following additions to the disclaimer: 62 | 63 | There is no warranty against interference with your enjoyment of 64 | the library or against infringement. There is no warranty that our 65 | efforts or the library will fulfill any of your particular purposes 66 | or needs. This library is provided with all faults, and the entire 67 | risk of satisfactory quality, performance, accuracy, and effort is 68 | with the user. 69 | 70 | Some files in the "contrib" directory and some configure-generated 71 | files that are distributed with libpng have other copyright owners, and 72 | are released under other open source licenses. 73 | 74 | libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are 75 | Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from 76 | libpng-0.96, and are distributed according to the same disclaimer and 77 | license as libpng-0.96, with the following individuals added to the 78 | list of Contributing Authors: 79 | 80 | Tom Lane 81 | Glenn Randers-Pehrson 82 | Willem van Schaik 83 | 84 | libpng versions 0.89, June 1996, through 0.96, May 1997, are 85 | Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, 86 | and are distributed according to the same disclaimer and license as 87 | libpng-0.88, with the following individuals added to the list of 88 | Contributing Authors: 89 | 90 | John Bowler 91 | Kevin Bracey 92 | Sam Bushell 93 | Magnus Holmgren 94 | Greg Roelofs 95 | Tom Tanner 96 | 97 | Some files in the "scripts" directory have other copyright owners, 98 | but are released under this license. 99 | 100 | libpng versions 0.5, May 1995, through 0.88, January 1996, are 101 | Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. 102 | 103 | For the purposes of this copyright and license, "Contributing Authors" 104 | is defined as the following set of individuals: 105 | 106 | Andreas Dilger 107 | Dave Martindale 108 | Guy Eric Schalnat 109 | Paul Schmidt 110 | Tim Wegner 111 | 112 | The PNG Reference Library is supplied "AS IS". The Contributing 113 | Authors and Group 42, Inc. disclaim all warranties, expressed or 114 | implied, including, without limitation, the warranties of 115 | merchantability and of fitness for any purpose. The Contributing 116 | Authors and Group 42, Inc. assume no liability for direct, indirect, 117 | incidental, special, exemplary, or consequential damages, which may 118 | result from the use of the PNG Reference Library, even if advised of 119 | the possibility of such damage. 120 | 121 | Permission is hereby granted to use, copy, modify, and distribute this 122 | source code, or portions hereof, for any purpose, without fee, subject 123 | to the following restrictions: 124 | 125 | 1. The origin of this source code must not be misrepresented. 126 | 127 | 2. Altered versions must be plainly marked as such and must not 128 | be misrepresented as being the original source. 129 | 130 | 3. This Copyright notice may not be removed or altered from any 131 | source or altered source distribution. 132 | 133 | The Contributing Authors and Group 42, Inc. specifically permit, 134 | without fee, and encourage the use of this source code as a component 135 | to supporting the PNG file format in commercial products. If you use 136 | this source code in a product, acknowledgment is not required but would 137 | be appreciated. 138 | -------------------------------------------------------------------------------- /wgpu/sdl3-triangle/main.odin: -------------------------------------------------------------------------------- 1 | package vendor_wgpu_example_triangle 2 | 3 | import "base:runtime" 4 | 5 | import "core:fmt" 6 | 7 | import "vendor:wgpu" 8 | 9 | state: struct { 10 | ctx: runtime.Context, 11 | os: OS, 12 | 13 | instance: wgpu.Instance, 14 | surface: wgpu.Surface, 15 | adapter: wgpu.Adapter, 16 | device: wgpu.Device, 17 | config: wgpu.SurfaceConfiguration, 18 | queue: wgpu.Queue, 19 | module: wgpu.ShaderModule, 20 | pipeline_layout: wgpu.PipelineLayout, 21 | pipeline: wgpu.RenderPipeline, 22 | } 23 | 24 | main :: proc() { 25 | state.ctx = context 26 | 27 | os_init() 28 | 29 | state.instance = wgpu.CreateInstance(nil) 30 | if state.instance == nil { 31 | panic("WebGPU is not supported") 32 | } 33 | state.surface = os_get_surface(state.instance) 34 | 35 | wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, { callback = on_adapter }) 36 | 37 | on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: string, userdata1, userdata2: rawptr) { 38 | context = state.ctx 39 | if status != .Success || adapter == nil { 40 | fmt.panicf("request adapter failure: [%v] %s", status, message) 41 | } 42 | state.adapter = adapter 43 | wgpu.AdapterRequestDevice(adapter, nil, { callback = on_device }) 44 | } 45 | 46 | on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: string, userdata1, userdata2: rawptr) { 47 | context = state.ctx 48 | if status != .Success || device == nil { 49 | fmt.panicf("request device failure: [%v] %s", status, message) 50 | } 51 | state.device = device 52 | 53 | width, height := os_get_framebuffer_size() 54 | 55 | state.config = wgpu.SurfaceConfiguration { 56 | device = state.device, 57 | usage = { .RenderAttachment }, 58 | format = .BGRA8Unorm, 59 | width = width, 60 | height = height, 61 | presentMode = .Fifo, 62 | alphaMode = .Opaque, 63 | } 64 | wgpu.SurfaceConfigure(state.surface, &state.config) 65 | 66 | state.queue = wgpu.DeviceGetQueue(state.device) 67 | 68 | shader :: ` 69 | @vertex 70 | fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { 71 | let x = f32(i32(in_vertex_index) - 1); 72 | let y = f32(i32(in_vertex_index & 1u) * 2 - 1); 73 | return vec4(x, y, 0.0, 1.0); 74 | } 75 | 76 | @fragment 77 | fn fs_main() -> @location(0) vec4 { 78 | return vec4(1.0, 0.0, 0.0, 1.0); 79 | }` 80 | 81 | state.module = wgpu.DeviceCreateShaderModule(state.device, &{ 82 | nextInChain = &wgpu.ShaderSourceWGSL{ 83 | sType = .ShaderSourceWGSL, 84 | code = shader, 85 | }, 86 | }) 87 | 88 | state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{}) 89 | state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{ 90 | layout = state.pipeline_layout, 91 | vertex = { 92 | module = state.module, 93 | entryPoint = "vs_main", 94 | }, 95 | fragment = &{ 96 | module = state.module, 97 | entryPoint = "fs_main", 98 | targetCount = 1, 99 | targets = &wgpu.ColorTargetState{ 100 | format = .BGRA8Unorm, 101 | writeMask = wgpu.ColorWriteMaskFlags_All, 102 | }, 103 | }, 104 | primitive = { 105 | topology = .TriangleList, 106 | 107 | }, 108 | multisample = { 109 | count = 1, 110 | mask = 0xFFFFFFFF, 111 | }, 112 | }) 113 | 114 | os_run() 115 | } 116 | } 117 | 118 | resize :: proc "c" () { 119 | context = state.ctx 120 | 121 | state.config.width, state.config.height = os_get_framebuffer_size() 122 | wgpu.SurfaceConfigure(state.surface, &state.config) 123 | } 124 | 125 | frame :: proc "c" (dt: f32) { 126 | context = state.ctx 127 | 128 | surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface) 129 | switch surface_texture.status { 130 | case .SuccessOptimal, .SuccessSuboptimal: 131 | // All good, could handle suboptimal here. 132 | case .Timeout, .Outdated, .Lost: 133 | // Skip this frame, and re-configure surface. 134 | if surface_texture.texture != nil { 135 | wgpu.TextureRelease(surface_texture.texture) 136 | } 137 | resize() 138 | return 139 | case .OutOfMemory, .DeviceLost, .Error: 140 | // Fatal error 141 | fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status) 142 | } 143 | defer wgpu.TextureRelease(surface_texture.texture) 144 | 145 | frame := wgpu.TextureCreateView(surface_texture.texture, nil) 146 | defer wgpu.TextureViewRelease(frame) 147 | 148 | command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil) 149 | defer wgpu.CommandEncoderRelease(command_encoder) 150 | 151 | render_pass_encoder := wgpu.CommandEncoderBeginRenderPass( 152 | command_encoder, &{ 153 | colorAttachmentCount = 1, 154 | colorAttachments = &wgpu.RenderPassColorAttachment{ 155 | view = frame, 156 | loadOp = .Clear, 157 | storeOp = .Store, 158 | depthSlice = wgpu.DEPTH_SLICE_UNDEFINED, 159 | clearValue = { 0, 1, 0, 1 }, 160 | }, 161 | }, 162 | ) 163 | 164 | wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline) 165 | wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) 166 | 167 | wgpu.RenderPassEncoderEnd(render_pass_encoder) 168 | wgpu.RenderPassEncoderRelease(render_pass_encoder) 169 | 170 | command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil) 171 | defer wgpu.CommandBufferRelease(command_buffer) 172 | 173 | wgpu.QueueSubmit(state.queue, { command_buffer }) 174 | wgpu.SurfacePresent(state.surface) 175 | } 176 | 177 | finish :: proc() { 178 | wgpu.RenderPipelineRelease(state.pipeline) 179 | wgpu.PipelineLayoutRelease(state.pipeline_layout) 180 | wgpu.ShaderModuleRelease(state.module) 181 | wgpu.QueueRelease(state.queue) 182 | wgpu.DeviceRelease(state.device) 183 | wgpu.AdapterRelease(state.adapter) 184 | wgpu.SurfaceRelease(state.surface) 185 | wgpu.InstanceRelease(state.instance) 186 | } 187 | -------------------------------------------------------------------------------- /wgpu/glfw-triangle/main.odin: -------------------------------------------------------------------------------- 1 | package vendor_wgpu_example_triangle 2 | 3 | import "base:runtime" 4 | 5 | import "core:fmt" 6 | 7 | import "vendor:wgpu" 8 | 9 | state: struct { 10 | ctx: runtime.Context, 11 | os: OS, 12 | 13 | instance: wgpu.Instance, 14 | surface: wgpu.Surface, 15 | adapter: wgpu.Adapter, 16 | device: wgpu.Device, 17 | config: wgpu.SurfaceConfiguration, 18 | queue: wgpu.Queue, 19 | module: wgpu.ShaderModule, 20 | pipeline_layout: wgpu.PipelineLayout, 21 | pipeline: wgpu.RenderPipeline, 22 | } 23 | 24 | main :: proc() { 25 | state.ctx = context 26 | 27 | os_init() 28 | 29 | state.instance = wgpu.CreateInstance(nil) 30 | if state.instance == nil { 31 | panic("WebGPU is not supported") 32 | } 33 | state.surface = os_get_surface(state.instance) 34 | 35 | wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, { callback = on_adapter }) 36 | 37 | on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: string, userdata1: rawptr, userdata2: rawptr) { 38 | context = state.ctx 39 | if status != .Success || adapter == nil { 40 | fmt.panicf("request adapter failure: [%v] %s", status, message) 41 | } 42 | state.adapter = adapter 43 | wgpu.AdapterRequestDevice(adapter, nil, { callback = on_device }) 44 | } 45 | 46 | on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: string, userdata1: rawptr, userdata2: rawptr) { 47 | context = state.ctx 48 | if status != .Success || device == nil { 49 | fmt.panicf("request device failure: [%v] %s", status, message) 50 | } 51 | state.device = device 52 | 53 | width, height := os_get_framebuffer_size() 54 | 55 | state.config = wgpu.SurfaceConfiguration { 56 | device = state.device, 57 | usage = { .RenderAttachment }, 58 | format = .BGRA8Unorm, 59 | width = width, 60 | height = height, 61 | presentMode = .Fifo, 62 | alphaMode = .Opaque, 63 | } 64 | wgpu.SurfaceConfigure(state.surface, &state.config) 65 | 66 | state.queue = wgpu.DeviceGetQueue(state.device) 67 | 68 | shader :: ` 69 | @vertex 70 | fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { 71 | let x = f32(i32(in_vertex_index) - 1); 72 | let y = f32(i32(in_vertex_index & 1u) * 2 - 1); 73 | return vec4(x, y, 0.0, 1.0); 74 | } 75 | 76 | @fragment 77 | fn fs_main() -> @location(0) vec4 { 78 | return vec4(1.0, 0.0, 0.0, 1.0); 79 | }` 80 | 81 | state.module = wgpu.DeviceCreateShaderModule(state.device, &{ 82 | nextInChain = &wgpu.ShaderSourceWGSL{ 83 | sType = .ShaderSourceWGSL, 84 | code = shader, 85 | }, 86 | }) 87 | 88 | state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{}) 89 | state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{ 90 | layout = state.pipeline_layout, 91 | vertex = { 92 | module = state.module, 93 | entryPoint = "vs_main", 94 | }, 95 | fragment = &{ 96 | module = state.module, 97 | entryPoint = "fs_main", 98 | targetCount = 1, 99 | targets = &wgpu.ColorTargetState{ 100 | format = .BGRA8Unorm, 101 | writeMask = wgpu.ColorWriteMaskFlags_All, 102 | }, 103 | }, 104 | primitive = { 105 | topology = .TriangleList, 106 | 107 | }, 108 | multisample = { 109 | count = 1, 110 | mask = 0xFFFFFFFF, 111 | }, 112 | }) 113 | 114 | os_run() 115 | } 116 | } 117 | 118 | resize :: proc "c" () { 119 | context = state.ctx 120 | 121 | state.config.width, state.config.height = os_get_framebuffer_size() 122 | wgpu.SurfaceConfigure(state.surface, &state.config) 123 | } 124 | 125 | frame :: proc "c" (dt: f32) { 126 | context = state.ctx 127 | 128 | surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface) 129 | switch surface_texture.status { 130 | case .SuccessOptimal, .SuccessSuboptimal: 131 | // All good, could handle suboptimal here. 132 | case .Timeout, .Outdated, .Lost: 133 | // Skip this frame, and re-configure surface. 134 | if surface_texture.texture != nil { 135 | wgpu.TextureRelease(surface_texture.texture) 136 | } 137 | resize() 138 | return 139 | case .OutOfMemory, .DeviceLost, .Error: 140 | // Fatal error 141 | fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status) 142 | } 143 | defer wgpu.TextureRelease(surface_texture.texture) 144 | 145 | frame := wgpu.TextureCreateView(surface_texture.texture, nil) 146 | defer wgpu.TextureViewRelease(frame) 147 | 148 | command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil) 149 | defer wgpu.CommandEncoderRelease(command_encoder) 150 | 151 | render_pass_encoder := wgpu.CommandEncoderBeginRenderPass( 152 | command_encoder, &{ 153 | colorAttachmentCount = 1, 154 | colorAttachments = &wgpu.RenderPassColorAttachment{ 155 | view = frame, 156 | loadOp = .Clear, 157 | storeOp = .Store, 158 | depthSlice = wgpu.DEPTH_SLICE_UNDEFINED, 159 | clearValue = { 0, 1, 0, 1 }, 160 | }, 161 | }, 162 | ) 163 | 164 | wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline) 165 | wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) 166 | 167 | wgpu.RenderPassEncoderEnd(render_pass_encoder) 168 | wgpu.RenderPassEncoderRelease(render_pass_encoder) 169 | 170 | command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil) 171 | defer wgpu.CommandBufferRelease(command_buffer) 172 | 173 | wgpu.QueueSubmit(state.queue, { command_buffer }) 174 | wgpu.SurfacePresent(state.surface) 175 | } 176 | 177 | finish :: proc() { 178 | wgpu.RenderPipelineRelease(state.pipeline) 179 | wgpu.PipelineLayoutRelease(state.pipeline_layout) 180 | wgpu.ShaderModuleRelease(state.module) 181 | wgpu.QueueRelease(state.queue) 182 | wgpu.DeviceRelease(state.device) 183 | wgpu.AdapterRelease(state.adapter) 184 | wgpu.SurfaceRelease(state.surface) 185 | wgpu.InstanceRelease(state.instance) 186 | } 187 | --------------------------------------------------------------------------------