Merge branch 'raysan5:master' into test

This commit is contained in:
MULTi 2025-12-28 22:24:43 +05:30 committed by GitHub
commit b0ea362bcb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
204 changed files with 20521 additions and 5229 deletions

View File

@ -22,7 +22,7 @@ jobs:
- name: Diff parse files
id: diff
run: |
git add -N tools/rlparser
git add -N tools/rlparser/output
git diff --name-only --exit-code
continue-on-error: true
@ -32,6 +32,6 @@ jobs:
set -x
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add tools/rlparser
git add tools/rlparser/output
git commit -m "rlparser: update raylib_api.* by CI"
git push

View File

@ -29,8 +29,9 @@ jobs:
shell: bash
- name: Build and run rexm tool (requires GNU Makefile)
# "rexm update" validates and updates all required examples in raylib and even raylib.com repos,
# note that it calls examples/Makefile.Web internally, so it requires [make] tool available
# "rexm validate" validates examples collection, looking for inconsistencies, it does not rebuild examples
# "rexm update" validates and updates all examples with inconsistencies, pushing fixes to raylib and raylib.com repos
# note that rexm calls examples/Makefile.Web internally, so it requires [make] tool available
run: |
sudo apt-get update && sudo apt-get install -y libopengl0 libglu1-mesa libx11-dev libxrandr-dev libxcursor-dev libxi-dev libxinerama-dev libgl1-mesa-dev libglu1-mesa-dev
cd "${{ github.workspace }}/src"
@ -47,7 +48,7 @@ jobs:
export REXM_EXAMPLES_COLLECTION_FILE_PATH="${{ github.workspace }}/examples/examples_list.txt"
export REXM_EXAMPLES_VS2022_SLN_FILE="${{ github.workspace }}/projects/VS2022/raylib.sln"
export EMSDK_PATH="${{ github.workspace }}/emsdk-cache/emsdk-main"
./rexm update
./rexm validate
shell: bash
- name: Commit changes to raylib repo (DISABLED)

12
.gitignore vendored
View File

@ -58,14 +58,23 @@ packages/
*.h.pch
./*.obj
# Ignore SDL libs for testing
src/external/SDL2
src/external/SDL3
# Emscripten
emsdk
# Ignore wasm data in examples/
examples/**/*
!examples/**/*.*
!examples/**/*/
examples/**/*.exe
examples/**/*.wasm
examples/**/*.data
examples/**/*.js
examples/**/*.html
examples/**/logs/*
# Ignore files build by xcode
*.mode*v*
@ -115,7 +124,8 @@ build-*/
docgen_tmp/
# Tools stuff
tools/parser/raylib_parser
tools/parser/rlparser.exe
tools/parser/rlparser
tools/rexm/rexm.exe
tools/rexm/rexm

View File

@ -29,8 +29,10 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [dray](https://github.com/redthing1/dray) | **5.0** | [D](https://dlang.org) | Apache-2.0 |
| [raylib-d](https://github.com/schveiguy/raylib-d) | **5.5** | [D](https://dlang.org) | Zlib |
| [rayex](https://github.com/shiryel/rayex) | 3.7 | [elixir](https://elixir-lang.org) | Apache-2.0 |
| [raylib-elle](https://github.com/acquitelol/elle/blob/rewrite/std/raylib.le) | **5.5** | [Elle](https://github.com/acquitelol/elle) | GPL-3.0 |
| [raylib-factor](https://github.com/factor/factor/blob/master/extra/raylib/raylib.factor) | 4.5 | [Factor](https://factorcode.org) | BSD |
| [raylib-freebasic](https://github.com/WIITD/raylib-freebasic) | **5.0** | [FreeBASIC](https://www.freebasic.net) | MIT |
| [raylib.f](https://github.com/cthulhuology/raylib.f) | **5.5** | [Forth](https://forth.com) | Zlib |
| [fortran-raylib](https://github.com/interkosmos/fortran-raylib) | **5.5** | [Fortran](https://fortran-lang.org) | ISC |
| [raylib-go](https://github.com/gen2brain/raylib-go) | **5.5** | [Go](https://golang.org) | Zlib |
| [raylib-guile](https://github.com/petelliott/raylib-guile) | **auto** | [Guile](https://www.gnu.org/software/guile) | Zlib |
@ -74,6 +76,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-rs](https://github.com/raylib-rs/raylib-rs) | **5.5** | [Rust](https://www.rust-lang.org) | Zlib |
| [raylib-ruby](https://github.com/wilsonsilva/raylib-ruby) | 4.5 | [Ruby](https://www.ruby-lang.org) | Zlib |
| [Relib](https://github.com/RedCubeDev-ByteSpace/Relib) | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | **???** |
| [ringraylib5](https://github.com/ring-lang/ring/tree/master/extensions/ringraylib5) | **5.0** | [Ring](https://ring-lang.github.io/) | **???** |
| [racket-raylib](https://github.com/eutro/racket-raylib) | **5.5** | [Racket](https://racket-lang.org) | MIT/Apache-2.0 |
| [raylib-swift](https://github.com/STREGAsGate/Raylib) | 4.0 | [Swift](https://swift.org) | MIT |
| [raylib-scopes](https://github.com/salotz/raylib-scopes) | auto | [Scopes](http://scopes.rocks) | MIT |

View File

@ -565,7 +565,7 @@ Detailed changes:
[rtext] ADDED: SetTextLineSpacing() to define line breaks text drawing spacing by @raysan5
[rtext] RENAMED: LoadFont*() parameter names for consistency and coherence by @raysan5
[rtext] REVIEWED: GetCodepointCount(), ignore unused return value of GetCodepointNext by @ashn-dot-dev
[rtext] REVIEWED: TextFormat() warn user if buffer overflow occured (#3399) by @Murlocohol
[rtext] REVIEWED: TextFormat() warn user if buffer overflow occurred (#3399) by @Murlocohol
[rtext] REVIEWED: TextFormat(), added "..." for truncation (#3366) by @raysan5
[rtext] REVIEWED: GetGlyphIndex() (#3000) by @raysan5
[rtext] REVIEWED: GetCodepointNext() to return default value by @chocolate42

View File

@ -6,7 +6,7 @@ if(EMSCRIPTEN)
# When configuring web builds with "emcmake cmake -B build -S .", set PLATFORM to Web by default
SET(PLATFORM Web CACHE STRING "Platform to build for.")
endif()
enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM;SDL" "Platform to build for.")
enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM;SDL;RGFW" "Platform to build for.")
enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0;Software" "Force a specific OpenGL Version?")

View File

@ -41,6 +41,7 @@ while (!WindowShouldClose())
}
// Always use accumulators as `x++` instead of `++x`
for (int i = 0; i < NUM_VALUES; i++) printf("%i", i);
// Be careful with the switch formatting!

View File

@ -140,7 +140,7 @@ contributors
------------
<a href="https://github.com/raysan5/raylib/graphs/contributors">
<img src="https://contrib.rocks/image?repo=raysan5/raylib&max=500&columns=20&anon=1" />
<img src="https://contrib.rocks/image?repo=raysan5/raylib&max=800&columns=24&anon=0" />
</a>
license

18
SECURITY.md Normal file
View File

@ -0,0 +1,18 @@
# Security Policy
## Supported Versions
Most considerations of errors and defects can be handled using the project Issues and/or Discussions.
| Version | Supported |
| ------- | ------------------ |
| 6.0.x | :white_check_mark: |
| < 5.5 | :x: |
## Reporting a Vulnerability
Discovered vulnerability can be directly reported using the project Issues and/or Discussions.
_TODO: Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc._

View File

@ -106,9 +106,9 @@ const config_h_flags = outer: {
if (std.mem.startsWith(u8, line, "//")) continue;
if (std.mem.startsWith(u8, line, "#if")) continue;
var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace
var flag = std.mem.trimStart(u8, line, " \t"); // Trim whitespace
flag = flag["#define ".len - 1 ..]; // Remove #define
flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace
flag = std.mem.trimStart(u8, flag, " \t"); // Trim whitespace
flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space
flag = "-D" ++ flag; // Prepend with -D
@ -155,9 +155,9 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
);
}
// Sets a flag indiciating the use of a custom `config.h`
try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
if (options.config.len > 0) {
// Sets a flag indicating the use of a custom `config.h`
try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
// Splits a space-separated list of config flags into multiple flags
//
// Note: This means certain flags like `-x c++` won't be processed properly.
@ -187,13 +187,13 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
try raylib_flags_arr.append(b.allocator, flag);
}
} else {
// Set default config if no custome config got set
// Set default config if no custom config got set
try raylib_flags_arr.appendSlice(b.allocator, &config_h_flags);
}
// No GLFW required on PLATFORM_DRM
if (options.platform != .drm) {
raylib.addIncludePath(b.path("src/external/glfw/include"));
raylib.root_module.addIncludePath(b.path("src/external/glfw/include"));
}
var c_source_files: std.ArrayList([]const u8) = try .initCapacity(b.allocator, 2);
@ -224,7 +224,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
raylib.root_module.addCMacro(options.opengl_version.toCMacroStr(), "");
}
raylib.addIncludePath(b.path("src/platforms"));
raylib.root_module.addIncludePath(b.path("src/platforms"));
switch (target.result.os.tag) {
.windows => {
switch (options.platform) {
@ -438,7 +438,7 @@ pub const Options = struct {
pub fn getOptions(b: *std.Build) Options {
return .{
.platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform,
.platform = b.option(PlatformBackend, "platform", "Choose the platform backend for desktop target") 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,

View File

@ -141,6 +141,8 @@ elseif ("${PLATFORM}" MATCHES "SDL")
add_compile_definitions(USING_SDL2_PACKAGE)
endif()
endif()
elseif ("${PLATFORM}" MATCHES "RGFW")
set(PLATFORM_CPP "PLATFORM_DESKTOP_RGFW")
endif ()
if (NOT ${OPENGL_VERSION} MATCHES "OFF")

View File

@ -231,7 +231,7 @@ endif
# -Wno-missing-braces ignore invalid warning (GCC bug 53119)
# -Wno-unused-value ignore unused return values of some functions (i.e. fread())
# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
CFLAGS = -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Wunused-result
CFLAGS = -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Wno-unused-result
ifeq ($(BUILD_MODE),DEBUG)
CFLAGS += -g -D_DEBUG
@ -486,7 +486,19 @@ endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
# Libraries for DRM compiling
# NOTE: Required packages: libasound2-dev (ALSA)
LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lgbm -ldrm -ldl -latomic
LDLIBS = -lraylib -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl -latomic
# TODO: Examples compilation does not define GRAPHICS, is it required?
#ifeq ($(GRAPHICS),GRAPHICS_API_OPENGL_ES2)
# LDLIBS += -lGLESv2 -lEGL
#endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
# Libraries for Windows desktop compilation
LDFLAGS += -L..\src
LDLIBS = -lraylib -lgdi32 -lwinmm -lshcore
ifneq ($(GRAPHICS),GRAPHICS_API_OPENGL_11_SOFTWARE)
LDLIBS += -lopengl32
endif
endif
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
# Libraries for web (HTML5) compiling
@ -513,12 +525,13 @@ CORE = \
core/core_basic_screen_manager \
core/core_basic_window \
core/core_clipboard_text \
core/core_compute_hash \
core/core_custom_frame_control \
core/core_custom_logging \
core/core_delta_time \
core/core_directory_files \
core/core_drop_files \
core/core_high_dpi \
core/core_highdpi_demo \
core/core_highdpi_testbed \
core/core_input_actions \
core/core_input_gamepad \
@ -539,6 +552,7 @@ CORE = \
core/core_storage_values \
core/core_text_file_loading \
core/core_undo_redo \
core/core_viewport_scaling \
core/core_vr_simulator \
core/core_window_flags \
core/core_window_letterbox \
@ -546,6 +560,7 @@ CORE = \
core/core_world_screen
SHAPES = \
shapes/shapes_ball_physics \
shapes/shapes_basic_shapes \
shapes/shapes_bouncing_ball \
shapes/shapes_bullet_hell \
@ -568,11 +583,14 @@ SHAPES = \
shapes/shapes_math_angle_rotation \
shapes/shapes_math_sine_cosine \
shapes/shapes_mouse_trail \
shapes/shapes_penrose_tile \
shapes/shapes_pie_chart \
shapes/shapes_rectangle_advanced \
shapes/shapes_rectangle_scaling \
shapes/shapes_recursive_tree \
shapes/shapes_ring_drawing \
shapes/shapes_rlgl_color_wheel \
shapes/shapes_rlgl_triangle \
shapes/shapes_rounded_rectangle_drawing \
shapes/shapes_simple_particles \
shapes/shapes_splines_drawing \
@ -585,6 +603,7 @@ TEXTURES = \
textures/textures_background_scrolling \
textures/textures_blend_modes \
textures/textures_bunnymark \
textures/textures_cellular_automata \
textures/textures_fog_of_war \
textures/textures_gif_player \
textures/textures_image_channel \
@ -601,9 +620,11 @@ TEXTURES = \
textures/textures_particles_blending \
textures/textures_polygon_drawing \
textures/textures_raw_data \
textures/textures_screen_buffer \
textures/textures_sprite_animation \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
textures/textures_sprite_stacking \
textures/textures_srcrec_dstrec \
textures/textures_textured_curve \
textures/textures_tiled_drawing \
@ -621,6 +642,7 @@ TEXT = \
text/text_input_box \
text/text_rectangle_bounds \
text/text_sprite_fonts \
text/text_strings_management \
text/text_unicode_emojis \
text/text_unicode_ranges \
text/text_words_alignment \
@ -635,6 +657,7 @@ MODELS = \
models/models_box_collisions \
models/models_cubicmap_rendering \
models/models_decals \
models/models_directional_billboard \
models/models_first_person_maze \
models/models_geometric_shapes \
models/models_heightmap_rendering \
@ -665,6 +688,7 @@ SHADERS = \
shaders/shaders_depth_writing \
shaders/shaders_eratosthenes_sieve \
shaders/shaders_fog_rendering \
shaders/shaders_game_of_life \
shaders/shaders_hot_reloading \
shaders/shaders_hybrid_rendering \
shaders/shaders_julia_set \
@ -696,6 +720,7 @@ AUDIO = \
audio/audio_sound_loading \
audio/audio_sound_multi \
audio/audio_sound_positioning \
audio/audio_spectrum_visualizer \
audio/audio_stream_effects
OTHERS = \

View File

@ -130,7 +130,7 @@ ifeq ($(ANDROID_ARCH),ARM)
CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
endif
ifeq ($(ANDROID_ARCH),ARM64)
CFLAGS = -std=c99 -target aarch64 -mfix-cortex-a53-835769
CFLAGS = -std=c99 -mfix-cortex-a53-835769
endif
# Compilation functions attributes options
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC

View File

@ -513,12 +513,13 @@ CORE = \
core/core_basic_screen_manager \
core/core_basic_window \
core/core_clipboard_text \
core/core_compute_hash \
core/core_custom_frame_control \
core/core_custom_logging \
core/core_delta_time \
core/core_directory_files \
core/core_drop_files \
core/core_high_dpi \
core/core_highdpi_demo \
core/core_highdpi_testbed \
core/core_input_actions \
core/core_input_gamepad \
@ -539,6 +540,7 @@ CORE = \
core/core_storage_values \
core/core_text_file_loading \
core/core_undo_redo \
core/core_viewport_scaling \
core/core_vr_simulator \
core/core_window_flags \
core/core_window_letterbox \
@ -546,6 +548,7 @@ CORE = \
core/core_world_screen
SHAPES = \
shapes/shapes_ball_physics \
shapes/shapes_basic_shapes \
shapes/shapes_bouncing_ball \
shapes/shapes_bullet_hell \
@ -568,11 +571,14 @@ SHAPES = \
shapes/shapes_math_angle_rotation \
shapes/shapes_math_sine_cosine \
shapes/shapes_mouse_trail \
shapes/shapes_penrose_tile \
shapes/shapes_pie_chart \
shapes/shapes_rectangle_advanced \
shapes/shapes_rectangle_scaling \
shapes/shapes_recursive_tree \
shapes/shapes_ring_drawing \
shapes/shapes_rlgl_color_wheel \
shapes/shapes_rlgl_triangle \
shapes/shapes_rounded_rectangle_drawing \
shapes/shapes_simple_particles \
shapes/shapes_splines_drawing \
@ -585,6 +591,7 @@ TEXTURES = \
textures/textures_background_scrolling \
textures/textures_blend_modes \
textures/textures_bunnymark \
textures/textures_cellular_automata \
textures/textures_fog_of_war \
textures/textures_gif_player \
textures/textures_image_channel \
@ -601,9 +608,11 @@ TEXTURES = \
textures/textures_particles_blending \
textures/textures_polygon_drawing \
textures/textures_raw_data \
textures/textures_screen_buffer \
textures/textures_sprite_animation \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
textures/textures_sprite_stacking \
textures/textures_srcrec_dstrec \
textures/textures_textured_curve \
textures/textures_tiled_drawing \
@ -621,6 +630,7 @@ TEXT = \
text/text_input_box \
text/text_rectangle_bounds \
text/text_sprite_fonts \
text/text_strings_management \
text/text_unicode_emojis \
text/text_unicode_ranges \
text/text_words_alignment \
@ -635,6 +645,7 @@ MODELS = \
models/models_box_collisions \
models/models_cubicmap_rendering \
models/models_decals \
models/models_directional_billboard \
models/models_first_person_maze \
models/models_geometric_shapes \
models/models_heightmap_rendering \
@ -665,6 +676,7 @@ SHADERS = \
shaders/shaders_depth_writing \
shaders/shaders_eratosthenes_sieve \
shaders/shaders_fog_rendering \
shaders/shaders_game_of_life \
shaders/shaders_hot_reloading \
shaders/shaders_hybrid_rendering \
shaders/shaders_julia_set \
@ -696,6 +708,7 @@ AUDIO = \
audio/audio_sound_loading \
audio/audio_sound_multi \
audio/audio_sound_positioning \
audio/audio_spectrum_visualizer \
audio/audio_stream_effects
# Default target entry
@ -752,6 +765,9 @@ core/core_basic_window: core/core_basic_window.c
core/core_clipboard_text: core/core_clipboard_text.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_compute_hash: core/core_compute_hash.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_custom_frame_control: core/core_custom_frame_control.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@ -767,7 +783,7 @@ core/core_directory_files: core/core_directory_files.c
core/core_drop_files: core/core_drop_files.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_high_dpi: core/core_high_dpi.c
core/core_highdpi_demo: core/core_highdpi_demo.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_highdpi_testbed: core/core_highdpi_testbed.c
@ -833,6 +849,9 @@ core/core_text_file_loading: core/core_text_file_loading.c
core/core_undo_redo: core/core_undo_redo.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_viewport_scaling: core/core_viewport_scaling.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_vr_simulator: core/core_vr_simulator.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file core/resources/shaders/glsl100/distortion.fs@resources/shaders/glsl100/distortion.fs
@ -850,6 +869,9 @@ core/core_world_screen: core/core_world_screen.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
# Compile SHAPES examples
shapes/shapes_ball_physics: shapes/shapes_ball_physics.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
shapes/shapes_basic_shapes: shapes/shapes_basic_shapes.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@ -916,6 +938,9 @@ shapes/shapes_math_sine_cosine: shapes/shapes_math_sine_cosine.c
shapes/shapes_mouse_trail: shapes/shapes_mouse_trail.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
shapes/shapes_penrose_tile: shapes/shapes_penrose_tile.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
shapes/shapes_pie_chart: shapes/shapes_pie_chart.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@ -931,6 +956,12 @@ shapes/shapes_recursive_tree: shapes/shapes_recursive_tree.c
shapes/shapes_ring_drawing: shapes/shapes_ring_drawing.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
shapes/shapes_rlgl_color_wheel: shapes/shapes_rlgl_color_wheel.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
shapes/shapes_rlgl_triangle: shapes/shapes_rlgl_triangle.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
shapes/shapes_rounded_rectangle_drawing: shapes/shapes_rounded_rectangle_drawing.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@ -966,7 +997,10 @@ textures/textures_blend_modes: textures/textures_blend_modes.c
textures/textures_bunnymark: textures/textures_bunnymark.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/wabbit_alpha.png@resources/wabbit_alpha.png
--preload-file textures/resources/raybunny.png@resources/raybunny.png
textures/textures_cellular_automata: textures/textures_cellular_automata.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
textures/textures_fog_of_war: textures/textures_fog_of_war.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@ -1032,6 +1066,9 @@ textures/textures_raw_data: textures/textures_raw_data.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/fudesumi.raw@resources/fudesumi.raw
textures/textures_screen_buffer: textures/textures_screen_buffer.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
textures/textures_sprite_animation: textures/textures_sprite_animation.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/scarfy.png@resources/scarfy.png
@ -1046,6 +1083,10 @@ textures/textures_sprite_explosion: textures/textures_sprite_explosion.c
--preload-file textures/resources/boom.wav@resources/boom.wav \
--preload-file textures/resources/explosion.png@resources/explosion.png
textures/textures_sprite_stacking: textures/textures_sprite_stacking.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/booth.png@resources/booth.png
textures/textures_srcrec_dstrec: textures/textures_srcrec_dstrec.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/scarfy.png@resources/scarfy.png
@ -1112,6 +1153,9 @@ text/text_sprite_fonts: text/text_sprite_fonts.c
--preload-file text/resources/sprite_fonts/alpha_beta.png@resources/sprite_fonts/alpha_beta.png \
--preload-file text/resources/sprite_fonts/jupiter_crash.png@resources/sprite_fonts/jupiter_crash.png
text/text_strings_management: text/text_strings_management.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
text/text_unicode_emojis: text/text_unicode_emojis.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file text/resources/dejavu.fnt@resources/dejavu.fnt \
@ -1172,6 +1216,10 @@ models/models_decals: models/models_decals.c
--preload-file models/resources/models/obj/character_diffuse.png@resources/models/obj/character_diffuse.png \
--preload-file models/resources/raylib_logo.png@resources/raylib_logo.png
models/models_directional_billboard: models/models_directional_billboard.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file models/resources/skillbot.png@resources/skillbot.png
models/models_first_person_maze: models/models_first_person_maze.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file models/resources/cubicmap.png@resources/cubicmap.png \
@ -1316,6 +1364,19 @@ shaders/shaders_fog_rendering: shaders/shaders_fog_rendering.c
--preload-file shaders/resources/shaders/glsl100/lighting.vs@resources/shaders/glsl100/lighting.vs \
--preload-file shaders/resources/shaders/glsl100/fog.fs@resources/shaders/glsl100/fog.fs
shaders/shaders_game_of_life: shaders/shaders_game_of_life.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file shaders/resources/shaders/glsl100/game_of_life.fs@resources/shaders/glsl100/game_of_life.fs \
--preload-file shaders/resources/game_of_life/acorn.png@resources/game_of_life/acorn.png \
--preload-file shaders/resources/game_of_life/breeder.png@resources/game_of_life/breeder.png \
--preload-file shaders/resources/game_of_life/glider.png@resources/game_of_life/glider.png \
--preload-file shaders/resources/game_of_life/glider_gun.png@resources/game_of_life/glider_gun.png \
--preload-file shaders/resources/game_of_life/oscillators.png@resources/game_of_life/oscillators.png \
--preload-file shaders/resources/game_of_life/puffer_train.png@resources/game_of_life/puffer_train.png \
--preload-file shaders/resources/game_of_life/r_pentomino.png@resources/game_of_life/r_pentomino.png \
--preload-file shaders/resources/game_of_life/spaceships.png@resources/game_of_life/spaceships.png \
--preload-file shaders/resources/game_of_life/still_lifes.png@resources/game_of_life/still_lifes.png
shaders/shaders_hot_reloading: shaders/shaders_hot_reloading.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file shaders/resources/shaders/glsl100/reload.fs@resources/shaders/glsl100/reload.fs
@ -1468,6 +1529,11 @@ audio/audio_sound_positioning: audio/audio_sound_positioning.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file audio/resources/coin.wav@resources/coin.wav
audio/audio_spectrum_visualizer: audio/audio_spectrum_visualizer.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file audio/resources/shaders/glsl100/fft.fs@resources/shaders/glsl100/fft.fs \
--preload-file audio/resources/country.mp3@resources/country.mp3
audio/audio_stream_effects: audio/audio_stream_effects.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file audio/resources/country.mp3@resources/country.mp3

View File

@ -17,11 +17,11 @@ You may find it easier to use than other toolchains, especially when it comes to
- `zig build [module]` to compile all examples for a module (e.g. `zig build core`)
- `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`)
## EXAMPLES COLLECTION [TOTAL: 192]
## EXAMPLES COLLECTION [TOTAL: 205]
### category: core [45]
### category: core [47]
Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality.
Examples using raylib [core](../src/rcore.c) module platform functionality: window creation, inputs, drawing modes and system functionality.
| example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
@ -43,7 +43,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c
| [core_3d_camera_free](core/core_3d_camera_free.c) | <img src="core/core_3d_camera_free.png" alt="core_3d_camera_free" width="80"> | ⭐☆☆☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_3d_camera_first_person](core/core_3d_camera_first_person.c) | <img src="core/core_3d_camera_first_person.png" alt="core_3d_camera_first_person" width="80"> | ⭐⭐☆☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_3d_camera_split_screen](core/core_3d_camera_split_screen.c) | <img src="core/core_3d_camera_split_screen.png" alt="core_3d_camera_split_screen" width="80"> | ⭐⭐⭐☆ | 3.7 | 4.0 | [Jeffery Myers](https://github.com/JeffM2501) |
| [core_3d_camera_fps](core/core_3d_camera_fps.c) | <img src="core/core_3d_camera_fps.png" alt="core_3d_camera_fps" width="80"> | ⭐⭐⭐☆ | 5.5 | 5.5 | [Agnis Aldins](https://github.com/nezvers) |
| [core_3d_camera_fps](core/core_3d_camera_fps.c) | <img src="core/core_3d_camera_fps.png" alt="core_3d_camera_fps" width="80"> | ⭐⭐⭐☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) |
| [core_3d_picking](core/core_3d_picking.c) | <img src="core/core_3d_picking.png" alt="core_3d_picking" width="80"> | ⭐⭐☆☆ | 1.3 | 4.0 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_world_screen](core/core_world_screen.c) | <img src="core/core_world_screen.png" alt="core_world_screen" width="80"> | ⭐⭐☆☆ | 1.3 | 1.4 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_window_flags](core/core_window_flags.c) | <img src="core/core_window_flags.png" alt="core_window_flags" width="80"> | ⭐⭐⭐☆ | 3.5 | 3.5 | [Ramon Santamaria](https://github.com/raysan5) |
@ -61,17 +61,19 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c
| [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) | <img src="core/core_smooth_pixelperfect.png" alt="core_smooth_pixelperfect" width="80"> | ⭐⭐⭐☆ | 3.7 | 4.0 | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) |
| [core_random_sequence](core/core_random_sequence.c) | <img src="core/core_random_sequence.png" alt="core_random_sequence" width="80"> | ⭐☆☆☆ | 5.0 | 5.0 | [Dalton Overmyer](https://github.com/REDl3east) |
| [core_automation_events](core/core_automation_events.c) | <img src="core/core_automation_events.png" alt="core_automation_events" width="80"> | ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_high_dpi](core/core_high_dpi.c) | <img src="core/core_high_dpi.png" alt="core_high_dpi" width="80"> | ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) |
| [core_highdpi_demo](core/core_highdpi_demo.c) | <img src="core/core_highdpi_demo.png" alt="core_highdpi_demo" width="80"> | ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) |
| [core_render_texture](core/core_render_texture.c) | <img src="core/core_render_texture.png" alt="core_render_texture" width="80"> | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_undo_redo](core/core_undo_redo.c) | <img src="core/core_undo_redo.png" alt="core_undo_redo" width="80"> | ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_viewport_scaling](core/core_viewport_scaling.c) | <img src="core/core_viewport_scaling.png" alt="core_viewport_scaling" width="80"> | ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) |
| [core_input_actions](core/core_input_actions.c) | <img src="core/core_input_actions.png" alt="core_input_actions" width="80"> | ⭐⭐☆☆ | 5.5 | 5.6 | [Jett](https://github.com/JettMonstersGoBoom) |
| [core_directory_files](core/core_directory_files.c) | <img src="core/core_directory_files.png" alt="core_directory_files" width="80"> | ⭐☆☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) |
| [core_highdpi_testbed](core/core_highdpi_testbed.c) | <img src="core/core_highdpi_testbed.png" alt="core_highdpi_testbed" width="80"> | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_screen_recording](core/core_screen_recording.c) | <img src="core/core_screen_recording.png" alt="core_screen_recording" width="80"> | ⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_clipboard_text](core/core_clipboard_text.c) | <img src="core/core_clipboard_text.png" alt="core_clipboard_text" width="80"> | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
| [core_screen_recording](core/core_screen_recording.c) | <img src="core/core_screen_recording.png" alt="core_screen_recording" width="80"> | ⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_clipboard_text](core/core_clipboard_text.c) | <img src="core/core_clipboard_text.png" alt="core_clipboard_text" width="80"> | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ananth S](https://github.com/Ananth1839) |
| [core_text_file_loading](core/core_text_file_loading.c) | <img src="core/core_text_file_loading.png" alt="core_text_file_loading" width="80"> | ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) |
| [core_compute_hash](core/core_compute_hash.c) | <img src="core/core_compute_hash.png" alt="core_compute_hash" width="80"> | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
### category: shapes [34]
### category: shapes [38]
Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module.
@ -111,8 +113,12 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
| [shapes_starfield_effect](shapes/shapes_starfield_effect.c) | <img src="shapes/shapes_starfield_effect.png" alt="shapes_starfield_effect" width="80"> | ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
| [shapes_lines_drawing](shapes/shapes_lines_drawing.c) | <img src="shapes/shapes_lines_drawing.png" alt="shapes_lines_drawing" width="80"> | ⭐☆☆☆ | 5.6-dev | 5.6 | [Robin](https://github.com/RobinsAviary) |
| [shapes_math_angle_rotation](shapes/shapes_math_angle_rotation.c) | <img src="shapes/shapes_math_angle_rotation.png" alt="shapes_math_angle_rotation" width="80"> | ⭐☆☆☆ | 5.6-dev | 5.6 | [Kris](https://github.com/krispy-snacc) |
| [shapes_rlgl_color_wheel](shapes/shapes_rlgl_color_wheel.c) | <img src="shapes/shapes_rlgl_color_wheel.png" alt="shapes_rlgl_color_wheel" width="80"> | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
| [shapes_rlgl_triangle](shapes/shapes_rlgl_triangle.c) | <img src="shapes/shapes_rlgl_triangle.png" alt="shapes_rlgl_triangle" width="80"> | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
| [shapes_ball_physics](shapes/shapes_ball_physics.c) | <img src="shapes/shapes_ball_physics.png" alt="shapes_ball_physics" width="80"> | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) |
| [shapes_penrose_tile](shapes/shapes_penrose_tile.c) | <img src="shapes/shapes_penrose_tile.png" alt="shapes_penrose_tile" width="80"> | ⭐⭐⭐⭐️ | 5.5 | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) |
### category: textures [26]
### category: textures [29]
Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/rtextures.c) module.
@ -143,9 +149,12 @@ Examples using raylib textures functionality, including image/textures loading/g
| [textures_image_kernel](textures/textures_image_kernel.c) | <img src="textures/textures_image_kernel.png" alt="textures_image_kernel" width="80"> | ⭐⭐⭐⭐️ | 1.3 | 1.3 | [Karim Salem](https://github.com/kimo-s) |
| [textures_image_channel](textures/textures_image_channel.c) | <img src="textures/textures_image_channel.png" alt="textures_image_channel" width="80"> | ⭐⭐☆☆ | 5.5 | 5.5 | [Bruno Cabral](https://github.com/brccabral) |
| [textures_image_rotate](textures/textures_image_rotate.c) | <img src="textures/textures_image_rotate.png" alt="textures_image_rotate" width="80"> | ⭐⭐☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) |
| [textures_screen_buffer](textures/textures_screen_buffer.c) | <img src="textures/textures_screen_buffer.png" alt="textures_screen_buffer" width="80"> | ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) |
| [textures_textured_curve](textures/textures_textured_curve.c) | <img src="textures/textures_textured_curve.png" alt="textures_textured_curve" width="80"> | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) |
| [textures_sprite_stacking](textures/textures_sprite_stacking.c) | <img src="textures/textures_sprite_stacking.png" alt="textures_sprite_stacking" width="80"> | ⭐⭐☆☆ | 5.6-dev | 6.0 | [Robin](https://github.com/RobinsAviary) |
| [textures_cellular_automata](textures/textures_cellular_automata.c) | <img src="textures/textures_cellular_automata.png" alt="textures_cellular_automata" width="80"> | ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
### category: text [15]
### category: text [16]
Examples using raylib text functionality, including sprite fonts loading/generation and text drawing, provided by raylib [text](../src/rtext.c) module.
@ -166,8 +175,9 @@ Examples using raylib text functionality, including sprite fonts loading/generat
| [text_codepoints_loading](text/text_codepoints_loading.c) | <img src="text/text_codepoints_loading.png" alt="text_codepoints_loading" width="80"> | ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) |
| [text_inline_styling](text/text_inline_styling.c) | <img src="text/text_inline_styling.png" alt="text_inline_styling" width="80"> | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) |
| [text_words_alignment](text/text_words_alignment.c) | <img src="text/text_words_alignment.png" alt="text_words_alignment" width="80"> | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
| [text_strings_management](text/text_strings_management.c) | <img src="text/text_strings_management.png" alt="text_strings_management" width="80"> | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) |
### category: models [26]
### category: models [27]
Examples using raylib models functionality, including models loading/generation and drawing, provided by raylib [models](../src/rmodels.c) module.
@ -199,8 +209,9 @@ Examples using raylib models functionality, including models loading/generation
| [models_basic_voxel](models/models_basic_voxel.c) | <img src="models/models_basic_voxel.png" alt="models_basic_voxel" width="80"> | ⭐⭐☆☆ | 5.5 | 5.5 | [Tim Little](https://github.com/timlittle) |
| [models_rotating_cube](models/models_rotating_cube.c) | <img src="models/models_rotating_cube.png" alt="models_rotating_cube" width="80"> | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) |
| [models_decals](models/models_decals.c) | <img src="models/models_decals.png" alt="models_decals" width="80"> | ⭐⭐⭐⭐️ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
| [models_directional_billboard](models/models_directional_billboard.c) | <img src="models/models_directional_billboard.png" alt="models_directional_billboard" width="80"> | ⭐⭐☆☆ | 5.6-dev | 5.6 | [Robin](https://github.com/RobinsAviary) |
### category: shaders [32]
### category: shaders [33]
Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module.
@ -238,8 +249,9 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| [shaders_lightmap_rendering](shaders/shaders_lightmap_rendering.c) | <img src="shaders/shaders_lightmap_rendering.png" alt="shaders_lightmap_rendering" width="80"> | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) |
| [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) | <img src="shaders/shaders_rounded_rectangle.png" alt="shaders_rounded_rectangle" width="80"> | ⭐⭐⭐☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) |
| [shaders_depth_rendering](shaders/shaders_depth_rendering.c) | <img src="shaders/shaders_depth_rendering.png" alt="shaders_depth_rendering" width="80"> | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) |
| [shaders_game_of_life](shaders/shaders_game_of_life.c) | <img src="shaders/shaders_game_of_life.png" alt="shaders_game_of_life" width="80"> | ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
### category: audio [8]
### category: audio [9]
Examples using raylib audio functionality, including sound/music loading and playing. This functionality is provided by raylib [raudio](../src/raudio.c) module. Note this module can be used standalone independently of raylib.
@ -253,6 +265,7 @@ Examples using raylib audio functionality, including sound/music loading and pla
| [audio_stream_effects](audio/audio_stream_effects.c) | <img src="audio/audio_stream_effects.png" alt="audio_stream_effects" width="80"> | ⭐⭐⭐⭐️ | 4.2 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) |
| [audio_sound_multi](audio/audio_sound_multi.c) | <img src="audio/audio_sound_multi.png" alt="audio_sound_multi" width="80"> | ⭐⭐☆☆ | 5.0 | 5.0 | [Jeffery Myers](https://github.com/JeffM2501) |
| [audio_sound_positioning](audio/audio_sound_positioning.c) | <img src="audio/audio_sound_positioning.png" alt="audio_sound_positioning" width="80"> | ⭐⭐☆☆ | 5.5 | 5.5 | [Le Juez Victor](https://github.com/Bigfoot71) |
| [audio_spectrum_visualizer](audio/audio_spectrum_visualizer.c) | <img src="audio/audio_spectrum_visualizer.png" alt="audio_spectrum_visualizer" width="80"> | ⭐⭐⭐☆ | 6.0 | 5.6-dev | [IANN](https://github.com/meisei4) |
### category: others [6]

View File

@ -36,6 +36,12 @@ int main(void)
float timePlayed = 0.0f; // Time played normalized [0.0f..1.0f]
bool pause = false; // Music playing paused
float pan = 0.0f; // Default audio pan center [-1.0f..1.0f]
SetMusicPan(music, pan);
float volume = 0.8f; // Default audio volume [0.0f..1.0f]
SetMusicVolume(music, volume);
SetTargetFPS(30); // Set our game to run at 30 frames-per-second
//--------------------------------------------------------------------------------------
@ -62,6 +68,34 @@ int main(void)
else ResumeMusicStream(music);
}
// Set audio pan
if (IsKeyDown(KEY_LEFT))
{
pan -= 0.05f;
if (pan < -1.0f) pan = -1.0f;
SetMusicPan(music, pan);
}
else if (IsKeyDown(KEY_RIGHT))
{
pan += 0.05f;
if (pan > 1.0f) pan = 1.0f;
SetMusicPan(music, pan);
}
// Set audio volume
if (IsKeyDown(KEY_DOWN))
{
volume -= 0.05f;
if (volume < 0.0f) volume = 0.0f;
SetMusicVolume(music, volume);
}
else if (IsKeyDown(KEY_UP))
{
volume += 0.05f;
if (volume > 1.0f) volume = 1.0f;
SetMusicVolume(music, volume);
}
// Get normalized time played for current music stream
timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music);
@ -76,6 +110,11 @@ int main(void)
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, LIGHTGRAY);
DrawText("LEFT-RIGHT for PAN CONTROL", 320, 74, 10, DARKBLUE);
DrawRectangle(300, 100, 200, 12, LIGHTGRAY);
DrawRectangleLines(300, 100, 200, 12, GRAY);
DrawRectangle(300 + (pan + 1.0)/2.0f*200 - 5, 92, 10, 28, DARKGRAY);
DrawRectangle(200, 200, 400, 12, LIGHTGRAY);
DrawRectangle(200, 200, (int)(timePlayed*400.0f), 12, MAROON);
DrawRectangleLines(200, 200, 400, 12, GRAY);
@ -83,6 +122,11 @@ int main(void)
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, LIGHTGRAY);
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, LIGHTGRAY);
DrawText("UP-DOWN for VOLUME CONTROL", 320, 334, 10, DARKGREEN);
DrawRectangle(300, 360, 200, 12, LIGHTGRAY);
DrawRectangleLines(300, 360, 200, 12, GRAY);
DrawRectangle(300 + volume*200 - 5, 352, 10, 28, DARKGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}

