Compare commits

..

113 Commits

Author SHA1 Message Date
Nikolas
a4d18b2d1c
Add init functions from Zig vectors to raylib vectors 2025-11-15 19:36:39 +01:00
Nikolas
3cd4d3179d
Bundle raylib artifact with raylib module
Co-authored-by: haxsam <haxsam@pm.me>
2025-10-30 22:21:33 +01:00
Maicon Santana
6ecc0455eb
[examples] Add core_monitor_change and shaders_ascii_rendering (#293)
* Add monitor_change example

* Adding `core_monitor_change` and `shaders_ascii_rendering` examples
2025-10-26 16:00:10 +01:00
maiconpintoabreu
d9933008f5 Add ported solar system example 2025-10-26 15:59:39 +01:00
Nikolas
163b1ef2e9
Bump raylib to master (#283) 2025-10-09 17:52:41 +02:00
maiconpintoabreu
1e257d1738 Add box collisions and add unload for modelanimations for bone socket 2025-09-30 19:23:12 +02:00
maiconpintoabreu
a1d02a5ec8 Add bone socket example 2025-09-27 11:25:45 +02:00
Nikolas
0248dc6e98
Bump raylib to master 2025-09-21 18:27:42 +02:00
Mike Moseley
d64fc43f38 examples: transition from deprecated writer 2025-09-18 22:30:31 +02:00
Nikolas
39ce5d4a8e
Update zemscripten (#286) 2025-09-15 20:18:07 +02:00
Nikolas
33f216d4fc
Make Gesture a packed struct (#284) 2025-09-11 19:24:23 +02:00
Nikolas
651b37a025
Formatting 2025-09-11 19:24:23 +02:00
Timothy Fiss
c84506a92d replace c_int with NPatchType 2025-09-06 20:30:52 +02:00
Nikolas
9ad8b8ba74
Fix zig fetch command for emsdk 2025-09-01 20:51:30 +02:00
Jorn
c7ea429994 update readme
`error: invalid option: -Dshared` by Zig 0.15.1
changed to .linkage = .dynamic
2025-09-01 16:30:21 +02:00
Nikolas
ed42d5dbdc
Cleanup embed paths for emsdk 2025-08-31 16:57:11 +02:00
Nikolas
c5d9cf405d
Fix project templates (#278) 2025-08-31 16:55:14 +02:00
Nikolas
acd5507b0e
Bump raylib to master (#278) 2025-08-31 16:42:31 +02:00
haxsam
b44a355a81 [build.zig]: a concrete approach to build for web 2025-08-31 16:42:21 +02:00
Timothy Fiss
df70c5c952 rename existing examples for consistent naming 2025-08-25 18:22:36 +02:00
Timothy Fiss
4bb5254d6b example: add unicode 2025-08-25 18:22:36 +02:00
Timothy Fiss
e623387b8c example: add rectangle_bounds 2025-08-25 18:22:36 +02:00
Timothy Fiss
166996bccc example: add input_box 2025-08-25 18:22:36 +02:00
Timothy Fiss
42956d00c0 example: add font_spritefont 2025-08-25 18:22:36 +02:00
Timothy Fiss
d39c75c234 example: add font_sdf.zig 2025-08-25 18:22:36 +02:00
Timothy Fiss
180d2e04de example: add font_loading 2025-08-25 18:22:36 +02:00
Timothy Fiss
10c8f7d7ad add all the text resources 2025-08-25 18:22:36 +02:00
Timothy Fiss
6efd4175ef add: example font_filters, fix typo
example font_filters
2025-08-25 18:22:36 +02:00
Timothy Fiss
a787270fea example: add draw_3d 2025-08-25 18:22:36 +02:00
Timothy Fiss
6ab4e51407 example: add codepoints_loading
update c_l to include copywrite header and description
2025-08-25 18:22:36 +02:00
Nikolas
3c33e0469f
Format project templates 2025-08-25 15:47:31 +02:00
stanchyk7
55937dd8a9 Update project_setup.ps1 for Zig 0.15.1 2025-08-25 15:43:44 +02:00
stanchyk7
492e809dd5 Update project_setup.sh for Zig 0.15.1 2025-08-25 15:43:33 +02:00
Nikolas
178530d5f5
Update to Zig 0.15.1 2025-08-23 15:32:42 +02:00
Mike Will
dfea9ed840 add examples shaders_basic_pbr and shaders_hybrid_render 2025-08-09 18:55:54 +02:00
Timothy Fiss
125ead95a3 example: add top_down_lights 2025-08-09 18:51:00 +02:00
Timothy Fiss
813f0323af example: add splines_drawing 2025-08-09 18:51:00 +02:00
Timothy Fiss
346e87c8aa example: add easings_rectange_array 2025-08-09 18:51:00 +02:00
Timothy Fiss
be3790195a example: add easings_box_anim 2025-08-09 18:51:00 +02:00
Timothy Fiss
52767eb8ae example: add easing_ball_anim 2025-08-09 18:51:00 +02:00
Nikolas
b7d89cb7b9
Repository move 2025-08-07 21:27:11 +02:00
Maicon Santana
7bdb0cd320
Add unload on missing types (#267) 2025-08-07 19:41:01 +02:00
Nikolas
a6e9ce520f
Return rectangle list without taking it as an arg in genImageFontAtlas (#263) 2025-08-03 14:21:44 +02:00
Nikolas
3eee232f10
Make codepoints in loadFontData optional (#263) 2025-08-03 13:56:43 +02:00
Nikolas
22bb251252
Use addModule instead of createModule again (#265) (partial revert of #264) 2025-08-03 13:23:46 +02:00
Maicon Santana
ac0b07c4bd
prepare build to run on zig 15 (#264)
* prepare build to run on zig 15

* set raylib as static for web
2025-08-01 18:54:55 +02:00
leonardo-kr
e8167c2e56
add dropped files example (#260)
* add dropped files example

* reformat build.zig
2025-07-23 16:24:56 +02:00
Mike Will
14f49a38dd
update name changes for rgui's sliderBar and checkBox functions in examples (#252)
update name changes for rgui's `sliderBar` and `checkBox` in examples
2025-07-23 16:21:50 +02:00
Nikolas
5013830647
Bump raylib to master (#239, #243, #249) 2025-06-27 15:00:18 +02:00
Maicon Santana
97cb212bf0
remove emrun from emcc to avoid the game to keep calling stdio.html (#238)
* remove emrun from emcc to avoid the game to keep calling stdio.html

* Remove formater

* Add --emrun for examples and templates
2025-06-27 13:24:07 +02:00
Nikolas
3bf08a304c
Fix return type for raygui.labelButton 2025-05-04 17:31:08 +02:00
Nikolas
2e60ac0127
Fixup RAYLIB_VERSION constant (#236) 2025-05-01 17:16:16 +02:00
Daniel Hill
0de5f8aed0 fix(raygui): make some funcs return bool instead of i32 2025-04-20 13:50:02 +02:00
Daniel Hill
67fd5af55a fix(raygui): strip "Gui" prefix from Zig functions 2025-04-20 13:50:02 +02:00
Daniel Hill
f4b69764db feat(raygui): get message box example working 2025-04-20 13:50:02 +02:00
Nikolas
d6c77762cb
Automatically generate functions that return their slice length, where possible 2025-03-30 19:29:51 +02:00
Nikolas
c30197911a
Add loadRandomSequence 2025-03-30 18:05:49 +02:00
Tommy D. Rossi
a00552ea79
Fix exportImageToMemory (#232)
* fix exportImageToMemory

* update make_return_cast
2025-03-30 18:00:07 +02:00
Nikolas
e072ff119b
Update raylib/raygui to latest master (#231) 2025-03-23 20:01:44 +01:00
Axel Magnuson
dfe22275cf
Core 2D Camera Platformer Example (#222)
* Core 2D Camera Platformer Example

* Use decl literals for enums in platformer example
2025-03-23 19:52:05 +01:00
Erazem Kos
8d5a7d382c
Update feature macro documentation for zig 0.14.0 (#225)
Update feature macro documentation for zig 0.14.0
2025-03-20 12:00:40 +01:00
Mike Will
d4fc514d54
examples: Use decl literals (#221) 2025-03-12 21:21:15 +01:00
Nikolas
03ec79ef85
Manually include ubsan in emscripten builds (#220) 2025-03-12 21:16:53 +01:00
Nikolas
17a1754271
Update raylib hash so we get the new shiny build.zig.zon 2025-03-10 14:07:10 +01:00
Nikolas
a7f626993c
Fix basic_window_web, where a bool was passed to an int 2025-03-10 13:27:50 +01:00
Rik Chilvers
5bbafa4f86
Work around zig#23051 (#216) 2025-03-06 22:37:40 +01:00
Nikolas
b6af3509c8
Update raylib ad raygui in build.zig.zon 2025-03-06 15:26:13 +01:00
Nikolas
e18e2db5e5
Make secretViewActive in guiTextInputBox optional (#205) 2025-03-06 15:24:09 +01:00
kukuen
1a9b848c06
Port of basic_window_web from raylib (#210)
Port basic_window_web from raylib
2025-03-06 15:19:10 +01:00
Nikolas
279bcc0a13
Update to new forced literal (#213) 2025-03-06 15:17:23 +01:00
Nikolas
9444b5a438
Use zig init in project template 2025-03-06 15:14:45 +01:00
Nikolas
57a8a21b48
Update Zig version in README 2025-03-05 18:20:56 +01:00
Nikolas
9e69ca5946
Merge changes from devel 2025-03-05 18:16:21 +01:00
Nikolas
1b6a05ca3b
Update to Zig 0.14.0 and raylib 5.6-dev 2025-03-05 18:09:59 +01:00
Nikolas
e4d66a8dae
Perform colorToInt conversion manually during compiletime (#176) 2025-03-04 17:50:50 +01:00
Nikolas
94fa7e23b0
Finish move to sentinal terminated slices (#203) 2025-03-04 17:50:23 +01:00
Nikolas
bc82c6ebd7
Move from sentinel-terminated pointers to sentinel-terminated slices globally ([+:0] -> [:0]) (#203) 2025-02-24 16:44:49 +01:00
Michael Lohr
4d452b2bcd
Add raymarching example (#208)
* feat: add raymarching example

* add to build.zig
2025-02-16 19:44:48 +01:00
Woshiwuja
8e5ef1045d
Added heightmap example (#206)
* added heightmap example

* better formatting
2025-02-16 19:43:02 +01:00
Frost-Phoenix
d3fdd327d5 example: add audio_module_playing 2025-02-16 19:41:48 +01:00
Frost-Phoenix
09ec2ca22b example: add audio_sound_loading 2025-02-16 19:41:48 +01:00
Frost-Phoenix
9882dd4ba1 example: add audio_music_stream 2025-02-16 19:41:48 +01:00
Frost-Phoenix
5004bb2316 example: add text_writing_anim 2025-02-02 12:24:49 +01:00
Frost-Phoenix
9faf4b97a1 add text_raylib_fonts example
remove unused import and simplify code
2025-02-02 12:24:49 +01:00
Klaus
58724227e7
Fixing linker error for raygui when building in shared mode. (#197) 2025-01-26 16:32:48 +01:00
haxsam
ae7cb3fa93
Update to latest zig master
updated raylib and raygui
2025-01-18 22:08:45 +01:00
haxsam
ae76994a2d [build.zig] improve build system
- Is now possible to switch platform

- Forwarded option structs from raylib build.zig

- raygui build step depends on raylib build.zig
2025-01-18 22:08:08 +01:00
vent
1ef4995f82
Fix zig build test (#192) 2025-01-12 21:52:40 +01:00
vent
cb9fb452c6
Fix segault in textures_image_loading (#190) 2025-01-11 18:09:12 +01:00
vent
41022159ad
Error check using IsValid functions and return error unions (#191)
* Verify shaders are valid

* Verify images are valid

* Verify models are valid

* Verify materials are valid

* Verify textures are valid

* Verify render textures are valid

* Verify waves are valid

* Verify sounds are valid

* Verify music is valid

* Verify audio streams are valid

* Verify fonts are valid

* Update examples to handle error unions
2025-01-11 18:07:33 +01:00
James Davis
30ce68004f
Use GamepadAxis enum for getGamepadAxisMovement instead of c_int (#187)
* Updated getGamepadAxisMovement to take enum and cast return to f32

* Updated raylib-ext.zig GetGamepadAxisMovement to take enum

* modified generate_functions.py to make changes instead
2025-01-10 19:18:45 +01:00
Josh Lankford
561481f4ae add new shape examples to build.zig 2025-01-10 19:16:57 +01:00
Josh Lankford
f8b1495c69 add draw rectangle rounded example 2025-01-10 19:16:57 +01:00
Josh Lankford
882b69d8c9 add draw circle sector example 2025-01-10 19:16:57 +01:00
Josh Lankford
9f30de1eac add draw ring example 2025-01-10 19:16:57 +01:00
Josh Lankford
3720deda6d add following eyes example 2025-01-10 19:16:57 +01:00
Josh Lankford
a7deec3964 add collision area example 2025-01-10 19:16:57 +01:00
Josh Lankford
2fcdf3af45 add lines bezier example 2025-01-10 19:16:57 +01:00
Josh Lankford
16f4871846 add rectangle scaling example 2025-01-10 19:16:57 +01:00
Josh Lankford
21e7bb8cd3 add raylib logo animation example 2025-01-10 19:16:57 +01:00
Josh Lankford
2a569ea2ef add color palette example 2025-01-10 19:16:57 +01:00
Josh Lankford
4e08de5584 add bouncing ball example 2025-01-10 19:16:57 +01:00
Josh Lankford
350388c8ec add basic shapes example 2025-01-10 19:16:57 +01:00
raugl
4e05ee5a3f
Added missing variadic arguments to traceLog() (#186)
* Added missing variadic arguments to `traceLog()`

* Made changes resillient to `generate_function.py`
2025-01-06 17:26:37 +01:00
Not-Nik
57041e707c
[raygui] Allow GuiControlProperty and GuiDefaultProperty as types for property in GuiGetStyle/GuiSetStyle (#131) 2025-01-04 00:24:09 +01:00
Not-Nik
16a388c9c2
Fix build errors related to update to rl 5.5 2025-01-03 23:56:01 +01:00
Kaio Delphino
265461f4ec
fix: MATERIAL and SHADER_LOC default values (#183)
These constants were assigned to inexistent enums.
2025-01-03 23:43:27 +01:00
vent
845af357e4
Remove redundant namespaces from enums (#178) 2024-12-23 21:27:02 +01:00
Alexander Moening
0dcee846f4
Add both field for runtime Linux platform detection (#179)
Add `both` field to allow GLFW to use runtime platform detection
2024-12-20 17:12:46 +01:00
Daniel Koucher Machado
de8c2d4585
Automatically include Emscripten headers (#173)
* add emscripten headers

* update func to return error
2024-11-26 20:18:33 +01:00
Michał
606d9bb9ba
raylib: add missing fields to Mesh struct (#175)
Add missing veoId and vboId fields to the Mesh struct. This fixes
some crashes when meshes are being manipulated on the Zig side, for
example when genMesh* functions are used.
2024-11-26 20:16:46 +01:00
Jonathan Marler
94570c4b60
fix zig fetch command in README (#130)
* fix zig fetch command in README

All URLs within build.zig.zon files must point to archives that never
change.  However, the zig fetch command in the README.md adds a URL
that points to the `devel` git branch whose content changes whenever
the `devel` branch is updated.

I've updated the README a url that zig will resolve to a SHA before it
writes it to the zon file.

* Update template scripts

---------

Co-authored-by: Not-Nik <nik.wipper@gmx.de>
2024-11-25 14:19:38 +01:00
Андрей Краевский
ff775330c7
Update raylib to version 5.5 (#174) 2024-11-25 14:18:03 +01:00
143 changed files with 15011 additions and 3267 deletions

View File

@ -1,12 +1,12 @@
![logo](https://github.com/Not-Nik/raylib-zig/raw/devel/logo/logo.png)
![logo](https://github.com/raylib-zig/raylib-zig/raw/devel/logo/logo.png)
# raylib-zig
Manually tweaked, auto-generated [raylib](https://github.com/raysan5/raylib) bindings for zig.
Bindings tested on raylib version 5.5-dev and Zig 0.13.0
Bindings tested on raylib version 5.6-dev and Zig 0.15.1
Thanks to all the [contributors](https://github.com/Not-Nik/raylib-zig/graphs/contributors) for their help with this
Thanks to all the [contributors](https://github.com/raylib-zig/raylib-zig/graphs/contributors) for their help with this
binding.
## Example
@ -38,9 +38,9 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.white);
rl.clearBackground(.white);
rl.drawText("Congrats! You created your first window!", 190, 200, 20, rl.Color.light_gray);
rl.drawText("Congrats! You created your first window!", 190, 200, 20, .light_gray);
//----------------------------------------------------------------------------------
}
}
@ -55,22 +55,22 @@ want to run an example, say `basic_window` run `zig build basic_window`
### Using raylib-zig's template
* Execute `project_setup.sh project_name`, this will create a folder with the name specified
* You can copy that folder anywhere you want and edit the source
* Run `zig build run` at any time to test your project
- Execute `project_setup.sh project_name`, this will create a folder with the name specified
- You can copy that folder anywhere you want and edit the source
- Run `zig build run` at any time to test your project
### In an existing project (e.g. created with `zig init`)
Download and add raylib-zig as a dependency by running the following command in your project root:
```
zig fetch --save https://github.com/Not-Nik/raylib-zig/archive/devel.tar.gz
zig fetch --save git+https://github.com/raylib-zig/raylib-zig#devel
```
Then add raylib-zig as a dependency and import its modules and artifact in your `build.zig`:
```zig
const raylib_dep = b.dependency("raylib-zig", .{
const raylib_dep = b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
});
@ -88,8 +88,8 @@ exe.root_module.addImport("raylib", raylib);
exe.root_module.addImport("raygui", raygui);
```
If you additionally want to support Web as a platform with emscripten, you will need to use `emcc.zig` by importing
raylib-zig's build script with `const rlz = @import("raylib-zig");` and then accessing its functions with `rlz.emcc`.
If you additionally want to support Web as a platform with emscripten, you will need to use `emsdk` by importing
raylib-zig's build script with `const rlz = @import("raylib_zig");` and then accessing like described here [Exporting for web](https://github.com/raylib-zig/raylib-zig?tab=readme-ov-file#exporting-for-web).
Refer to raylib-zig's project template on how to use them.
### Passing build options
@ -98,10 +98,10 @@ raylib allows customisations of certain parts of its build process such as choos
shared library or not including certain modules. You can optionally pass these options to raylib-zig dependency like so
```zig
const raylib_dep = b.dependency("raylib-zig", .{
const raylib_dep = b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
.shared = true, // Build raylib as a shared library
.linkage = .dynamic, // Build raylib as a shared library
.opengl_version = rlz.OpenglVersion.gl_2_1, // Use OpenGL 2.1 (requires importing raylib-zig's build script)
});
```
@ -113,21 +113,55 @@ fonts, 3D models and audio, linkage variants. You can specify these options for
corresponding C macro before you link with it, e.g.:
```zig
raylib_artifact.defineCMacro("SUPPORT_FILEFORMAT_JPG", null);
raylib_artifact.root_module.addCMacro("SUPPORT_FILEFORMAT_JPG", "");
```
## Exporting for web
To export your project for the web, first install emsdk.
Once emsdk is installed, set it up by running
To export your project for the web, first add emsdk to your dependencies.
Its also possible to use a local emsdk folder.
`emsdk install latest`
`zig fetch --save=emsdk git+https://github.com/emscripten-core/emsdk#4.0.9`
Find the folder where it's installed and run
Add this to your build method to build for the web
`zig build -Dtarget=wasm32-emscripten --sysroot [path to emsdk]/upstream/emscripten`
```zig
if (target.query.os_tag == .emscripten) {
const emsdk = rlz.emsdk;
const wasm = b.addLibrary(.{
.name = <your_project_name>,
.root_module = exe_mod,
});
once that is finished, the exported project should be located at `zig-out/htmlout`
const install_dir: std.Build.InstallDir = .{ .custom = "web" };
const emcc_flags = emsdk.emccDefaultFlags(b.allocator, .{ .optimize = optimize });
const emcc_settings = emsdk.emccDefaultSettings(b.allocator, .{ .optimize = optimize });
const emcc_step = emsdk.emccStep(b, raylib_artifact, wasm, .{
.optimize = optimize,
.flags = emcc_flags,
.settings = emcc_settings,
.install_dir = install_dir,
});
b.getInstallStep().dependOn(emcc_step);
const html_filename = try std.fmt.allocPrint(b.allocator, "{s}.html", .{wasm.name});
const emrun_step = emsdk.emrunStep(
b,
b.getInstallPath(install_dir, html_filename),
&.{},
);
emrun_step.dependOn(emcc_step);
run_step.dependOn(emrun_step);
}
```
then you can run
`zig build -Dtarget=wasm32-emscripten`
once that is finished, the exported project should be located at `zig-out/web`
### When is the binding updated?
@ -136,6 +170,6 @@ implementation stuff should be updatable with some hacks on your side.
### What needs to be done?
+ _(Done)_ Set up a proper package build and a build script for the examples
+ Port all the examples
+ Member functions/initialisers
- _(Done)_ Set up a proper package build and a build script for the examples
- Port all the examples
- Member functions/initialisers

469
build.zig
View File

@ -3,42 +3,12 @@
const std = @import("std");
const this = @This();
const rl = @import("raylib");
pub const emsdk = rl.emsdk;
pub const emcc = @import("emcc.zig");
pub const Options = struct {
raudio: bool = true,
rmodels: bool = true,
rshapes: bool = true,
rtext: bool = true,
rtextures: bool = true,
platform: PlatformBackend = .glfw,
shared: bool = false,
linux_display_backend: LinuxDisplayBackend = .X11,
opengl_version: OpenglVersion = .auto,
};
pub const OpenglVersion = enum {
auto,
gl_1_1,
gl_2_1,
gl_3_3,
gl_4_3,
gles_2,
gles_3,
};
pub const LinuxDisplayBackend = enum {
X11,
Wayland,
};
pub const PlatformBackend = enum {
glfw,
rgfw,
sdl,
drm,
};
pub const Options = rl.Options;
pub const OpenglVersion = rl.OpenglVersion;
pub const LinuxDisplayBackend = rl.LinuxDisplayBackend;
pub const PlatformBackend = rl.PlatformBackend;
const Program = struct {
name: []const u8,
@ -46,103 +16,34 @@ const Program = struct {
desc: []const u8,
};
fn link(
b: *std.Build,
exe: *std.Build.Step.Compile,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
options: Options,
) void {
const lib = getRaylib(b, target, optimize, options);
const target_os = exe.rootModuleTarget().os.tag;
switch (target_os) {
.windows => {
exe.linkSystemLibrary("winmm");
exe.linkSystemLibrary("gdi32");
exe.linkSystemLibrary("opengl32");
},
.macos => {
exe.linkFramework("OpenGL");
exe.linkFramework("Cocoa");
exe.linkFramework("IOKit");
exe.linkFramework("CoreAudio");
exe.linkFramework("CoreVideo");
},
.freebsd, .openbsd, .netbsd, .dragonfly => {
exe.linkSystemLibrary("GL");
exe.linkSystemLibrary("rt");
exe.linkSystemLibrary("dl");
exe.linkSystemLibrary("m");
exe.linkSystemLibrary("X11");
exe.linkSystemLibrary("Xrandr");
exe.linkSystemLibrary("Xinerama");
exe.linkSystemLibrary("Xi");
exe.linkSystemLibrary("Xxf86vm");
exe.linkSystemLibrary("Xcursor");
},
.emscripten, .wasi => {
// When using emscripten, the libries don't need to be linked
// because emscripten is going to do that later.
},
else => { // Linux and possibly others.
exe.linkSystemLibrary("GL");
exe.linkSystemLibrary("rt");
exe.linkSystemLibrary("dl");
exe.linkSystemLibrary("m");
exe.linkSystemLibrary("X11");
},
}
exe.linkLibrary(lib);
}
var _raylib_lib_cache: ?*std.Build.Step.Compile = null;
fn getRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) *std.Build.Step.Compile {
if (_raylib_lib_cache) |lib| return lib else {
const raylib = b.dependency("raylib", .{
.target = target,
.optimize = optimize,
.raudio = options.raudio,
.rmodels = options.rmodels,
.rshapes = options.rshapes,
.rtext = options.rtext,
.rtextures = options.rtextures,
.platform = options.platform,
.shared = options.shared,
.linux_display_backend = options.linux_display_backend,
.opengl_version = options.opengl_version,
});
const raylib_dep = b.dependency("raylib", .{
.target = target,
.optimize = optimize,
.raudio = options.raudio,
.rmodels = options.rmodels,
.rshapes = options.rshapes,
.rtext = options.rtext,
.rtextures = options.rtextures,
.platform = options.platform,
.linkage = options.linkage,
.linux_display_backend = options.linux_display_backend,
.opengl_version = options.opengl_version,
.android_api_version = options.android_api_version,
.android_ndk = options.android_ndk,
});
const lib = raylib.artifact("raylib");
const raylib = raylib_dep.artifact("raylib");
const raygui_dep = b.dependency("raygui", .{
.target = target,
.optimize = optimize,
});
const raygui_dep = b.dependency("raygui", .{
.target = target,
.optimize = optimize,
});
var gen_step = b.addWriteFiles();
lib.step.dependOn(&gen_step.step);
rl.addRaygui(b, raylib, raygui_dep, options);
const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n");
lib.addCSourceFile(.{
.file = raygui_c_path,
.flags = &[_][]const u8{
"-std=gnu99",
"-D_GNU_SOURCE",
"-DGL_SILENCE_DEPRECATION=199309L",
"-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674
},
});
lib.addIncludePath(raylib.path("src"));
lib.addIncludePath(raygui_dep.path("src"));
lib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h");
b.installArtifact(lib);
_raylib_lib_cache = lib;
return lib;
}
b.installArtifact(raylib);
return raylib;
}
fn getModule(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Module {
@ -172,18 +73,11 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const defaults = Options{};
const options = Options{
.platform = b.option(PlatformBackend, "platform", "Compile raylib in native mode (no X11)") orelse defaults.platform,
.raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio,
.rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels,
.rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext,
.rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures,
.rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes,
.shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared,
.linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend,
.opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version,
};
const raylib_artifact = this.getRaylib(b, target, optimize, Options.getOptions(b));
const raylib = this.getModule(b, target, optimize);
const raygui = this.gui.getModule(b, target, optimize);
raylib.linkLibrary(raylib_artifact);
const examples = [_]Program{
.{
@ -191,6 +85,21 @@ pub fn build(b: *std.Build) !void {
.path = "examples/audio/raw_stream.zig",
.desc = "Plays a sine wave",
},
.{
.name = "music_stream",
.path = "examples/audio/music_stream.zig",
.desc = "Use music stream to play an audio file",
},
.{
.name = "sound_loading",
.path = "examples/audio/sound_loading.zig",
.desc = "Load and play a song",
},
.{
.name = "module_playing",
.path = "examples/audio/module_playing.zig",
.desc = "Module playing (streaming)",
},
.{
.name = "basic_screen_manager",
.path = "examples/core/basic_screen_manager.zig",
@ -201,6 +110,16 @@ pub fn build(b: *std.Build) !void {
.path = "examples/core/basic_window.zig",
.desc = "Creates a basic window with text",
},
.{
.name = "core_monitor_change",
.path = "examples/core/core_monitor_change.zig",
.desc = "Simple Monitor Manager",
},
.{
.name = "basic_window_web",
.path = "examples/core/basic_window_web.zig",
.desc = "Creates a basic window with text (web)",
},
.{
.name = "input_keys",
.path = "examples/core/input_keys.zig",
@ -226,6 +145,11 @@ pub fn build(b: *std.Build) !void {
.path = "examples/core/2d_camera.zig",
.desc = "Shows the functionality of a 2D camera",
},
.{
.name = "2d_camera_platformer",
.path = "examples/core/2d_camera_platformer.zig",
.desc = "2D camera platformer",
},
.{
.name = "3d_camera_first_person",
.path = "examples/core/3d_camera_first_person.zig",
@ -246,11 +170,41 @@ pub fn build(b: *std.Build) !void {
.path = "examples/core/3d_picking.zig",
.desc = "Shows picking in 3d mode",
},
.{
.name = "drop_files",
.path = "examples/core/drop_files.zig",
.desc = "Demonstrates how to implement a drop files functionality",
},
.{
.name = "window_flags",
.path = "examples/core/window_flags.zig",
.desc = "Demonstrates various flags used during and after window creation",
},
.{
.name = "gui_message_box",
.path = "examples/gui/message_box.zig",
.desc = "Demonstrates showing and hiding a message box",
},
.{
.name = "raymarching",
.path = "examples/shaders/raymarching.zig",
.desc = "Uses a raymarching in a shader to render shapes",
},
.{
.name = "shaders_ascii_rendering",
.path = "examples/shaders/shaders_ascii_rendering.zig",
.desc = "Post-processing to render in ASCII",
},
.{
.name = "shaders_basic_pbr",
.path = "examples/shaders/shaders_basic_pbr.zig",
.desc = "Demonstrates physically based rendering",
},
.{
.name = "shaders_hybrid_render",
.path = "examples/shaders/shaders_hybrid_render.zig",
.desc = "Demonstrates hybrid rendering",
},
.{
.name = "texture_outline",
.path = "examples/shaders/texture_outline.zig",
@ -261,6 +215,86 @@ pub fn build(b: *std.Build) !void {
.path = "examples/shapes/logo_raylib.zig",
.desc = "Renders the raylib-zig logo",
},
.{
.name = "logo_raylib_anim",
.path = "examples/shapes/logo_raylib_anim.zig",
.desc = "Animates the raylib logo",
},
.{
.name = "basic_shapes",
.path = "examples/shapes/basic_shapes.zig",
.desc = "Renders various shapes",
},
.{
.name = "bouncing_ball",
.path = "examples/shapes/bouncing_ball.zig",
.desc = "Bouncing ball animation with collision detection",
},
.{
.name = "collision_area",
.path = "examples/shapes/collision_area.zig",
.desc = "Demonstrates collision detection",
},
.{
.name = "colors_palette",
.path = "examples/shapes/colors_palette.zig",
.desc = "Renders an interactive color palette",
},
.{
.name = "draw_circle_sector",
.path = "examples/shapes/draw_circle_sector.zig",
.desc = "Dynamically renders a circle sector using raygui",
},
.{
.name = "draw_rectangle_rounded",
.path = "examples/shapes/draw_rectangle_rounded.zig",
.desc = "Dynamically renders a rounded rectangle using raygui",
},
.{
.name = "draw_ring",
.path = "examples/shapes/draw_ring.zig",
.desc = "Dynaically renders a ring using raygui",
},
.{
.name = "easings_ball_anim",
.path = "examples/shapes/easings_ball_anim.zig",
.desc = "Renders a ball that demonstrates various easing functions",
},
.{
.name = "easings_box_anim",
.path = "examples/shapes/easings_box_anim.zig",
.desc = "Renders a box that demonstrates various easing functions",
},
.{
.name = "easings_rectangle_array",
.path = "examples/shapes/easings_rectangle_array.zig",
.desc = "Renders a box that demonstrates various easing functions",
},
.{
.name = "following_eyes",
.path = "examples/shapes/following_eyes.zig",
.desc = "Renders eyes that follow mouse movement",
},
.{
.name = "lines_bezier",
.path = "examples/shapes/lines_bezier.zig",
.desc = "Renders an interactive line bezier",
},
.{
.name = "rectangle_scaling",
.path = "examples/shapes/rectangle_scaling.zig",
.desc = "Renders a resizable rectangle",
},
.{
.name = "splines_drawing",
.path = "examples/shapes/splines_drawing.zig",
.desc = "Renders a spline",
},
.{
.name = "top_down_lights",
.path = "examples/shapes/top_down_lights.zig",
.desc = "Renders a sceen with shadows and a top down persepective",
},
.{
.name = "sprite_anim",
.path = "examples/textures/sprite_anim.zig",
@ -272,21 +306,90 @@ pub fn build(b: *std.Build) !void {
.desc = "Background scrolling & parallax demo",
},
.{
.name = "text_format_text",
.path = "examples/text/text_format_text.zig",
.name = "codepoints_loading",
.path = "examples/text/codepoints_loading.zig",
.desc = "Renders UTF-8 text",
},
.{
.name = "draw_3d",
.path = "examples/text/draw_3d.zig",
.desc = "Renders an example of text rendered in a 3d world",
},
.{
.name = "font_filters",
.path = "examples/text/font_filters.zig",
.desc = "Demonstrates the various font filters",
},
.{
.name = "font_loading",
.path = "examples/text/font_loading.zig",
.desc = "Demonstrates how to load fonts",
},
.{
.name = "font_sdf",
.path = "examples/text/font_sdf.zig",
.desc = "Demonstrates rending a sdf font",
},
.{
.name = "font_spritefont",
.path = "examples/text/font_spritefont.zig",
.desc = "Demonstrates rendering spritefonts",
},
.{
.name = "format_text",
.path = "examples/text/format_text.zig",
.desc = "Renders variables as text",
},
.{
.name = "input_box",
.path = "examples/text/input_box.zig",
.desc = "Show and example of an input_box",
},
.{
.name = "raylib_fonts",
.path = "examples/text/raylib_fonts.zig",
.desc = "Show fonts included with raylib",
},
.{
.name = "rectangle_bounds",
.path = "examples/text/rectangle_bounds.zig",
.desc = "demonstrate a flexible, resizeable, text box",
},
.{
.name = "unicode",
.path = "examples/text/unicode.zig",
.desc = "demonstrate rendering of unicode",
},
.{
.name = "writing_anim",
.path = "examples/text/writing_anim.zig",
.desc = "Simple text animation",
},
.{
.name = "textures_image_loading",
.path = "examples/textures/textures_image_loading.zig",
.desc = "Image loading and texture creation",
},
// .{
// .name = "models_loading",
// .path = "examples/models/models_loading.zig",
// .desc = "Loads a model and renders it",
// },
.{
.name = "models_heightmap",
.path = "examples/models/models_heightmap.zig",
.desc = "Heightmap loading and drawing",
},
.{
.name = "models_bone_socket",
.path = "examples/models/models_bone_socket.zig",
.desc = "Bone socket",
},
.{
.name = "models_box_collisions",
.path = "examples/models/models_box_collisions.zig",
.desc = "Box collisions",
},
.{
.name = "models_rlgl_solar_system",
.path = "examples/models/models_rlgl_solar_system.zig",
.desc = "Solar System",
},
// .{
// .name = "shaders_basic_lighting",
// .path = "examples/shaders/shaders_basic_lighting.zig",
@ -294,21 +397,16 @@ pub fn build(b: *std.Build) !void {
// },
};
const raylib = this.getModule(b, target, optimize);
const raygui = this.gui.getModule(b, target, optimize);
const raylib_test = b.addTest(.{
.root_source_file = b.path("lib/raylib.zig"),
.target = target,
.optimize = optimize,
.root_module = raylib,
});
raylib_test.linkLibC();
const raygui_test = b.addTest(.{
.root_source_file = b.path("lib/raygui.zig"),
.target = target,
.optimize = optimize,
.root_module = raygui,
});
raygui_test.root_module.addImport("raylib-zig", raylib);
raygui_test.linkLibC();
const test_step = b.step("test", "Check for library compilation errors");
test_step.dependOn(&raylib_test.step);
@ -317,33 +415,54 @@ pub fn build(b: *std.Build) !void {
const examples_step = b.step("examples", "Builds all the examples");
for (examples) |ex| {
const mod = b.createModule(.{
.root_source_file = b.path(ex.path),
.target = target,
.optimize = optimize,
});
if (target.query.os_tag == .emscripten) {
const exe_lib = emcc.compileForEmscripten(b, ex.name, ex.path, target, optimize);
exe_lib.root_module.addImport("raylib", raylib);
exe_lib.root_module.addImport("raygui", raygui);
const raylib_lib = getRaylib(b, target, optimize, options);
const wasm = b.addLibrary(.{
.name = ex.name,
.root_module = mod,
});
wasm.root_module.addImport("raylib", raylib);
wasm.root_module.addImport("raygui", raygui);
// Note that raylib itself isn't actually added to the exe_lib
// output file, so it also needs to be linked with emscripten.
exe_lib.linkLibrary(raylib_lib);
const link_step = try emcc.linkWithEmscripten(b, &[_]*std.Build.Step.Compile{ exe_lib, raylib_lib });
link_step.addArg("--embed-file");
link_step.addArg("resources/");
const install_dir: std.Build.InstallDir = .{ .custom = "web" };
const emcc_flags = emsdk.emccDefaultFlags(b.allocator, .{
.optimize = optimize,
.asyncify = !std.mem.endsWith(u8, ex.name, "web"),
});
const emcc_settings = emsdk.emccDefaultSettings(b.allocator, .{
.optimize = optimize,
});
const emcc_step = emsdk.emccStep(b, raylib_artifact, wasm, .{
.optimize = optimize,
.flags = emcc_flags,
.settings = emcc_settings,
.shell_file_path = emsdk.shell(b),
.install_dir = install_dir,
.embed_paths = &.{.{ .src_path = "resources/" }},
});
const html_filename = try std.fmt.allocPrint(b.allocator, "{s}.html", .{wasm.name});
const emrun_step = emsdk.emrunStep(
b,
b.getInstallPath(install_dir, html_filename),
&.{},
);
emrun_step.dependOn(emcc_step);
const run_step = try emcc.emscriptenRunStep(b);
run_step.step.dependOn(&link_step.step);
const run_option = b.step(ex.name, ex.desc);
run_option.dependOn(&run_step.step);
examples_step.dependOn(&exe_lib.step);
run_option.dependOn(emrun_step);
examples_step.dependOn(emcc_step);
} else {
const exe = b.addExecutable(.{
.name = ex.name,
.root_source_file = b.path(ex.path),
.optimize = optimize,
.target = target,
.root_module = mod,
});
this.link(b, exe, target, optimize, options);
exe.root_module.addImport("raylib", raylib);
exe.root_module.addImport("raygui", raygui);

View File

@ -1,17 +1,26 @@
.{
.name = "raylib-zig",
.version = "5.5.0",
.name = .raylib_zig,
.version = "5.6.0-dev",
.fingerprint = 0xc4cfa8c610114f28,
.dependencies = .{
.raylib = .{
.url = "https://github.com/raysan5/raylib/archive/c4be01329493d0e772a04de08639b4da32905d2a.tar.gz",
.hash = "1220d1c8697d41a42d4eaaf3f8709865534d1f3d6ad63f8a27500fa881380651a1c5",
.url = "git+https://github.com/raysan5/raylib#8ada37d9671682f420a2be1f1afd4b06173b81ad",
.hash = "raylib-5.6.0-dev-whq8uCg2ywTzCiX3VEP9RuCMXR6_VnDBmkj8GjL_p5QN",
},
.raygui = .{
.url = "https://github.com/raysan5/raygui/archive/1e03efca48c50c5ea4b4a053d5bf04bad58d3e43.tar.gz",
.hash = "122062b24f031e68f0d11c91dfc32aed5baf06caf26ed3c80ea1802f9e788ef1c358",
}
.url = "git+https://github.com/raysan5/raygui#9cdfec460b43a17264af3c181c46f62bf107ac17",
.hash = "N-V-__8AALUbbwDKkSH4nbf3Ml_dTWo9qbELvle5i9eQZMuo",
},
.emsdk = .{
.url = "git+https://github.com/emscripten-core/emsdk#4.0.9",
.hash = "N-V-__8AAJl1DwBezhYo_VE6f53mPVm00R-Fk28NPW7P14EQ",
},
.zemscripten = .{
.url = "git+https://github.com/zig-gamedev/zemscripten?ref=main#00da03b188220374a57cb34cda6230b8d53737ea",
.hash = "zemscripten-0.2.0-dev-sRlDqFJSAAB8hgnRt5DDMKP3zLlDtMnUDwYRJVCa5lGY",
},
},
.minimum_zig_version = "0.13.0",
.minimum_zig_version = "0.15.1",
.paths = .{
"build.zig",
"build.zig.zon",

130
emcc.zig
View File

@ -1,130 +0,0 @@
// raylib-zig (c) Nikolas Wipper 2020-2024
const std = @import("std");
const builtin = @import("builtin");
const emccOutputDir = "zig-out" ++ std.fs.path.sep_str ++ "htmlout" ++ std.fs.path.sep_str;
const emccOutputFile = "index.html";
pub fn emscriptenRunStep(b: *std.Build) !*std.Build.Step.Run {
// If compiling on windows , use emrun.bat.
const emrunExe = switch (builtin.os.tag) {
.windows => "emrun.bat",
else => "emrun",
};
var emrun_run_arg = try b.allocator.alloc(u8, b.sysroot.?.len + emrunExe.len + 1);
defer b.allocator.free(emrun_run_arg);
if (b.sysroot == null) {
emrun_run_arg = try std.fmt.bufPrint(
emrun_run_arg,
"{s}",
.{ emrunExe }
);
} else {
emrun_run_arg = try std.fmt.bufPrint(
emrun_run_arg,
"{s}" ++ std.fs.path.sep_str ++ "{s}",
.{ b.sysroot.?, emrunExe }
);
}
const run_cmd = b.addSystemCommand(&[_][]const u8{ emrun_run_arg, emccOutputDir ++ emccOutputFile });
return run_cmd;
}
// Creates the static library to build a project for Emscripten.
pub fn compileForEmscripten(
b: *std.Build,
name: []const u8,
root_source_file: []const u8,
target: std.Build.ResolvedTarget,
optimize: std.builtin.Mode,
) *std.Build.Step.Compile {
// TODO: It might be a good idea to create a custom compile step, that does
// both the compile to static library and the link with emcc by overidding
// the make function of the step. However it might also be a bad idea since
// it messes with the build system itself.
// The project is built as a library and linked later.
return b.addStaticLibrary(.{
.name = name,
.root_source_file = b.path(root_source_file),
.target = target,
.optimize = optimize,
});
}
// Links a set of items together using emscripten.
//
// Will accept objects and static libraries as items to link. As for files to
// include, it is recomended to have a single resources directory and just pass
// the entire directory instead of passing every file individually. The entire
// path given will be the path to read the file within the program. So, if
// "resources/image.png" is passed, your program will use "resources/image.png"
// as the path to load the file.
//
// TODO: Test if shared libraries are accepted, I don't remember if emcc can
// link a shared library with a project or not.
// TODO: Add a parameter that allows a custom output directory.
pub fn linkWithEmscripten(
b: *std.Build,
itemsToLink: []const *std.Build.Step.Compile,
) !*std.Build.Step.Run {
const emccExe = switch (builtin.os.tag) {
.windows => "emcc.bat",
else => "emcc",
};
var emcc_run_arg = try b.allocator.alloc(u8, b.sysroot.?.len + emccExe.len + 1);
defer b.allocator.free(emcc_run_arg);
if (b.sysroot == null) {
emcc_run_arg = try std.fmt.bufPrint(
emcc_run_arg,
"{s}",
.{ emccExe }
);
} else {
emcc_run_arg = try std.fmt.bufPrint(
emcc_run_arg,
"{s}" ++ std.fs.path.sep_str ++ "{s}",
.{ b.sysroot.?, emccExe },
);
}
// Create the output directory because emcc can't do it.
const mkdir_command = switch (builtin.os.tag) {
.windows => b.addSystemCommand(&.{ "cmd.exe", "/c", "if", "not", "exist", emccOutputDir, "mkdir", emccOutputDir }),
else => b.addSystemCommand(&.{ "mkdir", "-p", emccOutputDir }),
};
// Actually link everything together.
const emcc_command = b.addSystemCommand(&[_][]const u8{emcc_run_arg});
for (itemsToLink) |item| {
emcc_command.addFileArg(item.getEmittedBin());
emcc_command.step.dependOn(&item.step);
}
// This puts the file in zig-out/htmlout/index.html.
emcc_command.step.dependOn(&mkdir_command.step);
emcc_command.addArgs(&[_][]const u8{
"-o",
emccOutputDir ++ emccOutputFile,
"-sUSE_OFFSET_CONVERTER",
"-sFULL-ES3=1",
"-sUSE_GLFW=3",
"-sASYNCIFY",
"-O3",
"--emrun",
});
return emcc_command;
}
// TODO: See if zig's standard library already has somehing like this.
fn lastIndexOf(string: []const u8, character: u8) usize {
// Interestingly, Zig has no nice way of iterating a slice backwards.
for (0..string.len) |i| {
const index = string.len - i - 1;
if (string[index] == character) return index;
}
return string.len - 1;
}

View File

@ -0,0 +1,141 @@
const rl = @import("raylib");
const MAX_CIRCLES = 64;
const CircleWave = struct {
position: rl.Vector2,
radius: f32,
alpha: f32,
speed: f32,
color: rl.Color,
};
const screenWidth = 800;
const screenHeight = 450;
const colors = [14]rl.Color{ .orange, .red, .gold, .lime, .blue, .violet, .brown, .light_gray, .pink, .yellow, .green, .sky_blue, .purple, .beige };
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() !void {
// Initialization
//--------------------------------------------------------------------------------------
rl.setConfigFlags(rl.ConfigFlags{ .msaa_4x_hint = true }); // NOTE: Try to enable MSAA 4X
rl.initWindow(screenWidth, screenHeight, "raylib [audio] example - module playing (streaming)");
defer rl.closeWindow(); // Close window and OpenGL context
rl.initAudioDevice(); // Initialize audio device
defer rl.closeAudioDevice(); // Close audio device (music streaming is automatically stopped)
// Creates some circles for visual effect
var circles: [MAX_CIRCLES]CircleWave = undefined;
for (&circles) |*circle| {
initCircle(circle);
}
var music: rl.Music = try rl.loadMusicStream("resources/audio/mini1111.xm");
defer rl.unloadMusicStream(music); // Unload music stream buffers from RAM
music.looping = false;
var pitch: f32 = 1;
rl.playMusicStream(music);
var timePlayed: f32 = 0;
var pause: bool = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
rl.updateMusicStream(music); // Update music buffer with new stream data
// Restart music playing (stop and play)
if (rl.isKeyPressed(.space)) {
rl.stopMusicStream(music);
rl.playMusicStream(music);
pause = false;
}
// Pause/Resume music playing
if (rl.isKeyPressed(.p)) {
pause = !pause;
if (pause) {
rl.pauseMusicStream(music);
} else {
rl.resumeMusicStream(music);
}
}
if (rl.isKeyDown(.down)) {
pitch -= 0.01;
} else if (rl.isKeyDown(.up)) {
pitch += 0.01;
}
rl.setMusicPitch(music, pitch);
// Get timePlayed scaled to bar dimensions
timePlayed = rl.getMusicTimePlayed(music) / rl.getMusicTimeLength(music) * (screenWidth - 40);
if (!pause) {
for (&circles) |*circle| {
circle.alpha += circle.speed;
circle.radius += circle.speed * 10.0;
if (circle.alpha > 1.0) circle.speed *= -1;
if (circle.alpha <= 0.0) {
initCircle(circle);
}
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
rl.clearBackground(.white);
for (circles) |circle| {
rl.drawCircleV(circle.position, circle.radius, .fade(circle.color, circle.alpha));
}
// Draw time bar
rl.drawRectangle(20, screenHeight - 20 - 12, screenWidth - 40, 12, .light_gray);
rl.drawRectangle(20, screenHeight - 20 - 12, @intFromFloat(timePlayed), 12, .maroon);
rl.drawRectangleLines(20, screenHeight - 20 - 12, screenWidth - 40, 12, .gray);
// Draw help instructions
rl.drawRectangle(20, 20, 425, 145, .white);
rl.drawRectangleLines(20, 20, 425, 145, .gray);
rl.drawText("PRESS SPACE TO RESTART MUSIC", 40, 40, 20, .black);
rl.drawText("PRESS P TO PAUSE/RESUME", 40, 70, 20, .black);
rl.drawText("PRESS UP/DOWN TO CHANGE SPEED", 40, 100, 20, .black);
rl.drawText(rl.textFormat("SPEED: %f", .{pitch}), 40, 130, 20, .maroon);
rl.endDrawing();
//----------------------------------------------------------------------------------
}
}
fn initCircle(circle: *CircleWave) void {
circle.alpha = 0.0;
circle.radius = getRandomValuef32(10, 40);
circle.position.x = getRandomValuef32(@intFromFloat(circle.radius), @intFromFloat(screenWidth - circle.radius));
circle.position.y = getRandomValuef32(@intFromFloat(circle.radius), @intFromFloat(screenHeight - circle.radius));
circle.speed = getRandomValuef32(1, 100) / 2000.0;
circle.color = colors[@intCast(rl.getRandomValue(0, 13))];
}
fn getRandomValuef32(min: i32, max: i32) f32 {
return @as(f32, @floatFromInt(rl.getRandomValue(min, max)));
}

View File

@ -0,0 +1,78 @@
const rl = @import("raylib");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() !void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [audio] example - music playing (streaming)");
defer rl.closeWindow(); // Close window and OpenGL context
rl.initAudioDevice(); // Initialize audio device
defer rl.closeAudioDevice(); // Close audio device (music streaming is automatically stopped)
const music: rl.Music = try rl.loadMusicStream("resources/audio/country.mp3");
defer rl.unloadMusicStream(music); // Unload music stream buffers from RAM
rl.playMusicStream(music);
var timePlayed: f32 = 0; // Time played normalized [0.0f..1.0f]
var pause: bool = false; // Music playing paused
rl.setTargetFPS(30); // Set our game to run at 30 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
rl.updateMusicStream(music); // Update music buffer with new stream data
// Restart music playing (stop and play)
if (rl.isKeyPressed(.space)) {
rl.stopMusicStream(music);
rl.playMusicStream(music);
}
// Pause/Resume music playing
if (rl.isKeyPressed(.p)) {
pause = !pause;
if (pause) {
rl.pauseMusicStream(music);
} else {
rl.resumeMusicStream(music);
}
}
// Get normalized time played for current music stream
timePlayed = rl.getMusicTimePlayed(music) / rl.getMusicTimeLength(music);
if (timePlayed > 1.0) {
timePlayed = 1.0; // Make sure time played is no longer than music
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.white);
rl.drawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, .light_gray);
rl.drawRectangle(200, 200, 400, 12, .light_gray);
rl.drawRectangle(200, 200, @intFromFloat(timePlayed * 400), 12, .maroon);
rl.drawRectangleLines(200, 200, 400, 12, .gray);
rl.drawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, .light_gray);
rl.drawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, .light_gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -1,17 +1,20 @@
// raylib-zig (c) Nikolas Wipper 2023
const rl = @import("raylib");
const std = @import("std");
const MAX_SAMPLES = 512;
const MAX_SAMPLES_PER_UPDATE = 4096;
const pi = @import("std").math.pi;
const C = std.builtin.CallingConvention.c;
var frequency: f32 = 440;
var audioFrequency: f32 = 440;
var oldFrequency: f32 = 1;
var sineIdx: f32 = 0;
fn audioInputCallback(buffer: ?*anyopaque, frames: c_uint) callconv(.C) void {
fn audioInputCallback(buffer: ?*anyopaque, frames: c_uint) callconv(C) void {
audioFrequency = frequency + (audioFrequency - frequency) * 0.95;
const incr = audioFrequency / 44100;
@ -41,7 +44,7 @@ pub fn main() anyerror!void {
rl.setAudioStreamBufferSizeDefault(MAX_SAMPLES_PER_UPDATE);
// Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
const stream = rl.loadAudioStream(44100, 16, 1);
const stream = try rl.loadAudioStream(44100, 16, 1);
defer rl.unloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM
rl.setAudioStreamCallback(stream, &audioInputCallback);
@ -69,7 +72,7 @@ pub fn main() anyerror!void {
// Update
//----------------------------------------------------------------------------------
if (rl.isMouseButtonDown(.mouse_button_left)) {
if (rl.isMouseButtonDown(.left)) {
// Sample mouse input.
const mousePosition = rl.getMousePosition();
@ -111,12 +114,12 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
rl.drawText(rl.textFormat("sine frequency: %i", .{@as(i32, @intFromFloat(frequency))}),
rl.getScreenWidth() - 220, 10, 20, rl.Color.red);
rl.getScreenWidth() - 220, 10, 20, .red);
rl.drawText("click mouse button to change frequency or pan",
10, 10, 20, rl.Color.dark_gray);
10, 10, 20, .dark_gray);
// Draw the current buffer state proportionate to the screen
for (0..screenWidth) |i| {
@ -124,7 +127,7 @@ pub fn main() anyerror!void {
const y: f32 = @floatFromInt(data[@divFloor(i * MAX_SAMPLES, screenWidth)]);
position.y = 250 + 50 * y / 32000;
rl.drawPixelV(position, rl.Color.red);
rl.drawPixelV(position, .red);
}
//----------------------------------------------------------------------------------
}

View File

@ -0,0 +1,46 @@
const rl = @import("raylib");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() !void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [audio] example - sound loading and playing");
defer rl.closeWindow(); // Close window and OpenGL context
rl.initAudioDevice(); // Initialize audio device
defer rl.closeAudioDevice(); // Close audio device
const fxWav: rl.Sound = try rl.loadSound("resources/audio/sound.wav"); // Load WAV audio file
const fxOgg: rl.Sound = try rl.loadSound("resources/audio/target.ogg"); // Load OGG audio file
defer rl.unloadSound(fxWav); // Unload sound data
defer rl.unloadSound(fxOgg); // Unload sound data
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (rl.isKeyPressed(.space)) rl.playSound(fxWav); // Play WAV sound
if (rl.isKeyPressed(.enter)) rl.playSound(fxOgg); // Play OGG sound
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.white);
rl.drawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, .light_gray);
rl.drawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, .light_gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -27,7 +27,7 @@ pub fn main() anyerror!void {
spacing += @as(i32, @intFromFloat(buildings[i].width));
buildColors[i] = rl.Color.init(
buildColors[i] = .init(
@as(u8, @intCast(rl.getRandomValue(200, 240))),
@as(u8, @intCast(rl.getRandomValue(200, 240))),
@as(u8, @intCast(rl.getRandomValue(200, 250))),
@ -36,8 +36,8 @@ pub fn main() anyerror!void {
}
var camera = rl.Camera2D{
.target = rl.Vector2.init(player.x + 20, player.y + 20),
.offset = rl.Vector2.init(screenWidth / 2, screenHeight / 2),
.target = .init(player.x + 20, player.y + 20),
.offset = .init(screenWidth / 2, screenHeight / 2),
.rotation = 0,
.zoom = 1,
};
@ -51,19 +51,19 @@ pub fn main() anyerror!void {
//----------------------------------------------------------------------------------
// Player movement
if (rl.isKeyDown(rl.KeyboardKey.key_right)) {
if (rl.isKeyDown(.right)) {
player.x += 2;
} else if (rl.isKeyDown(rl.KeyboardKey.key_left)) {
} else if (rl.isKeyDown(.left)) {
player.x -= 2;
}
// Camera target follows player
camera.target = rl.Vector2.init(player.x + 20, player.y + 20);
camera.target = .init(player.x + 20, player.y + 20);
// Camera rotation controls
if (rl.isKeyDown(rl.KeyboardKey.key_a)) {
if (rl.isKeyDown(.a)) {
camera.rotation -= 1;
} else if (rl.isKeyDown(rl.KeyboardKey.key_s)) {
} else if (rl.isKeyDown(.s)) {
camera.rotation += 1;
}
@ -76,7 +76,7 @@ pub fn main() anyerror!void {
camera.zoom = rl.math.clamp(camera.zoom, 0.1, 3.0);
// Camera reset (zoom and rotation)
if (rl.isKeyPressed(rl.KeyboardKey.key_r)) {
if (rl.isKeyPressed(.r)) {
camera.zoom = 1.0;
camera.rotation = 0.0;
}
@ -87,51 +87,51 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
{
camera.begin();
defer camera.end();
rl.drawRectangle(-6000, 320, 13000, 8000, rl.Color.dark_gray);
rl.drawRectangle(-6000, 320, 13000, 8000, .dark_gray);
for (buildings, 0..) |building, i| {
rl.drawRectangleRec(building, buildColors[i]);
}
rl.drawRectangleRec(player, rl.Color.red);
rl.drawRectangleRec(player, .red);
rl.drawLine(
@as(i32, @intFromFloat(camera.target.x)),
-screenHeight * 10,
@as(i32, @intFromFloat(camera.target.x)),
screenHeight * 10,
rl.Color.green,
.green,
);
rl.drawLine(
-screenWidth * 10,
@as(i32, @intFromFloat(camera.target.y)),
screenWidth * 10,
@as(i32, @intFromFloat(camera.target.y)),
rl.Color.green,
.green,
);
}
rl.drawText("SCREEN AREA", 640, 10, 20, rl.Color.red);
rl.drawText("SCREEN AREA", 640, 10, 20, .red);
rl.drawRectangle(0, 0, screenWidth, 5, rl.Color.red);
rl.drawRectangle(0, 5, 5, screenHeight - 10, rl.Color.red);
rl.drawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, rl.Color.red);
rl.drawRectangle(0, screenHeight - 5, screenWidth, 5, rl.Color.red);
rl.drawRectangle(0, 0, screenWidth, 5, .red);
rl.drawRectangle(0, 5, 5, screenHeight - 10, .red);
rl.drawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, .red);
rl.drawRectangle(0, screenHeight - 5, screenWidth, 5, .red);
rl.drawRectangle(10, 10, 250, 113, rl.Color.sky_blue.fade(0.5));
rl.drawRectangleLines(10, 10, 250, 113, rl.Color.blue);
rl.drawRectangle(10, 10, 250, 113, .fade(.sky_blue, 0.5));
rl.drawRectangleLines(10, 10, 250, 113, .blue);
rl.drawText("Free 2d camera controls:", 20, 20, 10, rl.Color.black);
rl.drawText("- Right/Left to move Offset", 40, 40, 10, rl.Color.dark_gray);
rl.drawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, rl.Color.dark_gray);
rl.drawText("- A / S to Rotate", 40, 80, 10, rl.Color.dark_gray);
rl.drawText("- R to reset Zoom and Rotation", 40, 100, 10, rl.Color.dark_gray);
rl.drawText("Free 2d camera controls:", 20, 20, 10, .black);
rl.drawText("- Right/Left to move Offset", 40, 40, 10, .dark_gray);
rl.drawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, .dark_gray);
rl.drawText("- A / S to Rotate", 40, 80, 10, .dark_gray);
rl.drawText("- R to reset Zoom and Rotation", 40, 100, 10, .dark_gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -27,14 +27,14 @@ pub fn main() anyerror!void {
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
if (rl.isKeyPressed(.key_one)) {
if (rl.isKeyPressed(.one)) {
zoomMode = 0;
} else if (rl.isKeyPressed(.key_two)) {
} else if (rl.isKeyPressed(.two)) {
zoomMode = 1;
}
// Translate based on mouse right click
if (rl.isMouseButtonDown(.mouse_button_right)) {
if (rl.isMouseButtonDown(.right)) {
var delta = rl.getMouseDelta();
delta = rl.math.vector2Scale(delta, -1.0 / camera.zoom);
camera.target = rl.math.vector2Add(camera.target, delta);
@ -63,7 +63,7 @@ pub fn main() anyerror!void {
}
} else {
// Zoom based on left click
if (rl.isMouseButtonPressed(.mouse_button_left)) {
if (rl.isMouseButtonPressed(.left)) {
// Get the world point that is under the mouse
const mouseWorldPos = rl.getScreenToWorld2D(rl.getMousePosition(), camera);
@ -74,7 +74,7 @@ pub fn main() anyerror!void {
// under the cursor to the screen space point under the cursor at any zoom
camera.target = mouseWorldPos;
}
if (rl.isMouseButtonDown(.mouse_button_left)) {
if (rl.isMouseButtonDown(.left)) {
// Zoom increment
const deltaX = rl.getMouseDelta().x;
var scaleFactor = 1.0 + (0.01 * @abs(deltaX));
@ -91,7 +91,7 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
{
camera.begin();
@ -103,14 +103,14 @@ pub fn main() anyerror!void {
rl.drawGrid(100, 50);
rl.gl.rlPopMatrix();
rl.drawCircle(screenWidth / 2, screenHeight / 2, 50, rl.Color.maroon);
rl.drawCircle(screenWidth / 2, screenHeight / 2, 50, .maroon);
}
rl.drawText("[1][2] Select mouse zoom mode (Wheel or Move)", 20, 20, 20, rl.Color.dark_gray);
rl.drawText("[1][2] Select mouse zoom mode (Wheel or Move)", 20, 20, 20, .dark_gray);
if (zoomMode == 0) {
rl.drawText("Mouse right button drag to move, mouse wheel to zoom", 20, 50, 20, rl.Color.dark_gray);
rl.drawText("Mouse right button drag to move, mouse wheel to zoom", 20, 50, 20, .dark_gray);
} else {
rl.drawText("Mouse right button drag to move, mouse press and move to zoom", 20, 50, 20, rl.Color.dark_gray);
rl.drawText("Mouse right button drag to move, mouse press and move to zoom", 20, 50, 20, .dark_gray);
}
//----------------------------------------------------------------------------------

View File

@ -0,0 +1,334 @@
// raylib-zig (c) Axel Magnuson 2025
//
// This is a fairly close 1-1 copy of the original example from raylib, and
// thus might not represent completely idiomatic or clean zig.
const rl = @import("raylib");
const rm = @import("raymath");
const Rect = rl.Rectangle;
const Vec2 = rl.Vector2;
const Color = rl.Color;
const Camera2D = rl.Camera2D;
const CameraUpdater = *const fn (
camera: *Camera2D,
player: *Player,
env_items: []EnvItem,
delta: f32,
width: i32,
height: i32,
) void;
const G: i32 = 400;
const PLAYER_JUMP_SPD: f32 = 350;
const PLAYER_HOR_SPD: f32 = 200;
const Player = struct {
can_jump: bool,
speed: f32,
position: rl.Vector2,
};
const EnvItem = struct {
blocking: bool,
rect: rl.Rectangle,
color: rl.Color,
};
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [core] example - 2d camera");
defer rl.closeWindow(); // Close window and OpenGL context
var player: Player = .{ .can_jump = false, .speed = 0, .position = Vec2.init(400, 280) };
var env_items = [_]EnvItem{
.{ .rect = Rect.init(0, 0, 1000, 400), .blocking = false, .color = .light_gray },
.{ .rect = Rect.init(0, 400, 1000, 200), .blocking = true, .color = .gray },
.{ .rect = Rect.init(300, 200, 400, 10), .blocking = true, .color = .gray },
.{ .rect = Rect.init(250, 300, 100, 10), .blocking = true, .color = .gray },
.{ .rect = Rect.init(650, 300, 100, 10), .blocking = true, .color = .gray },
};
var camera: rl.Camera2D = .{
.target = player.position,
.offset = Vec2.init(screen_width / 2, screen_height / 2),
.rotation = 0,
.zoom = 1,
};
// store pointers to the multiple functions that could be used to update the camera
const camera_updaters = [_]CameraUpdater{
updateCameraCenter,
updatecameraCenterInsideMap,
updateCameraCenterSmoothFollow,
updateCameraEvenOutOnLanding,
updateCameraPlayerBoundsPush,
};
var camera_option: usize = 0;
const camera_descriptions = [_][:0]const u8{
"Follow player center",
"Follow player center, but clamp to map edges",
"Follow player center; smoothed",
"Follow player center horizontally; update player center vertically after landing",
"Player push camera on getting too close to screen edge",
};
rl.setTargetFPS(60); // Set our game to run at 60 frames per second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) {
// Update
//----------------------------------------------------------------------------------
const delta_time = rl.getFrameTime();
updatePlayer(&player, &env_items, delta_time);
camera.zoom += rl.getMouseWheelMove() * 0.05;
if (camera.zoom > 3) camera.zoom = 3;
if (camera.zoom < 0.25) camera.zoom = 0.25;
// input: reset
if (rl.isKeyPressed(.r)) {
camera.zoom = 1;
player.position = Vec2.init(400, 280);
}
// input: cycle camera mode
if (rl.isKeyPressed(.c)) {
camera_option = (camera_option + 1) % camera_updaters.len;
}
// call update camera by pointer
camera_updaters[camera_option](
&camera,
&player,
&env_items,
delta_time,
screen_width,
screen_height,
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
{
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.light_gray);
{
rl.beginMode2D(camera);
defer rl.endMode2D();
for (env_items) |env_item| {
rl.drawRectangleRec(env_item.rect, env_item.color);
}
const player_rect = Rect.init(player.position.x - 20, player.position.y - 40, 40, 40);
rl.drawRectangleRec(player_rect, .red);
rl.drawCircleV(player.position, 5, .gold);
}
rl.drawText("Controls:", 20, 20, 10, .black);
rl.drawText("- Right/Left to move", 40, 40, 10, .dark_gray);
// todo: controls text
rl.drawText("- Current camera mode:", 20, 120, 10, .black);
rl.drawText(camera_descriptions[camera_option], 40, 140, 10, .dark_gray);
}
//----------------------------------------------------------------------------------
}
}
//------------------------------------------------------------------------------------
// Player update function
//------------------------------------------------------------------------------------
fn updatePlayer(player: *Player, env_items: []EnvItem, delta: f32) void {
if (rl.isKeyDown(.left)) player.position.x -= PLAYER_HOR_SPD * delta;
if (rl.isKeyDown(.right)) player.position.x += PLAYER_HOR_SPD * delta;
if (rl.isKeyDown(.space) and player.can_jump) {
player.speed = -PLAYER_JUMP_SPD;
player.can_jump = false;
}
var hit_obstacle = false;
for (env_items) |ei| {
var p: *Vec2 = &player.position;
if (ei.blocking and
ei.rect.x <= p.x and
ei.rect.x + ei.rect.width >= p.x and
ei.rect.y >= p.y and
ei.rect.y <= p.y + player.speed * delta)
{
hit_obstacle = true;
player.speed = 0;
p.y = ei.rect.y;
break;
}
}
if (!hit_obstacle) {
player.position.y += player.speed * delta;
player.speed += G * delta;
player.can_jump = false;
} else player.can_jump = true;
}
//------------------------------------------------------------------------------------
// Selectable camera update functions
//------------------------------------------------------------------------------------
// Follow player center
fn updateCameraCenter(
camera: *Camera2D,
player: *Player,
_: []EnvItem,
_: f32,
width: i32,
height: i32,
) void {
const widthf: f32 = @floatFromInt(width);
const heightf: f32 = @floatFromInt(height);
camera.offset = Vec2.init(widthf / 2, heightf / 2);
camera.target = player.position;
}
// Follow player center, but clamp to map edges
fn updatecameraCenterInsideMap(
camera: *Camera2D,
player: *Player,
env_items: []EnvItem,
_: f32,
width: i32,
height: i32,
) void {
const widthf: f32 = @floatFromInt(width);
const heightf: f32 = @floatFromInt(height);
camera.offset = Vec2.init(widthf / 2, heightf / 2);
camera.target = player.position;
var min_x: f32 = 1000;
var min_y: f32 = 1000;
var max_x: f32 = -1000;
var max_y: f32 = -1000;
for (env_items) |ei| {
min_x = @min(ei.rect.x, min_x);
min_y = @min(ei.rect.y, min_y);
max_x = @max(ei.rect.x + ei.rect.width, max_x);
max_y = @max(ei.rect.y + ei.rect.height, max_y);
}
const max = rl.getWorldToScreen2D(Vec2.init(max_x, max_y), camera.*);
const min = rl.getWorldToScreen2D(Vec2.init(min_x, min_y), camera.*);
if (max.x < widthf) camera.offset.x = widthf - (max.x - widthf / 2);
if (max.y < heightf) camera.offset.y = heightf - (max.y - heightf / 2);
if (min.x > 0) camera.offset.x = widthf / 2 - min.x;
if (min.y > 0) camera.offset.y = heightf / 2 - min.y;
}
// Follow player center; smoothed
fn updateCameraCenterSmoothFollow(
camera: *Camera2D,
player: *Player,
_: []EnvItem,
delta: f32,
width: i32,
height: i32,
) void {
const min_speed = 30;
const min_effect_length = 10;
const fraction_speed = 0.8;
const widthf: f32 = @floatFromInt(width);
const heightf: f32 = @floatFromInt(height);
camera.offset = Vec2.init(widthf / 2, heightf / 2);
const diff = player.position.subtract(camera.target);
const length = diff.length();
if (length > min_effect_length) {
const speed = @max(fraction_speed * length, min_speed);
camera.target = camera.target.add(diff.scale(speed * delta / length));
}
}
var evening_out: bool = false;
var even_out_target: f32 = 0;
// Follow player center horizontally; update player center vertically after landing
fn updateCameraEvenOutOnLanding(
camera: *Camera2D,
player: *Player,
_: []EnvItem,
delta: f32,
width: i32,
height: i32,
) void {
const even_out_speed = 700;
const widthf: f32 = @floatFromInt(width);
const heightf: f32 = @floatFromInt(height);
camera.offset = Vec2.init(widthf / 2, heightf / 2);
camera.target.x = player.position.x;
if (evening_out) {
if (even_out_target > camera.target.y) {
camera.target.y += even_out_speed * delta;
if (camera.target.y > even_out_target) {
camera.target.y = even_out_target;
evening_out = false;
}
} else {
camera.target.y -= even_out_speed * delta;
if (camera.target.y < even_out_target) {
camera.target.y = even_out_target;
evening_out = false;
}
}
} else {
if (player.can_jump and player.speed == 0 and player.position.y != camera.target.y) {
evening_out = true;
even_out_target = player.position.y;
}
}
}
// Player push camera on getting too close to screen edge
fn updateCameraPlayerBoundsPush(
camera: *Camera2D,
player: *Player,
_: []EnvItem,
_: f32,
width: i32,
height: i32,
) void {
const bbox = Vec2.init(0.2, 0.2);
const widthf: f32 = @floatFromInt(width);
const heightf: f32 = @floatFromInt(height);
const bbox_world_min = rl.getScreenToWorld2D(Vec2.init((1 - bbox.x) * 0.5 * widthf, (1 - bbox.y) * 0.5 * heightf), camera.*);
const bbox_world_max = rl.getScreenToWorld2D(Vec2.init((1 + bbox.x) * 0.5 * widthf, (1 + bbox.y) * 0.5 * heightf), camera.*);
camera.offset = Vec2.init((1 - bbox.x) * 0.5 * widthf, (1 - bbox.y) * 0.5 * heightf);
if (player.position.x < bbox_world_min.x) camera.target.x = player.position.x;
if (player.position.y < bbox_world_min.y) camera.target.y = player.position.y;
if (player.position.x > bbox_world_max.x) camera.target.x = bbox_world_min.x + (player.position.x - bbox_world_max.x);
if (player.position.y > bbox_world_max.y) camera.target.y = bbox_world_min.y + (player.position.y - bbox_world_max.y);
}

View File

@ -14,11 +14,11 @@ pub fn main() anyerror!void {
defer rl.closeWindow(); // Close window and OpenGL context
var camera = rl.Camera3D{
.position = rl.Vector3.init(4, 2, 4),
.target = rl.Vector3.init(0, 1.8, 0),
.up = rl.Vector3.init(0, 1, 0),
.position = .init(4, 2, 4),
.target = .init(0, 1.8, 0),
.up = .init(0, 1, 0),
.fovy = 60,
.projection = rl.CameraProjection.camera_perspective,
.projection = .perspective,
};
var heights: [MAX_COLUMNS]f32 = undefined;
@ -27,12 +27,12 @@ pub fn main() anyerror!void {
for (0..heights.len) |i| {
heights[i] = @as(f32, @floatFromInt(rl.getRandomValue(1, 12)));
positions[i] = rl.Vector3.init(
positions[i] = .init(
@as(f32, @floatFromInt(rl.getRandomValue(-15, 15))),
heights[i] / 2.0,
@as(f32, @floatFromInt(rl.getRandomValue(-15, 15))),
);
colors[i] = rl.Color.init(
colors[i] = .init(
@as(u8, @intCast(rl.getRandomValue(20, 255))),
@as(u8, @intCast(rl.getRandomValue(10, 55))),
30,
@ -48,7 +48,7 @@ pub fn main() anyerror!void {
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
camera.update(rl.CameraMode.camera_first_person);
camera.update(.first_person);
//----------------------------------------------------------------------------------
// Draw
@ -56,31 +56,31 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
{
camera.begin();
defer camera.end();
// Draw ground
rl.drawPlane(rl.Vector3.init(0, 0, 0), rl.Vector2.init(32, 32), rl.Color.light_gray);
rl.drawCube(rl.Vector3.init(-16.0, 2.5, 0.0), 1.0, 5.0, 32.0, rl.Color.blue); // Draw a blue wall
rl.drawCube(rl.Vector3.init(16.0, 2.5, 0.0), 1.0, 5.0, 32.0, rl.Color.lime); // Draw a green wall
rl.drawCube(rl.Vector3.init(0.0, 2.5, 16.0), 32.0, 5.0, 1.0, rl.Color.gold); // Draw a yellow wall
rl.drawPlane(.init(0, 0, 0), .init(32, 32), .light_gray);
rl.drawCube(.init(-16.0, 2.5, 0.0), 1.0, 5.0, 32.0, .blue); // Draw a blue wall
rl.drawCube(.init(16.0, 2.5, 0.0), 1.0, 5.0, 32.0, .lime); // Draw a green wall
rl.drawCube(.init(0.0, 2.5, 16.0), 32.0, 5.0, 1.0, .gold); // Draw a yellow wall
// Draw some cubes around
for (heights, 0..) |height, i| {
rl.drawCube(positions[i], 2.0, height, 2.0, colors[i]);
rl.drawCubeWires(positions[i], 2.0, height, 2.0, rl.Color.maroon);
rl.drawCubeWires(positions[i], 2.0, height, 2.0, .maroon);
}
}
rl.drawRectangle(10, 10, 220, 70, rl.Color.sky_blue.fade(0.5));
rl.drawRectangleLines(10, 10, 220, 70, rl.Color.blue);
rl.drawRectangle(10, 10, 220, 70, .fade(.sky_blue, 0.5));
rl.drawRectangleLines(10, 10, 220, 70, .blue);
rl.drawText("First person camera default controls:", 20, 20, 10, rl.Color.black);
rl.drawText("- Move with keys: W, A, S, D", 40, 40, 10, rl.Color.dark_gray);
rl.drawText("- Mouse move to look around", 40, 60, 10, rl.Color.dark_gray);
rl.drawText("First person camera default controls:", 20, 20, 10, .black);
rl.drawText("- Move with keys: W, A, S, D", 40, 40, 10, .dark_gray);
rl.drawText("- Mouse move to look around", 40, 60, 10, .dark_gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -16,11 +16,11 @@ pub fn main() anyerror!void {
// Define the camera to look into our 3d world
var camera = rl.Camera{
.position = rl.Vector3.init(10, 10, 10),
.target = rl.Vector3.init(0, 0, 0),
.up = rl.Vector3.init(0, 1, 0),
.position = .init(10, 10, 10),
.target = .init(0, 0, 0),
.up = .init(0, 1, 0),
.fovy = 45,
.projection = rl.CameraProjection.camera_perspective,
.projection = .perspective,
};
const cubePosition = rl.Vector3.init(0, 0, 0);
@ -33,10 +33,10 @@ pub fn main() anyerror!void {
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//-----------------------------------------------------------------------------
camera.update(rl.CameraMode.camera_free);
camera.update(.free);
if (rl.isKeyPressed(rl.KeyboardKey.key_z)) {
camera.target = rl.Vector3.init(0, 0, 0);
if (rl.isKeyPressed(.z)) {
camera.target = .init(0, 0, 0);
}
//-----------------------------------------------------------------------------
@ -45,25 +45,25 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
{
camera.begin();
defer camera.end();
rl.drawCube(cubePosition, 2, 2, 2, rl.Color.red);
rl.drawCubeWires(cubePosition, 2, 2, 2, rl.Color.maroon);
rl.drawCube(cubePosition, 2, 2, 2, .red);
rl.drawCubeWires(cubePosition, 2, 2, 2, .maroon);
rl.drawGrid(10, 1);
}
rl.drawRectangle(10, 10, 320, 93, rl.Color.fade(rl.Color.sky_blue, 0.5));
rl.drawRectangleLines(10, 10, 320, 93, rl.Color.blue);
rl.drawRectangle(10, 10, 320, 93, .fade(.sky_blue, 0.5));
rl.drawRectangleLines(10, 10, 320, 93, .blue);
rl.drawText("Free camera default controls:", 20, 20, 10, rl.Color.black);
rl.drawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, rl.Color.dark_gray);
rl.drawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, rl.Color.dark_gray);
rl.drawText("- Z to zoom to (0, 0, 0)", 40, 80, 10, rl.Color.dark_gray);
rl.drawText("Free camera default controls:", 20, 20, 10, .black);
rl.drawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, .dark_gray);
rl.drawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, .dark_gray);
rl.drawText("- Z to zoom to (0, 0, 0)", 40, 80, 10, .dark_gray);
//-----------------------------------------------------------------------------
}
}

View File

@ -11,11 +11,11 @@ pub fn main() anyerror!void {
// Define the camera to look into our 3d world
var camera = rl.Camera{
.position = rl.Vector3.init(10, 10, 10),
.target = rl.Vector3.init(0, 0, 0),
.up = rl.Vector3.init(0, 1, 0),
.position = .init(10, 10, 10),
.target = .init(0, 0, 0),
.up = .init(0, 1, 0),
.fovy = 45,
.projection = rl.CameraProjection.camera_perspective,
.projection = .perspective,
};
const cubePosition = rl.Vector3.init(0, 1, 0);
@ -31,21 +31,21 @@ pub fn main() anyerror!void {
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
if (rl.isCursorHidden()) rl.updateCamera(&camera, rl.CameraMode.camera_first_person);
if (rl.isCursorHidden()) rl.updateCamera(&camera, .first_person);
// Toggle camera controls
if (rl.isMouseButtonPressed(rl.MouseButton.mouse_button_right)) {
if (rl.isMouseButtonPressed(.right)) {
if (rl.isCursorHidden()) rl.enableCursor() else rl.disableCursor();
}
if (rl.isMouseButtonPressed(rl.MouseButton.mouse_button_left)) {
if (rl.isMouseButtonPressed(.left)) {
if (!collision.hit) {
ray = rl.getScreenToWorldRay(rl.getMousePosition(), camera);
// Check collision between ray and box
collision = rl.getRayCollisionBox(ray, rl.BoundingBox{
.max = rl.Vector3.init(cubePosition.x - cubeSize.x / 2, cubePosition.y - cubeSize.y / 2, cubePosition.z - cubeSize.z / 2),
.min = rl.Vector3.init(cubePosition.x + cubeSize.x / 2, cubePosition.y + cubeSize.y / 2, cubePosition.z + cubeSize.z / 2),
.max = .init(cubePosition.x - cubeSize.x / 2, cubePosition.y - cubeSize.y / 2, cubePosition.z - cubeSize.z / 2),
.min = .init(cubePosition.x + cubeSize.x / 2, cubePosition.y + cubeSize.y / 2, cubePosition.z + cubeSize.z / 2),
});
} else collision.hit = false;
}
@ -56,33 +56,33 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
{
camera.begin();
defer camera.end();
if (collision.hit) {
rl.drawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, rl.Color.red);
rl.drawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, rl.Color.maroon);
rl.drawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, .red);
rl.drawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, .maroon);
rl.drawCubeWires(cubePosition, cubeSize.x + 0.2, cubeSize.y + 0.2, cubeSize.z + 0.2, rl.Color.green);
rl.drawCubeWires(cubePosition, cubeSize.x + 0.2, cubeSize.y + 0.2, cubeSize.z + 0.2, .green);
} else {
rl.drawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, rl.Color.gray);
rl.drawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, rl.Color.dark_gray);
rl.drawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, .gray);
rl.drawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, .dark_gray);
}
rl.drawRay(ray, rl.Color.maroon);
rl.drawRay(ray, .maroon);
rl.drawGrid(10, 1);
}
rl.drawText("Try clicking on the box with your mouse!", 240, 10, 20, rl.Color.dark_gray);
rl.drawText("Try clicking on the box with your mouse!", 240, 10, 20, .dark_gray);
if (collision.hit) {
rl.drawText("BOX SELECTED", @divTrunc((screenWidth - rl.measureText("BOX SELECTED", 30)), 2), screenHeight * 0.1, 30, rl.Color.green);
rl.drawText("BOX SELECTED", @divTrunc((screenWidth - rl.measureText("BOX SELECTED", 30)), 2), screenHeight * 0.1, 30, .green);
}
rl.drawText("Right click mouse to toggle camera controls", 10, 430, 10, rl.Color.gray);
rl.drawText("Right click mouse to toggle camera controls", 10, 430, 10, .gray);
rl.drawFPS(10, 10);
}

View File

@ -56,7 +56,7 @@ pub fn main() anyerror!void {
// TODO: Update `title` state variables here!
// Press ENTER to change to `gameplay` state
if (rl.isKeyPressed(.key_enter) or rl.isGestureDetected(.gesture_tap)) {
if (rl.isKeyPressed(.enter) or rl.isGestureDetected(.{ .tap = true })) {
current_screen = .gameplay;
}
},
@ -64,7 +64,7 @@ pub fn main() anyerror!void {
// TODO: Update `gameplay` state variables here!
// Press ENTER to change to `ending` state
if (rl.isKeyPressed(.key_enter) or rl.isGestureDetected(.gesture_tap)) {
if (rl.isKeyPressed(.enter) or rl.isGestureDetected(.{ .tap = true })) {
current_screen = .ending;
}
},
@ -72,7 +72,7 @@ pub fn main() anyerror!void {
// TODO: Update `ending` state variables here!
// Press ENTER to return to `title` state
if (rl.isKeyPressed(.key_enter) or rl.isGestureDetected(.gesture_tap)) {
if (rl.isKeyPressed(.enter) or rl.isGestureDetected(.{ .tap = true })) {
current_screen = .title;
}
},
@ -85,18 +85,18 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
switch (current_screen) {
.logo => {
// TODO: Draw `logo` state here!
rl.drawText("LOGO SCREEN", 20, 20, 40, rl.Color.light_gray);
rl.drawText("LOGO SCREEN", 20, 20, 40, .light_gray);
rl.drawText(
"WAIT for 2 SECONDS...",
290,
220,
20,
rl.Color.gray,
.gray,
);
},
.title => {
@ -106,21 +106,21 @@ pub fn main() anyerror!void {
0,
screen_width,
screen_height,
rl.Color.green,
.green,
);
rl.drawText(
"TITLE SCREEN",
20,
20,
40,
rl.Color.dark_green,
.dark_green,
);
rl.drawText(
"PRESS ENTER or TAP to JUMP to GAMEPLAY SCREEN",
120,
220,
20,
rl.Color.dark_green,
.dark_green,
);
},
.gameplay => {
@ -130,15 +130,15 @@ pub fn main() anyerror!void {
0,
screen_width,
screen_height,
rl.Color.purple,
.purple,
);
rl.drawText("GAMEPLAY SCREEN", 20, 20, 40, rl.Color.maroon);
rl.drawText("GAMEPLAY SCREEN", 20, 20, 40, .maroon);
rl.drawText(
"PRESS ENTER or TAP to JUMP to ENDING SCREEN",
130,
220,
20,
rl.Color.maroon,
.maroon,
);
},
.ending => {
@ -148,21 +148,21 @@ pub fn main() anyerror!void {
0,
screen_width,
screen_height,
rl.Color.blue,
.blue,
);
rl.drawText(
"ENDING SCREEN",
20,
20,
40,
rl.Color.dark_blue,
.dark_blue,
);
rl.drawText(
"PRESS ENTER or TAP to RETURN to TITLE SCREEN",
120,
220,
20,
rl.Color.dark_blue,
.dark_blue,
);
},
}

View File

@ -26,9 +26,9 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.white);
rl.clearBackground(.white);
rl.drawText("Congrats! You created your first window!", 190, 200, 20, rl.Color.light_gray);
rl.drawText("Congrats! You created your first window!", 190, 200, 20, .light_gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,53 @@
// A raylib-zig port of https://github.com/raysan5/raylib/blob/master/examples/core/core_basic_window_web.c
const std = @import("std");
const rl = @import("raylib");
const builtin = @import("builtin");
const emscripten = std.os.emscripten;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
rl.initWindow(screenWidth, screenHeight, "raylib-zig [core] example - basic window");
defer rl.closeWindow(); // Close window and OpenGL context
if (builtin.os.tag == .emscripten) {
emscripten.emscripten_set_main_loop(@ptrCast(&updateDrawFrame), 0, 1);
} else {
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
updateDrawFrame();
}
}
}
// Update and Draw one frame
fn updateDrawFrame() void {
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.white);
rl.drawText("Congrats! You created your first window!", 190, 200, 20, .light_gray);
//----------------------------------------------------------------------------------
}

View File

@ -0,0 +1,153 @@
// raylib-zig (c) 2025 Maicon Santana (@maiconpintoabreu)
const std = @import("std");
const rl = @import("raylib");
const MAX_MONITORS = 10;
// Monitor Details
const Monitor = struct {
position: rl.Vector2,
name: [*c]const u8,
width: i32,
height: i32,
physicalWidth: i32,
physicalHeight: i32,
refreshRate: i32,
};
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth: i32 = 800;
const screenHeight: i32 = 450;
var monitors: [MAX_MONITORS]Monitor = undefined;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [core] example - monitor change");
defer rl.closeWindow(); // Close window and OpenGL context
var currentMonitorIndex: i32 = rl.getCurrentMonitor();
var monitorCount: usize = 0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
// Variables to find the max x and Y to calculate the scale
var maxWidth: i32 = 1;
var maxHeight: i32 = 1;
// Monitor offset is to fix when monitor position x is negative
var monitorOffsetX: f32 = 0;
// Rebuild monitors array every frame
monitorCount = @intCast(rl.getMonitorCount());
for (0..monitorCount) |i| {
const intI: i32 = @intCast(i);
monitors[i] = .{
.position = rl.getMonitorPosition(intI),
.name = rl.getMonitorName(intI),
.width = rl.getMonitorWidth(intI),
.height = rl.getMonitorHeight(intI),
.physicalWidth = rl.getMonitorPhysicalWidth(intI),
.physicalHeight = rl.getMonitorPhysicalHeight(intI),
.refreshRate = rl.getMonitorRefreshRate(intI),
};
if (monitors[i].position.x < monitorOffsetX) {
monitorOffsetX = monitors[i].position.x * -1.0;
}
const width: i32 = @as(i32, @intFromFloat(monitors[i].position.x)) + monitors[i].width;
const height: i32 = @as(i32, @intFromFloat(monitors[i].position.y)) + monitors[i].height;
if (maxWidth < width) maxWidth = width;
if (maxHeight < height) maxHeight = height;
}
if (rl.isKeyPressed(.enter) and monitorCount > 1) {
currentMonitorIndex += 1;
// Set index to 0 if the last one
if (currentMonitorIndex == monitorCount) currentMonitorIndex = 0;
rl.setWindowMonitor(currentMonitorIndex); // Move window to currentMonitorIndex
} else {
// Get currentMonitorIndex if manually moved
currentMonitorIndex = rl.getCurrentMonitor();
}
var monitorScale: f32 = 0.6;
const intMonitorOffsetX: i32 = @intFromFloat(monitorOffsetX);
if (maxHeight > maxWidth + intMonitorOffsetX) {
monitorScale *= @as(f32, @floatFromInt(screenHeight)) / @as(f32, @floatFromInt(maxHeight));
} else {
monitorScale *= @as(f32, @floatFromInt(screenWidth)) / @as(f32, @floatFromInt((maxWidth + intMonitorOffsetX)));
}
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("Press [Enter] to move window to next monitor available", 20, 20, 20, .dark_gray);
rl.drawRectangleLines(20, 60, screenWidth - 40, screenHeight - 100, .dark_gray);
// Draw Monitor Rectangles with information inside
for (0..monitorCount) |i| {
// Calculate retangle position and size using monitorScale
const rec: rl.Rectangle = .{
.x = (monitors[i].position.x + monitorOffsetX) * monitorScale + 140,
.y = monitors[i].position.y * monitorScale + 80,
.width = @as(f32, @floatFromInt(monitors[i].width)) * monitorScale,
.height = @as(f32, @floatFromInt(monitors[i].height)) * monitorScale,
};
// Draw monitor name and information inside the rectangle
rl.drawText(
rl.textFormat("[%i] %s", .{ i, monitors[i].name }),
@intFromFloat(rec.x + 10.0),
@intFromFloat(rec.y + (100.0 * monitorScale)),
@as(i32, @intFromFloat(120.0 * monitorScale)),
.blue,
);
rl.drawText(rl.textFormat("Resolution: [%ipx x %ipx]\nRefreshRate: [%ihz]\nPhysical Size: [%imm x %imm]\nPosition: %3.0f x %3.0f", .{
monitors[i].width,
monitors[i].height,
monitors[i].refreshRate,
monitors[i].physicalWidth,
monitors[i].physicalHeight,
monitors[i].position.x,
monitors[i].position.y,
}), @intFromFloat(rec.x + 10), @intFromFloat(rec.y + (200 * monitorScale)), @as(i32, @intFromFloat(120.0 * monitorScale)), .dark_gray);
// Highlight current monitor
if (i == currentMonitorIndex) {
rl.drawRectangleLinesEx(rec, 5, .red);
const windowPosition: rl.Vector2 = .{
.x = (rl.getWindowPosition().x + monitorOffsetX) * monitorScale + 140,
.y = rl.getWindowPosition().y * monitorScale + 80,
};
// Draw window position based on monitors
rl.drawRectangleV(
windowPosition,
.{ .x = @as(f32, @floatFromInt(screenWidth)) * monitorScale, .y = @as(f32, @floatFromInt(screenHeight)) * monitorScale },
rl.fade(.green, 0.5),
);
} else {
rl.drawRectangleLinesEx(rec, 5, .gray);
}
}
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,102 @@
// raylib-zig (c) Leonardo Kreienbuehl 2025
const rl = @import("raylib");
const std = @import("std");
const MAX_FILEPATH_RECORDED = 4096;
const MAX_FILEPATH_SIZE = 2048;
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [core] example - drop files");
defer rl.closeWindow(); // Close window and OpenGL context
var filePathCounter: usize = 0;
var filePaths: [MAX_FILEPATH_RECORDED][MAX_FILEPATH_SIZE]u8 = std.mem.zeroes([MAX_FILEPATH_RECORDED][MAX_FILEPATH_SIZE]u8);
rl.setTargetFPS(60);
// Main game loop
while (!rl.windowShouldClose()) {
// Update
//----------------------------------------------------------------------------------
if (rl.isFileDropped()) {
const droppedFiles: rl.FilePathList = rl.loadDroppedFiles();
for (0..droppedFiles.count) |i| {
const offset: usize = @as(usize, @intCast(filePathCounter));
const droppedFilePathLength: usize = std.mem.len(droppedFiles.paths[i]);
if (filePathCounter < (MAX_FILEPATH_RECORDED - 1)) {
_ = rl.textCopy(
@ptrCast(@constCast(&filePaths[offset])),
droppedFiles.paths[i][0..droppedFilePathLength :0],
);
filePathCounter += 1;
}
}
rl.unloadDroppedFiles(droppedFiles);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
if (filePathCounter == 0) {
rl.drawText(
"Drop your files to this window!",
100,
40,
20,
rl.Color.dark_gray,
);
} else {
rl.drawText(
"Dropped files:",
100,
40,
20,
rl.Color.dark_gray,
);
for (0..filePathCounter) |i| {
const castedI: i32 = @intCast(i);
if (@mod(i, 2) == 0) {
rl.drawRectangle(
0,
85 + 40 * castedI,
screenWidth,
40,
rl.fade(rl.Color.light_gray, 0.5),
);
} else {
rl.drawRectangle(
0,
85 + 40 * castedI,
screenWidth,
40,
rl.fade(rl.Color.light_gray, 0.3),
);
}
rl.drawText(
filePaths[i][0 .. MAX_FILEPATH_SIZE - 1 :0],
120,
100 + 40 * castedI,
10,
rl.Color.gray,
);
}
}
//----------------------------------------------------------------------------------
}
}

View File

@ -21,16 +21,16 @@ pub fn main() anyerror!void {
// Update
//----------------------------------------------------------------------------------
if (rl.isKeyDown(rl.KeyboardKey.key_right)) {
if (rl.isKeyDown(.right)) {
ballPosition.x += 2.0;
}
if (rl.isKeyDown(rl.KeyboardKey.key_left)) {
if (rl.isKeyDown(.left)) {
ballPosition.x -= 2.0;
}
if (rl.isKeyDown(rl.KeyboardKey.key_up)) {
if (rl.isKeyDown(.up)) {
ballPosition.y -= 2.0;
}
if (rl.isKeyDown(rl.KeyboardKey.key_down)) {
if (rl.isKeyDown(.down)) {
ballPosition.y += 2.0;
}
//----------------------------------------------------------------------------------
@ -40,11 +40,11 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
rl.drawText("move the ball with arrow keys", 10, 10, 20, rl.Color.dark_gray);
rl.drawText("move the ball with arrow keys", 10, 10, 20, .dark_gray);
rl.drawCircleV(ballPosition, 50, rl.Color.maroon);
rl.drawCircleV(ballPosition, 50, .maroon);
//----------------------------------------------------------------------------------
}
}

View File

@ -25,12 +25,12 @@ pub fn main() anyerror!void {
ballPosition.x = @as(f32, @floatFromInt(rl.getMouseX()));
ballPosition.y = @as(f32, @floatFromInt(rl.getMouseY()));
if (rl.isMouseButtonPressed(rl.MouseButton.mouse_button_left)) {
ballColor = rl.Color.maroon;
} else if (rl.isMouseButtonPressed(rl.MouseButton.mouse_button_middle)) {
ballColor = rl.Color.lime;
} else if (rl.isMouseButtonPressed(rl.MouseButton.mouse_button_right)) {
ballColor = rl.Color.dark_blue;
if (rl.isMouseButtonPressed(.left)) {
ballColor = .maroon;
} else if (rl.isMouseButtonPressed(.middle)) {
ballColor = .lime;
} else if (rl.isMouseButtonPressed(.right)) {
ballColor = .dark_blue;
}
//----------------------------------------------------------------------------------
@ -39,11 +39,11 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
rl.drawCircleV(ballPosition, 40, ballColor);
rl.drawText("move ball with mouse and click mouse button to change color", 10, 10, 20, rl.Color.dark_gray);
rl.drawText("move ball with mouse and click mouse button to change color", 10, 10, 20, .dark_gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -30,18 +30,18 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.white);
rl.clearBackground(.white);
rl.drawRectangle(screenWidth / 2 - 40, @as(i32, @intFromFloat(boxPositionY)), 80, 80, rl.Color.maroon);
rl.drawRectangle(screenWidth / 2 - 40, @as(i32, @intFromFloat(boxPositionY)), 80, 80, .maroon);
rl.drawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, rl.Color.gray);
rl.drawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, .gray);
rl.drawText(
rl.textFormat("Box position Y: %03i", .{@as(i32, @intFromFloat(boxPositionY))}),
10,
40,
20,
rl.Color.light_gray,
.light_gray,
);
//----------------------------------------------------------------------------------
}

View File

@ -26,25 +26,25 @@ pub fn main() anyerror!void {
//----------------------------------------------------------------------------------
ballPosition = rl.getMousePosition();
ballColor = rl.Color.beige;
ballColor = .beige;
if (rl.isMouseButtonDown(rl.MouseButton.mouse_button_left)) {
ballColor = rl.Color.maroon;
if (rl.isMouseButtonDown(.left)) {
ballColor = .maroon;
}
if (rl.isMouseButtonDown(rl.MouseButton.mouse_button_middle)) {
ballColor = rl.Color.lime;
if (rl.isMouseButtonDown(.middle)) {
ballColor = .lime;
}
if (rl.isMouseButtonDown(rl.MouseButton.mouse_button_right)) {
ballColor = rl.Color.dark_blue;
if (rl.isMouseButtonDown(.right)) {
ballColor = .dark_blue;
}
if (rl.isMouseButtonPressed(rl.MouseButton.mouse_button_left)) {
if (rl.isMouseButtonPressed(.left)) {
touchCounter = 10;
}
if (rl.isMouseButtonPressed(rl.MouseButton.mouse_button_middle)) {
if (rl.isMouseButtonPressed(.middle)) {
touchCounter = 10;
}
if (rl.isMouseButtonPressed(rl.MouseButton.mouse_button_right)) {
if (rl.isMouseButtonPressed(.right)) {
touchCounter = 10;
}
@ -58,7 +58,7 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
const nums = [_]i32{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (nums) |i| {
@ -68,13 +68,13 @@ pub fn main() anyerror!void {
if ((touchPosition.x >= 0) and (touchPosition.y >= 0)) {
// Draw circle and touch index number
rl.drawCircleV(touchPosition, 34, rl.Color.orange);
rl.drawCircleV(touchPosition, 34, .orange);
rl.drawText(
rl.textFormat("%d", .{i}),
@as(i32, @intFromFloat(touchPosition.x)) - 10,
@as(i32, @intFromFloat(touchPosition.y)) - 70,
40,
rl.Color.black,
.black,
);
}
}
@ -82,8 +82,8 @@ pub fn main() anyerror!void {
// Draw the normal mouse location
rl.drawCircleV(ballPosition, 30 + (touchCounter * 3), ballColor);
rl.drawText("move ball with mouse and click mouse button to change color", 10, 10, 20, rl.Color.dark_gray);
rl.drawText("touch the screen at multiple locations to get multiple balls", 10, 30, 20, rl.Color.dark_gray);
rl.drawText("move ball with mouse and click mouse button to change color", 10, 10, 20, .dark_gray);
rl.drawText("touch the screen at multiple locations to get multiple balls", 10, 30, 20, .dark_gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -58,9 +58,9 @@ pub fn main() anyerror!void {
while (!rl.windowShouldClose()) {
// Update
// ---------------------------------------------------------------------
if (rl.isKeyPressed(.key_f)) rl.toggleFullscreen(); // Modifies window size when scaling!
if (rl.isKeyPressed(.f)) rl.toggleFullscreen(); // Modifies window size when scaling!
if (rl.isKeyPressed(.key_r)) {
if (rl.isKeyPressed(.r)) {
if (rl.isWindowState(rl.ConfigFlags { .window_resizable = true })) {
rl.clearWindowState(rl.ConfigFlags { .window_resizable = true });
} else {
@ -68,7 +68,7 @@ pub fn main() anyerror!void {
}
}
if (rl.isKeyPressed(.key_d)) {
if (rl.isKeyPressed(.d)) {
if (rl.isWindowState(rl.ConfigFlags { .window_undecorated = true })) {
rl.clearWindowState(rl.ConfigFlags { .window_undecorated = true });
} else {
@ -76,7 +76,7 @@ pub fn main() anyerror!void {
}
}
if (rl.isKeyPressed(.key_h)) {
if (rl.isKeyPressed(.h)) {
if (!rl.isWindowState(rl.ConfigFlags { .window_hidden = true })) {
rl.setWindowState(rl.ConfigFlags { .window_hidden = true });
}
@ -88,7 +88,7 @@ pub fn main() anyerror!void {
if (frames_counter >= 240) rl.clearWindowState(rl.ConfigFlags { .window_hidden = true }); // Show window after 3 seconds
}
if (rl.isKeyPressed(.key_n)) {
if (rl.isKeyPressed(.n)) {
if (!rl.isWindowState(rl.ConfigFlags { .window_minimized = true })) {
rl.minimizeWindow();
}
@ -100,32 +100,32 @@ pub fn main() anyerror!void {
if (frames_counter >= 240) rl.restoreWindow(); // Restore window after 3 seconds
}
if (rl.isKeyPressed(.key_m)) {
if (rl.isKeyPressed(.m)) {
// NOTE: Requires `flag_window_resizable` enabled!
if (rl.isWindowState(rl.ConfigFlags { .window_maximized = true })) {
rl.restoreWindow();
} else rl.maximizeWindow();
}
if (rl.isKeyPressed(.key_u)) {
if (rl.isKeyPressed(.u)) {
if (rl.isWindowState(rl.ConfigFlags { .window_unfocused = true })) {
rl.clearWindowState(rl.ConfigFlags { .window_unfocused = true });
} else rl.setWindowState(rl.ConfigFlags { .window_unfocused = true });
}
if (rl.isKeyPressed(.key_t)) {
if (rl.isKeyPressed(.t)) {
if (rl.isWindowState(rl.ConfigFlags { .window_topmost = true })) {
rl.clearWindowState(rl.ConfigFlags { .window_topmost = true });
} else rl.setWindowState(rl.ConfigFlags { .window_topmost = true });
}
if (rl.isKeyPressed(.key_a)) {
if (rl.isKeyPressed(.a)) {
if (rl.isWindowState(rl.ConfigFlags { .window_always_run = true })) {
rl.clearWindowState(rl.ConfigFlags { .window_always_run = true });
} else rl.setWindowState(rl.ConfigFlags { .window_always_run = true });
}
if (rl.isKeyPressed(.key_v)) {
if (rl.isKeyPressed(.v)) {
if (rl.isWindowState(rl.ConfigFlags { .vsync_hint = true })) {
rl.clearWindowState(rl.ConfigFlags { .vsync_hint = true });
} else rl.setWindowState(rl.ConfigFlags { .vsync_hint = true });
@ -149,17 +149,17 @@ pub fn main() anyerror!void {
defer rl.endDrawing();
if (rl.isWindowState(rl.ConfigFlags { .window_transparent = true })) {
rl.clearBackground(rl.Color.blank);
} else rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.blank);
} else rl.clearBackground(.ray_white);
rl.drawCircleV(ball_position, ball_radius, rl.Color.maroon);
rl.drawCircleV(ball_position, ball_radius, .maroon);
rl.drawRectangleLinesEx(
rl.Rectangle.init(0, 0, @floatFromInt(rl.getScreenWidth()), @floatFromInt(rl.getScreenHeight())),
.init(0, 0, @floatFromInt(rl.getScreenWidth()), @floatFromInt(rl.getScreenHeight())),
4,
rl.Color.ray_white,
.ray_white,
);
rl.drawCircleV(rl.getMousePosition(), 10, rl.Color.dark_blue);
rl.drawCircleV(rl.getMousePosition(), 10, .dark_blue);
rl.drawFPS(10, 10);
@ -168,7 +168,7 @@ pub fn main() anyerror!void {
10,
40,
10,
rl.Color.green,
.green,
);
// Draw window state info
@ -177,7 +177,7 @@ pub fn main() anyerror!void {
10,
60,
10,
rl.Color.gray,
.gray,
);
rl.drawText(
rl.textFormat("[F] flag_fullscreen_mode: %d", .{
@ -186,7 +186,7 @@ pub fn main() anyerror!void {
10,
80,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[R] flag_window_resizable: %d", .{
@ -195,7 +195,7 @@ pub fn main() anyerror!void {
10,
100,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[D] flag_window_undecorated: %d", .{
@ -204,7 +204,7 @@ pub fn main() anyerror!void {
10,
120,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[H] flag_window_hidden: %d", .{
@ -213,7 +213,7 @@ pub fn main() anyerror!void {
10,
140,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[N] flag_window_minimized: %d", .{
@ -222,7 +222,7 @@ pub fn main() anyerror!void {
10,
160,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[M] flag_window_maximized: %d", .{
@ -231,7 +231,7 @@ pub fn main() anyerror!void {
10,
180,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[U] flag_window_unfocused: %d", .{
@ -240,7 +240,7 @@ pub fn main() anyerror!void {
10,
200,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[T] flag_window_topmost: %d", .{
@ -249,7 +249,7 @@ pub fn main() anyerror!void {
10,
220,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[A] flag_window_always_run: %d", .{
@ -258,7 +258,7 @@ pub fn main() anyerror!void {
10,
240,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("[V] flag_vsync_hint: %d", .{
@ -267,7 +267,7 @@ pub fn main() anyerror!void {
10,
260,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
@ -275,7 +275,7 @@ pub fn main() anyerror!void {
10,
300,
10,
rl.Color.gray,
.gray,
);
rl.drawText(
rl.textFormat("flag_window_highdpi: %d", .{
@ -284,7 +284,7 @@ pub fn main() anyerror!void {
10,
320,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("flag_window_transparent: %d", .{
@ -293,7 +293,7 @@ pub fn main() anyerror!void {
10,
340,
10,
rl.Color.lime,
.lime,
);
rl.drawText(
rl.textFormat("flag_msaa_4x_hint: %d", .{
@ -302,7 +302,7 @@ pub fn main() anyerror!void {
10,
360,
10,
rl.Color.lime,
.lime,
);
}
// ---------------------------------------------------------------------

View File

@ -0,0 +1,60 @@
//! # raylib-zig [gui] example - message box
//!
//! Example originally created with raylib-zig 5.6-dev, last time updated with
//! raylib-zig 5.6-dev
//!
//! Example licensed under an unmodified zlib/libpng license, which is an
//! OSI-certified, BSD-like license that allows static linking with closed
//! source software
//!
//! Copyright (c) Nikolas Wipper 2025
const std = @import("std");
const rl = @import("raylib");
const rg = @import("raygui");
/// `rl.getColor` only accepts a `u32`. Performing `@intCast` on the return value
/// of `rg.getStyle` invokes checked undefined behavior from Zig when passed to
/// `rl.getColor`, hence the custom implementation here...
fn getColor(hex: i32) rl.Color {
var color: rl.Color = .black;
// zig fmt: off
color.r = @intCast((hex >> 24) & 0xFF);
color.g = @intCast((hex >> 16) & 0xFF);
color.b = @intCast((hex >> 8) & 0xFF);
color.a = @intCast((hex >> 0) & 0xFF);
// zig fmt: on
return color;
}
pub fn main() !void {
rl.initWindow(400, 200, "raygui - controls test suite");
defer rl.closeWindow();
rl.setTargetFPS(60);
var show_message_box = false;
const color_int = rg.getStyle(.default, .{ .default = .background_color });
while (!rl.windowShouldClose()) {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(getColor(color_int));
if (rg.button(.init(24, 24, 120, 30), "#191#Show Message"))
show_message_box = true;
if (show_message_box) {
const result = rg.messageBox(
.init(85, 70, 250, 100),
"#191#Message Box",
"Hi! This is a message",
"Nice;Cool",
);
if (result >= 0) show_message_box = false;
}
}
}

View File

@ -0,0 +1,148 @@
const std = @import("std");
const rl = @import("raylib");
const BONE_SOCKETS = 3;
const BONE_SOCKET_HAT = 0;
const BONE_SOCKET_HAND_R = 1;
const BONE_SOCKET_HAND_L = 2;
pub fn main() anyerror!void {
const screenWidth: i32 = 800;
const screenHeight: i32 = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [models] example - bone socket");
defer rl.closeWindow();
// Define the camera to look into our 3d world
var camera: rl.Camera3D = .{
.position = .{ .x = 5.0, .y = 5.0, .z = 5.0 },
.target = .{ .x = 0.0, .y = 2.0, .z = 0.0 },
.up = .{ .x = 0.0, .y = 1.0, .z = 0.0 },
.fovy = 45.0,
.projection = .perspective,
};
// Load gltf model
var characterModel: rl.Model = try rl.loadModel("examples/models/resources/models/gltf/greenman.glb"); // Load character model
defer characterModel.unload();
const equipModel: [BONE_SOCKETS]rl.Model = .{
try rl.loadModel("examples/models/resources/models/gltf/greenman_hat.glb"), // Index for the hat model is the same as BONE_SOCKET_HAT
try rl.loadModel("examples/models/resources/models/gltf/greenman_sword.glb"), // Index for the sword model is the same as BONE_SOCKET_HAND_R
try rl.loadModel("examples/models/resources/models/gltf/greenman_shield.glb"), // Index for the shield model is the same as BONE_SOCKET_HAND_L
};
defer for (equipModel) |model| {
model.unload();
};
var showEquip: [3]bool = .{ true, true, true }; // Toggle on/off equip
// Load gltf model animations
var animIndex: usize = 0;
var animCurrentFrame: i32 = 0;
const modelAnimations = try rl.loadModelAnimations("examples/models/resources/models/gltf/greenman.glb");
const animsCount = modelAnimations.len;
defer rl.unloadModelAnimations(modelAnimations);
// indices of bones for sockets
var boneSocketIndex: [BONE_SOCKETS]usize = undefined;
// search bones for sockets
for (0..@as(usize, @intCast(characterModel.boneCount))) |i| {
const boneName: [:0]const u8 = @ptrCast(&characterModel.bones[i].name);
if (rl.textIsEqual(boneName, "socket_hat")) {
boneSocketIndex[BONE_SOCKET_HAT] = i;
continue;
}
if (rl.textIsEqual(boneName, "socket_hand_R")) {
boneSocketIndex[BONE_SOCKET_HAND_R] = i;
continue;
}
if (rl.textIsEqual(boneName, "socket_hand_L")) {
boneSocketIndex[BONE_SOCKET_HAND_L] = i;
continue;
}
}
const position: rl.Vector3 = .zero(); // Set model position
var angle: f32 = 0.0; // Set angle for rotate character
rl.disableCursor(); // Limit cursor to relative movement inside the window
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
while (!rl.windowShouldClose()) {
// Update
//----------------------------------------------------------------------------------
rl.updateCamera(&camera, .third_person);
// Rotate character
if (rl.isKeyDown(.f)) {
angle += 1.0;
angle = @mod(angle, 360.0);
} else if (rl.isKeyDown(.h)) {
angle -= 1.0;
angle = @mod(angle, 360.0);
}
// Select current animation
if (rl.isKeyPressed(.t)) animIndex = (animIndex + 1) % animsCount else if (rl.isKeyPressed(.g)) animIndex = (animIndex + animsCount - 1) % animsCount;
// Toggle shown of equip
if (rl.isKeyPressed(.one)) showEquip[BONE_SOCKET_HAT] = !showEquip[BONE_SOCKET_HAT];
if (rl.isKeyPressed(.two)) showEquip[BONE_SOCKET_HAND_R] = !showEquip[BONE_SOCKET_HAND_R];
if (rl.isKeyPressed(.three)) showEquip[BONE_SOCKET_HAND_L] = !showEquip[BONE_SOCKET_HAND_L];
// Update model animation
const anim = modelAnimations[animIndex];
animCurrentFrame = @mod(animCurrentFrame + 1, anim.frameCount);
rl.updateModelAnimation(characterModel, anim, animCurrentFrame);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
{
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
{
rl.beginMode3D(camera);
defer rl.endMode3D();
// Draw character
const characterRotate: rl.Quaternion = rl.math.quaternionFromAxisAngle(.{ .x = 0.0, .y = 1.0, .z = 0.0 }, angle * std.math.rad_per_deg);
characterModel.transform = rl.math.matrixMultiply(rl.math.quaternionToMatrix(characterRotate), rl.math.matrixTranslate(position.x, position.y, position.z));
rl.updateModelAnimation(characterModel, anim, animCurrentFrame);
rl.drawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform);
// Draw equipments (hat, sword, shield)
for (0..BONE_SOCKETS) |i| {
if (!showEquip[i]) continue;
const transform = &anim.framePoses[@intCast(animCurrentFrame)][boneSocketIndex[i]];
const inRotation = characterModel.bindPose[boneSocketIndex[i]].rotation;
const outRotation = transform.rotation;
// Calculate socket rotation (angle between bone in initial pose and same bone in current animation frame)
const rotate = rl.math.quaternionMultiply(outRotation, rl.math.quaternionInvert(inRotation));
var matrixTransform = rl.math.quaternionToMatrix(rotate);
// Translate socket to its position in the current animation
matrixTransform = rl.math.matrixMultiply(matrixTransform, rl.math.matrixTranslate(transform.translation.x, transform.translation.y, transform.translation.z));
// Transform the socket using the transform of the character (angle and translate)
matrixTransform = rl.math.matrixMultiply(matrixTransform, characterModel.transform);
// Draw mesh at socket position with socket angle rotation
rl.drawMesh(equipModel[i].meshes[0], equipModel[i].materials[1], matrixTransform);
}
rl.drawGrid(10, 1.0);
}
rl.drawText("Use the T/G to switch animation", 10, 10, 20, .gray);
rl.drawText("Use the F/H to rotate character left/right", 10, 35, 20, .gray);
rl.drawText("Use the 1,2,3 to toggle shown of hat, sword and shield", 10, 60, 20, .gray);
//----------------------------------------------------------------------------------
}
}
}

View File

@ -0,0 +1,119 @@
const rl = @import("raylib");
pub fn main() anyerror!void {
const screenWidth: i32 = 800;
const screenHeight: i32 = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [models] example - box collisions");
// De-Initialization
//--------------------------------------------------------------------------------------
defer rl.closeWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
// Define the camera to look into our 3d world
const camera: rl.Camera = .{
.position = .{ .x = 0.0, .y = 10.0, .z = 10.0 },
.target = .{ .x = 0.0, .y = 0.0, .z = 0.0 },
.up = .{ .x = 0.0, .y = 1.0, .z = 0.0 },
.fovy = 45.0,
.projection = .perspective,
};
var playerPosition: rl.Vector3 = .{ .x = 0.0, .y = 1.0, .z = 2.0 };
const playerSize: rl.Vector3 = .{ .x = 1.0, .y = 2.0, .z = 1.0 };
var playerColor: rl.Color = .green;
const enemyBoxPos: rl.Vector3 = .{ .x = -4.0, .y = 1.0, .z = 0.0 };
const enemyBoxSize: rl.Vector3 = .{ .x = 2.0, .y = 2.0, .z = 2.0 };
const enemySpherePos: rl.Vector3 = .{ .x = 4.0, .y = 0.0, .z = 0.0 };
const enemySphereSize: f32 = 1.5;
var collision: bool = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
while (!rl.windowShouldClose()) {
// Update
//----------------------------------------------------------------------------------
// Move player
if (rl.isKeyDown(.right)) playerPosition.x += 0.2 else if (rl.isKeyDown(.left)) playerPosition.x -= 0.2 else if (rl.isKeyDown(.down)) playerPosition.z += 0.2 else if (rl.isKeyDown(.up)) playerPosition.z -= 0.2;
collision = false;
// Check collisions player vs enemy-box
if (rl.checkCollisionBoxes(.{
.min = .{
.x = playerPosition.x - playerSize.x / 2,
.y = playerPosition.y - playerSize.y / 2,
.z = playerPosition.z - playerSize.z / 2,
},
.max = .{
.x = playerPosition.x + playerSize.x / 2,
.y = playerPosition.y + playerSize.y / 2,
.z = playerPosition.z + playerSize.z / 2,
},
}, .{
.min = .{
.x = enemyBoxPos.x - enemyBoxSize.x / 2,
.y = enemyBoxPos.y - enemyBoxSize.y / 2,
.z = enemyBoxPos.z - enemyBoxSize.z / 2,
},
.max = .{
.x = enemyBoxPos.x + enemyBoxSize.x / 2,
.y = enemyBoxPos.y + enemyBoxSize.y / 2,
.z = enemyBoxPos.z + enemyBoxSize.z / 2,
},
})) collision = true;
// Check collisions player vs enemy-sphere
if (rl.checkCollisionBoxSphere(.{
.min = .{
.x = playerPosition.x - playerSize.x / 2,
.y = playerPosition.y - playerSize.y / 2,
.z = playerPosition.z - playerSize.z / 2,
},
.max = .{
.x = playerPosition.x + playerSize.x / 2,
.y = playerPosition.y + playerSize.y / 2,
.z = playerPosition.z + playerSize.z / 2,
},
}, enemySpherePos, enemySphereSize)) collision = true;
if (collision) playerColor = .red else playerColor = .green;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
{
rl.beginMode3D(camera);
defer rl.endMode3D();
// Draw enemy-box
rl.drawCube(enemyBoxPos, enemyBoxSize.x, enemyBoxSize.y, enemyBoxSize.z, .gray);
rl.drawCubeWires(enemyBoxPos, enemyBoxSize.x, enemyBoxSize.y, enemyBoxSize.z, .dark_gray);
// Draw enemy-sphere
rl.drawSphere(enemySpherePos, enemySphereSize, .gray);
rl.drawSphereWires(enemySpherePos, enemySphereSize, 16, 16, .dark_gray);
// Draw player
rl.drawCubeV(playerPosition, playerSize, playerColor);
rl.drawGrid(10, 1.0); // Draw a grid
}
rl.drawText("Move player with arrow keys to collide", 220, 40, 20, .gray);
rl.drawFPS(10, 10);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,49 @@
const rl = @import("raylib");
pub fn main() anyerror!void {
const screenWidth: i32 = 800;
const screenHeight: i32 = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing");
const cameraPosition: rl.Vector3 = .{ .x = 18, .y = 21, .z = 18 };
const cameraTarget: rl.Vector3 = .{ .x = 0, .y = 0, .z = 0 };
const cameraUp: rl.Vector3 = .{ .x = 0, .y = 1, .z = 0 };
const cameraProjection = rl.CameraProjection.perspective;
var camera = rl.Camera{ .fovy = 45.0, .position = cameraPosition, .up = cameraUp, .projection = cameraProjection, .target = cameraTarget };
const image: rl.Image = try rl.loadImage("examples/models/resources/heightmap.png");
const texture: rl.Texture2D = try rl.loadTextureFromImage(image);
const meshSize = rl.Vector3{ .x = 16, .y = 8, .z = 16 };
const mesh = rl.genMeshHeightmap(image, meshSize);
var model = try rl.loadModelFromMesh(mesh);
model.materials[0].maps[@intFromEnum(rl.MATERIAL_MAP_DIFFUSE)].texture = texture;
const mapPosition = rl.Vector3{ .x = -8.0, .y = 0.0, .z = -8.0 };
rl.unloadImage(image);
rl.setTargetFPS(60);
while (!rl.windowShouldClose()) {
rl.updateCamera(&camera, .orbital);
rl.beginDrawing();
rl.clearBackground(.ray_white);
rl.beginMode3D(camera);
rl.drawModel(model, mapPosition, 1, .red);
rl.drawGrid(20, 1.0);
rl.endMode3D();
rl.drawTexture(texture, screenWidth - texture.width - 20, 20, .white);
rl.drawRectangleLines(screenWidth - texture.width - 20, 20, texture.width, texture.height, .green);
rl.drawFPS(10, 10);
rl.endDrawing();
}
rl.unloadTexture(texture);
rl.unloadModel(model);
rl.closeWindow();
}

View File

@ -0,0 +1,153 @@
const std = @import("std");
const rl = @import("raylib");
const rlgl = rl.gl;
pub fn main() anyerror!void {
const screenWidth: i32 = 800;
const screenHeight: i32 = 450;
const sunRadius = 4.0;
const earthRadius = 0.6;
const earthOrbitRadius = 8.0;
const moonRadius = 0.16;
const moonOrbitRadius = 1.5;
rl.initWindow(screenWidth, screenHeight, "raylib [models] example - rlgl solar system");
// Define the camera to look into our 3d world
var camera: rl.Camera = std.mem.zeroes(rl.Camera);
camera.position = .{ .x = 16.0, .y = 16.0, .z = 16.0 }; // Camera position
camera.target = .{ .x = 0.0, .y = 0.0, .z = 0.0 }; // Camera looking at point
camera.up = .{ .x = 0.0, .y = 1.0, .z = 0.0 }; // Camera up vector (rotation towards target)
camera.fovy = 45.0; // Camera field-of-view Y
camera.projection = .perspective; // Camera projection type
const rotationSpeed: f32 = 0.2; // General system rotation speed
var earthRotation: f32 = 0.0; // Rotation of earth around itself (days) in degrees
var earthOrbitRotation: f32 = 0.0; // Rotation of earth around the Sun (years) in degrees
var moonRotation: f32 = 0.0; // Rotation of moon around itself
var moonOrbitRotation: f32 = 0.0; // Rotation of moon around earth in degrees
// De-Initialization
//--------------------------------------------------------------------------------------
defer rl.closeWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
while (!rl.windowShouldClose()) {
// Update
//----------------------------------------------------------------------------------
rl.updateCamera(&camera, .orbital);
earthRotation += (5.0 * rotationSpeed);
earthOrbitRotation += (365.0 / 360.0 * (5.0 * rotationSpeed) * rotationSpeed);
moonRotation += (2.0 * rotationSpeed);
moonOrbitRotation += (8.0 * rotationSpeed);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
{
rl.beginMode3D(camera);
defer rl.endMode3D();
rlgl.rlPushMatrix();
rlgl.rlScalef(sunRadius, sunRadius, sunRadius); // Scale Sun
drawSphereBasic(.gold); // Draw the Sun
rlgl.rlPopMatrix();
rlgl.rlPushMatrix();
rlgl.rlRotatef(earthOrbitRotation, 0.0, 1.0, 0.0); // Rotation for Earth orbit around Sun
rlgl.rlTranslatef(earthOrbitRadius, 0.0, 0.0); // Translation for Earth orbit
rlgl.rlPushMatrix();
rlgl.rlRotatef(earthRotation, 0.25, 1.0, 0.0); // Rotation for Earth itself
rlgl.rlScalef(earthRadius, earthRadius, earthRadius); // Scale Earth
drawSphereBasic(.blue); // Draw the Earth
rlgl.rlPopMatrix();
rlgl.rlRotatef(moonOrbitRotation, 0.0, 1.0, 0.0); // Rotation for Moon orbit around Earth
rlgl.rlTranslatef(moonOrbitRadius, 0.0, 0.0); // Translation for Moon orbit
rlgl.rlRotatef(moonRotation, 0.0, 1.0, 0.0); // Rotation for Moon itself
rlgl.rlScalef(moonRadius, moonRadius, moonRadius); // Scale Moon
drawSphereBasic(.light_gray); // Draw the Moon
rlgl.rlPopMatrix();
// Some reference elements (not affected by previous matrix transformations)
rl.drawCircle3D(.{ .x = 0.0, .y = 0.0, .z = 0.0 }, earthOrbitRadius, .{ .x = 1, .y = 0, .z = 0 }, 90.0, rl.fade(.red, 0.5));
rl.drawGrid(20, 1.0);
}
rl.drawText("EARTH ORBITING AROUND THE SUN!", 400, 10, 20, .maroon);
rl.drawFPS(10, 10);
//----------------------------------------------------------------------------------
}
}
//--------------------------------------------------------------------------------------------
// Module Functions Definition
//--------------------------------------------------------------------------------------------
// Draw sphere without any matrix transformation
// NOTE: Sphere is drawn in world position ( 0, 0, 0 ) with radius 1.0f
fn drawSphereBasic(color: rl.Color) void {
const rings: usize = 16;
const slices: usize = 16;
const floatRings: f32 = @floatFromInt(rings);
const floatSlices: f32 = @floatFromInt(slices);
// Make sure there is enough space in the internal render batch
// buffer to store all required vertex, batch is reseted if required
_ = rlgl.rlCheckRenderBatchLimit((rings + 2) * slices * 6);
rlgl.rlBegin(rlgl.rl_triangles);
rlgl.rlColor4ub(color.r, color.g, color.b, color.a);
for (0..(rings + 2)) |i| {
const floatI: f32 = @floatFromInt(i);
for (0..slices) |j| {
const floatJ: f32 = @floatFromInt(j);
rlgl.rlVertex3f(
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * floatI)) * std.math.sin(std.math.rad_per_deg * (floatJ * 360 / floatSlices)),
std.math.sin(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * floatI)),
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * floatI)) * std.math.cos(std.math.rad_per_deg * (floatJ * 360 / floatSlices)),
);
rlgl.rlVertex3f(
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))) * std.math.sin(std.math.rad_per_deg * ((floatJ + 1.0) * 360 / floatSlices)),
std.math.sin(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))),
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))) * std.math.cos(std.math.rad_per_deg * ((floatJ + 1.0) * 360 / floatSlices)),
);
rlgl.rlVertex3f(
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))) * std.math.sin(std.math.rad_per_deg * (floatJ * 360 / floatSlices)),
std.math.sin(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))),
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))) * std.math.cos(std.math.rad_per_deg * (floatJ * 360 / floatSlices)),
);
rlgl.rlVertex3f(
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * floatI)) * std.math.sin(std.math.rad_per_deg * (floatJ * 360 / floatSlices)),
std.math.sin(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * floatI)),
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * floatI)) * std.math.cos(std.math.rad_per_deg * (floatJ * 360 / floatSlices)),
);
rlgl.rlVertex3f(
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI))) * std.math.sin(std.math.rad_per_deg * ((floatJ + 1.0) * 360 / floatSlices)),
std.math.sin(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI))),
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI))) * std.math.cos(std.math.rad_per_deg * ((floatJ + 1.0) * 360 / floatSlices)),
);
rlgl.rlVertex3f(
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))) * std.math.sin(std.math.rad_per_deg * ((floatJ + 1.0) * 360 / floatSlices)),
std.math.sin(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))),
std.math.cos(std.math.rad_per_deg * (270.0 + (180.0 / (floatRings + 1.0)) * (floatI + 1.0))) * std.math.cos(std.math.rad_per_deg * ((floatJ + 1.0) * 360 / floatSlices)),
);
}
}
rlgl.rlEnd();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,5 @@
robot.glb model by @Quaternius (https://www.patreon.com/quaternius)
Licensed under CC0 1.0 Universal (CC0 1.0) - Public Domain Dedication (https://creativecommons.org/publicdomain/zero/1.0/)
greenman.glb, greenman_hat.glb, greenman_sword.glb, greenman_shield.glb models by @iP (https://github.com/ipzaur)
Licensed under CC0 1.0 Universal (CC0 1.0) - Public Domain Dedication (https://creativecommons.org/publicdomain/zero/1.0/)

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,117 @@
// raylib [shaders] example - Raymarching shapes generation
//
// Example complexity rating: [] 4/4
//
// NOTE: This example requires raylib OpenGL 3.3 for shaders support and only #version 330
// is currently supported. OpenGL ES 2.0 platforms are not supported at the moment.
//
// Example originally created with raylib 2.0, last time updated with raylib 4.2
//
// Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
// BSD-like license that allows static linking with closed source software
//
// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5)
const rl = @import("raylib");
const std = @import("std");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.setConfigFlags(rl.ConfigFlags{ .window_resizable = true });
rl.initWindow(screenWidth, screenHeight, "raylib [shaders] example - raymarching shapes");
defer rl.closeWindow(); // Close window and OpenGL context
// Define the camera to look into our 3d world
var camera = rl.Camera3D{
.position = .{ .x = 2.5, .y = 2.5, .z = 3.0 }, // Camera position
.target = .{ .x = 0.0, .y = 0.0, .z = 0.7 }, // Camera looking at point
.up = .{ .x = 0.0, .y = 1.0, .z = 0.0 }, // Camera up vector (rotation towards target)
.fovy = 65.0, // Camera field-of-view Y
.projection = .perspective, // Camera projection type
};
// Load raymarching shader
const shader = try rl.loadShader(null, "resources/shaders/glsl330/raymarching.fs");
defer rl.unloadShader(shader);
// Get shader locations for required uniforms
const viewEyeLoc = rl.getShaderLocation(shader, "viewEye");
const viewCenterLoc = rl.getShaderLocation(shader, "viewCenter");
const runTimeLoc = rl.getShaderLocation(shader, "runTime");
const resolutionLoc = rl.getShaderLocation(shader, "resolution");
var resolution = [2]f32{ @floatFromInt(screenWidth), @floatFromInt(screenHeight) };
rl.setShaderValue(shader, resolutionLoc, &resolution, .vec2);
var runTime: f32 = 0.0;
rl.disableCursor(); // Limit cursor to relative movement inside the window
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
rl.updateCamera(&camera, .first_person);
const cameraPos = [3]f32{ camera.position.x, camera.position.y, camera.position.z };
const cameraTarget = [3]f32{ camera.target.x, camera.target.y, camera.target.z };
const deltaTime = rl.getFrameTime();
runTime += deltaTime;
// Set shader required uniform values
rl.setShaderValue(shader, viewEyeLoc, &cameraPos, .vec3);
rl.setShaderValue(shader, viewCenterLoc, &cameraTarget, .vec3);
rl.setShaderValue(shader, runTimeLoc, &runTime, .float);
// Check if screen is resized
if (rl.isWindowResized()) {
resolution = [2]f32{
@floatFromInt(rl.getScreenWidth()),
@floatFromInt(rl.getScreenHeight()),
};
rl.setShaderValue(shader, resolutionLoc, &resolution, .vec2);
}
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
// We only draw a white full-screen rectangle,
// frame is generated in shader using raymarching
{
rl.beginShaderMode(shader);
defer rl.endShaderMode();
rl.drawRectangle(
0,
0,
rl.getScreenWidth(),
rl.getScreenHeight(),
.white,
);
}
rl.drawText(
"(c) Raymarching shader by Iñigo Quilez. MIT License.",
rl.getScreenWidth() - 280,
rl.getScreenHeight() - 20,
10,
.black,
);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,4 @@
| resource | author | licence | notes |
| :----------------- | :-----------: | :------ | :---- |
| fudesumi.png | [Eiden Marsal](https://www.artstation.com/marshall_z) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/) | - |
| raysan.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -0,0 +1,80 @@
#version 100
precision mediump float;
// Input from the vertex shader
varying vec2 fragTexCoord;
// Output color for the screen
varying vec4 finalColor;
uniform sampler2D texture0;
uniform vec2 resolution;
// Fontsize less then 9 may be not complete
uniform float fontSize;
float GreyScale(in vec3 col)
{
return dot(col, vec3(0.2126, 0.7152, 0.0722));
}
float GetCharacter(float n, vec2 p)
{
p = floor(p*vec2(-4.0, 4.0) + 2.5);
// Check if the calculated coordinate is inside the 5x5 grid (from 0.0 to 4.0)
if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)
{
float a = floor(p.x + 0.5) + 5.0*floor(p.y + 0.5);
// This checked if the 'a'-th bit of 'n' was set
float shiftedN = floor(n/pow(2.0, a));
if (mod(shiftedN, 2.0) == 1.0)
{
return 1.0; // The bit is on
}
}
return 0.0; // The bit is off, or we are outside the grid
}
// -----------------------------------------------------------------------------
// Main shader logic
// -----------------------------------------------------------------------------
void main()
{
vec2 charPixelSize = vec2(fontSize, fontSize);
vec2 uvCellSize = charPixelSize/resolution;
// The cell size is based on the fontSize set by application
vec2 cellUV = floor(fragTexCoord/uvCellSize)*uvCellSize;
vec3 cellColor = texture2D(texture0, cellUV).rgb;
// Gray is used to define what character will be selected to draw
float gray = GreyScale(cellColor);
float n = 4096.0;
// Character set from https://www.shadertoy.com/view/lssGDj
// Create new bitmaps https://thrill-project.com/archiv/coding/bitmap/
if (gray > 0.2) n = 65600.0; // :
if (gray > 0.3) n = 18725316.0; // v
if (gray > 0.4) n = 15255086.0; // o
if (gray > 0.5) n = 13121101.0; // &
if (gray > 0.6) n = 15252014.0; // 8
if (gray > 0.7) n = 13195790.0; // @
if (gray > 0.8) n = 11512810.0; // #
vec2 localUV = (fragTexCoord - cellUV)/uvCellSize; // Range [0.0, 1.0]
vec2 p = localUV*2.0 - 1.0; // Range [-1.0, 1.0]
// cellColor and charShape will define the color of the char
vec3 color = cellColor*GetCharacter(n, p);
gl_FragColor = vec4(color, 1.0);
}

View File

@ -0,0 +1,78 @@
#version 120
// Input from the vertex shader
varying vec2 fragTexCoord;
// Output color for the screen
varying vec4 finalColor;
uniform sampler2D texture0;
uniform vec2 resolution;
// Fontsize less then 9 may be not complete
uniform float fontSize;
float GreyScale(in vec3 col)
{
return dot(col, vec3(0.2126, 0.7152, 0.0722));
}
float GetCharacter(float n, vec2 p)
{
p = floor(p*vec2(-4.0, 4.0) + 2.5);
// Check if the calculated coordinate is inside the 5x5 grid (from 0.0 to 4.0)
if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)
{
float a = floor(p.x + 0.5) + 5.0*floor(p.y + 0.5);
// This checked if the 'a'-th bit of 'n' was set
float shiftedN = floor(n/pow(2.0, a));
if (mod(shiftedN, 2.0) == 1.0)
{
return 1.0; // The bit is on
}
}
return 0.0; // The bit is off, or we are outside the grid
}
// -----------------------------------------------------------------------------
// Main shader logic
// -----------------------------------------------------------------------------
void main()
{
vec2 charPixelSize = vec2(fontSize, fontSize);
vec2 uvCellSize = charPixelSize / resolution;
// The cell size is based on the fontSize set by application
vec2 cellUV = floor(fragTexCoord / uvCellSize)*uvCellSize;
vec3 cellColor = texture2D(texture0, cellUV).rgb;
// Gray is used to define what character will be selected to draw
float gray = GreyScale(cellColor);
float n = 4096.0;
// Character set from https://www.shadertoy.com/view/lssGDj
// Create new bitmaps https://thrill-project.com/archiv/coding/bitmap/
if (gray > 0.2) n = 65600.0; // :
if (gray > 0.3) n = 18725316.0; // v
if (gray > 0.4) n = 15255086.0; // o
if (gray > 0.5) n = 13121101.0; // &
if (gray > 0.6) n = 15252014.0; // 8
if (gray > 0.7) n = 13195790.0; // @
if (gray > 0.8) n = 11512810.0; // #
vec2 localUV = (fragTexCoord - cellUV)/uvCellSize; // Range [0.0, 1.0]
vec2 p = localUV*2.0 - 1.0; // Range [-1.0, 1.0]
// cellColor and charShape will define the color of the char
vec3 color = cellColor*GetCharacter(n, p);
gl_FragColor = vec4(color, 1.0);
}

View File

@ -0,0 +1,73 @@
#version 330
// Input from the vertex shader
in vec2 fragTexCoord;
// Output color for the screen
out vec4 finalColor;
uniform sampler2D texture0;
uniform vec2 resolution;
// Fontsize less then 9 may be not complete
uniform float fontSize;
float GreyScale(in vec3 col)
{
return dot(col, vec3(0.2126, 0.7152, 0.0722));
}
float GetCharacter(int n, vec2 p)
{
p = floor(p*vec2(-4.0, 4.0) + 2.5);
// Check if the coordinate is inside the 5x5 grid (0 to 4)
if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)
{
int a = int(round(p.x) + 5.0*round(p.y));
if (((n >> a) & 1) == 1)
{
return 1.0;
}
}
return 0.0; // The bit is off, or we are outside the grid
}
// -----------------------------------------------------------------------------
// Main shader logic
// -----------------------------------------------------------------------------
void main()
{
vec2 charPixelSize = vec2(fontSize, fontSize);
vec2 uvCellSize = charPixelSize/resolution;
// The cell size is based on the fontSize set by application
vec2 cellUV = floor(fragTexCoord/uvCellSize)*uvCellSize;
vec3 cellColor = texture(texture0, cellUV).rgb;
// Gray is used to define what character will be selected to draw
float gray = GreyScale(cellColor);
int n = 4096;
// Character set from https://www.shadertoy.com/view/lssGDj
// Create new bitmaps https://thrill-project.com/archiv/coding/bitmap/
if (gray > 0.2) n = 65600; // :
if (gray > 0.3) n = 18725316; // v
if (gray > 0.4) n = 15255086; // o
if (gray > 0.5) n = 13121101; // &
if (gray > 0.6) n = 15252014; // 8
if (gray > 0.7) n = 13195790; // @
if (gray > 0.8) n = 11512810; // #
vec2 localUV = (fragTexCoord - cellUV)/uvCellSize; // Range [0.0, 1.0]
vec2 p = localUV*2.0 - 1.0; // Range [-1.0, 1.0]
vec3 color = cellColor*GetCharacter(n, p);
finalColor = vec4(color, 1.0);
}

View File

@ -0,0 +1,100 @@
// raylib-zig (c) 2025 Maicon Santana (@maiconpintoabreu)
const builtin = @import("builtin");
const rl = @import("raylib");
const GLSL_VERSION: i16 = if (builtin.cpu.arch.isWasm()) 100 else 330;
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [core] example - monitor change");
// De-Initialization
//--------------------------------------------------------------------------------------
defer rl.closeWindow(); // Close window and OpenGL context
// Texture to test static drawing
const fudesumi: rl.Texture2D = try rl.loadTexture("examples/shaders/resources/fudesumi.png");
defer fudesumi.unload();
// Texture to test moving drawing
const raysan: rl.Texture2D = try rl.loadTexture("examples/shaders/resources/raysan.png");
defer raysan.unload();
// Load shader to be used on postprocessing
const shader: rl.Shader = try rl.loadShader(
null,
rl.textFormat("examples/shaders/resources/shaders/glsl%i/ascii.fs", .{GLSL_VERSION}),
);
// These locations are used to send data to the GPU
const resolutionLoc: i32 = rl.getShaderLocation(shader, "resolution");
const fontSizeLoc: i32 = rl.getShaderLocation(shader, "fontSize");
// Set the character size for the ASCII effect
// Fontsize should be 9 or more
var fontSize: f32 = 9.0;
// Send the updated values to the shader
const resolution: rl.Vector2 = .{ .x = @floatFromInt(screenWidth), .y = @floatFromInt(screenHeight) };
rl.setShaderValue(shader, resolutionLoc, &resolution, .vec2);
var circlePos: rl.Vector2 = .{ .x = 40.0, .y = @as(f32, @floatFromInt(screenHeight)) * 0.5 };
var circleSpeed: f32 = 1.0;
// RenderTexture to apply the postprocessing later
const target: rl.RenderTexture2D = try rl.loadRenderTexture(screenWidth, screenHeight);
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
circlePos.x += circleSpeed;
if ((circlePos.x > 200.0) or (circlePos.x < 40.0)) circleSpeed *= -1; // Revert speed
if (rl.isKeyPressed(.left) and (fontSize > 9.0)) fontSize -= 1.0; // Reduce fontSize
if (rl.isKeyPressed(.right) and (fontSize < 15.0)) fontSize += 1.0; // Increase fontSize
// Set fontsize for the shader
rl.setShaderValue(shader, fontSizeLoc, &fontSize, .float);
// Draw
//----------------------------------------------------------------------------------
{
rl.beginTextureMode(target);
defer rl.endTextureMode();
rl.clearBackground(.white);
// Draw scene in our render texture
rl.drawTexture(fudesumi, 500, -30, .white);
rl.drawTextureV(raysan, circlePos, .white);
}
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
{
rl.beginShaderMode(shader);
defer rl.endShaderMode();
// Draw the scene texture (that we rendered earlier) to the screen
// The shader will process every pixel of this texture
rl.drawTextureRec(target.texture, .{
.x = 0,
.y = 0,
.width = @floatFromInt(target.texture.width),
.height = -@as(f32, @floatFromInt(target.texture.height)),
}, .zero(), .white);
}
rl.drawRectangle(0, 0, screenWidth, 40, .black);
rl.drawText(rl.textFormat("Ascii effect - FontSize:%2.0f - [Left] -1 [Right] +1 ", .{fontSize}), 120, 10, 20, .light_gray);
rl.drawFPS(10, 10);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,366 @@
// raylib [shaders] example - Basic PBR
//
// Example complexity rating: [] 4/4
//
// Example originally created with raylib 5.0, last time updated with raylib 5.1-dev
//
// Example contributed by Afan OLOVCIC (@_DevDad) and reviewed by Ramon Santamaria (@raysan5)
//
// Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
// BSD-like license that allows static linking with closed source software
//
// Copyright (c) 2023-2025 Afan OLOVCIC (@_DevDad)
//
// Model: "Old Rusty Car" (https://skfb.ly/LxRy) by Renafox,
// licensed under Creative Commons Attribution-NonCommercial
// (http://creativecommons.org/licenses/by-nc/4.0/)
const rl = @import("raylib");
/// Casts ShaderLocationIndex to a u32
fn uSli(sli: rl.ShaderLocationIndex) u32 {
return @intCast(@intFromEnum(sli));
}
/// Casts MaterialMapIndex to a u32
fn uMmi(mmi: rl.MaterialMapIndex) u32 {
return @intCast(@intFromEnum(mmi));
}
/// Max dynamic lights supported by shader
const max_lights = 4;
/// Current number of dynamic lights that have been created
var light_count: u32 = 0;
//------------------------------------------------------------------------------
// Types and Structures Definition
//------------------------------------------------------------------------------
/// Light data
const Light = extern struct {
type: Type = .directional,
enabled: bool = false,
_enabled_pad1: u8 = 0,
_enabled_pad2: @Type(.{.int = .{
.signedness = .unsigned,
.bits = @bitSizeOf(c_uint) - 16,
}}) = 0,
position: rl.Vector3 = .init(0, 0, 0),
target: rl.Vector3 = .init(0, 0, 0),
color: [4]f32 = .{ 0, 0, 0, 0 },
intensity: f32 = 0,
// Shader light parameters locations
loc: extern struct {
type: i32 = 0,
enabled: i32 = 0,
position: i32 = 0,
target: i32 = 0,
color: i32 = 0,
intensity: i32 = 0,
} = .{},
/// Light type
const Type = enum(c_uint) {
directional = 0,
point,
spot,
};
/// Create light with provided data
///
/// NOTE: It updates `light_count` and is limited to `max_lights`
fn init(
t: Type,
position: rl.Vector3,
target: rl.Vector3,
color: rl.Color,
intensity: f32,
shader: rl.Shader,
) Light {
if (light_count >= max_lights) {
return .{};
}
const light: Light = .{
.type = t,
.enabled = true,
.position = position,
.target = target,
.color = .{
@as(f32, @floatFromInt(color.r)) / 255.0,
@as(f32, @floatFromInt(color.g)) / 255.0,
@as(f32, @floatFromInt(color.b)) / 255.0,
@as(f32, @floatFromInt(color.a)) / 255.0,
},
.intensity = intensity,
// NOTE: Shader parameters names for lights must match the requested ones
.loc = .{
.type = rl.getShaderLocation(shader, rl.textFormat("lights[%i].type", .{ light_count })),
.enabled = rl.getShaderLocation(shader, rl.textFormat("lights[%i].enabled", .{ light_count })),
.position = rl.getShaderLocation(shader, rl.textFormat("lights[%i].position", .{ light_count })),
.target = rl.getShaderLocation(shader, rl.textFormat("lights[%i].target", .{ light_count })),
.color = rl.getShaderLocation(shader, rl.textFormat("lights[%i].color", .{ light_count })),
.intensity = rl.getShaderLocation(shader, rl.textFormat("lights[%i].intensity", .{ light_count })),
},
};
light.update(shader);
light_count += 1;
return light;
}
/// Send light properties to shader
///
/// NOTE: Light shader locations should be available
fn update(self: Light, shader: rl.Shader) void {
rl.setShaderValue(shader, self.loc.type, &self.type, .int);
rl.setShaderValue(shader, self.loc.enabled, &self.enabled, .int);
// Send to shader light position values
const position: [3]f32 = .{ self.position.x, self.position.y, self.position.z };
rl.setShaderValue(shader, self.loc.position, &position, .vec3);
// Send to shader light target position values
const target: [3]f32 = .{ self.target.x, self.target.y, self.target.z };
rl.setShaderValue(shader, self.loc.target, &target, .vec3);
rl.setShaderValue(shader, self.loc.color, &self.color, .vec4);
rl.setShaderValue(shader, self.loc.intensity, &self.intensity, .float);
}
};
//----------------------------------------------------------------------------------
// Main Entry Point
//----------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.setConfigFlags(.{ .msaa_4x_hint = true });
rl.initWindow(screen_width, screen_height, "raylib [shaders] example - basic pbr");
defer rl.closeWindow(); // Close window and OpenGL context
// Define the camera to look into our 3d world
var camera: rl.Camera = .{
.position = .init(2, 2, 6), // Camera position
.target = .init(0, 0.5, 0), // Camera looking at point
.up = .init(0, 1, 0), // Camera up vector (rotation towards target)
.fovy = 45, // Camera field-of-view Y
.projection = .perspective, // Camera projection type
};
// Load PBR shader and setup all required locations
const shader: rl.Shader = try rl.loadShader(
"resources/shaders/glsl330/pbr.vs",
"resources/shaders/glsl330/pbr.fs",
);
defer rl.unloadShader(shader);
shader.locs[uSli(.map_albedo)] = rl.getShaderLocation(shader, "albedoMap");
// WARNING: Metalness, roughness, and ambient occlusion are all packed into a MRA texture
// They are passed as to the SHADER_LOC_MAP_METALNESS location for convenience,
// shader already takes care of it accordingly
shader.locs[uSli(.map_metalness)] = rl.getShaderLocation(shader, "mraMap");
shader.locs[uSli(.map_normal)] = rl.getShaderLocation(shader, "normalMap");
// WARNING: Similar to the MRA map, the emissive map packs different information
// into a single texture: it stores height and emission data
// It is binded to SHADER_LOC_MAP_EMISSION location an properly processed on shader
shader.locs[uSli(.map_emission)] = rl.getShaderLocation(shader, "emissiveMap");
shader.locs[uSli(.color_diffuse)] = rl.getShaderLocation(shader, "albedoColor");
// Setup additional required shader locations, including lights data
shader.locs[uSli(.vector_view)] = rl.getShaderLocation(shader, "viewPos");
const loc_light_count: i32 = rl.getShaderLocation(shader, "numOfLights");
const max_light_count: i32 = max_lights;
rl.setShaderValue(shader, loc_light_count, &max_light_count, .int);
// Setup ambient color and intensity parameters
const ambient_intensity: f32 = 0.02;
const ambient_color: rl.Vector3 = blk: {
const c: rl.Color = .init(26, 32, 135, 255);
break :blk .init(
@as(f32, @floatFromInt(c.r)) / 255.0,
@as(f32, @floatFromInt(c.g)) / 255.0,
@as(f32, @floatFromInt(c.b)) / 255.0,
);
};
rl.setShaderValue(shader, rl.getShaderLocation(shader, "ambientColor"), &ambient_color, .vec3);
rl.setShaderValue(shader, rl.getShaderLocation(shader, "ambient"), &ambient_intensity, .float);
// Get location for shader parameters that can be modified in real time
const loc_metallic_value = rl.getShaderLocation(shader, "metallicValue");
const loc_roughness_value = rl.getShaderLocation(shader, "roughnessValue");
const loc_emissive_intensity = rl.getShaderLocation(shader, "emissivePower");
const loc_emissive_color = rl.getShaderLocation(shader, "emissiveColor");
const loc_texture_tiling = rl.getShaderLocation(shader, "tiling");
// Load old car model using PBR maps and shader
// WARNING: We know this model consists of a single model.meshes[0] and
// that model.materials[0] is by default assigned to that mesh
// There could be more complex models consisting of multiple meshes and
// multiple materials defined for those meshes... but always 1 mesh = 1 material
const car: rl.Model = try .init("resources/models/old_car_new.glb");
defer {
car.materials[0].shader = .{ .id = 0, .locs = null };
rl.unloadMaterial(car.materials[0]);
car.materials[0].maps = null;
car.unload();
}
// Assign already setup PBR shader to model.materials[0], used by models.meshes[0]
car.materials[0].shader = shader;
// Setup materials[0].maps default parameters
car.materials[0].maps[uMmi(.albedo)].color = .white;
car.materials[0].maps[uMmi(.metalness)].value = 1.0;
car.materials[0].maps[uMmi(.roughness)].value = 0.0;
car.materials[0].maps[uMmi(.occlusion)].value = 1.0;
car.materials[0].maps[uMmi(.emission)].color = .init(255, 162, 0, 255);
// Setup materials[0].maps default textures
car.materials[0].maps[uMmi(.albedo)].texture = try .init("resources/textures/old_car_d.png");
car.materials[0].maps[uMmi(.metalness)].texture = try .init("resources/textures/old_car_mra.png");
car.materials[0].maps[uMmi(.normal)].texture = try .init("resources/textures/old_car_n.png");
car.materials[0].maps[uMmi(.emission)].texture = try .init("resources/textures/old_car_e.png");
// Load floor model mesh and assign material parameters
// NOTE: A basic plane shape can be generated instead of being loaded from a model file
const floor: rl.Model = try .init("resources/models/plane.glb");
defer {
floor.materials[0].shader = .{ .id = 0, .locs = null };
rl.unloadMaterial(floor.materials[0]);
floor.materials[0].maps = null;
floor.unload();
}
//Mesh floorMesh = GenMeshPlane(10, 10, 10, 10);
//GenMeshTangents(&floorMesh); // TODO: Review tangents generation
//Model floor = LoadModelFromMesh(floorMesh);
// Assign material shader for our floor model, same PBR shader
floor.materials[0].shader = shader;
floor.materials[0].maps[uMmi(.albedo)].color = .white;
floor.materials[0].maps[uMmi(.metalness)].value = 0.8;
floor.materials[0].maps[uMmi(.roughness)].value = 0.1;
floor.materials[0].maps[uMmi(.occlusion)].value = 1.0;
floor.materials[0].maps[uMmi(.emission)].color = .black;
floor.materials[0].maps[uMmi(.albedo)].texture = try .init("resources/textures/road_a.png");
floor.materials[0].maps[uMmi(.metalness)].texture = try .init("resources/textures/road_mra.png");
floor.materials[0].maps[uMmi(.normal)].texture = try .init("resources/textures/road_n.png");
// Models texture tiling parameter can be stored in the Material struct if required (CURRENTLY NOT USED)
// NOTE: Material.params[4] are available for generic parameters storage (float)
const car_texture_tiling: rl.Vector2 = .init(0.5, 0.5);
const floor_texture_tiling: rl.Vector2 = .init(0.5, 0.5);
// Create some lights
var lights: [max_lights]Light = .{
.init(.point, .init(-1, 1, -2), .init(0, 0, 0), .yellow, 4, shader),
.init(.point, .init(2, 1, 1), .init(0, 0, 0), .green, 3.3, shader),
.init(.point, .init(-2, 1, 1), .init(0, 0, 0), .red, 8.3, shader),
.init(.point, .init(1, 1, -2), .init(0, 0, 0), .blue, 2, shader),
};
// Setup material texture maps usage in shader
// NOTE: By default, the texture maps are always used
const usage: i32 = 1;
rl.setShaderValue(shader, rl.getShaderLocation(shader, "useTexAlbedo"), &usage, .int);
rl.setShaderValue(shader, rl.getShaderLocation(shader, "useTexNormal"), &usage, .int);
rl.setShaderValue(shader, rl.getShaderLocation(shader, "useTexMRA"), &usage, .int);
rl.setShaderValue(shader, rl.getShaderLocation(shader, "useTexEmissive"), &usage, .int);
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//---------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
camera.update(.orbital);
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
const camera_pos: [3]f32 = .{ camera.position.x, camera.position.y, camera.position.z };
rl.setShaderValue(shader, shader.locs[uSli(.vector_view)], &camera_pos, .vec3);
// Check key inputs to enable/disable lights
if (rl.isKeyPressed(.one)) {
lights[2].enabled = !lights[2].enabled;
}
if (rl.isKeyPressed(.two)) {
lights[1].enabled = !lights[1].enabled;
}
if (rl.isKeyPressed(.three)) {
lights[3].enabled = !lights[3].enabled;
}
if (rl.isKeyPressed(.four)) {
lights[0].enabled = !lights[0].enabled;
}
// Update light values on shader (actually, only enable/disable them)
for (&lights) |*l| {
l.update(shader);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.black);
{
rl.beginMode3D(camera);
defer rl.endMode3D();
// Set floor model texture tiling and emissive color parameters on shader
rl.setShaderValue(shader, loc_texture_tiling, &floor_texture_tiling, .vec2);
const floor_emissive_color: rl.Vector4 = rl.colorNormalize(floor.materials[0].maps[uMmi(.emission)].color);
rl.setShaderValue(shader, loc_emissive_color, &floor_emissive_color, .vec4);
// Set floor metallic and roughness values
rl.setShaderValue(shader, loc_metallic_value, &floor.materials[0].maps[uMmi(.metalness)].value, .float);
rl.setShaderValue(shader, loc_roughness_value, &floor.materials[0].maps[uMmi(.roughness)].value, .float);
floor.draw(.init(0, 0, 0), 5, .white); // Draw floor model
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
rl.setShaderValue(shader, loc_texture_tiling, &car_texture_tiling, .vec2);
const car_emissive_color: rl.Vector4 = rl.colorNormalize(car.materials[0].maps[uMmi(.emission)].color);
rl.setShaderValue(shader, loc_emissive_color, &car_emissive_color, .vec4);
const emissive_intensity: f32 = 0.01;
rl.setShaderValue(shader, loc_emissive_intensity, &emissive_intensity, .float);
// Set old car metallic and roughness values
rl.setShaderValue(shader, loc_metallic_value, &car.materials[0].maps[uMmi(.metalness)].value, .float);
rl.setShaderValue(shader, loc_roughness_value, &car.materials[0].maps[uMmi(.roughness)].value, .float);
car.draw(.init(0, 0, 0), 0.25, .white); // Draw car model
// Draw spheres to show the lights positions
for (&lights) |*l| {
const light_color: rl.Color = .init(
@intFromFloat(l.color[0] * 255),
@intFromFloat(l.color[1] * 255),
@intFromFloat(l.color[2] * 255),
@intFromFloat(l.color[3] * 255),
);
if (l.enabled) {
rl.drawSphereEx(l.position, 0.2, 8, 8, light_color);
} else {
rl.drawSphereWires(l.position, 0.2, 8, 8, rl.colorAlpha(light_color, 0.3));
}
}
}
rl.drawText("Toggle lights: [1][2][3][4]", 10, 40, 20, .light_gray);
rl.drawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)",
screen_width - 320, screen_height - 20, 10, .light_gray);
rl.drawFPS(10, 10);
}
}

View File

@ -0,0 +1,197 @@
// raylib [shaders] example - Hybrid Rendering
//
// Example complexity rating: [] 4/4
//
// Example originally created with raylib 4.2, last time updated with raylib 4.2
//
// Example contributed by Buğra Alptekin Sarı (@BugraAlptekinSari) and reviewed by Ramon Santamaria (@raysan5)
//
// Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
// BSD-like license that allows static linking with closed source software
//
// Copyright (c) 2022-2025 Buğra Alptekin Sarı (@BugraAlptekinSari)
const rl = @import("raylib");
const pi = @import("std").math.pi;
//------------------------------------------------------------------------------------
// Declare custom Structs
//------------------------------------------------------------------------------------
const RayLocs = struct {
cam_pos: i32,
cam_dir: i32,
screen_center: i32,
};
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [shaders] example - write depth buffer");
defer rl.closeWindow(); // Close window and OpenGL context
// This Shader calculates pixel depth and color using raymarch
const shdr_raymarch: rl.Shader = try rl.loadShader(null, "resources/shaders/glsl330/hybrid_raymarch.fs");
defer rl.unloadShader(shdr_raymarch);
// This Shader is a standard rasterization fragment shader with the addition of depth writing
// You are required to write depth for all shaders if one shader does it
const shdr_raster: rl.Shader = try rl.loadShader(null, "resources/shaders/glsl330/hybrid_raster.fs");
defer rl.unloadShader(shdr_raster);
// Declare Struct used to store camera locs.
const march_locs: RayLocs = .{
.cam_pos = rl.getShaderLocation(shdr_raymarch, "camPos"),
.cam_dir = rl.getShaderLocation(shdr_raymarch, "camDir"),
.screen_center = rl.getShaderLocation(shdr_raymarch, "screenCenter"),
};
// Transfer screenCenter position to shader. Which is used to calculate ray direction.
const screen_center: rl.Vector2 = .init(screen_width / 2.0, screen_height / 2.0);
rl.setShaderValue(shdr_raymarch, march_locs.screen_center , &screen_center , .vec2);
// Use Customized function to create writable depth texture buffer
const target: rl.RenderTexture2D = try loadRenderTextureDepthTex(screen_width, screen_height);
defer unloadRenderTextureDepthTex(target);
// Define the camera to look into our 3d world
var camera: rl.Camera = .{
.position = .init(0.5, 1, 1.5), // Camera position
.target = .init(0, 0.5, 0), // Camera looking at point
.up = .init(0, 1, 0), // Camera up vector (rotation towards target)
.fovy = 45, // Camera field-of-view Y
.projection = .perspective, // Camera projection type
};
// Camera FOV is pre-calculated in the camera Distance.
const cam_dist: f32 = 1.0 / @tan(camera.fovy * 0.5 * (pi / 180.0));
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
camera.update(.orbital);
// Update Camera Postion in the ray march shader.
rl.setShaderValue(shdr_raymarch, march_locs.cam_pos, &camera.position, .vec3);
// Update Camera Looking Vector. Vector length determines FOV.
const cam_dir: rl.Vector3 = .scale(.normalize(.subtract(camera.target, camera.position)), cam_dist);
rl.setShaderValue(shdr_raymarch, march_locs.cam_dir, &cam_dir, .vec3);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw into our custom render texture (framebuffer)
{
target.begin();
defer target.end();
rl.clearBackground(.white);
// Raymarch Scene
rl.gl.rlEnableDepthTest(); //Manually enable Depth Test to handle multiple rendering methods.
{
shdr_raymarch.activate();
defer shdr_raymarch.deactivate();
rl.drawRectangleRec(.init(0, 0, screen_width, screen_height), .white);
}
// Rasterize Scene
{
rl.beginMode3D(camera);
defer rl.endMode3D();
shdr_raster.activate();
defer shdr_raster.deactivate();
rl.drawCubeWiresV(.init(0, 0.5, 1), .init(1, 1, 1), .red);
rl.drawCubeV(.init(0, 0.5, 1), .init(1, 1, 1), .purple);
rl.drawCubeWiresV(.init(0, 0.5, -1), .init(1, 1, 1), .dark_green);
rl.drawCubeV(.init(0, 0.5, -1), .init(1, 1, 1), .yellow);
rl.drawGrid(10, 1);
}
}
// Draw into screen our custom render texture
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
target.texture.drawRec(.init(0, 0, screen_width, -screen_height), .init(0, 0), .white);
rl.drawFPS(10, 10);
}
}
//------------------------------------------------------------------------------------
// Define custom functions required for the example
//------------------------------------------------------------------------------------
// Load custom render texture, create a writable depth texture buffer
fn loadRenderTextureDepthTex(width: i32, height: i32) !rl.RenderTexture2D {
const id = rl.gl.rlLoadFramebuffer(); // Load an empty framebuffer
if (id <= 0) {
return error.LoadFrameBufferFail;
}
rl.gl.rlEnableFramebuffer(id);
defer rl.gl.rlDisableFramebuffer();
const pix_format: i32 = @intFromEnum(rl.gl.rlPixelFormat.rl_pixelformat_uncompressed_r8g8b8a8);
const target: rl.RenderTexture2D = .{
.id = id,
// Create color texture (default to RGBA)
.texture = .{
.id = rl.gl.rlLoadTexture(null, width, height, pix_format, 1),
.width = width,
.height = height,
.format = .uncompressed_r8g8b8a8,
.mipmaps = 1,
},
// Create depth texture buffer (instead of raylib default renderbuffer)
.depth = .{
.id = rl.gl.rlLoadTextureDepth(width, height, false),
.width = width,
.height = height,
.format = .compressed_etc2_rgb, //DEPTH_COMPONENT_24BIT?
.mipmaps = 1,
}
};
// Attach color texture and depth texture to FBO
const channel0: i32 = @intFromEnum(rl.gl.rlFramebufferAttachType.rl_attachment_color_channel0);
const depth: i32 = @intFromEnum(rl.gl.rlFramebufferAttachType.rl_attachment_depth);
const texture2d: i32 = @intFromEnum(rl.gl.rlFramebufferAttachTextureType.rl_attachment_texture2d);
rl.gl.rlFramebufferAttach(target.id, target.texture.id, channel0, texture2d, 0);
rl.gl.rlFramebufferAttach(target.id, target.depth.id, depth, texture2d, 0);
// Check if fbo is complete with attachments (valid)
if (rl.gl.rlFramebufferComplete(target.id)) {
rl.traceLog(.info, "FBO: [ID %i] Framebuffer object created successfully", .{ target.id });
}
return target;
}
// Unload render texture from GPU memory (VRAM)
fn unloadRenderTextureDepthTex(target: rl.RenderTexture2D) void {
// Color texture attached to FBO is deleted
rl.gl.rlUnloadTexture(target.texture.id);
rl.gl.rlUnloadTexture(target.depth.id);
// NOTE: Depth texture is automatically
// queried and deleted before deleting framebuffer
rl.gl.rlUnloadFramebuffer(target.id);
}

View File

@ -15,10 +15,10 @@ pub fn main() anyerror!void {
rl.initWindow(screenWidth, screenHeight, "raylib [shaders] example - Apply an outline to a texture");
defer rl.closeWindow(); // Close window and OpenGL context
const texture: rl.Texture = rl.Texture.init("resources/textures/fudesumi.png");
const texture: rl.Texture = try .init("resources/textures/fudesumi.png");
defer rl.unloadTexture(texture);
const shdrOutline: rl.Shader = rl.loadShader(null, "resources/shaders/glsl330/outline.fs");
const shdrOutline: rl.Shader = try rl.loadShader(null, "resources/shaders/glsl330/outline.fs");
defer rl.unloadShader(shdrOutline);
var outlineSize: f32 = 2.0;
@ -38,19 +38,19 @@ pub fn main() anyerror!void {
shdrOutline,
outlineSizeLoc,
&outlineSize,
rl.ShaderUniformDataType.shader_uniform_float,
.float,
);
rl.setShaderValue(
shdrOutline,
outlineColorLoc,
&outlineColor,
rl.ShaderUniformDataType.shader_uniform_vec4,
.vec4,
);
rl.setShaderValue(
shdrOutline,
textureSizeLoc,
&textureSize,
rl.ShaderUniformDataType.shader_uniform_vec2,
.vec2,
);
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
@ -67,7 +67,7 @@ pub fn main() anyerror!void {
shdrOutline,
outlineSizeLoc,
&outlineSize,
rl.ShaderUniformDataType.shader_uniform_float,
.float,
);
//----------------------------------------------------------------------------------
@ -76,7 +76,7 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
{
rl.beginShaderMode(shdrOutline);
@ -85,18 +85,18 @@ pub fn main() anyerror!void {
texture.draw(
@divFloor(rl.getScreenWidth(), 2) - @divFloor(texture.width, 2),
-30,
rl.Color.white,
.white,
);
}
rl.drawText("Shader-based\ntexture\noutline", 10, 10, 20, rl.Color.gray);
rl.drawText("Shader-based\ntexture\noutline", 10, 10, 20, .gray);
rl.drawText(
rl.textFormat("Outline size: %i px", .{@as(i32, @intFromFloat(outlineSize))}),
10,
120,
20,
rl.Color.maroon,
.maroon,
);
rl.drawFPS(710, 10);

View File

@ -0,0 +1,58 @@
const rl = @import("raylib");
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - basic shapes drawing");
defer rl.closeWindow(); // Close window and OpenGL context
var rotation: f32 = 0.0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
rotation += 0.2;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("some basic shapes available on raylib", 20, 20, 20, .dark_gray);
// Circle shapes and lines
rl.drawCircle(screenWidth / 5, 120, 35, .dark_blue);
rl.drawCircleGradient(screenWidth / 5, 220, 60, .green, .sky_blue);
rl.drawCircleLines(screenWidth / 5, 340, 80, .dark_blue);
// Rectangle shapes and lines
rl.drawRectangle(screenWidth / 4 * 2 - 60, 100, 120, 60, .red);
rl.drawRectangleGradientH(screenWidth / 4 * 2 - 90, 170, 180, 130, .maroon, .gold);
rl.drawRectangleLines(screenWidth / 4 * 2 - 40, 320, 80, 60, .orange); // NOTE: Uses QUADS internally, not lines
// Triangle shapes and lines
rl.drawTriangle(.{ .x = (screenWidth / 4.0 * 3.0), .y = 80.0 }, .{ .x = (screenWidth / 4.0 * 3.0 - 60.0), .y = 150.0 }, .{ .x = (screenWidth / 4.0 * 3.0 + 60.0), .y = 150.0 }, .violet);
rl.drawTriangleLines(.{ .x = (screenWidth / 4.0 * 3.0), .y = 160.0 }, .{ .x = (screenWidth / 4.0 * 3.0 - 20.0), .y = 230.0 }, .{ .x = (screenWidth / 4.0 * 3.0 + 20.0), .y = 230.0 }, .dark_blue);
// Polygon shapes and lines
rl.drawPoly(.{ .x = (screenWidth / 4.0 * 3), .y = 330 }, 6, 80, rotation, .brown);
rl.drawPolyLines(.{ .x = (screenWidth / 4.0 * 3), .y = 330 }, 6, 90, rotation, .brown);
rl.drawPolyLinesEx(.{ .x = (screenWidth / 4.0 * 3), .y = 330 }, 6, 85, rotation, 6, .beige);
// NOTE: We draw all LINES based shapes together to optimize internal drawing,
// this way, all LINES are rendered in a single draw pass
rl.drawLine(18, 42, screenWidth - 18, 42, .black);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,69 @@
const rl = @import("raylib");
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - bouncing ball");
defer rl.closeWindow(); // Close window and OpenGL context
var ballPosition: rl.Vector2 = rl.Vector2{
.x = @floatFromInt(@divExact(rl.getScreenWidth(), 2)),
.y = @floatFromInt(@divExact(rl.getScreenHeight(), 2)),
};
var ballSpeed: rl.Vector2 = rl.Vector2{ .x = 5.0, .y = 4.0 };
const ballRadius: i32 = 20;
var pause: bool = false;
var framesCounter: i32 = 0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
if (rl.isKeyPressed(.space)) {
pause = !pause;
}
if (!pause) {
ballPosition.x += ballSpeed.x;
ballPosition.y += ballSpeed.y;
const ballWidthEdge: f32 = @floatFromInt(rl.getScreenWidth() - ballRadius);
if ((ballPosition.x >= ballWidthEdge) or (ballPosition.x <= ballRadius)) {
ballSpeed.x = ballSpeed.x * -1.0;
}
const ballHeightEdge: f32 = @floatFromInt(rl.getScreenHeight() - ballRadius);
if ((ballPosition.y >= ballHeightEdge) or (ballPosition.y <= ballRadius)) {
ballSpeed.y = ballSpeed.y * -1.0;
}
} else {
framesCounter += 1;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawCircleV(ballPosition, ballRadius, .maroon);
rl.drawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, rl.getScreenHeight() - 25, 20, .light_gray);
// On pause, we draw a blinking message
if (pause and @mod(@divFloor(framesCounter, 30), 2) == 0) {
rl.drawText("PAUSED", 350, 200, 30, .gray);
}
rl.drawFPS(10, 10);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,114 @@
const rl = @import("raylib");
fn boxFmt(colliding: bool) rl.Color {
if (colliding) return .red;
return .black;
}
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - collision area");
defer rl.closeWindow(); // Close window and OpenGL context
// Box A: Movingbox
var boxA = rl.Rectangle{ .x = 10, .y = (@as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0) - 50, .width = 200, .height = 100 };
var boxASpeedX: f32 = 4;
// Box B: Mouse moved box
var boxB = rl.Rectangle{ .x = (@as(f32, @floatFromInt(rl.getScreenWidth())) / 2.0) - 30, .y = (@as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0) - 30, .width = 60, .height = 60 };
var boxCollision = rl.Rectangle{ .x = 0, .y = 0, .width = 0, .height = 0 };
const screenUpperLimit = 40;
var pause = false;
var collision = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
// Move box if not paused
if (!pause) {
boxA.x += boxASpeedX;
}
// Bounce box on x screen limits
if ((boxA.x + boxA.width) >= @as(f32, @floatFromInt(rl.getScreenWidth())) or (boxA.x <= 0)) {
boxASpeedX *= -1;
}
// Update player-controlled-box (box02)
boxB.x = @as(f32, @floatFromInt(rl.getMouseX())) - boxB.width / 2;
boxB.y = @as(f32, @floatFromInt(rl.getMouseY())) - boxB.height / 2;
// Make sure Box B does not go out of move area limits
if ((boxB.x + boxB.width) >= @as(f32, @floatFromInt(rl.getScreenWidth()))) {
boxB.x = @as(f32, @floatFromInt(rl.getScreenWidth())) - boxB.width;
} else if (boxB.x <= 0) {
boxB.x = 0;
}
if ((boxB.y + boxB.height) >= @as(f32, @floatFromInt(rl.getScreenHeight()))) {
boxB.y = @as(f32, @floatFromInt(rl.getScreenHeight())) - boxB.height;
} else if (boxB.y <= screenUpperLimit) {
boxB.y = screenUpperLimit;
}
// Check boxes collision
collision = rl.checkCollisionRecs(boxA, boxB);
// Get collision rectangle (only on collision)
if (collision) {
boxCollision = rl.getCollisionRec(boxA, boxB);
}
// Pause Box A movement
if (rl.isKeyPressed(.space)) {
pause = !pause;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.drawRectangle(0, 0, screenWidth, screenUpperLimit, boxFmt(collision));
rl.drawRectangleRec(boxA, .gold);
rl.drawRectangleRec(boxB, .blue);
if (collision) {
// Draw collision area
rl.drawRectangleRec(boxCollision, .lime);
// Draw collision message
rl.drawText(
"COLLISION!",
@divFloor(rl.getScreenWidth(), @as(i32, 2)) - @divFloor(rl.measureText("COLLISION!", 20), @as(i32, 2)),
screenUpperLimit / 2 - 10,
20,
.black,
);
// Draw collision area
rl.drawText(rl.textFormat("Collision Area: %i", .{@as(i32, @intFromFloat(boxCollision.width * boxCollision.height))}), @divFloor(rl.getScreenWidth(), 2) - 100, screenUpperLimit + 10, 20, .black);
}
// Draw help instructions
rl.drawText("Press SPACE to PAUSE/RESUME", 20, screenHeight - 35, 20, .light_gray);
rl.drawFPS(10, 10);
rl.clearBackground(.ray_white);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,126 @@
const std = @import("std");
const rl = @import("raylib");
const maxColorCount = 21; // Number of colors available
pub fn getAlpha(state: bool) f32 {
if (state) {
return 0.6;
}
return 1.0;
}
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - colors palette");
defer rl.closeWindow(); // Close window and OpenGL context
const colors = [maxColorCount]rl.Color{
.dark_gray,
.maroon,
.orange,
.dark_green,
.dark_blue,
.dark_purple,
.dark_brown,
.gray,
.red,
.gold,
.lime,
.blue,
.violet,
.brown,
.light_gray,
.pink,
.yellow,
.green,
.sky_blue,
.purple,
.beige,
};
const colorNames = [maxColorCount][:0]const u8{
"DARKGRAY",
"MAROON",
"ORANGE",
"DARKGREEN",
"DARKBLUE",
"DARKPURPLE",
"DARKBROWN",
"GRAY",
"RED",
"GOLD",
"LIME",
"BLUE",
"VIOLET",
"BROWN",
"LIGHTGRAY",
"PINK",
"YELLOW",
"GREEN",
"SKYBLUE",
"PURPLE",
"BEIGE",
};
var colorsRecs = std.mem.zeroes([maxColorCount]rl.Rectangle);
var i: u8 = 0;
while (i < maxColorCount) : (i += 1) {
colorsRecs[i].x = 20.0 + 100.0 * @as(f32, @floatFromInt(i % 7)) + 10.0 * @as(f32, @floatFromInt(i % 7));
colorsRecs[i].y = 80.0 + 100.0 * @as(f32, @floatFromInt(i / 7)) + 10.0 * @as(f32, @floatFromInt(i / 7));
colorsRecs[i].width = 100.0;
colorsRecs[i].height = 100.0;
}
var colorState: [maxColorCount]bool = std.mem.zeroes([maxColorCount]bool);
var mousePoint = rl.Vector2{ .x = 0.0, .y = 0.0 };
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
mousePoint = rl.getMousePosition();
i = 0;
while (i < maxColorCount) : (i += 1) {
if (rl.checkCollisionPointRec(mousePoint, colorsRecs[i])) {
colorState[i] = true;
} else {
colorState[i] = false;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("raylib colors palette", 28, 42, 20, .black);
rl.drawText("press SPACE to see all colors", rl.getScreenWidth() - 180, rl.getScreenHeight() - 40, 10, .gray);
i = 0;
while (i < maxColorCount) : (i += 1) {
rl.drawRectangleRec(colorsRecs[i], .fade(colors[i], getAlpha(colorState[i])));
if (rl.isKeyDown(.space) or colorState[i]) {
rl.drawRectangle(@intFromFloat(colorsRecs[i].x), @as(i32, @intFromFloat(colorsRecs[i].y)) + @as(i32, @intFromFloat(colorsRecs[i].height)) - 26, @as(i32, @intFromFloat(colorsRecs[i].width)), 20, .black);
rl.drawRectangleLinesEx(colorsRecs[i], 6, .fade(.black, 0.3));
rl.drawText(colorNames[i], @as(i32, @intFromFloat(colorsRecs[i].x)) + @as(i32, @intFromFloat(colorsRecs[i].width)) - rl.measureText(colorNames[i], 10) - 12, @as(i32, @intFromFloat(colorsRecs[i].y)) + @as(i32, @intFromFloat(colorsRecs[i].height)) - 20, 10, colors[i]);
}
}
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,69 @@
const std = @import("std");
const math = std.math;
const rl = @import("raylib");
const rgui = @import("raygui");
fn labelFmt(segments: f32, minSegments: f32) [*c]const u8 {
if (segments >= minSegments) return "MANUAL";
return "AUTO";
}
fn colorFmt(segments: f32, minSegments: f32) rl.Color {
if (segments >= minSegments) return .maroon;
return .dark_gray;
}
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - draw circle sector");
defer rl.closeWindow(); // Close window and OpenGL context
const center = rl.Vector2{ .x = @as(f32, @floatFromInt(rl.getScreenWidth() - 300)) / 2.0, .y = @as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0 };
var outerRadius: f32 = 180.0;
var startAngle: f32 = 0.0;
var endAngle: f32 = 180.0;
var segments: f32 = 10.0;
var minSegments: f32 = 4;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
// NOTE: All variables update happens inside GUI control functions
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawLine(500, 0, 500, rl.getScreenHeight(), .fade(.light_gray, 0.6));
rl.drawRectangle(500, 0, rl.getScreenWidth() - 500, rl.getScreenHeight(), .fade(.light_gray, 0.3));
rl.drawCircleSector(center, outerRadius, startAngle, endAngle, @as(i32, @intFromFloat(segments)), .fade(.maroon, 0.3));
rl.drawCircleSectorLines(center, outerRadius, startAngle, endAngle, @as(i32, @intFromFloat(segments)), .fade(.maroon, 0.6));
// Draw GUI controls
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 40, .width = 120, .height = 20 }, "StartAngle", rl.textFormat("%.2", .{startAngle}), &startAngle, 0, 720);
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 70, .width = 120, .height = 20 }, "EndAngle", rl.textFormat("%.2", .{endAngle}), &endAngle, 0, 720);
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 140, .width = 120, .height = 20 }, "Radius", rl.textFormat("%.2", .{outerRadius}), &outerRadius, 0, 200);
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 170, .width = 120, .height = 20 }, "Segments", rl.textFormat("%.2", .{segments}), &segments, 0, 100);
minSegments = math.trunc(math.ceil((endAngle - startAngle) / 90));
rl.drawText(rl.textFormat("MODE: %s", .{labelFmt(segments, minSegments)}), 600, 200, 10, colorFmt(segments, minSegments));
rl.drawFPS(10, 10);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,73 @@
const rl = @import("raylib");
const rgui = @import("raygui");
fn labelFmt(segments: f32) [*c]const u8 {
if (segments >= 4) return "MANUAL";
return "AUTO";
}
fn colorFmt(segments: f32) rl.Color {
if (segments >= 4) return .maroon;
return .dark_gray;
}
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - draw rectangle rounded");
defer rl.closeWindow(); // Close window and OpenGL context
var roundness: f32 = 0.2;
var width: f32 = 200.0;
var height: f32 = 100.0;
var segments: f32 = 0.0;
var lineThick: f32 = 1.0;
var drawRect: bool = false;
var drawRoundedRect: bool = true;
var drawRoundedLines: bool = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
const rec = rl.Rectangle{ .x = (@as(f32, @floatFromInt(rl.getScreenWidth())) - width - 250) / 2.0, .y = (@as(f32, @floatFromInt(rl.getScreenHeight())) - height) / 2.0, .width = width, .height = height };
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawLine(560, 0, 560, rl.getScreenHeight(), .fade(.light_gray, 0.6));
rl.drawRectangle(560, 0, rl.getScreenWidth() - 500, rl.getScreenHeight(), .fade(.light_gray, 0.3));
if (drawRect) rl.drawRectangleRec(rec, .fade(.gold, 0.6));
if (drawRoundedRect) rl.drawRectangleRounded(rec, roundness, @as(i32, @intFromFloat(segments)), .fade(.maroon, 0.2));
if (drawRoundedLines) rl.drawRectangleRoundedLinesEx(rec, roundness, @as(i32, @intFromFloat(segments)), lineThick, .fade(.maroon, 0.4));
// Draw GUI controls
_ = rgui.sliderBar(rl.Rectangle{ .x = 640, .y = 40, .width = 105, .height = 20 }, "Width", rl.textFormat("%.2", .{width}), &width, 0, @as(f32, @floatFromInt(rl.getScreenWidth() - 300)));
_ = rgui.sliderBar(rl.Rectangle{ .x = 640, .y = 70, .width = 105, .height = 20 }, "Height", rl.textFormat("%.2", .{height}), &height, 0, @as(f32, @floatFromInt(rl.getScreenHeight() - 50)));
_ = rgui.sliderBar(rl.Rectangle{ .x = 640, .y = 140, .width = 105, .height = 20 }, "Roundness", rl.textFormat("%.2", .{roundness}), &roundness, 0.0, 1.0);
_ = rgui.sliderBar(rl.Rectangle{ .x = 640, .y = 170, .width = 105, .height = 20 }, "Thickness", rl.textFormat("%.2", .{lineThick}), &lineThick, 0, 20);
_ = rgui.sliderBar(rl.Rectangle{ .x = 640, .y = 240, .width = 105, .height = 20 }, "Segments", rl.textFormat("%.2", .{segments}), &segments, 0, 60);
_ = rgui.checkBox(rl.Rectangle{ .x = 640, .y = 320, .width = 20, .height = 20 }, "DrawRoundedRect", &drawRoundedRect);
_ = rgui.checkBox(rl.Rectangle{ .x = 640, .y = 350, .width = 20, .height = 20 }, "DrawRoundedLines", &drawRoundedLines);
_ = rgui.checkBox(rl.Rectangle{ .x = 640, .y = 380, .width = 20, .height = 20 }, "DrawRect", &drawRect);
rl.drawText(rl.textFormat("MODE: %s", .{labelFmt(segments)}), 640, 280, 10, colorFmt(segments));
rl.drawFPS(10, 10);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,83 @@
const std = @import("std");
const math = std.math;
const rl = @import("raylib");
const rgui = @import("raygui");
fn labelFmt(segments: f32, minSegments: f32) [*c]const u8 {
if (segments >= minSegments) return "MANUAL";
return "AUTO";
}
fn colorFmt(segments: f32, minSegments: f32) rl.Color {
if (segments >= minSegments) return .maroon;
return .dark_gray;
}
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - draw ring");
defer rl.closeWindow(); // Close window and OpenGL context
const center = rl.Vector2{ .x = @as(f32, @floatFromInt(rl.getScreenWidth() - 300)) / 2.0, .y = @as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0 };
var innerRadius: f32 = 80.0;
var outerRadius: f32 = 190.0;
var startAngle: f32 = 0.0;
var endAngle: f32 = 360.0;
var segments: f32 = 0.0;
var drawRing = true;
var drawRingLines = false;
var drawCircleLines = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
// NOTE: All variables update happens inside GUI control functions
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawLine(500, 0, 500, rl.getScreenHeight(), .fade(.light_gray, 0.6));
rl.drawRectangle(500, 0, rl.getScreenWidth() - 500, rl.getScreenHeight(), .fade(.light_gray, 0.3));
if (drawRing) rl.drawRing(center, innerRadius, outerRadius, startAngle, endAngle, @intFromFloat(segments), .fade(.maroon, 0.3));
if (drawRingLines) rl.drawRingLines(center, innerRadius, outerRadius, startAngle, endAngle, @intFromFloat(segments), .fade(.black, 0.4));
if (drawCircleLines) rl.drawCircleSectorLines(center, outerRadius, startAngle, endAngle, @intFromFloat(segments), .fade(.black, 0.4));
// Draw GUI controls
//------------------------------------------------------------------------------
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 40, .width = 120, .height = 20 }, "StartAngle", rl.textFormat("%.2", .{startAngle}), &startAngle, -450, 450);
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 70, .width = 120, .height = 20 }, "EndAngle", rl.textFormat("%.2", .{endAngle}), &endAngle, -450, 450);
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 140, .width = 120, .height = 20 }, "InnerRadius", rl.textFormat("%.2", .{innerRadius}), &innerRadius, 0, 100);
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 170, .width = 120, .height = 20 }, "OuterRadius", rl.textFormat("%.2", .{outerRadius}), &outerRadius, 0, 200);
_ = rgui.sliderBar(rl.Rectangle{ .x = 600, .y = 240, .width = 120, .height = 20 }, "Segments", rl.textFormat("%.2", .{segments}), &segments, 0, 100);
_ = rgui.checkBox(rl.Rectangle{ .x = 600, .y = 320, .width = 20, .height = 20 }, "Draw Ring", &drawRing);
_ = rgui.checkBox(rl.Rectangle{ .x = 600, .y = 350, .width = 20, .height = 20 }, "Draw RingLines", &drawRingLines);
_ = rgui.checkBox(rl.Rectangle{ .x = 600, .y = 380, .width = 20, .height = 20 }, "Draw CircleLines", &drawCircleLines);
//------------------------------------------------------------------------------
const minSegments: f32 = math.ceil((endAngle - startAngle) / 90);
rl.drawText(rl.textFormat("MODE: %s", .{labelFmt(segments, minSegments)}), 600, 270, 10, colorFmt(segments, minSegments));
rl.drawFPS(10, 10);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,86 @@
const rl = @import("raylib");
const reasings = @import("reasings.zig");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [shapes] example - easings ball anim");
defer rl.closeWindow(); // Defer closing window and OpenGL context
// Ball variable value to be animated with easings
var ballPositionX: i32 = -100;
var ballRadius: f32 = 20;
var ballAlpha: f32 = 0;
var state: i32 = 0;
var framesCounter: i32 = 0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
switch (state) {
0 => { // Move ball position X with easing
framesCounter += 1;
ballPositionX = @intFromFloat(reasings.elasticOut(@floatFromInt(framesCounter), -100, @as(f32, @floatFromInt(screenWidth)) / 2 + 100, 120));
if (framesCounter >= 120) {
framesCounter = 0;
state = 1;
}
},
1 => { // Increase ball radius with easing
framesCounter += 1;
ballRadius = reasings.elasticIn(@floatFromInt(framesCounter), 20, 500, 200);
if (framesCounter >= 200) {
framesCounter = 0;
state = 2;
}
},
2 => { // Change ball alpha with easing (background color blending)
framesCounter += 1;
ballAlpha = reasings.cubicOut(@floatFromInt(framesCounter), 0.0, 1.0, 200);
if (framesCounter >= 200) {
framesCounter = 0;
state = 3;
}
},
3 => { // Reset state to play again
if (rl.isKeyPressed(.enter)) {
ballPositionX = -100;
ballRadius = 20;
ballAlpha = 0.0;
state = 0;
}
},
else => unreachable,
}
if (rl.isKeyPressed(.r)) framesCounter = 0;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
if (state >= 2) rl.drawRectangle(0, 0, screenWidth, screenHeight, .green);
rl.drawCircle(ballPositionX, 200, ballRadius, .fade(.red, 1.0 - ballAlpha));
if (state == 3) rl.drawText("PRESS [ENTER] TO PLAY AGAIN!", 240, 200, 20, .black);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,127 @@
const rl = @import("raylib");
const reasing = @import("reasings.zig");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [shapes] example - easings box anim");
defer rl.closeWindow();
// Box variables to be animated with easings
var rec: rl.Rectangle = rl.Rectangle{
.x = @as(f32, @floatFromInt(rl.getScreenWidth())) / 2.0,
.y = -100,
.height = 100,
.width = 100,
};
var rotation: f32 = 0.0;
var alpha: f32 = 1.0;
var state: i32 = 0;
var framesCounter: i32 = 0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
switch (state) {
// Move box down to center of screen
0 => {
framesCounter += 1;
// NOTE: Remember that 3rd parameter of easing function refers to
// desired value variation, do not confuse it with expected final value!
rec.y = reasing.elasticOut(@floatFromInt(framesCounter), -100, @as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0 + 100, 120);
if (framesCounter >= 120) {
framesCounter = 0;
state = 1;
}
},
// Scale box to an horizontal bar
1 => {
framesCounter += 1;
rec.height = reasing.bounceOut(@floatFromInt(framesCounter), 100, -90, 120);
rec.width = reasing.bounceOut(@floatFromInt(framesCounter), 100, @floatFromInt(rl.getScreenWidth()), 120);
if (framesCounter >= 120) {
framesCounter = 0;
state = 2;
}
},
// Rotate horizontal bar rectangle
2 => {
framesCounter += 1;
rotation = reasing.quadOut(@floatFromInt(framesCounter), 0.0, 270.0, 240);
if (framesCounter >= 240) {
framesCounter = 0;
state = 3;
}
},
// Increase bar size to fill all screen
3 => {
framesCounter += 1;
rec.height = reasing.circOut(@floatFromInt(framesCounter), 10, @floatFromInt(rl.getScreenWidth()), 120);
if (framesCounter >= 120) {
framesCounter = 0;
state = 4;
}
},
// Fade out animation
4 => {
framesCounter += 1;
alpha = reasing.sineOut(@floatFromInt(framesCounter), 1.0, -1.0, 160);
if (framesCounter >= 160) {
framesCounter = 0;
state = 5;
}
},
5 => {},
else => unreachable,
}
// Reset animation at any moment
if (rl.isKeyPressed(.space)) {
rec = rl.Rectangle{
.x = @as(f32, @floatFromInt(rl.getScreenWidth())) / 2.0,
.y = -100,
.height = 100,
.width = 100,
};
rotation = 0.0;
alpha = 1.0;
state = 0;
framesCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawRectanglePro(rec, rl.Vector2{
.x = rec.width / 2,
.y = rec.height / 2,
}, rotation, .fade(.black, alpha));
rl.drawText("PRESS [SPACE] TO RESET BOX ANIMATION!", 10, rl.getScreenHeight() - 25, 20, .light_gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,91 @@
const rl = @import("raylib");
const reasings = @import("reasings.zig");
const RECS_WIDTH = 50;
const RECS_HEIGHT = 50;
const SCREEN_WIDTH = 800;
const SCREEN_HEIGHT = 450;
const MAX_RECS_X = SCREEN_WIDTH / RECS_WIDTH;
const MAX_RECS_Y = SCREEN_HEIGHT / RECS_HEIGHT;
const PLAY_TIME_IN_FRAMES = 240; // At 60 fps = 4 seconds
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
rl.initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [shapes] example - easings rectangle array");
defer rl.closeWindow(); // Close window and OpenGL context
var recs: [MAX_RECS_X * MAX_RECS_Y]rl.Rectangle = undefined;
for (0..MAX_RECS_Y) |y| {
for (0..MAX_RECS_X) |x| {
recs[y * MAX_RECS_X + x].x = RECS_WIDTH / 2.0 + RECS_WIDTH * @as(f32, @floatFromInt(x));
recs[y * MAX_RECS_X + x].y = RECS_HEIGHT / 2.0 + RECS_HEIGHT * @as(f32, @floatFromInt(y));
recs[y * MAX_RECS_X + x].width = RECS_WIDTH;
recs[y * MAX_RECS_X + x].height = RECS_HEIGHT;
}
}
var rotation: f32 = 0.0;
var framesCounter: i32 = 0;
var state: i32 = 0; // Rectangles animation state: 0-Playing, 1-Finished
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (state == 0) {
framesCounter += 1;
for (&recs) |*rec| {
rec.height = reasings.circOut(@floatFromInt(framesCounter), RECS_HEIGHT, -RECS_HEIGHT, PLAY_TIME_IN_FRAMES);
rec.width = reasings.circOut(@floatFromInt(framesCounter), RECS_WIDTH, -RECS_WIDTH, PLAY_TIME_IN_FRAMES);
if (rec.height < 0) rec.height = 0;
if (rec.width < 0) rec.width = 0;
if ((rec.height == 0) and (rec.width == 0)) state = 1; // Finish playing
rotation = reasings.linearIn(@floatFromInt(framesCounter), 0.0, 360.0, PLAY_TIME_IN_FRAMES);
}
} else if ((state == 1) and rl.isKeyPressed(.space)) {
// When animation has finished, press space to restart
framesCounter = 0;
for (&recs) |*rec| {
rec.height = RECS_HEIGHT;
rec.width = RECS_WIDTH;
}
state = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
if (state == 0) {
for (recs) |rec| {
rl.drawRectanglePro(rec, rl.Vector2{
.x = rec.width / 2,
.y = rec.height / 2,
}, rotation, .red);
}
} else if (state == 1) rl.drawText("PRESS [SPACE] TO PLAY AGAIN!", 240, 200, 20, .gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,85 @@
const std = @import("std");
const math = std.math;
const rl = @import("raylib");
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - following eyes");
defer rl.closeWindow(); // Close window and OpenGL context
const scleraLeftPosition = rl.Vector2{ .x = @as(f32, @floatFromInt(rl.getScreenWidth())) / 2.0 - 100.0, .y = @as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0 };
const scleraRightPosition = rl.Vector2{ .x = @as(f32, @floatFromInt(rl.getScreenWidth())) / 2.0 + 100.0, .y = @as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0 };
const scleraRadius: i32 = 80;
var irisLeftPosition = rl.Vector2{ .x = @as(f32, @floatFromInt(rl.getScreenWidth())) / 2.0 - 100.0, .y = @as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0 };
var irisRightPosition = rl.Vector2{ .x = @as(f32, @floatFromInt(rl.getScreenWidth())) / 2.0 + 100.0, .y = @as(f32, @floatFromInt(rl.getScreenHeight())) / 2.0 };
const irisRadius: i32 = 24;
var angle: f32 = 0.0;
var dx: f32 = 0.0;
var dy: f32 = 0.0;
var dxx: f32 = 0.0;
var dyy: f32 = 0.0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
irisLeftPosition = rl.getMousePosition();
irisRightPosition = rl.getMousePosition();
// Check not inside the left eye sclera
if (!rl.checkCollisionPointCircle(irisLeftPosition, scleraLeftPosition, scleraRadius - irisRadius)) {
dx = irisLeftPosition.x - scleraLeftPosition.x;
dy = irisLeftPosition.y - scleraLeftPosition.y;
angle = math.atan2(dy, dx);
dxx = (scleraRadius - irisRadius) * math.cos(angle);
dyy = (scleraRadius - irisRadius) * math.sin(angle);
irisLeftPosition.x = scleraLeftPosition.x + dxx;
irisLeftPosition.y = scleraLeftPosition.y + dyy;
}
// Check not inside the right eye sclera
if (!rl.checkCollisionPointCircle(irisRightPosition, scleraRightPosition, scleraRadius - irisRadius)) {
dx = irisRightPosition.x - scleraRightPosition.x;
dy = irisRightPosition.y - scleraRightPosition.y;
angle = math.atan2(dy, dx);
dxx = (scleraRadius - irisRadius) * math.cos(angle);
dyy = (scleraRadius - irisRadius) * math.sin(angle);
irisRightPosition.x = scleraRightPosition.x + dxx;
irisRightPosition.y = scleraRightPosition.y + dyy;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.drawCircleV(scleraLeftPosition, scleraRadius, .light_gray);
rl.drawCircleV(irisLeftPosition, irisRadius, .brown);
rl.drawCircleV(irisLeftPosition, 10, .black);
rl.drawCircleV(scleraRightPosition, scleraRadius, .light_gray);
rl.drawCircleV(irisRightPosition, irisRadius, .dark_green);
rl.drawCircleV(irisRightPosition, 10, .black);
rl.drawFPS(10, 10);
rl.clearBackground(.ray_white);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,75 @@
const rl = @import("raylib");
fn collisionFmt(isColliding: bool) f32 {
if (isColliding) return 14.0;
return 8.0;
}
fn movingFmt(isMoving: bool) rl.Color {
if (isMoving) return .red;
return .blue;
}
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
//rl.setConfigFlags(@enumFromInt(rl.ConfigFlags.flag_msaa_4x_hint));
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - cubic-bezier lines");
defer rl.closeWindow(); // Close window and OpenGL context
var startPoint = rl.Vector2{ .x = 30, .y = 30 };
var endPoint = rl.Vector2{ .x = screenWidth - 30, .y = screenHeight - 30 };
var moveStartPoint = false;
var moveEndPoint = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
const mouse: rl.Vector2 = rl.getMousePosition();
if (rl.checkCollisionPointCircle(mouse, startPoint, 10.0) and rl.isMouseButtonDown(.left)) {
moveStartPoint = true;
} else if (rl.checkCollisionPointCircle(mouse, endPoint, 10.0) and rl.isMouseButtonDown(.left)) {
moveEndPoint = true;
}
if (moveStartPoint) {
startPoint = mouse;
if (rl.isMouseButtonReleased(.left)) {
moveStartPoint = false;
}
}
if (moveEndPoint) {
endPoint = mouse;
if (rl.isMouseButtonReleased(.left)) {
moveEndPoint = false;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("MOVE START-END POINTS WITH MOUSE", 15, 20, 20, .gray);
// Draw line Cubic Bezier, in-out interpolation (easing), no control points
rl.drawLineBezier(startPoint, endPoint, 4.0, .blue);
// Draw start-end spline circles with some details
rl.drawCircleV(startPoint, collisionFmt(rl.checkCollisionPointCircle(mouse, startPoint, 10.0)), movingFmt(moveStartPoint));
rl.drawCircleV(endPoint, collisionFmt(rl.checkCollisionPointCircle(mouse, endPoint, 10.0)), movingFmt(moveEndPoint));
//----------------------------------------------------------------------------------
}
}

View File

@ -28,13 +28,13 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
rl.drawRectangle(screenWidth / 2 - 128, screenHeight / 2 - 128, 256, 256, raylib_zig);
rl.drawRectangle(screenWidth / 2 - 112, screenHeight / 2 - 112, 224, 224, rl.Color.ray_white);
rl.drawRectangle(screenWidth / 2 - 112, screenHeight / 2 - 112, 224, 224, .ray_white);
rl.drawText("raylib-zig", screenWidth / 2 - 96, screenHeight / 2 + 57, 41, raylib_zig);
rl.drawText("this is NOT a texture!", 350, 370, 10, rl.Color.gray);
rl.drawText("this is NOT a texture!", 350, 370, 10, .gray);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,128 @@
const rl = @import("raylib");
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - raylib logo animation");
defer rl.closeWindow(); // Close window and OpenGL context
const logoPositionX = (screenWidth / 2) - 128;
const logoPositionY = (screenHeight / 2) - 128;
var framesCounter: u8 = 0;
var lettersCount: u8 = 0;
var topSideRecWidth: i32 = 16;
var leftSideRecHeight: i32 = 16;
var bottomSideRecWidth: i32 = 16;
var rightSideRecHeight: i32 = 16;
var state: u8 = 0;
var alpha: f32 = 1.0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
if (state == 0) {
framesCounter += 1;
if (framesCounter == 120) {
state = 1;
framesCounter = 0;
}
} else if (state == 1) {
topSideRecWidth += 4;
leftSideRecHeight += 4;
if (topSideRecWidth == 256) state = 2;
} else if (state == 2) // State 2: Bottom and right bars growing
{
bottomSideRecWidth += 4;
rightSideRecHeight += 4;
if (bottomSideRecWidth == 256) state = 3;
} else if (state == 3) // State 3: Letters appearing (one by one)
{
framesCounter += 1;
if (@mod(framesCounter, 12) == 0) // Every 12 frames, one more letter!
{
lettersCount += 1;
framesCounter = 0;
}
if (lettersCount >= 10) // When all letters have appeared, just fade out everything
{
alpha -= 0.02;
if (alpha <= 0.0) {
alpha = 0.0;
state = 4;
}
}
} else if (state == 4) // State 4: Reset and Replay
{
if (rl.isKeyPressed(.r)) {
framesCounter = 0;
lettersCount = 0;
topSideRecWidth = 16;
leftSideRecHeight = 16;
bottomSideRecWidth = 16;
rightSideRecHeight = 16;
alpha = 1.0;
state = 0; // Return to State 0
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
if (state == 0) {
if (@mod(framesCounter, @as(u8, 15)) == 0) rl.drawRectangle(logoPositionX, logoPositionY, 16, 16, .black);
} else if (state == 1) {
rl.drawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, .black);
rl.drawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, .black);
} else if (state == 2) {
rl.drawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, .black);
rl.drawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, .black);
rl.drawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, .black);
rl.drawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, .black);
} else if (state == 3) {
rl.drawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, .fade(.black, alpha));
rl.drawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, .fade(.black, alpha));
rl.drawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, .fade(.black, alpha));
rl.drawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, .fade(.black, alpha));
rl.drawRectangle(
(@divFloor(rl.getScreenWidth(), @as(i32, 2))) - 112,
(@divFloor(rl.getScreenHeight(), @as(i32, 2))) - 112,
224,
224,
.fade(.ray_white, alpha),
);
rl.drawText(rl.textSubtext("raylib", 0, lettersCount), @divFloor(rl.getScreenWidth(), @as(i32, 2)) - 44, @divFloor(rl.getScreenHeight(), @as(i32, 2)) + 48, 50, .fade(.black, alpha));
} else if (state == 4) {
rl.drawText("[R] REPLAY", 340, 200, 20, .gray);
}
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,192 @@
const math = @import("std").math;
// Linear Easing functions
pub fn linearNone(t: f32, b: f32, c: f32, d: f32) f32 {
return (c * t / d + b);
}
pub fn linearIn(t: f32, b: f32, c: f32, d: f32) f32 {
return (c * t / d + b);
}
pub fn linearOut(t: f32, b: f32, c: f32, d: f32) f32 {
return (c * t / d + b);
}
pub fn linearInOut(t: f32, b: f32, c: f32, d: f32) f32 {
return (c * t / d + b);
}
pub fn sineIn(t: f32, b: f32, c: f32, d: f32) f32 {
return (-c * math.cos(t / d * (math.pi / 2.0)) + c + b);
}
pub fn sineOut(t: f32, b: f32, c: f32, d: f32) f32 {
return (c * math.sin(t / d * (math.pi / 2.0)) + b);
}
pub fn sineInOut(t: f32, b: f32, c: f32, d: f32) f32 {
return (-c / 2.0 * (math.cos(math.pi * t / d) - 1.0) + b);
}
// Circular Easing functions
pub fn circIn(t: f32, b: f32, c: f32, d: f32) f32 {
const postFix = t / d;
return (-c * (math.sqrt(1.0 - postFix * postFix) - 1.0) + b);
}
pub fn circOut(t: f32, b: f32, c: f32, d: f32) f32 {
const postFix = t / d - 1.0;
return (c * math.sqrt(1.0 - postFix * postFix) + b);
}
pub fn circInOut(t: f32, b: f32, c: f32, d: f32) f32 {
var postFix = t / d;
if ((postFix / 2.0) < 1.0) return (-c / 2.0 * (math.sqrt(1.0 - postFix * postFix) - 1.0) + b);
postFix -= 2.0;
return (c / 2.0 * (math.sqrt(1.0 - postFix * postFix) + 1.0) + b);
}
// Cubic Easing functions
pub fn cubicIn(t: f32, b: f32, c: f32, d: f32) f32 {
const postFix = t / d;
return (c * postFix * postFix * postFix + b);
}
pub fn cubicOut(t: f32, b: f32, c: f32, d: f32) f32 {
const postFix = t / d - 1.0;
return (c * (postFix * postFix * postFix + 1.0) + b);
}
pub fn cubicInOut(t: f32, b: f32, c: f32, d: f32) f32 {
const postFix = t / d;
if (postFix / 2.0 < 1.0) return (c / 2.0 * postFix * postFix * postFix + b);
postFix -= 2.0;
return (c / 2.0 * (t * t * t + 2.0) + b);
}
// Quadratic Easing functions
pub fn quadIn(t: f32, b: f32, c: f32, d: f32) f32 {
const postfix = t / d;
return (c * postfix * postfix + b);
}
pub fn quadOut(t: f32, b: f32, c: f32, d: f32) f32 {
const postFix = t / d;
return (-c * postFix * (postFix - 2.0) + b);
}
pub fn quadInOut(t: f32, b: f32, c: f32, d: f32) f32 // Ease: Quadratic In Out
{
const postFix = t / d;
return if (postFix / 2 < 1)
(((c / 2) * (postFix * postFix)) + b)
else
(-c / 2.0 * (((postFix - 1.0) * (postFix - 3.0)) - 1.0) + b);
}
// Exponential Easing functions
pub fn expoIn(t: f32, b: f32, c: f32, d: f32) f32 {
return if (t == 0.0) b else (c * math.pow(f32, 2.0, 10.0 * (t / d - 1.0)) + b);
}
pub fn expoOut(t: f32, b: f32, c: f32, d: f32) f32 {
return if (t == d) (b + c) else (c * (-math.pow(f32, 2.0, -10.0 * t / d) + 1.0) + b);
}
pub fn expoInOut(t: f32, b: f32, c: f32, d: f32) f32 {
if (t == 0.0) return b;
if (t == d) return (b + c);
const postFix = t / d;
if ((postFix / 2.0) < 1.0) return (c / 2.0 * math.pow(f32, 2.0, 10.0 * (postFix - 1.0)) + b);
return (c / 2.0 * (-math.pow(f32, 2.0, -10.0 * (postFix - 1.0)) + 2.0) + b);
}
// Back Easing functions
pub fn backIn(t: f32, b: f32, c: f32, d: f32) f32 {
const s = 1.70158;
const postFix = t / d;
return (c * (postFix) * postFix * ((s + 1.0) * postFix - s) + b);
}
pub fn backOut(t: f32, b: f32, c: f32, d: f32) f32 {
const s = 1.70158;
const postFix = t / d - 1.0;
return (c * (postFix * postFix * ((s + 1.0) * postFix + s) + 1.0) + b);
}
pub fn backInOut(t: f32, b: f32, c: f32, d: f32) f32 {
const s = 1.70158;
t /= d;
if (t / 2.0 < 1.0) {
s *= 1.525;
return (c / 2.0 * (t * t * ((s + 1.0) * t - s)) + b);
}
t -= 2;
const postFix = t;
s *= 1.525;
return (c / 2.0 * ((postFix) * t * ((s + 1.0) * t + s) + 2.0) + b);
}
// Bounce Easing functions
pub fn bounceOut(t: f32, b: f32, c: f32, d: f32) f32 {
var tDivD = t / d;
if (tDivD < (1.0 / 2.75)) {
return (c * (7.5625 * tDivD * tDivD) + b);
} else if (tDivD < (2.0 / 2.75)) {
tDivD -= (1.5 / 2.75);
return (c * (7.5625 * tDivD * tDivD + 0.75) + b);
} else if (tDivD < (2.5 / 2.75)) {
tDivD -= (2.25 / 2.75);
return (c * (7.5625 * tDivD * tDivD + 0.9375) + b);
} else {
tDivD -= (2.625 / 2.75);
return (c * (7.5625 * tDivD * tDivD + 0.984375) + b);
}
}
pub fn bounceIn(t: f32, b: f32, c: f32, d: f32) f32 {
return (c - bounceOut(d - t, 0.0, c, d) + b);
}
pub fn bounceInOut(t: f32, b: f32, c: f32, d: f32) f32 {
if (t < d / 2.0) return (bounceIn(t * 2.0, 0.0, c, d) * 0.5 + b);
return (bounceOut(t * 2.0 - d, 0.0, c, d) * 0.5 + c * 0.5 + b);
}
// Elastic Easing functions
pub fn elasticIn(t: f32, b: f32, c: f32, d: f32) f32 {
if (t == 0.0) return b;
var tDivD = t / d;
if (tDivD == 1.0) return (b + c);
const p = d * 0.3;
const a = c;
const s = p / 4.0;
tDivD -= 1;
const postFix = a * math.pow(f32, 2.0, 10.0 * tDivD);
return (-(postFix * math.sin((tDivD * d - s) * (2.0 * math.pi) / p)) + b);
}
pub fn elasticOut(t: f32, b: f32, c: f32, d: f32) f32 {
if (t == 0.0) return b;
const tDivD = t / d;
if (tDivD == 1.0) return (b + c);
const p = d * 0.3;
const a = c;
const s = p / 4.0;
return (a * math.pow(f32, 2.0, -10.0 * tDivD) * math.sin((tDivD * d - s) * (2.0 * math.pi) / p) + c + b);
}
pub fn elasticInOut(t: f32, b: f32, c: f32, d: f32) f32 {
if (t == 0.0) return b;
const tDivD = t / d;
if (tDivD / 2.0 == 2.0) return (b + c);
const p = d * (0.3 * 1.5);
const a = c;
const s = p / 4.0;
if (tDivD < 1.0) {
tDivD -= 1;
const postFix = a * math.pow(f32, 2.0, 10.0 * tDivD);
return -0.5 * (postFix * math.sin((tDivD * d - s) * (2.0 * math.pi) / p)) + b;
}
tDivD -= 1;
const postFix = a * math.pow(f32, 2.0, -10.0 * (tDivD));
return (postFix * math.sin((tDivD * d - s) * (2.0 * math.pi) / p) * 0.5 + c + b);
}

View File

@ -0,0 +1,83 @@
const rl = @import("raylib");
const mouseScaleMarkSize = 12;
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib-zig [shapes] example - rectangle scaling mouse");
defer rl.closeWindow(); // Close window and OpenGL context
var rec: rl.Rectangle = rl.Rectangle{ .x = 100, .y = 100, .width = 200, .height = 80 };
var mousePosition: rl.Vector2 = rl.Vector2{ .x = 0, .y = 0 };
var mouseScaleReady: bool = false;
var mouseScaleMode: bool = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
mousePosition = rl.getMousePosition();
if (rl.checkCollisionPointRec(mousePosition, rl.Rectangle{ .x = (rec.x + rec.width) - mouseScaleMarkSize, .y = (rec.y + rec.height) - mouseScaleMarkSize, .width = mouseScaleMarkSize, .height = mouseScaleMarkSize })) {
mouseScaleReady = true;
if (rl.isMouseButtonPressed(.left)) {
mouseScaleMode = true;
}
} else {
mouseScaleReady = false;
}
if (mouseScaleMode) {
mouseScaleReady = true;
rec.width = (mousePosition.x - rec.x);
rec.height = (mousePosition.y - rec.y);
// Check minimum rec size
if (rec.width < mouseScaleMarkSize) {
rec.width = mouseScaleMarkSize;
}
if (rec.height < mouseScaleMarkSize) {
rec.height = mouseScaleMarkSize;
}
// Check maximum rec size
if (rec.width > (@as(f32, @floatFromInt(rl.getScreenWidth())) - rec.x)) {
rec.width = @as(f32, @floatFromInt(rl.getScreenWidth())) - rec.x;
}
if (rec.height > (@as(f32, @floatFromInt(rl.getScreenHeight())) - rec.y)) {
rec.height = @as(f32, @floatFromInt(rl.getScreenHeight())) - rec.y;
}
if (rl.isMouseButtonReleased(.left)) {
mouseScaleMode = false;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("Scale rectangle dragging from bottom-right corner!", 10, 10, 20, .gray);
rl.drawRectangleRec(rec, .fade(.green, 0.5));
if (mouseScaleReady) {
rl.drawRectangleLinesEx(rec, 1, .red);
rl.drawTriangle(rl.Vector2{ .x = rec.x + rec.width - mouseScaleMarkSize, .y = rec.y + rec.height }, rl.Vector2{ .x = rec.x + rec.width, .y = rec.y + rec.height }, rl.Vector2{ .x = rec.x + rec.width, .y = rec.y + rec.height - mouseScaleMarkSize }, .red);
}
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,226 @@
const rl = @import("raylib");
const rgui = @import("raygui");
const MAX_SPLINE_POINTS = 32;
const screenWidth = 800;
const screenHeight = 450;
// Cubic Bezier spline control points
// NOTE: Every segment has two control points
const ControlPoint = struct {
start: rl.Vector2,
end: rl.Vector2,
};
// Spline types
const SplineType = enum(i32) {
linear = 0, // Linear
basis = 1, // B-Spline
catmullrom = 2, // Catmull-Rom
bezier = 3, // Cubic Bezier
};
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
rl.setConfigFlags(.{ .msaa_4x_hint = true });
rl.initWindow(screenWidth, screenHeight, "raylib [shapes] example - splines drawing");
defer rl.closeWindow(); // Close window and OpenGL context
var points: [MAX_SPLINE_POINTS]rl.Vector2 = undefined;
points[0] = rl.Vector2{ .x = 50.0, .y = 400.0 };
points[1] = rl.Vector2{ .x = 160.0, .y = 220.0 };
points[2] = rl.Vector2{ .x = 340.0, .y = 380.0 };
points[3] = rl.Vector2{ .x = 520.0, .y = 60.0 };
points[4] = rl.Vector2{ .x = 710.0, .y = 260.0 };
for (5..MAX_SPLINE_POINTS) |i| {
points[i] = rl.Vector2{ .x = 0, .y = 0 };
}
// Array required for spline bezier-cubic,
// including control points interleaved with start-end segment points
var pointsInterleaved: [3 * (MAX_SPLINE_POINTS - 1) + 1]rl.Vector2 = undefined;
for (&pointsInterleaved) |*point| {
point.* = rl.Vector2{ .x = 0, .y = 0 };
}
var pointCount: usize = 5;
var selectedPoint: ?*rl.Vector2 = null;
var focusedPoint: ?*rl.Vector2 = null;
var selectedControlPoint: ?*rl.Vector2 = null;
var focusedControlPoint: ?*rl.Vector2 = null;
// Cubic Bezier control points initialization
var control: [MAX_SPLINE_POINTS - 1]ControlPoint = undefined;
for (&control) |*cp| {
cp.* = .{ .end = .{ .x = 0, .y = 0 }, .start = .{ .x = 0, .y = 0 } };
}
for (0..pointCount) |i| {
control[i].start = .{ .x = points[i].x + 50, .y = points[i].y };
control[i].end = .{ .x = points[i + 1].x - 50, .y = points[i + 1].y };
}
// Spline config variables
var splineThickness: f32 = 8.0;
var splineTypeActive = SplineType.linear;
var splineTypeEditMode = false;
var splineHelpersActive = true;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Spline points creation logic (at the end of spline)
if (rl.isMouseButtonPressed(.right) and (pointCount < MAX_SPLINE_POINTS)) {
points[pointCount] = rl.getMousePosition();
const i = pointCount - 1;
control[i].start = rl.Vector2{ .x = points[i].x + 50, .y = points[i].y };
control[i].end = rl.Vector2{ .x = points[i + 1].x - 50, .y = points[i + 1].y };
pointCount += 1;
}
// Spline point focus and selection logic
if (selectedPoint == null and ((splineTypeActive != SplineType.bezier) or selectedControlPoint == null)) {
focusedPoint = null;
for (0..pointCount) |i| {
if (rl.checkCollisionPointCircle(rl.getMousePosition(), points[i], 8.0)) {
focusedPoint = &points[i];
break;
}
}
if (rl.isMouseButtonPressed(.left)) selectedPoint = focusedPoint;
}
// Spline point movement logic
if (selectedPoint) |point| {
point.* = rl.getMousePosition();
if (rl.isMouseButtonReleased(.left)) selectedPoint = null;
}
// Cubic Bezier spline control points logic
if ((splineTypeActive == SplineType.bezier) and focusedPoint == null) {
// Spline control point focus and selection logic
if (selectedControlPoint == null) {
focusedControlPoint = null;
for (0..pointCount) |i| {
if (rl.checkCollisionPointCircle(rl.getMousePosition(), control[i].start, 6.0)) {
focusedControlPoint = &control[i].start;
break;
} else if (rl.checkCollisionPointCircle(rl.getMousePosition(), control[i].end, 6.0)) {
focusedControlPoint = &control[i].end;
break;
}
}
if (rl.isMouseButtonPressed(.left)) selectedControlPoint = focusedControlPoint;
}
// Spline control point movement logic
if (selectedControlPoint) |cp| {
cp.* = rl.getMousePosition();
if (rl.isMouseButtonReleased(.left)) selectedControlPoint = null;
}
}
// Spline selection logic
splineTypeActive = switch (rl.getKeyPressed()) {
.one => SplineType.linear,
.two => SplineType.basis,
.three => SplineType.catmullrom,
.four => SplineType.basis,
else => splineTypeActive,
};
// Clear selection when changing to a spline without control points
if (rl.isKeyPressed(.one) or rl.isKeyPressed(.two) or rl.isKeyPressed(.three)) selectedControlPoint = null;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
switch (splineTypeActive) {
SplineType.linear => rl.drawSplineLinear(points[0..pointCount], splineThickness, .red),
SplineType.basis => rl.drawSplineBasis(points[0..pointCount], splineThickness, .red),
SplineType.catmullrom => rl.drawSplineCatmullRom(points[0..pointCount], splineThickness, .red),
SplineType.bezier => {
// NOTE: Cubic-bezier spline requires the 2 control points of each segnment to be
// provided interleaved with the start and end point of every segment
for (0..pointCount - 1) |i| {
pointsInterleaved[3 * i] = points[i];
pointsInterleaved[3 * i + 1] = control[i].start;
pointsInterleaved[3 * i + 2] = control[i].end;
}
pointsInterleaved[3 * (pointCount - 1)] = points[pointCount - 1];
// Draw spline: cubic-bezier (with control points)
rl.drawSplineBezierCubic(pointsInterleaved[0 .. 3 * pointCount], splineThickness, .red);
// Draw spline control points
for (0..pointCount - 1) |i| {
// Every cubic bezier point have two control points
rl.drawCircleV(control[i].start, 6, .gold);
rl.drawCircleV(control[i].end, 6, .gold);
if (focusedControlPoint == &control[i].start) rl.drawCircleV(control[i].start, 8, .green) else if (focusedControlPoint == &control[i].end) rl.drawCircleV(control[i].end, 8, .green);
rl.drawLineEx(points[i], control[i].start, 1.0, .light_gray);
rl.drawLineEx(points[i + 1], control[i].end, 1.0, .light_gray);
// Draw spline control lines
rl.drawLineV(points[i], control[i].start, .gray);
rl.drawLineV(control[i].end, points[i + 1], .gray);
}
},
}
if (splineHelpersActive) {
// Draw spline point helpers
for (0..pointCount) |i| {
const radius: f32 = if (focusedPoint == &points[i]) 12 else 8;
const color: rl.Color = if (focusedPoint == &points[i]) .blue else .dark_blue;
rl.drawCircleLinesV(points[i], radius, color);
if ((splineTypeActive != SplineType.linear) and
(splineTypeActive != SplineType.bezier) and
(i < pointCount - 1)) rl.drawLineV(points[i], points[i + 1], .gray);
rl.drawText(rl.textFormat("[%.0f, %.0f]", .{ points[i].x, points[i].y }), @intFromFloat(points[i].x), @intFromFloat(points[i].y + 10), 10, .black);
}
}
// Check all possible UI states that require controls lock
if (splineTypeEditMode or selectedPoint != null or selectedControlPoint != null) rgui.lock();
// Draw spline config
_ = rgui.label(.{ .x = 12, .y = 62, .width = 140, .height = 24 }, rl.textFormat("Spline thickness: %i", .{@as(i64, @intFromFloat(splineThickness))}));
_ = rgui.sliderBar(.{ .x = 12, .y = 60 + 24, .width = 140, .height = 16 }, "", "", &splineThickness, 1.0, 40.0);
_ = rgui.checkBox(.{ .x = 12, .y = 110, .width = 20, .height = 20 }, "Show point helpers", &splineHelpersActive);
if (splineTypeEditMode) rgui.unlock();
_ = rgui.label(.{ .x = 12, .y = 10, .width = 140, .height = 24 }, "Spline type:");
var active: i32 = @intFromEnum(splineTypeActive);
if (rgui.dropdownBox(.{
.x = 12,
.y = 8 + 24,
.width = 140,
.height = 28,
}, "LINEAR;BSPLINE;CATMULLROM;BEZIER", &active, splineTypeEditMode) > 0) splineTypeEditMode = !splineTypeEditMode;
splineTypeActive = @enumFromInt(active);
rgui.unlock();
}
}

View File

@ -0,0 +1,341 @@
const rl = @import("raylib");
const std = @import("std");
// Custom Blend Modes
const RLGL_SRC_ALPHA = 0x0302;
const RLGL_MIN = 0x8007;
const RLGL_MAX = 0x8008;
const MAX_BOXES = 20;
/// MAX_BOXES *3. Each box can cast up to two shadow volumes for the edges it is away from, and one for the box itself
const MAX_SHADOWS = MAX_BOXES * 3;
const MAX_LIGHTS = 16;
// Shadow geometry type
const ShadowGeometry = struct {
vertices: [4]rl.Vector2,
};
// Light info type
const LightInfo = struct {
/// Is this light slot active?
active: bool,
/// Does this light need to be updated?
dirty: bool,
/// Is this light in a valid position?
valid: bool,
/// Light position
position: rl.Vector2,
/// Alpha mask for the light
mask: rl.RenderTexture,
/// The distance the light touches
outerRadius: f32,
/// A cached rectangle of the light bounds to help with culling
bounds: rl.Rectangle,
shadows: [MAX_SHADOWS]ShadowGeometry,
shadowCount: usize,
};
var lights: [MAX_LIGHTS]LightInfo = undefined;
// Move a light and mark it as dirty so that we update it's mask next frame
fn MoveLight(slot: usize, x: f32, y: f32) void {
lights[slot].dirty = true;
lights[slot].position.x = x;
lights[slot].position.y = y;
// update the cached bounds
lights[slot].bounds.x = x - lights[slot].outerRadius;
lights[slot].bounds.y = y - lights[slot].outerRadius;
}
// Compute a shadow volume for the edge
// It takes the edge and projects it back by the light radius and turns it into a quad
fn computeShadowVolumeForEdge(slot: usize, sp: rl.Vector2, ep: rl.Vector2) void {
if (lights[slot].shadowCount >= MAX_SHADOWS) return;
const extension = lights[slot].outerRadius * 2;
const spVector = rl.math.vector2Normalize(rl.math.vector2Subtract(sp, lights[slot].position));
const spProjection = rl.math.vector2Add(sp, rl.math.vector2Scale(spVector, extension));
const epVector = rl.math.vector2Normalize(rl.math.vector2Subtract(ep, lights[slot].position));
const epProjection = rl.math.vector2Add(ep, rl.math.vector2Scale(epVector, extension));
lights[slot].shadows[lights[slot].shadowCount].vertices[0] = sp;
lights[slot].shadows[lights[slot].shadowCount].vertices[1] = ep;
lights[slot].shadows[lights[slot].shadowCount].vertices[2] = epProjection;
lights[slot].shadows[lights[slot].shadowCount].vertices[3] = spProjection;
lights[slot].shadowCount += 1;
}
// Draw the light and shadows to the mask for a light
fn drawLightMask(slot: usize) void {
// Use the light mask
rl.beginTextureMode(lights[slot].mask);
defer rl.endTextureMode();
rl.clearBackground(.white);
// Force the blend mode to only set the alpha of the destination
rl.gl.rlSetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MIN);
rl.gl.rlSetBlendMode(@intFromEnum(rl.gl.rlBlendMode.rl_blend_custom));
// defer going back to normal blend mode
defer rl.gl.rlSetBlendMode(@intFromEnum(rl.gl.rlBlendMode.rl_blend_alpha));
// If we are valid, then draw the light radius to the alpha mask
if (lights[slot].valid) rl.drawCircleGradient(@intFromFloat(lights[slot].position.x), @intFromFloat(lights[slot].position.y), lights[slot].outerRadius, rl.colorAlpha(.white, 0), .white);
rl.gl.rlDrawRenderBatchActive();
// Cut out the shadows from the light radius by forcing the alpha to maximum
rl.gl.rlSetBlendMode(@intFromEnum(rl.gl.rlBlendMode.rl_blend_alpha));
rl.gl.rlSetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MAX);
rl.gl.rlSetBlendMode(@intFromEnum(rl.gl.rlBlendMode.rl_blend_custom));
// Draw the shadows to the alpha mask
for (0..lights[slot].shadowCount) |i| {
rl.drawTriangleFan(&lights[slot].shadows[i].vertices, .white);
}
rl.gl.rlDrawRenderBatchActive();
}
// Setup a light
fn setupLight(slot: usize, x: f32, y: f32, radius: f32) !void {
lights[slot].active = true;
lights[slot].valid = false; // The light must prove it is valid
lights[slot].mask = try rl.loadRenderTexture(rl.getScreenWidth(), rl.getScreenHeight());
lights[slot].outerRadius = radius;
lights[slot].bounds.width = radius * 2;
lights[slot].bounds.height = radius * 2;
MoveLight(slot, x, y);
// Force the render texture to have something in it
drawLightMask(slot);
}
// See if a light needs to update it's mask
// fn UpdateLight(slot: usize, Rectangle* boxes, int count) bool
fn updateLight(slot: usize, boxes: []rl.Rectangle) bool {
if (!lights[slot].active or !lights[slot].dirty) return false;
lights[slot].dirty = false;
lights[slot].shadowCount = 0;
lights[slot].valid = false;
for (boxes) |box| {
// Are we in a box? if so we are not valid
if (rl.checkCollisionPointRec(lights[slot].position, box)) return false;
// If this box is outside our bounds, we can skip it
if (!rl.checkCollisionRecs(lights[slot].bounds, box)) continue;
// Check the edges that are on the same side we are, and cast shadow volumes out from them
// Top
var sp = rl.Vector2{ .x = box.x, .y = box.y };
var ep = rl.Vector2{ .x = box.x + box.width, .y = box.y };
if (lights[slot].position.y > ep.y) computeShadowVolumeForEdge(slot, sp, ep);
// Right
sp = ep;
ep.y += box.height;
if (lights[slot].position.x < ep.x) computeShadowVolumeForEdge(slot, sp, ep);
// Bottom
sp = ep;
ep.x -= box.width;
if (lights[slot].position.y < ep.y) computeShadowVolumeForEdge(slot, sp, ep);
// Left
sp = ep;
ep.y -= box.height;
if (lights[slot].position.x > ep.x) computeShadowVolumeForEdge(slot, sp, ep);
// The box itself
lights[slot].shadows[lights[slot].shadowCount].vertices[0] = rl.Vector2{ .x = box.x, .y = box.y };
lights[slot].shadows[lights[slot].shadowCount].vertices[1] = rl.Vector2{ .x = box.x, .y = box.y + box.height };
lights[slot].shadows[lights[slot].shadowCount].vertices[2] = rl.Vector2{ .x = box.x + box.width, .y = box.y + box.height };
lights[slot].shadows[lights[slot].shadowCount].vertices[3] = rl.Vector2{ .x = box.x + box.width, .y = box.y };
lights[slot].shadowCount += 1;
}
lights[slot].valid = true;
drawLightMask(slot);
return true;
}
// Set up some boxes
fn setupBoxes(boxes: []rl.Rectangle) void {
boxes[0] = rl.Rectangle{ .x = 150, .y = 80, .width = 40, .height = 40 };
boxes[1] = rl.Rectangle{ .x = 1200, .y = 700, .width = 40, .height = 40 };
boxes[2] = rl.Rectangle{ .x = 200, .y = 600, .width = 40, .height = 40 };
boxes[3] = rl.Rectangle{ .x = 1000, .y = 50, .width = 40, .height = 40 };
boxes[4] = rl.Rectangle{ .x = 500, .y = 350, .width = 40, .height = 40 };
for (5..boxes.len) |i| {
boxes[i] = rl.Rectangle{
.x = @floatFromInt(rl.getRandomValue(0, rl.getScreenWidth())),
.y = @floatFromInt(rl.getRandomValue(0, rl.getScreenHeight())),
.width = @floatFromInt(rl.getRandomValue(10, 100)),
.height = @floatFromInt(rl.getRandomValue(10, 100)),
};
}
}
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [shapes] example - top down lights");
defer rl.closeWindow(); // Close window and OpenGL context
// Initialize our 'world' of boxes
var boxes: [MAX_BOXES]rl.Rectangle = undefined;
setupBoxes(&boxes);
// Create a checkerboard ground texture
const img = rl.genImageChecked(64, 64, 32, 32, .dark_brown, .dark_gray);
defer rl.unloadImage(img);
const backgroundTexture = try rl.loadTextureFromImage(img);
defer rl.unloadTexture(backgroundTexture);
// Create a global light mask to hold all the blended lights
const lightMask = try rl.loadRenderTexture(rl.getScreenWidth(), rl.getScreenHeight());
defer rl.unloadRenderTexture(lightMask);
// Setup initial light
try setupLight(0, 600, 400, 300);
defer {
//deinitialize light
for (&lights) |*light| {
if (light.active) rl.unloadRenderTexture(light.mask);
}
}
var nextLight: usize = 1;
var showLines = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Drag light 0
if (rl.isMouseButtonDown(.left)) MoveLight(0, rl.getMousePosition().x, rl.getMousePosition().y);
// Make a new light
if (rl.isMouseButtonPressed(.right) and (nextLight < MAX_LIGHTS)) {
try setupLight(nextLight, rl.getMousePosition().x, rl.getMousePosition().y, 200);
nextLight += 1;
}
// Toggle debug info
if (rl.isKeyPressed(.f1)) showLines = !showLines;
// Update the lights and keep track if any were dirty so we know if we need to update the master light mask
var dirtyLights = false;
for (0..MAX_LIGHTS) |i| {
if (updateLight(i, &boxes)) dirtyLights = true;
}
// Update the light mask
if (dirtyLights) {
// Build up the light mask
rl.beginTextureMode(lightMask);
defer rl.endTextureMode();
rl.clearBackground(.black);
// Force the blend mode to only set the alpha of the destination
rl.gl.rlSetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MIN);
rl.gl.rlSetBlendMode(@intFromEnum(rl.gl.rlBlendMode.rl_blend_custom));
defer rl.gl.rlSetBlendMode(@intFromEnum(rl.gl.rlBlendMode.rl_blend_alpha));
// Merge in all the light masks
for (lights) |light| {
if (light.active) rl.drawTextureRec(light.mask.texture, rl.Rectangle{
.x = 0,
.y = 0,
.width = @floatFromInt(rl.getScreenWidth()),
.height = @floatFromInt(-rl.getScreenHeight()),
}, rl.Vector2.zero(), .white);
}
rl.gl.rlDrawRenderBatchActive();
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.black);
// Draw the tile background
rl.drawTextureRec(backgroundTexture, rl.Rectangle{
.x = 0,
.y = 0,
.width = @floatFromInt(rl.getScreenWidth()),
.height = @floatFromInt(rl.getScreenHeight()),
}, rl.Vector2.zero(), .white);
// Overlay the shadows from all the lights
rl.drawTextureRec(lightMask.texture, rl.Rectangle{
.x = 0,
.y = 0,
.width = @floatFromInt(rl.getScreenWidth()),
.height = @floatFromInt(-rl.getScreenHeight()),
}, rl.Vector2.zero(), rl.colorAlpha(.white, if (showLines) 0.75 else 1.0));
// Draw the lights
for (0..MAX_LIGHTS) |i| {
if (lights[i].active) rl.drawCircle(@intFromFloat(lights[i].position.x), @intFromFloat(lights[i].position.y), 10, if (i == 0) .yellow else .white);
}
if (showLines) {
for (0..lights[0].shadowCount) |s| {
rl.drawTriangleFan(&lights[0].shadows[s].vertices, .dark_purple);
}
for (boxes) |box| {
if (rl.checkCollisionRecs(box, lights[0].bounds)) rl.drawRectangleRec(box, .purple);
rl.drawRectangleLines(@intFromFloat(box.x), @intFromFloat(box.y), @intFromFloat(box.width), @intFromFloat(box.height), .dark_blue);
}
rl.drawText("(F1) Hide Shadow Volumes", 10, 50, 10, .green);
} else {
rl.drawText("(F1) Show Shadow Volumes", 10, 50, 10, .green);
}
rl.drawFPS(screenWidth - 80, 10);
rl.drawText("Drag to move light #1", 10, 10, 10, .dark_green);
rl.drawText("Right click to add new light", 10, 30, 10, .dark_green);
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
}

View File

@ -0,0 +1,166 @@
//!******************************************************************************************
//!
//! raylib-zog port of the [text] example - Codepoints loading
//! https://github.com/raysan5/raylib/blob/master/examples/text/text_codepoints_loading.c
//!
//! Example complexity rating: [] 3/4
//!
//! Example originally created with raylib 4.2, last time updated with raylib 2.5
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Copyright (c) 2022-2025 Ramon Santamaria (@raysan5)
//!
//!*******************************************************************************************
const rl = @import("raylib");
const std = @import("std");
/// Text to be displayed, must be UTF-8 (save this code file as UTF-8)
/// NOTE: It can contain all the required text for the game,
/// this text will be scanned to get all the required codepoints
const text = "いろはにほへと ちりぬるを\nわかよたれそ つねならむ\nうゐのおくやま けふこえて\nあさきゆめみし ゑひもせす";
// Remove codepoint duplicates if requested
// static int *CodepointRemoveDuplicates(int *codepoints, int codepointCount, int *codepointResultCount);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [text] example - codepoints loading");
defer rl.closeWindow(); // Close window and OpenGL context
// Convert each utf-8 character into its
// corresponding codepoint in the font file.
const codepoints = try rl.loadCodepoints(text);
const codepoints_count = codepoints.len;
//the DebugAllocator provides us with a nice general purpose allocator, great for small projects like this
var font: rl.Font = undefined;
var codepoints_no_dups: [:0]i32 = undefined;
var codepoints_no_dups_count: usize = undefined;
{
var dba = std.heap.DebugAllocator(.{}){};
var alloc = dba.allocator();
// Removed duplicate codepoints to generate smaller font atlas
codepoints_no_dups = try CodepointRemoveDuplicates(alloc, codepoints);
codepoints_no_dups_count = std.mem.len(codepoints_no_dups.ptr);
defer alloc.free(codepoints_no_dups);
// we can free codepoints at the end of this block, atlas has already been generated
rl.unloadCodepoints(codepoints);
// Load font containing all the provided codepoint glyphs
// A texture font atlas is automatically generated
// example assumes it is being run from the root of the project
font = try rl.loadFontEx("examples/text/resources/DotGothic16-Regular.ttf", 36, codepoints_no_dups);
// Set bilinear scale filter for better font scaling
rl.setTextureFilter(font.texture, .bilinear);
rl.setTextLineSpacing(20); // Set line spacing for multiline text (when line breaks are included '\n')
}
defer rl.unloadFont(font); // Unload font at the end of the program
var show_font_atlas = false;
var codepoint_size: i32 = 0;
var start: i32 = 0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (rl.isKeyPressed(.space)) show_font_atlas = !show_font_atlas;
// Testing code: getting next and previous codepoints on provided text
if (rl.isKeyPressed(.right)) {
// Get next codepoint in string and move pointer
const err = rl.getCodepointNext(text[@intCast(start)..text.len], &codepoint_size);
if (err == '?') @panic("getCodepointNext failed");
if (start + codepoint_size < text.len) {
start += codepoint_size;
} else {
start = text.len;
}
} else if (rl.isKeyPressed(.left)) {
// Get previous codepoint in string and move pointer
const err = rl.getCodepointPrevious(text[@intCast(start)..text.len], &codepoint_size);
if (err == '?') @panic("getCodepointNext failed");
if (start - codepoint_size > 0) {
start -= codepoint_size;
} else {
start = 0;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawRectangle(0, 0, rl.getScreenWidth(), 70, .black);
rl.drawText(rl.textFormat("Total codepoints contained in provided text: %i", .{codepoints_count}), 10, 10, 20, .green);
rl.drawText(rl.textFormat("Total codepoints required for font atlas (duplicates excluded): %u", .{codepoints_no_dups_count}), 10, 40, 20, .green);
if (show_font_atlas) {
// Draw generated font texture atlas containing provided codepoints
rl.drawTexture(font.texture, 150, 100, .black);
rl.drawRectangleLines(150, 100, font.texture.width, font.texture.height, .black);
} else {
// Draw provided text with loaded font, containing all required codepoint glyphs
rl.drawTextEx(font, text, .{ .x = 160, .y = 110 }, 48, 5, .black);
}
rl.drawText("Press SPACE to toggle font atlas view!", 10, rl.getScreenHeight() - 30, 20, .gray);
//----------------------------------------------------------------------------------
}
}
/// Remove codepoint duplicates if requested
/// WARNING: This process could be a bit slow if there text to process is very long
fn CodepointRemoveDuplicates(allocator: std.mem.Allocator, codepoints: []i32) ![:0]i32 {
var no_dups: [:0]i32 = try allocator.allocSentinel(i32, codepoints.len, 0);
std.mem.copyForwards(i32, no_dups, codepoints);
var no_dups_count: usize = no_dups.len;
// Remove duplicates
var i: usize = 0;
while (i < no_dups_count) {
defer i += 1;
var j: usize = i + 1;
while (j < no_dups_count) {
defer j += 1;
const match = no_dups[i] == no_dups[j];
if (match) {
var k: usize = j;
while (k < no_dups_count) {
defer k += 1;
no_dups[k] = no_dups[k + 1];
}
no_dups_count -= 1;
j -= 1;
no_dups[no_dups_count] = 0;
}
}
}
// NOTE: The size of codepointsNoDups is the same as original array but
// only required positions are filled (codepointsNoDupsCount)
return no_dups;
}

694
examples/text/draw_3d.zig Normal file
View File

@ -0,0 +1,694 @@
//!******************************************************************************************
//!
//! raylib-zig port of the [text] example - Draw 3d
//! https://github.com/raysan5/raylib/blob/master/examples/text/text_draw_3d.c
//!
//! Example complexity rating: [] 4/4
//!
//! NOTE: Draw a 2D text in 3D space, each letter is drawn in a quad (or 2 quads if backface is set)
//! where the texture coodinates of each quad map to the texture coordinates of the glyphs
//! inside the font texture.
//!
//! A more efficient approach, i believe, would be to render the text in a render texture and
//! map that texture to a plane and render that, or maybe a shader but my method allows more
//! flexibility...for example to change position of each letter individually to make somethink
//! like a wavy text effect.
//!
//! Special thanks to:
//! @Nighten for the DrawTextStyle() code https://github.com/NightenDushi/Raylib_DrawTextStyle
//! Chris Camacho (codifies - http://bedroomcoders.co.uk/) for the alpha discard shader
//!
//! Example originally created with raylib 3.5, last time updated with raylib 4.0
//!
//! Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Copyright (c) 2021-2025 Vlad Adrian (@demizdor)
//!
//!*******************************************************************************************
const std = @import("std");
const rl = @import("raylib");
const cl = @import("codepoints_loading.zig");
//--------------------------------------------------------------------------------------
// Globals
//--------------------------------------------------------------------------------------
const letter_boundry_size = 0.25;
const text_max_layers = 32;
const letter_boundry_color = rl.Color.violet;
var show_letter_boundry = false;
var show_text_boundry = false;
//--------------------------------------------------------------------------------------
// Data Types definition
//--------------------------------------------------------------------------------------
// Configuration structure for waving the text
const WaveTextConfig = struct {
waveRange: rl.Vector3,
waveSpeed: rl.Vector3,
waveOffset: rl.Vector3,
};
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.setConfigFlags(.{ .msaa_4x_hint = true, .vsync_hint = true });
rl.initWindow(screen_width, screen_height, "raylib [text] example - draw 2D text in 3D");
defer rl.closeWindow();
var spin = true; // Spin the camera?
var multicolor = false; // Multicolor mode
// Define the camera to look into our 3d world
var camera: rl.Camera3D = .{
.position = .{ .x = -10, .y = 15, .z = -10 },
.target = .{ .x = 0, .y = 0, .z = 0 },
.up = .{ .x = 0, .y = 1, .z = 0 },
.fovy = 45,
.projection = .perspective,
};
var camera_mode = rl.CameraMode.orbital;
const cube_postition = rl.Vector3{ .x = 0.0, .y = 1.0, .z = 0.0 };
const cube_size = rl.Vector3{ .x = 2.0, .y = 2.0, .z = 2.0 };
// Use the default font
const default_font = try rl.getFontDefault();
defer rl.unloadFont(default_font);
var font = try rl.getFontDefault();
defer rl.unloadFont(font);
var font_size: f32 = 0.8;
var fontSpacing: f32 = 0.05;
var lineSpacing: f32 = -0.1;
// var tbox = rl.Vector3{};
var layers: usize = 1;
var quads: usize = 0;
var layerDistance: f32 = 0.01;
const wcfg = WaveTextConfig{
.waveSpeed = .{ .x = 3, .y = 3, .z = 0.5 },
.waveOffset = .{ .x = 0.35, .y = 0.35, .z = 0.35 },
.waveRange = .{ .x = 0.45, .y = 0.45, .z = 0.45 },
};
var time: f32 = 0.0;
// Setup a light and dark color
var light = rl.Color.maroon;
var dark = rl.Color.red;
// Load the alpha discard shader
const alphaDiscard = try rl.loadShader(null, "examples/text/resources/shaders/glsl330/alpha_discard.fs");
// Array filled with multiple random colors (when multicolor mode is set)
var multi: [text_max_layers]rl.Color = undefined;
// Set the text (using markdown!)
var text = [_:0]u8{0} ** 64;
var fw = std.Io.Writer.fixed(text[0..]);
_ = try fw.writeAll("Hello ~~World~~ In 3D!");
rl.disableCursor(); // Limit cursor to relative movement inside the window
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
rl.updateCamera(&camera, camera_mode);
// Handle font files dropped
if (rl.isFileDropped()) {
const droppedFiles: rl.FilePathList = rl.loadDroppedFiles();
defer rl.unloadDroppedFiles(droppedFiles); // Unload filepaths from memory
// NOTE: We only support first ttf file dropped
const path: [:0]const u8 = std.mem.span(droppedFiles.paths[0]);
if (rl.isFileExtension(path, ".ttf")) {
rl.unloadFont(font);
font = try rl.loadFontEx(path, @intFromFloat(font_size), null);
} else if (rl.isFileExtension(path, ".fnt")) {
rl.unloadFont(font);
font = try rl.loadFont(path);
font_size = @floatFromInt(font.baseSize);
}
}
// Handle Events
if (rl.isKeyPressed(.f1)) show_letter_boundry = !show_letter_boundry;
if (rl.isKeyPressed(.f2)) show_text_boundry = !show_text_boundry;
if (rl.isKeyPressed(.f3)) {
// Handle camera change
spin = !spin;
// we need to reset the camera when changing modes
camera = rl.Camera3D{
.target = .{ .x = 0.0, .y = 0.0, .z = 0.0 }, // Camera looking at point
.up = .{ .x = 0.0, .y = 1.0, .z = 0.0 }, // Camera up vector (rotation towards target)
.fovy = 45.0, // Camera field-of-view Y
.projection = .perspective, // Camera mode type
.position = .{ .x = 10.0, .y = 10.0, .z = -10.0 }, // Camera position
};
camera_mode = .free;
if (spin) {
camera_mode = .orbital;
camera.position = .{ .x = -10.0, .y = 15.0, .z = -10.0 }; // Camera position
}
}
// Handle clicking the cube
if (rl.isMouseButtonPressed(.left)) {
const ray = rl.getScreenToWorldRay(rl.getMousePosition(), camera);
// Check collision between ray and box
const collision = rl.getRayCollisionBox(ray, .{ .max = .{ .x = cube_postition.x - cube_size.x / 2, .y = cube_postition.y - cube_size.y / 2, .z = cube_postition.z - cube_size.z / 2 }, .min = .{ .x = cube_postition.x + cube_size.x / 2, .y = cube_postition.y + cube_size.y / 2, .z = cube_postition.z + cube_size.z / 2 } });
if (collision.hit) {
// Generate new random colors
light = generateRandomColor(0.5, 0.78);
dark = generateRandomColor(0.4, 0.58);
}
}
// Handle text layers changes
if (rl.isKeyPressed(.home)) {
if (layers > 1) layers -= 1;
} else if (rl.isKeyPressed(.end)) {
if (layers < text_max_layers) layers += 1;
}
// Handle text changes
const key_pressed = rl.getKeyPressed();
switch (key_pressed) {
.left => font_size -= 0.5,
.right => font_size += 0.5,
.up => fontSpacing -= 0.1,
.down => fontSpacing += 0.1,
.page_up => lineSpacing -= 0.1,
.page_down => lineSpacing += 0.1,
.insert => layerDistance -= 0.001,
.delete => layerDistance += 0.001,
.tab => {
multicolor = !multicolor; // Enable /disable multicolor mode
if (multicolor) {
// Fill color array with random colors
for (0..text_max_layers) |i| {
multi[i] = generateRandomColor(0.5, 0.8);
multi[i].a = @intCast(rl.getRandomValue(0, 255));
}
}
},
else => {},
}
// Handle text input
const ch = rl.getCharPressed();
switch (key_pressed) {
.backspace => {
const len = rl.textLength(&text);
if (len > 0) text[len - 1] = 0;
},
.enter => {
const len = rl.textLength(&text);
if (len < text.len - 1) {
text[len] = '\n';
text[len + 1] = 0;
}
},
else => {
// append only printable chars
const len = rl.textLength(&text);
if (len < text.len) {
text[len] = @intCast(ch);
text[len + 1] = 0;
}
},
}
// Measure 3D text so we can center it
const tbox = measureTextWave3D(font, &text, font_size, fontSpacing, lineSpacing);
quads = 0; // Reset quad counter
time += rl.getFrameTime(); // Update timer needed by `DrawTextWave3D()`
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
{
rl.beginMode3D(camera);
defer rl.endMode3D();
rl.drawCubeV(cube_postition, cube_size, dark);
rl.drawCubeWires(cube_postition, 2.1, 2.1, 2.1, light);
rl.drawGrid(10, 2.0);
// Use a shader to handle the depth buffer issue with transparent textures
// NOTE: more info at https://bedroomcoders.co.uk/posts/198
rl.beginShaderMode(alphaDiscard);
defer rl.endShaderMode();
// Draw the 3D text above the red cube
{
rl.gl.rlPushMatrix();
defer rl.gl.rlPopMatrix();
rl.gl.rlRotatef(90.0, 1.0, 0.0, 0.0);
rl.gl.rlRotatef(90.0, 0.0, 0.0, -1.0);
for (0..layers) |i| {
var clr = light;
if (multicolor) clr = multi[i];
drawTextWave3D(font, &text, .{
.x = -tbox.x / 2.0,
.y = layerDistance * @as(f32, @floatFromInt(i)),
.z = -4.5,
}, font_size, fontSpacing, lineSpacing, true, wcfg, time, clr);
}
// Draw the text boundry if set
if (show_text_boundry) rl.drawCubeWiresV(.{ .x = 0.0, .y = 0.0, .z = -4.5 + tbox.z / 2 }, tbox, dark);
}
// Don't draw the letter boundries for the 3D text below
const slb = show_letter_boundry;
show_letter_boundry = false;
defer show_letter_boundry = slb;
// Draw 3D options (use default font)
//-------------------------------------------------------------------------
{
rl.gl.rlPushMatrix();
defer rl.gl.rlPopMatrix();
rl.gl.rlRotatef(180.0, 0.0, 1.0, 0.0);
// In the C version of this library we use rl.textFormat to format our text. This doesn't play nice Zig's slice strings.
// You might be able to make it work but I switched to using the std.fmt interfaces which are more ergonomic in zig anyways.
// I use an oversized fixed buffer, but you could use an allocator to get a more robust solution
var text_buf = [_:0]u8{0} ** 64;
var opt = try std.fmt.bufPrintZ(&text_buf, "< SIZE: {d} >", .{font_size});
var m = rl.measureTextEx(default_font, opt, 0.8, 0.1);
var pos = rl.Vector3{ .x = -m.x / 2.0, .y = 0.01, .z = 2.0 };
drawText3D(default_font, opt, pos, 0.8, 0.1, 0.0, false, .blue);
pos.z += 0.5 + m.y;
opt = try std.fmt.bufPrintZ(&text_buf, "< SPACING: {d} >", .{fontSpacing});
quads += std.mem.len(opt.ptr);
m = rl.measureTextEx(default_font, opt, 0.8, 0.1);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt, pos, 0.8, 0.1, 0.0, false, .blue);
pos.z += 0.5 + m.y;
opt = try std.fmt.bufPrintZ(&text_buf, "< LINE: {d} >", .{lineSpacing});
quads += std.mem.len(opt.ptr);
m = rl.measureTextEx(default_font, opt, 0.8, 0.1);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt, pos, 0.8, 0.1, 0.0, false, .blue);
pos.z += 0.5 + m.y;
opt = try std.fmt.bufPrintZ(&text_buf, "< LBOX: {s} >", .{if (slb) "ON" else "OFF"});
quads += std.mem.len(opt.ptr);
m = rl.measureTextEx(default_font, opt, 0.8, 0.1);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt, pos, 0.8, 0.1, 0.0, false, .red);
pos.z += 0.5 + m.y;
opt = try std.fmt.bufPrintZ(&text_buf, "< TBOX: {s} >", .{if (show_text_boundry) "ON" else "OFF"});
quads += std.mem.len(opt.ptr);
m = rl.measureTextEx(default_font, opt, 0.8, 0.1);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt, pos, 0.8, 0.1, 0.0, false, .red);
pos.z += 0.5 + m.y;
opt = try std.fmt.bufPrintZ(&text_buf, "< LAYER DISTANCE: {d} >", .{layerDistance});
quads += std.mem.len(opt.ptr);
m = rl.measureTextEx(default_font, opt, 0.8, 0.1);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt, pos, 0.8, 0.1, 0.0, false, .dark_purple);
}
//-------------------------------------------------------------------------
// Draw 3D info text (use default font)
//-------------------------------------------------------------------------
const opt1 = "All the text displayed here is in 3D";
quads += opt1.len;
var m = rl.measureTextEx(default_font, opt1, 1.0, 0.05);
var pos = rl.Vector3{ .x = -m.x / 2.0, .y = 0.01, .z = 2.0 };
drawText3D(default_font, opt1, pos, 1.0, 0.05, 0.0, false, .dark_blue);
pos.z += 1.5 + m.y;
const opt2 = "press [Left]/[Right] to change the font size";
quads += opt2.len;
m = rl.measureTextEx(default_font, opt2, 0.6, 0.05);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt2, pos, 0.6, 0.05, 0.0, false, .dark_blue);
pos.z += 0.5 + m.y;
const opt3 = "press [Up]/[Down] to change the font spacing";
quads += opt3.len;
m = rl.measureTextEx(default_font, opt3, 0.6, 0.05);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt3, pos, 0.6, 0.05, 0.0, false, .dark_blue);
pos.z += 0.5 + m.y;
const opt4 = "press [PgUp]/[PgDown] to change the line spacing";
quads += opt4.len;
m = rl.measureTextEx(default_font, opt4, 0.6, 0.05);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt4, pos, 0.6, 0.05, 0.0, false, .dark_blue);
pos.z += 0.5 + m.y;
const opt5 = "press [F1] to toggle the letter boundry";
quads += opt5.len;
m = rl.measureTextEx(default_font, opt5, 0.6, 0.05);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt5, pos, 0.6, 0.05, 0.0, false, .dark_blue);
pos.z += 0.5 + m.y;
const opt6 = "press [F2] to toggle the text boundry";
quads += opt6.len;
m = rl.measureTextEx(default_font, opt6, 0.6, 0.05);
pos.x = -m.x / 2.0;
drawText3D(default_font, opt6, pos, 0.6, 0.05, 0.0, false, .dark_blue);
//-------------------------------------------------------------------------
}
// Draw 2D info text & stats
//-------------------------------------------------------------------------
rl.drawText("Drag & drop a font file to change the font!\nType something, see what happens!\n\nPress [F3] to toggle the camera", 10, 35, 10, .black);
quads += rl.textLength(&text) * 2 * layers;
var buf = [_:0]u8{0} ** 70;
const tmp = std.fmt.bufPrintZ(&buf, "{} layer(s) | {s} camera | {} quads ({} verts)", .{
layers,
if (spin) "ORBITAL" else "FREE",
quads,
quads * 4,
}) catch unreachable;
var width = rl.measureText(tmp, 10);
rl.drawText(tmp, screen_width - 20 - width, 10, 10, .dark_green);
const tmp2 = "[Home]/[End] to add/remove 3D text layers";
width = rl.measureText(tmp2, 10);
rl.drawText(tmp2, screen_width - 20 - width, 25, 10, .dark_gray);
const tmp3 = "[Insert]/[Delete] to increase/decrease distance between layers";
width = rl.measureText(tmp3, 10);
rl.drawText(tmp3, screen_width - 20 - width, 40, 10, .dark_gray);
const tmp4 = "click the [CUBE] for a random color";
width = rl.measureText(tmp4, 10);
rl.drawText(tmp4, screen_width - 20 - width, 55, 10, .dark_gray);
const tmp5 = "[Tab] to toggle multicolor mode";
width = rl.measureText(tmp5, 10);
rl.drawText(tmp5, screen_width - 20 - width, 70, 10, .dark_gray);
//-------------------------------------------------------------------------
rl.drawFPS(10, 10);
//----------------------------------------------------------------------------------
}
}
//--------------------------------------------------------------------------------------
// Module Functions Definitions
//--------------------------------------------------------------------------------------
/// Draw codepoint at specified position in 3D space
fn drawTextCodepoint3D(font: rl.Font, codepoint: i32, start_position: rl.Vector3, fontSize: f32, backface: bool, tint: rl.Color) void {
// Character index position in sprite font
// NOTE: In case a codepoint is not available in the font, index returned points to '?'
const index: usize = @intCast(rl.getGlyphIndex(font, codepoint));
const scale: f32 = fontSize / @as(f32, @floatFromInt(font.baseSize));
const glyphPadding: f32 = @floatFromInt(font.glyphPadding);
// Character destination rectangle on screen
// NOTE: We consider charsPadding on drawing
const position = rl.Vector3{
.x = start_position.x + @as(f32, @floatFromInt(font.glyphs[index].offsetX - font.glyphPadding)) * scale,
.y = start_position.y,
.z = start_position.z + @as(f32, @floatFromInt(font.glyphs[index].offsetY - font.glyphPadding)) * scale,
};
// Character source rectangle from font texture atlas
// NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects
const srcRec = rl.Rectangle{
.x = font.recs[index].x - glyphPadding,
.y = font.recs[index].y - glyphPadding,
.width = font.recs[index].width + 2.0 * glyphPadding,
.height = font.recs[index].height + 2.0 * glyphPadding,
};
const width: f32 = (font.recs[index].width + 2.0 * glyphPadding) * scale;
const height: f32 = (font.recs[index].height + 2.0 * glyphPadding) * scale;
if (font.texture.id > 0) {
const x = 0.0;
const y = 0.0;
const z = 0.0;
// normalized texture coordinates of the glyph inside the font texture (0.0f -> 1.0f)
const tx: f32 = srcRec.x / @as(f32, @floatFromInt(font.texture.width));
const ty: f32 = srcRec.y / @as(f32, @floatFromInt(font.texture.height));
const tw: f32 = (srcRec.x + srcRec.width) / @as(f32, @floatFromInt(font.texture.width));
const th: f32 = (srcRec.y + srcRec.height) / @as(f32, @floatFromInt(font.texture.height));
if (show_letter_boundry) rl.drawCubeWiresV(.{ .x = position.x + width / 2, .y = position.y, .z = position.z + height / 2 }, .{ .x = width, .y = letter_boundry_size, .z = height }, letter_boundry_color);
//not entirely sure if this has a side effect, its in the original, so I'm not touching it
_ = rl.gl.rlCheckRenderBatchLimit(if (backface) 8 else 4);
rl.gl.rlSetTexture(font.texture.id);
defer rl.gl.rlSetTexture(0);
rl.gl.rlPushMatrix();
defer rl.gl.rlPopMatrix();
rl.gl.rlTranslatef(position.x, position.y, position.z);
rl.gl.rlBegin(rl.gl.rl_quads);
defer rl.gl.rlEnd();
rl.gl.rlColor4ub(tint.r, tint.g, tint.b, tint.a);
// Front Face
rl.gl.rlNormal3f(0.0, 1.0, 0.0); // Normal Pointing Up
rl.gl.rlTexCoord2f(tx, ty);
rl.gl.rlVertex3f(x, y, z); // Top Left Of The Texture and Quad
rl.gl.rlTexCoord2f(tx, th);
rl.gl.rlVertex3f(x, y, z + height); // Bottom Left Of The Texture and Quad
rl.gl.rlTexCoord2f(tw, th);
rl.gl.rlVertex3f(x + width, y, z + height); // Bottom Right Of The Texture and Quad
rl.gl.rlTexCoord2f(tw, ty);
rl.gl.rlVertex3f(x + width, y, z); // Top Right Of The Texture and Quad
if (backface) {
// Back Face
rl.gl.rlNormal3f(0.0, -1.0, 0.0); // Normal Pointing Down
rl.gl.rlTexCoord2f(tx, ty);
rl.gl.rlVertex3f(x, y, z); // Top Right Of The Texture and Quad
rl.gl.rlTexCoord2f(tw, ty);
rl.gl.rlVertex3f(x + width, y, z); // Top Left Of The Texture and Quad
rl.gl.rlTexCoord2f(tw, th);
rl.gl.rlVertex3f(x + width, y, z + height); // Bottom Left Of The Texture and Quad
rl.gl.rlTexCoord2f(tx, th);
rl.gl.rlVertex3f(x, y, z + height); // Bottom Right Of The Texture and Quad
}
}
}
/// Draw a 2D text in 3D space
fn drawText3D(font: rl.Font, text: [:0]const u8, position: rl.Vector3, font_size: f32, font_spacing: f32, line_spacing: f32, backface: bool, tint: rl.Color) void {
const length = rl.textLength(text); // Total length in bytes of the text, scanned by codepoints in loop
var text_offset_y: f32 = 0.0; // Offset between lines (on line break '\n')
var text_offset_x: f32 = 0.0; // Offset X to next character to draw
const scale = font_size / @as(f32, @floatFromInt(font.baseSize));
var i: usize = 0;
while (i < length) {
// Get next codepoint from byte string and glyph index in font
var codepoint_byte_count: i32 = 0;
const codepoint = rl.getCodepoint(text[i..], &codepoint_byte_count);
const index: usize = @intCast(rl.getGlyphIndex(font, codepoint));
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepoint_byte_count = 1;
if (codepoint == '\n') {
// NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user
text_offset_y += font_size + line_spacing;
text_offset_x = 0.0;
} else {
if ((codepoint != ' ') and (codepoint != '\t')) {
drawTextCodepoint3D(font, codepoint, .{
.x = position.x + text_offset_x,
.y = position.y,
.z = position.z + text_offset_y,
}, font_size, backface, tint);
}
if (font.glyphs[index].advanceX == 0) {
text_offset_x += font.recs[index].width * scale + font_spacing;
} else {
text_offset_x += @as(f32, @floatFromInt(font.glyphs[index].advanceX)) * scale + font_spacing;
}
}
i += @intCast(codepoint_byte_count); // Move text bytes counter to next codepoint
}
}
/// Draw a 2D text in 3D space and wave the parts that start with `~~` and end with `~~`.
/// This is a modified version of the original code by @Nighten found here https://github.com/NightenDushi/Raylib_DrawTextStyle
fn drawTextWave3D(font: rl.Font, text: [:0]const u8, position: rl.Vector3, fontSize: f32, fontSpacing: f32, lineSpacing: f32, backface: bool, config: WaveTextConfig, time: f32, tint: rl.Color) void {
const length = rl.textLength(text); // Total length in bytes of the text, scanned by codepoints in loop
var text_offset_x: f32 = 0.0; // Offset X to next character to draw
var text_offset_y: f32 = 0.0; // Offset between lines (on line break '\n')
const scale = fontSize / @as(f32, @floatFromInt(font.baseSize));
var wave = false;
var i: usize = 0;
var k: usize = 0;
while (i < length) : (k += 1) {
// Get next codepoint from byte string and glyph index in font
var codepointByteCount: i32 = 0;
const codepoint = rl.getCodepoint(text[i..], &codepointByteCount);
const index: usize = @intCast(rl.getGlyphIndex(font, codepoint));
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1;
switch (codepoint) {
'\n' => {
// NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user
text_offset_y += fontSize + lineSpacing;
text_offset_x = 0.0;
k = 0;
},
'~' => {
if (rl.getCodepoint(text[i + 1 ..], &codepointByteCount) == '~') {
codepointByteCount += 1;
wave = !wave;
}
},
else => {
if ((codepoint != ' ') and (codepoint != '\t')) {
var pos = position;
if (wave) // Apply the wave effect
{
const kF: f32 = @floatFromInt(k);
pos.x += std.math.sin(time * config.waveSpeed.x - kF * config.waveOffset.x) * config.waveRange.x;
pos.y += std.math.sin(time * config.waveSpeed.y - kF * config.waveOffset.y) * config.waveRange.y;
pos.z += std.math.sin(time * config.waveSpeed.z - kF * config.waveOffset.z) * config.waveRange.z;
}
drawTextCodepoint3D(font, codepoint, .{
.x = pos.x + text_offset_x,
.y = pos.y,
.z = pos.z + text_offset_y,
}, fontSize, backface, tint);
}
if (font.glyphs[index].advanceX == 0) {
text_offset_x += font.recs[index].width * scale + fontSpacing;
} else {
text_offset_x += @as(f32, @floatFromInt(font.glyphs[index].advanceX)) * scale + fontSpacing;
}
},
}
i += @intCast(codepointByteCount); // Move text bytes counter to next codepoint
}
}
/// Measure a text in 3D ignoring the `~~` chars.
fn measureTextWave3D(font: rl.Font, text: [:0]const u8, fontSize: f32, fontSpacing: f32, lineSpacing: f32) rl.Vector3 {
const len = rl.textLength(text);
var temp_len: usize = 0; // Used to count longer text line num chars
var len_counter: usize = 0;
var temp_text_width: f32 = 0.0; // Used to count longer text line width
const scale = fontSize / @as(f32, @floatFromInt(font.baseSize));
var text_height = scale;
var text_width: f32 = 0.0;
var letter: i32 = 0; // Current character
var index: usize = 0; // Index position in sprite font
var i: usize = 0;
while (i < len) {
var next: i32 = 0;
letter = rl.getCodepoint(text[i..], &next);
index = @intCast(rl.getGlyphIndex(font, letter));
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
if (letter == 0x3f) next = 1;
i += @intCast(next);
if (letter != '\n') {
if (letter == '~' and rl.getCodepoint(text[i + 1 ..], &next) == '~') {
i += 1;
} else {
len_counter += 1;
if (font.glyphs[index].advanceX != 0) {
text_width += @as(f32, @floatFromInt(font.glyphs[index].advanceX)) * scale;
} else text_width += (font.recs[index].width + @as(f32, @floatFromInt(font.glyphs[index].offsetX))) * scale;
}
} else {
if (temp_text_width < text_width) temp_text_width = text_width;
len_counter = 0;
text_width = 0.0;
text_height += fontSize + lineSpacing;
}
if (temp_len < len_counter) temp_len = len_counter;
}
if (temp_text_width < text_width) temp_text_width = text_width;
const vec = rl.Vector3{
.x = temp_text_width + (@as(f32, @floatFromInt(temp_len - 1)) * fontSpacing), // Adds chars spacing to measure
.y = 0.25,
.z = text_height,
};
return vec;
}
/// Generates a nice color with a random hue
fn generateRandomColor(s: f32, v: f32) rl.Color {
const Phi: f32 = 0.618033988749895; // Golden ratio conjugate
var h: f32 = @floatFromInt(rl.getRandomValue(0, 360));
h = std.math.mod(f32, (h + h * Phi), 360.0) catch 0;
return rl.colorFromHSV(h, s, v);
}

View File

@ -0,0 +1,143 @@
//!*******************************************************************************************
//!
//! raylib-zig port of the [text] example - Font filters
//! https://github.com/raysan5/raylib/blob/master/examples/text/text_font_filters.c
//!
//! Example complexity rating: [] 2/4
//!
//! NOTE: After font loading, font texture atlas filter could be configured for a softer
//! display of the font when scaling it to different sizes, that way, it's not required
//! to generate multiple fonts at multiple sizes (as long as the scaling is not very different)
//!
//! Example originally created with raylib 1.3, last time updated with raylib 4.2
//!
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
//!
//!*******************************************************************************************
const std = @import("std");
const rl = @import("raylib");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [text] example - font filters");
defer rl.closeWindow();
const msg = "Loaded Font";
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
// TTF Font loading with custom generation parameters
var font = try rl.loadFontEx("examples/text/resources/KAISG.ttf", 96, null);
// Generate mipmap levels to use trilinear filtering
// NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR
rl.genTextureMipmaps(&font.texture);
var font_size: f32 = @floatFromInt(font.baseSize);
var fontPosition = rl.Vector2{ .x = 40.0, .y = screen_height / 2.0 - 80.0 };
var text_size = rl.Vector2{ .x = 0.0, .y = 0.0 };
// Setup texture scaling filter
rl.setTextureFilter(font.texture, .point);
var currentFontFilter: i32 = 0; // TEXTURE_FILTER_POINT
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
font_size += rl.getMouseWheelMove() * 4.0;
// Choose font texture filter method
const key_pressed = rl.getKeyPressed();
switch (key_pressed) {
.one => {
rl.setTextureFilter(font.texture, .point);
currentFontFilter = 0;
},
.two => {
rl.setTextureFilter(font.texture, .bilinear);
currentFontFilter = 1;
},
.three => {
// NOTE: Trilinear filter won't be noticed on 2D drawing
rl.setTextureFilter(font.texture, .trilinear);
currentFontFilter = 2;
},
else => {},
}
text_size = rl.measureTextEx(font, msg, font_size, 0);
if (rl.isKeyDown(.left)) {
fontPosition.x -= 10;
} else if (rl.isKeyDown(.right)) {
fontPosition.x += 10;
}
// Load a dropped TTF file dynamically (at current fontSize)
if (rl.isFileDropped()) {
const dropped_files: rl.FilePathList = rl.loadDroppedFiles();
defer rl.unloadDroppedFiles(dropped_files); // Unload filepaths from memory
// NOTE: We only support first ttf file dropped
const path: [:0]const u8 = std.mem.span(dropped_files.paths[0]);
if (rl.isFileExtension(path, ".ttf")) {
rl.unloadFont(font);
font = try rl.loadFontEx(path, @intFromFloat(font_size), null);
} else if (rl.isFileExtension(path, ".fnt")) {
rl.unloadFont(font);
font = try rl.loadFont(path);
font_size = @floatFromInt(font.baseSize);
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("Use mouse wheel to change font size", 20, 20, 10, .gray);
rl.drawText("Use KEY_RIGHT and KEY_LEFT to move text", 20, 40, 10, .gray);
rl.drawText("Use 1, 2, 3 to change texture filter", 20, 60, 10, .gray);
rl.drawText("Drop a new TTF font for dynamic loading", 20, 80, 10, .dark_gray);
rl.drawTextEx(font, msg, fontPosition, font_size, 0, .black);
// TODO: It seems texSize measurement is not accurate due to chars offsets...
//DrawRectangleLines(fontPosition.x, fontPosition.y, textSize.x, textSize.y, RED);
rl.drawRectangle(0, screen_height - 80, screen_width, 80, .light_gray);
rl.drawText(rl.textFormat("Font size: %02.02f", .{font_size}), 20, screen_height - 50, 10, .dark_gray);
rl.drawText(rl.textFormat("Text size: [%02.02f, %02.02f]", .{ text_size.x, text_size.y }), 20, screen_height - 30, 10, .dark_gray);
rl.drawText("CURRENT TEXTURE FILTER:", 250, 400, 20, .gray);
switch (currentFontFilter) {
0 => rl.drawText("POINT", 570, 400, 20, .black),
1 => rl.drawText("BILINEAR", 570, 400, 20, .black),
2 => rl.drawText("TRILINEAR", 570, 400, 20, .black),
else => unreachable,
}
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,95 @@
//!******************************************************************************************
//!
//! raylib-zig port of the [text] example - Font loading
//! https://github.com/raysan5/raylib/blob/master/examples/text/text_font_loading.c
//!
//! Example complexity rating: [] 1/4
//!
//! NOTE: raylib can load fonts from multiple input file formats:
//!
//! - TTF/OTF > Sprite font atlas is generated on loading, user can configure
//! some of the generation parameters (size, characters to include)
//! - BMFonts > Angel code font fileformat, sprite font image must be provided
//! together with the .fnt file, font generation cna not be configured
//! - XNA Spritefont > Sprite font image, following XNA Spritefont conventions,
//! Characters in image must follow some spacing and order rules
//!
//! Example originally created with raylib 1.4, last time updated with raylib 3.0
//!
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Copyright (c) 2016-2025 Ramon Santamaria (@raysan5)
//!
//!*******************************************************************************************
const rl = @import("raylib");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [text] example - font loading");
defer rl.closeWindow();
// Define characters to draw
// NOTE: raylib supports UTF-8 encoding, following list is actually codified as UTF8 internally
const msg = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI\nJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmn\nopqrstuvwxyz{|}~¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓ\nÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷\nøùúûüýþÿ";
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
// BMFont (AngelCode) : Font data and image atlas have been generated using external program
const font_bm = try rl.loadFont("examples/text/resources/pixantiqua.fnt");
defer rl.unloadFont(font_bm);
// TTF font : Font data and atlas are generated directly from TTF
// NOTE: We define a font base size of 32 pixels tall and up-to 250 characters
const font_ttf = try rl.loadFontEx("examples/text/resources/pixantiqua.ttf", 32, null);
defer rl.unloadFont(font_ttf);
rl.setTextLineSpacing(16); // Set line spacing for multiline text (when line breaks are included '\n')
var use_ttf = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (rl.isKeyDown(.space)) {
use_ttf = true;
} else {
use_ttf = false;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("Hold SPACE to use TTF generated font", 20, 20, 20, .light_gray);
if (!use_ttf) {
rl.drawTextEx(font_bm, msg, .{ .x = 20.0, .y = 100.0 }, @floatFromInt(font_bm.baseSize), 2, .maroon);
rl.drawText("Using BMFont (Angelcode) imported", 20, rl.getScreenHeight() - 30, 20, .gray);
} else {
rl.drawTextEx(font_ttf, msg, .{ .x = 20.0, .y = 100.0 }, @floatFromInt(font_ttf.baseSize), 2, .lime);
rl.drawText("Using TTF font generated", 20, rl.getScreenHeight() - 30, 20, .gray);
}
//----------------------------------------------------------------------------------
}
}

132
examples/text/font_sdf.zig Normal file
View File

@ -0,0 +1,132 @@
//!*******************************************************************************************
//!
//! raylib-zig port of the [text] example - Font SDF loading
//! https://github.com/raysan5/raylib/blob/master/examples/text/text_font_sdf.c
//!
//! Example complexity rating: [] 3/4
//!
//! Example originally created with raylib 1.3, last time updated with raylib 4.0
//!
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
//!
//!*******************************************************************************************
const std = @import("std");
const rl = @import("raylib");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [text] example - SDF fonts");
defer rl.closeWindow();
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
const msg = "Signed Distance Fields";
// Loading file to memory
const font_default = try rl.loadFontEx("examples/text/resources/anonymous_pro_bold.ttf", 16, null);
defer font_default.unload();
var font_sdf: rl.Font = font_default;
defer font_sdf.unload();
{
// SDF font generation from TTF font
const file_data = try rl.loadFileData("examples/text/resources/anonymous_pro_bold.ttf");
defer rl.unloadFileData(file_data); // Free memory from loaded file
font_sdf = .{
.baseSize = 16,
.glyphCount = 95,
.glyphPadding = 0,
.glyphs = @ptrCast(try rl.loadFontData(@ptrCast(file_data), 16, null, .sdf)),
.texture = undefined,
.recs = undefined,
};
const atlas_image, const atlas_recs = try rl.genImageFontAtlas(font_sdf.glyphs[0..@intCast(font_sdf.glyphCount)], font_sdf.baseSize, 0, 1);
defer atlas_image.unload();
font_sdf.texture = try rl.loadTextureFromImage(atlas_image);
font_sdf.recs = @ptrCast(atlas_recs);
}
// Load SDF required shader (we use default vertex shader)
const shader = try rl.loadShader(null, "examples/text/resources/shaders/glsl330/sdf.fs");
defer rl.unloadShader(shader);
rl.setTextureFilter(font_sdf.texture, .bilinear); // Required for SDF font
var font_position = rl.Vector2{ .x = 40, .y = @as(f32, @floatFromInt(screen_height)) / 2.0 - 50 };
var text_size = rl.Vector2{ .x = 0.0, .y = 0.0 };
var font_size: f32 = 16.0;
var current_font: i32 = 0; // 0 - fontDefault, 1 - fontSDF
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
font_size += rl.getMouseWheelMove() * 8.0;
if (font_size < 6) font_size = 6;
if (rl.isKeyDown(.space)) {
current_font = 1;
} else {
current_font = 0;
}
if (current_font == 0) {
text_size = rl.measureTextEx(font_default, msg, font_size, 0);
} else {
text_size = rl.measureTextEx(font_sdf, msg, font_size, 0);
}
font_position.x = @as(f32, @floatFromInt(rl.getScreenWidth())) / 2 - text_size.x / 2;
font_position.y = @as(f32, @floatFromInt(rl.getScreenHeight())) / 2 - text_size.y / 2 + 80;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
if (current_font == 1) {
// NOTE: SDF fonts require a custom SDf shader to compute fragment color
rl.beginShaderMode(shader); // Activate SDF font shader
rl.drawTextEx(font_sdf, msg, font_position, font_size, 0, .black);
rl.endShaderMode(); // Activate our default shader for next drawings
rl.drawTexture(font_sdf.texture, 10, 10, .black);
} else {
rl.drawTextEx(font_default, msg, font_position, font_size, 0, .black);
rl.drawTexture(font_default.texture, 10, 10, .black);
}
if (current_font == 1) {
rl.drawText("SDF!", 320, 20, 80, .red);
} else {
rl.drawText("default font", 315, 40, 30, .gray);
}
rl.drawText("FONT SIZE: 16.0", rl.getScreenWidth() - 240, 20, 20, .dark_gray);
rl.drawText(rl.textFormat("RENDER SIZE: %02.02f", .{font_size}), rl.getScreenWidth() - 240, 50, 20, .dark_gray);
rl.drawText("Use MOUSE WHEEL to SCALE TEXT!", rl.getScreenWidth() - 240, 90, 10, .dark_gray);
rl.drawText("HOLD SPACE to USE SDF FONT VERSION!", 340, rl.getScreenHeight() - 30, 20, .maroon);
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,94 @@
//!******************************************************************************************
//!
//! raylib-zig port of the [text] example - Sprite font loading
//! https://github.com/raysan5/raylib/blob/master/examples/text/text_font_spritefont.c
//!
//! Example complexity rating: [] 1/4
//!
//! NOTE: Sprite fonts should be generated following this conventions:
//!
//! - Characters must be ordered starting with character 32 (Space)
//! - Every character must be contained within the same Rectangle height
//! - Every character and every line must be separated by the same distance (margin/padding)
//! - Rectangles must be defined by a MAGENTA color background
//!
//! Following those constraints, a font can be provided just by an image,
//! this is quite handy to avoid additional font descriptor files (like BMFonts use).
//!
//! Example originally created with raylib 1.0, last time updated with raylib 1.0
//!
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
//!
//!*******************************************************************************************
const rl = @import("raylib");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [text] example - sprite font loading");
defer rl.closeWindow();
const msg1 = "THIS IS A custom SPRITE FONT...";
const msg2 = "...and this is ANOTHER CUSTOM font...";
const msg3 = "...and a THIRD one! GREAT! :D";
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
const font1 = try rl.loadFont("examples/text/resources/custom_mecha.png"); // Font loading
defer rl.unloadFont(font1);
const font2 = try rl.loadFont("examples/text/resources/custom_alagard.png"); // Font loading
defer rl.unloadFont(font2);
const font3 = try rl.loadFont("examples/text/resources/custom_jupiter_crash.png"); // Font loading
defer rl.unloadFont(font3);
const font_position1 = rl.Vector2{
.x = @as(f32, @floatFromInt(screen_width)) / 2.0 - rl.measureTextEx(font1, msg1, @floatFromInt(font1.baseSize), -3).x / 2,
.y = @as(f32, @floatFromInt(screen_height)) / 2.0 - @as(f32, @floatFromInt(font1.baseSize)) / 2.0 - 80.0,
};
const font_position2 = rl.Vector2{
.x = @as(f32, @floatFromInt(screen_width)) / 2.0 - rl.measureTextEx(font2, msg2, @floatFromInt(font2.baseSize), -2).x / 2,
.y = @as(f32, @floatFromInt(screen_height)) / 2.0 - @as(f32, @floatFromInt(font1.baseSize)) / 2.0 - 10.0,
};
const font_position3 = rl.Vector2{
.x = @as(f32, @floatFromInt(screen_width)) / 2.0 - rl.measureTextEx(font3, msg3, @floatFromInt(font3.baseSize), 2).x / 2,
.y = @as(f32, @floatFromInt(screen_height)) / 2.0 - @as(f32, @floatFromInt(font1.baseSize)) / 2.0 + 50.0,
};
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update variables here...
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawTextEx(font1, msg1, font_position1, @floatFromInt(font1.baseSize), -3, .white);
rl.drawTextEx(font2, msg2, font_position2, @floatFromInt(font2.baseSize), -2, .white);
rl.drawTextEx(font3, msg3, font_position3, @floatFromInt(font3.baseSize), 2, .white);
//----------------------------------------------------------------------------------
}
}

View File

@ -35,15 +35,15 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.white);
rl.clearBackground(.white);
rl.drawText(rl.textFormat("Score: %08i", .{score}), 200, 80, 20, rl.Color.red);
rl.drawText(rl.textFormat("Score: %08i", .{score}), 200, 80, 20, .red);
rl.drawText(rl.textFormat("HiScore: %08i", .{hiscore}), 200, 120, 20, rl.Color.green);
rl.drawText(rl.textFormat("HiScore: %08i", .{hiscore}), 200, 120, 20, .green);
rl.drawText(rl.textFormat("Lives: %02i", .{lives}), 200, 160, 40, rl.Color.blue);
rl.drawText(rl.textFormat("Lives: %02i", .{lives}), 200, 160, 40, .blue);
rl.drawText(rl.textFormat("Elapsed Time: %02.02f ms", .{rl.getFrameTime() * 1000}), 200, 220, 20, rl.Color.black);
rl.drawText(rl.textFormat("Elapsed Time: %02.02f ms", .{rl.getFrameTime() * 1000}), 200, 220, 20, .black);
//----------------------------------------------------------------------------------
}
}

126
examples/text/input_box.zig Normal file
View File

@ -0,0 +1,126 @@
//!******************************************************************************************
//!
//! raylib-zig port of the [raylib-zig port of the [text] example - Input Box
//! https://github.com/raysan5/raylib/blob/master/examples/text/text_input_box.c
//!
//! Example complexity rating: [] 2/4
//!
//! Example originally created with raylib 1.7, last time updated with raylib 3.5
//!
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Copyright (c) 2017-2025 Ramon Santamaria (@raysan5)
//!
//!*******************************************************************************************
const rl = @import("raylib");
const max_input_chars = 9;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [text] example - input box");
defer rl.closeWindow();
var name = [_:0]u8{0} ** max_input_chars;
var letter_count: usize = 0;
const text_box = rl.Rectangle{
.x = @as(f32, @floatFromInt(screen_width)) / 2.0 - 100,
.y = 180,
.width = 255,
.height = 50,
};
var mouse_on_text = false;
var framesCounter: usize = 0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
mouse_on_text = rl.checkCollisionPointRec(rl.getMousePosition(), text_box);
if (mouse_on_text) {
// Set the window's cursor to the I-Beam
rl.setMouseCursor(.ibeam);
// Get char pressed (unicode character) on the queue
// Check if more characters have been pressed on the same frame
var key = rl.getKeyPressed();
while (key != .null) : (key = rl.getKeyPressed()) {
// NOTE: Only allow keys in range [32..125]
const keyInt: c_int = @intFromEnum(key);
if ((keyInt >= 32) and (keyInt <= 125) and (letter_count < name.len)) {
name[letter_count] = @intCast(keyInt);
letter_count += 1;
}
}
if (rl.isKeyPressed(.backspace)) {
if (letter_count <= 1) {
letter_count = 0;
} else {
letter_count -= 1;
}
name[letter_count] = 0;
}
} else rl.setMouseCursor(.default);
if (mouse_on_text) {
framesCounter += 1;
} else {
framesCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("PLACE MOUSE OVER INPUT BOX!", 240, 140, 20, .gray);
rl.drawRectangleRec(text_box, .light_gray);
rl.drawRectangleLines(
@intFromFloat(text_box.x),
@intFromFloat(text_box.y),
@intFromFloat(text_box.width),
@intFromFloat(text_box.height),
if (mouse_on_text) .red else .dark_gray,
);
rl.drawText(&name, @intFromFloat(text_box.x + 5), @intFromFloat(text_box.y + 8), 40, .maroon);
rl.drawText(rl.textFormat("INPUT CHARS: %i/%i", .{ letter_count, @as(usize, @intCast(max_input_chars)) }), 315, 250, 20, .dark_gray);
if (mouse_on_text) {
if (letter_count < max_input_chars) {
// Draw blinking underscore char
if (((framesCounter / 20) % 2) == 0) {
rl.drawText("_", @as(i32, @intFromFloat(text_box.x)) + 8 + rl.measureText(&name, 40), @intFromFloat(text_box.y + 12), 40, .maroon);
}
} else {
rl.drawText("Press BACKSPACE to delete chars...", 230, 300, 20, .gray);
}
}
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,89 @@
const rl = @import("raylib");
const Color = rl.Color;
const MAX_FONTS = 8;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() !void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [text] example - raylib fonts");
defer rl.closeWindow(); // Close window and OpenGL context
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
var fonts: [MAX_FONTS]rl.Font = undefined;
fonts[0] = try rl.loadFont("resources/text/fonts/alagard.png");
fonts[1] = try rl.loadFont("resources/text/fonts/pixelplay.png");
fonts[2] = try rl.loadFont("resources/text/fonts/mecha.png");
fonts[3] = try rl.loadFont("resources/text/fonts/setback.png");
fonts[4] = try rl.loadFont("resources/text/fonts/romulus.png");
fonts[5] = try rl.loadFont("resources/text/fonts/pixantiqua.png");
fonts[6] = try rl.loadFont("resources/text/fonts/alpha_beta.png");
fonts[7] = try rl.loadFont("resources/text/fonts/jupiter_crash.png");
// Fonts unloading
defer for (fonts) |font| {
rl.unloadFont(font);
};
const messages = [MAX_FONTS][:0]const u8{
"ALAGARD FONT designed by Hewett Tsoi",
"PIXELPLAY FONT designed by Aleksander Shevchuk",
"MECHA FONT designed by Captain Falcon",
"SETBACK FONT designed by Brian Kent (AEnigma)",
"ROMULUS FONT designed by Hewett Tsoi",
"PIXANTIQUA FONT designed by Gerhard Grossmann",
"ALPHA_BETA FONT designed by Brian Kent (AEnigma)",
"JUPITER_CRASH FONT designed by Brian Kent (AEnigma)",
};
const spacings = [_]i32{ 2, 4, 8, 4, 3, 4, 4, 1 };
var positions: [MAX_FONTS]rl.Vector2 = undefined;
for (0..MAX_FONTS) |i| {
const font_base_size = @as(f32, @floatFromInt(fonts[i].baseSize));
positions[i].x = screenWidth / 2.0 - rl.measureTextEx(fonts[i], messages[i], font_base_size * 2.0, @floatFromInt(spacings[i])).x / 2.0;
positions[i].y = 60.0 + font_base_size + 45.0 * @as(f32, @floatFromInt(i));
}
// Small Y position corrections
positions[3].y += 8;
positions[4].y += 2;
positions[7].y -= 8;
const colors = [MAX_FONTS]Color{ Color.maroon, Color.orange, Color.dark_green, Color.dark_blue, Color.dark_purple, Color.lime, Color.gold, Color.red };
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
rl.clearBackground(Color.white);
rl.drawText("free fonts included with raylib", 250, 20, 20, Color.dark_gray);
rl.drawLine(220, 50, 590, 50, Color.dark_gray);
for (0..MAX_FONTS) |i| {
const font_base_size = @as(f32, @floatFromInt(fonts[i].baseSize));
rl.drawTextEx(fonts[i], messages[i], positions[i], font_base_size * 2.0, @floatFromInt(spacings[i]), colors[i]);
}
rl.endDrawing();
//----------------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,282 @@
//!******************************************************************************************
//!
//! raylib-zig port of the [text] example - Rectangle bounds
//!
//! Example complexity rating: [] 4/4
//!
//! Example originally created with raylib 2.5, last time updated with raylib 4.0
//!
//! Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
//!
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Copyright (c) 2018-2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
//!
//!*******************************************************************************************
const rl = @import("raylib");
const std = @import("std");
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [text] example - draw text inside a rectangle");
defer rl.closeWindow();
const text: [:0]const u8 = "Text cannot escape\tthis container\t...word wrap also works when active so here's a long text for testing.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nec ullamcorper sit amet risus nullam eget felis eget.";
var resizing = false;
var word_wrap = true;
var container = rl.Rectangle{
.x = 25.0,
.y = 25.0,
.width = @floatFromInt(screen_width - 50),
.height = @floatFromInt(screen_height - 250),
};
var resizer = rl.Rectangle{
.x = container.x + container.width - 17,
.y = container.y + container.height - 17,
.width = 14,
.height = 14,
};
// Minimum width and heigh for the container rectangle
const minWidth = 60.0;
const minHeight = 60.0;
const maxWidth = screen_width - 50.0;
const maxHeight = screen_height - 160.0;
var lastMouse = rl.Vector2{ .x = 0.0, .y = 0.0 }; // Stores last mouse coordinates
var border_color = rl.Color.maroon; // Container border color
const font = try rl.getFontDefault(); // Get default system font
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (rl.isKeyPressed(.space)) word_wrap = !word_wrap;
const mouse = rl.getMousePosition();
// Check if the mouse is inside the container and toggle border color
if (rl.checkCollisionPointRec(mouse, container)) {
border_color = rl.fade(.maroon, 0.4);
} else if (!resizing) {
border_color = .maroon;
}
// Container resizing logic
if (resizing) {
if (rl.isMouseButtonReleased(.left)) resizing = false;
const width = container.width + (mouse.x - lastMouse.x);
container.width = if (width > minWidth) if (width < maxWidth) width else maxWidth else minWidth;
const height = container.height + (mouse.y - lastMouse.y);
container.height = if (height > minHeight) if (height < maxHeight) height else maxHeight else minHeight;
} else {
// Check if we're resizing
if (rl.isMouseButtonDown(.left) and rl.checkCollisionPointRec(mouse, resizer)) resizing = true;
}
// Move resizer rectangle properly
resizer.x = container.x + container.width - 17;
resizer.y = container.y + container.height - 17;
lastMouse = mouse; // Update mouse
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawRectangleLinesEx(container, 3, border_color); // Draw container border
// Draw text in container (add some padding)
drawTextBoxed(font, text, .{
.x = container.x + 4,
.y = container.y + 4,
.width = container.width - 4,
.height = container.height - 4,
}, 20.0, 2.0, word_wrap, .gray);
rl.drawRectangleRec(resizer, border_color); // Draw the resize box
// Draw bottom info
rl.drawRectangle(0, screen_height - 54, screen_width, 54, .gray);
rl.drawRectangleRec(.{
.x = 382.0,
.y = screen_height - 34.0,
.width = 12.0,
.height = 12.0,
}, .maroon);
rl.drawText("Word Wrap: ", 313, screen_height - 115, 20, .black);
if (word_wrap) {
rl.drawText("ON", 447, screen_height - 115, 20, .red);
} else {
rl.drawText("OFF", 447, screen_height - 115, 20, .black);
}
rl.drawText("Press [SPACE] to toggle word wrap", 218, screen_height - 86, 20, .gray);
rl.drawText("Click hold & drag the to resize the container", 155, screen_height - 38, 20, .ray_white);
//----------------------------------------------------------------------------------
}
}
//--------------------------------------------------------------------------------------
// Module functions definition
//--------------------------------------------------------------------------------------
// Draw text using font inside rectangle limits
fn drawTextBoxed(font: rl.Font, text: [:0]const u8, rec: rl.Rectangle, font_size: f32, spacing: f32, word_wrap: bool, tint: rl.Color) void {
drawTextBoxedSelectable(font, text, rec, font_size, spacing, word_wrap, tint, 0, 0, .white, .white);
}
// Draw text using font inside rectangle limits with support for text selection
fn drawTextBoxedSelectable(font: rl.Font, text: [:0]const u8, rec: rl.Rectangle, font_size: f32, spacing: f32, word_wrap: bool, tint: rl.Color, select_box_start: i32, select_length: i32, select_tint: rl.Color, select_back_tint: rl.Color) void {
var select_start = select_box_start;
const length = rl.textLength(text); // Total length in bytes of the text, scanned by codepoints in loop
var text_offset_y: f32 = 0; // Offset between lines (on line break '\n')
var text_offset_x: f32 = 0.0; // Offset X to next character to draw
const scale_factor = font_size / @as(f32, @floatFromInt(font.baseSize)); // Character rectangle scaling factor
// Word/character wrapping mechanism variables
const MeasureState = enum(u8) { measure, draw };
var state: MeasureState = if (word_wrap) .measure else .draw;
var start_line: i32 = -1; // Index where to begin drawing (where a line begins)
var end_line: i32 = -1; // Index where to stop drawing (where a line ends)
var last_char: i32 = -1; // Holds last value of the character position
var i: i32 = 0;
var k: i32 = 0;
while (i < length) : ({
i += 1;
k += 1;
}) {
// Get next codepoint from byte string and glyph index in font
var codepoint_byte_count: i32 = 0;
const codepoint = rl.getCodepoint(text[@intCast(i)..], &codepoint_byte_count);
const index: usize = @intCast(rl.getGlyphIndex(font, codepoint));
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepoint_byte_count = 1;
i += @intCast(codepoint_byte_count - 1);
var glyph_width: f32 = 0;
if (codepoint != '\n') {
glyph_width = if (font.glyphs[index].advanceX == 0) font.recs[index].width * scale_factor else @as(f32, @floatFromInt(font.glyphs[index].advanceX)) * scale_factor;
if (i + 1 < length) glyph_width = glyph_width + spacing;
}
// NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container
// We store this info in startLine and endLine, then we change states, draw the text between those two variables
// and change states again and again recursively until the end of the text (or until we get outside of the container).
// When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately
// and begin drawing on the next line before we can get outside the container.
if (state == .measure) {
// TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
// Ref: http://jkorpela.fi/chars/spaces.html
if ((codepoint == ' ') or (codepoint == '\t') or (codepoint == '\n')) end_line = @intCast(i);
if ((text_offset_x + glyph_width) > rec.width) {
end_line = if (end_line < 1) @intCast(i) else end_line;
if (i == end_line) end_line -= codepoint_byte_count;
if ((start_line + codepoint_byte_count) == end_line) end_line = @as(i32, @intCast(i)) - codepoint_byte_count;
state = if (state == .draw) .measure else .draw;
} else if ((i + 1) == length) {
end_line = @intCast(i);
state = if (state == .draw) .measure else .draw;
} else if (codepoint == '\n') {
state = if (state == .draw) .measure else .draw;
}
if (state == .draw) {
text_offset_x = 0;
i = @intCast(start_line);
glyph_width = 0;
// Save character position when we switch states
const tmp = last_char;
last_char = k - 1;
k = tmp;
}
} else {
if (codepoint == '\n') {
if (!word_wrap) {
const bS: f32 = @floatFromInt(font.baseSize);
text_offset_y += (bS + bS / 2) * scale_factor;
text_offset_x = 0;
}
} else {
if (!word_wrap and ((text_offset_x + glyph_width) > rec.width)) {
const bS: f32 = @floatFromInt(font.baseSize);
text_offset_y += (bS + bS / 2) * scale_factor;
text_offset_x = 0;
}
// When text overflows rectangle height limit, just stop drawing
if ((text_offset_y + @as(f32, @floatFromInt(font.baseSize)) * scale_factor) > rec.height) break;
// Draw selection background
var is_glyph_selected = false;
if ((select_start >= 0) and (k >= select_start) and (k < (select_start + select_length))) {
rl.drawRectangleRec(.{
.x = rec.x + text_offset_x - 1,
.y = rec.y + text_offset_y,
.width = glyph_width,
.height = @as(f32, @floatFromInt(font.baseSize)) * scale_factor,
}, select_back_tint);
is_glyph_selected = true;
}
// Draw current character glyph
if ((codepoint != ' ') and (codepoint != '\t')) {
rl.drawTextCodepoint(font, codepoint, .{
.x = rec.x + text_offset_x,
.y = rec.y + text_offset_y,
}, font_size, if (is_glyph_selected) select_tint else tint);
}
}
if (word_wrap and (i == end_line)) {
const bS: f32 = @floatFromInt(font.baseSize);
text_offset_y += (bS + bS / 2) * scale_factor;
text_offset_x = 0;
start_line = end_line;
end_line = -1;
glyph_width = 0;
select_start += last_char - k;
k = last_char;
state = if (state == .draw) .measure else .draw;
}
}
if ((text_offset_x != 0) or (codepoint != ' ')) text_offset_x += glyph_width; // avoid leading spaces
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,20 @@
| resource | author | licence | notes |
| :----------------------------- | :---------: | :------ | :---- |
| fonts/alagard.png | Hewett Tsoi | [Freeware](https://www.dafont.com/es/alagard.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
| fonts/romulus.png | Hewett Tsoi | [Freeware](https://www.dafont.com/es/romulus.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
| 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) |
| 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) |
| 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) |
| fonts/mecha.png | Captain Falcon | [Freeware](https://www.dafont.com/es/mecha-cf.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
| fonts/pixelplay.png | Aleksander Shevchuk | [Freeware](https://www.dafont.com/es/pixelplay.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
| fonts/pixantiqua.ttf | Gerhard Großmann | [Freeware](https://www.dafont.com/es/pixantiqua.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
| 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) | - |
| 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) |
| 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) |
| 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) |
| 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) |
| 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 |
| 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) |
| 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) |
| pixantiqua.ttf | Gerhard Großmann | [Freeware](https://www.dafont.com/es/pixantiqua.font) | - |
| 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) |

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

View File

@ -0,0 +1,580 @@
info face="Noto Serif CJK JP" size=-16 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=2,2 outline=1
common lineHeight=23 base=18 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4
page id=0 file="noto_cjk.png"
chars count=576
char id=32 x=507 y=185 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=15
char id=33 x=449 y=285 width=5 height=14 xoffset=0 yoffset=5 xadvance=5 page=0 chnl=15
char id=34 x=393 y=315 width=8 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
char id=35 x=285 y=287 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=36 x=500 y=61 width=10 height=18 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=37 x=52 y=257 width=15 height=15 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15
char id=38 x=495 y=268 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=39 x=413 y=315 width=5 height=8 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=15
char id=40 x=339 y=21 width=7 height=19 xoffset=0 yoffset=4 xadvance=6 page=0 chnl=15
char id=41 x=330 y=21 width=7 height=19 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
char id=42 x=321 y=317 width=10 height=9 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=15
char id=43 x=26 y=322 width=11 height=11 xoffset=-1 yoffset=7 xadvance=9 page=0 chnl=15
char id=44 x=353 y=316 width=6 height=9 xoffset=-1 yoffset=15 xadvance=5 page=0 chnl=15
char id=45 x=136 y=334 width=7 height=4 xoffset=-1 yoffset=12 xadvance=5 page=0 chnl=15
char id=46 x=109 y=334 width=5 height=5 xoffset=0 yoffset=14 xadvance=5 page=0 chnl=15
char id=47 x=500 y=81 width=8 height=18 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
char id=48 x=406 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=49 x=418 y=286 width=9 height=14 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=15
char id=50 x=394 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=51 x=382 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=52 x=272 y=287 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=53 x=370 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=54 x=358 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=55 x=346 y=286 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=56 x=334 y=287 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=57 x=322 y=287 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=58 x=502 y=300 width=5 height=11 xoffset=0 yoffset=8 xadvance=5 page=0 chnl=15
char id=59 x=190 y=238 width=6 height=16 xoffset=-1 yoffset=8 xadvance=5 page=0 chnl=15
char id=60 x=39 y=322 width=11 height=11 xoffset=-1 yoffset=7 xadvance=9 page=0 chnl=15
char id=61 x=440 y=315 width=11 height=7 xoffset=-1 yoffset=9 xadvance=9 page=0 chnl=15
char id=62 x=78 y=321 width=11 height=11 xoffset=-1 yoffset=7 xadvance=9 page=0 chnl=15
char id=63 x=460 y=252 width=7 height=15 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
char id=64 x=72 y=221 width=16 height=16 xoffset=-1 yoffset=6 xadvance=14 page=0 chnl=15
char id=65 x=447 y=269 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=66 x=175 y=289 width=12 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15
char id=67 x=75 y=290 width=13 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15
char id=68 x=415 y=270 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=69 x=119 y=290 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15
char id=70 x=105 y=290 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15
char id=71 x=431 y=269 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=72 x=302 y=271 width=15 height=14 xoffset=-1 yoffset=5 xadvance=14 page=0 chnl=15
char id=73 x=439 y=285 width=8 height=14 xoffset=-1 yoffset=5 xadvance=6 page=0 chnl=15
char id=74 x=268 y=200 width=9 height=17 xoffset=-2 yoffset=5 xadvance=6 page=0 chnl=15
char id=75 x=367 y=270 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=76 x=203 y=289 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15
char id=77 x=158 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15
char id=78 x=285 y=271 width=15 height=14 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15
char id=79 x=479 y=269 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=80 x=189 y=289 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15
char id=81 x=209 y=142 width=14 height=18 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=82 x=30 y=291 width=13 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15
char id=83 x=259 y=287 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=84 x=45 y=291 width=13 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15
char id=85 x=335 y=270 width=14 height=14 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15
char id=86 x=399 y=270 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=87 x=485 y=252 width=19 height=14 xoffset=-1 yoffset=5 xadvance=17 page=0 chnl=15
char id=88 x=0 y=291 width=13 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15
char id=89 x=15 y=291 width=13 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15
char id=90 x=217 y=287 width=12 height=14 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=15
char id=91 x=8 y=164 width=6 height=18 xoffset=0 yoffset=4 xadvance=5 page=0 chnl=15
char id=92 x=497 y=141 width=8 height=18 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
char id=93 x=0 y=164 width=6 height=18 xoffset=-1 yoffset=4 xadvance=5 page=0 chnl=15
char id=94 x=465 y=313 width=9 height=7 xoffset=0 yoffset=8 xadvance=9 page=0 chnl=15
char id=95 x=145 y=334 width=11 height=3 xoffset=-1 yoffset=17 xadvance=9 page=0 chnl=15
char id=96 x=74 y=335 width=6 height=6 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
char id=97 x=13 y=322 width=11 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15
char id=98 x=398 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=99 x=129 y=321 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=15
char id=100 x=426 y=217 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=101 x=117 y=321 width=10 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15
char id=102 x=140 y=238 width=10 height=16 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=15
char id=103 x=52 y=239 width=11 height=16 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15
char id=104 x=440 y=217 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=105 x=469 y=252 width=7 height=15 xoffset=-1 yoffset=4 xadvance=5 page=0 chnl=15
char id=106 x=95 y=0 width=8 height=20 xoffset=-3 yoffset=4 xadvance=5 page=0 chnl=15
char id=107 x=412 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=108 x=451 y=252 width=7 height=15 xoffset=-1 yoffset=4 xadvance=5 page=0 chnl=15
char id=109 x=386 y=302 width=18 height=11 xoffset=-1 yoffset=8 xadvance=16 page=0 chnl=15
char id=110 x=488 y=300 width=12 height=11 xoffset=-1 yoffset=8 xadvance=11 page=0 chnl=15
char id=111 x=91 y=321 width=11 height=11 xoffset=-1 yoffset=8 xadvance=10 page=0 chnl=15
char id=112 x=300 y=218 width=12 height=16 xoffset=-1 yoffset=8 xadvance=10 page=0 chnl=15
char id=113 x=286 y=219 width=12 height=16 xoffset=-1 yoffset=8 xadvance=10 page=0 chnl=15
char id=114 x=141 y=321 width=10 height=11 xoffset=-1 yoffset=8 xadvance=7 page=0 chnl=15
char id=115 x=165 y=320 width=9 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=15
char id=116 x=429 y=286 width=8 height=14 xoffset=-1 yoffset=5 xadvance=6 page=0 chnl=15
char id=117 x=474 y=300 width=12 height=11 xoffset=-1 yoffset=8 xadvance=10 page=0 chnl=15
char id=118 x=0 y=322 width=11 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15
char id=119 x=424 y=302 width=16 height=11 xoffset=-1 yoffset=8 xadvance=13 page=0 chnl=15
char id=120 x=104 y=321 width=11 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=15
char id=121 x=342 y=218 width=12 height=16 xoffset=-2 yoffset=8 xadvance=9 page=0 chnl=15
char id=122 x=153 y=320 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=15
char id=123 x=467 y=141 width=8 height=18 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
char id=124 x=111 y=0 width=4 height=20 xoffset=0 yoffset=4 xadvance=4 page=0 chnl=15
char id=125 x=457 y=141 width=8 height=18 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
char id=126 x=27 y=335 width=11 height=6 xoffset=-1 yoffset=9 xadvance=9 page=0 chnl=15
char id=160 x=507 y=180 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=15
char id=161 x=478 y=252 width=5 height=15 xoffset=0 yoffset=8 xadvance=5 page=0 chnl=15
char id=162 x=430 y=252 width=10 height=15 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=163 x=310 y=287 width=10 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=15
char id=164 x=52 y=322 width=11 height=11 xoffset=-1 yoffset=7 xadvance=9 page=0 chnl=15
char id=165 x=201 y=305 width=12 height=13 xoffset=-2 yoffset=6 xadvance=9 page=0 chnl=15
char id=166 x=105 y=0 width=4 height=20 xoffset=0 yoffset=4 xadvance=4 page=0 chnl=15
char id=167 x=244 y=200 width=10 height=17 xoffset=3 yoffset=4 xadvance=16 page=0 chnl=15
char id=168 x=116 y=334 width=9 height=4 xoffset=-1 yoffset=5 xadvance=7 page=0 chnl=15
char id=169 x=251 y=271 width=15 height=14 xoffset=-1 yoffset=5 xadvance=13 page=0 chnl=15
char id=170 x=383 y=316 width=8 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
char id=171 x=248 y=317 width=10 height=10 xoffset=-1 yoffset=9 xadvance=8 page=0 chnl=15
char id=172 x=427 y=315 width=11 height=7 xoffset=-1 yoffset=10 xadvance=9 page=0 chnl=15
char id=173 x=127 y=334 width=7 height=4 xoffset=-1 yoffset=12 xadvance=5 page=0 chnl=15
char id=174 x=236 y=317 width=10 height=10 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=15
char id=175 x=158 y=333 width=7 height=3 xoffset=0 yoffset=6 xadvance=7 page=0 chnl=15
char id=176 x=486 y=313 width=7 height=7 xoffset=-1 yoffset=5 xadvance=6 page=0 chnl=15
char id=177 x=154 y=256 width=15 height=15 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=178 x=270 y=317 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
char id=179 x=260 y=317 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
char id=180 x=58 y=335 width=6 height=6 xoffset=1 yoffset=4 xadvance=7 page=0 chnl=15
char id=181 x=26 y=240 width=11 height=16 xoffset=0 yoffset=7 xadvance=10 page=0 chnl=15
char id=182 x=216 y=200 width=12 height=17 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15
char id=183 x=102 y=334 width=5 height=5 xoffset=0 yoffset=10 xadvance=5 page=0 chnl=15
char id=184 x=504 y=313 width=6 height=7 xoffset=0 yoffset=16 xadvance=7 page=0 chnl=15
char id=185 x=280 y=317 width=7 height=10 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15
char id=186 x=403 y=315 width=8 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
char id=187 x=224 y=320 width=10 height=10 xoffset=-1 yoffset=9 xadvance=8 page=0 chnl=15
char id=188 x=137 y=256 width=15 height=15 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15
char id=189 x=375 y=236 width=16 height=15 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15
char id=190 x=120 y=256 width=15 height=15 xoffset=0 yoffset=5 xadvance=15 page=0 chnl=15
char id=191 x=442 y=252 width=7 height=15 xoffset=0 yoffset=8 xadvance=7 page=0 chnl=15
char id=192 x=273 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15
char id=193 x=353 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15
char id=194 x=48 y=202 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15
char id=195 x=337 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15
char id=196 x=0 y=203 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15
char id=197 x=225 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15
char id=198 x=20 y=275 width=18 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15
char id=199 x=400 y=141 width=13 height=18 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15
char id=200 x=443 y=141 width=12 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15
char id=201 x=498 y=101 width=12 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15
char id=202 x=429 y=141 width=12 height=18 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=15
char id=203 x=202 y=200 width=12 height=17 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=15
char id=204 x=502 y=121 width=8 height=18 xoffset=-1 yoffset=1 xadvance=6 page=0 chnl=15
char id=205 x=477 y=141 width=8 height=18 xoffset=-1 yoffset=1 xadvance=6 page=0 chnl=15
char id=206 x=487 y=141 width=8 height=18 xoffset=-1 yoffset=1 xadvance=6 page=0 chnl=15
char id=207 x=279 y=200 width=8 height=17 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
char id=208 x=319 y=271 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=15
char id=209 x=142 y=143 width=15 height=18 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15
char id=210 x=305 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15
char id=211 x=369 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15
char id=212 x=491 y=180 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15
char id=213 x=475 y=180 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15
char id=214 x=96 y=201 width=14 height=17 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15
char id=215 x=173 y=305 width=12 height=13 xoffset=2 yoffset=6 xadvance=16 page=0 chnl=15
char id=216 x=209 y=219 width=14 height=16 xoffset=-1 yoffset=4 xadvance=12 page=0 chnl=15
char id=217 x=241 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15
char id=218 x=257 y=142 width=14 height=18 xoffset=-1 yoffset=1 xadvance=13 page=0 chnl=15
char id=219 x=64 y=202 width=14 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15
char id=220 x=16 y=203 width=14 height=17 xoffset=-1 yoffset=2 xadvance=13 page=0 chnl=15
char id=221 x=385 y=141 width=13 height=18 xoffset=-1 yoffset=1 xadvance=11 page=0 chnl=15
char id=222 x=231 y=287 width=12 height=14 xoffset=-1 yoffset=5 xadvance=11 page=0 chnl=15
char id=223 x=299 y=254 width=12 height=15 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15
char id=224 x=13 y=240 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=225 x=0 y=240 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=226 x=493 y=217 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=227 x=367 y=253 width=11 height=15 xoffset=-1 yoffset=4 xadvance=9 page=0 chnl=15
char id=228 x=341 y=253 width=11 height=15 xoffset=-1 yoffset=4 xadvance=9 page=0 chnl=15
char id=229 x=480 y=217 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=230 x=442 y=301 width=15 height=11 xoffset=-1 yoffset=8 xadvance=14 page=0 chnl=15
char id=231 x=406 y=253 width=10 height=15 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=15
char id=232 x=116 y=238 width=10 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=233 x=128 y=238 width=10 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=234 x=104 y=239 width=10 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=235 x=418 y=253 width=10 height=15 xoffset=-1 yoffset=4 xadvance=9 page=0 chnl=15
char id=236 x=172 y=238 width=7 height=16 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=15
char id=237 x=181 y=238 width=7 height=16 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=15
char id=238 x=163 y=238 width=7 height=16 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=15
char id=239 x=501 y=235 width=9 height=15 xoffset=-2 yoffset=4 xadvance=5 page=0 chnl=15
char id=240 x=454 y=217 width=11 height=16 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=15
char id=241 x=327 y=253 width=12 height=15 xoffset=-1 yoffset=4 xadvance=11 page=0 chnl=15
char id=242 x=91 y=239 width=11 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=243 x=78 y=239 width=11 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=244 x=65 y=239 width=11 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=245 x=393 y=253 width=11 height=15 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15
char id=246 x=380 y=253 width=11 height=15 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15
char id=247 x=233 y=271 width=16 height=14 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=248 x=215 y=305 width=11 height=13 xoffset=-1 yoffset=7 xadvance=10 page=0 chnl=15
char id=249 x=384 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=250 x=356 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=251 x=314 y=218 width=12 height=16 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=252 x=313 y=254 width=12 height=15 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15
char id=253 x=0 y=0 width=12 height=21 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=15
char id=254 x=14 y=0 width=11 height=21 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=15
char id=255 x=81 y=0 width=12 height=20 xoffset=-2 yoffset=4 xadvance=9 page=0 chnl=15
char id=8220 x=361 y=316 width=9 height=8 xoffset=-1 yoffset=4 xadvance=7 page=0 chnl=15
char id=8222 x=372 y=316 width=9 height=8 xoffset=-1 yoffset=14 xadvance=7 page=0 chnl=15
char id=9829 x=18 y=222 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12288 x=507 y=141 width=3 height=3 xoffset=-1 yoffset=-1 xadvance=16 page=0 chnl=15
char id=12290 x=476 y=313 width=8 height=7 xoffset=-1 yoffset=14 xadvance=16 page=0 chnl=15
char id=12353 x=147 y=289 width=12 height=14 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15
char id=12354 x=73 y=183 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12355 x=459 y=300 width=13 height=11 xoffset=1 yoffset=9 xadvance=16 page=0 chnl=15
char id=12356 x=483 y=235 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12357 x=298 y=287 width=10 height=14 xoffset=3 yoffset=7 xadvance=16 page=0 chnl=15
char id=12358 x=415 y=141 width=12 height=18 xoffset=2 yoffset=3 xadvance=16 page=0 chnl=15
char id=12359 x=187 y=305 width=12 height=13 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15
char id=12360 x=409 y=180 width=15 height=17 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12361 x=53 y=307 width=14 height=13 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=15
char id=12362 x=108 y=220 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12363 x=271 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12364 x=0 y=184 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12365 x=32 y=202 width=14 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12366 x=72 y=143 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12367 x=152 y=238 width=9 height=16 xoffset=3 yoffset=4 xadvance=16 page=0 chnl=15
char id=12368 x=256 y=219 width=13 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15
char id=12369 x=375 y=181 width=15 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12370 x=340 y=122 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12371 x=284 y=254 width=13 height=15 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15
char id=12372 x=426 y=180 width=15 height=17 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12373 x=142 y=201 width=13 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12374 x=57 y=123 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12375 x=443 y=180 width=14 height=17 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15
char id=12376 x=112 y=201 width=13 height=17 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15
char id=12377 x=235 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12378 x=209 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12379 x=309 y=200 width=18 height=16 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12380 x=137 y=163 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12381 x=358 y=181 width=15 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12382 x=396 y=161 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12383 x=217 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12384 x=277 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12385 x=324 y=181 width=15 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12386 x=430 y=121 width=16 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12387 x=195 y=320 width=13 height=10 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=15
char id=12388 x=267 y=303 width=17 height=12 xoffset=-1 yoffset=7 xadvance=16 page=0 chnl=15
char id=12389 x=218 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12390 x=411 y=236 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12391 x=338 y=236 width=17 height=15 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12392 x=370 y=218 width=12 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15
char id=12393 x=392 y=181 width=15 height=17 xoffset=2 yoffset=3 xadvance=16 page=0 chnl=15
char id=12394 x=477 y=199 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12395 x=160 y=220 width=15 height=16 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12396 x=447 y=235 width=16 height=15 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12397 x=491 y=161 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12398 x=465 y=235 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12399 x=36 y=221 width=16 height=16 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12400 x=479 y=101 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12401 x=247 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12402 x=495 y=199 width=15 height=16 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12403 x=36 y=144 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12404 x=253 y=181 width=16 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12405 x=348 y=200 width=17 height=16 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12406 x=289 y=200 width=18 height=16 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12407 x=386 y=200 width=17 height=16 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12408 x=228 y=303 width=18 height=12 xoffset=-1 yoffset=7 xadvance=16 page=0 chnl=15
char id=12409 x=139 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12410 x=456 y=285 width=17 height=13 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=15
char id=12411 x=55 y=183 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12412 x=171 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12413 x=95 y=123 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12414 x=193 y=219 width=14 height=16 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12415 x=405 y=200 width=16 height=16 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12416 x=367 y=200 width=17 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12417 x=90 y=221 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12418 x=328 y=218 width=12 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15
char id=12419 x=383 y=270 width=14 height=14 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15
char id=12420 x=472 y=161 width=17 height=17 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12421 x=159 y=305 width=12 height=13 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15
char id=12422 x=109 y=182 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12423 x=348 y=302 width=11 height=12 xoffset=3 yoffset=8 xadvance=16 page=0 chnl=15
char id=12424 x=241 y=219 width=13 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15
char id=12425 x=127 y=201 width=13 height=17 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15
char id=12426 x=500 y=41 width=10 height=18 xoffset=3 yoffset=3 xadvance=16 page=0 chnl=15
char id=12427 x=188 y=256 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12428 x=177 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12429 x=177 y=220 width=14 height=16 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12430 x=351 y=270 width=14 height=14 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15
char id=12431 x=163 y=182 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12432 x=393 y=236 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12433 x=181 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12434 x=143 y=220 width=15 height=16 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12435 x=54 y=221 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12436 x=289 y=142 width=14 height=18 xoffset=2 yoffset=3 xadvance=16 page=0 chnl=15
char id=12437 x=463 y=269 width=14 height=14 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15
char id=12438 x=101 y=306 width=13 height=13 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15
char id=12441 x=40 y=335 width=7 height=6 xoffset=-6 yoffset=3 xadvance=0 page=0 chnl=15
char id=12442 x=49 y=335 width=7 height=6 xoffset=-5 yoffset=3 xadvance=0 page=0 chnl=15
char id=12443 x=495 y=313 width=7 height=7 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12444 x=0 y=335 width=7 height=7 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12445 x=333 y=317 width=8 height=9 xoffset=4 yoffset=8 xadvance=16 page=0 chnl=15
char id=12446 x=65 y=322 width=11 height=11 xoffset=4 yoffset=6 xadvance=16 page=0 chnl=15
char id=12447 x=193 y=142 width=14 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12448 x=453 y=314 width=10 height=7 xoffset=3 yoffset=9 xadvance=16 page=0 chnl=15
char id=12449 x=334 y=303 width=12 height=12 xoffset=2 yoffset=9 xadvance=16 page=0 chnl=15
char id=12450 x=126 y=220 width=15 height=16 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12451 x=374 y=302 width=10 height=12 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15
char id=12452 x=157 y=201 width=13 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12453 x=161 y=289 width=12 height=14 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15
char id=12454 x=459 y=180 width=14 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12455 x=289 y=317 width=14 height=9 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=15
char id=12456 x=494 y=285 width=16 height=13 xoffset=0 yoffset=6 xadvance=16 page=0 chnl=15
char id=12457 x=116 y=306 width=13 height=13 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15
char id=12458 x=459 y=199 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12459 x=307 y=181 width=15 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12460 x=453 y=161 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12461 x=289 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12462 x=285 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12463 x=80 y=202 width=14 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12464 x=448 y=121 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12465 x=0 y=222 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12466 x=19 y=124 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12467 x=304 y=303 width=14 height=12 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=15
char id=12468 x=429 y=235 width=16 height=15 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12469 x=199 y=181 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12470 x=160 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12471 x=103 y=257 width=15 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12472 x=341 y=181 width=15 height=17 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12473 x=69 y=257 width=15 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12474 x=145 y=182 width=16 height=17 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12475 x=86 y=257 width=15 height=15 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12476 x=278 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12477 x=204 y=254 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12478 x=322 y=122 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12479 x=321 y=142 width=14 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12480 x=38 y=124 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12481 x=127 y=182 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12482 x=434 y=161 width=17 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12483 x=320 y=303 width=12 height=12 xoffset=2 yoffset=9 xadvance=16 page=0 chnl=15
char id=12484 x=252 y=254 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12485 x=266 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12486 x=441 y=199 width=16 height=16 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12487 x=228 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12488 x=256 y=200 width=10 height=17 xoffset=4 yoffset=4 xadvance=16 page=0 chnl=15
char id=12489 x=230 y=200 width=12 height=17 xoffset=3 yoffset=4 xadvance=16 page=0 chnl=15
char id=12490 x=91 y=182 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12491 x=406 y=302 width=16 height=11 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=15
char id=12492 x=35 y=258 width=15 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12493 x=484 y=121 width=16 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12494 x=90 y=290 width=13 height=14 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=15
char id=12495 x=176 y=320 width=17 height=10 xoffset=-1 yoffset=8 xadvance=16 page=0 chnl=15
char id=12496 x=196 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12497 x=177 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12498 x=60 y=290 width=13 height=14 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15
char id=12499 x=171 y=256 width=15 height=15 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12500 x=0 y=258 width=16 height=15 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=12501 x=236 y=254 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12502 x=18 y=144 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12503 x=90 y=143 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12504 x=248 y=303 width=17 height=12 xoffset=-1 yoffset=7 xadvance=16 page=0 chnl=15
char id=12505 x=120 y=273 width=17 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12506 x=475 y=285 width=17 height=13 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=15
char id=12507 x=357 y=236 width=16 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12508 x=415 y=161 width=17 height=17 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12509 x=37 y=183 width=16 height=17 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12510 x=286 y=303 width=16 height=12 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=15
char id=12511 x=354 y=253 width=11 height=15 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15
char id=12512 x=18 y=258 width=15 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12513 x=268 y=254 width=14 height=15 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12514 x=215 y=271 width=16 height=14 xoffset=0 yoffset=5 xadvance=16 page=0 chnl=15
char id=12515 x=131 y=306 width=12 height=13 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15
char id=12516 x=423 y=199 width=16 height=16 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12517 x=305 y=317 width=14 height=9 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=15
char id=12518 x=0 y=307 width=16 height=13 xoffset=0 yoffset=6 xadvance=16 page=0 chnl=15
char id=12519 x=210 y=320 width=12 height=10 xoffset=2 yoffset=9 xadvance=16 page=0 chnl=15
char id=12520 x=85 y=306 width=14 height=13 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=15
char id=12521 x=225 y=219 width=14 height=16 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12522 x=39 y=239 width=11 height=16 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15
char id=12523 x=0 y=275 width=18 height=14 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=15
char id=12524 x=36 y=307 width=15 height=13 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=15
char id=12525 x=69 y=306 width=14 height=13 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=15
char id=12526 x=145 y=305 width=12 height=13 xoffset=2 yoffset=8 xadvance=16 page=0 chnl=15
char id=12527 x=220 y=254 width=14 height=15 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12528 x=19 y=183 width=16 height=17 xoffset=0 yoffset=4 xadvance=16 page=0 chnl=15
char id=12529 x=18 y=307 width=16 height=13 xoffset=0 yoffset=6 xadvance=16 page=0 chnl=15
char id=12530 x=271 y=219 width=13 height=16 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=15
char id=12531 x=268 y=271 width=15 height=14 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=15
char id=12532 x=304 y=122 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12533 x=133 y=289 width=12 height=14 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15
char id=12534 x=245 y=287 width=12 height=14 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=15
char id=12535 x=190 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12536 x=140 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12537 x=329 y=200 width=17 height=16 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=12538 x=54 y=144 width=16 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=12539 x=66 y=335 width=6 height=6 xoffset=5 yoffset=10 xadvance=16 page=0 chnl=15
char id=12540 x=9 y=335 width=16 height=6 xoffset=0 yoffset=10 xadvance=16 page=0 chnl=15
char id=12541 x=343 y=317 width=8 height=9 xoffset=4 yoffset=8 xadvance=16 page=0 chnl=15
char id=12542 x=361 y=302 width=11 height=12 xoffset=4 yoffset=5 xadvance=16 page=0 chnl=15
char id=12543 x=172 y=201 width=13 height=17 xoffset=1 yoffset=4 xadvance=16 page=0 chnl=15
char id=19968 x=82 y=334 width=18 height=5 xoffset=-1 yoffset=8 xadvance=16 page=0 chnl=15
char id=19975 x=217 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=16 page=0 chnl=15
char id=19979 x=120 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=19981 x=100 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20037 x=80 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20096 x=60 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20102 x=394 y=121 width=16 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=20107 x=40 y=103 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20108 x=60 y=274 width=18 height=14 xoffset=-1 yoffset=5 xadvance=16 page=0 chnl=15
char id=20154 x=20 y=104 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20260 x=0 y=104 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20307 x=480 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20316 x=320 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20320 x=340 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20663 x=320 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20814 x=120 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20837 x=80 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20853 x=60 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20891 x=40 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=20986 x=0 y=144 width=16 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=20999 x=480 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=21040 x=460 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=21147 x=133 y=123 width=17 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=21151 x=440 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=21315 x=420 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=21507 x=377 y=162 width=17 height=17 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=21527 x=152 y=122 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=21534 x=400 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=21705 x=380 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=22622 x=360 y=41 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=22825 x=340 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=22833 x=260 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=22836 x=220 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=22909 x=160 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=23376 x=140 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=23398 x=120 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=23544 x=80 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=23558 x=60 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=24120 x=40 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=24180 x=117 y=0 width=18 height=19 xoffset=-1 yoffset=2 xadvance=16 page=0 chnl=15
char id=24320 x=20 y=44 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=24433 x=0 y=44 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=24471 x=469 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=24515 x=16 y=164 width=19 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=24605 x=197 y=162 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=24651 x=357 y=162 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=25105 x=449 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=26080 x=409 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=26082 x=369 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=26085 x=187 y=200 width=13 height=17 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15
char id=26131 x=457 y=0 width=17 height=19 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=26178 x=0 y=124 width=17 height=18 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=15
char id=26368 x=440 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=26377 x=420 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=26408 x=400 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=26543 x=380 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=27493 x=360 y=101 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=27515 x=340 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=27714 x=320 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=27835 x=300 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=27963 x=280 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=28937 x=260 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=29483 x=240 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=29503 x=220 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=29627 x=200 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=29702 x=157 y=163 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=29827 x=180 y=102 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=30002 x=159 y=142 width=15 height=18 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=15
char id=30045 x=460 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=30693 x=440 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=31119 x=420 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=31169 x=348 y=21 width=19 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=31348 x=400 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=32299 x=380 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=32368 x=360 y=81 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=32705 x=340 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=32769 x=257 y=162 width=18 height=17 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=32773 x=300 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=32780 x=280 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=32988 x=260 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=32993 x=240 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=33021 x=220 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=33853 x=200 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=34382 x=180 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=34678 x=160 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=34892 x=140 y=82 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=35265 x=120 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=35328 x=100 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=36208 x=80 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=36335 x=60 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=36523 x=40 y=83 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=36817 x=20 y=84 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=36820 x=0 y=84 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=36861 x=480 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=36941 x=460 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=36965 x=440 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=37326 x=420 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=38590 x=400 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=38750 x=380 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=39034 x=360 y=61 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=39118 x=300 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=39135 x=280 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=39340 x=260 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=39532 x=240 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=39543 x=220 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=40575 x=200 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=40614 x=180 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=16 page=0 chnl=15
char id=44040 x=160 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=44049 x=357 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=44057 x=140 y=62 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=44060 x=19 y=23 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=44163 x=145 y=21 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=44221 x=412 y=121 width=16 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=44256 x=238 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=44397 x=237 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=44536 x=80 y=274 width=18 height=14 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15
char id=44544 x=100 y=63 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=44592 x=282 y=21 width=14 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=45033 x=466 y=121 width=16 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=45149 x=237 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=45208 x=437 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=45209 x=0 y=23 width=17 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=45212 x=20 y=64 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=45216 x=0 y=64 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=45320 x=198 y=21 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=45328 x=176 y=142 width=15 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=45397 x=495 y=0 width=15 height=19 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15
char id=45576 x=297 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=45716 x=317 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=45720 x=337 y=162 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=45768 x=266 y=21 width=14 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=45796 x=27 y=0 width=18 height=20 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15
char id=46020 x=40 y=275 width=18 height=14 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15
char id=46024 x=117 y=163 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=46160 x=320 y=42 width=18 height=18 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=46301 x=300 y=42 width=18 height=18 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=46384 x=257 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=46972 x=197 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=46976 x=280 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=47000 x=163 y=21 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=47196 x=258 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=47336 x=240 y=42 width=18 height=18 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=47476 x=298 y=237 width=18 height=15 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=47484 x=97 y=163 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=47532 x=65 y=0 width=14 height=20 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15
char id=47560 x=277 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=47564 x=200 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=47568 x=180 y=42 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=47588 x=127 y=21 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=47673 x=181 y=21 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=47784 x=318 y=236 width=18 height=15 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=48148 x=297 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=48152 x=317 y=0 width=18 height=19 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15
char id=48373 x=217 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=49373 x=376 y=121 width=16 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=49436 x=73 y=22 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=49464 x=55 y=22 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=49688 x=377 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=49845 x=397 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=49884 x=125 y=143 width=15 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=49892 x=358 y=122 width=16 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=50420 x=100 y=43 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=50500 x=417 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=50504 x=114 y=123 width=17 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=50506 x=460 y=101 width=17 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=50508 x=76 y=123 width=17 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=50612 x=215 y=21 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=50631 x=249 y=21 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=50640 x=47 y=0 width=16 height=20 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15
char id=50728 x=77 y=163 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=50836 x=198 y=237 width=18 height=15 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15
char id=50857 x=57 y=164 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=50948 x=37 y=22 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=50976 x=489 y=21 width=18 height=18 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=51012 x=37 y=164 width=18 height=17 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15
char id=51060 x=298 y=21 width=14 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=51080 x=91 y=22 width=16 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=51088 x=337 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=51228 x=109 y=22 width=16 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=51460 x=429 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=51648 x=232 y=21 width=15 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=51652 x=108 y=143 width=15 height=18 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=52380 x=476 y=0 width=17 height=19 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15
char id=52840 x=314 y=21 width=14 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=15
char id=54032 x=389 y=21 width=18 height=18 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=54532 x=100 y=274 width=18 height=14 xoffset=-1 yoffset=5 xadvance=15 page=0 chnl=15
char id=54616 x=177 y=0 width=18 height=19 xoffset=-1 yoffset=3 xadvance=15 page=0 chnl=15
char id=54620 x=157 y=0 width=18 height=19 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15
char id=54988 x=137 y=0 width=18 height=19 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=15
char id=65292 x=420 y=315 width=5 height=8 xoffset=0 yoffset=15 xadvance=16 page=0 chnl=15
char id=65311 x=467 y=217 width=11 height=16 xoffset=2 yoffset=4 xadvance=16 page=0 chnl=15

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@ -0,0 +1,188 @@
info face="PixAntiqua" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=2,2,2,2 spacing=2,2 outline=0
common lineHeight=32 base=27 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4
page id=0 file="pixantiqua.png"
chars count=184
char id=32 x=9 y=304 width=7 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=33 x=391 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=34 x=240 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=35 x=468 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=36 x=152 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=37 x=176 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=38 x=303 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=39 x=495 y=266 width=8 height=36 xoffset=-3 yoffset=-2 xadvance=5 page=0 chnl=15
char id=40 x=256 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=199 x=432 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=200 x=126 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=201 x=147 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=202 x=288 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=203 x=189 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=204 x=468 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=205 x=486 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=206 x=0 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=207 x=72 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=208 x=329 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=209 x=277 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=210 x=182 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=211 x=26 y=76 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=41 x=272 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=42 x=288 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=43 x=414 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=44 x=378 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=45 x=414 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=46 x=443 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=47 x=392 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=48 x=485 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=49 x=450 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=50 x=21 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=51 x=42 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=59 x=456 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=60 x=168 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=61 x=309 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=62 x=336 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=63 x=315 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=64 x=364 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=65 x=390 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=66 x=120 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=67 x=144 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=68 x=168 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=69 x=294 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=52 x=488 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=53 x=63 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=54 x=24 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=55 x=48 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=56 x=72 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=57 x=96 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=58 x=404 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=70 x=252 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=71 x=192 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=72 x=78 y=76 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=78 x=78 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=79 x=355 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=80 x=264 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=81 x=381 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=82 x=288 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=83 x=312 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=91 x=144 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=92 x=108 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=93 x=304 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=94 x=34 y=0 width=32 height=36 xoffset=-3 yoffset=-2 xadvance=29 page=0 chnl=15
char id=95 x=231 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=96 x=442 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=97 x=408 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=98 x=432 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=99 x=210 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=84 x=336 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=85 x=360 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=86 x=0 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=87 x=68 y=0 width=30 height=36 xoffset=-3 yoffset=-2 xadvance=27 page=0 chnl=15
char id=88 x=26 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=89 x=384 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=90 x=84 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=100 x=456 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=101 x=480 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=102 x=54 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=103 x=0 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=104 x=24 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=105 x=469 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=106 x=18 y=266 width=16 height=36 xoffset=-8 yoffset=-2 xadvance=8 page=0 chnl=15
char id=107 x=48 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=108 x=417 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=109 x=161 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15
char id=110 x=72 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=111 x=96 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=117 x=192 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=118 x=216 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=119 x=248 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15
char id=120 x=240 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=121 x=264 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=122 x=288 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=123 x=432 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=124 x=365 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=125 x=378 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=126 x=393 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=127 x=132 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15
char id=160 x=0 y=304 width=7 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=161 x=352 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=162 x=351 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=163 x=336 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=165 x=360 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=167 x=384 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=169 x=433 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=170 x=224 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=171 x=105 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=172 x=0 y=0 width=32 height=36 xoffset=-3 yoffset=-2 xadvance=29 page=0 chnl=15
char id=173 x=494 y=38 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=174 x=52 y=76 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=175 x=52 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=176 x=126 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=177 x=435 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=178 x=320 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=179 x=336 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=181 x=459 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=112 x=120 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=113 x=144 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=114 x=396 y=228 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=115 x=168 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=116 x=36 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=182 x=408 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=183 x=498 y=190 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=185 x=192 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=186 x=208 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=187 x=477 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=191 x=456 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=192 x=407 y=0 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=193 x=234 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=194 x=416 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=195 x=156 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=196 x=130 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=197 x=104 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=198 x=190 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15
char id=212 x=0 y=76 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=213 x=338 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=214 x=312 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=215 x=357 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=216 x=286 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=217 x=456 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=218 x=480 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=219 x=0 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=220 x=24 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=221 x=48 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=222 x=260 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=223 x=72 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=224 x=96 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=225 x=120 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=226 x=144 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=227 x=168 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=228 x=192 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=229 x=216 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=230 x=219 y=0 width=27 height=36 xoffset=-3 yoffset=-2 xadvance=24 page=0 chnl=15
char id=231 x=372 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=73 x=90 y=266 width=16 height=36 xoffset=-3 yoffset=-2 xadvance=13 page=0 chnl=15
char id=74 x=216 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=75 x=240 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=76 x=273 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=77 x=100 y=0 width=30 height=36 xoffset=-3 yoffset=-2 xadvance=27 page=0 chnl=15
char id=232 x=312 y=152 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=233 x=240 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=234 x=264 y=190 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=235 x=104 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=236 x=430 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=237 x=482 y=266 width=11 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=238 x=160 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=11 page=0 chnl=15
char id=239 x=176 y=266 width=14 height=36 xoffset=-3 yoffset=-2 xadvance=8 page=0 chnl=15
char id=240 x=128 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=241 x=200 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=242 x=224 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=243 x=248 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=244 x=272 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=245 x=296 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=246 x=320 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=247 x=330 y=190 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=248 x=208 y=38 width=24 height=36 xoffset=-3 yoffset=-2 xadvance=21 page=0 chnl=15
char id=249 x=344 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=250 x=368 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=251 x=416 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=252 x=440 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=253 x=464 y=76 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15
char id=254 x=0 y=228 width=19 height=36 xoffset=-3 yoffset=-2 xadvance=16 page=0 chnl=15
char id=255 x=0 y=114 width=22 height=36 xoffset=-3 yoffset=-2 xadvance=19 page=0 chnl=15

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

View File

@ -0,0 +1,20 @@
#version 100
precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
void main()
{
vec4 texelColor = texture2D(texture0, fragTexCoord);
if (texelColor.a == 0.0) discard;
gl_FragColor = texelColor*fragColor*colDiffuse;
}

View File

@ -0,0 +1,25 @@
#version 100
precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// NOTE: Add your custom variables here
const float smoothing = 1.0/16.0;
void main()
{
// Texel color fetching from texture sampler
// NOTE: Calculate alpha using signed distance field (SDF)
float distance = texture2D(texture0, fragTexCoord).a;
float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
// Calculate final fragment color
gl_FragColor = vec4(fragColor.rgb, fragColor.a*alpha);
}

View File

@ -0,0 +1,19 @@
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Output fragment color
out vec4 finalColor;
void main()
{
vec4 texelColor = texture(texture0, fragTexCoord);
if (texelColor.a == 0.0) discard;
finalColor = texelColor * fragColor * colDiffuse;
}

View File

@ -0,0 +1,26 @@
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Output fragment color
out vec4 finalColor;
// NOTE: Add your custom variables here
void main()
{
// Texel color fetching from texture sampler
// NOTE: Calculate alpha using signed distance field (SDF)
float distanceFromOutline = texture(texture0, fragTexCoord).a - 0.5;
float distanceChangePerFragment = length(vec2(dFdx(distanceFromOutline), dFdy(distanceFromOutline)));
float alpha = smoothstep(-distanceChangePerFragment, distanceChangePerFragment, distanceFromOutline);
// Calculate final fragment color
finalColor = vec4(fragColor.rgb, fragColor.a*alpha);
}

View File

@ -0,0 +1,191 @@
info face="Symbola" size=-64 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=2,2 outline=2
common lineHeight=81 base=59 scaleW=1024 scaleH=1024 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4
page id=0 file="symbola.png"
chars count=187
char id=9749 x=135 y=333 width=63 height=61 xoffset=1 yoffset=9 xadvance=65 page=0 chnl=15
char id=9752 x=366 y=396 width=57 height=59 xoffset=0 yoffset=10 xadvance=58 page=0 chnl=15
char id=9760 x=257 y=0 width=46 height=68 xoffset=0 yoffset=7 xadvance=47 page=0 chnl=15
char id=9785 x=61 y=579 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=9786 x=183 y=578 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=10083 x=984 y=200 width=35 height=50 xoffset=1 yoffset=12 xadvance=37 page=0 chnl=15
char id=10084 x=266 y=697 width=58 height=44 xoffset=1 yoffset=15 xadvance=60 page=0 chnl=15
char id=127744 x=736 y=266 width=40 height=63 xoffset=4 yoffset=10 xadvance=48 page=0 chnl=15
char id=127789 x=401 y=637 width=64 height=56 xoffset=0 yoffset=14 xadvance=64 page=0 chnl=15
char id=127790 x=697 y=331 width=62 height=60 xoffset=1 yoffset=10 xadvance=64 page=0 chnl=15
char id=127791 x=0 y=699 width=64 height=51 xoffset=0 yoffset=17 xadvance=64 page=0 chnl=15
char id=127792 x=456 y=202 width=64 height=63 xoffset=0 yoffset=9 xadvance=64 page=0 chnl=15
char id=127798 x=523 y=695 width=58 height=35 xoffset=3 yoffset=27 xadvance=64 page=0 chnl=15
char id=127805 x=825 y=330 width=60 height=60 xoffset=0 yoffset=11 xadvance=60 page=0 chnl=15
char id=127806 x=259 y=268 width=60 height=63 xoffset=0 yoffset=10 xadvance=60 page=0 chnl=15
char id=127807 x=322 y=333 width=59 height=61 xoffset=0 yoffset=10 xadvance=60 page=0 chnl=15
char id=127808 x=0 y=269 width=63 height=63 xoffset=0 yoffset=9 xadvance=63 page=0 chnl=15
char id=127811 x=305 y=396 width=59 height=59 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=127812 x=696 y=0 width=64 height=66 xoffset=2 yoffset=8 xadvance=68 page=0 chnl=15
char id=127813 x=61 y=397 width=58 height=60 xoffset=0 yoffset=11 xadvance=58 page=0 chnl=15
char id=127814 x=946 y=265 width=61 height=62 xoffset=0 yoffset=9 xadvance=61 page=0 chnl=15
char id=127815 x=584 y=635 width=56 height=56 xoffset=0 yoffset=12 xadvance=56 page=0 chnl=15
char id=127827 x=121 y=397 width=58 height=60 xoffset=0 yoffset=10 xadvance=58 page=0 chnl=15
char id=127828 x=0 y=334 width=68 height=61 xoffset=0 yoffset=10 xadvance=68 page=0 chnl=15
char id=127829 x=68 y=70 width=65 height=65 xoffset=0 yoffset=8 xadvance=65 page=0 chnl=15
char id=127830 x=737 y=135 width=59 height=64 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=127831 x=560 y=0 width=66 height=66 xoffset=0 yoffset=8 xadvance=66 page=0 chnl=15
char id=127832 x=135 y=70 width=65 height=65 xoffset=0 yoffset=8 xadvance=65 page=0 chnl=15
char id=127837 x=630 y=331 width=65 height=60 xoffset=0 yoffset=13 xadvance=65 page=0 chnl=15
char id=127838 x=628 y=0 width=66 height=66 xoffset=0 yoffset=8 xadvance=66 page=0 chnl=15
char id=127839 x=566 y=267 width=59 height=63 xoffset=0 yoffset=9 xadvance=59 page=0 chnl=15
char id=127840 x=562 y=332 width=66 height=60 xoffset=0 yoffset=12 xadvance=66 page=0 chnl=15
char id=127841 x=798 y=135 width=57 height=64 xoffset=0 yoffset=9 xadvance=57 page=0 chnl=15
char id=127842 x=467 y=637 width=57 height=56 xoffset=0 yoffset=13 xadvance=57 page=0 chnl=15
char id=127845 x=213 y=137 width=65 height=64 xoffset=0 yoffset=9 xadvance=65 page=0 chnl=15
char id=127846 x=950 y=67 width=34 height=65 xoffset=0 yoffset=8 xadvance=34 page=0 chnl=15
char id=127850 x=522 y=202 width=64 height=63 xoffset=0 yoffset=9 xadvance=64 page=0 chnl=15
char id=127851 x=544 y=135 width=64 height=64 xoffset=0 yoffset=9 xadvance=65 page=0 chnl=15
char id=127855 x=440 y=333 width=49 height=61 xoffset=0 yoffset=10 xadvance=49 page=0 chnl=15
char id=127856 x=207 y=638 width=64 height=57 xoffset=0 yoffset=11 xadvance=64 page=0 chnl=15
char id=127857 x=710 y=633 width=65 height=55 xoffset=0 yoffset=13 xadvance=66 page=0 chnl=15
char id=127858 x=237 y=396 width=66 height=59 xoffset=0 yoffset=12 xadvance=66 page=0 chnl=15
char id=127859 x=195 y=268 width=62 height=63 xoffset=1 yoffset=9 xadvance=64 page=0 chnl=15
char id=127861 x=77 y=0 width=65 height=68 xoffset=0 yoffset=6 xadvance=65 page=0 chnl=15
char id=127862 x=857 y=135 width=57 height=64 xoffset=0 yoffset=9 xadvance=58 page=0 chnl=15
char id=127863 x=47 y=203 width=41 height=64 xoffset=0 yoffset=9 xadvance=41 page=0 chnl=15
char id=127867 x=833 y=633 width=66 height=54 xoffset=0 yoffset=12 xadvance=66 page=0 chnl=15
char id=127868 x=986 y=67 width=25 height=53 xoffset=0 yoffset=12 xadvance=25 page=0 chnl=15
char id=127870 x=383 y=333 width=55 height=61 xoffset=1 yoffset=10 xadvance=57 page=0 chnl=15
char id=127871 x=530 y=394 width=42 height=59 xoffset=0 yoffset=12 xadvance=42 page=0 chnl=15
char id=127874 x=0 y=70 width=66 height=65 xoffset=0 yoffset=8 xadvance=66 page=0 chnl=15
char id=128065 x=384 y=696 width=68 height=39 xoffset=-2 yoffset=19 xadvance=64 page=0 chnl=15
char id=128068 x=132 y=698 width=57 height=47 xoffset=0 yoffset=15 xadvance=57 page=0 chnl=15
char id=128069 x=777 y=633 width=54 height=55 xoffset=0 yoffset=14 xadvance=54 page=0 chnl=15
char id=128121 x=478 y=136 width=64 height=64 xoffset=0 yoffset=8 xadvance=64 page=0 chnl=15
char id=128122 x=65 y=269 width=63 height=63 xoffset=0 yoffset=9 xadvance=63 page=0 chnl=15
char id=128123 x=339 y=637 width=60 height=57 xoffset=2 yoffset=14 xadvance=64 page=0 chnl=15
char id=128125 x=505 y=267 width=59 height=63 xoffset=0 yoffset=9 xadvance=60 page=0 chnl=15
char id=128126 x=321 y=268 width=60 height=63 xoffset=2 yoffset=7 xadvance=64 page=0 chnl=15
char id=128127 x=889 y=67 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128128 x=627 y=266 width=55 height=63 xoffset=0 yoffset=9 xadvance=55 page=0 chnl=15
char id=128139 x=574 y=394 width=68 height=58 xoffset=0 yoffset=12 xadvance=68 page=0 chnl=15
char id=128140 x=202 y=70 width=65 height=65 xoffset=0 yoffset=8 xadvance=65 page=0 chnl=15
char id=128147 x=642 y=634 width=66 height=55 xoffset=0 yoffset=12 xadvance=66 page=0 chnl=15
char id=128151 x=588 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15
char id=128152 x=280 y=137 width=64 height=64 xoffset=0 yoffset=9 xadvance=64 page=0 chnl=15
char id=128153 x=654 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15
char id=128155 x=720 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15
char id=128156 x=786 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15
char id=128157 x=77 y=137 width=67 height=64 xoffset=0 yoffset=9 xadvance=68 page=0 chnl=15
char id=128159 x=335 y=69 width=64 height=65 xoffset=0 yoffset=8 xadvance=64 page=0 chnl=15
char id=128162 x=130 y=268 width=63 height=63 xoffset=0 yoffset=9 xadvance=63 page=0 chnl=15
char id=128163 x=146 y=137 width=65 height=64 xoffset=0 yoffset=9 xadvance=65 page=0 chnl=15
char id=128164 x=454 y=695 width=67 height=38 xoffset=0 yoffset=23 xadvance=67 page=0 chnl=15
char id=128169 x=916 y=134 width=57 height=64 xoffset=0 yoffset=9 xadvance=58 page=0 chnl=15
char id=128420 x=852 y=201 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15
char id=128512 x=732 y=513 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128514 x=644 y=393 width=63 height=58 xoffset=0 yoffset=12 xadvance=63 page=0 chnl=15
char id=128515 x=610 y=514 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128518 x=488 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128519 x=144 y=0 width=59 height=68 xoffset=0 yoffset=7 xadvance=59 page=0 chnl=15
char id=128520 x=584 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128521 x=427 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128523 x=61 y=519 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128524 x=0 y=519 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128525 x=915 y=452 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128526 x=854 y=452 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128527 x=793 y=453 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128528 x=732 y=453 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128529 x=671 y=453 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128530 x=488 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128533 x=122 y=459 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128534 x=854 y=572 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128535 x=305 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128536 x=122 y=579 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128537 x=366 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128538 x=244 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128539 x=305 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128541 x=366 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128542 x=427 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128543 x=488 y=577 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128544 x=549 y=575 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128545 x=671 y=573 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128546 x=732 y=573 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128547 x=793 y=573 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128548 x=427 y=0 width=59 height=67 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128549 x=915 y=572 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128550 x=0 y=639 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128553 x=898 y=392 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128554 x=959 y=391 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128555 x=0 y=459 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128556 x=61 y=459 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128557 x=305 y=0 width=59 height=67 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128558 x=183 y=458 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128559 x=244 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128560 x=709 y=393 width=61 height=58 xoffset=0 yoffset=12 xadvance=62 page=0 chnl=15
char id=128561 x=835 y=392 width=61 height=58 xoffset=0 yoffset=12 xadvance=61 page=0 chnl=15
char id=128562 x=366 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128563 x=427 y=457 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128564 x=90 y=203 width=88 height=63 xoffset=0 yoffset=7 xadvance=59 page=0 chnl=15
char id=128565 x=549 y=455 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128566 x=610 y=574 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128567 x=610 y=454 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128568 x=401 y=69 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128569 x=878 y=0 width=67 height=65 xoffset=0 yoffset=8 xadvance=67 page=0 chnl=15
char id=128570 x=523 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128571 x=828 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128573 x=767 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128575 x=706 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128576 x=645 y=68 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=128577 x=122 y=519 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128578 x=183 y=518 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128579 x=244 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=128580 x=305 y=517 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129296 x=200 y=333 width=59 height=61 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129297 x=366 y=0 width=59 height=67 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=129298 x=383 y=268 width=59 height=63 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129299 x=549 y=515 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129300 x=0 y=0 width=75 height=68 xoffset=0 yoffset=7 xadvance=72 page=0 chnl=15
char id=129301 x=671 y=513 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129302 x=181 y=396 width=54 height=60 xoffset=2 yoffset=7 xadvance=59 page=0 chnl=15
char id=129303 x=778 y=266 width=98 height=62 xoffset=-1 yoffset=12 xadvance=96 page=0 chnl=15
char id=129312 x=0 y=137 width=75 height=64 xoffset=-1 yoffset=9 xadvance=74 page=0 chnl=15
char id=129314 x=793 y=513 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129315 x=346 y=136 width=64 height=64 xoffset=-1 yoffset=9 xadvance=64 page=0 chnl=15
char id=129316 x=444 y=267 width=59 height=63 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129319 x=488 y=0 width=70 height=66 xoffset=0 yoffset=8 xadvance=70 page=0 chnl=15
char id=129320 x=854 y=512 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129321 x=915 y=512 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129322 x=0 y=579 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129323 x=762 y=0 width=59 height=66 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=129324 x=772 y=393 width=61 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129325 x=949 y=329 width=59 height=60 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129326 x=261 y=333 width=59 height=61 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129327 x=462 y=69 width=59 height=65 xoffset=0 yoffset=8 xadvance=59 page=0 chnl=15
char id=129346 x=975 y=134 width=46 height=64 xoffset=-1 yoffset=8 xadvance=44 page=0 chnl=15
char id=129347 x=675 y=135 width=60 height=64 xoffset=-1 yoffset=9 xadvance=58 page=0 chnl=15
char id=129360 x=70 y=334 width=63 height=61 xoffset=-1 yoffset=10 xadvance=61 page=0 chnl=15
char id=129361 x=191 y=698 width=73 height=45 xoffset=-1 yoffset=18 xadvance=72 page=0 chnl=15
char id=129362 x=253 y=203 width=66 height=63 xoffset=-1 yoffset=9 xadvance=64 page=0 chnl=15
char id=129363 x=122 y=639 width=83 height=57 xoffset=-1 yoffset=14 xadvance=82 page=0 chnl=15
char id=129364 x=491 y=332 width=69 height=60 xoffset=-1 yoffset=11 xadvance=68 page=0 chnl=15
char id=129365 x=412 y=136 width=64 height=64 xoffset=-1 yoffset=8 xadvance=63 page=0 chnl=15
char id=129366 x=947 y=0 width=66 height=65 xoffset=-1 yoffset=8 xadvance=65 page=0 chnl=15
char id=129367 x=180 y=203 width=71 height=63 xoffset=-1 yoffset=8 xadvance=70 page=0 chnl=15
char id=129368 x=878 y=266 width=66 height=62 xoffset=-1 yoffset=9 xadvance=65 page=0 chnl=15
char id=129369 x=269 y=70 width=64 height=65 xoffset=-1 yoffset=8 xadvance=63 page=0 chnl=15
char id=129370 x=823 y=0 width=53 height=66 xoffset=1 yoffset=8 xadvance=55 page=0 chnl=15
char id=129371 x=205 y=0 width=50 height=68 xoffset=1 yoffset=7 xadvance=52 page=0 chnl=15
char id=129372 x=389 y=202 width=65 height=63 xoffset=1 yoffset=9 xadvance=67 page=0 chnl=15
char id=129373 x=887 y=330 width=60 height=60 xoffset=1 yoffset=10 xadvance=62 page=0 chnl=15
char id=129374 x=961 y=632 width=61 height=51 xoffset=1 yoffset=15 xadvance=64 page=0 chnl=15
char id=129375 x=526 y=637 width=56 height=56 xoffset=1 yoffset=12 xadvance=58 page=0 chnl=15
char id=129377 x=425 y=396 width=53 height=59 xoffset=1 yoffset=10 xadvance=56 page=0 chnl=15
char id=129378 x=321 y=203 width=66 height=63 xoffset=-1 yoffset=9 xadvance=64 page=0 chnl=15
char id=129379 x=761 y=331 width=62 height=60 xoffset=1 yoffset=12 xadvance=64 page=0 chnl=15
char id=129380 x=480 y=396 width=48 height=59 xoffset=4 yoffset=13 xadvance=56 page=0 chnl=15
char id=129381 x=0 y=397 width=59 height=60 xoffset=0 yoffset=10 xadvance=59 page=0 chnl=15
char id=129382 x=684 y=266 width=50 height=63 xoffset=1 yoffset=10 xadvance=53 page=0 chnl=15
char id=129383 x=610 y=135 width=63 height=64 xoffset=1 yoffset=8 xadvance=65 page=0 chnl=15
char id=129384 x=901 y=632 width=58 height=53 xoffset=2 yoffset=16 xadvance=63 page=0 chnl=15
char id=129385 x=326 y=696 width=56 height=41 xoffset=2 yoffset=19 xadvance=60 page=0 chnl=15
char id=129386 x=273 y=637 width=64 height=57 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15
char id=129387 x=0 y=203 width=45 height=64 xoffset=4 yoffset=9 xadvance=53 page=0 chnl=15
char id=129472 x=66 y=699 width=64 height=49 xoffset=0 yoffset=14 xadvance=64 page=0 chnl=15
char id=129488 x=61 y=639 width=59 height=58 xoffset=0 yoffset=12 xadvance=59 page=0 chnl=15
char id=129505 x=918 y=200 width=64 height=63 xoffset=0 yoffset=10 xadvance=64 page=0 chnl=15

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

586
examples/text/unicode.zig Normal file
View File

@ -0,0 +1,586 @@
//!******************************************************************************************
//!
//! raylib-zig port of the [text] example - Unicode
//! https://github.com/raysan5/raylib/blob/master/examples/text/text_unicode.c
//!
//! Example complexity rating: [] 4/4
//!
//! Example originally created with raylib 2.5, last time updated with raylib 4.0
//!
//! Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
//! Translated to raylib-zig by Timothy Fiss (@TheFissk)
//!
//! Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
//! BSD-like license that allows static linking with closed source software
//!
//! Copyright (c) 2019-2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
//!
//!*******************************************************************************************/
const rl = @import("raylib");
const std = @import("std");
const emoji_per_width = 8;
const emoji_per_height = 4;
// String containing 180 emoji codepoints separated by a '\0' char
const emojiCodepoints = "\xF0\x9F\x8C\x80\x00\xF0\x9F\x98\x80\x00\xF0\x9F\x98\x82\x00\xF0\x9F\xA4\xA3\x00\xF0\x9F\x98\x83\x00\xF0\x9F\x98\x86\x00\xF0\x9F\x98\x89\x00" ++
"\xF0\x9F\x98\x8B\x00\xF0\x9F\x98\x8E\x00\xF0\x9F\x98\x8D\x00\xF0\x9F\x98\x98\x00\xF0\x9F\x98\x97\x00\xF0\x9F\x98\x99\x00\xF0\x9F\x98\x9A\x00\xF0\x9F\x99\x82\x00" ++
"\xF0\x9F\xA4\x97\x00\xF0\x9F\xA4\xA9\x00\xF0\x9F\xA4\x94\x00\xF0\x9F\xA4\xA8\x00\xF0\x9F\x98\x90\x00\xF0\x9F\x98\x91\x00\xF0\x9F\x98\xB6\x00\xF0\x9F\x99\x84\x00" ++
"\xF0\x9F\x98\x8F\x00\xF0\x9F\x98\xA3\x00\xF0\x9F\x98\xA5\x00\xF0\x9F\x98\xAE\x00\xF0\x9F\xA4\x90\x00\xF0\x9F\x98\xAF\x00\xF0\x9F\x98\xAA\x00\xF0\x9F\x98\xAB\x00" ++
"\xF0\x9F\x98\xB4\x00\xF0\x9F\x98\x8C\x00\xF0\x9F\x98\x9B\x00\xF0\x9F\x98\x9D\x00\xF0\x9F\xA4\xA4\x00\xF0\x9F\x98\x92\x00\xF0\x9F\x98\x95\x00\xF0\x9F\x99\x83\x00" ++
"\xF0\x9F\xA4\x91\x00\xF0\x9F\x98\xB2\x00\xF0\x9F\x99\x81\x00\xF0\x9F\x98\x96\x00\xF0\x9F\x98\x9E\x00\xF0\x9F\x98\x9F\x00\xF0\x9F\x98\xA4\x00\xF0\x9F\x98\xA2\x00" ++
"\xF0\x9F\x98\xAD\x00\xF0\x9F\x98\xA6\x00\xF0\x9F\x98\xA9\x00\xF0\x9F\xA4\xAF\x00\xF0\x9F\x98\xAC\x00\xF0\x9F\x98\xB0\x00\xF0\x9F\x98\xB1\x00\xF0\x9F\x98\xB3\x00" ++
"\xF0\x9F\xA4\xAA\x00\xF0\x9F\x98\xB5\x00\xF0\x9F\x98\xA1\x00\xF0\x9F\x98\xA0\x00\xF0\x9F\xA4\xAC\x00\xF0\x9F\x98\xB7\x00\xF0\x9F\xA4\x92\x00\xF0\x9F\xA4\x95\x00" ++
"\xF0\x9F\xA4\xA2\x00\xF0\x9F\xA4\xAE\x00\xF0\x9F\xA4\xA7\x00\xF0\x9F\x98\x87\x00\xF0\x9F\xA4\xA0\x00\xF0\x9F\xA4\xAB\x00\xF0\x9F\xA4\xAD\x00\xF0\x9F\xA7\x90\x00" ++
"\xF0\x9F\xA4\x93\x00\xF0\x9F\x98\x88\x00\xF0\x9F\x91\xBF\x00\xF0\x9F\x91\xB9\x00\xF0\x9F\x91\xBA\x00\xF0\x9F\x92\x80\x00\xF0\x9F\x91\xBB\x00\xF0\x9F\x91\xBD\x00" ++
"\xF0\x9F\x91\xBE\x00\xF0\x9F\xA4\x96\x00\xF0\x9F\x92\xA9\x00\xF0\x9F\x98\xBA\x00\xF0\x9F\x98\xB8\x00\xF0\x9F\x98\xB9\x00\xF0\x9F\x98\xBB\x00\xF0\x9F\x98\xBD\x00" ++
"\xF0\x9F\x99\x80\x00\xF0\x9F\x98\xBF\x00\xF0\x9F\x8C\xBE\x00\xF0\x9F\x8C\xBF\x00\xF0\x9F\x8D\x80\x00\xF0\x9F\x8D\x83\x00\xF0\x9F\x8D\x87\x00\xF0\x9F\x8D\x93\x00" ++
"\xF0\x9F\xA5\x9D\x00\xF0\x9F\x8D\x85\x00\xF0\x9F\xA5\xA5\x00\xF0\x9F\xA5\x91\x00\xF0\x9F\x8D\x86\x00\xF0\x9F\xA5\x94\x00\xF0\x9F\xA5\x95\x00\xF0\x9F\x8C\xBD\x00" ++
"\xF0\x9F\x8C\xB6\x00\xF0\x9F\xA5\x92\x00\xF0\x9F\xA5\xA6\x00\xF0\x9F\x8D\x84\x00\xF0\x9F\xA5\x9C\x00\xF0\x9F\x8C\xB0\x00\xF0\x9F\x8D\x9E\x00\xF0\x9F\xA5\x90\x00" ++
"\xF0\x9F\xA5\x96\x00\xF0\x9F\xA5\xA8\x00\xF0\x9F\xA5\x9E\x00\xF0\x9F\xA7\x80\x00\xF0\x9F\x8D\x96\x00\xF0\x9F\x8D\x97\x00\xF0\x9F\xA5\xA9\x00\xF0\x9F\xA5\x93\x00" ++
"\xF0\x9F\x8D\x94\x00\xF0\x9F\x8D\x9F\x00\xF0\x9F\x8D\x95\x00\xF0\x9F\x8C\xAD\x00\xF0\x9F\xA5\xAA\x00\xF0\x9F\x8C\xAE\x00\xF0\x9F\x8C\xAF\x00\xF0\x9F\xA5\x99\x00" ++
"\xF0\x9F\xA5\x9A\x00\xF0\x9F\x8D\xB3\x00\xF0\x9F\xA5\x98\x00\xF0\x9F\x8D\xB2\x00\xF0\x9F\xA5\xA3\x00\xF0\x9F\xA5\x97\x00\xF0\x9F\x8D\xBF\x00\xF0\x9F\xA5\xAB\x00" ++
"\xF0\x9F\x8D\xB1\x00\xF0\x9F\x8D\x98\x00\xF0\x9F\x8D\x9D\x00\xF0\x9F\x8D\xA0\x00\xF0\x9F\x8D\xA2\x00\xF0\x9F\x8D\xA5\x00\xF0\x9F\x8D\xA1\x00\xF0\x9F\xA5\x9F\x00" ++
"\xF0\x9F\xA5\xA1\x00\xF0\x9F\x8D\xA6\x00\xF0\x9F\x8D\xAA\x00\xF0\x9F\x8E\x82\x00\xF0\x9F\x8D\xB0\x00\xF0\x9F\xA5\xA7\x00\xF0\x9F\x8D\xAB\x00\xF0\x9F\x8D\xAF\x00" ++
"\xF0\x9F\x8D\xBC\x00\xF0\x9F\xA5\x9B\x00\xF0\x9F\x8D\xB5\x00\xF0\x9F\x8D\xB6\x00\xF0\x9F\x8D\xBE\x00\xF0\x9F\x8D\xB7\x00\xF0\x9F\x8D\xBB\x00\xF0\x9F\xA5\x82\x00" ++
"\xF0\x9F\xA5\x83\x00\xF0\x9F\xA5\xA4\x00\xF0\x9F\xA5\xA2\x00\xF0\x9F\x91\x81\x00\xF0\x9F\x91\x85\x00\xF0\x9F\x91\x84\x00\xF0\x9F\x92\x8B\x00\xF0\x9F\x92\x98\x00" ++
"\xF0\x9F\x92\x93\x00\xF0\x9F\x92\x97\x00\xF0\x9F\x92\x99\x00\xF0\x9F\x92\x9B\x00\xF0\x9F\xA7\xA1\x00\xF0\x9F\x92\x9C\x00\xF0\x9F\x96\xA4\x00\xF0\x9F\x92\x9D\x00" ++
"\xF0\x9F\x92\x9F\x00\xF0\x9F\x92\x8C\x00\xF0\x9F\x92\xA4\x00\xF0\x9F\x92\xA2\x00\xF0\x9F\x92\xA3\x00";
const Message = struct {
text: [:0]const u8,
language: [:0]const u8,
};
/// Array containing all of the emojis messages
const messages = [_]Message{
.{
.text = "\x46\x61\x6C\x73\x63\x68\x65\x73\x20\xC3\x9C\x62\x65\x6E\x20\x76\x6F\x6E\x20\x58\x79\x6C\x6F\x70\x68\x6F\x6E\x6D\x75\x73\x69\x6B\x20\x71\x75\xC3\xA4\x6C\x74\x20\x6A\x65\x64\x65\x6E\x20\x67\x72\xC3\xB6\xC3\x9F\x65\x72\x65\x6E\x20\x5A\x77\x65\x72\x67",
.language = "German",
},
.{
.text = "\x42\x65\x69\xC3\x9F\x20\x6E\x69\x63\x68\x74\x20\x69\x6E\x20\x64\x69\x65\x20\x48\x61\x6E\x64\x2C\x20\x64\x69\x65\x20\x64\x69\x63\x68\x20\x66\xC3\xBC\x74\x74\x65\x72\x74\x2E",
.language = "German",
},
.{
.text = "\x41\x75\xC3\x9F\x65\x72\x6F\x72\x64\x65\x6E\x74\x6C\x69\x63\x68\x65\x20\xC3\x9C\x62\x65\x6C\x20\x65\x72\x66\x6F\x72\x64\x65\x72\x6E\x20\x61\x75\xC3\x9F\x65\x72\x6F\x72\x64\x65\x6E\x74\x6C\x69\x63\x68\x65\x20\x4D\x69\x74\x74\x65\x6C\x2E",
.language = "German",
},
.{
.text = "\xD4\xBF\xD6\x80\xD5\xB6\xD5\xA1\xD5\xB4\x20\xD5\xA1\xD5\xBA\xD5\xA1\xD5\xAF\xD5\xAB\x20\xD5\xB8\xD6\x82\xD5\xBF\xD5\xA5\xD5\xAC\x20\xD6\x87\x20\xD5\xAB\xD5\xB6\xD5\xAE\xD5\xAB\x20\xD5\xA1\xD5\xB6\xD5\xB0\xD5\xA1\xD5\xB6\xD5\xA3\xD5\xAB\xD5\xBD\xD5\xBF\x20\xD5\xB9\xD5\xA8\xD5\xB6\xD5\xA5\xD6\x80",
.language = "Armenian",
},
.{
.text = "\xD4\xB5\xD6\x80\xD5\xA2\x20\xD5\xB8\xD6\x80\x20\xD5\xAF\xD5\xA1\xD6\x81\xD5\xAB\xD5\xB6\xD5\xA8\x20\xD5\xA5\xD5\xAF\xD5\xA1\xD6\x82\x20\xD5\xA1\xD5\xB6\xD5\xBF\xD5\xA1\xD5\xBC\x2C\x20\xD5\xAE\xD5\xA1\xD5\xBC\xD5\xA5\xD6\x80\xD5\xA8\x20\xD5\xA1\xD5\xBD\xD5\xA1\xD6\x81\xD5\xAB\xD5\xB6\x2E\x2E\x2E\x20\xC2\xAB\xD4\xBF\xD5\xB8\xD5\xBF\xD5\xA8\x20\xD5\xB4\xD5\xA5\xD6\x80\xD5\xB8\xD5\xB6\xD6\x81\xD5\xAB\xD6\x81\x20\xD5\xA7\x3A\xC2\xBB",
.language = "Armenian",
},
.{
.text = "\xD4\xB3\xD5\xA1\xD5\xBC\xD5\xA8\xD5\x9D\x20\xD5\xA3\xD5\xA1\xD6\x80\xD5\xB6\xD5\xA1\xD5\xB6\x2C\x20\xD5\xB1\xD5\xAB\xD6\x82\xD5\xB6\xD5\xA8\xD5\x9D\x20\xD5\xB1\xD5\xB4\xD5\xBC\xD5\xA1\xD5\xB6",
.language = "Armenian",
},
.{
.text = "\x4A\x65\xC5\xBC\x75\x20\x6B\x6C\xC4\x85\x74\x77\x2C\x20\x73\x70\xC5\x82\xC3\xB3\x64\xC5\xBA\x20\x46\x69\x6E\x6F\x6D\x20\x63\x7A\xC4\x99\xC5\x9B\xC4\x87\x20\x67\x72\x79\x20\x68\x61\xC5\x84\x62\x21",
.language = "Polish",
},
.{
.text = "\x44\x6F\x62\x72\x79\x6D\x69\x20\x63\x68\xC4\x99\x63\x69\x61\x6D\x69\x20\x6A\x65\x73\x74\x20\x70\x69\x65\x6B\xC5\x82\x6F\x20\x77\x79\x62\x72\x75\x6B\x6F\x77\x61\x6E\x65\x2E",
.language = "Polish",
},
.{
.text = "\xC3\x8E\xC8\x9B\x69\x20\x6D\x75\x6C\xC8\x9B\x75\x6D\x65\x73\x63\x20\x63\xC4\x83\x20\x61\x69\x20\x61\x6C\x65\x73\x20\x72\x61\x79\x6C\x69\x62\x2E\x0A\xC8\x98\x69\x20\x73\x70\x65\x72\x20\x73\xC4\x83\x20\x61\x69\x20\x6F\x20\x7A\x69\x20\x62\x75\x6E\xC4\x83\x21",
.language = "Romanian",
},
.{
.text = "\xD0\xAD\xD1\x85\x2C\x20\xD1\x87\xD1\x83\xD0\xB6\xD0\xB0\xD0\xBA\x2C\x20\xD0\xBE\xD0\xB1\xD1\x89\xD0\xB8\xD0\xB9\x20\xD1\x81\xD1\x8A\xD1\x91\xD0\xBC\x20\xD1\x86\xD0\xB5\xD0\xBD\x20\xD1\x88\xD0\xBB\xD1\x8F\xD0\xBF\x20\x28\xD1\x8E\xD1\x84\xD1\x82\xD1\x8C\x29\x20\xD0\xB2\xD0\xB4\xD1\x80\xD1\x8B\xD0\xB7\xD0\xB3\x21",
.language = "Russian",
},
.{
.text = "\xD0\xAF\x20\xD0\xBB\xD1\x8E\xD0\xB1\xD0\xBB\xD1\x8E\x20\x72\x61\x79\x6C\x69\x62\x21",
.language = "Russian",
},
.{
.text = "\xD0\x9C\xD0\xBE\xD0\xBB\xD1\x87\xD0\xB8\x2C\x20\xD1\x81\xD0\xBA\xD1\x80\xD1\x8B\xD0\xB2\xD0\xB0\xD0\xB9\xD1\x81\xD1\x8F\x20\xD0\xB8\x20\xD1\x82\xD0\xB0\xD0\xB8\x0A\xD0\x98\x20\xD1\x87\xD1\x83\xD0\xB2\xD1\x81\xD1\x82\xD0\xB2\xD0\xB0\x20\xD0\xB8\x20\xD0\xBC\xD0\xB5\xD1\x87\xD1\x82\xD1\x8B\x20\xD1\x81\xD0\xB2\xD0\xBE\xD0\xB8\x20\xE2\x80\x93\x0A\xD0\x9F\xD1\x83\xD1\x81\xD0\xBA\xD0\xB0\xD0\xB9\x20\xD0\xB2\x20\xD0\xB4\xD1\x83\xD1\x88\xD0\xB5\xD0\xB2\xD0\xBD\xD0\xBE\xD0\xB9\x20\xD0\xB3\xD0\xBB\xD1\x83\xD0\xB1\xD0\xB8\xD0\xBD\xD0\xB5\x0A\xD0\x98\x20\xD0\xB2\xD1\x81\xD1\x85\xD0\xBE\xD0\xB4\xD1\x8F\xD1\x82\x20\xD0\xB8\x20\xD0\xB7\xD0\xB0\xD0\xB9\xD0\xB4\xD1\x83\xD1\x82\x20\xD0\xBE\xD0\xBD\xD0\xB5\x0A\xD0\x9A\xD0\xB0\xD0\xBA\x20\xD0\xB7\xD0\xB2\xD0\xB5\xD0\xB7\xD0\xB4\xD1\x8B\x20\xD1\x8F\xD1\x81\xD0\xBD\xD1\x8B\xD0\xB5\x20\xD0\xB2\x20\xD0\xBD\xD0\xBE\xD1\x87\xD0\xB8\x2D\x0A\xD0\x9B\xD1\x8E\xD0\xB1\xD1\x83\xD0\xB9\xD1\x81\xD1\x8F\x20\xD0\xB8\xD0\xBC\xD0\xB8\x20\xE2\x80\x93\x20\xD0\xB8\x20\xD0\xBC\xD0\xBE\xD0\xBB\xD1\x87\xD0\xB8\x2E",
.language = "Russian",
},
.{
.text = "\x56\x6F\x69\x78\x20\x61\x6D\x62\x69\x67\x75\xC3\xAB\x20\x64\xE2\x80\x99\x75\x6E\x20\x63\xC5\x93\x75\x72\x20\x71\x75\x69\x20\x61\x75\x20\x7A\xC3\xA9\x70\x68\x79\x72\x20\x70\x72\xC3\xA9\x66\xC3\xA8\x72\x65\x20\x6C\x65\x73\x20\x6A\x61\x74\x74\x65\x73\x20\x64\x65\x20\x6B\x69\x77\x69",
.language = "French",
},
.{
.text = "\x42\x65\x6E\x6A\x61\x6D\xC3\xAD\x6E\x20\x70\x69\x64\x69\xC3\xB3\x20\x75\x6E\x61\x20\x62\x65\x62\x69\x64\x61\x20\x64\x65\x20\x6B\x69\x77\x69\x20\x79\x20\x66\x72\x65\x73\x61\x3B\x20\x4E\x6F\xC3\xA9\x2C\x20\x73\x69\x6E\x20\x76\x65\x72\x67\xC3\xBC\x65\x6E\x7A\x61\x2C\x20\x6C\x61\x20\x6D\xC3\xA1\x73\x20\x65\x78\x71\x75\x69\x73\x69\x74\x61\x20\x63\x68\x61\x6D\x70\x61\xC3\xB1\x61\x20\x64\x65\x6C\x20\x6D\x65\x6E\xC3\xBA\x2E",
.language = "Spanish",
},
.{
.text = "\xCE\xA4\xCE\xB1\xCF\x87\xCE\xAF\xCF\x83\xCF\x84\xCE\xB7\x20\xCE\xB1\xCE\xBB\xCF\x8E\xCF\x80\xCE\xB7\xCE\xBE\x20\xCE\xB2\xCE\xB1\xCF\x86\xCE\xAE\xCF\x82\x20\xCF\x88\xCE\xB7\xCE\xBC\xCE\xAD\xCE\xBD\xCE\xB7\x20\xCE\xB3\xCE\xB7\x2C\x20\xCE\xB4\xCF\x81\xCE\xB1\xCF\x83\xCE\xBA\xCE\xB5\xCE\xBB\xCE\xAF\xCE\xB6\xCE\xB5\xCE\xB9\x20\xCF\x85\xCF\x80\xCE\xAD\xCF\x81\x20\xCE\xBD\xCF\x89\xCE\xB8\xCF\x81\xCE\xBF\xCF\x8D\x20\xCE\xBA\xCF\x85\xCE\xBD\xCF\x8C\xCF\x82",
.language = "Greek",
},
.{
.text = "\xCE\x97\x20\xCE\xBA\xCE\xB1\xCE\xBB\xCF\x8D\xCF\x84\xCE\xB5\xCF\x81\xCE\xB7\x20\xCE\xAC\xCE\xBC\xCF\x85\xCE\xBD\xCE\xB1\x20\xCE\xB5\xCE\xAF\xCE\xBD\xCE\xB1\xCE\xB9\x20\xCE\xB7\x20\xCE\xB5\xCF\x80\xCE\xAF\xCE\xB8\xCE\xB5\xCF\x83\xCE\xB7\x2E",
.language = "Greek",
},
.{
.text = "\xCE\xA7\xCF\x81\xCF\x8C\xCE\xBD\xCE\xB9\xCE\xB1\x20\xCE\xBA\xCE\xB1\xCE\xB9\x20\xCE\xB6\xCE\xB1\xCE\xBC\xCE\xAC\xCE\xBD\xCE\xB9\xCE\xB1\x21",
.language = "Greek",
},
.{
.text = "\xCE\xA0\xCF\x8E\xCF\x82\x20\xCF\x84\xCE\xB1\x20\xCF\x80\xCE\xB1\xCF\x82\x20\xCF\x83\xCE\xAE\xCE\xBC\xCE\xB5\xCF\x81\xCE\xB1\x3B",
.language = "Greek",
},
.{
.text = "\xE6\x88\x91\xE8\x83\xBD\xE5\x90\x9E\xE4\xB8\x8B\xE7\x8E\xBB\xE7\x92\x83\xE8\x80\x8C\xE4\xB8\x8D\xE4\xBC\xA4\xE8\xBA\xAB\xE4\xBD\x93\xE3\x80\x82",
.language = "Chinese",
},
.{
.text = "\xE4\xBD\xA0\xE5\x90\x83\xE4\xBA\x86\xE5\x90\x97\xEF\xBC\x9F",
.language = "Chinese",
},
.{
.text = "\xE4\xB8\x8D\xE4\xBD\x9C\xE4\xB8\x8D\xE6\xAD\xBB\xE3\x80\x82",
.language = "Chinese",
},
.{
.text = "\xE6\x9C\x80\xE8\xBF\x91\xE5\xA5\xBD\xE5\x90\x97\xEF\xBC\x9F",
.language = "Chinese",
},
.{
.text = "\xE5\xA1\x9E\xE7\xBF\x81\xE5\xA4\xB1\xE9\xA9\xAC\xEF\xBC\x8C\xE7\x84\x89\xE7\x9F\xA5\xE9\x9D\x9E\xE7\xA6\x8F\xE3\x80\x82",
.language = "Chinese",
},
.{
.text = "\xE5\x8D\x83\xE5\x86\x9B\xE6\x98\x93\xE5\xBE\x97\x2C\x20\xE4\xB8\x80\xE5\xB0\x86\xE9\x9A\xBE\xE6\xB1\x82",
.language = "Chinese",
},
.{
.text = "\xE4\xB8\x87\xE4\xBA\x8B\xE5\xBC\x80\xE5\xA4\xB4\xE9\x9A\xBE\xE3\x80\x82",
.language = "Chinese",
},
.{
.text = "\xE9\xA3\x8E\xE6\x97\xA0\xE5\xB8\xB8\xE9\xA1\xBA\xEF\xBC\x8C\xE5\x85\xB5\xE6\x97\xA0\xE5\xB8\xB8\xE8\x83\x9C\xE3\x80\x82",
.language = "Chinese",
},
.{
.text = "\xE6\xB4\xBB\xE5\x88\xB0\xE8\x80\x81\xEF\xBC\x8C\xE5\xAD\xA6\xE5\x88\xB0\xE8\x80\x81\xE3\x80\x82",
.language = "Chinese",
},
.{
.text = "\xE4\xB8\x80\xE8\xA8\x80\xE6\x97\xA2\xE5\x87\xBA\xEF\xBC\x8C\xE9\xA9\xB7\xE9\xA9\xAC\xE9\x9A\xBE\xE8\xBF\xBD\xE3\x80\x82",
.language = "Chinese",
},
.{
.text = "\xE8\xB7\xAF\xE9\x81\xA5\xE7\x9F\xA5\xE9\xA9\xAC\xE5\x8A\x9B\xEF\xBC\x8C\xE6\x97\xA5\xE4\xB9\x85\xE8\xA7\x81\xE4\xBA\xBA\xE5\xBF\x83",
.language = "Chinese",
},
.{
.text = "\xE6\x9C\x89\xE7\x90\x86\xE8\xB5\xB0\xE9\x81\x8D\xE5\xA4\xA9\xE4\xB8\x8B\xEF\xBC\x8C\xE6\x97\xA0\xE7\x90\x86\xE5\xAF\xB8\xE6\xAD\xA5\xE9\x9A\xBE\xE8\xA1\x8C\xE3\x80\x82",
.language = "Chinese",
},
.{
.text = "\xE7\x8C\xBF\xE3\x82\x82\xE6\x9C\xA8\xE3\x81\x8B\xE3\x82\x89\xE8\x90\xBD\xE3\x81\xA1\xE3\x82\x8B",
.language = "Japanese",
},
.{
.text = "\xE4\xBA\x80\xE3\x81\xAE\xE7\x94\xB2\xE3\x82\x88\xE3\x82\x8A\xE5\xB9\xB4\xE3\x81\xAE\xE5\x8A\x9F",
.language = "Japanese",
},
.{
.text = "\xE3\x81\x86\xE3\x82\x89\xE3\x82\x84\xE3\x81\xBE\xE3\x81\x97\x20\x20\xE6\x80\x9D\xE3\x81\xB2\xE5\x88\x87\xE3\x82\x8B\xE6\x99\x82\x20\x20\xE7\x8C\xAB\xE3\x81\xAE\xE6\x81\x8B",
.language = "Japanese",
},
.{
.text = "\xE8\x99\x8E\xE7\xA9\xB4\xE3\x81\xAB\xE5\x85\xA5\xE3\x82\x89\xE3\x81\x9A\xE3\x82\x93\xE3\x81\xB0\xE8\x99\x8E\xE5\xAD\x90\xE3\x82\x92\xE5\xBE\x97\xE3\x81\x9A\xE3\x80\x82",
.language = "Japanese",
},
.{
.text = "\xE4\xBA\x8C\xE5\x85\x8E\xE3\x82\x92\xE8\xBF\xBD\xE3\x81\x86\xE8\x80\x85\xE3\x81\xAF\xE4\xB8\x80\xE5\x85\x8E\xE3\x82\x92\xE3\x82\x82\xE5\xBE\x97\xE3\x81\x9A\xE3\x80\x82",
.language = "Japanese",
},
.{
.text = "\xE9\xA6\xAC\xE9\xB9\xBF\xE3\x81\xAF\xE6\xAD\xBB\xE3\x81\xAA\xE3\x81\xAA\xE3\x81\x8D\xE3\x82\x83\xE6\xB2\xBB\xE3\x82\x89\xE3\x81\xAA\xE3\x81\x84\xE3\x80\x82",
.language = "Japanese",
},
.{
.text = "\xE6\x9E\xAF\xE9\x87\x8E\xE8\xB7\xAF\xE3\x81\xAB\xE3\x80\x80\xE5\xBD\xB1\xE3\x81\x8B\xE3\x81\x95\xE3\x81\xAA\xE3\x82\x8A\xE3\x81\xA6\xE3\x80\x80\xE3\x82\x8F\xE3\x81\x8B\xE3\x82\x8C\xE3\x81\x91\xE3\x82\x8A",
.language = "Japanese",
},
.{
.text = "\xE7\xB9\xB0\xE3\x82\x8A\xE8\xBF\x94\xE3\x81\x97\xE9\xBA\xA6\xE3\x81\xAE\xE7\x95\x9D\xE7\xB8\xAB\xE3\x81\xB5\xE8\x83\xA1\xE8\x9D\xB6\xE5\x93\x89",
.language = "Japanese",
},
.{
.text = "\xEC\x95\x84\xEB\x93\x9D\xED\x95\x9C\x20\xEB\xB0\x94\xEB\x8B\xA4\x20\xEC\x9C\x84\xEC\x97\x90\x20\xEA\xB0\x88\xEB\xA7\xA4\xEA\xB8\xB0\x20\xEB\x91\x90\xEC\x97\x87\x20\xEB\x82\xA0\xEC\x95\x84\x20\xEB\x8F\x88\xEB\x8B\xA4\x2E\x0A\xEB\x84\x88\xED\x9B\x8C\xEB\x84\x88\xED\x9B\x8C\x20\xEC\x8B\x9C\xEB\xA5\xBC\x20\xEC\x93\xB4\xEB\x8B\xA4\x2E\x20\xEB\xAA\xA8\xEB\xA5\xB4\xEB\x8A\x94\x20\xEB\x82\x98\xEB\x9D\xBC\x20\xEA\xB8\x80\xEC\x9E\x90\xEB\x8B\xA4\x2E\x0A\xEB\x84\x90\xEB\x94\xB0\xEB\x9E\x80\x20\xED\x95\x98\xEB\x8A\x98\x20\xEB\xB3\xB5\xED\x8C\x90\xEC\x97\x90\x20\xEB\x82\x98\xEB\x8F\x84\x20\xEA\xB0\x99\xEC\x9D\xB4\x20\xEC\x8B\x9C\xEB\xA5\xBC\x20\xEC\x93\xB4\xEB\x8B\xA4\x2E",
.language = "Korean",
},
.{
.text = "\xEC\xA0\x9C\x20\xEB\x88\x88\xEC\x97\x90\x20\xEC\x95\x88\xEA\xB2\xBD\xEC\x9D\xB4\xEB\x8B\xA4",
.language = "Korean",
},
.{
.text = "\xEA\xBF\xA9\x20\xEB\xA8\xB9\xEA\xB3\xA0\x20\xEC\x95\x8C\x20\xEB\xA8\xB9\xEB\x8A\x94\xEB\x8B\xA4",
.language = "Korean",
},
.{
.text = "\xEB\xA1\x9C\xEB\xA7\x88\xEB\x8A\x94\x20\xED\x95\x98\xEB\xA3\xA8\xEC\x95\x84\xEC\xB9\xA8\xEC\x97\x90\x20\xEC\x9D\xB4\xEB\xA3\xA8\xEC\x96\xB4\xEC\xA7\x84\x20\xEA\xB2\x83\xEC\x9D\xB4\x20\xEC\x95\x84\xEB\x8B\x88\xEB\x8B\xA4",
.language = "Korean",
},
.{
.text = "\xEA\xB3\xA0\xEC\x83\x9D\x20\xEB\x81\x9D\xEC\x97\x90\x20\xEB\x82\x99\xEC\x9D\xB4\x20\xEC\x98\xA8\xEB\x8B\xA4",
.language = "Korean",
},
.{
.text = "\xEA\xB0\x9C\xEC\xB2\x9C\xEC\x97\x90\xEC\x84\x9C\x20\xEC\x9A\xA9\x20\xEB\x82\x9C\xEB\x8B\xA4",
.language = "Korean",
},
.{
.text = "\xEC\x95\x88\xEB\x85\x95\xED\x95\x98\xEC\x84\xB8\xEC\x9A\x94\x3F",
.language = "Korean",
},
.{
.text = "\xEB\xA7\x8C\xEB\x82\x98\xEC\x84\x9C\x20\xEB\xB0\x98\xEA\xB0\x91\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4",
.language = "Korean",
},
.{
.text = "\xED\x95\x9C\xEA\xB5\xAD\xEB\xA7\x90\x20\xED\x95\x98\xEC\x8B\xA4\x20\xEC\xA4\x84\x20\xEC\x95\x84\xEC\x84\xB8\xEC\x9A\x94\x3F",
.language = "Korean",
},
};
//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
// Arrays that holds the random emojis
const Emoji = struct {
index: usize, // Index inside `emojiCodepoints`
message: *const Message, // Message index
color: rl.Color, // Emoji color
};
var emojis: [emoji_per_height * emoji_per_width]Emoji = undefined;
var hovered: ?*Emoji = null;
var selected_emoji: ?*Emoji = null;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() anyerror!void {
// Initialization
//--------------------------------------------------------------------------------------
const screen_width = 800;
const screen_height = 450;
rl.setConfigFlags(.{ .msaa_4x_hint = true, .vsync_hint = true });
rl.initWindow(screen_width, screen_height, "raylib [text] example - unicode");
defer rl.closeWindow();
// Load the font resources
// NOTE: fontAsian is for asian languages,
// fontEmoji is the emojis and fontDefault is used for everything else
const font_default = try rl.loadFont("examples/text/resources/dejavu.fnt");
defer rl.unloadFont(font_default);
const font_asian = try rl.loadFont("examples/text/resources/noto_cjk.fnt");
defer rl.unloadFont(font_asian);
const font_emoji = try rl.loadFont("examples/text/resources/symbola.fnt");
defer rl.unloadFont(font_emoji);
var hovered_pos = rl.Vector2{ .x = 0.0, .y = 0.0 };
var selected_pos = rl.Vector2{ .x = 0.0, .y = 0.0 };
// Set a random set of emojis when starting up
randomizeEmoji();
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Add a new set of emojis when SPACE is pressed
if (rl.isKeyPressed(.space)) randomizeEmoji();
// Set the selected emoji
if (rl.isMouseButtonPressed(.left) and (hovered != null) and (hovered != selected_emoji)) {
selected_emoji = hovered;
selected_pos = hovered_pos;
}
const mouse = rl.getMousePosition();
var position = rl.Vector2{ .x = 28.8, .y = 10.0 };
hovered = null;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
// Draw random emojis in the background
//------------------------------------------------------------------------------
for (&emojis, 0..) |*emoji, i| {
const txt = emojiCodepoints[emoji.index..];
const emoji_rect = rl.Rectangle{
.x = position.x,
.y = position.y,
.height = @floatFromInt(font_emoji.baseSize),
.width = @floatFromInt(font_emoji.baseSize),
};
if (!rl.checkCollisionPointRec(mouse, emoji_rect)) {
rl.drawTextEx(font_emoji, txt, position, @floatFromInt(font_emoji.baseSize), 1.0, if (selected_emoji == emoji) emoji.color else rl.fade(.light_gray, 0.4));
} else {
rl.drawTextEx(font_emoji, txt, position, @floatFromInt(font_emoji.baseSize), 1.0, emoji.color);
hovered = emoji;
hovered_pos = position;
}
if ((i != 0) and (i % emoji_per_width == 0)) {
position.y += @as(f32, @floatFromInt(font_emoji.baseSize)) + 24.25;
position.x = 28.8;
} else {
position.x += @as(f32, @floatFromInt(font_emoji.baseSize)) + 28.8;
}
}
//------------------------------------------------------------------------------
// Draw the message when a emoji is selected
//------------------------------------------------------------------------------
if (selected_emoji) |selected| {
const message = selected.message;
const horizontal_padding = 20;
const vertical_padding = 30;
var font = &font_default;
// Set correct font for asian languages
font = if (rl.textIsEqual(message.language, "Chinese") or
rl.textIsEqual(message.language, "Korean") or
rl.textIsEqual(message.language, "Japanese")) &font_asian else font;
// Calculate size for the message box (approximate the height and width)
var sz = rl.measureTextEx(font.*, message.text, @floatFromInt(font.baseSize), 1.0);
if (sz.x > 300) {
sz.y *= sz.x / 300;
sz.x = 300;
} else if (sz.x < 160) {
sz.x = 160;
}
var msg_rect = rl.Rectangle{
.x = selected_pos.x - 38.8,
.y = selected_pos.y,
.width = 2 * horizontal_padding + sz.x,
.height = 2 * vertical_padding + sz.y,
};
msg_rect.y -= msg_rect.height;
// Coordinates for the chat bubble triangle
var a = rl.Vector2{ .x = selected_pos.x, .y = msg_rect.y + msg_rect.height };
var b = rl.Vector2{ .x = a.x + 8, .y = a.y + 10 };
var c = rl.Vector2{ .x = a.x + 10, .y = a.y };
// Don't go outside the screen
if (msg_rect.x < 10) msg_rect.x += 28;
if (msg_rect.y < 10) {
msg_rect.y = selected_pos.y + 84;
a.y = msg_rect.y;
c.y = a.y;
b.y = a.y - 10;
// Swap values so we can actually render the triangle :(
const tmp = a;
a = b;
b = tmp;
}
if (msg_rect.x + msg_rect.width > screen_width) msg_rect.x -= (msg_rect.x + msg_rect.width) - screen_width + 10;
// Draw chat bubble
rl.drawRectangleRec(msg_rect, selected.color);
rl.drawTriangle(a, b, c, selected.color);
// Draw the main text message
const text_rect = rl.Rectangle{
.x = msg_rect.x + horizontal_padding / 2,
.y = msg_rect.y + vertical_padding / 2,
.width = msg_rect.width - horizontal_padding,
.height = msg_rect.height,
};
drawTextBoxed(font.*, message.text, text_rect, @floatFromInt(font.baseSize), 1.0, true, .white);
// Draw the info text below the main message
const size = message.text.len;
const length = rl.getCodepointCount(message.text);
const info = rl.textFormat("%s %u characters %i bytes", .{ message.language.ptr, length, size });
sz = rl.measureTextEx(font_default, info, 10, 1.0);
rl.drawText(info, @intFromFloat(text_rect.x + text_rect.width - sz.x), @intFromFloat(msg_rect.y + msg_rect.height - sz.y - 2), 10, .ray_white);
}
//------------------------------------------------------------------------------
// Draw the info text
rl.drawText("These emojis have something to tell you, click each to find out!", (screen_width - 650) / 2, screen_height - 40, 20, .gray);
rl.drawText("Each emoji is a unicode character from a font, not a texture... Press [SPACEBAR] to refresh", (screen_width - 484) / 2, screen_height - 16, 10, .gray);
//----------------------------------------------------------------------------------
}
}
// Fills the emoji array with random emoji (only those emojis present in fontEmoji)
fn randomizeEmoji() void {
hovered = null;
selected_emoji = null;
const start = rl.getRandomValue(45, 360);
for (&emojis, 0..) |*emoji, i| {
// 0-179 emoji codepoints (from emoji char array) each 4bytes + null char
emoji.index = @intCast(rl.getRandomValue(0, 179) * 5);
// Generate a random color for this emoji
const hue: f32 = @floatFromInt(@rem(start * @as(i32, @intCast(i + 1)), 360));
emoji.color = rl.fade(rl.colorFromHSV(hue, 0.6, 0.85), 0.8);
// Set a random message for this emoji
emoji.message = &messages[@intCast(rl.getRandomValue(0, messages.len - 1))];
}
}
//--------------------------------------------------------------------------------------
// Module functions definition
//--------------------------------------------------------------------------------------
// Draw text using font inside rectangle limits
fn drawTextBoxed(font: rl.Font, text: [:0]const u8, rec: rl.Rectangle, font_size: f32, spacing: f32, word_wrap: bool, tint: rl.Color) void {
drawTextBoxedSelectable(font, text, rec, font_size, spacing, word_wrap, tint, 0, 0, .white, .white);
}
// Draw text using font inside rectangle limits with support for text selection
fn drawTextBoxedSelectable(font: rl.Font, text: [:0]const u8, rec: rl.Rectangle, font_size: f32, spacing: f32, word_wrap: bool, tint: rl.Color, select_box_start: i32, select_length: i32, select_tint: rl.Color, select_back_tint: rl.Color) void {
var select_start = select_box_start;
const length = rl.textLength(text); // Total length in bytes of the text, scanned by codepoints in loop
var text_offset_y: f32 = 0; // Offset between lines (on line break '\n')
var text_offset_x: f32 = 0.0; // Offset X to next character to draw
const scale_factor = font_size / @as(f32, @floatFromInt(font.baseSize)); // Character rectangle scaling factor
// Word/character wrapping mechanism variables
const MeasureState = enum(u8) { measure, draw };
var state: MeasureState = if (word_wrap) .measure else .draw;
var start_line: i32 = -1; // Index where to begin drawing (where a line begins)
var end_line: i32 = -1; // Index where to stop drawing (where a line ends)
var last_char: i32 = -1; // Holds last value of the character position
var i: i32 = 0;
var k: i32 = 0;
while (i < length) : ({
i += 1;
k += 1;
}) {
// Get next codepoint from byte string and glyph index in font
var codepoint_byte_count: i32 = 0;
const codepoint = rl.getCodepoint(text[@intCast(i)..], &codepoint_byte_count);
const index: usize = @intCast(rl.getGlyphIndex(font, codepoint));
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepoint_byte_count = 1;
i += @intCast(codepoint_byte_count - 1);
var glyph_width: f32 = 0;
if (codepoint != '\n') {
glyph_width = if (font.glyphs[index].advanceX == 0) font.recs[index].width * scale_factor else @as(f32, @floatFromInt(font.glyphs[index].advanceX)) * scale_factor;
if (i + 1 < length) glyph_width = glyph_width + spacing;
}
// NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container
// We store this info in startLine and endLine, then we change states, draw the text between those two variables
// and change states again and again recursively until the end of the text (or until we get outside of the container).
// When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately
// and begin drawing on the next line before we can get outside the container.
if (state == .measure) {
// TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
// Ref: http://jkorpela.fi/chars/spaces.html
if ((codepoint == ' ') or (codepoint == '\t') or (codepoint == '\n')) end_line = @intCast(i);
if ((text_offset_x + glyph_width) > rec.width) {
end_line = if (end_line < 1) @intCast(i) else end_line;
if (i == end_line) end_line -= codepoint_byte_count;
if ((start_line + codepoint_byte_count) == end_line) end_line = @as(i32, @intCast(i)) - codepoint_byte_count;
state = if (state == .draw) .measure else .draw;
} else if ((i + 1) == length) {
end_line = @intCast(i);
state = if (state == .draw) .measure else .draw;
} else if (codepoint == '\n') {
state = if (state == .draw) .measure else .draw;
}
if (state == .draw) {
text_offset_x = 0;
i = @intCast(start_line);
glyph_width = 0;
// Save character position when we switch states
const tmp = last_char;
last_char = k - 1;
k = tmp;
}
} else {
if (codepoint == '\n') {
if (!word_wrap) {
const bS: f32 = @floatFromInt(font.baseSize);
text_offset_y += (bS + bS / 2) * scale_factor;
text_offset_x = 0;
}
} else {
if (!word_wrap and ((text_offset_x + glyph_width) > rec.width)) {
const bS: f32 = @floatFromInt(font.baseSize);
text_offset_y += (bS + bS / 2) * scale_factor;
text_offset_x = 0;
}
// When text overflows rectangle height limit, just stop drawing
if ((text_offset_y + @as(f32, @floatFromInt(font.baseSize)) * scale_factor) > rec.height) break;
// Draw selection background
var is_glyph_selected = false;
if ((select_start >= 0) and (k >= select_start) and (k < (select_start + select_length))) {
rl.drawRectangleRec(.{
.x = rec.x + text_offset_x - 1,
.y = rec.y + text_offset_y,
.width = glyph_width,
.height = @as(f32, @floatFromInt(font.baseSize)) * scale_factor,
}, select_back_tint);
is_glyph_selected = true;
}
// Draw current character glyph
if ((codepoint != ' ') and (codepoint != '\t')) {
rl.drawTextCodepoint(font, codepoint, .{
.x = rec.x + text_offset_x,
.y = rec.y + text_offset_y,
}, font_size, if (is_glyph_selected) select_tint else tint);
}
}
if (word_wrap and (i == end_line)) {
const bS: f32 = @floatFromInt(font.baseSize);
text_offset_y += (bS + bS / 2) * scale_factor;
text_offset_x = 0;
start_line = end_line;
end_line = -1;
glyph_width = 0;
select_start += last_char - k;
k = last_char;
state = if (state == .draw) .measure else .draw;
}
}
if ((text_offset_x != 0) or (codepoint != ' ')) text_offset_x += glyph_width; // avoid leading spaces
}
}

View File

@ -0,0 +1,46 @@
const rl = @import("raylib");
const Color = rl.Color;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
pub fn main() void {
// Initialization
//--------------------------------------------------------------------------------------
const screenWidth = 800;
const screenHeight = 450;
rl.initWindow(screenWidth, screenHeight, "raylib [text] example - text writing anim");
defer rl.closeWindow(); // Close window and OpenGL context
const message = "This sample illustrates a text writing\nanimation effect! Check it out! ;)";
var framesCounter: i32 = 0;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl.windowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
framesCounter += if (rl.isKeyDown(.space)) 8 else 1;
if (rl.isKeyPressed(.enter)) framesCounter = 0;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl.beginDrawing();
rl.clearBackground(Color.white);
rl.drawText(rl.textSubtext(message, 0, @divFloor(framesCounter, 10)), 210, 160, 20, Color.maroon);
rl.drawText("PRESS [ENTER] to RESTART!", 240, 260, 20, Color.light_gray);
rl.drawText("HOLD [SPACE] to SPEED UP!", 239, 300, 20, Color.light_gray);
rl.endDrawing();
//----------------------------------------------------------------------------------
}
}

View File

@ -17,7 +17,7 @@ pub fn main() anyerror!void {
defer rl.closeWindow(); // Close window and OpenGL context
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
const scarfy: rl.Texture = rl.Texture.init("resources/textures/scarfy.png"); // Texture loading
const scarfy = try rl.Texture.init("resources/textures/scarfy.png"); // Texture loading
defer rl.unloadTexture(scarfy); // Texture unloading
const position = rl.Vector2.init(350.0, 280.0);
@ -51,9 +51,9 @@ pub fn main() anyerror!void {
}
// Control frames speed
if (rl.isKeyPressed(rl.KeyboardKey.key_right)) {
if (rl.isKeyPressed(.right)) {
framesSpeed += 1;
} else if (rl.isKeyPressed(rl.KeyboardKey.key_left)) {
} else if (rl.isKeyPressed(.left)) {
framesSpeed -= 1;
}
@ -70,37 +70,37 @@ pub fn main() anyerror!void {
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
rl.clearBackground(.ray_white);
rl.drawTexture(scarfy, 15, 40, rl.Color.white);
rl.drawRectangleLines(15, 40, scarfy.width, scarfy.height, rl.Color.lime);
rl.drawTexture(scarfy, 15, 40, .white);
rl.drawRectangleLines(15, 40, scarfy.width, scarfy.height, .lime);
rl.drawRectangleLines(
15 + @as(i32, @intFromFloat(frameRec.x)),
40 + @as(i32, @intFromFloat(frameRec.y)),
@as(i32, @intFromFloat(frameRec.width)),
@as(i32, @intFromFloat(frameRec.height)),
rl.Color.red,
.red,
);
rl.drawText("FRAME SPEED: ", 165, 210, 10, rl.Color.dark_gray);
rl.drawText(rl.textFormat("%02i FPS", .{framesSpeed}), 575, 210, 10, rl.Color.dark_gray);
rl.drawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 240, 10, rl.Color.dark_gray);
rl.drawText("FRAME SPEED: ", 165, 210, 10, .dark_gray);
rl.drawText(rl.textFormat("%02i FPS", .{framesSpeed}), 575, 210, 10, .dark_gray);
rl.drawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 240, 10, .dark_gray);
for ([_]u32{0} ** MAX_FRAME_SPEED, 0..) |_, i| {
if (i < framesSpeed) {
rl.drawRectangle(250 + 21 * @as(i32, @intCast(i)), 205, 20, 20, rl.Color.red);
rl.drawRectangle(250 + 21 * @as(i32, @intCast(i)), 205, 20, 20, .red);
}
rl.drawRectangleLines(250 + 21 * @as(i32, @intCast(i)), 205, 20, 20, rl.Color.maroon);
rl.drawRectangleLines(250 + 21 * @as(i32, @intCast(i)), 205, 20, 20, .maroon);
}
scarfy.drawRec(frameRec, position, rl.Color.white); // Draw part of the texture
scarfy.drawRec(frameRec, position, .white); // Draw part of the texture
rl.drawText(
"(c) Scarfy sprite by Eiden Marsal",
screenWidth - 200,
screenHeight - 20,
10,
rl.Color.gray,
.gray,
);
//----------------------------------------------------------------------------------
}

View File

@ -20,9 +20,9 @@ pub fn main() anyerror!void {
// NOTE: Be careful, background width must be equal or bigger than screen width
// if not, texture should be draw more than two times for scrolling effect
const background = rl.loadTexture("resources/textures/cyberpunk_street_background.png");
const midground = rl.loadTexture("resources/textures/cyberpunk_street_midground.png");
const foreground = rl.loadTexture("resources/textures/cyberpunk_street_foreground.png");
const background = try rl.loadTexture("resources/textures/cyberpunk_street_background.png");
const midground = try rl.loadTexture("resources/textures/cyberpunk_street_midground.png");
const foreground = try rl.loadTexture("resources/textures/cyberpunk_street_foreground.png");
defer rl.unloadTexture(background); // Unload background texture
defer rl.unloadTexture(midground); // Unload midground texture
defer rl.unloadTexture(foreground); // Unload foreground texture
@ -59,49 +59,49 @@ pub fn main() anyerror!void {
// NOTE: Texture is scaled twice its size
rl.drawTextureEx(
background,
rl.Vector2.init(scrolling_back, 20.0),
.init(scrolling_back, 20.0),
0.0,
2.0,
rl.Color.white,
.white,
);
rl.drawTextureEx(
background,
rl.Vector2.init(@as(f32, @floatFromInt(background.width * 2)) + scrolling_back, 20),
.init(@as(f32, @floatFromInt(background.width * 2)) + scrolling_back, 20),
0.0,
2.0,
rl.Color.white,
.white,
);
// Draw midground image twice
rl.drawTextureEx(
midground,
rl.Vector2.init(scrolling_mid, 20.0),
.init(scrolling_mid, 20.0),
0.0,
2.0,
rl.Color.white,
.white,
);
rl.drawTextureEx(
midground,
rl.Vector2.init(@as(f32, @floatFromInt(midground.width * 2)) + scrolling_mid, 20),
.init(@as(f32, @floatFromInt(midground.width * 2)) + scrolling_mid, 20),
0.0,
2.0,
rl.Color.white,
.white,
);
// Draw foreground image twice
rl.drawTextureEx(
foreground,
rl.Vector2.init(scrolling_fore, 70.0),
.init(scrolling_fore, 70.0),
0.0,
2.0,
rl.Color.white,
.white,
);
rl.drawTextureEx(
foreground,
rl.Vector2.init(@as(f32, @floatFromInt(foreground.width * 2)) + scrolling_fore, 70),
.init(@as(f32, @floatFromInt(foreground.width * 2)) + scrolling_fore, 70),
0.0,
2.0,
rl.Color.white,
.white,
);
rl.drawText(
@ -109,14 +109,14 @@ pub fn main() anyerror!void {
10,
10,
20,
rl.Color.red,
.red,
);
rl.drawText(
"(c) Cyberpunk Street Environment by Luis Zuno (@ansimuz)",
screen_width - 330,
screen_height - 20,
10,
rl.Color.ray_white,
.ray_white,
);
}
}

View File

@ -25,16 +25,16 @@ pub fn main() anyerror!void {
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
const image = rl.loadImage("logo/logo.png"); // Loaded in CPU memory (RAM)
const texture = rl.loadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM)
const image = try rl.loadImage("logo/logo.png"); // Loaded in CPU memory (RAM)
const texture = try rl.loadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM)
// Once image has been converted to texture and uploaded to VRAM,
// it can be unloaded from RAM
rl.unloadImage(image);
// De-Initialization
//--------------------------------------------------------------------------------------
defer rl.unloadTexture(texture); // Texture unloading
defer rl.closeWindow(); // Close window and OpenGL context
defer rl.unloadTexture(texture); // Texture unloading
//--------------------------------------------------------------------------------------
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second

View File

@ -23,17 +23,99 @@ ZIGGIFY = {
"c_uint": "u32"
}
IGNORE_TYPES = [
"[*c]Color",
"[*c]GlyphInfo",
"[*c]c_int",
"[*c]c_uint",
"[*c][*c]u8",
"[*c][*c]const u8",
"[*c]Material",
"[*c]ModelAnimation",
"[*c]f32",
IGNORE_C_TYPE = [
"rlGetShaderLocsDefault",
]
TRIVIAL_SIZE = [
"LoadFileData",
"CompressData",
"DecompressData",
"EncodeDataBase64",
"DecodeDataBase64",
"ExportImageToMemory",
"LoadImagePalette",
"LoadCodepoints",
"TextSplit",
#"LoadMaterials",
"LoadModelAnimations",
]
HAS_ERROR = TRIVIAL_SIZE
MANUAL = [
"TextFormat",
"TraceLog",
"LoadShader",
"LoadRandomSequence",
"ExportDataAsCode",
"SaveFileData",
"LoadImage",
"LoadImageRaw",
"LoadImageAnim",
"LoadImageFromTexture",
"LoadImageFromScreen",
"LoadImageFromMemory",
"LoadImageColors",
"LoadMaterialDefault",
"LoadMaterials", # todo: Make this automatic, by adding a IsXValid check in this script
"LoadModel",
"LoadModelFromMesh",
"LoadTexture",
"LoadTextureFromImage",
"LoadTextureCubemap",
"LoadRenderTexture",
"LoadWave",
"LoadWaveSamples",
"LoadSound",
"LoadMusicStream",
"LoadAudioStream",
"DrawMeshInstanced",
"UnloadModelAnimations",
"ComputeCRC32",
"ComputeMD5",
"ComputeSHA1",
"SetWindowIcons",
"CheckCollisionPointPoly",
"ColorToInt",
"GetFontDefault",
"LoadFont",
"LoadFontEx",
"LoadFontFromImage",
"LoadFontData",
"ImageText",
"ImageTextEx",
"GenImageFontAtlas",
"UnloadFontData",
"DrawTextCodepoints",
"LoadUTF8",
"LoadTextLines",
"UnloadTextLines",
"TextJoin",
"DrawLineStrip",
"DrawTriangleFan",
"DrawTriangleStrip",
"DrawTriangleStrip3D",
"GuiTabBar",
"GuiListViewEx",
"GuiPanel",
"GuiScrollPanel",
"GuiButton",
"GuiLabelButton",
"GuiCheckBox",
"GuiTextBox",
"DrawSplineLinear",
"DrawSplineBasis",
"DrawSplineCatmullRom",
"DrawSplineBezierQuadratic",
"DrawSplineBezierCubic",
"ImageKernelConvolution",
"GuiGetIcons",
"GuiLoadIcons",
"GuiSetStyle",
"GuiGetStyle"
]
# Some C types have a different sizes on different systems and Zig
# knows that so we tell it to get the system specific size for us.
def c_to_zig_type(c: str) -> str:
@ -47,7 +129,9 @@ def c_to_zig_type(c: str) -> str:
return const + c
def ziggify_type(name: str, t: str, func_name) -> str:
def ziggify_type(name: str, t: str, func_name: str) -> str:
if func_name in IGNORE_C_TYPE:
return t
NO_STRINGS = ["data", "fileData", "compData"]
single = [
@ -59,24 +143,24 @@ def ziggify_type(name: str, t: str, func_name) -> str:
"AutomationEventList", "list", "batch", "glInternalFormat", "glFormat",
"glType", "mipmaps", "active", "scroll", "view", "checked", "mouseCell",
"scrollIndex", "focus", "secretViewActive", "color", "alpha", "colorHsv",
"translation", "rotation", "scale", "mat"
"translation", "rotation", "scale", "mat", "glyphCount"
]
multi = [
"data", "compData", "points", "fileData", "colors", "pixels",
"fontChars", "chars", "recs", "codepoints", "textList", "transforms",
"animations", "samples", "LoadImageColors", "LoadImagePalette",
"LoadFontData", "LoadCodepoints", "TextSplit", "LoadMaterials",
"LoadFontData", "LoadCodepoints", "LoadMaterials",
"LoadModelAnimations", "LoadWaveSamples", "images",
"LoadRandomSequence", "sequence", "kernel", "GlyphInfo", "glyphs", "glyphRecs",
"matf", "rlGetShaderLocsDefault", "locs", "GuiGetIcons", "GuiLoadIcons"
]
string = False
if name == "text" and t == "[*c][*c]const u8":
return "[][*:0]const u8"
if name == "text" and (t == "[*c][*c]const u8" or t == "[*c][*c]u8"):
return "[][:0]const u8"
if t.startswith("[*c]") and name not in single and name not in multi:
if (t == "[*c]const u8" or t == "[*c]u8") and name not in NO_STRINGS: # Strings are multis.
if (t == "[*c]const u8" or t == "[*c]u8" or name == "TextSplit") and name not in NO_STRINGS: # Strings are multis.
string = True
else:
raise ValueError(f"{t} {name} not classified")
@ -84,8 +168,10 @@ def ziggify_type(name: str, t: str, func_name) -> str:
pre = ""
while t.startswith("[*c]"):
t = t[4:]
if string and not t.startswith("[*c]"):
pre += "[*:0]"
if func_name in TRIVIAL_SIZE and not pre:
pre += "[]"
elif string and not t.startswith("[*c]"):
pre += "[:0]"
elif name in single:
pre += "*"
else:
@ -94,7 +180,11 @@ def ziggify_type(name: str, t: str, func_name) -> str:
if t in ZIGGIFY:
t = ZIGGIFY[t]
return pre + t
error = ""
if name in HAS_ERROR:
error = "RaylibError!"
return error + pre + t
def add_namespace_to_type(t: str) -> str:
@ -108,7 +198,8 @@ def add_namespace_to_type(t: str) -> str:
pre += "const "
if t.startswith("Gui"):
t = "rgui." + t
# Strip "Gui" prefix to match types in prelude
t = "rgui." + t[3:]
elif t[0].isupper():
t = "rl." + t
elif t in ["float3", "float16"]:
@ -119,21 +210,20 @@ def add_namespace_to_type(t: str) -> str:
return pre + t
def make_return_cast(source_type: str, dest_type: str, inner: str) -> str:
if source_type == dest_type:
def make_return_cast(func_name: str, source_type: str, dest_type: str, inner: str) -> str:
if source_type == dest_type or func_name in IGNORE_C_TYPE:
return inner
if source_type.startswith("[*c][*c]"):
inner = f"@as([*][:0]{source_type[8:]}, @ptrCast({inner}))"
if func_name in TRIVIAL_SIZE:
return f"{inner}[0..@as(usize, @intCast(_len))]"
if source_type in ["[*c]const u8", "[*c]u8"]:
return f"std.mem.span({inner})"
if source_type in ZIGGIFY:
return f"@as({dest_type}, {inner})"
# These all have to be done manually because their sizes depend on the
# function arguments.
if source_type in IGNORE_TYPES:
return None
else:
raise ValueError(f"Don't know what to do {source_type} {dest_type} {inner}")
raise ValueError(f"Don't know what to do with '{func_name}': {source_type} {dest_type} {inner}")
def fix_pointer(name: str, t: str):
@ -173,9 +263,10 @@ _fix_enums_data = [
("flag", "ConfigFlags", r"IsWindowState"),
("flags", "Gesture", r"SetGesturesEnabled"),
("button", "GamepadButton", r".*GamepadButton.*"),
("axis", "GamepadAxis", r".*GamepadAxis.*"),
("button", "MouseButton", r".*MouseButton.*"),
("control", "GuiControl", r"Gui.etStyle"),
# ("property", "GuiControlProperty", r"Gui.etStyle"),
("control", "GuiControl", r"Gui.etStyle"), # "Gui" prefix needed here for type parsing later
# ("property", "GuiControlProperty", r"Gui.etStyle"), # "Gui" prefix needed here for type parsing later
]
def fix_enums(arg_name, arg_type, func_name):
if func_name.startswith("rl"):
@ -190,8 +281,12 @@ def fix_enums(arg_name, arg_type, func_name):
return arg_type
def convert_name_case(name):
return name[:1].lower() + name[1:] if name else ''
def convert_name(name):
if not name:
return ''
if name.startswith("Gui"):
name = name[3:]
return name[:1].lower() + name[1:]
def parse_header(header_name: str, output_file: str, ext_file: str, prefix: str, prelude_file: str, ext_prelude_file: str, skip_after: str = "#/never\\#"):
@ -271,6 +366,8 @@ def parse_header(header_name: str, output_file: str, ext_file: str, prefix: str,
if not arguments:
arguments = "void"
zig_name = convert_name(func_name)
for arg in arguments.split(", "):
if arg == "void":
break
@ -289,6 +386,9 @@ def parse_header(header_name: str, output_file: str, ext_file: str, prefix: str,
arg_type = c_to_zig_type(arg_type)
arg_name, arg_type = fix_pointer(arg_name, arg_type)
if arg_name == zig_name:
arg_name += "_"
single_opt = [
("rlDrawVertexArrayElements", "buffer"),
("rlDrawVertexArrayElementsInstanced", "buffer"),
@ -299,6 +399,7 @@ def parse_header(header_name: str, output_file: str, ext_file: str, prefix: str,
("rlLoadShaderBuffer", "data"),
("rlLoadShaderCode", "vsCode"),
("rlLoadShaderCode", "fsCode"),
("GuiTextInputBox", "secretViewActive")
]
zig_type = ziggify_type(arg_name, arg_type, func_name)
@ -323,61 +424,34 @@ def parse_header(header_name: str, output_file: str, ext_file: str, prefix: str,
ext_ret = add_namespace_to_type(return_type)
ext_heads.append(f"pub extern \"c\" fn {func_name}({zig_c_arguments}) {ext_ret};")
zig_name = convert_name_case(func_name)
func_prelude = ""
if func_name in TRIVIAL_SIZE:
zig_arguments.pop()
zig_call_args[-1] = "@as([*c]c_int, @ptrCast(&_len))"
func_prelude = "var _len: i32 = 0;\n "
# TODO: Ziggify return type
zig_arguments = ", ".join(zig_arguments)
zig_call_args = ", ".join(zig_call_args)
manual = [
"TextFormat",
"LoadShader",
"ExportDataAsCode",
"LoadFileData",
"SaveFileData",
"ExportDataAsCode",
"LoadImageFromMemory",
"DrawMeshInstanced",
"UnloadModelAnimations",
"CompressData",
"DecompressData",
"EncodeDataBase64",
"DecodeDataBase64",
"SetWindowIcons",
"CheckCollisionPointPoly",
"LoadFontEx",
"GenImageFontAtlas",
"UnloadFontData",
"DrawTextCodepoints",
"LoadUTF8",
"TextJoin",
"DrawLineStrip",
"DrawTriangleFan",
"DrawTriangleStrip",
"DrawTriangleStrip3D",
"GuiTabBar",
"GuiListViewEx",
"GuiPanel",
"GuiScrollPanel",
"DrawSplineLinear",
"DrawSplineBasis",
"DrawSplineCatmullRom",
"DrawSplineBezierQuadratic",
"DrawSplineBezierCubic",
"ImageKernelConvolution"
]
if func_name in manual or "FromMemory" in func_name:
if func_name in MANUAL or "FromMemory" in func_name:
continue
inner = f"cdef.{func_name}({zig_call_args})"
if func_name in TRIVIAL_SIZE:
func_prelude += f"const _ptr = {inner};\n if (_ptr == 0) return RaylibError.{func_name};\n "
inner = "_ptr"
zig_return = ziggify_type(func_name, return_type, func_name)
return_cast = make_return_cast(return_type, zig_return, f"cdef.{func_name}({zig_call_args})")
return_cast = make_return_cast(func_name, return_type, zig_return, inner)
if return_cast:
zig_funcs.append(
inline_comment +
f"pub fn {zig_name}({zig_arguments}) {zig_return}" +
" {\n " +
func_prelude +
("return " if zig_return != "void" else "") +
return_cast + ";"
"\n}"

Some files were not shown because too many files have changed in this diff Show More