├── 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 | 
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 | 
37 |
38 | ### [01-primitive](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/01-primitive)
39 |
40 | 
41 |
42 | ### [02-argbuffers](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/02-argbuffers)
43 |
44 | 
45 |
46 | ### [03-animation](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/03-animation)
47 |
48 | 
49 |
50 | ### [04-instancing](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/04-instancing)
51 |
52 | 
53 |
54 | ### [05-perspective](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/05-perspective)
55 |
56 | 
57 |
58 | ### [06-lighting](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/06-lighting)
59 |
60 | 
61 |
62 | ### [07-texturing](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/07-texturing)
63 |
64 | 
65 |
66 | ### [08-compute](https://github.com/odin-lang/examples/tree/master/metal/learn_metal/08-compute)
67 |
68 | 
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 |
--------------------------------------------------------------------------------