View File

@ -69,6 +69,7 @@ int main(void)
};
SetSoundPosition(camera, sound, spherePos, 20.0f);
if (!IsSoundPlaying(sound)) PlaySound(sound);
//----------------------------------------------------------------------------------
@ -94,6 +95,8 @@ int main(void)
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
//------------------------------------------------------------------------------------

View File

@ -0,0 +1,285 @@
/*******************************************************************************************
*
* raylib [audio] example - spectrum visualizer
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 6.0, last time updated with raylib 5.6-dev
*
* Inspired by Inigo Quilez's https://www.shadertoy.com/
* Resources/specification: https://gist.github.com/soulthreads/2efe50da4be1fb5f7ab60ff14ca434b8
*
* Example created by created by IANN (@meisei4) 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) 2025 IANN (@meisei4)
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#if defined(PLATFORM_DESKTOP)
#define GLSL_VERSION 330
#else // PLATFORM_ANDROID, PLATFORM_WEB
#define GLSL_VERSION 100
#endif
#define MONO 1
#define SAMPLE_RATE 44100
#define SAMPLE_RATE_F 44100.0f
#define FFT_WINDOW_SIZE 1024
#define BUFFER_SIZE 512
#define PER_SAMPLE_BIT_DEPTH 16
#define AUDIO_STREAM_RING_BUFFER_SIZE (FFT_WINDOW_SIZE*2)
#define EFFECTIVE_SAMPLE_RATE (SAMPLE_RATE_F*0.5f)
#define WINDOW_TIME ((double)FFT_WINDOW_SIZE/(double)EFFECTIVE_SAMPLE_RATE)
#define FFT_HISTORICAL_SMOOTHING_DUR 2.0f
#define MIN_DECIBELS (-100.0f) // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/minDecibels
#define MAX_DECIBELS (-30.0f) // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/maxDecibels
#define INVERSE_DECIBEL_RANGE (1.0f/(MAX_DECIBELS - MIN_DECIBELS))
#define DB_TO_LINEAR_SCALE (20.0f/2.302585092994046f)
#define SMOOTHING_TIME_CONSTANT 0.8f // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/smoothingTimeConstant
#define TEXTURE_HEIGHT 1
#define FFT_ROW 0
#define UNUSED_CHANNEL 0.0f
typedef struct FFTComplex { float real, imaginary; } FFTComplex;
typedef struct FFTData {
FFTComplex *spectrum;
FFTComplex *workBuffer;
float *prevMagnitudes;
float (*fftHistory)[BUFFER_SIZE];
int fftHistoryLen;
int historyPos;
double lastFftTime;
float tapbackPos;
} FFTData;
static void CaptureFrame(FFTData *fftData, const float *audioSamples);
static void RenderFrame(const FFTData *fftData, Image *fftImage);
static void CooleyTukeyFFTSlow(FFTComplex *spectrum, int n);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//----------------------------------------------------------------------------------- ---
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [audio] example - spectrum visualizer");
Image fftImage = GenImageColor(BUFFER_SIZE, TEXTURE_HEIGHT, WHITE);
Texture2D fftTexture = LoadTextureFromImage(fftImage);
RenderTexture2D bufferA = LoadRenderTexture(screenWidth, screenHeight);
Vector2 iResolution = { (float)screenWidth, (float)screenHeight };
Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/fft.fs", GLSL_VERSION));
int iResolutionLocation = GetShaderLocation(shader, "iResolution");
int iChannel0Location = GetShaderLocation(shader, "iChannel0");
SetShaderValue(shader, iResolutionLocation, &iResolution, SHADER_UNIFORM_VEC2);
SetShaderValueTexture(shader, iChannel0Location, fftTexture);
InitAudioDevice();
SetAudioStreamBufferSizeDefault(AUDIO_STREAM_RING_BUFFER_SIZE);
// WARNING: Memory out-of-bounds on PLATFORM_WEB
Wave wav = LoadWave("resources/country.mp3");
WaveFormat(&wav, SAMPLE_RATE, PER_SAMPLE_BIT_DEPTH, MONO);
AudioStream audioStream = LoadAudioStream(SAMPLE_RATE, PER_SAMPLE_BIT_DEPTH, MONO);
PlayAudioStream(audioStream);
int fftHistoryLen = (int)ceilf(FFT_HISTORICAL_SMOOTHING_DUR/WINDOW_TIME) + 1;
FFTData fft = {
.spectrum = RL_CALLOC(sizeof(FFTComplex), FFT_WINDOW_SIZE),
.workBuffer = RL_CALLOC(sizeof(FFTComplex), FFT_WINDOW_SIZE),
.prevMagnitudes = RL_CALLOC(BUFFER_SIZE, sizeof(float)),
.fftHistory = RL_CALLOC(fftHistoryLen, sizeof(float[BUFFER_SIZE])),
.fftHistoryLen = fftHistoryLen,
.historyPos = 0,
.lastFftTime = 0.0,
.tapbackPos = 0.01f
};
size_t wavCursor = 0;
const short *wavPCM16 = wav.data;
short chunkSamples[AUDIO_STREAM_RING_BUFFER_SIZE] = { 0 };
float audioSamples[FFT_WINDOW_SIZE] = { 0 };
SetTargetFPS(60);
//----------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
while (IsAudioStreamProcessed(audioStream))
{
for (int i = 0; i < AUDIO_STREAM_RING_BUFFER_SIZE; i++)
{
int left = (wav.channels == 2)? wavPCM16[wavCursor*2 + 0] : wavPCM16[wavCursor];
int right = (wav.channels == 2)? wavPCM16[wavCursor*2 + 1] : left;
chunkSamples[i] = (short)((left + right)/2);
if (++wavCursor >= wav.frameCount) wavCursor = 0;
}
UpdateAudioStream(audioStream, chunkSamples, AUDIO_STREAM_RING_BUFFER_SIZE);
for (int i = 0; i < FFT_WINDOW_SIZE; i++) audioSamples[i] = (chunkSamples[i*2] + chunkSamples[i*2 + 1])*0.5f/32767.0f;
}
CaptureFrame(&fft, audioSamples);
RenderFrame(&fft, &fftImage);
UpdateTexture(fftTexture, fftImage.data);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginShaderMode(shader);
SetShaderValueTexture(shader, iChannel0Location, fftTexture);
DrawTextureRec(bufferA.texture,
(Rectangle){ 0, 0, (float)screenWidth, (float)-screenHeight },
(Vector2){ 0, 0 }, WHITE);
EndShaderMode();
EndDrawing();
//------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
UnloadRenderTexture(bufferA);
UnloadTexture(fftTexture);
UnloadImage(fftImage);
UnloadAudioStream(audioStream);
UnloadWave(wav);
CloseAudioDevice();
RL_FREE(fft.spectrum);
RL_FREE(fft.workBuffer);
RL_FREE(fft.prevMagnitudes);
RL_FREE(fft.fftHistory);
CloseWindow(); // Close window and OpenGL context
//----------------------------------------------------------------------------------
return 0;
}
// CooleyTukey FFT https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm#Data_reordering,_bit_reversal,_and_in-place_algorithms
static void CooleyTukeyFFTSlow(FFTComplex *spectrum, int n)
{
int j = 0;
for (int i = 1; i < n - 1; i++)
{
int bit = n >> 1;
while (j >= bit)
{
j -= bit;
bit >>= 1;
}
j += bit;
if (i < j)
{
FFTComplex temp = spectrum[i];
spectrum[i] = spectrum[j];
spectrum[j] = temp;
}
}
for (int len = 2; len <= n; len <<= 1)
{
float angle = -2.0f*PI/len;
FFTComplex twiddleUnit = { cosf(angle), sinf(angle) };
for (int i = 0; i < n; i += len)
{
FFTComplex twiddleCurrent = { 1.0f, 0.0f };
for (int j = 0; j < len/2; j++)
{
FFTComplex even = spectrum[i + j];
FFTComplex odd = spectrum[i + j + len/2];
FFTComplex twiddledOdd = {
odd.real*twiddleCurrent.real - odd.imaginary*twiddleCurrent.imaginary,
odd.real*twiddleCurrent.imaginary + odd.imaginary*twiddleCurrent.real
};
spectrum[i + j].real = even.real + twiddledOdd.real;
spectrum[i + j].imaginary = even.imaginary + twiddledOdd.imaginary;
spectrum[i + j + len/2].real = even.real - twiddledOdd.real;
spectrum[i + j + len/2].imaginary = even.imaginary - twiddledOdd.imaginary;
float twiddleRealNext = twiddleCurrent.real*twiddleUnit.real - twiddleCurrent.imaginary*twiddleUnit.imaginary;
twiddleCurrent.imaginary = twiddleCurrent.real*twiddleUnit.imaginary + twiddleCurrent.imaginary*twiddleUnit.real;
twiddleCurrent.real = twiddleRealNext;
}
}
}
}
static void CaptureFrame(FFTData *fftData, const float *audioSamples)
{
for (int i = 0; i < FFT_WINDOW_SIZE; i++)
{
float x = (2.0f*PI*i)/(FFT_WINDOW_SIZE - 1.0f);
float blackmanWeight = 0.42f - 0.5f*cosf(x) + 0.08f*cosf(2.0f*x); // https://en.wikipedia.org/wiki/Window_function#Blackman_window
fftData->workBuffer[i].real = audioSamples[i]*blackmanWeight;
fftData->workBuffer[i].imaginary = 0.0f;
}
CooleyTukeyFFTSlow(fftData->workBuffer, FFT_WINDOW_SIZE);
memcpy(fftData->spectrum, fftData->workBuffer, sizeof(FFTComplex)*FFT_WINDOW_SIZE);
float smoothedSpectrum[BUFFER_SIZE];
for (int bin = 0; bin < BUFFER_SIZE; bin++)
{
float re = fftData->workBuffer[bin].real;
float im = fftData->workBuffer[bin].imaginary;
float linearMagnitude = sqrtf(re*re + im*im)/FFT_WINDOW_SIZE;
float smoothedMagnitude = SMOOTHING_TIME_CONSTANT*fftData->prevMagnitudes[bin] + (1.0f - SMOOTHING_TIME_CONSTANT)*linearMagnitude;
fftData->prevMagnitudes[bin] = smoothedMagnitude;
float db = logf(fmaxf(smoothedMagnitude, 1e-40f))*DB_TO_LINEAR_SCALE;
float normalized = (db - MIN_DECIBELS)*INVERSE_DECIBEL_RANGE;
smoothedSpectrum[bin] = Clamp(normalized, 0.0f, 1.0f);
}
fftData->lastFftTime = GetTime();
memcpy(fftData->fftHistory[fftData->historyPos], smoothedSpectrum, sizeof(smoothedSpectrum));
fftData->historyPos = (fftData->historyPos + 1)%fftData->fftHistoryLen;
}
static void RenderFrame(const FFTData *fftData, Image *fftImage)
{
double framesSinceTapback = floor(fftData->tapbackPos/WINDOW_TIME);
framesSinceTapback = Clamp(framesSinceTapback, 0.0, fftData->fftHistoryLen - 1);
int historyPosition = (fftData->historyPos - 1 - (int)framesSinceTapback)%fftData->fftHistoryLen;
if (historyPosition < 0) historyPosition += fftData->fftHistoryLen;
const float *amplitude = fftData->fftHistory[historyPosition];
for (int bin = 0; bin < BUFFER_SIZE; bin++) ImageDrawPixel(fftImage, bin, FFT_ROW, ColorFromNormalized((Vector4){ amplitude[bin], UNUSED_CHANNEL, UNUSED_CHANNEL, UNUSED_CHANNEL }));
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,37 @@
#version 100
precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform vec2 iResolution;
uniform sampler2D iChannel0;
const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
const float FFT_ROW = 0.0;
const float NUM_OF_BINS = 512.0;
void main()
{
vec2 fragCoord = fragTexCoord*iResolution;
float cellWidth = iResolution.x/NUM_OF_BINS;
float binIndex = floor(fragCoord.x/cellWidth);
float localX = mod(fragCoord.x, cellWidth);
float barWidth = cellWidth - 1.0;
vec4 color = WHITE;
if (localX <= barWidth)
{
float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
vec2 sampleCoord = vec2(sampleX, FFT_ROW);
float amplitude = texture2D(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
if (fragTexCoord.y < amplitude) color = BLACK;
}
gl_FragColor = color;
}

View File

@ -0,0 +1,35 @@
#version 120
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform vec2 iResolution;
uniform sampler2D iChannel0;
const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
const float FFT_ROW = 0.0;
const float NUM_OF_BINS = 512.0;
void main()
{
vec2 fragCoord = fragTexCoord*iResolution;
float cellWidth = iResolution.x/NUM_OF_BINS;
float binIndex = floor(fragCoord.x/cellWidth);
float localX = mod(fragCoord.x, cellWidth);
float barWidth = cellWidth - 1.0;
vec4 color = WHITE;
if (localX <= barWidth)
{
float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
vec2 sampleCoord = vec2(sampleX, FFT_ROW);
float amplitude = texture2D(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
if (fragTexCoord.y < amplitude) color = BLACK;
}
gl_FragColor = color;
}

View File

@ -0,0 +1,35 @@
#version 330
in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 finalColor;
uniform vec2 iResolution;
uniform sampler2D iChannel0;
const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
const float FFT_ROW = 0.0;
const float NUM_OF_BINS = 512.0;
void main()
{
vec2 fragCoord = fragTexCoord*iResolution;
float cellWidth = iResolution.x/NUM_OF_BINS;
float binIndex = floor(fragCoord.x/cellWidth);
float localX = mod(fragCoord.x, cellWidth);
float barWidth = cellWidth - 1.0;
vec4 color = WHITE;
if (localX <= barWidth)
{
float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
vec2 sampleCoord = vec2(sampleX, FFT_ROW);
float amplitude = texture(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
if (fragTexCoord.y < amplitude) color = BLACK;
}
finalColor = color;
}

View File

@ -125,8 +125,8 @@ int main(void)
DrawRectangle( 10, 10, 250, 113, Fade(SKYBLUE, 0.5f));
DrawRectangleLines( 10, 10, 250, 113, BLUE);
DrawText("Free 2d camera controls:", 20, 20, 10, BLACK);
DrawText("- Right/Left to move Offset", 40, 40, 10, DARKGRAY);
DrawText("Free 2D camera controls:", 20, 20, 10, BLACK);
DrawText("- Right/Left to move player", 40, 40, 10, DARKGRAY);
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, DARKGRAY);
DrawText("- A / S to Rotate", 40, 80, 10, DARKGRAY);
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, DARKGRAY);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -23,7 +23,7 @@
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main ()
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
@ -93,6 +93,7 @@ int main ()
// under the cursor to the screen space point under the cursor at any zoom
camera.target = mouseWorldPos;
}
if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
{
// Zoom increment
@ -110,7 +111,6 @@ int main ()
ClearBackground(RAYWHITE);
BeginMode2D(camera);
// Draw the 3d grid, rotated 90 degrees and centered around 0,0
// just so we have something in the XY plane
rlPushMatrix();
@ -121,7 +121,6 @@ int main ()
// Draw a reference circle
DrawCircle(GetScreenWidth()/2, GetScreenHeight()/2, 50, MAROON);
EndMode2D();
// Draw mouse reference
@ -142,5 +141,6 @@ int main ()
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -6,12 +6,12 @@
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Agnis Aldins (@nezvers) and reviewed by Ramon Santamaria (@raysan5)
* Example contributed by Agnis Aldiņš (@nezvers) 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) 2025 Agnis Aldins (@nezvers)
* Copyright (c) 2025 Agnis Aldiņš (@nezvers)
*
********************************************************************************************/

View File

@ -2,22 +2,25 @@
*
* raylib [core] example - clipboard text
*
* Example complexity rating: [] 1/4
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
*
* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
* Example contributed by Ananth S (@Ananth1839) 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) 2025 Robin (@RobinsAviary)
* Copyright (c) 2025 Ananth S (@Ananth1839)
*
********************************************************************************************/
#include "raylib.h"
#include <stdio.h>
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"
#define MAX_TEXT_SAMPLES 5
//------------------------------------------------------------------------------------
// Program main entry point
@ -31,28 +34,32 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [core] example - clipboard text");
// Define some sample texts
const char *sampleTexts[MAX_TEXT_SAMPLES] = {
"Hello from raylib!",
"The quick brown fox jumps over the lazy dog",
"Clipboard operations are useful!",
"raylib is a simple and easy-to-use library",
"Copy and paste me!"
};
const char *clipboardText = NULL;
char inputBuffer[256] = "Hello from raylib!"; // Random initial string
// List of text the user can switch through and copy
const char* copyableText[] = {"raylib is fun", "hello, clipboard!", "potato chips"};
// UI required variables
bool textBoxEditMode = false;
unsigned int textIndex = 0;
bool btnCutPressed = false;
bool btnCopyPressed = false;
bool btnPastePressed = false;
bool btnClearPressed = false;
bool btnRandomPressed = false;
const char* popupText = NULL;
// Set UI style
GuiSetStyle(DEFAULT, TEXT_SIZE, 20);
GuiSetIconScale(2);
// Initialize timers
// The amount of time the pop-up text is on screen, before fading
const float maxTime = 3.0f;
float textTimer = 0.0f;
// The length of time text is offset
const float animMaxTime = 0.1f;
float pasteAnim = 0.0f;
float copyAnim = 0.0f;
int copyAnimMult = 1;
float textAnim = 0.0f;
float textAlpha = 0.0f;
// Offset amount for animations
const int offsetAmount = -4;
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
@ -60,95 +67,55 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
// Check if the user has pressed the copy/paste key combinations
bool pastePressed = (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V));
bool copyPressed = (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C));
// Update animation timers
if (textTimer > 0) textTimer -= GetFrameTime();
if (pasteAnim > 0) pasteAnim -= GetFrameTime();
if (copyAnim > 0) copyAnim -= GetFrameTime();
if (textAnim > 0) textAnim -= GetFrameTime();
// React to the user pressing paste
if (pastePressed)
// Handle button interactions
if (btnCutPressed)
{
// Most operating systems hide this information until the user presses Ctrl-V on the window.
// Check to see if the clipboard contains an image
// This function does nothing outside of Windows, as it directly calls the Windows API
Image image = GetClipboardImage();
if (IsImageValid(image))
{
// Unload the image
UnloadImage(image);
// Update visuals
popupText = "clipboard contains image";
}
else
{
// Get text from the user's clipboard
SetClipboardText(inputBuffer);
clipboardText = GetClipboardText();
// Update visuals
popupText = "text pasted";
pasteAnim = animMaxTime;
inputBuffer[0] = '\0'; // Quick solution to clear text
//memset(inputBuffer, 0, 256); // Clear full buffer properly
}
// Reset animation values
textTimer = maxTime;
textAnim = animMaxTime;
textAlpha = 1;
if (btnCopyPressed)
{
SetClipboardText(inputBuffer); // Copy text to clipboard
clipboardText = GetClipboardText(); // Get text from clipboard
}
// React to the user pressing copy
if (copyPressed)
if (btnPastePressed)
{
// Set the text on the user's clipboard
SetClipboardText(copyableText[textIndex]);
// Reset values
textTimer = maxTime;
textAnim = animMaxTime;
copyAnim = animMaxTime;
copyAnimMult = 1;
textAlpha = 1;
// Update the text that pops up at the bottom of the screen
popupText = "text copied";
// Paste text from clipboard
clipboardText = GetClipboardText();
if (clipboardText != NULL) TextCopy(inputBuffer, clipboardText);
}
// Switch to the next item in the list when the user presses up
if (IsKeyPressed(KEY_UP))
if (btnClearPressed)
{
// Reset animation
copyAnim = animMaxTime;
copyAnimMult = 1;
textIndex += 1;
if (textIndex >= sizeof(copyableText) / sizeof(const char*)) // Length of array
{
// Loop back to the other end
textIndex = 0;
}
inputBuffer[0] = '\0'; // Quick solution to clear text
//memset(inputBuffer, 0, 256); // Clear full buffer properly
}
// Switch to the previous item in the list when the user presses down
if (IsKeyPressed(KEY_DOWN))
if (btnRandomPressed)
{
// Reset animation
copyAnim = animMaxTime;
copyAnimMult = -1;
if (textIndex == 0)
{
// Loop back to the other end
textIndex = (sizeof(copyableText) / sizeof(const char*)) - 1; // Length of array minus one
// Get random text from sample list
TextCopy(inputBuffer, sampleTexts[GetRandomValue(0, MAX_TEXT_SAMPLES - 1)]);
}
else
// Quick cut/copy/paste with keyboard shortcuts
if (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))
{
textIndex -= 1;
if (IsKeyPressed(KEY_X))
{
SetClipboardText(inputBuffer);
inputBuffer[0] = '\0'; // Quick solution to clear text
}
if (IsKeyPressed(KEY_C)) SetClipboardText(inputBuffer);
if (IsKeyPressed(KEY_V))
{
clipboardText = GetClipboardText();
if (clipboardText != NULL) TextCopy(inputBuffer, clipboardText);
}
}
//----------------------------------------------------------------------------------
@ -159,41 +126,30 @@ int main(void)
ClearBackground(RAYWHITE);
// Draw the user's pasted text, if there is any yet
if (clipboardText)
{
// Offset animation
int offset = 0;
if (pasteAnim > 0) offset = offsetAmount;
// Draw instructions
GuiLabel((Rectangle){ 50, 20, 700, 36 }, "Use the BUTTONS or KEY SHORTCUTS:");
DrawText("[CTRL+X] - CUT | [CTRL+C] COPY | [CTRL+V] | PASTE", 50, 60, 20, MAROON);
// Draw the pasted text
DrawText("pasted clipboard:", 10, 10 + offset, 20, DARKGREEN);
DrawText(clipboardText, 10, 30 + offset, 20, DARKGRAY);
}
// Draw text box
if (GuiTextBox((Rectangle){ 50, 120, 652, 40 }, inputBuffer, 256, textBoxEditMode)) textBoxEditMode = !textBoxEditMode;
// Offset animation
int textOffset = 0;
if (copyAnim > 0) textOffset = offsetAmount;
// Random text button
btnRandomPressed = GuiButton((Rectangle){ 50 + 652 + 8, 120, 40, 40 }, "#77#");
// Draw copyable text and controls
DrawText(copyableText[textIndex], 10, 330 + (textOffset * copyAnimMult), 20, MAROON);
DrawText("up/down to change string, ctrl-c to copy, ctrl-v to paste", 10, 355, 20, DARKGRAY);
// Draw buttons
btnCutPressed = GuiButton((Rectangle){ 50, 180, 158, 40 }, "#17#CUT");
btnCopyPressed = GuiButton((Rectangle){ 50 + 165, 180, 158, 40 }, "#16#COPY");
btnPastePressed = GuiButton((Rectangle){ 50 + 165*2, 180, 158, 40 }, "#18#PASTE");
btnClearPressed = GuiButton((Rectangle){ 50 + 165*3, 180, 158, 40 }, "#143#CLEAR");
// Alpha / Offset animation
if (textAlpha > 0)
{
// Offset animation
int offset = 0;
if (textAnim > 0) offset = offsetAmount;
// Draw pop up text
DrawText(popupText, 10, 425 + offset, 20, ColorAlpha(DARKGREEN, textAlpha));
// Fade-out animation
if (textTimer < 0)
{
textAlpha -= GetFrameTime();
}
}
// Draw clipboard status
GuiSetState(STATE_DISABLED);
GuiLabel((Rectangle){ 50, 260, 700, 40 }, "Clipboard current text data:");
GuiSetStyle(TEXTBOX, TEXT_READONLY, 1);
GuiTextBox((Rectangle){ 50, 300, 700, 40 }, (char *)clipboardText, 256, false);
GuiSetStyle(TEXTBOX, TEXT_READONLY, 0);
GuiLabel((Rectangle){ 50, 360, 700, 40 }, "Try copying text from other applications and pasting here!");
GuiSetState(STATE_NORMAL);
EndDrawing();
//----------------------------------------------------------------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,143 @@
/*******************************************************************************************
*
* raylib [core] example - compute hash
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 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) 2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
static char *GetDataAsHexText(const unsigned int *data, int dataSize);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - compute hash");
// UI controls variables
char textInput[96] = "The quick brown fox jumps over the lazy dog.";
bool textBoxEditMode = false;
bool btnComputeHashes = false;
// Data hash values
unsigned int hashCRC32 = 0;
unsigned int *hashMD5 = NULL;
unsigned int *hashSHA1 = NULL;
unsigned int *hashSHA256 = NULL;
// Base64 encoded data
char *base64Text = NULL;
int base64TextSize = 0;
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (btnComputeHashes)
{
int textInputLen = strlen(textInput);
// Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
base64Text = EncodeDataBase64((unsigned char *)textInput, textInputLen, &base64TextSize);
hashCRC32 = ComputeCRC32((unsigned char *)textInput, textInputLen); // Compute CRC32 hash code (4 bytes)
hashMD5 = ComputeMD5((unsigned char *)textInput, textInputLen); // Compute MD5 hash code, returns static int[4] (16 bytes)
hashSHA1 = ComputeSHA1((unsigned char *)textInput, textInputLen); // Compute SHA1 hash code, returns static int[5] (20 bytes)
hashSHA256 = ComputeSHA256((unsigned char *)textInput, textInputLen); // Compute SHA256 hash code, returns static int[8] (32 bytes)
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
GuiSetStyle(DEFAULT, TEXT_SIZE, 20);
GuiSetStyle(DEFAULT, TEXT_SPACING, 2);
GuiLabel((Rectangle){ 40, 26, 720, 32 }, "INPUT DATA (TEXT):");
GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
if (GuiTextBox((Rectangle){ 40, 64, 720, 32 }, textInput, 95, textBoxEditMode)) textBoxEditMode = !textBoxEditMode;
btnComputeHashes = GuiButton((Rectangle){ 40, 64 + 40, 720, 32 }, "COMPUTE INPUT DATA HASHES");
GuiSetStyle(DEFAULT, TEXT_SIZE, 20);
GuiSetStyle(DEFAULT, TEXT_SPACING, 2);
GuiLabel((Rectangle){ 40, 160, 720, 32 }, "INPUT DATA HASH VALUES:");
GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
GuiSetStyle(TEXTBOX, TEXT_READONLY, 1);
GuiLabel((Rectangle){ 40, 200, 120, 32 }, "CRC32 [32 bit]:");
GuiTextBox((Rectangle){ 40 + 120, 200, 720 - 120, 32 }, GetDataAsHexText(&hashCRC32, 1), 120, false);
GuiLabel((Rectangle){ 40, 200 + 36, 120, 32 }, "MD5 [128 bit]:");
GuiTextBox((Rectangle){ 40 + 120, 200 + 36, 720 - 120, 32 }, GetDataAsHexText(hashMD5, 4), 120, false);
GuiLabel((Rectangle){ 40, 200 + 36*2, 120, 32 }, "SHA1 [160 bit]:");
GuiTextBox((Rectangle){ 40 + 120, 200 + 36*2, 720 - 120, 32 }, GetDataAsHexText(hashSHA1, 5), 120, false);
GuiLabel((Rectangle){ 40, 200 + 36*3, 120, 32 }, "SHA256 [256 bit]:");
GuiTextBox((Rectangle){ 40 + 120, 200 + 36*3, 720 - 120, 32 }, GetDataAsHexText(hashSHA256, 8), 120, false);
GuiSetState(STATE_FOCUSED);
GuiLabel((Rectangle){ 40, 200 + 36*5 - 30, 320, 32 }, "BONUS - BAS64 ENCODED STRING:");
GuiSetState(STATE_NORMAL);
GuiLabel((Rectangle){ 40, 200 + 36*5, 120, 32 }, "BASE64 ENCODING:");
GuiTextBox((Rectangle){ 40 + 120, 200 + 36*5, 720 - 120, 32 }, base64Text, 120, false);
GuiSetStyle(TEXTBOX, TEXT_READONLY, 0);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
MemFree(base64Text); // Free Base64 text data
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
static char *GetDataAsHexText(const unsigned int *data, int dataSize)
{
static char text[128] = { 0 };
memset(text, 0, 128);
if ((data != NULL) && (dataSize > 0) && (dataSize < ((128/8) - 1)))
{
for (int i = 0; i < dataSize; i++) TextCopy(text + i*8, TextFormat("%08X", data[i]));
}
else TextCopy(text, "00000000");
return text;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -17,11 +17,11 @@
#include "raylib.h"
#include <stdio.h> // Required for: fopen(), fclose(), fputc(), fwrite(), printf(), fprintf(), funopen()
#include <stdio.h> // Required for: printf(), vprintf(), fprintf()
#include <time.h> // Required for: time_t, tm, time(), localtime(), strftime()
// Custom logging function
void CustomLog(int msgType, const char *text, va_list args)
void CustomTraceLog(int msgType, const char *text, va_list args)
{
char timeStr[64] = { 0 };
time_t now = time(NULL);
@ -54,7 +54,7 @@ int main(void)
const int screenHeight = 450;
// Set custom logger
SetTraceLogCallback(CustomLog);
SetTraceLogCallback(CustomTraceLog);
InitWindow(screenWidth, screenHeight, "raylib [core] example - custom logging");

View File

@ -20,9 +20,7 @@
#define RAYGUI_IMPLEMENTATION
#include "raygui.h" // Required for GUI controls
#include <string.h> // Required for: strcpy()
#define MAX_FILEPATH_SIZE 2048
#define MAX_FILEPATH_SIZE 1024
//------------------------------------------------------------------------------------
// Program main entry point
@ -53,12 +51,10 @@ int main(void)
//----------------------------------------------------------------------------------
if (btnBackPressed)
{
strcpy(directory, GetPrevDirectoryPath(directory));
TextCopy(directory, GetPrevDirectoryPath(directory));
UnloadDirectoryFiles(files);
files = LoadDirectoryFiles(directory);
}
//----------------------------------------------------------------------------------
// Draw
@ -68,19 +64,20 @@ int main(void)
DrawText(directory, 100, 40, 20, DARKGRAY);
btnBackPressed = GuiButton((Rectangle){ 40.0f, 40.0f, 20, 20 }, "<");
btnBackPressed = GuiButton((Rectangle){ 40.0f, 38.0f, 48, 24 }, "<");
for (int i = 0; i < (int)files.count; i++)
{
Color color = Fade(LIGHTGRAY, 0.3f);
if (!IsPathFile(files.paths[i]))
if (!IsPathFile(files.paths[i]) && DirectoryExists(files.paths[i]))
{
if (GuiButton((Rectangle){0.0f, 85.0f + 40.0f*(float)i, screenWidth, 40}, ""))
{
strcpy(directory, files.paths[i]);
TextCopy(directory, files.paths[i]);
UnloadDirectoryFiles(files);
files = LoadDirectoryFiles(directory);
continue;
}
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************************
*
* raylib [core] example - high dpi
* raylib [core] example - highdpi demo
*
* Example complexity rating: [] 2/4
*
@ -33,7 +33,7 @@ int main(void)
const int screenHeight = 450;
SetConfigFlags(FLAG_WINDOW_HIGHDPI | FLAG_WINDOW_RESIZABLE);
InitWindow(screenWidth, screenHeight, "raylib [core] example - high dpi");
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi demo");
SetWindowMinSize(450, 450);
int logicalGridDescY = 120;

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -27,9 +27,14 @@ int main(void)
const int screenWidth = 800;
const int screenHeight = 450;
SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI);
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi testbed");
// TODO: Load resources / Initialize variables at this point
Vector2 scaleDpi = GetWindowScaleDPI();
Vector2 mousePos = GetMousePosition();
int currentMonitor = GetCurrentMonitor();
int gridSpacing = 40; // Grid spacing in pixels
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
@ -39,7 +44,12 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update variables / Implement example logic at this point
mousePos = GetMousePosition();
currentMonitor = GetCurrentMonitor();
scaleDpi = GetWindowScaleDPI();
if (IsKeyPressed(KEY_SPACE)) ToggleBorderlessWindowed();
if (IsKeyPressed(KEY_F)) ToggleFullscreen();
//----------------------------------------------------------------------------------
// Draw
@ -48,11 +58,35 @@ int main(void)
ClearBackground(RAYWHITE);
// TODO: Draw everything that requires to be drawn at this point
// Draw grid
for (int h = 0; h < GetScreenHeight()/gridSpacing + 1; h++)
{
DrawText(TextFormat("%02i", h*gridSpacing), 4, h*gridSpacing - 4, 10, GRAY);
DrawLine(24, h*gridSpacing, GetScreenWidth(), h*gridSpacing, LIGHTGRAY);
}
for (int v = 0; v < GetScreenWidth()/gridSpacing + 1; v++)
{
DrawText(TextFormat("%02i", v*gridSpacing), v*gridSpacing - 10, 4, 10, GRAY);
DrawLine(v*gridSpacing, 20, v*gridSpacing, GetScreenHeight(), LIGHTGRAY);
}
DrawLineEx((Vector2){ 0, 0 }, (Vector2){ screenWidth, screenHeight }, 2.0f, RED);
DrawLineEx((Vector2){ 0, screenHeight }, (Vector2){ screenWidth, 0 }, 2.0f, RED);
DrawText("example base code template", 260, 400, 20, LIGHTGRAY);
// Draw UI info
DrawText(TextFormat("CURRENT MONITOR: %i/%i (%ix%i)", currentMonitor + 1, GetMonitorCount(),
GetMonitorWidth(currentMonitor), GetMonitorHeight(currentMonitor)), 50, 50, 20, DARKGRAY);
DrawText(TextFormat("SCREEN SIZE: %ix%i", GetScreenWidth(), GetScreenHeight()), 50, 90, 20, DARKGRAY);
DrawText(TextFormat("RENDER SIZE: %ix%i", GetRenderWidth(), GetRenderHeight()), 50, 130, 20, DARKGRAY);
DrawText(TextFormat("SCALE FACTOR: %.1fx%.1f", scaleDpi.x, scaleDpi.y), 50, 170, 20, GRAY);
// Draw reference rectangles, top-left and bottom-right corners
DrawRectangle(0, 0, 30, 60, RED);
DrawRectangle(GetScreenWidth() - 30, GetScreenHeight() - 60, 30, 60, BLUE);
// Draw mouse position
DrawCircleV(GetMousePosition(), 20, MAROON);
DrawRectangle(mousePos.x - 25, mousePos.y, 50, 2, BLACK);
DrawRectangle(mousePos.x, mousePos.y - 25, 2, 50, BLACK);
DrawText(TextFormat("[%i,%i]", GetMouseX(), GetMouseY()), mousePos.x - 44,
(mousePos.y > GetScreenHeight() - 60)? mousePos.y - 46 : mousePos.y + 30, 20, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------

View File

@ -71,6 +71,7 @@ int main(void)
// Set default actions
char actionSet = 0;
SetActionsDefault();
bool releaseAction = false;
Vector2 position = (Vector2){ 400.0f, 200.0f };
Vector2 size = (Vector2){ 40.0f, 40.0f };
@ -83,7 +84,8 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
gamepadIndex = 0; // set this to gamepad being checked
gamepadIndex = 0; // Set gamepad being checked
if (IsActionDown(ACTION_UP)) position.y -= 2;
if (IsActionDown(ACTION_DOWN)) position.y += 2;
if (IsActionDown(ACTION_LEFT)) position.x -= 2;
@ -94,6 +96,10 @@ int main(void)
position.y = (screenHeight-size.y)/2;
}
// Register release action for one frame
releaseAction = false;
if (IsActionReleased(ACTION_FIRE)) releaseAction = true;
// Switch control scheme by pressing TAB
if (IsKeyPressed(KEY_TAB))
{
@ -109,7 +115,7 @@ int main(void)
ClearBackground(GRAY);
DrawRectangleV(position, size, RED);
DrawRectangleV(position, size, releaseAction? BLUE : RED);
DrawText((actionSet == 0)? "Current input set: WASD (default)" : "Current input set: Cursor", 10, 10, 20, WHITE);
DrawText("Use TAB key to toggles Actions keyset", 10, 50, 20, GREEN);

View File

@ -51,6 +51,8 @@ int main(void)
const float leftTriggerDeadzone = -0.9f;
const float rightTriggerDeadzone = -0.9f;
Rectangle vibrateButton = { 0 };
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
@ -61,7 +63,12 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
// ...
if (IsKeyPressed(KEY_LEFT) && gamepad > 0) gamepad--;
if (IsKeyPressed(KEY_RIGHT)) gamepad++;
Vector2 mousePosition = GetMousePosition();
vibrateButton = (Rectangle){ 10, 70 + 20*GetGamepadAxisCount(gamepad) + 20, 75, 24 };
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mousePosition, vibrateButton)) SetGamepadVibration(gamepad, 1.0, 1.0, 1.0);
//----------------------------------------------------------------------------------
// Draw
@ -70,9 +77,6 @@ int main(void)
ClearBackground(RAYWHITE);
if (IsKeyPressed(KEY_LEFT) && gamepad > 0) gamepad--;
if (IsKeyPressed(KEY_RIGHT)) gamepad++;
if (IsGamepadAvailable(gamepad))
{
DrawText(TextFormat("GP%d: %s", gamepad, GetGamepadName(gamepad)), 10, 10, 10, BLACK);
@ -93,7 +97,8 @@ int main(void)
if (leftTrigger < leftTriggerDeadzone) leftTrigger = -1.0f;
if (rightTrigger < rightTriggerDeadzone) rightTrigger = -1.0f;
if (TextFindIndex(TextToLower(GetGamepadName(gamepad)), XBOX_ALIAS_1) > -1 || TextFindIndex(TextToLower(GetGamepadName(gamepad)), XBOX_ALIAS_2) > -1)
if ((TextFindIndex(TextToLower(GetGamepadName(gamepad)), XBOX_ALIAS_1) > -1) ||
(TextFindIndex(TextToLower(GetGamepadName(gamepad)), XBOX_ALIAS_2) > -1))
{
DrawTexture(texXboxPad, 0, 0, DARKGRAY);
@ -125,16 +130,14 @@ int main(void)
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_LEFT_THUMB)) leftGamepadColor = RED;
DrawCircle(259, 152, 39, BLACK);
DrawCircle(259, 152, 34, LIGHTGRAY);
DrawCircle(259 + (int)(leftStickX*20),
152 + (int)(leftStickY*20), 25, leftGamepadColor);
DrawCircle(259 + (int)(leftStickX*20), 152 + (int)(leftStickY*20), 25, leftGamepadColor);
// Draw axis: right joystick
Color rightGamepadColor = BLACK;
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_RIGHT_THUMB)) rightGamepadColor = RED;
DrawCircle(461, 237, 38, BLACK);
DrawCircle(461, 237, 33, LIGHTGRAY);
DrawCircle(461 + (int)(rightStickX*20),
237 + (int)(rightStickY*20), 25, rightGamepadColor);
DrawCircle(461 + (int)(rightStickX*20), 237 + (int)(rightStickY*20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(170, 30, 15, 70, GRAY);
@ -177,16 +180,14 @@ int main(void)
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_LEFT_THUMB)) leftGamepadColor = RED;
DrawCircle(319, 255, 35, BLACK);
DrawCircle(319, 255, 31, LIGHTGRAY);
DrawCircle(319 + (int)(leftStickX*20),
255 + (int)(leftStickY*20), 25, leftGamepadColor);
DrawCircle(319 + (int)(leftStickX*20), 255 + (int)(leftStickY*20), 25, leftGamepadColor);
// Draw axis: right joystick
Color rightGamepadColor = BLACK;
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_RIGHT_THUMB)) rightGamepadColor = RED;
DrawCircle(475, 255, 35, BLACK);
DrawCircle(475, 255, 31, LIGHTGRAY);
DrawCircle(475 + (int)(rightStickX*20),
255 + (int)(rightStickY*20), 25, rightGamepadColor);
DrawCircle(475 + (int)(rightStickX*20), 255 + (int)(rightStickY*20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(169, 48, 15, 70, GRAY);
@ -196,7 +197,6 @@ int main(void)
}
else
{
// Draw background: generic
DrawRectangleRounded((Rectangle){ 175, 110, 460, 220}, 0.3f, 16, DARKGRAY);
@ -237,23 +237,20 @@ int main(void)
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_LEFT_THUMB)) leftGamepadColor = RED;
DrawCircle(345, 260, 40, BLACK);
DrawCircle(345, 260, 35, LIGHTGRAY);
DrawCircle(345 + (int)(leftStickX*20),
260 + (int)(leftStickY*20), 25, leftGamepadColor);
DrawCircle(345 + (int)(leftStickX*20), 260 + (int)(leftStickY*20), 25, leftGamepadColor);
// Draw axis: right joystick
Color rightGamepadColor = BLACK;
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_RIGHT_THUMB)) rightGamepadColor = RED;
DrawCircle(465, 260, 40, BLACK);
DrawCircle(465, 260, 35, LIGHTGRAY);
DrawCircle(465 + (int)(rightStickX*20),
260 + (int)(rightStickY*20), 25, rightGamepadColor);
DrawCircle(465 + (int)(rightStickX*20), 260 + (int)(rightStickY*20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(151, 110, 15, 70, GRAY);
DrawRectangle(644, 110, 15, 70, GRAY);
DrawRectangle(151, 110, 15, (int)(((1 + leftTrigger)/2)*70), RED);
DrawRectangle(644, 110, 15, (int)(((1 + rightTrigger)/2)*70), RED);
}
DrawText(TextFormat("DETECTED AXIS [%i]:", GetGamepadAxisCount(gamepad)), 10, 50, 10, MAROON);
@ -263,13 +260,16 @@ int main(void)
DrawText(TextFormat("AXIS %i: %.02f", i, GetGamepadAxisMovement(gamepad, i)), 20, 70 + 20*i, 10, DARKGRAY);
}
// Draw vibrate button
DrawRectangleRec(vibrateButton, SKYBLUE);
DrawText("VIBRATE", vibrateButton.x + 14, vibrateButton.y + 1, 10, DARKGRAY);
if (GetGamepadButtonPressed() != GAMEPAD_BUTTON_UNKNOWN) DrawText(TextFormat("DETECTED BUTTON: %i", GetGamepadButtonPressed()), 10, 430, 10, RED);
else DrawText("DETECTED BUTTON: NONE", 10, 430, 10, GRAY);
}
else
{
DrawText(TextFormat("GP%d: NOT DETECTED", gamepad), 10, 10, 10, GRAY);
DrawTexture(texXboxPad, 0, 0, LIGHTGRAY);
}

View File

@ -118,4 +118,6 @@ int main(void)
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -22,9 +22,9 @@
#define GESTURE_LOG_SIZE 20
#define MAX_TOUCH_COUNT 32
//----------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
static char const *GetGestureName(int gesture); // Get text string for gesture value
static Color GetGestureColor(int gesture); // Get color for gesture value
@ -69,7 +69,6 @@ int main(void)
float angleLength = 90.0f;
float currentAngleDegrees = 0.0f;
Vector2 finalVector = { 0.0f, 0.0f };
char currentAngleStr[7] = "";
Vector2 protractorPosition = { 266.0f, 315.0f };
SetTargetFPS(60); // Set our game to run at 60 frames-per-second

View File

@ -0,0 +1,173 @@
/*******************************************************************************************
*
* raylib [core] example - Keyboard vs Gamepad Input Test
*
* Example complexity rating: [] 1/4
*
* This example is a diagnostic tool to verify that keyboard input is not
* incorrectly detected as gamepad input on Android devices.
*
* Issue reference: https://github.com/raysan5/raylib/issues/5387
*
* 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) 2025 raylib contributors
*
********************************************************************************************/
#include "raylib.h"
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard vs gamepad test");
Vector2 ballPosition = { (float)screenWidth/2, (float)screenHeight/2 };
int lastKeyPressed = 0;
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose())
{
// Update
//----------------------------------------------------------------------------------
// Track keyboard input
if (IsKeyDown(KEY_RIGHT)) ballPosition.x += 4.0f;
if (IsKeyDown(KEY_LEFT)) ballPosition.x -= 4.0f;
if (IsKeyDown(KEY_UP)) ballPosition.y -= 4.0f;
if (IsKeyDown(KEY_DOWN)) ballPosition.y += 4.0f;
// Keep ball on screen
if (ballPosition.x < 25) ballPosition.x = 25;
if (ballPosition.x > screenWidth - 25) ballPosition.x = screenWidth - 25;
if (ballPosition.y < 25) ballPosition.y = 25;
if (ballPosition.y > screenHeight - 25) ballPosition.y = screenHeight - 25;
// Track last key pressed
int key = GetKeyPressed();
if (key != 0) lastKeyPressed = key;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
// Title
DrawText("KEYBOARD vs GAMEPAD INPUT TEST", 180, 10, 20, DARKGRAY);
DrawText("Issue #5387: Keyboard detected as gamepad on some Android devices", 120, 35, 14, GRAY);
// Divider
DrawLine(0, 60, screenWidth, 60, LIGHTGRAY);
// Keyboard section
DrawText("KEYBOARD INPUT", 20, 75, 18, DARKBLUE);
DrawRectangle(20, 100, 360, 80, Fade(BLUE, 0.1f));
DrawText(TextFormat("Arrow Keys: [%s] [%s] [%s] [%s]",
IsKeyDown(KEY_UP) ? "UP" : "--",
IsKeyDown(KEY_DOWN) ? "DN" : "--",
IsKeyDown(KEY_LEFT) ? "LT" : "--",
IsKeyDown(KEY_RIGHT) ? "RT" : "--"), 30, 110, 16, BLACK);
DrawText(TextFormat("Last Key Pressed: %d", lastKeyPressed), 30, 135, 16, DARKGRAY);
DrawText(TextFormat("Any Key Down: %s", (IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) ||
IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT)) ? "YES" : "NO"), 30, 155, 16, DARKGRAY);
// Gamepad section
DrawText("GAMEPAD STATUS", 420, 75, 18, DARKGREEN);
DrawRectangle(420, 100, 360, 80, Fade(GREEN, 0.1f));
bool gamepadReady = IsGamepadAvailable(0);
DrawText(TextFormat("Gamepad 0 Available: %s", gamepadReady ? "YES" : "NO"),
430, 110, 16, gamepadReady ? RED : DARKGREEN);
if (gamepadReady)
{
DrawText(TextFormat("D-Pad: [%s] [%s] [%s] [%s]",
IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_FACE_UP) ? "UP" : "--",
IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_FACE_DOWN) ? "DN" : "--",
IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_FACE_LEFT) ? "LT" : "--",
IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_FACE_RIGHT) ? "RT" : "--"),
430, 135, 16, RED);
DrawText(TextFormat("Gamepad Name: %.20s", GetGamepadName(0)), 430, 155, 14, DARKGRAY);
}
else
{
DrawText("No gamepad detected", 430, 135, 16, DARKGREEN);
}
// Divider
DrawLine(0, 190, screenWidth, 190, LIGHTGRAY);
// Test result section
DrawText("TEST RESULT", 20, 200, 18, MAROON);
bool keyboardActive = IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) ||
IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT);
if (keyboardActive && gamepadReady)
{
// BUG DETECTED: Keyboard is triggering gamepad detection
DrawRectangle(20, 225, 760, 50, Fade(RED, 0.3f));
DrawText("BUG DETECTED: Keyboard input is being detected as gamepad!", 30, 235, 18, RED);
DrawText("The fix for issue #5387 may not be working correctly.", 30, 258, 14, DARKGRAY);
}
else if (keyboardActive && !gamepadReady)
{
// CORRECT: Keyboard works without triggering gamepad
DrawRectangle(20, 225, 760, 50, Fade(GREEN, 0.3f));
DrawText("PASS: Keyboard input detected correctly (no phantom gamepad)", 30, 235, 18, DARKGREEN);
DrawText("Issue #5387 fix is working as expected.", 30, 258, 14, DARKGRAY);
}
else if (!keyboardActive && gamepadReady)
{
// Gamepad is connected (might be real or might be bug on idle)
DrawRectangle(20, 225, 760, 50, Fade(ORANGE, 0.3f));
DrawText("INFO: Gamepad detected - press keyboard keys to test", 30, 235, 18, ORANGE);
DrawText("If gamepad stays active while pressing keyboard = BUG", 30, 258, 14, DARKGRAY);
}
else
{
// Idle state
DrawRectangle(20, 225, 760, 50, Fade(GRAY, 0.1f));
DrawText("WAITING: Press arrow keys to test keyboard input", 30, 235, 18, GRAY);
DrawText("Gamepad should NOT become available when pressing keyboard keys", 30, 258, 14, DARKGRAY);
}
// Ball controlled by keyboard
DrawText("Ball Control (Arrow Keys):", 20, 295, 16, DARKGRAY);
DrawCircleV(ballPosition, 25, MAROON);
DrawCircleLines((int)ballPosition.x, (int)ballPosition.y, 25, DARKGRAY);
// Instructions
DrawRectangle(0, screenHeight - 45, screenWidth, 45, Fade(BLACK, 0.05f));
DrawText("Instructions: Press keyboard arrow keys - the ball should move and gamepad should stay 'NO'",
20, screenHeight - 35, 14, DARKGRAY);
DrawText("If gamepad becomes 'YES' while pressing keyboard = issue #5387 is NOT fixed",
20, screenHeight - 18, 14, DARKGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -40,14 +40,8 @@ int main(void)
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_H))
{
if (IsCursorHidden())
{
ShowCursor();
}
else
{
HideCursor();
}
if (IsCursorHidden()) ShowCursor();
else HideCursor();
}
ballPosition = GetMousePosition();

View File

@ -46,7 +46,7 @@ int main(void)
// Clamp touch points available ( set the maximum touch points allowed )
if (tCount > MAX_TOUCH_POINTS) tCount = MAX_TOUCH_POINTS;
// Get touch points positions
for (int i = 0; i < tCount; ++i) touchPositions[i] = GetTouchPosition(i);
for (int i = 0; i < tCount; i++) touchPositions[i] = GetTouchPosition(i);
//----------------------------------------------------------------------------------
// Draw
@ -55,7 +55,7 @@ int main(void)
ClearBackground(RAYWHITE);
for (int i = 0; i < tCount; ++i)
for (int i = 0; i < tCount; i++)
{
// Make sure point is not (0, 0) as this means there is no touch for it
if ((touchPositions[i].x > 0) && (touchPositions[i].y > 0))

View File

@ -40,10 +40,9 @@ int main(void)
const int screenWidth = 800;
const int screenHeight = 450;
MonitorInfo monitors[MAX_MONITORS] = { 0 };
InitWindow(screenWidth, screenHeight, "raylib [core] example - monitor detector");
MonitorInfo monitors[MAX_MONITORS] = { 0 };
int currentMonitorIndex = GetCurrentMonitor();
int monitorCount = 0;
@ -55,7 +54,6 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
// Variables to find the max x and Y to calculate the scale
int maxWidth = 1;
int maxHeight = 1;
@ -76,7 +74,8 @@ int main(void)
GetMonitorPhysicalHeight(i),
GetMonitorRefreshRate(i)
};
if (monitors[i].position.x < monitorOffsetX) monitorOffsetX = (int)monitors[i].position.x*-1;
if (monitors[i].position.x < monitorOffsetX) monitorOffsetX = -(int)monitors[i].position.x;
const int width = (int)monitors[i].position.x + monitors[i].width;
const int height = (int)monitors[i].position.y + monitors[i].height;
@ -85,7 +84,7 @@ int main(void)
if (maxHeight < height) maxHeight = height;
}
if (IsKeyPressed(KEY_ENTER) && monitorCount > 1)
if (IsKeyPressed(KEY_ENTER) && (monitorCount > 1))
{
currentMonitorIndex += 1;
@ -94,16 +93,13 @@ int main(void)
SetWindowMonitor(currentMonitorIndex); // Move window to currentMonitorIndex
}
else
{
// Get currentMonitorIndex if manually moved
currentMonitorIndex = GetCurrentMonitor();
}
else currentMonitorIndex = GetCurrentMonitor(); // Get currentMonitorIndex if manually moved
float monitorScale = 0.6f;
if(maxHeight > maxWidth + monitorOffsetX) monitorScale *= ((float)screenHeight/(float)maxHeight);
if (maxHeight > (maxWidth + monitorOffsetX)) monitorScale *= ((float)screenHeight/(float)maxHeight);
else monitorScale *= ((float)screenWidth/(float)(maxWidth + monitorOffsetX));
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
@ -148,14 +144,9 @@ int main(void)
// Draw window position based on monitors
DrawRectangleV(windowPosition, (Vector2){screenWidth*monitorScale, screenHeight*monitorScale}, Fade(GREEN, 0.5));
}
else
{
DrawRectangleLinesEx(rec, 5, GRAY);
else DrawRectangleLinesEx(rec, 5, GRAY);
}
}
EndDrawing();
//----------------------------------------------------------------------------------
}

View File

@ -2,12 +2,10 @@
*
* raylib [core] example - screen recording
*
* Example complexity rating: [] 1/4
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
*
* Example contributed by Ramon Santamaria (@raysan5) 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
*
@ -17,6 +15,16 @@
#include "raylib.h"
// Using msf_gif library to record frames into GIF
#define MSF_GIF_IMPL
#include "msf_gif.h" // GIF recording functionality
#include <math.h> // Required for: sinf()
#define GIF_RECORD_FRAMERATE 5 // Record framerate, we get a frame every N frames
#define MAX_SINEWAVE_POINTS 256
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
@ -29,7 +37,20 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [core] example - screen recording");
// TODO: Load resources / Initialize variables at this point
bool gifRecording = false; // GIF recording state
unsigned int gifFrameCounter = 0; // GIF frames counter
MsfGifState gifState = { 0 }; // MSGIF context state
Vector2 circlePosition = { 0.0f, screenHeight/2.0f };
float timeCounter = 0.0f;
// Get sine wave points for line drawing
Vector2 sinePoints[MAX_SINEWAVE_POINTS] = { 0 };
for (int i = 0; i < MAX_SINEWAVE_POINTS; i++)
{
sinePoints[i].x = i*GetScreenWidth()/180.0f;
sinePoints[i].y = screenHeight/2.0f + 150*sinf((2*PI/1.5f)*(1.0f/60.0f)*(float)i); // Calculate for 60 fps
}
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
@ -39,7 +60,59 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update variables / Implement example logic at this point
// Update circle sinusoidal movement
timeCounter += GetFrameTime();
circlePosition.x += GetScreenWidth()/180.0f;
circlePosition.y = screenHeight/2.0f + 150*sinf((2*PI/1.5f)*timeCounter);
if (circlePosition.x > screenWidth)
{
circlePosition.x = 0.0f;
circlePosition.y = screenHeight/2.0f;
timeCounter = 0.0f;
}
// Start-Stop GIF recording on CTRL+R
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_R))
{
if (gifRecording)
{
// Stop current recording and save file
gifRecording = false;
MsfGifResult result = msf_gif_end(&gifState);
SaveFileData(TextFormat("%s/screenrecording.gif", GetApplicationDirectory()), result.data, (unsigned int)result.dataSize);
msf_gif_free(result);
TraceLog(LOG_INFO, "Finish animated GIF recording");
}
else
{
// Start a new recording
gifRecording = true;
gifFrameCounter = 0;
msf_gif_begin(&gifState, GetRenderWidth(), GetRenderHeight());
TraceLog(LOG_INFO, "Start animated GIF recording");
}
}
if (gifRecording)
{
gifFrameCounter++;
// NOTE: We record one gif frame depending on the desired gif framerate
if (gifFrameCounter > GIF_RECORD_FRAMERATE)
{
// Get image data for the current frame (from backbuffer)
// WARNING: This process is quite slow, it can generate stuttering
Image imScreen = LoadImageFromScreen();
// Add the frame to the gif recording, providing and "estimated" time for display in centiseconds
msf_gif_frame(&gifState, imScreen.data, (int)((1.0f/60.0f)*GIF_RECORD_FRAMERATE)/10, 16, imScreen.width*4);
gifFrameCounter = 0;
UnloadImage(imScreen); // Free image data
}
}
//----------------------------------------------------------------------------------
// Draw
@ -48,20 +121,43 @@ int main(void)
ClearBackground(RAYWHITE);
// TODO: Draw everything that requires to be drawn at this point
for (int i = 0; i < (MAX_SINEWAVE_POINTS - 1); i++)
{
DrawLineV(sinePoints[i], sinePoints[i + 1], MAROON);
DrawCircleV(sinePoints[i], 3, MAROON);
}
DrawLineEx((Vector2){ 0, 0 }, (Vector2){ screenWidth, screenHeight }, 2.0f, RED);
DrawLineEx((Vector2){ 0, screenHeight }, (Vector2){ screenWidth, 0 }, 2.0f, RED);
DrawText("example base code template", 260, 400, 20, LIGHTGRAY);
DrawCircleV(circlePosition, 30, RED);
DrawFPS(10, 10);
/*
// Draw record indicator
// WARNING: If drawn here, it will appear in the recorded image,
// use a render texture instead for the recording and LoadImageFromTexture(rt.texture)
if (gifRecording)
{
// Display the recording indicator every half-second
if ((int)(GetTime()/0.5)%2 == 1)
{
DrawCircle(30, GetScreenHeight() - 20, 10, MAROON);
DrawText("GIF RECORDING", 50, GetScreenHeight() - 25, 10, RED);
}
}
*/
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
// TODO: Unload all loaded resources at this point
// If still recording a GIF on close window, just finish
if (gifRecording)
{
MsfGifResult result = msf_gif_end(&gifState);
msf_gif_free(result);
gifRecording = false;
}
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -19,6 +19,8 @@
#include "raymath.h" // Required for: Lerp()
#include <string.h>
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
@ -59,10 +61,11 @@ int main(void)
int lastSpace = 0; // Keeping track of last valid space to insert '\n'
int lastWrapStart = 0; // Keeping track of the start of this wrapped line.
while (lines[i][j] != '\0')
while (j <= strlen(lines[i]))
{
if (lines[i][j] == ' ')
if (lines[i][j] == ' ' || lines[i][j] == '\0')
{
char before = lines[i][j];
// Making a C Style string by adding a '\0' at the required location so that we can use the MeasureText function
lines[i][j] = '\0';
@ -75,7 +78,7 @@ int main(void)
lastWrapStart = lastSpace + 1;
}
lines[i][j] = ' '; // Resetting the space back
if(before != '\0') lines[i][j] = ' '; // Resetting the space back
lastSpace = j; // Since we encountered a new space we update our last encountered space location
}
@ -92,7 +95,7 @@ int main(void)
textHeight += (int)size.y + 10;
}
// A simple scrollbar on the side to show how far we have red into the file
// A simple scrollbar on the side to show how far we have read into the file
Rectangle scrollBar = {
.x = (float)screenWidth - 5,
.y = 0,
@ -132,7 +135,13 @@ int main(void)
for (int i = 0, t = textTop; i < lineCount; i++)
{
// Each time we go through and calculate the height of the text to move the cursor appropriately
Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
Vector2 size;
if(strcmp(lines[i], "")){
// Fix for empty line in the text file
size = MeasureTextEx( GetFontDefault(), lines[i], (float)fontSize, 2);
}else{
size = MeasureTextEx( GetFontDefault(), " ", (float)fontSize, 2);
}
DrawText(lines[i], 10, t, fontSize, RED);

View File

@ -0,0 +1,321 @@
/*******************************************************************************************
*
* raylib [core] example - viewport scaling
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Agnis Aldiņš (@nezvers) 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) 2025 Agnis Aldiņš (@nezvers)
*
********************************************************************************************/
#include "raylib.h"
#define RESOLUTION_COUNT 4 // For iteration purposes and teaching example
typedef enum {
// Only upscale, useful for pixel art
KEEP_ASPECT_INTEGER,
KEEP_HEIGHT_INTEGER,
KEEP_WIDTH_INTEGER,
// Can also downscale
KEEP_ASPECT,
KEEP_HEIGHT,
KEEP_WIDTH,
// For itteration purposes and as a teaching example
VIEWPORT_TYPE_COUNT,
} ViewportType;
// For displaying on GUI
const char *ViewportTypeNames[VIEWPORT_TYPE_COUNT] = {
"KEEP_ASPECT_INTEGER",
"KEEP_HEIGHT_INTEGER",
"KEEP_WIDTH_INTEGER",
"KEEP_ASPECT",
"KEEP_HEIGHT",
"KEEP_WIDTH",
};
//--------------------------------------------------------------------------------------
// Module Functions Declaration
//--------------------------------------------------------------------------------------
static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
static void KeepAspectCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
static void KeepHeightCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
static void KeepWidthCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
static void ResizeRenderSize(ViewportType viewportType, int *screenWidth, int *screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect, RenderTexture2D *target);
// Example how to calculate position on RenderTexture
static Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle *textureRect, Rectangle *scaledRect);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//---------------------------------------------------------
int screenWidth = 800;
int screenHeight = 450;
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(screenWidth, screenHeight, "raylib [core] example - viewport scaling");
// Preset resolutions that could be created by subdividing screen resolution
Vector2 resolutionList[RESOLUTION_COUNT] = {
(Vector2){ 64, 64 },
(Vector2){ 256, 240 },
(Vector2){ 320, 180 },
// 4K doesn't work with integer scaling but included for example purposes with non-integer scaling
(Vector2){ 3840, 2160 },
};
int resolutionIndex = 0;
int gameWidth = 64;
int gameHeight = 64;
RenderTexture2D target = (RenderTexture2D){ 0 };
Rectangle sourceRect = (Rectangle){ 0 };
Rectangle destRect = (Rectangle){ 0 };
ViewportType viewportType = KEEP_ASPECT_INTEGER;
ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
// Button rectangles
Rectangle decreaseResolutionButton = (Rectangle){ 200, 30, 10, 10 };
Rectangle increaseResolutionButton = (Rectangle){ 215, 30, 10, 10 };
Rectangle decreaseTypeButton = (Rectangle){ 200, 45, 10, 10 };
Rectangle increaseTypeButton = (Rectangle){ 215, 45, 10, 10 };
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//----------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsWindowResized()) ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
Vector2 mousePosition = GetMousePosition();
bool mousePressed = IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
// Check buttons and rescale
if (CheckCollisionPointRec(mousePosition, decreaseResolutionButton) && mousePressed)
{
resolutionIndex = (resolutionIndex + RESOLUTION_COUNT - 1)%RESOLUTION_COUNT;
gameWidth = resolutionList[resolutionIndex].x;
gameHeight = resolutionList[resolutionIndex].y;
ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
}
if (CheckCollisionPointRec(mousePosition, increaseResolutionButton) && mousePressed)
{
resolutionIndex = (resolutionIndex + 1)%RESOLUTION_COUNT;
gameWidth = resolutionList[resolutionIndex].x;
gameHeight = resolutionList[resolutionIndex].y;
ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
}
if (CheckCollisionPointRec(mousePosition, decreaseTypeButton) && mousePressed)
{
viewportType = (viewportType + VIEWPORT_TYPE_COUNT - 1)%VIEWPORT_TYPE_COUNT;
ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
}
if (CheckCollisionPointRec(mousePosition, increaseTypeButton) && mousePressed)
{
viewportType = (viewportType + 1)%VIEWPORT_TYPE_COUNT;
ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
}
Vector2 textureMousePosition = Screen2RenderTexturePosition(mousePosition, &sourceRect, &destRect);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw our scene to the render texture
BeginTextureMode(target);
ClearBackground(WHITE);
DrawCircle(textureMousePosition.x, textureMousePosition.y, 20.0f, LIME);
EndTextureMode();
// Draw render texture to main framebuffer
BeginDrawing();
ClearBackground(BLACK);
// Draw our render texture with rotation applied
DrawTexturePro(target.texture, sourceRect, destRect, (Vector2){ 0.0f, 0.0f }, 0.0f, WHITE);
// Draw Native resolution (GUI or anything)
// Draw info box
Rectangle infoRect = (Rectangle){5, 5, 330, 105};
DrawRectangleRec(infoRect, Fade(LIGHTGRAY, 0.7f));
DrawRectangleLines(infoRect.x, infoRect.y, infoRect.width, infoRect.height, BLUE);
DrawText(TextFormat("Window Resolution: %d x %d", screenWidth, screenHeight), 15, 15, 10, BLACK);
DrawText(TextFormat("Game Resolution: %d x %d", gameWidth, gameHeight), 15, 30, 10, BLACK);
DrawText(TextFormat("Type: %s", ViewportTypeNames[viewportType]), 15, 45, 10, BLACK);
Vector2 scaleRatio = (Vector2){destRect.width/sourceRect.width, -destRect.height/sourceRect.height};
if (scaleRatio.x < 0.001f || scaleRatio.y < 0.001f) DrawText(TextFormat("Scale ratio: INVALID"), 15, 60, 10, BLACK);
else DrawText(TextFormat("Scale ratio: %.2f x %.2f", scaleRatio.x, scaleRatio.y), 15, 60, 10, BLACK);
DrawText(TextFormat("Source size: %.2f x %.2f", sourceRect.width, -sourceRect.height), 15, 75, 10, BLACK);
DrawText(TextFormat("Destination size: %.2f x %.2f", destRect.width, destRect.height), 15, 90, 10, BLACK);
// Draw buttons
DrawRectangleRec(decreaseTypeButton, SKYBLUE);
DrawRectangleRec(increaseTypeButton, SKYBLUE);
DrawRectangleRec(decreaseResolutionButton, SKYBLUE);
DrawRectangleRec(increaseResolutionButton, SKYBLUE);
DrawText("<", decreaseTypeButton.x + 3, decreaseTypeButton.y + 1, 10, BLACK);
DrawText(">", increaseTypeButton.x + 3, increaseTypeButton.y + 1, 10, BLACK);
DrawText("<", decreaseResolutionButton.x + 3, decreaseResolutionButton.y + 1, 10, BLACK);
DrawText(">", increaseResolutionButton.x + 3, increaseResolutionButton.y + 1, 10, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//----------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//----------------------------------------------------------------------------------
return 0;
}
//--------------------------------------------------------------------------------------
// Module Functions Definition
//--------------------------------------------------------------------------------------
static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
{
sourceRect->x = 0.0f;
sourceRect->y = (float)gameHeight;
sourceRect->width = (float)gameWidth;
sourceRect->height = (float)-gameHeight;
const int ratio_x = (screenWidth/gameWidth);
const int ratio_y = (screenHeight/gameHeight);
const float resizeRatio = (float)((ratio_x < ratio_y)? ratio_x : ratio_y);
destRect->x = (float)(int)((screenWidth - (gameWidth*resizeRatio))*0.5f);
destRect->y = (float)(int)((screenHeight - (gameHeight*resizeRatio))*0.5f);
destRect->width = (float)(int)(gameWidth*resizeRatio);
destRect->height = (float)(int)(gameHeight*resizeRatio);
}
static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
{
const float resizeRatio = (float)(screenHeight/gameHeight);
sourceRect->x = 0.0f;
sourceRect->y = 0.0f;
sourceRect->width = (float)(int)(screenWidth/resizeRatio);
sourceRect->height = (float)-gameHeight;
destRect->x = (float)(int)((screenWidth - (sourceRect->width*resizeRatio))*0.5f);
destRect->y = (float)(int)((screenHeight - (gameHeight*resizeRatio))*0.5f);
destRect->width = (float)(int)(sourceRect->width*resizeRatio);
destRect->height = (float)(int)(gameHeight*resizeRatio);
}
static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
{
const float resizeRatio = (float)(screenWidth/gameWidth);
sourceRect->x = 0.0f;
sourceRect->y = 0.0f;
sourceRect->width = (float)gameWidth;
sourceRect->height = (float)(int)(screenHeight/resizeRatio);
destRect->x = (float)(int)((screenWidth - (gameWidth*resizeRatio))*0.5f);
destRect->y = (float)(int)((screenHeight - (sourceRect->height*resizeRatio))*0.5f);
destRect->width = (float)(int)(gameWidth*resizeRatio);
destRect->height = (float)(int)(sourceRect->height*resizeRatio);
sourceRect->height *= -1.0f;
}
static void KeepAspectCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
{
sourceRect->x = 0.0f;
sourceRect->y = (float)gameHeight;
sourceRect->width = (float)gameWidth;
sourceRect->height = (float)-gameHeight;
const float ratio_x = ((float)screenWidth/(float)gameWidth);
const float ratio_y = ((float)screenHeight/(float)gameHeight);
const float resizeRatio = (ratio_x < ratio_y ? ratio_x : ratio_y);
destRect->x = (float)(int)((screenWidth - (gameWidth*resizeRatio))*0.5f);
destRect->y = (float)(int)((screenHeight - (gameHeight*resizeRatio))*0.5f);
destRect->width = (float)(int)(gameWidth*resizeRatio);
destRect->height = (float)(int)(gameHeight*resizeRatio);
}
static void KeepHeightCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
{
const float resizeRatio = ((float)screenHeight/(float)gameHeight);
sourceRect->x = 0.0f;
sourceRect->y = 0.0f;
sourceRect->width = (float)(int)((float)screenWidth/resizeRatio);
sourceRect->height = (float)-gameHeight;
destRect->x = (float)(int)((screenWidth - (sourceRect->width*resizeRatio))*0.5f);
destRect->y = (float)(int)((screenHeight - (gameHeight*resizeRatio))*0.5f);
destRect->width = (float)(int)(sourceRect->width*resizeRatio);
destRect->height = (float)(int)(gameHeight*resizeRatio);
}
static void KeepWidthCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
{
const float resizeRatio = ((float)screenWidth/(float)gameWidth);
sourceRect->x = 0.0f;
sourceRect->y = 0.0f;
sourceRect->width = (float)gameWidth;
sourceRect->height = (float)(int)((float)screenHeight/resizeRatio);
destRect->x = (float)(int)((screenWidth - (gameWidth*resizeRatio))*0.5f);
destRect->y = (float)(int)((screenHeight - (sourceRect->height*resizeRatio))*0.5f);
destRect->width = (float)(int)(gameWidth*resizeRatio);
destRect->height = (float)(int)(sourceRect->height*resizeRatio);
sourceRect->height *= -1.f;
}
static void ResizeRenderSize(ViewportType viewportType, int *screenWidth, int *screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect, RenderTexture2D *target)
{
*screenWidth = GetScreenWidth();
*screenHeight = GetScreenHeight();
switch(viewportType)
{
case KEEP_ASPECT_INTEGER: KeepAspectCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
case KEEP_HEIGHT_INTEGER: KeepHeightCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
case KEEP_WIDTH_INTEGER: KeepWidthCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
case KEEP_ASPECT: KeepAspectCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
case KEEP_HEIGHT: KeepHeightCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
case KEEP_WIDTH: KeepWidthCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
default: break;
}
UnloadRenderTexture(*target);
*target = LoadRenderTexture(sourceRect->width, -sourceRect->height);
}
// Example how to calculate position on RenderTexture
static Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle *textureRect, Rectangle *scaledRect)
{
Vector2 relativePosition = {point.x - scaledRect->x, point.y - scaledRect->y};
Vector2 ratio = {textureRect->width/scaledRect->width, -textureRect->height/scaledRect->height};
return (Vector2){relativePosition.x*ratio.x, relativePosition.y*ratio.x};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -43,7 +43,7 @@ int main(void)
*/
// Set configuration flags for window creation
//SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI);
//SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI);// | FLAG_WINDOW_TRANSPARENT);
InitWindow(screenWidth, screenHeight, "raylib [core] example - window flags");
Vector2 ballPosition = { GetScreenWidth()/2.0f, GetScreenHeight()/2.0f };
@ -97,7 +97,8 @@ int main(void)
if (IsWindowState(FLAG_WINDOW_MINIMIZED))
{
framesCounter++;
if (framesCounter >= 240) {
if (framesCounter >= 240)
{
RestoreWindow(); // Restore window after 3 seconds
framesCounter = 0;
}

View File

@ -18,7 +18,7 @@
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main()
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@ core;core_3d_camera_mode;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@rays
core;core_3d_camera_free;★☆☆☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5
core;core_3d_camera_first_person;★★☆☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5
core;core_3d_camera_split_screen;★★★☆;3.7;4.0;2021;2025;"Jeffery Myers";@JeffM2501
core;core_3d_camera_fps;★★★☆;5.5;5.5;2025;2025;"Agnis Aldins";@nezvers
core;core_3d_camera_fps;★★★☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers
core;core_3d_picking;★★☆☆;1.3;4.0;2015;2025;"Ramon Santamaria";@raysan5
core;core_world_screen;★★☆☆;1.3;1.4;2015;2025;"Ramon Santamaria";@raysan5
core;core_window_flags;★★★☆;3.5;3.5;2020;2025;"Ramon Santamaria";@raysan5
@ -43,15 +43,17 @@ core;core_custom_frame_control;★★★★;4.0;4.0;2021;2025;"Ramon Santamaria"
core;core_smooth_pixelperfect;★★★☆;3.7;4.0;2021;2025;"Giancamillo Alessandroni";@NotManyIdeasDev
core;core_random_sequence;★☆☆☆;5.0;5.0;2023;2025;"Dalton Overmyer";@REDl3east
core;core_automation_events;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria";@raysan5
core;core_high_dpi;★★☆☆;5.0;5.5;2025;2025;"Jonathan Marler";@marler8997
core;core_highdpi_demo;★★☆☆;5.0;5.5;2025;2025;"Jonathan Marler";@marler8997
core;core_render_texture;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_undo_redo;★★★☆;5.5;5.6;2025;2025;"Ramon Santamaria";@raysan5
core;core_viewport_scaling;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers
core;core_input_actions;★★☆☆;5.5;5.6;2025;2025;"Jett";@JettMonstersGoBoom
core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal
core;core_highdpi_testbed;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_screen_recording;★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary
core;core_screen_recording;★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_clipboard_text;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ananth S";@Ananth1839
core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04
core;core_compute_hash;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5
shapes;shapes_bouncing_ball;★☆☆☆;2.5;2.5;2013;2025;"Ramon Santamaria";@raysan5
shapes;shapes_bullet_hell;★☆☆☆;5.6;5.6;2025;2025;"Zero";@zerohorsepower
@ -86,6 +88,10 @@ shapes;shapes_simple_particles;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@
shapes;shapes_starfield_effect;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
shapes;shapes_lines_drawing;★☆☆☆;5.6-dev;5.6;2025;2025;"Robin";@RobinsAviary
shapes;shapes_math_angle_rotation;★☆☆☆;5.6-dev;5.6;2025;2025;"Kris";@krispy-snacc
shapes;shapes_rlgl_color_wheel;★★★☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary
shapes;shapes_rlgl_triangle;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary
shapes;shapes_ball_physics;★★☆☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto
shapes;shapes_penrose_tile;★★★★;5.5;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto
textures;textures_logo_raylib;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5
textures;textures_srcrec_dstrec;★★★☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5
textures;textures_image_drawing;★★☆☆;1.4;1.4;2016;2025;"Ramon Santamaria";@raysan5
@ -111,7 +117,10 @@ textures;textures_gif_player;★★★☆;4.2;4.2;2021;2025;"Ramon Santamaria";@
textures;textures_image_kernel;★★★★;1.3;1.3;2015;2025;"Karim Salem";@kimo-s
textures;textures_image_channel;★★☆☆;5.5;5.5;2024;2025;"Bruno Cabral";@brccabral
textures;textures_image_rotate;★★☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5
textures;textures_screen_buffer;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers
textures;textures_textured_curve;★★★☆;4.5;4.5;2022;2025;"Jeffery Myers";@JeffM2501
textures;textures_sprite_stacking;★★☆☆;5.6-dev;6.0;2025;2025;"Robin";@RobinsAviary
textures;textures_cellular_automata;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
text;text_sprite_fonts;★☆☆☆;1.7;3.7;2017;2025;"Ramon Santamaria";@raysan5
text;text_font_spritefont;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5
text;text_font_filters;★★☆☆;1.3;4.2;2015;2025;"Ramon Santamaria";@raysan5
@ -127,6 +136,7 @@ text;text_3d_drawing;★★★★;3.5;4.0;2021;2025;"Vlad Adrian";@demizdor
text;text_codepoints_loading;★★★☆;4.2;4.2;2022;2025;"Ramon Santamaria";@raysan5
text;text_inline_styling;★★★☆;5.6-dev;5.6-dev;2025;2025;"Wagner Barongello";@SultansOfCode
text;text_words_alignment;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
text;text_strings_management;★★★☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto
models;models_animation_playing;★★☆☆;2.5;3.5;2019;2025;"Culacant";@culacant
models;models_billboard_rendering;★★★☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5
models;models_box_collisions;★☆☆☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5
@ -153,6 +163,7 @@ models;models_tesseract_view;★★☆☆;5.6-dev;5.6-dev;2024;2025;"Timothy van
models;models_basic_voxel;★★☆☆;5.5;5.5;2025;2025;"Tim Little";@timlittle
models;models_rotating_cube;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe
models;models_decals;★★★★;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
models;models_directional_billboard;★★☆☆;5.6-dev;5.6;2025;2025;"Robin";@RobinsAviary
shaders;shaders_ascii_rendering;★★☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu
shaders;shaders_basic_lighting;★★★★;3.0;4.2;2019;2025;"Chris Camacho";@chriscamacho
shaders;shaders_model_shader;★★☆☆;1.3;3.7;2014;2025;"Ramon Santamaria";@raysan5
@ -185,6 +196,7 @@ shaders;shaders_basic_pbr;★★★★;5.0;5.5;2023;2025;"Afan OLOVCIC";@_DevDad
shaders;shaders_lightmap_rendering;★★★☆;4.5;4.5;2019;2025;"Jussi Viitala";@nullstare
shaders;shaders_rounded_rectangle;★★★☆;5.5;5.5;2025;2025;"Anstro Pleuton";@anstropleuton
shaders;shaders_depth_rendering;★★★☆;5.6-dev;5.6-dev;2025;2025;"Luís Almeida";@luis605
shaders;shaders_game_of_life;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
audio;audio_module_playing;★☆☆☆;1.5;3.5;2016;2025;"Ramon Santamaria";@raysan5
audio;audio_music_stream;★☆☆☆;1.3;4.2;2015;2025;"Ramon Santamaria";@raysan5
audio;audio_raw_stream;★★★☆;1.6;4.2;2015;2025;"Ramon Santamaria";@raysan5
@ -193,6 +205,7 @@ audio;audio_mixed_processor;★★★★;4.2;4.2;2023;2025;"hkc";@hatkidchan
audio;audio_stream_effects;★★★★;4.2;5.0;2022;2025;"Ramon Santamaria";@raysan5
audio;audio_sound_multi;★★☆☆;5.0;5.0;2023;2025;"Jeffery Myers";@JeffM2501
audio;audio_sound_positioning;★★☆☆;5.5;5.5;2025;2025;"Le Juez Victor";@Bigfoot71
audio;audio_spectrum_visualizer;★★★☆;6.0;5.6-dev;2025;2025;"IANN";@meisei4
others;rlgl_standalone;★★★★;1.6;4.0;2014;2025;"Ramon Santamaria";@raysan5
others;rlgl_compute_shader;★★★★;4.0;4.0;2021;2025;"Teddy Astie";@tsnake41
others;easings_testbed;★★★☆;2.5;3.0;2019;2025;"Juan Miguel López";@flashback-fx

View File

@ -0,0 +1,116 @@
/*******************************************************************************************
*
* raylib [models] example - directional billboard
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
*
* Example contributed by Robin (@RobinsAviary) 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) 2025 Robin (@RobinsAviary)
* Killbot art by patvanmackelberg https://opengameart.org/content/killbot-8-directional under CC0
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
#include <stdlib.h>
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [models] example - directional billboard");
// Set up the camera
Camera camera = { 0 };
camera.position = (Vector3){ 2.0f, 1.0f, 2.0f }; // Starting position
camera.target = (Vector3){ 0.0f, 0.5f, 0.0f }; // Target position
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Up vector
camera.fovy = 45.0f; // FOV
camera.projection = CAMERA_PERSPECTIVE; // Projection type (Standard 3D perspective)
// Load billboard texture
Texture skillbot = LoadTexture("resources/skillbot.png");
// Timer to update animation
float anim_timer = 0.0f;
// Animation frame
unsigned int anim = 0;
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(&camera, CAMERA_ORBITAL);
// Update timer with delta time
anim_timer += GetFrameTime();
// Update frame index after a certain amount of time (half a second)
if (anim_timer > 0.5f)
{
anim_timer = 0.0f;
anim += 1;
}
// Reset frame index to zero on overflow
if (anim >= 4) anim = 0;
// Find the current direction frame based on the camera position to the billboard object
float dir = (float)floor(((Vector2Angle((Vector2){ 2.0f, 0.0f }, (Vector2){ camera.position.x, camera.position.z })/PI)*4.0f) + 0.25f);
// Correct frame index if angle is negative
if (dir < 0.0f)
{
dir = 8.0f - (float)abs((int)dir);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(camera);
DrawGrid(10, 1.0f);
// Draw billboard pointing straight up to the sky, rotated relative to the camera and offset from the bottom
DrawBillboardPro(camera, skillbot, (Rectangle){ 0.0f + (anim*24.0f), 0.0f + (dir*24.0f), 24.0f, 24.0f }, Vector3Zero(), (Vector3){ 0.0f, 1.0f, 0.0f }, Vector2One(), (Vector2){ 0.5f, 0.0f }, 0, WHITE);
EndMode3D();
// Render various variables for reference
DrawText(TextFormat("animation: %d", anim), 10, 10, 20, DARKGRAY);
DrawText(TextFormat("direction frame: %.0f", dir), 10, 40, 20, DARKGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
// Unload billboard texture
UnloadTexture(skillbot);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -67,7 +67,7 @@ int main(void)
models[i] = LoadModel(voxFileNames[i]);
double t1 = GetTime()*1000.0;
TraceLog(LOG_WARNING, TextFormat("[%s] File loaded in %.3f ms", voxFileNames[i], t1 - t0));
TraceLog(LOG_INFO, TextFormat("[%s] Model file loaded in %.3f ms", voxFileNames[i], t1 - t0));
// Compute model translation matrix to center model on draw position (0, 0 , 0)
BoundingBox bb = GetModelBoundingBox(models[i]);
@ -80,6 +80,8 @@ int main(void)
}
int currentModel = 0;
Vector3 modelpos = { 0 };
Vector3 camerarot = { 0 };
// Load voxel shader
Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/voxel_lighting.vs", GLSL_VERSION),
@ -98,11 +100,7 @@ int main(void)
// Assign out lighting shader to model
for (int i = 0; i < MAX_VOX_FILES; i++)
{
Model m = models[i];
for (int j = 0; j < m.materialCount; j++)
{
m.materials[j].shader = shader;
}
for (int j = 0; j < models[i].materialCount; j++) models[i].materials[j].shader = shader;
}
// Create lights
@ -112,12 +110,8 @@ int main(void)
lights[2] = CreateLight(LIGHT_POINT, (Vector3) { -20, 20, 20 }, Vector3Zero(), GRAY, shader);
lights[3] = CreateLight(LIGHT_POINT, (Vector3) { 20, -20, -20 }, Vector3Zero(), GRAY, shader);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
Vector3 modelpos = { 0 };
Vector3 camerarot = { 0 };
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
@ -137,14 +131,10 @@ int main(void)
}
UpdateCameraPro(&camera,
(Vector3) {
(IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - // Move forward-backward
(IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f,
(IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - // Move right-left
(IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f,
0.0f // Move up-down
},
camerarot,
(Vector3){ (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, // Move forward-backward
(IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, // Move right-left
0.0f }, // Move up-down
camerarot, // Camera rotation
GetMouseWheelMove()*-2.0f); // Move to target (zoom)
// Cycle between models on mouse click
@ -156,8 +146,8 @@ int main(void)
// Update light values (actually, only enable/disable them)
for (int i = 0; i < MAX_LIGHTS; i++) UpdateLightValues(shader, lights[i]);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
@ -166,7 +156,6 @@ int main(void)
// Draw 3D model
BeginMode3D(camera);
DrawModel(models[currentModel], modelpos, 1.0f, WHITE);
DrawGrid(10, 1.0);
@ -176,16 +165,15 @@ int main(void)
if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, lights[i].color);
else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lights[i].color, 0.3f));
}
EndMode3D();
// Display info
DrawRectangle(10, 400, 340, 60, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(10, 400, 340, 60, Fade(DARKBLUE, 0.5f));
DrawText("MOUSE LEFT BUTTON to CYCLE VOX MODELS", 40, 410, 10, BLUE);
DrawText("MOUSE MIDDLE BUTTON to ZOOM OR ROTATE CAMERA", 40, 420, 10, BLUE);
DrawText("UP-DOWN-LEFT-RIGHT KEYS to MOVE CAMERA", 40, 430, 10, BLUE);
DrawText(TextFormat("File: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
DrawRectangle(10, 40, 340, 70, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(10, 40, 340, 70, Fade(DARKBLUE, 0.5f));
DrawText("- MOUSE LEFT BUTTON: CYCLE VOX MODELS", 20, 50, 10, BLUE);
DrawText("- MOUSE MIDDLE BUTTON: ZOOM OR ROTATE CAMERA", 20, 70, 10, BLUE);
DrawText("- UP-DOWN-LEFT-RIGHT KEYS: MOVE CAMERA", 20, 90, 10, BLUE);
DrawText(TextFormat("Model file: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
EndDrawing();
//----------------------------------------------------------------------------------
@ -201,5 +189,3 @@ int main(void)
return 0;
}

View File

@ -32,7 +32,7 @@ static Mesh GenMeshPoints(int numPoints);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main()
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
@ -57,7 +57,7 @@ int main()
Mesh mesh = GenMeshPoints(numPoints);
Model model = LoadModelFromMesh(mesh);
//SetTargetFPS(60);
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
@ -92,15 +92,12 @@ int main()
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(BLACK);
BeginMode3D(camera);
// The new method only uploads the points once to the GPU
if (useDrawModelPoints)
{
DrawModelPoints(model, position, 1.0f, WHITE);
}
if (useDrawModelPoints) DrawModelPoints(model, position, 1.0f, WHITE);
else
{
// The old method must continually draw the "points" (lines)
@ -124,17 +121,16 @@ int main()
// Draw a unit sphere for reference
DrawSphereWires(position, 1.0f, 10, 10, YELLOW);
EndMode3D();
// Draw UI text
DrawText(TextFormat("Point Count: %d", numPoints), 20, screenHeight - 50, 40, WHITE);
DrawText("Up - increase points", 20, 70, 20, WHITE);
DrawText("Down - decrease points", 20, 100, 20, WHITE);
DrawText("Space - drawing function", 20, 130, 20, WHITE);
DrawText(TextFormat("Point Count: %d", numPoints), 10, screenHeight - 50, 40, WHITE);
DrawText("UP - Increase points", 10, 40, 20, WHITE);
DrawText("DOWN - Decrease points", 10, 70, 20, WHITE);
DrawText("SPACE - Drawing function", 10, 100, 20, WHITE);
if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 20, 160, 20, GREEN);
else DrawText("Using: DrawPoint3D()", 20, 160, 20, RED);
if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 10, 130, 20, GREEN);
else DrawText("Using: DrawPoint3D()", 10, 130, 20, RED);
DrawFPS(10, 10);

View File

@ -54,7 +54,8 @@ int main(void)
Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f);
Model skybox = LoadModelFromMesh(cube);
// Set this to true to use an HDR Texture, Note that raylib must be built with HDR Support for this to work SUPPORT_FILEFORMAT_HDR
// Set this to true to use an HDR Texture
// NOTE: raylib must be built with HDR Support for this to work: SUPPORT_FILEFORMAT_HDR
bool useHDR = false;
// Load skybox shader and set required locations
@ -91,9 +92,11 @@ int main(void)
}
else
{
Image img = LoadImage("resources/skybox.png");
skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(img, CUBEMAP_LAYOUT_AUTO_DETECT); // CUBEMAP_LAYOUT_PANORAMA
UnloadImage(img);
// TODO: WARNING: On PLATFORM_WEB it requires a big amount of memory to process input image
// and generate the required cubemap image to be passed to rlLoadTextureCubemap()
Image image = LoadImage("resources/skybox.png");
skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(image, CUBEMAP_LAYOUT_AUTO_DETECT);
UnloadImage(image);
}
DisableCursor(); // Limit cursor to relative movement inside the window
@ -132,9 +135,9 @@ int main(void)
}
else
{
Image img = LoadImage(droppedFiles.paths[0]);
skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(img, CUBEMAP_LAYOUT_AUTO_DETECT);
UnloadImage(img);
Image image = LoadImage(droppedFiles.paths[0]);
skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(image, CUBEMAP_LAYOUT_AUTO_DETECT);
UnloadImage(image);
}
TextCopy(skyboxFileName, droppedFiles.paths[0]);

View File

@ -22,7 +22,7 @@
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main()
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -36,7 +36,7 @@ void UpdateDrawFrame(void); // Update and Draw one frame
//----------------------------------------------------------------------------------
// Program main entry point
//----------------------------------------------------------------------------------
int main()
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

View File

@ -0,0 +1,44 @@
#version 100
precision highp float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Input size in pixels of the textures
uniform vec2 resolution;
void main()
{
// Size of one pixel in texture coordinates (from 0.0 to 1.0)
float x = 1.0/resolution.x;
float y = 1.0/resolution.y;
// Status of the current cell (1 = alive, 0 = dead)
int origValue = (texture2D(texture0, fragTexCoord).r < 0.1)? 1 : 0;
// Sum of alive neighbors
int sumValue = (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left
sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top
sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right
sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left
sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right
sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left
sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom
sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right
// Game of life rules:
// Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise
// Current cell goes from dead to alive when exactly 3 neighbors are alive
if ((origValue == 1 && sumValue == 2) || sumValue == 3)
gl_FragColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black
else
gl_FragColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE
}

View File

@ -1,6 +1,7 @@
#version 100
#extension GL_EXT_frag_depth : enable // Extension required for writing depth
precision mediump float; // Precision required for OpenGL ES2 (WebGL)
varying vec2 fragTexCoord;

View File

@ -2,6 +2,9 @@
#extension GL_EXT_frag_depth : enable //Extension required for writing depth
#extension GL_OES_standard_derivatives : enable //Extension used for fwidth()
#define ZERO 0
precision mediump float; // Precision required for OpenGL ES2 (WebGL)
// Input vertex attributes (from vertex shader)
@ -17,8 +20,6 @@ uniform vec3 camPos;
uniform vec3 camDir;
uniform vec2 screenCenter;
#define ZERO 0
// SRC: https://learnopengl.com/Advanced-OpenGL/Depth-testing
float CalcDepth(in vec3 rd, in float Idist)
{
@ -257,7 +258,8 @@ vec4 render(in vec3 ro, in vec3 rd)
return vec4(vec3(clamp(col,0.0,1.0)),t);
}
vec3 CalcRayDir(vec2 nCoord){
vec3 CalcRayDir(vec2 nCoord)
{
vec3 horizontal = normalize(cross(camDir,vec3(.0 , 1.0, .0)));
vec3 vertical = normalize(cross(horizontal,camDir));
return normalize(camDir + horizontal*nCoord.x + vertical*nCoord.y);
@ -287,6 +289,7 @@ void main()
color = res.xyz;
depth = CalcDepth(rd,res.w);
}
gl_FragColor = vec4(color , 1.0);
gl_FragDepthEXT = depth;
}

View File

@ -1,9 +1,9 @@
#version 100
precision mediump float;
#extension GL_OES_standard_derivatives : enable
precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;

View File

@ -0,0 +1,42 @@
#version 120
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Input size in pixels of the textures
uniform vec2 resolution;
void main()
{
// Size of one pixel in texture coordinates (from 0.0 to 1.0)
float x = 1.0/resolution.x;
float y = 1.0/resolution.y;
// Status of the current cell (1 = alive, 0 = dead)
int origValue = (texture2D(texture0, fragTexCoord).r < 0.1)? 1 : 0;
// Sum of alive neighbors
int sumValue = (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left
sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top
sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right
sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left
sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right
sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left
sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom
sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right
// Game of life rules:
// Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise
// Current cell goes from dead to alive when exactly 3 neighbors are alive
if (((origValue == 1) && (sumValue == 2)) || sumValue == 3)
gl_FragColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black
else
gl_FragColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE
}

View File

@ -0,0 +1,45 @@
#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;
// Input size in pixels of the textures
uniform vec2 resolution;
void main()
{
// Size of one pixel in texture coordinates (from 0.0 to 1.0)
float x = 1.0/resolution.x;
float y = 1.0/resolution.y;
// Status of the current cell (1 = alive, 0 = dead)
int origValue = (texture(texture0, fragTexCoord).r < 0.1)? 1 : 0;
// Sum of alive neighbors
int sumValue = (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left
sumValue += (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top
sumValue += (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right
sumValue += (texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left
sumValue += (texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right
sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left
sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom
sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right
// Game of life rules:
// Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise
// Current cell goes from dead to alive when exactly 3 neighbors are alive
if (((origValue == 1) && (sumValue == 2)) || sumValue == 3)
finalColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black
else
finalColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE
}

View File

@ -9,7 +9,7 @@ uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Output fragment color
//out vec4 finalColor;
out vec4 finalColor;
// NOTE: Add your custom variables here
@ -17,6 +17,6 @@ void main()
{
vec4 texelColor = texture(texture0, fragTexCoord);
gl_FragColor = texelColor*colDiffuse*fragColor;
gl_FragDepth = gl_FragCoord.z;
finalColor = texelColor*colDiffuse*fragColor;
gl_FragDepth = finalColor.z;
}

View File

@ -1,5 +1,7 @@
# version 330
#define ZERO 0
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
@ -13,10 +15,12 @@ uniform vec3 camPos;
uniform vec3 camDir;
uniform vec2 screenCenter;
#define ZERO 0
// Output fragment color
out vec4 finalColor;
// https://learnopengl.com/Advanced-OpenGL/Depth-testing
float CalcDepth(in vec3 rd, in float Idist){
float CalcDepth(in vec3 rd, in float Idist)
{
float local_z = dot(normalize(camDir),rd)*Idist;
return (1.0/(local_z) - 1.0/0.01)/(1.0/1000.0 -1.0/0.01);
}
@ -26,10 +30,8 @@ float sdHorseshoe(in vec3 p, in vec2 c, in float r, in float le, vec2 w)
{
p.x = abs(p.x);
float l = length(p.xy);
p.xy = mat2(-c.x, c.y,
c.y, c.x)*p.xy;
p.xy = vec2((p.y>0.0 || p.x>0.0)?p.x:l*sign(-c.x),
(p.x>0.0)?p.y:l);
p.xy = mat2(-c.x, c.y, c.y, c.x)*p.xy;
p.xy = vec2(((p.y > 0.0) || (p.x > 0.0))? p.x : l*sign(-c.x), (p.x>0.0)? p.y : l);
p.xy = vec2(p.x, abs(p.y - r)) - vec2(le, 0.0);
vec2 q = vec2(length(max(p.xy, 0.0)) + min(0.0, max(p.x, p.y)), p.z);
@ -44,17 +46,16 @@ float sdSixWayCutHollowSphere(vec3 p, float r, float h, float t)
{
// Six way symetry Transformation
vec3 ap = abs(p);
if (ap.x < max(ap.y, ap.z)){
if (ap.x < max(ap.y, ap.z))
{
if (ap.y < ap.z) ap.xz = ap.zx;
else ap.xy = ap.yx;
}
vec2 q = vec2(length(ap.yz), ap.x);
float w = sqrt(r*r-h*h);
return ((h*q.x<w*q.y) ? length(q-vec2(w,h)) :
abs(length(q)-r)) - t;
return ((h*q.x < w*q.y)? length(q - vec2(w, h)) : abs(length(q) - r)) - t;
}
// https://iquilezles.org/articles/boxfunctions
@ -65,8 +66,8 @@ vec2 iBox(in vec3 ro, in vec3 rd, in vec3 rad)
vec3 k = abs(m)*rad;
vec3 t1 = -n - k;
vec3 t2 = -n + k;
return vec2(max(max(t1.x, t1.y), t1.z),
min(min(t2.x, t2.y), t2.z));
return vec2(max(max(t1.x, t1.y), t1.z), min(min(t2.x, t2.y), t2.z));
}
vec2 opU(vec2 d1, vec2 d2)
@ -74,14 +75,17 @@ vec2 opU(vec2 d1, vec2 d2)
return (d1.x < d2.x)? d1 : d2;
}
vec2 map(in vec3 pos){
vec2 map(in vec3 pos)
{
vec2 res = vec2(sdHorseshoe(pos - vec3(-1.0, 0.08, 1.0), vec2(cos(1.3), sin(1.3)), 0.2, 0.3, vec2(0.03,0.5)), 11.5);
res = opU(res, vec2(sdSixWayCutHollowSphere(pos-vec3(0.0, 1.0, 0.0), 4.0, 3.5, 0.5), 4.5));
return res;
}
// https://www.shadertoy.com/view/Xds3zN
vec2 raycast(in vec3 ro, in vec3 rd){
vec2 raycast(in vec3 ro, in vec3 rd)
{
vec2 res = vec2(-1.0, -1.0);
float tmin = 1.0;
@ -111,7 +115,6 @@ vec2 raycast(in vec3 ro, in vec3 rd){
return res;
}
// https://iquilezles.org/articles/rmshadows
float calcSoftshadow(in vec3 ro, in vec3 rd, in float mint, in float tmax)
{
@ -126,12 +129,13 @@ float calcSoftshadow(in vec3 ro, in vec3 rd, in float mint, in float tmax)
float s = clamp(8.0*h/t, 0.0, 1.0);
res = min(res, s);
t += clamp(h, 0.01, 0.2);
if (res<0.004 || t>tmax) break;
}
res = clamp(res, 0.0, 1.0);
return res*res*(3.0-2.0*res);
if ((res < 0.004) || (t > tmax)) break;
}
res = clamp(res, 0.0, 1.0);
return res*res*(3.0-2.0*res);
}
// https://iquilezles.org/articles/normalsSDF
vec3 calcNormal(in vec3 pos)
@ -156,6 +160,7 @@ float calcAO(in vec3 pos, in vec3 nor)
sca *= 0.95;
if (occ>0.35) break;
}
return clamp(1.0 - 3.0*occ, 0.0, 1.0)*(0.5+0.5*nor.y);
}
@ -167,7 +172,7 @@ float checkersGradBox(in vec2 p)
// analytical integral (box filter)
vec2 i = 2.0*(abs(fract((p - 0.5*w)*0.5)-0.5) - abs(fract((p + 0.5*w)*0.5) - 0.5))/w;
// xor pattern
return 0.5 - 0.5*i.x*i.y;
return (0.5 - 0.5*i.x*i.y);
}
// https://www.shadertoy.com/view/tdS3DG
@ -249,7 +254,8 @@ vec4 render(in vec3 ro, in vec3 rd)
return vec4(vec3(clamp(col,0.0,1.0)),t);
}
vec3 CalcRayDir(vec2 nCoord){
vec3 CalcRayDir(vec2 nCoord)
{
vec3 horizontal = normalize(cross(camDir,vec3(.0 , 1.0, .0)));
vec3 vertical = normalize(cross(horizontal,camDir));
return normalize(camDir + horizontal*nCoord.x + vertical*nCoord.y);
@ -279,6 +285,7 @@ void main()
color = res.xyz;
depth = CalcDepth(rd,res.w);
}
gl_FragColor = vec4(color , 1.0);
finalColor = vec4(color , 1.0);
gl_FragDepth = depth;
}

View File

@ -77,7 +77,7 @@ static void UpdateLight(Shader shader, Light light);
//----------------------------------------------------------------------------------
// Program main entry point
//----------------------------------------------------------------------------------
int main()
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------

View File

@ -138,7 +138,7 @@ int main(void)
// De-Initialization
//--------------------------------------------------------------------------------------
for (int i = 0; i < MAX_TEXTURES; ++i) UnloadTexture(texture[i]);
for (int i = 0; i < MAX_TEXTURES; i++) UnloadTexture(texture[i]);
UnloadShader(shdrColorCorrection);
CloseWindow(); // Close window and OpenGL context

View File

@ -0,0 +1,353 @@
/*******************************************************************************************
*
* raylib [shaders] example - game of life
*
* Example complexity rating: [] 3/4
*
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
*
* Example originally created with raylib 5.6, last time updated with raylib 5.6
*
* Example contributed by Jordi Santonja (@JordSant) 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) 2025 Jordi Santonja (@JordSant)
*
********************************************************************************************/
#include "raylib.h"
#define RAYGUI_IMPLEMENTATION
#include "raygui.h" // Required for GUI controls
#if defined(PLATFORM_DESKTOP)
#define GLSL_VERSION 330
#else // PLATFORM_ANDROID, PLATFORM_WEB
#define GLSL_VERSION 100
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Interaction mode
typedef enum {
MODE_RUN = 0,
MODE_PAUSE,
MODE_DRAW,
} InteractionMode;
// Struct to store example preset patterns
typedef struct {
char *name;
Vector2 position;
} PresetPattern;
//----------------------------------------------------------------------------------
// Functions declaration
//----------------------------------------------------------------------------------
void FreeImageToDraw(Image **imageToDraw);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - game of life");
const int menuWidth = 100;
const int windowWidth = screenWidth - menuWidth;
const int windowHeight = screenHeight;
const int worldWidth = 2048;
const int worldHeight = 2048;
const int randomTiles = 8; // Random preset: divide the world to compute random points in each tile
const Rectangle worldRectSource = { 0, 0, (float)worldWidth, (float)-worldHeight };
const Rectangle worldRectDest = { 0, 0, (float)worldWidth, (float)worldHeight };
const Rectangle textureOnScreen = { 0, 0, (float)windowWidth, (float)windowHeight };
const PresetPattern presetPatterns[] = {
{ "Glider", { 0.5f, 0.5f } }, { "R-pentomino", { 0.5f, 0.5f } }, { "Acorn", { 0.5f,0.5f } },
{ "Spaceships", { 0.1f, 0.5f } }, { "Still lifes", { 0.5f, 0.5f } }, { "Oscillators", { 0.5f, 0.5f } },
{ "Puffer train", { 0.1f, 0.5f } }, { "Glider Gun", { 0.2f, 0.2f } }, { "Breeder", { 0.1f, 0.5f } },
{ "Random", { 0.5f, 0.5f } }
};
const int numberOfPresets = sizeof(presetPatterns)/sizeof(presetPatterns[0]);
int zoom = 1;
float offsetX = (worldWidth - windowWidth)/2.0f; // Centered on window
float offsetY = (worldHeight - windowHeight)/2.0f; // Centered on window
int framesPerStep = 1;
int frame = 0;
int preset = -1; // No button pressed for preset
int mode = MODE_RUN; // Starting mode: running
bool buttonZoomIn = false; // Button states: false not pressed
bool buttonZomOut = false;
bool buttonFaster = false;
bool buttonSlower = false;
// Load shader
Shader shdrGameOfLife = LoadShader(0, TextFormat("resources/shaders/glsl%i/game_of_life.fs", GLSL_VERSION));
// Set shader uniform size of the world
int resolutionLoc = GetShaderLocation(shdrGameOfLife, "resolution");
const float resolution[2] = { (float)worldWidth, (float)worldHeight };
SetShaderValue(shdrGameOfLife, resolutionLoc, resolution, SHADER_UNIFORM_VEC2);
// Define two textures: the current world and the previous world
RenderTexture2D world1 = LoadRenderTexture(worldWidth, worldHeight);
RenderTexture2D world2 = LoadRenderTexture(worldWidth, worldHeight);
BeginTextureMode(world2);
ClearBackground(RAYWHITE);
EndTextureMode();
Image startPattern = LoadImage("resources/game_of_life/r_pentomino.png");
UpdateTextureRec(world2.texture, (Rectangle){ worldWidth/2.0f, worldHeight/2.0f, (float)(startPattern.width), (float)(startPattern.height) }, startPattern.data);
UnloadImage(startPattern);
// Pointers to the two textures, to be swapped
RenderTexture2D *currentWorld = &world2;
RenderTexture2D *previousWorld = &world1;
// Image to be used in DRAW mode, to be changed with mouse input
Image *imageToDraw = NULL;
SetTargetFPS(60); // Set at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
frame++;
// Change zoom: both by buttons or by mouse wheel
float mouseWheelMove = GetMouseWheelMove();
if (buttonZoomIn || (buttonZomOut && (zoom > 1)) || (mouseWheelMove != 0.0f))
{
FreeImageToDraw(&imageToDraw); // Zoom change: free the image to draw to be recreated again
const float centerX = offsetX + (windowWidth/2.0f)/zoom;
const float centerY = offsetY + (windowHeight/2.0f)/zoom;
if (buttonZoomIn || (mouseWheelMove > 0.0f)) zoom *= 2;
if ((buttonZomOut || (mouseWheelMove < 0.0f)) && (zoom > 1)) zoom /= 2;
offsetX = centerX - (windowWidth/2.0f)/zoom;
offsetY = centerY - (windowHeight/2.0f)/zoom;
}
// Change speed: number of frames per step
if (buttonFaster && framesPerStep > 1) framesPerStep--;
if (buttonSlower) framesPerStep++;
// Mouse management
if ((mode == MODE_RUN) || (mode == MODE_PAUSE))
{
FreeImageToDraw(&imageToDraw); // Free the image to draw: no longer needed in these modes
// Pan with mouse left button
static Vector2 previousMousePosition = { 0.0f, 0.0f };
const Vector2 mousePosition = GetMousePosition();
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && (mousePosition.x < windowWidth))
{
offsetX -= (mousePosition.x - previousMousePosition.x)/zoom;
offsetY -= (mousePosition.y - previousMousePosition.y)/zoom;
}
previousMousePosition = mousePosition;
}
else // MODE_DRAW
{
const float offsetDecimalX = offsetX - floorf(offsetX);
const float offsetDecimalY = offsetY - floorf(offsetY);
int sizeInWorldX = (int)(ceilf((float)(windowWidth + offsetDecimalX*zoom)/zoom));
int sizeInWorldY = (int)(ceilf((float)(windowHeight + offsetDecimalY*zoom)/zoom));
if (offsetX + sizeInWorldX >= worldWidth) sizeInWorldX = worldWidth - (int)floorf(offsetX);
if (offsetY + sizeInWorldY >= worldHeight) sizeInWorldY = worldHeight - (int)floorf(offsetY);
// Create image to draw if not created yet
if (imageToDraw == NULL)
{
RenderTexture2D worldOnScreen = LoadRenderTexture(sizeInWorldX, sizeInWorldY);
BeginTextureMode(worldOnScreen);
DrawTexturePro(currentWorld->texture, (Rectangle) { floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), -(float)(sizeInWorldY) },
(Rectangle) { 0, 0, (float)(sizeInWorldX), (float)(sizeInWorldY) }, (Vector2) { 0, 0 }, 0.0f, WHITE);
EndTextureMode();
imageToDraw = (Image*)RL_MALLOC(sizeof(Image));
*imageToDraw = LoadImageFromTexture(worldOnScreen.texture);
UnloadRenderTexture(worldOnScreen);
}
const Vector2 mousePosition = GetMousePosition();
static int firstColor = -1;
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && (mousePosition.x < windowWidth))
{
int mouseX = (int)(mousePosition.x + offsetDecimalX*zoom)/zoom;
int mouseY = (int)(mousePosition.y + offsetDecimalY*zoom)/zoom;
if (mouseX >= sizeInWorldX) mouseX = sizeInWorldX - 1;
if (mouseY >= sizeInWorldY) mouseY = sizeInWorldY - 1;
if (firstColor == -1) firstColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1;
const int prevColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1;
ImageDrawPixel(imageToDraw, mouseX, mouseY, (firstColor) ? BLACK : RAYWHITE);
if (prevColor != firstColor) UpdateTextureRec(currentWorld->texture, (Rectangle){ floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), (float)(sizeInWorldY) }, imageToDraw->data);
}
else firstColor = -1;
}
// Load selected preset
if (preset >= 0)
{
Image pattern;
if (preset < numberOfPresets - 1) // Preset with pattern image lo load
{
switch (preset)
{
case 0: pattern = LoadImage("resources/game_of_life/glider.png"); break;
case 1: pattern = LoadImage("resources/game_of_life/r_pentomino.png"); break;
case 2: pattern = LoadImage("resources/game_of_life/acorn.png"); break;
case 3: pattern = LoadImage("resources/game_of_life/spaceships.png"); break;
case 4: pattern = LoadImage("resources/game_of_life/still_lifes.png"); break;
case 5: pattern = LoadImage("resources/game_of_life/oscillators.png"); break;
case 6: pattern = LoadImage("resources/game_of_life/puffer_train.png"); break;
case 7: pattern = LoadImage("resources/game_of_life/glider_gun.png"); break;
case 8: pattern = LoadImage("resources/game_of_life/breeder.png"); break;
}
BeginTextureMode(*currentWorld);
ClearBackground(RAYWHITE);
EndTextureMode();
UpdateTextureRec(currentWorld->texture, (Rectangle){ worldWidth*presetPatterns[preset].position.x - pattern.width/2.0f,
worldHeight*presetPatterns[preset].position.y - pattern.height/2.0f,
(float)(pattern.width), (float)(pattern.height) }, pattern.data);
}
else // Last preset: Random values
{
pattern = GenImageColor(worldWidth/randomTiles, worldHeight/randomTiles, RAYWHITE);
for (int i = 0; i < randomTiles; i++)
{
for (int j = 0; j < randomTiles; j++)
{
ImageClearBackground(&pattern, RAYWHITE);
for (int x = 0; x < pattern.width; x++)
{
for (int y = 0; y < pattern.height; y++)
{
if (GetRandomValue(0, 100) < 15) ImageDrawPixel(&pattern, x, y, BLACK);
}
}
UpdateTextureRec(currentWorld->texture,
(Rectangle){ (float)(pattern.width*i), (float)(pattern.height*j),
(float)(pattern.width), (float)(pattern.height) }, pattern.data);
}
}
}
UnloadImage(pattern);
mode = MODE_PAUSE;
offsetX = worldWidth*presetPatterns[preset].position.x - windowWidth/zoom/2.0f;
offsetY = worldHeight*presetPatterns[preset].position.y - windowHeight/zoom/2.0f;
}
// Check window draw inside world limits
if (offsetX < 0) offsetX = 0;
if (offsetY < 0) offsetY = 0;
if (offsetX > worldWidth - (float)(windowWidth)/zoom) offsetX = worldWidth - (float)(windowWidth)/zoom;
if (offsetY > worldHeight - (float)(windowHeight)/zoom) offsetY = worldHeight - (float)(windowHeight)/zoom;
// Rectangles for drawing texture portion to screen
const Rectangle textureSourceToScreen = { offsetX, offsetY, (float)windowWidth/zoom, (float)windowHeight/zoom };
//----------------------------------------------------------------------------------
// Draw to texture
//----------------------------------------------------------------------------------
if ((mode == MODE_RUN) && ((frame%framesPerStep) == 0))
{
// Swap worlds
RenderTexture2D *tempWorld = currentWorld;
currentWorld = previousWorld;
previousWorld = tempWorld;
// Draw to texture
BeginTextureMode(*currentWorld);
BeginShaderMode(shdrGameOfLife);
DrawTexturePro(previousWorld->texture, worldRectSource, worldRectDest, (Vector2){ 0, 0 }, 0.0f, RAYWHITE);
EndShaderMode();
EndTextureMode();
}
//----------------------------------------------------------------------------------
// Draw to screen
//----------------------------------------------------------------------------------
BeginDrawing();
DrawTexturePro(currentWorld->texture, textureSourceToScreen, textureOnScreen, (Vector2){ 0, 0 }, 0.0f, WHITE);
DrawLine(windowWidth, 0, windowWidth, screenHeight, (Color){ 218, 218, 218, 255 });
DrawRectangle(windowWidth, 0, screenWidth - windowWidth, screenHeight, (Color){ 232, 232, 232, 255 });
DrawText("Conway's", 704, 4, 20, DARKBLUE);
DrawText(" game of", 704, 19, 20, DARKBLUE);
DrawText(" life", 708, 34, 20, DARKBLUE);
DrawText("in raylib", 757, 42, 6, BLACK);
DrawText("Presets", 710, 58, 8, GRAY);
preset = -1;
for (int i = 0; i < numberOfPresets; i++)
if (GuiButton((Rectangle){ 710.0f, 70.0f + 18*i, 80.0f, 16.0f }, presetPatterns[i].name)) preset = i;
GuiToggleGroup((Rectangle){ 710, 258, 80, 16 }, "Run\nPause\nDraw", &mode);
DrawText(TextFormat("Zoom: %ix", zoom), 710, 316, 8, GRAY);
buttonZoomIn = GuiButton((Rectangle){ 710, 328, 80, 16 }, "Zoom in");
buttonZomOut = GuiButton((Rectangle){ 710, 346, 80, 16 }, "Zoom out");
DrawText(TextFormat("Speed: %i frame%s", framesPerStep, (framesPerStep > 1)? "s" : ""), 710, 370, 8, GRAY);
buttonFaster = GuiButton((Rectangle){ 710, 382, 80, 16 }, "Faster");
buttonSlower = GuiButton((Rectangle){ 710, 400, 80, 16 }, "Slower");
DrawFPS(712, 426);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shdrGameOfLife);
UnloadRenderTexture(world1);
UnloadRenderTexture(world2);
FreeImageToDraw(&imageToDraw);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
//----------------------------------------------------------------------------------
// Functions definition
//----------------------------------------------------------------------------------
void FreeImageToDraw(Image **imageToDraw)
{
if (*imageToDraw != NULL)
{
UnloadImage(**imageToDraw);
RL_FREE(*imageToDraw);
*imageToDraw = NULL;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -138,6 +138,7 @@ int main(void)
ClearBackground(RAYWHITE);
DrawTextureRec(target.texture, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, (Vector2) { 0, 0 }, WHITE);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------

View File

@ -33,7 +33,7 @@
#define GLSL_VERSION 100
#endif
#define MAP_SIZE 10
#define MAP_SIZE 16
//------------------------------------------------------------------------------------
// Program main entry point
@ -88,8 +88,6 @@ int main(void)
RenderTexture lightmap = LoadRenderTexture(MAP_SIZE, MAP_SIZE);
SetTextureFilter(lightmap.texture, TEXTURE_FILTER_TRILINEAR);
Material material = LoadMaterialDefault();
material.shader = shader;
material.maps[MATERIAL_MAP_ALBEDO].texture = texture;
@ -103,30 +101,34 @@ int main(void)
DrawTexturePro(
light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height },
(Rectangle){ 0, 0, 20, 20 },
(Vector2){ 10.0, 10.0 },
(Rectangle){ 0, 0, 2.0f*MAP_SIZE, 2.0f*MAP_SIZE },
(Vector2){ (float)MAP_SIZE, (float)MAP_SIZE },
0.0,
RED
);
DrawTexturePro(
light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height },
(Rectangle){ 8, 4, 20, 20 },
(Vector2){ 10.0, 10.0 },
(Rectangle){ (float)MAP_SIZE*0.8f, (float)MAP_SIZE/2.0f, 2.0f*MAP_SIZE, 2.0f*MAP_SIZE },
(Vector2){ (float)MAP_SIZE, (float)MAP_SIZE },
0.0,
BLUE
);
DrawTexturePro(
light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height },
(Rectangle){ 8, 8, 10, 10 },
(Vector2){ 5.0, 5.0 },
(Rectangle){ (float)MAP_SIZE*0.8f, (float)MAP_SIZE*0.8f, (float)MAP_SIZE, (float)MAP_SIZE },
(Vector2){ (float)MAP_SIZE/2.0f, (float)MAP_SIZE/2.0f },
0.0,
GREEN
);
BeginBlendMode(BLEND_ALPHA);
EndTextureMode();
// NOTE: To enable trilinear filtering we need mipmaps available for texture
GenTextureMipmaps(&lightmap.texture);
SetTextureFilter(lightmap.texture, TEXTURE_FILTER_TRILINEAR);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
@ -141,24 +143,20 @@ int main(void)
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(camera);
DrawMesh(mesh, material, MatrixIdentity());
EndMode3D();
DrawFPS(10, 10);
DrawTexturePro(
lightmap.texture,
(Rectangle){ 0, 0, -MAP_SIZE, -MAP_SIZE },
DrawTexturePro(lightmap.texture, (Rectangle){ 0, 0, -MAP_SIZE, -MAP_SIZE },
(Rectangle){ (float)GetRenderWidth() - MAP_SIZE*8 - 10, 10, (float)MAP_SIZE*8, (float)MAP_SIZE*8 },
(Vector2){ 0.0, 0.0 },
0.0,
WHITE);
(Vector2){ 0.0, 0.0 }, 0.0, WHITE);
DrawText("lightmap", GetRenderWidth() - 66, 16 + MAP_SIZE*8, 10, GRAY);
DrawText("10x10 pixels", GetRenderWidth() - 76, 30 + MAP_SIZE*8, 10, GRAY);
DrawText(TextFormat("LIGHTMAP: %ix%i pixels", MAP_SIZE, MAP_SIZE), GetRenderWidth() - 130, 20 + MAP_SIZE*8, 10, GREEN);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,221 @@
/*******************************************************************************************
*
* raylib [shapes] example - ball physics
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
*
* Example contributed by David Buzatto (@davidbuzatto) 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) 2025 David Buzatto (@davidbuzatto)
*
********************************************************************************************/
#include "raylib.h"
#include <stdlib.h>
#include <math.h>
#define MAX_BALLS 5000 // Maximum quantity of balls
typedef struct Ball {
Vector2 pos; // Position
Vector2 vel; // Velocity
Vector2 ppos; // Previous position
float radius;
float friction;
float elasticity;
Color color;
bool grabbed;
} Ball;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - ball physics");
Ball balls[MAX_BALLS] = {{
.pos = { GetScreenWidth()/2, GetScreenHeight()/2 },
.vel = { 200, 200 },
.ppos = { 0 },
.radius = 40,
.friction = 0.99,
.elasticity = 0.9,
.color = BLUE,
.grabbed = false
}};
int ballCount = 1;
Ball *grabbedBall = NULL; // A pointer to the current ball that is grabbed
Vector2 pressOffset = {0}; // Mouse press offset relative to the ball that grabbedd
float gravity = 100; // World gravity
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//---------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
float delta = GetFrameTime();
Vector2 mousePos = GetMousePosition();
// Checks if a ball was grabbed
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
{
for (int i = ballCount - 1; i >= 0; i--)
{
Ball *ball = &balls[i];
pressOffset.x = mousePos.x - ball->pos.x;
pressOffset.y = mousePos.y - ball->pos.y;
// If the distance between the ball position and the mouse press position
// is less than or equal to the ball radius, the event occurred inside the ball
if (hypot(pressOffset.x, pressOffset.y) <= ball->radius)
{
ball->grabbed = true;
grabbedBall = ball;
break;
}
}
}
// Releases any ball the was grabbed
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
{
if (grabbedBall != NULL)
{
grabbedBall->grabbed = false;
grabbedBall = NULL;
}
}
// Creates a new ball
if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) || (IsKeyDown(KEY_LEFT_CONTROL) && IsMouseButtonDown(MOUSE_BUTTON_RIGHT)))
{
if (ballCount < MAX_BALLS)
{
balls[ballCount++] = (Ball){
.pos = mousePos,
.vel = { GetRandomValue(-300, 300), GetRandomValue(-300, 300) },
.ppos = { 0 },
.radius = 20 + GetRandomValue(0, 30),
.friction = 0.99,
.elasticity = 0.9,
.color = { GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 },
.grabbed = false
};
}
}
// Shake balls
if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
{
for (int i = 0; i < ballCount; i++)
{
if (!balls[i].grabbed) balls[i].vel = (Vector2){ GetRandomValue(-2000, 2000), GetRandomValue(-2000, 2000) };
}
}
// Changes gravity
gravity += GetMouseWheelMove()*5;
// Updates each ball state
for (int i = 0; i < ballCount; i++)
{
Ball *ball = &balls[i];
// The ball is not grabbed
if (!ball->grabbed)
{
// Ball repositioning using the velocity
ball->pos.x += ball->vel.x * delta;
ball->pos.y += ball->vel.y * delta;
// Does the ball hit the screen right boundary?
if ((ball->pos.x + ball->radius) >= screenWidth)
{
ball->pos.x = screenWidth - ball->radius; // Ball repositioning
ball->vel.x = -ball->vel.x*ball->elasticity; // Elasticity makes the ball lose 10% of its velocity on hit
}
// Does the ball hit the screen left boundary?
else if ((ball->pos.x - ball->radius) <= 0)
{
ball->pos.x = ball->radius;
ball->vel.x = -ball->vel.x*ball->elasticity;
}
// The same for y axis
if ((ball->pos.y + ball->radius) >= screenHeight)
{
ball->pos.y = screenHeight - ball->radius;
ball->vel.y = -ball->vel.y*ball->elasticity;
}
else if ((ball->pos.y - ball->radius) <= 0)
{
ball->pos.y = ball->radius;
ball->vel.y = -ball->vel.y*ball->elasticity;
}
// Friction makes the ball lose 1% of its velocity each frame
ball->vel.x = ball->vel.x*ball->friction;
// Gravity affects only the y axis
ball->vel.y = ball->vel.y*ball->friction + gravity;
}
else
{
// Ball repositioning using the mouse position
ball->pos.x = mousePos.x - pressOffset.x;
ball->pos.y = mousePos.y - pressOffset.y;
// While the ball is grabbed, recalculates its velocity
ball->vel.x = (ball->pos.x - ball->ppos.x)/delta;
ball->vel.y = (ball->pos.y - ball->ppos.y)/delta;
ball->ppos = ball->pos;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
for (int i = 0; i < ballCount; i++)
{
DrawCircleV(balls[i].pos, balls[i].radius, balls[i].color);
DrawCircleLinesV(balls[i].pos, balls[i].radius, BLACK);
}
DrawText("grab a ball by pressing with the mouse and throw it by releasing", 10, 10, 10, DARKGRAY);
DrawText("right click to create new balls (keep left control pressed to create a lot)", 10, 30, 10, DARKGRAY);
DrawText("use mouse wheel to change gravity", 10, 50, 10, DARKGRAY);
DrawText("middle click to shake", 10, 70, 10, DARKGRAY);
DrawText(TextFormat("BALL COUNT: %d", ballCount), 10, GetScreenHeight() - 70, 20, BLACK);
DrawText(TextFormat("GRAVITY: %.2f", gravity), 10, GetScreenHeight() - 40, 20, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -14,9 +14,6 @@
* Copyright (c) 2025 JP Mortiboys (@themushroompirates)
*
********************************************************************************************/
#if defined(WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "raylib.h"
@ -63,24 +60,16 @@ int main(void)
/* 8 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
/* 9 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR },
};
// Time for the hands to move to the new position (in seconds); this must be <1s
const float handsMoveDuration = .5f;
const float handsMoveDuration = 0.5f;
// We store the previous seconds value so we can see if the time has changed
int prevSeconds = -1;
// This represents the real position where the hands are right now
Vector2 currentAngles[6][24] = { 0 };
// This is the position where the hands were moving from
Vector2 srcAngles[6][24] = { 0 };
// This is the position where the hands are moving to
Vector2 dstAngles[6][24] = { 0 };
// Current animation timer
float handsMoveTimer = 0.0f;
// 12 or 24 hour mode
int hourMode = 24;
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
@ -91,7 +80,6 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
// Get the current time
time_t rawtime;
struct tm *timeinfo;
@ -99,7 +87,8 @@ int main(void)
time(&rawtime);
timeinfo = localtime(&rawtime);
if (timeinfo->tm_sec != prevSeconds) {
if (timeinfo->tm_sec != prevSeconds)
{
// The time has changed, so we need to move the hands to the new positions
prevSeconds = timeinfo->tm_sec;
@ -107,22 +96,17 @@ int main(void)
const char *clockDigits = TextFormat("%02d%02d%02d", timeinfo->tm_hour%hourMode, timeinfo->tm_min, timeinfo->tm_sec);
// Fetch where we want all the hands to be
for (int digit = 0; digit < 6; digit++) {
for (int cell = 0; cell < 24; cell++) {
for (int digit = 0; digit < 6; digit++)
{
for (int cell = 0; cell < 24; cell++)
{
srcAngles[digit][cell] = currentAngles[digit][cell];
dstAngles[digit][cell] = digitAngles[clockDigits[digit] - '0'][cell];
// Quick exception for 12h mode
if (digit == 0 && hourMode == 12 && clockDigits[0] == '0') {
dstAngles[digit][cell] = ZZ;
}
if (srcAngles[digit][cell].x > dstAngles[digit][cell].x) {
srcAngles[digit][cell].x -= 360.0f;
}
if (srcAngles[digit][cell].y > dstAngles[digit][cell].y) {
srcAngles[digit][cell].y -= 360.0f;
}
if ((digit == 0) && (hourMode == 12) && (clockDigits[0] == '0')) dstAngles[digit][cell] = ZZ;
if (srcAngles[digit][cell].x > dstAngles[digit][cell].x) srcAngles[digit][cell].x -= 360.0f;
if (srcAngles[digit][cell].y > dstAngles[digit][cell].y) srcAngles[digit][cell].y -= 360.0f;
}
}
@ -131,7 +115,8 @@ int main(void)
}
// Now let's animate all the hands if we need to
if (handsMoveTimer < handsMoveDuration) {
if (handsMoveTimer < handsMoveDuration)
{
// Increase the timer but don't go above the maximum
handsMoveTimer = Clamp(handsMoveTimer + GetFrameTime(), 0, handsMoveDuration);
@ -141,27 +126,18 @@ int main(void)
// A little cheeky smoothstep
t = t*t*(3.0f - 2.0f*t);
for (int digit = 0; digit < 6; digit++) {
for (int cell = 0; cell < 24; cell++) {
for (int digit = 0; digit < 6; digit++)
{
for (int cell = 0; cell < 24; cell++)
{
currentAngles[digit][cell].x = Lerp(srcAngles[digit][cell].x, dstAngles[digit][cell].x, t);
currentAngles[digit][cell].y = Lerp(srcAngles[digit][cell].y, dstAngles[digit][cell].y, t);
}
}
if (handsMoveTimer == handsMoveDuration) {
// The animation has now finished
}
}
// Handle input
// Toggle between 12 and 24 hour mode with space
if (IsKeyPressed(KEY_SPACE)) {
hourMode = 36 - hourMode;
}
if (IsKeyPressed(KEY_SPACE)) hourMode = 36 - hourMode; // Toggle between 12 and 24 hour mode with space
//----------------------------------------------------------------------------------
// Draw
@ -174,19 +150,22 @@ int main(void)
float xOffset = 4.0f;
for (int digit = 0; digit < 6; digit++) {
for (int row = 0; row < 6; row++) {
for (int col = 0; col < 4; col++) {
for (int digit = 0; digit < 6; digit++)
{
for (int row = 0; row < 6; row++)
{
for (int col = 0; col < 4; col++)
{
Vector2 centre = (Vector2){
xOffset + col*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f,
100 + row*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f
xOffset + col*(clockFaceSize+clockFaceSpacing) + clockFaceSize*0.5f,
100 + row*(clockFaceSize+clockFaceSpacing) + clockFaceSize*0.5f
};
DrawRing(centre, clockFaceSize*0.5f - 2.0f, clockFaceSize*0.5f, 0, 360, 24, DARKGRAY);
// Big hand
DrawRectanglePro(
(Rectangle){centre.x, centre.y, clockFaceSize*.5f+4.0f, 4.0f},
(Rectangle){centre.x, centre.y, clockFaceSize*0.5f+4.0f, 4.0f},
(Vector2){ 2.0f, 2.0f },
currentAngles[digit][row*4+col].x,
handsColor
@ -194,7 +173,7 @@ int main(void)
// Little hand
DrawRectanglePro(
(Rectangle){centre.x, centre.y, clockFaceSize*.5f+2.0f, 4.0f},
(Rectangle){centre.x, centre.y, clockFaceSize*0.5f+2.0f, 4.0f},
(Vector2){ 2.0f, 2.0f },
currentAngles[digit][row*4+col].y,
handsColor
@ -203,26 +182,22 @@ int main(void)
}
xOffset += (clockFaceSize+clockFaceSpacing)*4;
if (digit % 2 == 1) {
if (digit%2 == 1)
{
DrawRing((Vector2){xOffset + 4.0f, 160.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
DrawRing((Vector2){xOffset + 4.0f, 225.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
xOffset += sectionSpacing;
}
}
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------

View File

@ -284,11 +284,13 @@ static void DrawDisplaySegment(Vector2 center, int length, int thick, bool verti
if (!vertical)
{
// Horizontal segment points
// 3___________________________5
// / \
// /1 x 6\
// \ /
// \2___________________________4/
/*
3___________________________5
/ \
/1 x 6\
\ /
\2___________________________4/
*/
Vector2 segmentPointsH[6] = {
(Vector2){ center.x - length/2.0f - thick/2.0f, center.y }, // Point 1
(Vector2){ center.x - length/2.0f, center.y + thick/2.0f }, // Point 2

View File

@ -42,7 +42,7 @@ int main(void)
SetConfigFlags(FLAG_WINDOW_HIGHDPI);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - double pendulum");
// Simulation Paramters
// Simulation Parameters
float l1 = 15.0f, m1 = 0.2f, theta1 = DEG2RAD*170, w1 = 0;
float l2 = 15.0f, m2 = 0.1f, theta2 = DEG2RAD*0, w2 = 0;
float lengthScaler = 0.1f;
@ -76,7 +76,7 @@ int main(void)
float step = dt/SIMULATION_STEPS, step2 = step*step;
// Update Physics - larger steps = better approximation
for (int i = 0; i < SIMULATION_STEPS; ++i)
for (int i = 0; i < SIMULATION_STEPS; i++)
{
float delta = theta1 - theta2;
float sinD = sinf(delta), cosD = cosf(delta), cos2D = cosf(2*delta);

View File

@ -11,13 +11,29 @@
* 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) 2025 Hugo ARNAL (@hugoarnal)
* Copyright (c) 2025 Hugo ARNAL (@hugoarnal) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include <string.h>
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"
#include "raymath.h"
#define MAX_DRAW_LINES 8192
// Line data type
typedef struct {
Vector2 start;
Vector2 end;
} Line;
// Lines array as a global static variable to be stored
// in heap and avoid potential stack overflow (on Web platform)
static Line lines[MAX_DRAW_LINES] = { 0 };
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
@ -30,22 +46,31 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - kaleidoscope");
// Line drawing properties
int symmetry = 6;
float angle = 360.0f/(float)symmetry;
float thickness = 3.0f;
Rectangle resetButtonRec = { screenWidth - 55, 5, 50, 25 };
Rectangle backButtonRec = { screenWidth - 55, screenHeight - 30, 25, 25 };
Rectangle nextButtonRec = { screenWidth - 30, screenHeight - 30, 25, 25 };
Vector2 mousePos = { 0 };
Vector2 prevMousePos = { 0 };
SetTargetFPS(60);
ClearBackground(BLACK);
Vector2 scaleVector = { 1.0f, -1.0f };
Vector2 offset = { (float)screenWidth/2.0f, (float)screenHeight/2.0f };
Camera2D camera = { 0 };
camera.target = (Vector2){ 0 };
camera.offset = offset;
camera.rotation = 0.0f;
camera.zoom = 1.0f;
Vector2 scaleVector = { 1.0f, -1.0f };
int currentLineCounter = 0;
int totalLineCounter = 0;
int resetButtonClicked = false;
int backButtonClicked = false;
int nextButtonClicked = false;
SetTargetFPS(20);
//--------------------------------------------------------------------------------------
// Main game loop
@ -53,38 +78,93 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
Vector2 mousePos = GetMousePosition();
prevMousePos = mousePos;
mousePos = GetMousePosition();
Vector2 lineStart = Vector2Subtract(mousePos, offset);
Vector2 lineEnd = Vector2Subtract(prevMousePos, offset);
if (
IsMouseButtonDown(MOUSE_LEFT_BUTTON)
&& (CheckCollisionPointRec(mousePos, resetButtonRec) == false)
&& (CheckCollisionPointRec(mousePos, backButtonRec) == false)
&& (CheckCollisionPointRec(mousePos, nextButtonRec) == false)
)
{
for (int s = 0; (s < symmetry) && (totalLineCounter < (MAX_DRAW_LINES - 1)); s++)
{
lineStart = Vector2Rotate(lineStart, angle*DEG2RAD);
lineEnd = Vector2Rotate(lineEnd, angle*DEG2RAD);
// Store mouse line
lines[totalLineCounter].start = lineStart;
lines[totalLineCounter].end = lineEnd;
// Store reflective line
lines[totalLineCounter + 1].start = Vector2Multiply(lineStart, scaleVector);
lines[totalLineCounter + 1].end = Vector2Multiply(lineEnd, scaleVector);
totalLineCounter += 2;
currentLineCounter = totalLineCounter;
}
}
if (resetButtonClicked)
{
memset(&lines, 0, sizeof(Line)*MAX_DRAW_LINES);
currentLineCounter = 0;
totalLineCounter = 0;
}
if (backButtonClicked && (currentLineCounter > 0))
{
currentLineCounter -= 1;
}
if (nextButtonClicked && (currentLineCounter < MAX_DRAW_LINES) && ((currentLineCounter + 1) <= totalLineCounter))
{
currentLineCounter += 1;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode2D(camera);
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
for (int i = 0; i < symmetry; i++) {
lineStart = Vector2Rotate(lineStart, angle*DEG2RAD);
lineEnd = Vector2Rotate(lineEnd, angle*DEG2RAD);
DrawLineEx(lineStart, lineEnd, thickness, WHITE);
Vector2 reflectLineStart = Vector2Multiply(lineStart, scaleVector);
Vector2 reflectLineEnd = Vector2Multiply(lineEnd, scaleVector);
DrawLineEx(reflectLineStart, reflectLineEnd, thickness, WHITE);
for (int s = 0; s < symmetry; s++)
{
for (int i = 0; i < currentLineCounter; i += 2)
{
DrawLineEx(lines[i].start, lines[i].end, thickness, BLACK);
DrawLineEx(lines[i + 1].start, lines[i + 1].end, thickness, BLACK);
}
}
prevMousePos = mousePos;
EndMode2D();
if ((currentLineCounter - 1) < 0) GuiDisable();
backButtonClicked = GuiButton(backButtonRec, "<");
GuiEnable();
if ((currentLineCounter + 1) > totalLineCounter) GuiDisable();
nextButtonClicked = GuiButton(nextButtonRec, ">");
GuiEnable();
resetButtonClicked = GuiButton(resetButtonRec, "Reset");
DrawText(TextFormat("LINES: %i/%i", currentLineCounter, MAX_DRAW_LINES), 10, screenHeight - 30, 20, MAROON);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -16,6 +16,7 @@
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
//------------------------------------------------------------------------------------
@ -39,9 +40,6 @@ int main(void)
// The canvas to draw lines on
RenderTexture canvas = LoadRenderTexture(screenWidth, screenHeight);
// The background color of the canvas
const Color backgroundColor = RAYWHITE;
// The line's thickness
float lineThickness = 8.0f;
// The lines hue (in HSV, from 0-360)
@ -49,8 +47,10 @@ int main(void)
// Clear the canvas to the background color
BeginTextureMode(canvas);
ClearBackground(backgroundColor);
ClearBackground(RAYWHITE);
EndTextureMode();
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
@ -59,16 +59,13 @@ int main(void)
// Update
//----------------------------------------------------------------------------------
// Disable the hint text once the user clicks
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText)
{
startText = false;
}
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText) startText = false;
// Clear the canvas when the user middle-clicks
if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
{
BeginTextureMode(canvas);
ClearBackground(backgroundColor);
ClearBackground(RAYWHITE);
EndTextureMode();
}
@ -79,7 +76,7 @@ int main(void)
if (leftButtonDown || rightButtonDown)
{
// The color for the line
Color drawColor;
Color drawColor = WHITE;
if (leftButtonDown)
{
@ -88,19 +85,12 @@ int main(void)
// While the hue is >=360, subtract it to bring it down into the range 0-360
// This is more visually accurate than resetting to zero
while (lineHue >= 360.0f)
{
lineHue -= 360.0f;
}
while (lineHue >= 360.0f) lineHue -= 360.0f;
// Create the final color
drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f);
}
else if (rightButtonDown)
{
// Use the background color as an "eraser"
drawColor = backgroundColor;
}
else if (rightButtonDown) drawColor = RAYWHITE; // Use the background color as an "eraser"
// Draw the line onto the canvas
BeginTextureMode(canvas);
@ -122,6 +112,7 @@ int main(void)
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
// Draw the render texture to the screen, flipped vertically to make it appear top-side up
DrawTextureRec(canvas.texture, (Rectangle){ 0.0f, 0.0f, (float)canvas.texture.width,(float)-canvas.texture.height }, Vector2Zero(), WHITE);
@ -130,14 +121,14 @@ int main(void)
// Draw the hint text
if (startText) DrawText("try clicking and dragging!", 275, 215, 20, LIGHTGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
// Unload the canvas render texture
UnloadRenderTexture(canvas);
UnloadRenderTexture(canvas); // Unload the canvas render texture
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------

View File

@ -40,8 +40,8 @@ int main(void)
Vector2 sinePoints[WAVE_POINTS];
Vector2 cosPoints[WAVE_POINTS];
Vector2 center = { (screenWidth/2.0f) - 30.f, screenHeight/2.0f };
Rectangle start = { 20.f, screenHeight - 120.f , 200.0f, 100.0f};
Vector2 center = { (screenWidth/2.0f) - 30.0f, screenHeight/2.0f };
Rectangle start = { 20.0f, screenHeight - 120.f , 200.0f, 100.0f};
float radius = 130.0f;
float angle = 0.0f;
bool pause = false;
@ -98,7 +98,7 @@ int main(void)
// Base circle and axes
DrawCircleLinesV(center, radius, GRAY);
DrawLineEx((Vector2){ center.x, limitMin.y }, (Vector2){ center.x, limitMax.y }, 1.0f, GRAY);
DrawLineEx((Vector2){ limitMin.x, center.y }, (Vector2){ limitMax.x, center.y }, 1.f, GRAY);
DrawLineEx((Vector2){ limitMin.x, center.y }, (Vector2){ limitMax.x, center.y }, 1.0f, GRAY);
// Wave graph axes
DrawLineEx((Vector2){ start.x , start.y }, (Vector2){ start.x , start.y + start.height }, 2.0f, GRAY);
@ -135,19 +135,19 @@ int main(void)
DrawText(TextFormat("Cotangent %.2f", cotangent), 640, 250, 6, ORANGE);
// Complementary angle (beige)
DrawCircleSectorLines(center, radius*0.6f , -angle, -90.f , 36.0f, BEIGE);
DrawCircleSectorLines(center, radius*0.6f , -angle, -90.0f , 36.0f, BEIGE);
DrawText(TextFormat("Complementary %0.f°",complementary), 640, 150, 6, BEIGE);
// Supplementary angle (darkblue)
DrawCircleSectorLines(center, radius*0.5f , -angle, -180.f , 36.0f, DARKBLUE);
DrawCircleSectorLines(center, radius*0.5f , -angle, -180.0f , 36.0f, DARKBLUE);
DrawText(TextFormat("Supplementary %0.f°",supplementary), 640, 130, 6, DARKBLUE);
// Explementary angle (pink)
DrawCircleSectorLines(center, radius*0.4f , -angle, -360.f , 36.0f, PINK);
DrawCircleSectorLines(center, radius*0.4f , -angle, -360.0f , 36.0f, PINK);
DrawText(TextFormat("Explementary %0.f°",explementary), 640, 170, 6, PINK);
// Current angle - arc (lime), radius (black), endpoint (black)
DrawCircleSectorLines(center, radius*0.7f , -angle, 0.f, 36.0f, LIME);
DrawCircleSectorLines(center, radius*0.7f , -angle, 0.0f, 36.0f, LIME);
DrawLineEx((Vector2){ center.x , center.y }, point, 2.0f, BLACK);
DrawCircleV(point, 4.0f, BLACK);
@ -156,11 +156,12 @@ int main(void)
GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(GRAY));
GuiToggle((Rectangle){ 640, 70, 120, 20}, TextFormat("Pause"), &pause);
GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(LIME));
GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f°", angle), &angle, 0.0f, 360.f);
GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f°", angle), &angle, 0.0f, 360.0f);
// Angle values panel
GuiGroupBox((Rectangle){ 620, 110, 140, 170}, "Angle Values");
//------------------------------------------------------------------------------
DrawFPS(10, 10);
EndDrawing();

View File

@ -0,0 +1,271 @@
/*******************************************************************************************
*
* raylib [shapes] example - penrose tile
*
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev
* Based on: https://processing.org/examples/penrosetile.html
*
* Example contributed by David Buzatto (@davidbuzatto) 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) 2025 David Buzatto (@davidbuzatto)
*
********************************************************************************************/
#include "raylib.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define STR_MAX_SIZE 10000
#define TURTLE_STACK_MAX_SIZE 50
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef struct TurtleState {
Vector2 origin;
double angle;
} TurtleState;
typedef struct PenroseLSystem {
int steps;
char *production;
const char *ruleW;
const char *ruleX;
const char *ruleY;
const char *ruleZ;
float drawLength;
float theta;
} PenroseLSystem;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static TurtleState turtleStack[TURTLE_STACK_MAX_SIZE];
static int turtleTop = -1;
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
static void PushTurtleState(TurtleState state);
static TurtleState PopTurtleState(void);
static PenroseLSystem CreatePenroseLSystem(float drawLength);
static void BuildProductionStep(PenroseLSystem *ls);
static void DrawPenroseLSystem(PenroseLSystem *ls);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - penrose tile");
float drawLength = 460.0f;
int minGenerations = 0;
int maxGenerations = 4;
int generations = 0;
// Initializee new penrose tile
PenroseLSystem ls = CreatePenroseLSystem(drawLength*(generations/(float)maxGenerations));
for (int i = 0; i < generations; i++) BuildProductionStep(&ls);
SetTargetFPS(120); // Set our game to run at 120 frames-per-second
//---------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
bool rebuild = false;
if (IsKeyPressed(KEY_UP))
{
if (generations < maxGenerations)
{
generations++;
rebuild = true;
}
}
else if (IsKeyPressed(KEY_DOWN))
{
if (generations > minGenerations)
{
generations--;
if (generations > 0) rebuild = true;
}
}
if (rebuild)
{
RL_FREE(ls.production); // Free previous production for re-creation
ls = CreatePenroseLSystem(drawLength*(generations/(float)maxGenerations));
for (int i = 0; i < generations; i++) BuildProductionStep(&ls);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground( RAYWHITE );
if (generations > 0) DrawPenroseLSystem(&ls);
DrawText("penrose l-system", 10, 10, 20, DARKGRAY);
DrawText("press up or down to change generations", 10, 30, 20, DARKGRAY);
DrawText(TextFormat("generations: %d", generations), 10, 50, 20, DARKGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Push turtle state for next step
static void PushTurtleState(TurtleState state)
{
if (turtleTop < (TURTLE_STACK_MAX_SIZE - 1)) turtleStack[++turtleTop] = state;
else TraceLog(LOG_WARNING, "TURTLE STACK OVERFLOW!");
}
// Pop turtle state step
static TurtleState PopTurtleState(void)
{
if (turtleTop >= 0) return turtleStack[turtleTop--];
else TraceLog(LOG_WARNING, "TURTLE STACK UNDERFLOW!");
return (TurtleState){ 0 };
}
// Create a new penrose tile structure
static PenroseLSystem CreatePenroseLSystem(float drawLength)
{
// TODO: Review constant values assignment on recreation?
PenroseLSystem ls = {
.steps = 0,
.ruleW = "YF++ZF4-XF[-YF4-WF]++",
.ruleX = "+YF--ZF[3-WF--XF]+",
.ruleY = "-WF++XF[+++YF++ZF]-",
.ruleZ = "--YF++++WF[+ZF++++XF]--XF",
.drawLength = drawLength,
.theta = 36.0f // Degrees
};
ls.production = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE);
ls.production[0] = '\0';
strncpy(ls.production, "[X]++[X]++[X]++[X]++[X]", STR_MAX_SIZE);
return ls;
}
// Build next penrose step
static void BuildProductionStep(PenroseLSystem *ls)
{
char *newProduction = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE);
newProduction[0] = '\0';
int productionLength = strnlen(ls->production, STR_MAX_SIZE);
for (int i = 0; i < productionLength; i++)
{
char step = ls->production[i];
int remainingSpace = STR_MAX_SIZE - strnlen(newProduction, STR_MAX_SIZE) - 1;
switch (step)
{
case 'W': strncat(newProduction, ls->ruleW, remainingSpace); break;
case 'X': strncat(newProduction, ls->ruleX, remainingSpace); break;
case 'Y': strncat(newProduction, ls->ruleY, remainingSpace); break;
case 'Z': strncat(newProduction, ls->ruleZ, remainingSpace); break;
default:
{
if (step != 'F')
{
int t = strnlen(newProduction, STR_MAX_SIZE);
newProduction[t] = step;
newProduction[t + 1] = '\0';
}
} break;
}
}
ls->drawLength *= 0.5f;
strncpy(ls->production, newProduction, STR_MAX_SIZE);
RL_FREE(newProduction);
}
// Draw penrose tile lines
static void DrawPenroseLSystem(PenroseLSystem *ls)
{
Vector2 screenCenter = { GetScreenWidth()/2, GetScreenHeight()/2 };
TurtleState turtle = {
.origin = { 0 },
.angle = -90.0f
};
int repeats = 1;
int productionLength = (int)strnlen(ls->production, STR_MAX_SIZE);
ls->steps += 12;
if (ls->steps > productionLength) ls->steps = productionLength;
for (int i = 0; i < ls->steps; i++)
{
char step = ls->production[i];
if (step == 'F')
{
for (int j = 0; j < repeats; j++)
{
Vector2 startPosWorld = turtle.origin;
float radAngle = DEG2RAD*turtle.angle;
turtle.origin.x += ls->drawLength*cosf(radAngle);
turtle.origin.y += ls->drawLength*sinf(radAngle);
Vector2 startPosScreen = { startPosWorld.x + screenCenter.x, startPosWorld.y + screenCenter.y };
Vector2 endPosScreen = { turtle.origin.x + screenCenter.x, turtle.origin.y + screenCenter.y };
DrawLineEx(startPosScreen, endPosScreen, 2, Fade(BLACK, 0.2));
}
repeats = 1;
}
else if (step == '+')
{
for (int j = 0; j < repeats; j++) turtle.angle += ls->theta;
repeats = 1;
}
else if (step == '-')
{
for (int j = 0; j < repeats; j++) turtle.angle += -ls->theta;
repeats = 1;
}
else if (step == '[') PushTurtleState(turtle);
else if (step == ']') turtle = PopTurtleState();
else if ((step >= 48) && (step <= 57)) repeats = (int) step - 48;
}
turtleTop = -1;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -112,7 +112,7 @@ int main(void)
GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f", angle), &angle, 0, 180);
GuiSliderBar((Rectangle){ 640, 70, 120, 20 }, "Length", TextFormat("%.0f", length), &length, 12.0f, 240.0f);
GuiSliderBar((Rectangle){ 640, 100, 120, 20}, "Decay", TextFormat("%.2f", branchDecay), &branchDecay, 0.1f, 0.78f);
GuiSliderBar((Rectangle){ 640, 130, 120, 20 }, "Depth", TextFormat("%.0f", treeDepth), &treeDepth, 1.0f, 10.f);
GuiSliderBar((Rectangle){ 640, 130, 120, 20 }, "Depth", TextFormat("%.0f", treeDepth), &treeDepth, 1.0f, 10.0f);
GuiSliderBar((Rectangle){ 640, 160, 120, 20}, "Thick", TextFormat("%.0f", thick), &thick, 1, 8);
GuiCheckBox((Rectangle){ 640, 190, 20, 20 }, "Bezier", &bezier);
//------------------------------------------------------------------------------

View File

@ -0,0 +1,274 @@
/*******************************************************************************************
*
* raylib [shapes] example - rlgl color wheel
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
*
* Example contributed by Robin (@RobinsAviary) 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) 2025 Robin (@RobinsAviary)
*
********************************************************************************************/
#include "raylib.h"
#include "rlgl.h"
#include "raymath.h"
#include <stdlib.h>
#include <stdio.h>
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
// The minimum/maximum points the circle can have
const unsigned int pointsMin = 3;
const unsigned int pointsMax = 256;
// The current number of points and the radius of the circle
unsigned int triangleCount = 64;
float pointScale = 150.0f;
// Slider value, literally maps to value in HSV
float value = 1.0f;
// The center of the screen
Vector2 center = { (float)screenWidth/2.0f, (float)screenHeight/2.0f };
// The location of the color wheel
Vector2 circlePosition = center;
// The currently selected color
Color color = { 255, 255, 255, 255 };
// Indicates if the slider is being clicked
bool sliderClicked = false;
// Indicates if the current color going to be updated, as well as the handle position
bool settingColor = false;
// How the color wheel will be rendered
unsigned int renderType = RL_TRIANGLES;
// Enable anti-aliasing
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rlgl color wheel");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
triangleCount += (unsigned int)GetMouseWheelMove();
triangleCount = (unsigned int)Clamp((float)triangleCount, (float)pointsMin, (float)pointsMax);
Rectangle sliderRectangle = { 42.0f, 16.0f + 64.0f + 45.0f, 64.0f, 16.0f };
Vector2 mousePosition = GetMousePosition();
// Checks if the user is hovering over the value slider
bool sliderHover = (mousePosition.x >= sliderRectangle.x && mousePosition.y >= sliderRectangle.y && mousePosition.x < sliderRectangle.x + sliderRectangle.width && mousePosition.y < sliderRectangle.y + sliderRectangle.height);
// Copy color as hex
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_C))
{
if (IsKeyPressed(KEY_C))
{
SetClipboardText(TextFormat("#%02X%02X%02X", color.r, color.g, color.b));
}
}
// Scale up the color wheel, adjusting the handle visually
if (IsKeyDown(KEY_UP))
{
pointScale *= 1.025f;
if (pointScale > (float)screenHeight/2.0f)
{
pointScale = (float)screenHeight/2.0f;
}
else
{
circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), (Vector2){ 1.025f, 1.025f }), center);
}
}
// Scale down the wheel, adjusting the handle visually
if (IsKeyDown(KEY_DOWN))
{
pointScale *= 0.975f;
if (pointScale < 32.0f)
{
pointScale = 32.0f;
}
else
{
circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), (Vector2){ 0.975f, 0.975f }), center);
}
float distance = Vector2Distance(center, circlePosition)/pointScale;
float angle = ((Vector2Angle((Vector2){ 0.0f, -pointScale }, Vector2Subtract(center, circlePosition))/PI + 1.0f)/2.0f);
if (distance > 1.0f)
{
circlePosition = Vector2Add((Vector2){ sinf(angle*(PI*2.0f))*pointScale, -cosf(angle*(PI*2.0f))*pointScale }, center);
}
}
// Checks if the user clicked on the color wheel
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && Vector2Distance(GetMousePosition(), center) <= pointScale + 10.0f)
{
settingColor = true;
}
// Update flag when mouse button is released
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) settingColor = false;
// Check if the user clicked/released the slider for the color's value
if (sliderHover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) sliderClicked = true;
if (sliderClicked && IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) sliderClicked = false;
// Update render mode accordingly
if (IsKeyPressed(KEY_SPACE)) renderType = RL_LINES;
if (IsKeyReleased(KEY_SPACE)) renderType = RL_TRIANGLES;
// If the slider or the wheel was clicked, update the current color
if (settingColor || sliderClicked)
{
if (settingColor) circlePosition = GetMousePosition();
float distance = Vector2Distance(center, circlePosition)/pointScale;
float angle = ((Vector2Angle((Vector2){ 0.0f, -pointScale }, Vector2Subtract(center, circlePosition))/PI + 1.0f)/2.0f);
if (settingColor && distance > 1.0f) circlePosition = Vector2Add((Vector2){ sinf(angle*(PI*2.0f))*pointScale, -cosf(angle*(PI* 2.0f))*pointScale }, center);
float angle360 = angle*360.0f;
float valueActual = Clamp(distance, 0.0f, 1.0f);
color = ColorLerp((Color){ (int)(value*255.0f), (int)(value*255.0f), (int)(value*255.0f), 255 }, ColorFromHSV(angle360, Clamp(distance, 0.0f, 1.0f), 1.0f), valueActual);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
// Begin rendering color wheel
rlBegin(renderType);
for (unsigned int i = 0; i < triangleCount; i++)
{
float angleOffset = ((PI*2.0f)/(float)triangleCount);
float angle = angleOffset*(float)i;
float angleOffsetCalculated = ((float)i + 1)*angleOffset;
Vector2 scale = (Vector2){ pointScale, pointScale };
Vector2 offset = Vector2Multiply((Vector2){ sinf(angle), -cosf(angle) }, scale);
Vector2 offset2 = Vector2Multiply((Vector2){ sinf(angleOffsetCalculated), -cosf(angleOffsetCalculated) }, scale);
Vector2 position = Vector2Add(center, offset);
Vector2 position2 = Vector2Add(center, offset2);
float angleNonRadian = (angle/(2.0f*PI))*360.0f;
float angleNonRadianOffset = (angleOffset/(2.0f*PI))*360.0f;
Color currentColor = ColorFromHSV(angleNonRadian, 1.0f, 1.0f);
Color offsetColor = ColorFromHSV(angleNonRadian + angleNonRadianOffset, 1.0f, 1.0f);
// Input vertices differently depending on mode
if (renderType == RL_TRIANGLES)
{
// RL_TRIANGLES expects three vertices per triangle
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
rlVertex2f(position.x, position.y);
rlColor4f(value, value, value, 1.0f);
rlVertex2f(center.x, center.y);
rlColor4ub(offsetColor.r, offsetColor.g, offsetColor.b, offsetColor.a);
rlVertex2f(position2.x, position2.y);
}
else if (renderType == RL_LINES)
{
// RL_LINES expects two vertices per line
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
rlVertex2f(position.x, position.y);
rlColor4ub(WHITE.r, WHITE.g, WHITE.b, WHITE.a);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x, center.y);
rlColor4ub(offsetColor.r, offsetColor.g, offsetColor.b, offsetColor.a);
rlVertex2f(position2.x, position2.y);
rlVertex2f(position2.x, position2.y);
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
rlVertex2f(position.x, position.y);
}
}
rlEnd();
// Make the handle slightly more visible overtop darker colors
Color handleColor = BLACK;
if (Vector2Distance(center, circlePosition)/pointScale <= 0.5f && value <= 0.5f)
{
handleColor = DARKGRAY;
}
// Draw the color handle
DrawCircleLinesV(circlePosition, 4.0f, handleColor);
// Draw the color in a preview, with a darkened outline.
DrawRectangleV((Vector2){ 8.0f, 8.0f }, (Vector2){ 64.0f, 64.0f }, color);
DrawRectangleLinesEx((Rectangle){ 8.0f, 8.0f, 64.0f, 64.0f }, 2.0f, ColorLerp(color, BLACK, 0.5f));
// Draw current color as hex and decimal
DrawText(TextFormat("#%02X%02X%02X\n(%d, %d, %d)", color.r, color.g, color.b, color.r, color.g, color.b), 8, 8 + 64 + 8, 20, DARKGRAY);
// Update the visuals for the copying text
Color copyColor = DARKGRAY;
unsigned int offset = 0;
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_C))
{
copyColor = DARKGREEN;
offset = 4;
}
// Draw the copying text
DrawText("press ctrl+c to copy!", 8, 425 - offset, 20, copyColor);
// Display the number of rendered triangles
DrawText(TextFormat("triangle count: %d", triangleCount), 8, 395, 20, DARKGRAY);
// Slider to change color's value
GuiSliderBar(sliderRectangle, "value: ", "", &value, 0.0f, 1.0f);
// Draw FPS next to outlined color preview
DrawFPS(64 + 16, 8);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

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