Merge branch 'master' into rcamera_redesign_vector

This commit is contained in:
Ray 2023-02-14 17:47:09 +01:00 committed by GitHub
commit 056e0b857c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 2158 additions and 564 deletions

View File

@ -27,7 +27,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to
| raylib-guile | auto | [Guile](https://www.gnu.org/software/guile/) | Zlib | https://github.com/petelliott/raylib-guile | | raylib-guile | auto | [Guile](https://www.gnu.org/software/guile/) | Zlib | https://github.com/petelliott/raylib-guile |
| gforth-raylib | 3.5 | [Gforth](https://gforth.org/) | MIT | https://github.com/ArnautDaniel/gforth-raylib | | gforth-raylib | 3.5 | [Gforth](https://gforth.org/) | MIT | https://github.com/ArnautDaniel/gforth-raylib |
| h-raylib | 4.5-dev | [Haskell](https://haskell.org/) | Apache-2.0 | https://github.com/Anut-py/h-raylib | | h-raylib | 4.5-dev | [Haskell](https://haskell.org/) | Apache-2.0 | https://github.com/Anut-py/h-raylib |
| raylib-hx | 4.0 | [Haxe](https://haxe.org/) | Zlib | https://github.com/foreignsasquatch/raylib-hx | | raylib-hx | **4.2** | [Haxe](https://haxe.org/) | Zlib | https://github.com/foreignsasquatch/raylib-hx |
| hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | MIT | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib | | hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | MIT | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib |
| jaylib | **4.2** | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | GPLv3+CE | https://github.com/electronstudio/jaylib/ | | jaylib | **4.2** | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | GPLv3+CE | https://github.com/electronstudio/jaylib/ |
| raylib-j | **4.0** | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | Zlib | https://github.com/CreedVI/Raylib-J | | raylib-j | **4.0** | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | Zlib | https://github.com/CreedVI/Raylib-J |

View File

@ -9,14 +9,13 @@ Release: raylib 4.5 (xx February 2023) -WIP-
KEY CHANGES: KEY CHANGES:
- ADDED: M3D model format support with animations - ADDED: M3D model format support with animations
- ADDED: GLTF animation support - ADDED: GLTF animation support
- ADDED: QOA audio format support (import/export) -WIP-
- rlgl redesign to avoid render batch triangles limits pre-check: rlCheckRenderBatchLimit() - rlgl redesign to avoid render batch triangles limits pre-check: rlCheckRenderBatchLimit()
- rshapes simplification to minimize the requirement of rlgl functionality, now it only depends on 6 functions - rshapes simplification to minimize the requirement of rlgl functionality, now it only depends on 6 functions
- rl_gputex.h: Compressed textures loading, required by rtextures module, has been moved to a separate self-contained library - rl_gputex.h: Compressed textures loading, required by rtextures module, has been moved to a separate self-contained library
- raygui 3.5: New version of the immediate-mode gui system for tools development with raylib - raygui 3.5: New version of the immediate-mode gui system for tools development with raylib
Detailed changes: Detailed changes:
[core] ADDED: RAYLIB_VERSION_* values to raylib.h (#2856) by @RobLoach [core] ADDED: RAYLIB_VERSION_* values to raylib.h (#2856) by @RobLoach
[core] ADDED: Basic gamepad support for Android (#2709) by @deniska [core] ADDED: Basic gamepad support for Android (#2709) by @deniska
[core] ADDED: Support CAPS/NUM lock keys registering if locked [core] ADDED: Support CAPS/NUM lock keys registering if locked
@ -43,6 +42,7 @@ Detailed changes:
[core] REVIEWED: GetClipboardText() on PLATFORM_WEB, permissions issues [core] REVIEWED: GetClipboardText() on PLATFORM_WEB, permissions issues
[core] REVIEWED: Initial window position for display-sized fullscreen (#2742) by @daipom [core] REVIEWED: Initial window position for display-sized fullscreen (#2742) by @daipom
[core] REVIEWED: Sticky touches input (#2857) by @ImazighenGhost [core] REVIEWED: Sticky touches input (#2857) by @ImazighenGhost
[core] REVIEWED: Enable GetWindowHandle() on macOS (#2915) by @Not-Nik
[rlgl] ADDED: OpenGL ES 2.0 support on PLATFORM_DESKTOP (#2840) by @wtnbgo [rlgl] ADDED: OpenGL ES 2.0 support on PLATFORM_DESKTOP (#2840) by @wtnbgo
[rlgl] ADDED: Separate blending modes for color and alpha, BLEND_CUSTOM_SEPARATE (#2741) [rlgl] ADDED: Separate blending modes for color and alpha, BLEND_CUSTOM_SEPARATE (#2741)
[rlgl] ADDED: rlSetBlendFactorsSeparate and custom blend mode modification checks (#2741) by @pure01fx [rlgl] ADDED: rlSetBlendFactorsSeparate and custom blend mode modification checks (#2741) by @pure01fx
@ -58,7 +58,8 @@ Detailed changes:
[rlgl] REVIEWED: rlMultMatrixf(), use const pointer (#2807) by @planetis-m [rlgl] REVIEWED: rlMultMatrixf(), use const pointer (#2807) by @planetis-m
[rlgl] REVIEWED: Expose OpenGL blending mode factors and functions/equations [rlgl] REVIEWED: Expose OpenGL blending mode factors and functions/equations
[rlgl] REVIEWED: rLoadTextureDepth(), issue with depth textures on WebGL (#2824) [rlgl] REVIEWED: rLoadTextureDepth(), issue with depth textures on WebGL (#2824)
[raymath] REVIEWED: Vector2Angle() (#2829, #2832) by @AlxHnr and @planetis-m [raymath] ADDED: Vector2LineAngle() (#2887)
[raymath] REVIEWED: Vector2Angle() (#2829, #2832) by @AlxHnr, @planetis-m
[shapes] ADDED: CheckCollisionPointPoly() (#2685) by @acejacek [shapes] ADDED: CheckCollisionPointPoly() (#2685) by @acejacek
[shapes] REVIEWED: DrawPixel*(), use RL_QUADS/RL_TRIANGLES (#2750) by @hatkidchan [shapes] REVIEWED: DrawPixel*(), use RL_QUADS/RL_TRIANGLES (#2750) by @hatkidchan
[shapes] REVIEWED: DrawLineBezier*(), fix bezier line breaking (#2735, #2767) by @nobytesgiven [shapes] REVIEWED: DrawLineBezier*(), fix bezier line breaking (#2735, #2767) by @nobytesgiven
@ -88,21 +89,29 @@ Detailed changes:
[models] ADDED: GLTF animation support (#2844) by @charles-l [models] ADDED: GLTF animation support (#2844) by @charles-l
[models] ADDED: DrawCapsule() and DrawCapsuleWires() (#2761) by @IanBand [models] ADDED: DrawCapsule() and DrawCapsuleWires() (#2761) by @IanBand
[models] ADDED: LoadMaterials(), MTL files loading, same code as OBJ loader (#2872) by @JeffM2501 [models] ADDED: LoadMaterials(), MTL files loading, same code as OBJ loader (#2872) by @JeffM2501
[models] REVIEWED: DrawMesh(), using SHADER_LOC_COLOR_SPECULAR as a material map (#2908) by @haved
[models] REVIEWED: LoadM3D() vertex color support (#2878) by @GithubPrankster, @bztsrc
[models] REVIEWED: GenMeshHeightmap() (#2716) [models] REVIEWED: GenMeshHeightmap() (#2716)
[models] REVIEWED: LoadIQM() (#2676) [models] REVIEWED: LoadIQM() (#2676)
[models] REVIEWED: Simplify .vox signature check (#2752) by @CrezyDud [models] REVIEWED: Simplify .vox signature check (#2752) by @CrezyDud
[models] REVIEWED: LoadIQM(), support bone names loading if available (#2882) by @PencilAmazing [models] REVIEWED: LoadIQM(), support bone names loading if available (#2882) by @PencilAmazing
[models] `WARNING`: REMOVED: DrawCubeTexture(), DrawCubeTextureRec(), functions moved to new example: `models_draw_cube_texture` [models] `WARNING`: REMOVED: DrawCubeTexture(), DrawCubeTextureRec(), functions moved to new example: `models_draw_cube_texture`
[audio] ADDED: IsWaveReady()`, IsSoundReady(), IsMusicReady() (#2892) by @RobLoach
[audio] REVIEWED: Clear PCM buffer state when closing audio device (#2736) by @veins1 [audio] REVIEWED: Clear PCM buffer state when closing audio device (#2736) by @veins1
[audio] REVIEWED: Android backend selected (#2118, #2875) by @planetis-m [audio] REVIEWED: Android backend selected (#2118, #2875) by @planetis-m
[multi] ADDED: IsShaderReady(), IsImageReady(), IsFontReady() (#2892) by @RobLoach
[multi] ADDED: IsModelReady(), IsMaterialReady(), IsTextureReady(), IsRenderTextureReady() (#2895) by @RobLoach
[multi] REVIEWED: Multiple code/comment typos by @sDos280 [multi] REVIEWED: Multiple code/comment typos by @sDos280
[multi] REVIEWED: Grammar mistakes and typos (#2914) by @stickM4N
[multi] REVIEWED: Use TRACELOG() macro instead of TraceLog() in internal modules (#2881) by @RobLoach [multi] REVIEWED: Use TRACELOG() macro instead of TraceLog() in internal modules (#2881) by @RobLoach
[examples] ADDED: textures_textured_curve (#2821) by @JeffM2501 [examples] ADDED: textures_textured_curve (#2821) by @JeffM2501
[examples] ADDED: shaders_write_depth (#2836) by @BugraAlptekinSari [examples] ADDED: shaders_write_depth (#2836) by @BugraAlptekinSari
[examples] ADDED: shaders_hybrid_render (#2919) by @BugraAlptekinSari
[examples] RENAMED: Several shaders for naming consistency (#2707) [examples] RENAMED: Several shaders for naming consistency (#2707)
[examples] RENAMED: lighting_instanced.fs to lighting_instancing.fs (glsl100) (#2805) by @gtrxAC [examples] RENAMED: lighting_instanced.fs to lighting_instancing.fs (glsl100) (#2805) by @gtrxAC
[examples] REVIEWED: core_custom_logging.c (#2692) by @hartmannathan [examples] REVIEWED: core_custom_logging.c (#2692) by @hartmannathan
[examples] REVIEWED: core_camera_2d_platformer (#2687) by @skylar779 [examples] REVIEWED: core_camera_2d_platformer (#2687) by @skylar779
[examples] REVIEWED: core_input_gamepad.c (#2903) by @planetis-m
[examples] REVIEWED: core_custom_frame_control [examples] REVIEWED: core_custom_frame_control
[examples] REVIEWED: text_rectangle_bounds (#2746) by @SzieberthAdam [examples] REVIEWED: text_rectangle_bounds (#2746) by @SzieberthAdam
[examples] REVIEWED: textures_image_processing, added gaussian blurring (#2775) by @nobytesgiven [examples] REVIEWED: textures_image_processing, added gaussian blurring (#2775) by @nobytesgiven
@ -114,6 +123,9 @@ Detailed changes:
[build] ADDED: Packaging for distros with deb-based and rpm-based packages (#2877) by @KOLANICH [build] ADDED: Packaging for distros with deb-based and rpm-based packages (#2877) by @KOLANICH
[build] ADDED: Linkage library -latomic on Linux (only required for ARM32) [build] ADDED: Linkage library -latomic on Linux (only required for ARM32)
[build] ADDED: Required frameworks on macOS (#2793) by @SpexGuy [build] ADDED: Required frameworks on macOS (#2793) by @SpexGuy
[build] ADDED: WASM support for Zig build (#2901) by @Not-Nik
[build] REVIEWED: config.h format and inconsistencies
[build] REVIEWED: Zig build to latest master, avoid deprecated functions (#2910) by @star-tek-mb
[build] REVIEWED: CMake project template to easily target raylib version (#2700) by @RobLoach [build] REVIEWED: CMake project template to easily target raylib version (#2700) by @RobLoach
[build] REVIEWED: PATH for PLATFORM_WEB target (#2647) by @futureapricot [build] REVIEWED: PATH for PLATFORM_WEB target (#2647) by @futureapricot
[build] REVIEWED: build.zig to let user decide how to set build mode and linker fixes by @InKryption [build] REVIEWED: build.zig to let user decide how to set build mode and linker fixes by @InKryption
@ -141,7 +153,7 @@ Detailed changes:
[bindings] ADDED: TurboRaylib (Object Pascal) by @turborium [bindings] ADDED: TurboRaylib (Object Pascal) by @turborium
[bindings] ADDED: Kaylib (Kotlin/Native) by @Its-Kenta [bindings] ADDED: Kaylib (Kotlin/Native) by @Its-Kenta
[bindings] ADDED: Raylib-Nelua (Nelua) by @Its-Kenta [bindings] ADDED: Raylib-Nelua (Nelua) by @Its-Kenta
[misc] REVIEWED: Update some external libraries to latest versions [misc] REVIEWED: Update external libraries to latest versions
------------------------------------------------------------------------- -------------------------------------------------------------------------
Release: raylib 4.2 (11 August 2022) Release: raylib 4.2 (11 August 2022)

18
build.zig Normal file
View File

@ -0,0 +1,18 @@
const std = @import("std");
const raylib = @import("src/build.zig");
pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const lib = raylib.addRaylib(b, target, optimize);
lib.installHeader("src/raylib.h", "raylib.h");
lib.install();
}

View File

@ -523,7 +523,8 @@ SHADERS = \
shaders/shaders_hot_reloading \ shaders/shaders_hot_reloading \
shaders/shaders_mesh_instancing \ shaders/shaders_mesh_instancing \
shaders/shaders_multi_sample2d \ shaders/shaders_multi_sample2d \
shaders/shaders_write_depth shaders/shaders_write_depth \
shaders/shaders_hybrid_render
AUDIO = \ AUDIO = \
audio/audio_module_playing \ audio/audio_module_playing \
@ -581,10 +582,10 @@ ifeq ($(PLATFORM),PLATFORM_DRM)
rm -fv *.o rm -fv *.o
endif endif
ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM),PLATFORM_WEB)
ifeq ($(PLATFORM_OS),WINDOWS) ifeq ($(PLATFORM_OS),WINDOWS)
del *.wasm *.html *.js *.data del *.wasm *.html *.js *.data
else else
rm -f */*.wasm */*.html */*.js */*.data rm -f */*.wasm */*.html */*.js */*.data
endif endif
endif endif
@echo Cleaning done @echo Cleaning done

View File

@ -1,15 +1,11 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zig.CrossTarget) !*std.build.Step { fn add_module(comptime module: []const u8, b: *std.Build, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) !*std.Build.Step {
if (target.getOsTag() == .emscripten) { if (target.getOsTag() == .emscripten) {
@panic("Emscripten building via Zig unsupported"); @panic("Emscripten building via Zig unsupported");
} }
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const all = b.step(module, "All " ++ module ++ " examples"); const all = b.step(module, "All " ++ module ++ " examples");
const dir = try std.fs.cwd().openIterableDir(module, .{}); const dir = try std.fs.cwd().openIterableDir(module, .{});
var iter = dir.iterate(); var iter = dir.iterate();
@ -22,10 +18,12 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi
// zig's mingw headers do not include pthread.h // zig's mingw headers do not include pthread.h
if (std.mem.eql(u8, "core_loading_thread", name) and target.getOsTag() == .windows) continue; if (std.mem.eql(u8, "core_loading_thread", name) and target.getOsTag() == .windows) continue;
const exe = b.addExecutable(name, null); const exe = b.addExecutable(.{
.name = name,
.target = target,
.optimize = optimize,
});
exe.addCSourceFile(path, &[_][]const u8{}); exe.addCSourceFile(path, &[_][]const u8{});
exe.setTarget(target);
exe.setBuildMode(mode);
exe.linkLibC(); exe.linkLibC();
exe.addObjectFile(switch (target.getOsTag()) { exe.addObjectFile(switch (target.getOsTag()) {
.windows => "../src/raylib.lib", .windows => "../src/raylib.lib",
@ -83,21 +81,25 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi
return all; return all;
} }
pub fn build(b: *std.build.Builder) !void { pub fn build(b: *std.Build) !void {
// Standard target options allows the person running `zig build` to choose // Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which // what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options // means any target is allowed, and the default is native. Other options
// for restricting supported target set are available. // for restricting supported target set are available.
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const all = b.getInstallStep(); const all = b.getInstallStep();
all.dependOn(try add_module("audio", b, target)); all.dependOn(try add_module("audio", b, target, optimize));
all.dependOn(try add_module("core", b, target)); all.dependOn(try add_module("core", b, target, optimize));
all.dependOn(try add_module("models", b, target)); all.dependOn(try add_module("models", b, target, optimize));
all.dependOn(try add_module("others", b, target)); all.dependOn(try add_module("others", b, target, optimize));
all.dependOn(try add_module("shaders", b, target)); all.dependOn(try add_module("shaders", b, target, optimize));
all.dependOn(try add_module("shapes", b, target)); all.dependOn(try add_module("shapes", b, target, optimize));
all.dependOn(try add_module("text", b, target)); all.dependOn(try add_module("text", b, target, optimize));
all.dependOn(try add_module("textures", b, target)); all.dependOn(try add_module("textures", b, target, optimize));
} }

View File

@ -174,7 +174,7 @@ int main(void)
DrawText(TextFormat("AXIS %i: %.02f", i, GetGamepadAxisMovement(0, i)), 20, 70 + 20*i, 10, DARKGRAY); DrawText(TextFormat("AXIS %i: %.02f", i, GetGamepadAxisMovement(0, i)), 20, 70 + 20*i, 10, DARKGRAY);
} }
if (GetGamepadButtonPressed() != -1) DrawText(TextFormat("DETECTED BUTTON: %i", GetGamepadButtonPressed()), 10, 430, 10, RED); 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("DETECTED BUTTON: NONE", 10, 430, 10, GRAY);
} }
else else

View File

@ -0,0 +1,16 @@
#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;
varying vec4 fragColor;
uniform sampler2D texture0;
uniform vec4 colDiffuse;
void main()
{
vec4 texelColor = texture2D(texture0, fragTexCoord);
gl_FragColor = texelColor*colDiffuse*fragColor;
gl_FragDepthEXT = gl_FragCoord.z;
}

View File

@ -0,0 +1,288 @@
#version 100
#extension GL_EXT_frag_depth : enable //Extension required for writing depth
#extension GL_OES_standard_derivatives : enable //Extension used for fwidth()
precision mediump float; // Precision required for OpenGL ES2 (WebGL)
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Custom Input Uniform
uniform vec3 camPos;
uniform vec3 camDir;
uniform vec2 screenCenter;
#define ZERO 0
// https://learnopengl.com/Advanced-OpenGL/Depth-testing
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);
}
// https://iquilezles.org/articles/distfunctions/
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 = 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);
vec2 d = abs(q) - w;
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
// r = sphere's radius
// h = cutting's plane's position
// t = thickness
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.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;
}
// https://iquilezles.org/articles/boxfunctions
vec2 iBox( in vec3 ro, in vec3 rd, in vec3 rad )
{
vec3 m = 1.0/rd;
vec3 n = m*ro;
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 ) );
}
vec2 opU( vec2 d1, vec2 d2 )
{
return (d1.x<d2.x) ? d1 : d2;
}
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 res = vec2(-1.0,-1.0);
float tmin = 1.0;
float tmax = 20.0;
// raytrace floor plane
float tp1 = (-ro.y)/rd.y;
if( tp1>0.0 )
{
tmax = min( tmax, tp1 );
res = vec2( tp1, 1.0 );
}
float t = tmin;
for( int i=0; i<70 ; i++ )
{
if(t>tmax) break;
vec2 h = map( ro+rd*t );
if( abs(h.x)<(0.0001*t) )
{
res = vec2(t,h.y);
break;
}
t += h.x;
}
return res;
}
// https://iquilezles.org/articles/rmshadows
float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax )
{
// bounding volume
float tp = (0.8-ro.y)/rd.y; if( tp>0.0 ) tmax = min( tmax, tp );
float res = 1.0;
float t = mint;
for( int i=ZERO; i<24; i++ )
{
float h = map( ro + rd*t ).x;
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);
}
// https://iquilezles.org/articles/normalsSDF
vec3 calcNormal( in vec3 pos )
{
vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;
return normalize( e.xyy*map( pos + e.xyy ).x +
e.yyx*map( pos + e.yyx ).x +
e.yxy*map( pos + e.yxy ).x +
e.xxx*map( pos + e.xxx ).x );
}
// https://iquilezles.org/articles/nvscene2008/rwwtt.pdf
float calcAO( in vec3 pos, in vec3 nor )
{
float occ = 0.0;
float sca = 1.0;
for( int i=ZERO; i<5; i++ )
{
float h = 0.01 + 0.12*float(i)/4.0;
float d = map( pos + h*nor ).x;
occ += (h-d)*sca;
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);
}
// https://iquilezles.org/articles/checkerfiltering
float checkersGradBox( in vec2 p )
{
// filter kernel
vec2 w = fwidth(p) + 0.001;
// 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;
}
// https://www.shadertoy.com/view/tdS3DG
vec4 render( in vec3 ro, in vec3 rd)
{
// background
vec3 col = vec3(0.7, 0.7, 0.9) - max(rd.y,0.0)*0.3;
// raycast scene
vec2 res = raycast(ro,rd);
float t = res.x;
float m = res.y;
if( m>-0.5 )
{
vec3 pos = ro + t*rd;
vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal( pos );
vec3 ref = reflect( rd, nor );
// material
col = 0.2 + 0.2*sin( m*2.0 + vec3(0.0,1.0,2.0) );
float ks = 1.0;
if( m<1.5 )
{
float f = checkersGradBox( 3.0*pos.xz);
col = 0.15 + f*vec3(0.05);
ks = 0.4;
}
// lighting
float occ = calcAO( pos, nor );
vec3 lin = vec3(0.0);
// sun
{
vec3 lig = normalize( vec3(-0.5, 0.4, -0.6) );
vec3 hal = normalize( lig-rd );
float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
//if( dif>0.0001 )
dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );
float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
//spe *= 0.04+0.96*pow(clamp(1.0-sqrt(0.5*(1.0-dot(rd,lig))),0.0,1.0),5.0);
lin += col*2.20*dif*vec3(1.30,1.00,0.70);
lin += 5.00*spe*vec3(1.30,1.00,0.70)*ks;
}
// sky
{
float dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 ));
dif *= occ;
float spe = smoothstep( -0.2, 0.2, ref.y );
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0+dot(nor,rd),0.0,1.0), 5.0 );
//if( spe>0.001 )
spe *= calcSoftshadow( pos, ref, 0.02, 2.5 );
lin += col*0.60*dif*vec3(0.40,0.60,1.15);
lin += 2.00*spe*vec3(0.40,0.60,1.30)*ks;
}
// back
{
float dif = clamp( dot( nor, normalize(vec3(0.5,0.0,0.6))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0);
dif *= occ;
lin += col*0.55*dif*vec3(0.25,0.25,0.25);
}
// sss
{
float dif = pow(clamp(1.0+dot(nor,rd),0.0,1.0),2.0);
dif *= occ;
lin += col*0.25*dif*vec3(1.00,1.00,1.00);
}
col = lin;
col = mix( col, vec3(0.7,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) );
}
return vec4(vec3( clamp(col,0.0,1.0) ),t);
}
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);
}
mat3 setCamera()
{
vec3 cw = normalize(camDir);
vec3 cp = vec3(0.0, 1.0 ,0.0);
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = ( cross(cu,cw) );
return mat3( cu, cv, cw );
}
void main()
{
vec2 nCoord = (gl_FragCoord.xy - screenCenter.xy)/screenCenter.y;
mat3 ca = setCamera();
// focal length
float fl = length(camDir);
vec3 rd = ca * normalize( vec3(nCoord,fl) );
vec3 color = vec3(nCoord/2.0 + 0.5, 0.0);
float depth = gl_FragCoord.z;
{
vec4 res = render( camPos - vec3(0.0, 0.0, 0.0) , rd );
color = res.xyz;
depth = CalcDepth(rd,res.w);
}
gl_FragColor = vec4(color , 1.0);
gl_FragDepthEXT = depth;
}

View File

@ -0,0 +1,14 @@
#version 330
in vec2 fragTexCoord;
in vec4 fragColor;
uniform sampler2D texture0;
uniform vec4 colDiffuse;
void main()
{
vec4 texelColor = texture2D(texture0, fragTexCoord);
gl_FragColor = texelColor*colDiffuse*fragColor;
gl_FragDepth = gl_FragCoord.z;
}

View File

@ -0,0 +1,284 @@
# version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Custom Input Uniform
uniform vec3 camPos;
uniform vec3 camDir;
uniform vec2 screenCenter;
#define ZERO 0
// https://learnopengl.com/Advanced-OpenGL/Depth-testing
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);
}
// https://iquilezles.org/articles/distfunctions/
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 = 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);
vec2 d = abs(q) - w;
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
// r = sphere's radius
// h = cutting's plane's position
// t = thickness
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.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;
}
// https://iquilezles.org/articles/boxfunctions
vec2 iBox( in vec3 ro, in vec3 rd, in vec3 rad )
{
vec3 m = 1.0/rd;
vec3 n = m*ro;
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 ) );
}
vec2 opU( vec2 d1, vec2 d2 )
{
return (d1.x<d2.x) ? d1 : d2;
}
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 res = vec2(-1.0,-1.0);
float tmin = 1.0;
float tmax = 20.0;
// raytrace floor plane
float tp1 = (-ro.y)/rd.y;
if( tp1>0.0 )
{
tmax = min( tmax, tp1 );
res = vec2( tp1, 1.0 );
}
float t = tmin;
for( int i=0; i<70 ; i++ )
{
if(t>tmax) break;
vec2 h = map( ro+rd*t );
if( abs(h.x)<(0.0001*t) )
{
res = vec2(t,h.y);
break;
}
t += h.x;
}
return res;
}
// https://iquilezles.org/articles/rmshadows
float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax )
{
// bounding volume
float tp = (0.8-ro.y)/rd.y; if( tp>0.0 ) tmax = min( tmax, tp );
float res = 1.0;
float t = mint;
for( int i=ZERO; i<24; i++ )
{
float h = map( ro + rd*t ).x;
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);
}
// https://iquilezles.org/articles/normalsSDF
vec3 calcNormal( in vec3 pos )
{
vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;
return normalize( e.xyy*map( pos + e.xyy ).x +
e.yyx*map( pos + e.yyx ).x +
e.yxy*map( pos + e.yxy ).x +
e.xxx*map( pos + e.xxx ).x );
}
// https://iquilezles.org/articles/nvscene2008/rwwtt.pdf
float calcAO( in vec3 pos, in vec3 nor )
{
float occ = 0.0;
float sca = 1.0;
for( int i=ZERO; i<5; i++ )
{
float h = 0.01 + 0.12*float(i)/4.0;
float d = map( pos + h*nor ).x;
occ += (h-d)*sca;
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);
}
// https://iquilezles.org/articles/checkerfiltering
float checkersGradBox( in vec2 p )
{
// filter kernel
vec2 w = fwidth(p) + 0.001;
// 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;
}
// https://www.shadertoy.com/view/tdS3DG
vec4 render( in vec3 ro, in vec3 rd)
{
// background
vec3 col = vec3(0.7, 0.7, 0.9) - max(rd.y,0.0)*0.3;
// raycast scene
vec2 res = raycast(ro,rd);
float t = res.x;
float m = res.y;
if( m>-0.5 )
{
vec3 pos = ro + t*rd;
vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal( pos );
vec3 ref = reflect( rd, nor );
// material
col = 0.2 + 0.2*sin( m*2.0 + vec3(0.0,1.0,2.0) );
float ks = 1.0;
if( m<1.5 )
{
float f = checkersGradBox( 3.0*pos.xz);
col = 0.15 + f*vec3(0.05);
ks = 0.4;
}
// lighting
float occ = calcAO( pos, nor );
vec3 lin = vec3(0.0);
// sun
{
vec3 lig = normalize( vec3(-0.5, 0.4, -0.6) );
vec3 hal = normalize( lig-rd );
float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
//if( dif>0.0001 )
dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );
float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
//spe *= 0.04+0.96*pow(clamp(1.0-sqrt(0.5*(1.0-dot(rd,lig))),0.0,1.0),5.0);
lin += col*2.20*dif*vec3(1.30,1.00,0.70);
lin += 5.00*spe*vec3(1.30,1.00,0.70)*ks;
}
// sky
{
float dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 ));
dif *= occ;
float spe = smoothstep( -0.2, 0.2, ref.y );
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0+dot(nor,rd),0.0,1.0), 5.0 );
//if( spe>0.001 )
spe *= calcSoftshadow( pos, ref, 0.02, 2.5 );
lin += col*0.60*dif*vec3(0.40,0.60,1.15);
lin += 2.00*spe*vec3(0.40,0.60,1.30)*ks;
}
// back
{
float dif = clamp( dot( nor, normalize(vec3(0.5,0.0,0.6))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0);
dif *= occ;
lin += col*0.55*dif*vec3(0.25,0.25,0.25);
}
// sss
{
float dif = pow(clamp(1.0+dot(nor,rd),0.0,1.0),2.0);
dif *= occ;
lin += col*0.25*dif*vec3(1.00,1.00,1.00);
}
col = lin;
col = mix( col, vec3(0.7,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) );
}
return vec4(vec3( clamp(col,0.0,1.0) ),t);
}
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);
}
mat3 setCamera()
{
vec3 cw = normalize(camDir);
vec3 cp = vec3(0.0, 1.0 ,0.0);
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = ( cross(cu,cw) );
return mat3( cu, cv, cw );
}
void main()
{
vec2 nCoord = (gl_FragCoord.xy - screenCenter.xy)/screenCenter.y;
mat3 ca = setCamera();
// focal length
float fl = length(camDir);
vec3 rd = ca * normalize( vec3(nCoord,fl) );
vec3 color = vec3(nCoord/2.0 + 0.5, 0.0);
float depth = gl_FragCoord.z;
{
vec4 res = render( camPos - vec3(0.0, 0.0, 0.0) , rd );
color = res.xyz;
depth = CalcDepth(rd,res.w);
}
gl_FragColor = vec4(color , 1.0);
gl_FragDepth = depth;
}

View File

@ -0,0 +1,212 @@
/*******************************************************************************************
*
* raylib [shaders] example - Hybrid Rendering
*
* Example originally created with raylib 4.2, last time updated with raylib 4.2
*
* Example contributed by Buğra Alptekin Sarı (@BugraAlptekinSari) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2022-2023 Buğra Alptekin Sarı (@BugraAlptekinSari)
*
********************************************************************************************/
#include "raylib.h"
#include "rlgl.h"
#include "math.h" // Used for tan()
#include "raymath.h" // Used to calculate camera Direction
#if defined(PLATFORM_DESKTOP)
#define GLSL_VERSION 330
#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
#define GLSL_VERSION 100
#endif
//------------------------------------------------------------------------------------
// Declare custom functions required for the example
//------------------------------------------------------------------------------------
// Load custom render texture, create a writable depth texture buffer
static RenderTexture2D LoadRenderTextureDepthTex(int width, int height);
// Unload render texture from GPU memory (VRAM)
static void UnloadRenderTextureDepthTex(RenderTexture2D target);
//------------------------------------------------------------------------------------
// Declare custom Structs
//------------------------------------------------------------------------------------
typedef struct {
unsigned int camPos, camDir, screenCenter;
}RayLocs ;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - write depth buffer");
// This Shader calculates pixel depth and color using raymarch.
Shader raymarch_shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raymarch.fs", GLSL_VERSION));
// This Shader is a standard rasterization fragment shader with the addition of depth writing. You are required to write depth for all shaders if one shader does it.
Shader raster_shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raster.fs", GLSL_VERSION));
// Declare Struct used to store camera locs.
RayLocs march_locs = {0};
// Fill the struct with shader locs.
march_locs.camPos = GetShaderLocation(raymarch_shader, "camPos");
march_locs.camDir = GetShaderLocation(raymarch_shader, "camDir");
march_locs.screenCenter = GetShaderLocation(raymarch_shader, "screenCenter");
{ // Transfer screenCenter position to shader. Which is used to calculate ray direction.
Vector2 screenCenter = {.x = screenWidth/2.0, .y = screenHeight/2.0};
SetShaderValue(raymarch_shader, march_locs.screenCenter , &screenCenter , SHADER_UNIFORM_VEC2);
}
// Use Customized function to create writable depth texture buffer
RenderTexture2D target = LoadRenderTextureDepthTex(screenWidth, screenHeight);
// Define the camera to look into our 3d world
Camera camera = {
.position = (Vector3){ 0.5f, 1.0f, 1.5f }, // Camera position
.target = (Vector3){ 0.0f, 0.5f, 0.0f }, // Camera looking at point
.up = (Vector3){ 0.0f, 1.0f, 0.0f }, // Camera up vector (rotation towards target)
.fovy = 45.0f, // Camera field-of-view Y
.projection = CAMERA_PERSPECTIVE // Camera mode type
};
// Camera FOV is pre-calculated in the camera Distance.
double camDist = 1.0/(tan(camera.fovy*0.5*DEG2RAD));
SetCameraMode(camera, CAMERA_FIRST_PERSON);
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(&camera);
//Update Camera Postion in the ray march shader.
SetShaderValue(raymarch_shader, march_locs.camPos, &(camera.position), RL_SHADER_UNIFORM_VEC3);
{ // Update Camera Looking Vector. Vector length determines FOV.
Vector3 camDir = Vector3Scale( Vector3Normalize( Vector3Subtract(camera.target, camera.position)) , camDist);
SetShaderValue(raymarch_shader, march_locs.camDir, &(camDir), RL_SHADER_UNIFORM_VEC3);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw into our custom render texture (framebuffer)
BeginTextureMode(target);
ClearBackground(WHITE);
// Raymarch Scene
rlEnableDepthTest(); //Manually enable Depth Test to handle multiple rendering methods.
BeginShaderMode(raymarch_shader);
DrawRectangleRec((Rectangle){0,0,screenWidth,screenHeight},WHITE);
EndShaderMode();
// Raserize Scene
BeginMode3D(camera);
BeginShaderMode(raster_shader);
DrawCubeWiresV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, RED);
DrawCubeV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, PURPLE);
DrawCubeWiresV((Vector3){ 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, DARKGREEN);
DrawCubeV((Vector3) { 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, YELLOW);
DrawGrid(10, 1.0f);
EndShaderMode();
EndMode3D();
EndTextureMode();
// Draw into screen our custom render texture
BeginDrawing();
ClearBackground(RAYWHITE);
DrawTextureRec(target.texture, (Rectangle) { 0, 0, screenWidth, -screenHeight }, (Vector2) { 0, 0 }, WHITE);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadRenderTextureDepthTex(target);
UnloadShader(raymarch_shader);
UnloadShader(raster_shader);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
//------------------------------------------------------------------------------------
// Define custom functions required for the example
//------------------------------------------------------------------------------------
// Load custom render texture, create a writable depth texture buffer
RenderTexture2D LoadRenderTextureDepthTex(int width, int height)
{
RenderTexture2D target = { 0 };
target.id = rlLoadFramebuffer(width, height); // Load an empty framebuffer
if (target.id > 0)
{
rlEnableFramebuffer(target.id);
// Create color texture (default to RGBA)
target.texture.id = rlLoadTexture(0, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
target.texture.width = width;
target.texture.height = height;
target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
target.texture.mipmaps = 1;
// Create depth texture buffer (instead of raylib default renderbuffer)
target.depth.id = rlLoadTextureDepth(width, height, false);
target.depth.width = width;
target.depth.height = height;
target.depth.format = 19; //DEPTH_COMPONENT_24BIT?
target.depth.mipmaps = 1;
// Attach color texture and depth texture to FBO
rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_TEXTURE2D, 0);
// Check if fbo is complete with attachments (valid)
if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id);
rlDisableFramebuffer();
}
else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created");
return target;
}
// Unload render texture from GPU memory (VRAM)
void UnloadRenderTextureDepthTex(RenderTexture2D target)
{
if (target.id > 0)
{
// Color texture attached to FBO is deleted
rlUnloadTexture(target.texture.id);
rlUnloadTexture(target.depth.id);
// NOTE: Depth texture is automatically
// queried and deleted before deleting framebuffer
rlUnloadFramebuffer(target.id);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build.LibExeObjStep { pub fn addRaylib(b: *std.Build, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) *std.Build.CompileStep {
const raylib_flags = &[_][]const u8{ const raylib_flags = &[_][]const u8{
"-std=gnu99", "-std=gnu99",
"-D_GNU_SOURCE", "-D_GNU_SOURCE",
@ -8,8 +8,11 @@ pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build.
"-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/1891 "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/1891
}; };
const raylib = b.addStaticLibrary("raylib", null); const raylib = b.addStaticLibrary(.{
raylib.setTarget(target); .name = "raylib",
.target = target,
.optimize = optimize,
});
raylib.linkLibC(); raylib.linkLibC();
raylib.addIncludePath(srcdir ++ "/external/glfw/include"); raylib.addIncludePath(srcdir ++ "/external/glfw/include");
@ -100,14 +103,18 @@ pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build.
return raylib; return raylib;
} }
pub fn build(b: *std.build.Builder) void { pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose // Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which // what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options // means any target is allowed, and the default is native. Other options
// for restricting supported target set are available. // for restricting supported target set are available.
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const lib = addRaylib(b, target); const lib = addRaylib(b, target, optimize);
lib.setOutputDir(srcdir); lib.setOutputDir(srcdir);
lib.install(); lib.install();
} }

View File

@ -24,66 +24,68 @@
* 3. This notice may not be removed or altered from any source distribution. * 3. This notice may not be removed or altered from any source distribution.
* *
**********************************************************************************************/ **********************************************************************************************/
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module selection - Some modules could be avoided // Module selection - Some modules could be avoided
// Mandatory modules: rcore, rlgl, utils // Mandatory modules: rcore, rlgl, utils
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
#define SUPPORT_MODULE_RSHAPES 1 #define SUPPORT_MODULE_RSHAPES 1
#define SUPPORT_MODULE_RTEXTURES 1 #define SUPPORT_MODULE_RTEXTURES 1
#define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures #define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures
#define SUPPORT_MODULE_RMODELS 1 #define SUPPORT_MODULE_RMODELS 1
#define SUPPORT_MODULE_RAUDIO 1 #define SUPPORT_MODULE_RAUDIO 1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: rcore - Configuration Flags // Module: rcore - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital // Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
#define SUPPORT_CAMERA_SYSTEM 1 #define SUPPORT_CAMERA_SYSTEM 1
// Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag // Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
#define SUPPORT_GESTURES_SYSTEM 1 #define SUPPORT_GESTURES_SYSTEM 1
// Mouse gestures are directly mapped like touches and processed by gestures system // Mouse gestures are directly mapped like touches and processed by gestures system
#define SUPPORT_MOUSE_GESTURES 1 #define SUPPORT_MOUSE_GESTURES 1
// Reconfigure standard input to receive key inputs, works with SSH connection. // Reconfigure standard input to receive key inputs, works with SSH connection.
#define SUPPORT_SSH_KEYBOARD_RPI 1 #define SUPPORT_SSH_KEYBOARD_RPI 1
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
#define SUPPORT_WINMM_HIGHRES_TIMER 1 #define SUPPORT_WINMM_HIGHRES_TIMER 1
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used // Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used
//#define SUPPORT_BUSY_WAIT_LOOP 1 //#define SUPPORT_BUSY_WAIT_LOOP 1
// Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy // Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy
#define SUPPORT_PARTIALBUSY_WAIT_LOOP #define SUPPORT_PARTIALBUSY_WAIT_LOOP
// Wait for events passively (sleeping while no events) instead of polling them actively every frame // Wait for events passively (sleeping while no events) instead of polling them actively every frame
//#define SUPPORT_EVENTS_WAITING 1 //#define SUPPORT_EVENTS_WAITING 1
// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
#define SUPPORT_SCREEN_CAPTURE 1 #define SUPPORT_SCREEN_CAPTURE 1
// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
#define SUPPORT_GIF_RECORDING 1 #define SUPPORT_GIF_RECORDING 1
// Support CompressData() and DecompressData() functions // Support CompressData() and DecompressData() functions
#define SUPPORT_COMPRESSION_API 1 #define SUPPORT_COMPRESSION_API 1
// Support automatic generated events, loading and recording of those events when required // Support automatic generated events, loading and recording of those events when required
//#define SUPPORT_EVENTS_AUTOMATION 1 //#define SUPPORT_EVENTS_AUTOMATION 1
// Support custom frame control, only for advance users // Support custom frame control, only for advance users
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timming + PollInputEvents() // By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// Enabling this flag allows manual control of the frame processes, use at your own risk // Enabling this flag allows manual control of the frame processes, use at your own risk
//#define SUPPORT_CUSTOM_FRAME_CONTROL 1 //#define SUPPORT_CUSTOM_FRAME_CONTROL 1
// rcore: Configuration values // rcore: Configuration values
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity #define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) #define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported #define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported #define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported #define MAX_GAMEPADS 4 // Maximum number of gamepads supported
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad) #define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue #define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue #define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB #define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -110,12 +112,12 @@
// Default shader vertex attribute names to set location points // Default shader vertex attribute names to set location points
// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience // NOTE: When a new shader is loaded, the following locations are tried to be set for convenience
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0 #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
@ -133,36 +135,36 @@
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Use QUADS instead of TRIANGLES for drawing when possible // Use QUADS instead of TRIANGLES for drawing when possible
// Some lines-based shapes could still use lines // Some lines-based shapes could still use lines
#define SUPPORT_QUADS_DRAW_MODE 1 #define SUPPORT_QUADS_DRAW_MODE 1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: rtextures - Configuration Flags // Module: rtextures - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Selecte desired fileformats to be supported for image data loading // Select the desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1 #define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1 //#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1 //#define SUPPORT_FILEFORMAT_TGA 1
//#define SUPPORT_FILEFORMAT_JPG 1 //#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1 #define SUPPORT_FILEFORMAT_GIF 1
#define SUPPORT_FILEFORMAT_QOI 1 #define SUPPORT_FILEFORMAT_QOI 1
//#define SUPPORT_FILEFORMAT_PSD 1 //#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1 #define SUPPORT_FILEFORMAT_DDS 1
#define SUPPORT_FILEFORMAT_HDR 1 #define SUPPORT_FILEFORMAT_HDR 1
//#define SUPPORT_FILEFORMAT_PIC 1 //#define SUPPORT_FILEFORMAT_PIC 1
//#define SUPPORT_FILEFORMAT_PNM 1 //#define SUPPORT_FILEFORMAT_PNM 1
//#define SUPPORT_FILEFORMAT_KTX 1 //#define SUPPORT_FILEFORMAT_KTX 1
//#define SUPPORT_FILEFORMAT_ASTC 1 //#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1 //#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1 //#define SUPPORT_FILEFORMAT_PVR 1
// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi) // Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
#define SUPPORT_IMAGE_EXPORT 1 #define SUPPORT_IMAGE_EXPORT 1
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) // Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
#define SUPPORT_IMAGE_GENERATION 1 #define SUPPORT_IMAGE_GENERATION 1
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... // Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT() // If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
#define SUPPORT_IMAGE_MANIPULATION 1 #define SUPPORT_IMAGE_MANIPULATION 1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -170,51 +172,52 @@
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Default font is loaded on window initialization to be available for the user to render simple text // Default font is loaded on window initialization to be available for the user to render simple text
// NOTE: If enabled, uses external module functions to load default raylib font // NOTE: If enabled, uses external module functions to load default raylib font
#define SUPPORT_DEFAULT_FONT 1 #define SUPPORT_DEFAULT_FONT 1
// Selected desired font fileformats to be supported for loading // Selected desired font fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_FNT 1 #define SUPPORT_FILEFORMAT_FNT 1
#define SUPPORT_FILEFORMAT_TTF 1 #define SUPPORT_FILEFORMAT_TTF 1
// Support text management functions // Support text management functions
// If not defined, still some functions are supported: TextLength(), TextFormat() // If not defined, still some functions are supported: TextLength(), TextFormat()
#define SUPPORT_TEXT_MANIPULATION 1 #define SUPPORT_TEXT_MANIPULATION 1
// rtext: Configuration values // rtext: Configuration values
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: #define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() #define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: rmodels - Configuration Flags // Module: rmodels - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Selected desired model fileformats to be supported for loading // Selected desired model fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_OBJ 1 #define SUPPORT_FILEFORMAT_OBJ 1
#define SUPPORT_FILEFORMAT_MTL 1 #define SUPPORT_FILEFORMAT_MTL 1
#define SUPPORT_FILEFORMAT_IQM 1 #define SUPPORT_FILEFORMAT_IQM 1
#define SUPPORT_FILEFORMAT_GLTF 1 #define SUPPORT_FILEFORMAT_GLTF 1
#define SUPPORT_FILEFORMAT_VOX 1 #define SUPPORT_FILEFORMAT_VOX 1
#define SUPPORT_FILEFORMAT_M3D 1 #define SUPPORT_FILEFORMAT_M3D 1
// Support procedural mesh generation functions, uses external par_shapes.h library // Support procedural mesh generation functions, uses external par_shapes.h library
// NOTE: Some generated meshes DO NOT include generated texture coordinates // NOTE: Some generated meshes DO NOT include generated texture coordinates
#define SUPPORT_MESH_GENERATION 1 #define SUPPORT_MESH_GENERATION 1
// rmodels: Configuration values // rmodels: Configuration values
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported #define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: raudio - Configuration Flags // Module: raudio - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Desired audio fileformats to be supported for loading // Desired audio fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_WAV 1 #define SUPPORT_FILEFORMAT_WAV 1
#define SUPPORT_FILEFORMAT_OGG 1 #define SUPPORT_FILEFORMAT_OGG 1
#define SUPPORT_FILEFORMAT_XM 1 #define SUPPORT_FILEFORMAT_MP3 1
#define SUPPORT_FILEFORMAT_MOD 1 //#define SUPPORT_FILEFORMAT_QOA 1
#define SUPPORT_FILEFORMAT_MP3 1 //#define SUPPORT_FILEFORMAT_FLAC 1
//#define SUPPORT_FILEFORMAT_FLAC 1 #define SUPPORT_FILEFORMAT_XM 1
#define SUPPORT_FILEFORMAT_MOD 1
// raudio: Configuration values // raudio: Configuration values
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -228,14 +231,14 @@
// Module: utils - Configuration Flags // Module: utils - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Standard file io library (stdio.h) included // Standard file io library (stdio.h) included
#define SUPPORT_STANDARD_FILEIO #define SUPPORT_STANDARD_FILEIO 1
// Show TRACELOG() output messages // Show TRACELOG() output messages
// NOTE: By default LOG_DEBUG traces not shown // NOTE: By default LOG_DEBUG traces not shown
#define SUPPORT_TRACELOG 1 #define SUPPORT_TRACELOG 1
//#define SUPPORT_TRACELOG_DEBUG 1 //#define SUPPORT_TRACELOG_DEBUG 1
// utils: Configuration values // utils: Configuration values
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message #define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message
#endif // CONFIG_H #endif // CONFIG_H

660
src/external/qoa.h vendored Normal file
View File

@ -0,0 +1,660 @@
/*
Copyright (c) 2023, Dominic Szablewski - https://phoboslab.org
SPDX-License-Identifier: MIT
QOA - The "Quite OK Audio" format for fast, lossy audio compression
-- Data Format
A QOA file has an 8 byte file header, followed by a number of frames. Each frame
consists of an 8 byte frame header, the current 8 byte en-/decoder state per
channel and 256 slices per channel. Each slice is 8 bytes wide and encodes 20
samples of audio data.
Note that the last frame of a file may contain less than 256 slices per channel.
The last slice (per channel) in the last frame may contain less 20 samples, but
the slice will still be 8 bytes wide, with the unused samples zeroed out.
The samplerate and number of channels is only stated in the frame headers, but
not in the file header. A decoder may peek into the first frame of the file to
find these values.
In a valid QOA file all frames have the same number of channels and the same
samplerate. These restriction may be releaxed for streaming. This remains to
be decided.
All values in a QOA file are BIG ENDIAN. Luckily, EVERYTHING in a QOA file,
including the headers, is 64 bit aligned, so it's possible to read files with
just a read_u64() that does the byte swapping if neccessary.
In pseudocode, the file layout is as follows:
struct {
struct {
char magic[4]; // magic bytes 'qoaf'
uint32_t samples; // number of samples per channel in this file
} file_header; // = 64 bits
struct {
struct {
uint8_t num_channels; // number of channels
uint24_t samplerate; // samplerate in hz
uint16_t fsamples; // sample count per channel in this frame
uint16_t fsize; // frame size (including the frame header)
} frame_header; // = 64 bits
struct {
int16_t history[4]; // = 64 bits
int16_t weights[4]; // = 64 bits
} lms_state[num_channels];
qoa_slice_t slices[256][num_channels]; // = 64 bits each
} frames[samples * channels / qoa_max_framesize()];
} qoa_file;
Wheras the 64bit qoa_slice_t is defined as follows:
.- QOA_SLICE -- 64 bits, 20 samples --------------------------/ /------------.
| Byte[0] | Byte[1] | Byte[2] \ \ Byte[7] |
| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 / / 2 1 0 |
|------------+--------+--------+--------+---------+---------+-\ \--+---------|
| sf_index | r00 | r01 | r02 | r03 | r04 | / / | r19 |
`-------------------------------------------------------------\ \------------`
`sf_index` defines the scalefactor to use for this slice as an index into the
qoa_scalefactor_tab[16]
`r00`--`r19` are the residuals for the individiual samples, divided by the
scalefactor and quantized by the qoa_quant_tab[].
In the decoder, a prediction of the next sample is computed by multiplying the
state (the last four output samples) with the predictor. The residual from the
slice is then dequantized using the qoa_dequant_tab[] and added to the
prediction. The result is clamped to int16 to form the final output sample.
*/
/* -----------------------------------------------------------------------------
Header - Public functions */
#ifndef QOA_H
#define QOA_H
#ifdef __cplusplus
extern "C" {
#endif
#define QOA_MIN_FILESIZE 16
#define QOA_MAX_CHANNELS 8
#define QOA_SLICE_LEN 20
#define QOA_SLICES_PER_FRAME 256
#define QOA_FRAME_LEN (QOA_SLICES_PER_FRAME * QOA_SLICE_LEN)
#define QOA_LMS_LEN 4
#define QOA_MAGIC 0x716f6166 /* 'qoaf' */
#define QOA_FRAME_SIZE(channels, slices) \
(8 + QOA_LMS_LEN * 4 * channels + 8 * slices * channels)
typedef struct {
int history[QOA_LMS_LEN];
int weights[QOA_LMS_LEN];
} qoa_lms_t;
typedef struct {
unsigned int channels;
unsigned int samplerate;
unsigned int samples;
qoa_lms_t lms[QOA_MAX_CHANNELS];
#ifdef QOA_RECORD_TOTAL_ERROR
double error;
#endif
} qoa_desc;
unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes);
unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes);
void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len);
unsigned int qoa_max_frame_size(qoa_desc *qoa);
unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa);
unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len);
short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file);
#ifndef QOA_NO_STDIO
int qoa_write(const char *filename, const short *sample_data, qoa_desc *qoa);
void *qoa_read(const char *filename, qoa_desc *qoa);
#endif /* QOA_NO_STDIO */
#ifdef __cplusplus
}
#endif
#endif /* QOA_H */
/* -----------------------------------------------------------------------------
Implementation */
#ifdef QOA_IMPLEMENTATION
#include <stdlib.h>
#ifndef QOA_MALLOC
#define QOA_MALLOC(sz) malloc(sz)
#define QOA_FREE(p) free(p)
#endif
typedef unsigned long long qoa_uint64_t;
/* The quant_tab provides an index into the dequant_tab for residuals in the
range of -8 .. 8. It maps this range to just 3bits and becommes less accurate at
the higher end. Note that the residual zero is identical to the lowest positive
value. This is mostly fine, since the qoa_div() function always rounds away
from zero. */
static int qoa_quant_tab[17] = {
7, 7, 7, 5, 5, 3, 3, 1, /* -8..-1 */
0, /* 0 */
0, 2, 2, 4, 4, 6, 6, 6 /* 1.. 8 */
};
/* We have 16 different scalefactors. Like the quantized residuals these become
less accurate at the higher end. In theory, the highest scalefactor that we
would need to encode the highest 16bit residual is (2**16)/8 = 8192. However we
rely on the LMS filter to predict samples accurately enough that a maximum
residual of one quarter of the 16 bit range is high sufficent. I.e. with the
scalefactor 2048 times the quant range of 8 we can encode residuals up to 2**14.
The scalefactor values are computed as:
scalefactor_tab[s] <- round(pow(s + 1, 2.75)) */
static int qoa_scalefactor_tab[16] = {
1, 7, 21, 45, 84, 138, 211, 304, 421, 562, 731, 928, 1157, 1419, 1715, 2048
};
/* The reciprocal_tab maps each of the 16 scalefactors to their rounded
reciprocals 1/scalefactor. This allows us to calculate the scaled residuals in
the encoder with just one multiplication instead of an expensive division. We
do this in .16 fixed point with integers, instead of floats.
The reciprocal_tab is computed as:
reciprocal_tab[s] <- ((1<<16) + scalefactor_tab[s] - 1) / scalefactor_tab[s] */
static int qoa_reciprocal_tab[16] = {
65536, 9363, 3121, 1457, 781, 475, 311, 216, 156, 117, 90, 71, 57, 47, 39, 32
};
/* The dequant_tab maps each of the scalefactors and quantized residuals to
their unscaled & dequantized version.
Since qoa_div rounds away from the zero, the smallest entries are mapped to 3/4
instead of 1. The dequant_tab assumes the following dequantized values for each
of the quant_tab indices and is computed as:
float dqt[8] = {0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7};
dequant_tab[s][q] <- round(scalefactor_tab[s] * dqt[q]) */
static int qoa_dequant_tab[16][8] = {
{ 1, -1, 3, -3, 5, -5, 7, -7},
{ 5, -5, 18, -18, 32, -32, 49, -49},
{ 16, -16, 53, -53, 95, -95, 147, -147},
{ 34, -34, 113, -113, 203, -203, 315, -315},
{ 63, -63, 210, -210, 378, -378, 588, -588},
{ 104, -104, 345, -345, 621, -621, 966, -966},
{ 158, -158, 528, -528, 950, -950, 1477, -1477},
{ 228, -228, 760, -760, 1368, -1368, 2128, -2128},
{ 316, -316, 1053, -1053, 1895, -1895, 2947, -2947},
{ 422, -422, 1405, -1405, 2529, -2529, 3934, -3934},
{ 548, -548, 1828, -1828, 3290, -3290, 5117, -5117},
{ 696, -696, 2320, -2320, 4176, -4176, 6496, -6496},
{ 868, -868, 2893, -2893, 5207, -5207, 8099, -8099},
{1064, -1064, 3548, -3548, 6386, -6386, 9933, -9933},
{1286, -1286, 4288, -4288, 7718, -7718, 12005, -12005},
{1536, -1536, 5120, -5120, 9216, -9216, 14336, -14336},
};
/* The Least Mean Squares Filter is the heart of QOA. It predicts the next
sample based on the previous 4 reconstructed samples. It does so by continuously
adjusting 4 weights based on the residual of the previous prediction.
The next sample is predicted as the sum of (weight[i] * history[i]).
The adjustment of the weights is done with a "Sign-Sign-LMS" that adds or
subtracts the residual to each weight, based on the corresponding sample from
the history. This, suprisingly, is sufficent to get worthwhile predictions.
This is all done with fixed point integers. Hence the right-shifts when updating
the weights and calculating the prediction. */
static int qoa_lms_predict(qoa_lms_t *lms) {
int prediction = 0;
for (int i = 0; i < QOA_LMS_LEN; i++) {
prediction += lms->weights[i] * lms->history[i];
}
return prediction >> 13;
}
static void qoa_lms_update(qoa_lms_t *lms, int sample, int residual) {
int delta = residual >> 4;
for (int i = 0; i < QOA_LMS_LEN; i++) {
lms->weights[i] += lms->history[i] < 0 ? -delta : delta;
}
for (int i = 0; i < QOA_LMS_LEN-1; i++) {
lms->history[i] = lms->history[i+1];
}
lms->history[QOA_LMS_LEN-1] = sample;
}
/* qoa_div() implements a rounding division, but avoids rounding to zero for
small numbers. E.g. 0.1 will be rounded to 1. Note that 0 itself still
returns as 0, which is handled in the qoa_quant_tab[].
qoa_div() takes an index into the .16 fixed point qoa_reciprocal_tab as an
argument, so it can do the division with a cheaper integer multiplication. */
static inline int qoa_div(int v, int scalefactor) {
int reciprocal = qoa_reciprocal_tab[scalefactor];
int n = (v * reciprocal + (1 << 15)) >> 16;
n = n + ((v > 0) - (v < 0)) - ((n > 0) - (n < 0)); /* round away from 0 */
return n;
}
static inline int qoa_clamp(int v, int min, int max) {
return (v < min) ? min : (v > max) ? max : v;
}
static inline qoa_uint64_t qoa_read_u64(const unsigned char *bytes, unsigned int *p) {
bytes += *p;
*p += 8;
return
((qoa_uint64_t)(bytes[0]) << 56) | ((qoa_uint64_t)(bytes[1]) << 48) |
((qoa_uint64_t)(bytes[2]) << 40) | ((qoa_uint64_t)(bytes[3]) << 32) |
((qoa_uint64_t)(bytes[4]) << 24) | ((qoa_uint64_t)(bytes[5]) << 16) |
((qoa_uint64_t)(bytes[6]) << 8) | ((qoa_uint64_t)(bytes[7]) << 0);
}
static inline void qoa_write_u64(qoa_uint64_t v, unsigned char *bytes, unsigned int *p) {
bytes += *p;
*p += 8;
bytes[0] = (v >> 56) & 0xff;
bytes[1] = (v >> 48) & 0xff;
bytes[2] = (v >> 40) & 0xff;
bytes[3] = (v >> 32) & 0xff;
bytes[4] = (v >> 24) & 0xff;
bytes[5] = (v >> 16) & 0xff;
bytes[6] = (v >> 8) & 0xff;
bytes[7] = (v >> 0) & 0xff;
}
/* -----------------------------------------------------------------------------
Encoder */
unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes) {
unsigned int p = 0;
qoa_write_u64(((qoa_uint64_t)QOA_MAGIC << 32) | qoa->samples, bytes, &p);
return p;
}
unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes) {
unsigned int channels = qoa->channels;
unsigned int p = 0;
unsigned int slices = (frame_len + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN;
unsigned int frame_size = QOA_FRAME_SIZE(channels, slices);
/* Write the frame header */
qoa_write_u64((
(qoa_uint64_t)qoa->channels << 56 |
(qoa_uint64_t)qoa->samplerate << 32 |
(qoa_uint64_t)frame_len << 16 |
(qoa_uint64_t)frame_size
), bytes, &p);
/* Write the current LMS state */
for (int c = 0; c < channels; c++) {
qoa_uint64_t weights = 0;
qoa_uint64_t history = 0;
for (int i = 0; i < QOA_LMS_LEN; i++) {
history = (history << 16) | (qoa->lms[c].history[i] & 0xffff);
weights = (weights << 16) | (qoa->lms[c].weights[i] & 0xffff);
}
qoa_write_u64(history, bytes, &p);
qoa_write_u64(weights, bytes, &p);
}
/* We encode all samples with the channels interleaved on a slice level.
E.g. for stereo: (ch-0, slice 0), (ch 1, slice 0), (ch 0, slice 1), ...*/
for (int sample_index = 0; sample_index < frame_len; sample_index += QOA_SLICE_LEN) {
for (int c = 0; c < channels; c++) {
int slice_len = qoa_clamp(QOA_SLICE_LEN, 0, frame_len - sample_index);
int slice_start = sample_index * channels + c;
int slice_end = (sample_index + slice_len) * channels + c;
/* Brute for search for the best scalefactor. Just go through all
16 scalefactors, encode all samples for the current slice and
meassure the total squared error. */
qoa_uint64_t best_error = -1;
qoa_uint64_t best_slice;
qoa_lms_t best_lms;
for (int scalefactor = 0; scalefactor < 16; scalefactor++) {
/* We have to reset the LMS state to the last known good one
before trying each scalefactor, as each pass updates the LMS
state when encoding. */
qoa_lms_t lms = qoa->lms[c];
qoa_uint64_t slice = scalefactor;
qoa_uint64_t current_error = 0;
for (int si = slice_start; si < slice_end; si += channels) {
int sample = sample_data[si];
int predicted = qoa_lms_predict(&lms);
int residual = sample - predicted;
int scaled = qoa_div(residual, scalefactor);
int clamped = qoa_clamp(scaled, -8, 8);
int quantized = qoa_quant_tab[clamped + 8];
int dequantized = qoa_dequant_tab[scalefactor][quantized];
int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767);
int error = (sample - reconstructed);
current_error += error * error;
if (current_error > best_error) {
break;
}
qoa_lms_update(&lms, reconstructed, dequantized);
slice = (slice << 3) | quantized;
}
if (current_error < best_error) {
best_error = current_error;
best_slice = slice;
best_lms = lms;
}
}
qoa->lms[c] = best_lms;
#ifdef QOA_RECORD_TOTAL_ERROR
qoa->error += best_error;
#endif
/* If this slice was shorter than QOA_SLICE_LEN, we have to left-
shift all encoded data, to ensure the rightmost bits are the empty
ones. This should only happen in the last frame of a file as all
slices are completely filled otherwise. */
best_slice <<= (QOA_SLICE_LEN - slice_len) * 3;
qoa_write_u64(best_slice, bytes, &p);
}
}
return p;
}
void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len) {
if (
qoa->samples == 0 ||
qoa->samplerate == 0 || qoa->samplerate > 0xffffff ||
qoa->channels == 0 || qoa->channels > QOA_MAX_CHANNELS
) {
return NULL;
}
/* Calculate the encoded size and allocate */
unsigned int num_frames = (qoa->samples + QOA_FRAME_LEN-1) / QOA_FRAME_LEN;
unsigned int num_slices = (qoa->samples + QOA_SLICE_LEN-1) / QOA_SLICE_LEN;
unsigned int encoded_size = 8 + /* 8 byte file header */
num_frames * 8 + /* 8 byte frame headers */
num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */
num_slices * 8 * qoa->channels; /* 8 byte slices */
unsigned char *bytes = QOA_MALLOC(encoded_size);
for (int c = 0; c < qoa->channels; c++) {
/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the
prediction of the first few ms of a file. */
qoa->lms[c].weights[0] = 0;
qoa->lms[c].weights[1] = 0;
qoa->lms[c].weights[2] = -(1<<13);
qoa->lms[c].weights[3] = (1<<14);
/* Explicitly set the history samples to 0, as we might have some
garbage in there. */
for (int i = 0; i < QOA_LMS_LEN; i++) {
qoa->lms[c].history[i] = 0;
}
}
/* Encode the header and go through all frames */
unsigned int p = qoa_encode_header(qoa, bytes);
#ifdef QOA_RECORD_TOTAL_ERROR
qoa->error = 0;
#endif
int frame_len = QOA_FRAME_LEN;
for (int sample_index = 0; sample_index < qoa->samples; sample_index += frame_len) {
frame_len = qoa_clamp(QOA_FRAME_LEN, 0, qoa->samples - sample_index);
const short *frame_samples = sample_data + sample_index * qoa->channels;
unsigned int frame_size = qoa_encode_frame(frame_samples, qoa, frame_len, bytes + p);
p += frame_size;
}
*out_len = p;
return bytes;
}
/* -----------------------------------------------------------------------------
Decoder */
unsigned int qoa_max_frame_size(qoa_desc *qoa) {
return QOA_FRAME_SIZE(qoa->channels, QOA_SLICES_PER_FRAME);
}
unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa) {
unsigned int p = 0;
if (size < QOA_MIN_FILESIZE) {
return 0;
}
/* Read the file header, verify the magic number ('qoaf') and read the
total number of samples. */
qoa_uint64_t file_header = qoa_read_u64(bytes, &p);
if ((file_header >> 32) != QOA_MAGIC) {
return 0;
}
qoa->samples = file_header & 0xffffffff;
if (!qoa->samples) {
return 0;
}
/* Peek into the first frame header to get the number of channels and
the samplerate. */
qoa_uint64_t frame_header = qoa_read_u64(bytes, &p);
qoa->channels = (frame_header >> 56) & 0x0000ff;
qoa->samplerate = (frame_header >> 32) & 0xffffff;
if (qoa->channels == 0 || qoa->samples == 0 || qoa->samplerate == 0) {
return 0;
}
return 8;
}
unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len) {
unsigned int p = 0;
*frame_len = 0;
if (size < 8 + QOA_LMS_LEN * 4 * qoa->channels) {
return 0;
}
/* Read and verify the frame header */
qoa_uint64_t frame_header = qoa_read_u64(bytes, &p);
int channels = (frame_header >> 56) & 0x0000ff;
int samplerate = (frame_header >> 32) & 0xffffff;
int samples = (frame_header >> 16) & 0x00ffff;
int frame_size = (frame_header ) & 0x00ffff;
int data_size = frame_size - 8 - QOA_LMS_LEN * 4 * channels;
int num_slices = data_size / 8;
int max_total_samples = num_slices * QOA_SLICE_LEN;
if (
channels != qoa->channels ||
samplerate != qoa->samplerate ||
frame_size > size ||
samples * channels > max_total_samples
) {
return 0;
}
/* Read the LMS state: 4 x 2 bytes history, 4 x 2 bytes weights per channel */
for (int c = 0; c < channels; c++) {
qoa_uint64_t history = qoa_read_u64(bytes, &p);
qoa_uint64_t weights = qoa_read_u64(bytes, &p);
for (int i = 0; i < QOA_LMS_LEN; i++) {
qoa->lms[c].history[i] = ((signed short)(history >> 48));
history <<= 16;
qoa->lms[c].weights[i] = ((signed short)(weights >> 48));
weights <<= 16;
}
}
/* Decode all slices for all channels in this frame */
for (int sample_index = 0; sample_index < samples; sample_index += QOA_SLICE_LEN) {
for (int c = 0; c < channels; c++) {
qoa_uint64_t slice = qoa_read_u64(bytes, &p);
int scalefactor = (slice >> 60) & 0xf;
int slice_start = sample_index * channels + c;
int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c;
for (int si = slice_start; si < slice_end; si += channels) {
int predicted = qoa_lms_predict(&qoa->lms[c]);
int quantized = (slice >> 57) & 0x7;
int dequantized = qoa_dequant_tab[scalefactor][quantized];
int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767);
sample_data[si] = reconstructed;
slice <<= 3;
qoa_lms_update(&qoa->lms[c], reconstructed, dequantized);
}
}
}
*frame_len = samples;
return p;
}
short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) {
unsigned int p = qoa_decode_header(bytes, size, qoa);
if (!p) {
return NULL;
}
/* Calculate the required size of the sample buffer and allocate */
int total_samples = qoa->samples * qoa->channels;
short *sample_data = QOA_MALLOC(total_samples * sizeof(short));
unsigned int sample_index = 0;
unsigned int frame_len;
unsigned int frame_size;
/* Decode all frames */
do {
short *sample_ptr = sample_data + sample_index * qoa->channels;
frame_size = qoa_decode_frame(bytes + p, size - p, qoa, sample_ptr, &frame_len);
p += frame_size;
sample_index += frame_len;
} while (frame_size && sample_index < qoa->samples);
qoa->samples = sample_index;
return sample_data;
}
/* -----------------------------------------------------------------------------
File read/write convenience functions */
#ifndef QOA_NO_STDIO
#include <stdio.h>
int qoa_write(const char *filename, const short *sample_data, qoa_desc *qoa) {
FILE *f = fopen(filename, "wb");
unsigned int size;
void *encoded;
if (!f) {
return 0;
}
encoded = qoa_encode(sample_data, qoa, &size);
if (!encoded) {
fclose(f);
return 0;
}
fwrite(encoded, 1, size, f);
fclose(f);
QOA_FREE(encoded);
return size;
}
void *qoa_read(const char *filename, qoa_desc *qoa) {
FILE *f = fopen(filename, "rb");
int size, bytes_read;
void *data;
short *sample_data;
if (!f) {
return NULL;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
if (size <= 0) {
fclose(f);
return NULL;
}
fseek(f, 0, SEEK_SET);
data = QOA_MALLOC(size);
if (!data) {
fclose(f);
return NULL;
}
bytes_read = fread(data, 1, size, f);
fclose(f);
sample_data = qoa_decode(data, bytes_read, qoa);
QOA_FREE(data);
return sample_data;
}
#endif /* QOA_NO_STDIO */
#endif /* QOA_IMPLEMENTATION */

50
src/external/qoi.h vendored
View File

@ -1,31 +1,11 @@
/* /*
Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org
SPDX-License-Identifier: MIT
QOI - The "Quite OK Image" format for fast, lossless image compression QOI - The "Quite OK Image" format for fast, lossless image compression
Dominic Szablewski - https://phoboslab.org
-- LICENSE: The MIT License(MIT)
Copyright(c) 2021 Dominic Szablewski
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files(the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-- About -- About
QOI encodes and decodes images in a lossless format. Compared to stb_image and QOI encodes and decodes images in a lossless format. Compared to stb_image and
@ -424,13 +404,12 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
channels = desc->channels; channels = desc->channels;
for (px_pos = 0; px_pos < px_len; px_pos += channels) { for (px_pos = 0; px_pos < px_len; px_pos += channels) {
px.rgba.r = pixels[px_pos + 0];
px.rgba.g = pixels[px_pos + 1];
px.rgba.b = pixels[px_pos + 2];
if (channels == 4) { if (channels == 4) {
px = *(qoi_rgba_t *)(pixels + px_pos); px.rgba.a = pixels[px_pos + 3];
}
else {
px.rgba.r = pixels[px_pos + 0];
px.rgba.g = pixels[px_pos + 1];
px.rgba.b = pixels[px_pos + 2];
} }
if (px.v == px_prev.v) { if (px.v == px_prev.v) {
@ -598,13 +577,12 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
index[QOI_COLOR_HASH(px) % 64] = px; index[QOI_COLOR_HASH(px) % 64] = px;
} }
pixels[px_pos + 0] = px.rgba.r;
pixels[px_pos + 1] = px.rgba.g;
pixels[px_pos + 2] = px.rgba.b;
if (channels == 4) { if (channels == 4) {
*(qoi_rgba_t*)(pixels + px_pos) = px; pixels[px_pos + 3] = px.rgba.a;
}
else {
pixels[px_pos + 0] = px.rgba.r;
pixels[px_pos + 1] = px.rgba.g;
pixels[px_pos + 2] = px.rgba.b;
} }
} }

View File

@ -477,10 +477,10 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo
// Calculate file data_size required // Calculate file data_size required
int data_size = sizeof(ktx_header); int data_size = sizeof(ktx_header);
for (int i = 0, width = width, height = height; i < mipmaps; i++) for (int i = 0, w = width, h = height; i < mipmaps; i++)
{ {
data_size += get_pixel_data_size(width, height, format); data_size += get_pixel_data_size(w, h, format);
width /= 2; height /= 2; w /= 2; h /= 2;
} }
unsigned char *file_data = RL_CALLOC(data_size, 1); unsigned char *file_data = RL_CALLOC(data_size, 1);

View File

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html lang="en-us"> <html lang="EN-us">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

View File

@ -21,10 +21,11 @@
* *
* #define SUPPORT_FILEFORMAT_WAV * #define SUPPORT_FILEFORMAT_WAV
* #define SUPPORT_FILEFORMAT_OGG * #define SUPPORT_FILEFORMAT_OGG
* #define SUPPORT_FILEFORMAT_MP3
* #define SUPPORT_FILEFORMAT_QOA
* #define SUPPORT_FILEFORMAT_FLAC
* #define SUPPORT_FILEFORMAT_XM * #define SUPPORT_FILEFORMAT_XM
* #define SUPPORT_FILEFORMAT_MOD * #define SUPPORT_FILEFORMAT_MOD
* #define SUPPORT_FILEFORMAT_FLAC
* #define SUPPORT_FILEFORMAT_MP3
* Selected desired fileformats to be supported for loading. Some of those formats are * Selected desired fileformats to be supported for loading. Some of those formats are
* supported by default, to remove support, just comment unrequired #define in this module * supported by default, to remove support, just comment unrequired #define in this module
* *
@ -196,37 +197,6 @@ typedef struct tagBITMAPINFOHEADER {
#endif #endif
#endif #endif
#if defined(SUPPORT_FILEFORMAT_OGG)
// TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE
#include "external/stb_vorbis.c" // OGG loading functions
#endif
#if defined(SUPPORT_FILEFORMAT_XM)
#define JARXM_MALLOC RL_MALLOC
#define JARXM_FREE RL_FREE
#if defined(_MSC_VER ) // jar xm has warnings on windows, so disable them just for this file
#pragma warning( push )
#pragma warning( disable : 4244)
#endif
#define JAR_XM_IMPLEMENTATION
#include "external/jar_xm.h" // XM loading functions
#if defined(_MSC_VER )
#pragma warning( pop )
#endif
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
#define JARMOD_MALLOC RL_MALLOC
#define JARMOD_FREE RL_FREE
#define JAR_MOD_IMPLEMENTATION
#include "external/jar_mod.h" // MOD loading functions
#endif
#if defined(SUPPORT_FILEFORMAT_WAV) #if defined(SUPPORT_FILEFORMAT_WAV)
#define DRWAV_MALLOC RL_MALLOC #define DRWAV_MALLOC RL_MALLOC
#define DRWAV_REALLOC RL_REALLOC #define DRWAV_REALLOC RL_REALLOC
@ -236,6 +206,11 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/dr_wav.h" // WAV loading functions #include "external/dr_wav.h" // WAV loading functions
#endif #endif
#if defined(SUPPORT_FILEFORMAT_OGG)
// TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE
#include "external/stb_vorbis.c" // OGG loading functions
#endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
#define DRMP3_MALLOC RL_MALLOC #define DRMP3_MALLOC RL_MALLOC
#define DRMP3_REALLOC RL_REALLOC #define DRMP3_REALLOC RL_REALLOC
@ -245,6 +220,14 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/dr_mp3.h" // MP3 loading functions #include "external/dr_mp3.h" // MP3 loading functions
#endif #endif
#if defined(SUPPORT_FILEFORMAT_QOA)
#define QOA_MALLOC RL_MALLOC
#define QOA_FREE RL_FREE
#define QOA_IMPLEMENTATION
#include "external/qoa.h" // QOA loading and saving functions
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
#define DRFLAC_MALLOC RL_MALLOC #define DRFLAC_MALLOC RL_MALLOC
#define DRFLAC_REALLOC RL_REALLOC #define DRFLAC_REALLOC RL_REALLOC
@ -255,6 +238,31 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/dr_flac.h" // FLAC loading functions #include "external/dr_flac.h" // FLAC loading functions
#endif #endif
#if defined(SUPPORT_FILEFORMAT_XM)
#define JARXM_MALLOC RL_MALLOC
#define JARXM_FREE RL_FREE
#if defined(_MSC_VER ) // jar_xm has warnings on windows, so disable them just for this file
#pragma warning( push )
#pragma warning( disable : 4244)
#endif
#define JAR_XM_IMPLEMENTATION
#include "external/jar_xm.h" // XM loading functions
#if defined(_MSC_VER )
#pragma warning( pop )
#endif
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
#define JARMOD_MALLOC RL_MALLOC
#define JARMOD_FREE RL_FREE
#define JAR_MOD_IMPLEMENTATION
#include "external/jar_mod.h" // MOD loading functions
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -285,6 +293,7 @@ typedef enum {
MUSIC_AUDIO_OGG, // OGG audio context MUSIC_AUDIO_OGG, // OGG audio context
MUSIC_AUDIO_FLAC, // FLAC audio context MUSIC_AUDIO_FLAC, // FLAC audio context
MUSIC_AUDIO_MP3, // MP3 audio context MUSIC_AUDIO_MP3, // MP3 audio context
MUSIC_AUDIO_QOA, // QOA audio context
MUSIC_MODULE_XM, // XM module audio context MUSIC_MODULE_XM, // XM module audio context
MUSIC_MODULE_MOD // MOD module audio context MUSIC_MODULE_MOD // MOD module audio context
} MusicContextType; } MusicContextType;
@ -305,7 +314,7 @@ typedef enum {
#endif #endif
// NOTE: Different logic is used when feeding data to the playback device // NOTE: Different logic is used when feeding data to the playback device
// depending on whether or not data is streamed (Music vs Sound) // depending on whether data is streamed (Music vs Sound)
typedef enum { typedef enum {
AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STATIC = 0,
AUDIO_BUFFER_USAGE_STREAM AUDIO_BUFFER_USAGE_STREAM
@ -465,7 +474,7 @@ void InitAudioDevice(void)
return; return;
} }
// Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may // Mixing happens on a separate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may
// want to look at something a bit smarter later on to keep everything real-time, if that's necessary. // want to look at something a bit smarter later on to keep everything real-time, if that's necessary.
if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS) if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS)
{ {
@ -795,19 +804,6 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
else TRACELOG(LOG_WARNING, "WAVE: Failed to load OGG data"); else TRACELOG(LOG_WARNING, "WAVE: Failed to load OGG data");
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (strcmp(fileType, ".flac") == 0)
{
unsigned long long int totalFrameCount = 0;
// NOTE: We are forcing conversion to 16bit sample size on reading
wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL);
wave.sampleSize = 16;
if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount;
else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data");
}
#endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (strcmp(fileType, ".mp3") == 0) else if (strcmp(fileType, ".mp3") == 0)
{ {
@ -827,6 +823,38 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data"); else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data");
} }
#endif
#if defined(SUPPORT_FILEFORMAT_QOA)
else if (strcmp(fileType, ".qoa") == 0)
{
qoa_desc qoa = { 0 };
// NOTE: Returned sample data is always 16 bit?
wave.data = qoa_decode(fileData, dataSize, &qoa);
wave.sampleSize = 16;
if (wave.data != NULL)
{
wave.channels = qoa.channels;
wave.sampleRate = qoa.samplerate;
wave.frameCount = qoa.samples;
}
else TRACELOG(LOG_WARNING, "WAVE: Failed to load QOA data");
}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (strcmp(fileType, ".flac") == 0)
{
unsigned long long int totalFrameCount = 0;
// NOTE: We are forcing conversion to 16bit sample size on reading
wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL);
wave.sampleSize = 16;
if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount;
else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data");
}
#endif #endif
else TRACELOG(LOG_WARNING, "WAVE: Data format not supported"); else TRACELOG(LOG_WARNING, "WAVE: Data format not supported");
@ -957,6 +985,18 @@ bool ExportWave(Wave wave, const char *fileName)
drwav_free(fileData, NULL); drwav_free(fileData, NULL);
} }
#endif
#if defined(SUPPORT_FILEFORMAT_QOA)
else if (IsFileExtension(fileName, ".qoa"))
{
qoa_desc qoa = { 0 };
qoa.channels = wave.channels;
qoa.samplerate = wave.sampleRate;
qoa.samples = wave.frameCount;
// TODO: Review wave.data format required for export
success = qoa_write(fileName, wave.data, &qoa);
}
#endif #endif
else if (IsFileExtension(fileName, ".raw")) else if (IsFileExtension(fileName, ".raw"))
{ {
@ -1049,7 +1089,7 @@ void PlaySoundMulti(Sound sound)
unsigned int oldAge = 0; unsigned int oldAge = 0;
int oldIndex = -1; int oldIndex = -1;
// find the first non playing pool entry // find the first non-playing pool entry
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
{ {
if (AUDIO.MultiChannel.channels[i] > oldAge) if (AUDIO.MultiChannel.channels[i] > oldAge)
@ -1065,7 +1105,7 @@ void PlaySoundMulti(Sound sound)
} }
} }
// If no none playing pool members can be index choose the oldest // If no none playing pool members can be indexed choose the oldest
if (index == -1) if (index == -1)
{ {
TRACELOG(LOG_WARNING, "SOUND: Buffer pool is already full, count: %i", AUDIO.MultiChannel.poolCounter); TRACELOG(LOG_WARNING, "SOUND: Buffer pool is already full, count: %i", AUDIO.MultiChannel.poolCounter);
@ -1073,7 +1113,7 @@ void PlaySoundMulti(Sound sound)
if (oldIndex == -1) if (oldIndex == -1)
{ {
// Shouldn't be able to get here... but just in case something odd happens! // Shouldn't be able to get here... but just in case something odd happens!
TRACELOG(LOG_WARNING, "SOUND: Buffer pool could not determine oldest buffer not playing sound"); TRACELOG(LOG_WARNING, "SOUND: Buffer pool could not determine the oldest buffer not playing sound");
return; return;
} }
@ -1316,23 +1356,6 @@ Music LoadMusicStream(const char *fileName)
} }
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac"))
{
music.ctxType = MUSIC_AUDIO_FLAC;
music.ctxData = drflac_open_file(fileName, NULL);
if (music.ctxData != NULL)
{
drflac *ctxFlac = (drflac *)music.ctxData;
music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount;
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
#endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (IsFileExtension(fileName, ".mp3")) else if (IsFileExtension(fileName, ".mp3"))
{ {
@ -1351,6 +1374,46 @@ Music LoadMusicStream(const char *fileName)
} }
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_QOA)
else if (IsFileExtension(fileName, ".qoa"))
{
qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc));
// TODO: QOA stream support: Init context from file
int result = 0;
music.ctxType = MUSIC_AUDIO_QOA;
music.ctxData = ctxQoa;
if (result > 0)
{
music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels);
// TODO: Read next frame(s) from QOA stream
//music.frameCount = qoa_decode_frame(const unsigned char *bytes, unsigned int size, ctxQoa, short *sample_data, unsigned int *frame_len);
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac"))
{
music.ctxType = MUSIC_AUDIO_FLAC;
music.ctxData = drflac_open_file(fileName, NULL);
if (music.ctxData != NULL)
{
drflac *ctxFlac = (drflac *)music.ctxData;
music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount;
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
#endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
else if (IsFileExtension(fileName, ".xm")) else if (IsFileExtension(fileName, ".xm"))
{ {
@ -1408,12 +1471,15 @@ Music LoadMusicStream(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL);
#endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_QOA)
else if (music.ctxType == MUSIC_AUDIO_QOA) { /*TODO: Release QOA context data*/ RL_FREE(music.ctxData); }
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL);
#endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
#endif #endif
@ -1467,18 +1533,23 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
} }
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (strcmp(fileType, ".flac") == 0) else if (strcmp(fileType, ".ogg") == 0)
{ {
music.ctxType = MUSIC_AUDIO_FLAC; // Open ogg audio stream
music.ctxData = drflac_open_memory((const void*)data, dataSize, NULL); music.ctxType = MUSIC_AUDIO_OGG;
//music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL);
music.ctxData = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL);
if (music.ctxData != NULL) if (music.ctxData != NULL)
{ {
drflac *ctxFlac = (drflac *)music.ctxData; stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info
music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); // OGG bit rate defaults to 16 bit, it's enough for compressed format
music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount; music.stream = LoadAudioStream(info.sample_rate, 16, info.channels);
// WARNING: It seems this function returns length in frames, not samples, so we multiply by channels
music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData);
music.looping = true; // Looping enabled by default music.looping = true; // Looping enabled by default
musicLoaded = true; musicLoaded = true;
} }
@ -1502,23 +1573,41 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
} }
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_QOA)
else if (strcmp(fileType, ".ogg") == 0) else if (strcmp(fileType, ".qoa") == 0)
{ {
// Open ogg audio stream qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc));
music.ctxType = MUSIC_AUDIO_OGG;
//music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL); // TODO: Init QOA context data
music.ctxData = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL); int result = 0;
music.ctxType = MUSIC_AUDIO_QOA;
music.ctxData = ctxQoa;
if (result > 0)
{
music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels);
// TODO: Read next frame(s) from QOA stream
//music.frameCount = qoa_decode_frame(const unsigned char *bytes, unsigned int size, ctxQoa, short *sample_data, unsigned int *frame_len);
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (strcmp(fileType, ".flac") == 0)
{
music.ctxType = MUSIC_AUDIO_FLAC;
music.ctxData = drflac_open_memory((const void*)data, dataSize, NULL);
if (music.ctxData != NULL) if (music.ctxData != NULL)
{ {
stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info drflac *ctxFlac = (drflac *)music.ctxData;
// OGG bit rate defaults to 16 bit, it's enough for compressed format music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
music.stream = LoadAudioStream(info.sample_rate, 16, info.channels); music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount;
// WARNING: It seems this function returns length in frames, not samples, so we multiply by channels
music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData);
music.looping = true; // Looping enabled by default music.looping = true; // Looping enabled by default
musicLoaded = true; musicLoaded = true;
} }
@ -1593,14 +1682,17 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
#if defined(SUPPORT_FILEFORMAT_WAV) #if defined(SUPPORT_FILEFORMAT_WAV)
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData); else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_QOA)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); else if (music.ctxType == MUSIC_AUDIO_QOA) { /*TODO: Release QOA context*/ RL_FREE(music.ctxData); }
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
@ -1645,12 +1737,15 @@ void UnloadMusicStream(Music music)
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL);
#endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_QOA)
else if (music.ctxType == MUSIC_AUDIO_QOA) { /*TODO: Release QOA context*/ RL_FREE(music.ctxData); }
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL);
#endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
#endif #endif
@ -1700,12 +1795,15 @@ void StopMusicStream(Music music)
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break; case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: drflac__seek_to_first_frame((drflac *)music.ctxData); break;
#endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
case MUSIC_AUDIO_MP3: drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); break; case MUSIC_AUDIO_MP3: drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_QOA)
case MUSIC_AUDIO_QOA: /*TODO: Restart QOA context to beginning*/ break;
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: drflac__seek_to_first_frame((drflac *)music.ctxData); break;
#endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music.ctxData); break; case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music.ctxData); break;
#endif #endif
@ -1732,11 +1830,14 @@ void SeekMusicStream(Music music, float position)
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_frame((stb_vorbis *)music.ctxData, positionInFrames); break; case MUSIC_AUDIO_OGG: stb_vorbis_seek_frame((stb_vorbis *)music.ctxData, positionInFrames); break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break;
#endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break; case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break;
#endif
#if defined(SUPPORT_FILEFORMAT_QOA)
case MUSIC_AUDIO_QOA: /*TODO: Seek to specific QOA frame*/ break;
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break;
#endif #endif
default: break; default: break;
} }
@ -1754,6 +1855,7 @@ void UpdateMusicStream(Music music)
// On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in
int frameSize = music.stream.channels*music.stream.sampleSize/8; int frameSize = music.stream.channels*music.stream.sampleSize/8;
unsigned int pcmSize = subBufferSizeInFrames*frameSize; unsigned int pcmSize = subBufferSizeInFrames*frameSize;
if (AUDIO.System.pcmBufferSize < pcmSize) if (AUDIO.System.pcmBufferSize < pcmSize)
{ {
RL_FREE(AUDIO.System.pcmBuffer); RL_FREE(AUDIO.System.pcmBuffer);
@ -1815,19 +1917,6 @@ void UpdateMusicStream(Music music)
} }
} break; } break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC:
{
while (true)
{
int frameCountRed = drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize));
frameCountRedTotal += frameCountRed;
frameCountStillNeeded -= frameCountRed;
if (frameCountStillNeeded == 0) break;
else drflac__seek_to_first_frame((drflac *)music.ctxData);
}
} break;
#endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
case MUSIC_AUDIO_MP3: case MUSIC_AUDIO_MP3:
{ {
@ -1841,6 +1930,25 @@ void UpdateMusicStream(Music music)
} }
} break; } break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_QOA)
case MUSIC_AUDIO_QOA:
{
// TODO: Read QOA required framecount to fill buffer to keep music playing
} break;
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC:
{
while (true)
{
int frameCountRed = drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize));
frameCountRedTotal += frameCountRed;
frameCountStillNeeded -= frameCountRed;
if (frameCountStillNeeded == 0) break;
else drflac__seek_to_first_frame((drflac *)music.ctxData);
}
} break;
#endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
case MUSIC_MODULE_XM: case MUSIC_MODULE_XM:
{ {
@ -1999,8 +2107,8 @@ void UnloadAudioStream(AudioStream stream)
} }
// Update audio stream buffers with data // Update audio stream buffers with data
// NOTE 1: Only updates one buffer of the stream source: unqueue -> update -> queue // NOTE 1: Only updates one buffer of the stream source: dequeue -> update -> queue
// NOTE 2: To unqueue a buffer it needs to be processed: IsAudioStreamProcessed() // NOTE 2: To dequeue a buffer it needs to be processed: IsAudioStreamProcessed()
void UpdateAudioStream(AudioStream stream, const void *data, int frameCount) void UpdateAudioStream(AudioStream stream, const void *data, int frameCount)
{ {
if (stream.buffer != NULL) if (stream.buffer != NULL)
@ -2197,7 +2305,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
if (currentSubBufferIndex > 1) return 0; if (currentSubBufferIndex > 1) return 0;
// Another thread can update the processed state of buffers so // Another thread can update the processed state of buffers, so
// we just take a copy here to try and avoid potential synchronization problems // we just take a copy here to try and avoid potential synchronization problems
bool isSubBufferProcessed[2] = { 0 }; bool isSubBufferProcessed[2] = { 0 };
isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0]; isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0];
@ -2211,7 +2319,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
{ {
// We break from this loop differently depending on the buffer's usage // We break from this loop differently depending on the buffer's usage
// - For static buffers, we simply fill as much data as we can // - For static buffers, we simply fill as much data as we can
// - For streaming buffers we only fill the halves of the buffer that are processed // - For streaming buffers we only fill half of the buffer that are processed
// Unprocessed halves must keep their audio data in-tact // Unprocessed halves must keep their audio data in-tact
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
{ {
@ -2268,7 +2376,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
// For static buffers we can fill the remaining frames with silence for safety, but we don't want // For static buffers we can fill the remaining frames with silence for safety, but we don't want
// to report those frames as "read". The reason for this is that the caller uses the return value // to report those frames as "read". The reason for this is that the caller uses the return value
// to know whether or not a non-looping sound has finished playback. // to know whether a non-looping sound has finished playback.
if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining; if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining;
} }

View File

@ -216,7 +216,7 @@ typedef struct Vector4 {
// Quaternion, 4 components (Vector4 alias) // Quaternion, 4 components (Vector4 alias)
typedef Vector4 Quaternion; typedef Vector4 Quaternion;
// Matrix, 4x4 components, column major, OpenGL style, right handed // Matrix, 4x4 components, column major, OpenGL style, right-handed
typedef struct Matrix { typedef struct Matrix {
float m0, m4, m8, m12; // Matrix first row (4 components) float m0, m4, m8, m12; // Matrix first row (4 components)
float m1, m5, m9, m13; // Matrix second row (4 components) float m1, m5, m9, m13; // Matrix second row (4 components)
@ -413,8 +413,8 @@ typedef struct Ray {
// RayCollision, ray hit information // RayCollision, ray hit information
typedef struct RayCollision { typedef struct RayCollision {
bool hit; // Did the ray hit something? bool hit; // Did the ray hit something?
float distance; // Distance to nearest hit float distance; // Distance to the nearest hit
Vector3 point; // Point of nearest hit Vector3 point; // Point of the nearest hit
Vector3 normal; // Surface normal of hit Vector3 normal; // Surface normal of hit
} RayCollision; } RayCollision;
@ -681,7 +681,7 @@ typedef enum {
MOUSE_CURSOR_RESIZE_NS = 6, // Vertical resize/move arrow shape MOUSE_CURSOR_RESIZE_NS = 6, // Vertical resize/move arrow shape
MOUSE_CURSOR_RESIZE_NWSE = 7, // Top-left to bottom-right diagonal resize/move arrow shape MOUSE_CURSOR_RESIZE_NWSE = 7, // Top-left to bottom-right diagonal resize/move arrow shape
MOUSE_CURSOR_RESIZE_NESW = 8, // The top-right to bottom-left diagonal resize/move arrow shape MOUSE_CURSOR_RESIZE_NESW = 8, // The top-right to bottom-left diagonal resize/move arrow shape
MOUSE_CURSOR_RESIZE_ALL = 9, // The omni-directional resize/move cursor shape MOUSE_CURSOR_RESIZE_ALL = 9, // The omnidirectional resize/move cursor shape
MOUSE_CURSOR_NOT_ALLOWED = 10 // The operation-not-allowed shape MOUSE_CURSOR_NOT_ALLOWED = 10 // The operation-not-allowed shape
} MouseCursor; } MouseCursor;
@ -839,10 +839,10 @@ typedef enum {
typedef enum { typedef enum {
CUBEMAP_LAYOUT_AUTO_DETECT = 0, // Automatically detect layout type CUBEMAP_LAYOUT_AUTO_DETECT = 0, // Automatically detect layout type
CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces
CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by an horizontal line with faces CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by a horizontal line with faces
CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces
CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces
CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirectangular map) CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirrectangular map)
} CubemapLayout; } CubemapLayout;
// Font type, defines generation method // Font type, defines generation method
@ -903,7 +903,7 @@ typedef enum {
} NPatchLayout; } NPatchLayout;
// Callbacks to hook some internal functions // Callbacks to hook some internal functions
// WARNING: This callbacks are intended for advance users // WARNING: These callbacks are intended for advance users
typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, unsigned int *bytesRead); // FileIO: Load binary data typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, unsigned int *bytesRead); // FileIO: Load binary data
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, unsigned int bytesToWrite); // FileIO: Save binary data typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, unsigned int bytesToWrite); // FileIO: Save binary data
@ -1222,7 +1222,7 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Image loading functions // Image loading functions
// NOTE: This functions do not require GPU access // NOTE: These functions do not require GPU access
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)

View File

@ -912,7 +912,7 @@ RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
{ {
Vector3 result = { 0 }; Vector3 result = { 0 };
// Calculate unproject matrix (multiply view matrix by projection matrix) and invert it // Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it
Matrix matViewProj = { // MatrixMultiply(view, projection); Matrix matViewProj = { // MatrixMultiply(view, projection);
view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12, view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12,
view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13, view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13,
@ -975,7 +975,7 @@ RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
// Create quaternion from source point // Create quaternion from source point
Quaternion quat = { source.x, source.y, source.z, 1.0f }; Quaternion quat = { source.x, source.y, source.z, 1.0f };
// Multiply quat point by unproject matrix // Multiply quat point by unprojecte matrix
Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv) Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv)
matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w, matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w,
matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w, matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w,

View File

@ -370,7 +370,7 @@ void CameraRoll(Camera3D *camera, float angle)
// Moves camera slightly to simulate a walking motion // Moves camera slightly to simulate a walking motion
// Note: Only active if camera->swingCounter > 0 // Note: Only active if camera->swingCounter > 0
void CameraViewBobbing(Camera3D* camera) void CameraViewBobbing(Camera3D *camera)
{ {
if (camera->swingCounter > 0) if (camera->swingCounter > 0)
{ {
@ -409,19 +409,10 @@ Matrix GetCameraProjectionMatrix(Camera3D *camera, float aspect)
#ifndef CAMERA_STANDALONE #ifndef CAMERA_STANDALONE
static int init_frames = 3; // TODO review and remove
// Update camera position for selected mode // Update camera position for selected mode
// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM // Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM
void UpdateCamera(Camera3D *camera, int mode) void UpdateCamera(Camera3D *camera, int mode)
{ {
// Avoid inital mouse "jump"
if (init_frames > 0) {
SetMousePosition(0, 0);
init_frames--;
return;
}
Vector2 mousePositionDelta = GetMouseDelta(); Vector2 mousePositionDelta = GetMouseDelta();
bool moveInWorldPlane = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON; bool moveInWorldPlane = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON;
@ -457,8 +448,6 @@ void UpdateCamera(Camera3D *camera, int mode)
// Apply view bobbing when moving around (per default only active in CAMERA_FIRST_PERSON) // Apply view bobbing when moving around (per default only active in CAMERA_FIRST_PERSON)
if (mode == CAMERA_FIRST_PERSON && (IsKeyDown(KEY_W) || IsKeyDown(KEY_A) || IsKeyDown(KEY_S) || IsKeyDown(KEY_D))) CameraViewBobbing(camera); if (mode == CAMERA_FIRST_PERSON && (IsKeyDown(KEY_W) || IsKeyDown(KEY_A) || IsKeyDown(KEY_S) || IsKeyDown(KEY_D))) CameraViewBobbing(camera);
} }
#endif // !CAMERA_STANDALONE #endif // !CAMERA_STANDALONE
#endif // CAMERA_IMPLEMENTATION #endif // CAMERA_IMPLEMENTATION

View File

@ -242,6 +242,7 @@
#include <unistd.h> // Required for: usleep() #include <unistd.h> // Required for: usleep()
//#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition
void *glfwGetCocoaWindow(GLFWwindow* handle);
#include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow() #include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow()
#endif #endif
@ -864,7 +865,7 @@ void InitWindow(int width, int height, const char *title)
LoadFontDefault(); LoadFontDefault();
#if defined(SUPPORT_MODULE_RSHAPES) #if defined(SUPPORT_MODULE_RSHAPES)
Rectangle rec = GetFontDefault().recs[95]; Rectangle rec = GetFontDefault().recs[95];
// NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); // WARNING: Module required: rshapes SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); // WARNING: Module required: rshapes
#endif #endif
#else #else
@ -1317,7 +1318,7 @@ void MaximizeWindow(void)
void MinimizeWindow(void) void MinimizeWindow(void)
{ {
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
// NOTE: Following function launches callback that sets appropiate flag! // NOTE: Following function launches callback that sets appropriate flag!
glfwIconifyWindow(CORE.Window.handle); glfwIconifyWindow(CORE.Window.handle);
#endif #endif
} }
@ -1416,13 +1417,13 @@ void SetWindowState(unsigned int flags)
// State change: FLAG_WINDOW_TRANSPARENT // State change: FLAG_WINDOW_TRANSPARENT
if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) != (flags & FLAG_WINDOW_TRANSPARENT)) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0)) if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) != (flags & FLAG_WINDOW_TRANSPARENT)) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0))
{ {
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only by configured before window initialization"); TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
} }
// State change: FLAG_WINDOW_HIGHDPI // State change: FLAG_WINDOW_HIGHDPI
if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) != (flags & FLAG_WINDOW_HIGHDPI)) && ((flags & FLAG_WINDOW_HIGHDPI) > 0)) if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) != (flags & FLAG_WINDOW_HIGHDPI)) && ((flags & FLAG_WINDOW_HIGHDPI) > 0))
{ {
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization"); TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
} }
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
@ -1435,13 +1436,13 @@ void SetWindowState(unsigned int flags)
// State change: FLAG_MSAA_4X_HINT // State change: FLAG_MSAA_4X_HINT
if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0)) if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0))
{ {
TRACELOG(LOG_WARNING, "WINDOW: MSAA can only by configured before window initialization"); TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
} }
// State change: FLAG_INTERLACED_HINT // State change: FLAG_INTERLACED_HINT
if (((CORE.Window.flags & FLAG_INTERLACED_HINT) != (flags & FLAG_INTERLACED_HINT)) && ((flags & FLAG_INTERLACED_HINT) > 0)) if (((CORE.Window.flags & FLAG_INTERLACED_HINT) != (flags & FLAG_INTERLACED_HINT)) && ((flags & FLAG_INTERLACED_HINT) > 0))
{ {
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only by configured before window initialization"); TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
} }
#endif #endif
} }
@ -1524,13 +1525,13 @@ void ClearWindowState(unsigned int flags)
// State change: FLAG_WINDOW_TRANSPARENT // State change: FLAG_WINDOW_TRANSPARENT
if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0)) if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0))
{ {
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only by configured before window initialization"); TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
} }
// State change: FLAG_WINDOW_HIGHDPI // State change: FLAG_WINDOW_HIGHDPI
if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) && ((flags & FLAG_WINDOW_HIGHDPI) > 0)) if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) && ((flags & FLAG_WINDOW_HIGHDPI) > 0))
{ {
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization"); TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
} }
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
@ -1543,13 +1544,13 @@ void ClearWindowState(unsigned int flags)
// State change: FLAG_MSAA_4X_HINT // State change: FLAG_MSAA_4X_HINT
if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0)) if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0))
{ {
TRACELOG(LOG_WARNING, "WINDOW: MSAA can only by configured before window initialization"); TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
} }
// State change: FLAG_INTERLACED_HINT // State change: FLAG_INTERLACED_HINT
if (((CORE.Window.flags & FLAG_INTERLACED_HINT) > 0) && ((flags & FLAG_INTERLACED_HINT) > 0)) if (((CORE.Window.flags & FLAG_INTERLACED_HINT) > 0) && ((flags & FLAG_INTERLACED_HINT) > 0))
{ {
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only by configured before window initialization"); TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
} }
#endif #endif
} }
@ -1677,7 +1678,7 @@ void *GetWindowHandle(void)
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
// NOTE: Returned handle is: (objc_object *) // NOTE: Returned handle is: (objc_object *)
return NULL; // TODO: return (void *)glfwGetCocoaWindow(window); return (void *)glfwGetCocoaWindow(CORE.Window.handle);
#endif #endif
return NULL; return NULL;
@ -2481,10 +2482,10 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
// All locations reseted to -1 (no location) // All locations reset to -1 (no location)
for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
// Get handles to GLSL input attibute locations // Get handles to GLSL input attribute locations
shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
@ -2552,7 +2553,7 @@ void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniform
{ {
rlEnableShader(shader.id); rlEnableShader(shader.id);
rlSetUniform(locIndex, value, uniformType, count); rlSetUniform(locIndex, value, uniformType, count);
//rlDisableShader(); // Avoid reseting current shader program, in case other uniforms are set //rlDisableShader(); // Avoid resetting current shader program, in case other uniforms are set
} }
} }
@ -2617,7 +2618,7 @@ Ray GetMouseRay(Vector2 mouse, Camera camera)
Vector3 farPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); Vector3 farPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
// Unproject the mouse cursor in the near plane. // Unproject the mouse cursor in the near plane.
// We need this as the source position because orthographic projects, compared to perspect doesn't have a // We need this as the source position because orthographic projects, compared to perspective doesn't have a
// convergence point, meaning that the "eye" of the camera is more like a plane than a point. // convergence point, meaning that the "eye" of the camera is more like a plane than a point.
Vector3 cameraPlanePointerPos = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView); Vector3 cameraPlanePointerPos = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView);
@ -2807,7 +2808,7 @@ double GetTime(void)
// Setup window configuration flags (view FLAGS) // Setup window configuration flags (view FLAGS)
// NOTE: This function is expected to be called before window creation, // NOTE: This function is expected to be called before window creation,
// because it setups some flags for the window creation process. // because it sets up some flags for the window creation process.
// To configure window states after creation, just use SetWindowState() // To configure window states after creation, just use SetWindowState()
void SetConfigFlags(unsigned int flags) void SetConfigFlags(unsigned int flags)
{ {
@ -3032,7 +3033,7 @@ const char *GetDirectoryPath(const char *filePath)
if (filePath[1] != ':' && filePath[0] != '\\' && filePath[0] != '/') if (filePath[1] != ':' && filePath[0] != '\\' && filePath[0] != '/')
{ {
// For security, we set starting path to current directory, // For security, we set starting path to current directory,
// obtained path will be concated to this // obtained path will be concatenated to this
dirPath[0] = '.'; dirPath[0] = '.';
dirPath[1] = '/'; dirPath[1] = '/';
} }
@ -3928,7 +3929,7 @@ static bool InitGraphicsDevice(int width, int height)
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
// NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars... // NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars...
// ...in top-down or left-right to match display aspect ratio (no weird scalings) // ...in top-down or left-right to match display aspect ratio (no weird scaling)
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
glfwSetErrorCallback(ErrorCallback); glfwSetErrorCallback(ErrorCallback);
@ -4099,8 +4100,8 @@ static bool InitGraphicsDevice(int width, int height)
// remember center for switchinging from fullscreen to window // remember center for switchinging from fullscreen to window
if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width)) if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
{ {
// If screen width/height equal to the dislpay, we can't calclulate the window pos for toggling fullscreened/windowed. // If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed.
// Toggling fullscreened/windowed with pos(0, 0) can cause problems in some platforms, such as X11. // Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11.
CORE.Window.position.x = CORE.Window.display.width/4; CORE.Window.position.x = CORE.Window.display.width/4;
CORE.Window.position.y = CORE.Window.display.height/4; CORE.Window.position.y = CORE.Window.display.height/4;
} }
@ -4137,7 +4138,7 @@ static bool InitGraphicsDevice(int width, int height)
// framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched // framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched
// by the sides to fit all monitor space... // by the sides to fit all monitor space...
// Try to setup the most appropiate fullscreen framebuffer for the requested screenWidth/screenHeight // Try to setup the most appropriate fullscreen framebuffer for the requested screenWidth/screenHeight
// It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset) // It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset)
// Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale // Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale
// TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed... // TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed...
@ -4204,7 +4205,7 @@ static bool InitGraphicsDevice(int width, int height)
// NOTE: V-Sync can be enabled by graphic driver configuration // NOTE: V-Sync can be enabled by graphic driver configuration
if (CORE.Window.flags & FLAG_VSYNC_HINT) if (CORE.Window.flags & FLAG_VSYNC_HINT)
{ {
// WARNING: It seems to hits a critical render path in Intel HD Graphics // WARNING: It seems to hit a critical render path in Intel HD Graphics
glfwSwapInterval(1); glfwSwapInterval(1);
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC"); TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC");
} }
@ -4215,12 +4216,12 @@ static bool InitGraphicsDevice(int width, int height)
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
{ {
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling.
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE); // Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
#if !defined(__APPLE__) #if !defined(__APPLE__)
glfwGetFramebufferSize(CORE.Window.handle, &fbWidth, &fbHeight); glfwGetFramebufferSize(CORE.Window.handle, &fbWidth, &fbHeight);
// Screen scaling matrix is required in case desired screen area is different than display area // Screen scaling matrix is required in case desired screen area is different from display area
CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f); CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f);
// Mouse input scaling for the new screen size // Mouse input scaling for the new screen size
@ -4818,7 +4819,7 @@ static void InitTimer(void)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could // NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop // take longer than expected... for that reason we use the busy wait loop
// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected // Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timming on Win32! // Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
void WaitTime(double seconds) void WaitTime(double seconds)
{ {
#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP) #if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
@ -5413,7 +5414,7 @@ static void CharCallback(GLFWwindow *window, unsigned int key)
//TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key); //TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key);
// NOTE: Registers any key down considering OS keyboard layout but // NOTE: Registers any key down considering OS keyboard layout but
// do not detects action events, those should be managed by user... // does not detect action events, those should be managed by user...
// Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
// Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char
@ -5456,7 +5457,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight(); gestureEvent.position[0].y /= (float)GetScreenHeight();
// Gesture data is sent to gestures system for processing // Gesture data is sent to gestures-system for processing
ProcessGestureEvent(gestureEvent); ProcessGestureEvent(gestureEvent);
#endif #endif
} }
@ -5487,7 +5488,7 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight(); gestureEvent.position[0].y /= (float)GetScreenHeight();
// Gesture data is sent to gestures system for processing // Gesture data is sent to gestures-system for processing
ProcessGestureEvent(gestureEvent); ProcessGestureEvent(gestureEvent);
#endif #endif
} }

View File

@ -249,7 +249,7 @@ static double rgGetCurrentTime(void);
// Module Functions Definition // Module Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Enable only desired getures to be detected // Enable only desired gestures to be detected
void SetGesturesEnabled(unsigned int flags) void SetGesturesEnabled(unsigned int flags)
{ {
GESTURES.enabledFlags = flags; GESTURES.enabledFlags = flags;
@ -300,7 +300,7 @@ void ProcessGestureEvent(GestureEvent event)
{ {
if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0]; if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0];
// NOTE: GESTURES.Drag.intensity dependend on the resolution of the screen // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen
GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.timeDuration)); GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.timeDuration));
@ -472,7 +472,7 @@ Vector2 GetGestureDragVector(void)
} }
// Get drag angle // Get drag angle
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise // NOTE: Angle in degrees, horizontal-right is 0, counterclockwise
float GetGestureDragAngle(void) float GetGestureDragAngle(void)
{ {
// NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP
@ -488,8 +488,8 @@ Vector2 GetGesturePinchVector(void)
return GESTURES.Pinch.vector; return GESTURES.Pinch.vector;
} }
// Get angle beween two pinch points // Get angle between two pinch points
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise // NOTE: Angle in degrees, horizontal-right is 0, counterclockwise
float GetGesturePinchAngle(void) float GetGesturePinchAngle(void)
{ {
// NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE

View File

@ -502,7 +502,7 @@ typedef enum {
} rlShaderAttributeDataType; } rlShaderAttributeDataType;
// Framebuffer attachment type // Framebuffer attachment type
// NOTE: By default up to 8 color channels defined but it can be more // NOTE: By default up to 8 color channels defined, but it can be more
typedef enum { typedef enum {
RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0 RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0
RL_ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachment type: color 1 RL_ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachment type: color 1

View File

@ -1125,7 +1125,7 @@ void UnloadModel(Model model)
// Unload materials maps // Unload materials maps
// NOTE: As the user could be sharing shaders and textures between models, // NOTE: As the user could be sharing shaders and textures between models,
// we don't unload the material but just free it's maps, // we don't unload the material but just free its maps,
// the user is responsible for freeing models shaders and textures // the user is responsible for freeing models shaders and textures
for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps); for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
@ -1146,7 +1146,7 @@ void UnloadModelKeepMeshes(Model model)
{ {
// Unload materials maps // Unload materials maps
// NOTE: As the user could be sharing shaders and textures between models, // NOTE: As the user could be sharing shaders and textures between models,
// we don't unload the material but just free it's maps, // we don't unload the material but just free its maps,
// the user is responsible for freeing models shaders and textures // the user is responsible for freeing models shaders and textures
for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps); for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
@ -1230,7 +1230,7 @@ void UploadMesh(Mesh *mesh, bool dynamic)
rlEnableVertexAttribute(1); rlEnableVertexAttribute(1);
// WARNING: When setting default vertex attribute values, the values for each generic vertex attribute // WARNING: When setting default vertex attribute values, the values for each generic vertex attribute
// is part of current state and it is maintained even if a different program object is used // is part of current state, and it is maintained even if a different program object is used
if (mesh->normals != NULL) if (mesh->normals != NULL)
{ {
@ -1383,7 +1383,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
} }
// Get a copy of current matrices to work with, // Get a copy of current matrices to work with,
// just in case stereo render is required and we need to modify them // just in case stereo render is required, and we need to modify them
// NOTE: At this point the modelview matrix just contains the view matrix (camera) // NOTE: At this point the modelview matrix just contains the view matrix (camera)
// That's because BeginMode3D() sets it and there is no model-drawing function // That's because BeginMode3D() sets it and there is no model-drawing function
// that modifies it, all use rlPushMatrix() and rlPopMatrix() // that modifies it, all use rlPushMatrix() and rlPopMatrix()
@ -1396,7 +1396,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView); if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection); if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
// Model transformation matrix is send to shader uniform location: SHADER_LOC_MATRIX_MODEL // Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL
if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transform); if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transform);
// Accumulate several model transformations: // Accumulate several model transformations:
@ -1517,7 +1517,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
else rlDrawVertexArray(0, mesh.vertexCount); else rlDrawVertexArray(0, mesh.vertexCount);
} }
// Unbind all binded texture maps // Unbind all bound texture maps
for (int i = 0; i < MAX_MATERIAL_MAPS; i++) for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
{ {
if (material.maps[i].texture.id > 0) if (material.maps[i].texture.id > 0)
@ -1587,7 +1587,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
} }
// Get a copy of current matrices to work with, // Get a copy of current matrices to work with,
// just in case stereo render is required and we need to modify them // just in case stereo render is required, and we need to modify them
// NOTE: At this point the modelview matrix just contains the view matrix (camera) // NOTE: At this point the modelview matrix just contains the view matrix (camera)
// That's because BeginMode3D() sets it and there is no model-drawing function // That's because BeginMode3D() sets it and there is no model-drawing function
// that modifies it, all use rlPushMatrix() and rlPopMatrix() // that modifies it, all use rlPushMatrix() and rlPopMatrix()
@ -1738,7 +1738,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances); else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances);
} }
// Unbind all binded texture maps // Unbind all bound texture maps
for (int i = 0; i < MAX_MATERIAL_MAPS; i++) for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
{ {
if (material.maps[i].texture.id > 0) if (material.maps[i].texture.id > 0)
@ -1875,34 +1875,34 @@ bool ExportMesh(Mesh mesh, const char *fileName)
// Process obj materials // Process obj materials
static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount) static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount)
{ {
// Init model materials // Init model materials
for (int m = 0; m < materialCount; m++) for (int m = 0; m < materialCount; m++)
{ {
// Init material to default // Init material to default
// NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE
rayMaterials[m] = LoadMaterialDefault(); rayMaterials[m] = LoadMaterialDefault();
// Get default texture, in case no texture is defined // Get default texture, in case no texture is defined
// NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
if (materials[m].diffuse_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd if (materials[m].diffuse_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd
rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3]; rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3];
rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
if (materials[m].specular_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks if (materials[m].specular_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks
rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2] * 255.0f), 255 }; //float specular[3]; rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2] * 255.0f), 255 }; //float specular[3];
rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f;
if (materials[m].bump_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump if (materials[m].bump_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump
rayMaterials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE; rayMaterials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE;
rayMaterials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess; rayMaterials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess;
rayMaterials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2] * 255.0f), 255 }; //float emission[3]; rayMaterials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2] * 255.0f), 255 }; //float emission[3];
if (materials[m].displacement_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp if (materials[m].displacement_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp
} }
} }
#endif #endif
@ -2559,7 +2559,7 @@ Mesh GenMeshSphere(float radius, int rings, int slices)
return mesh; return mesh;
} }
// Generate hemi-sphere mesh (half sphere, no bottom cap) // Generate hemisphere mesh (half sphere, no bottom cap)
Mesh GenMeshHemiSphere(float radius, int rings, int slices) Mesh GenMeshHemiSphere(float radius, int rings, int slices)
{ {
Mesh mesh = { 0 }; Mesh mesh = { 0 };
@ -3242,7 +3242,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
} }
} }
// Move data from mapVertices temp arays to vertices float array // Move data from mapVertices temp arrays to vertices float array
mesh.vertexCount = vCounter; mesh.vertexCount = vCounter;
mesh.triangleCount = vCounter/3; mesh.triangleCount = vCounter/3;
@ -3742,7 +3742,7 @@ RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
// NOTE: We use an additional .01 to fix numerical errors // NOTE: We use an additional .01 to fix numerical errors
collision.normal = Vector3Scale(collision.normal, 2.01f); collision.normal = Vector3Scale(collision.normal, 2.01f);
collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min)); collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min));
// The relevant elemets of the vector are now slightly larger than 1.0f (or smaller than -1.0f) // The relevant elements of the vector are now slightly larger than 1.0f (or smaller than -1.0f)
// and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal! // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal!
collision.normal.x = (float)((int)collision.normal.x); collision.normal.x = (float)((int)collision.normal.x);
collision.normal.y = (float)((int)collision.normal.y); collision.normal.y = (float)((int)collision.normal.y);
@ -3842,7 +3842,7 @@ RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3
// Calculate u parameter and test bound // Calculate u parameter and test bound
u = Vector3DotProduct(tv, p)*invDet; u = Vector3DotProduct(tv, p)*invDet;
// The intersection lies outside of the triangle // The intersection lies outside the triangle
if ((u < 0.0f) || (u > 1.0f)) return collision; if ((u < 0.0f) || (u > 1.0f)) return collision;
// Prepare to test v parameter // Prepare to test v parameter
@ -3851,7 +3851,7 @@ RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3
// Calculate V parameter and test bound // Calculate V parameter and test bound
v = Vector3DotProduct(ray.direction, q)*invDet; v = Vector3DotProduct(ray.direction, q)*invDet;
// The intersection lies outside of the triangle // The intersection lies outside the triangle
if ((v < 0.0f) || ((u + v) > 1.0f)) return collision; if ((v < 0.0f) || ((u + v) > 1.0f)) return collision;
t = Vector3DotProduct(edge2, q)*invDet; t = Vector3DotProduct(edge2, q)*invDet;
@ -4041,7 +4041,7 @@ static Model LoadOBJ(const char *fileName)
} }
// Init model materials // Init model materials
ProcessMaterialsOBJ(model.materials, materials, materialCount); ProcessMaterialsOBJ(model.materials, materials, materialCount);
tinyobj_attrib_free(&attrib); tinyobj_attrib_free(&attrib);
tinyobj_shapes_free(meshes, meshCount); tinyobj_shapes_free(meshes, meshCount);
@ -4671,7 +4671,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
{ {
Image image = { 0 }; Image image = { 0 };
if (cgltfImage->uri != NULL) // Check if image data is provided as a uri (base64 or path) if (cgltfImage->uri != NULL) // Check if image data is provided as an uri (base64 or path)
{ {
if ((strlen(cgltfImage->uri) > 5) && if ((strlen(cgltfImage->uri) > 5) &&
(cgltfImage->uri[0] == 'd') && (cgltfImage->uri[0] == 'd') &&
@ -4959,7 +4959,7 @@ static Model LoadGLTF(const char *fileName)
for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++) for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++)
{ {
// Check the different attributes for every pimitive // Check the different attributes for every primitive
if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position) // POSITION if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position) // POSITION
{ {
cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data; cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
@ -5110,7 +5110,7 @@ static Model LoadGLTF(const char *fileName)
{ {
// The primitive actually keeps the pointer to the corresponding material, // The primitive actually keeps the pointer to the corresponding material,
// raylib instead assigns to the mesh the by its index, as loaded in model.materials array // raylib instead assigns to the mesh the by its index, as loaded in model.materials array
// To get the index, we check if material pointers match and we assign the corresponding index, // To get the index, we check if material pointers match, and we assign the corresponding index,
// skipping index 0, the default material // skipping index 0, the default material
if (&data->materials[m] == data->meshes[i].primitives[p].material) if (&data->materials[m] == data->meshes[i].primitives[p].material)
{ {
@ -5613,7 +5613,7 @@ static Model LoadM3D(const char *fileName)
// Materials are grouped together // Materials are grouped together
if (mi != m3d->face[i].materialid) if (mi != m3d->face[i].materialid)
{ {
// there should be only one material switch per material kind, but be bulletproof for unoptimal model files // there should be only one material switch per material kind, but be bulletproof for non-optimal model files
if (k + 1 >= model.meshCount) if (k + 1 >= model.meshCount)
{ {
model.meshCount++; model.meshCount++;
@ -5633,8 +5633,9 @@ static Model LoadM3D(const char *fileName)
model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float)); model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float));
model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
// If color map is provided, we allocate storage for vertex colors // If no map is provided, we allocate storage for vertex colors
if (m3d->cmap != NULL) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); // M3D specs only consider vertex colors if no material is provided
if (mi != M3D_UNDEF) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
if (m3d->numbone && m3d->numskin) if (m3d->numbone && m3d->numskin)
{ {
@ -5838,7 +5839,7 @@ static Model LoadM3D(const char *fileName)
} }
// Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets // Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets
// called, but not before, however DrawMesh uses these if they exists (so not good if they are left empty). // called, but not before, however DrawMesh uses these if they exist (so not good if they are left empty).
if (m3d->numbone && m3d->numskin) if (m3d->numbone && m3d->numskin)
{ {
for(i = 0; i < model.meshCount; i++) for(i = 0; i < model.meshCount; i++)

View File

@ -978,7 +978,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
rlSetTexture(texShapes.id); rlSetTexture(texShapes.id);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
// Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner // Draw all the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
{ {
float angle = angles[k]; float angle = angles[k];
@ -1207,7 +1207,7 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
// Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
{ {
float angle = angles[k]; float angle = angles[k];
@ -1342,7 +1342,7 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo
// Use LINES to draw the outline // Use LINES to draw the outline
rlBegin(RL_LINES); rlBegin(RL_LINES);
// Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
{ {
float angle = angles[k]; float angle = angles[k];

View File

@ -65,7 +65,7 @@
#include <stdio.h> // Required for: vsprintf() #include <stdio.h> // Required for: vsprintf()
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] #include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] #include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
#include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] #include <ctype.h> // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
#define STB_RECT_PACK_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION
@ -336,7 +336,7 @@ Font LoadFont(const char *fileName)
} }
else else
{ {
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default we set point filter (best performance) SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS); TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);
} }
@ -584,7 +584,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
glyphCount = (glyphCount > 0)? glyphCount : 95; glyphCount = (glyphCount > 0)? glyphCount : 95;
// Fill fontChars in case not provided externally // Fill fontChars in case not provided externally
// NOTE: By default we fill glyphCount consecutevely, starting at 32 (Space) // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space)
if (fontChars == NULL) if (fontChars == NULL)
{ {
@ -647,7 +647,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
} }
} }
// Get bounding box for character (may be offset to account for chars that dip above or below the line) // Get bounding box for character (maybe offset to account for chars that dip above or below the line)
/* /*
int chX1, chY1, chX2, chY2; int chX1, chY1, chX2, chY2;
stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2); stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);
@ -777,7 +777,7 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
for (int i = 0; i < glyphCount; i++) for (int i = 0; i < glyphCount; i++)
{ {
// It return char rectangles in atlas // It returns char rectangles in atlas
recs[i].x = rects[i].x + (float)padding; recs[i].x = rects[i].x + (float)padding;
recs[i].y = rects[i].y + (float)padding; recs[i].y = rects[i].y + (float)padding;
recs[i].width = (float)chars[i].image.width; recs[i].width = (float)chars[i].image.width;
@ -1040,7 +1040,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
int size = TextLength(text); // Total size in bytes of the text, scanned by codepoints in loop int size = TextLength(text); // Total size in bytes of the text, scanned by codepoints in loop
int textOffsetY = 0; // Offset between lines (on line break '\n') int textOffsetY = 0; // Offset between lines (on linebreak '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw float textOffsetX = 0.0f; // Offset X to next character to draw
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
@ -1053,7 +1053,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte // but we need to draw all the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1; if (codepoint == 0x3f) codepointByteCount = 1;
if (codepoint == '\n') if (codepoint == '\n')
@ -1119,7 +1119,7 @@ void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSiz
// Draw multiple character (codepoints) // Draw multiple character (codepoints)
void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint) void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint)
{ {
int textOffsetY = 0; // Offset between lines (on line break '\n') int textOffsetY = 0; // Offset between lines (on linebreak '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw float textOffsetX = 0.0f; // Offset X to next character to draw
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
@ -1195,7 +1195,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
index = GetGlyphIndex(font, letter); index = GetGlyphIndex(font, letter);
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1 // but we need to draw all the bad bytes using the '?' symbol so to not skip any we set next = 1
if (letter == 0x3f) next = 1; if (letter == 0x3f) next = 1;
i += next - 1; i += next - 1;
@ -1410,7 +1410,7 @@ char *TextReplace(char *text, const char *replace, const char *by)
char *insertPoint = NULL; // Next insert point char *insertPoint = NULL; // Next insert point
char *temp = NULL; // Temp pointer char *temp = NULL; // Temp pointer
int replaceLen = 0; // Replace string length of (the string to remove) int replaceLen = 0; // Replace string length of (the string to remove)
int byLen = 0; // Replacement length (the string to replace replace by) int byLen = 0; // Replacement length (the string to replace by)
int lastReplacePos = 0; // Distance between replace and end of last replace int lastReplacePos = 0; // Distance between replace and end of last replace
int count = 0; // Number of replacements int count = 0; // Number of replacements
@ -1756,7 +1756,7 @@ const char *CodepointToUTF8(int codepoint, int *utf8Size)
#endif // SUPPORT_TEXT_MANIPULATION #endif // SUPPORT_TEXT_MANIPULATION
// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found // Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found
// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned // When an invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
// Total number of bytes processed are returned as a parameter // Total number of bytes processed are returned as a parameter
// NOTE: The standard says U+FFFD should be returned in case of errors // NOTE: The standard says U+FFFD should be returned in case of errors
// but that character is not supported by the default font in raylib // but that character is not supported by the default font in raylib

View File

@ -751,7 +751,7 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner,
float factor = (dist - radius*density)/(radius*(1.0f - density)); float factor = (dist - radius*density)/(radius*(1.0f - density));
factor = (float)fmax(factor, 0.0f); factor = (float)fmax(factor, 0.0f);
factor = (float)fmin(factor, 1.f); // dist can be bigger than radius so we have to check factor = (float)fmin(factor, 1.f); // dist can be bigger than radius, so we have to check
pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor)); pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor));
pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor)); pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor));
@ -898,7 +898,7 @@ Image GenImageCellular(int width, int height, int tileSize)
} }
} }
// I made this up but it seems to give good results at all tile sizes // I made this up, but it seems to give good results at all tile sizes
int intensity = (int)(minDistance*256.0f/tileSize); int intensity = (int)(minDistance*256.0f/tileSize);
if (intensity > 255) intensity = 255; if (intensity > 255) intensity = 255;
@ -1176,7 +1176,7 @@ void ImageFormat(Image *image, int newFormat)
} break; } break;
case PIXELFORMAT_UNCOMPRESSED_R32: case PIXELFORMAT_UNCOMPRESSED_R32:
{ {
// WARNING: Image is converted to GRAYSCALE eqeuivalent 32bit // WARNING: Image is converted to GRAYSCALE equivalent 32bit
image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float)); image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float));
@ -1214,7 +1214,7 @@ void ImageFormat(Image *image, int newFormat)
RL_FREE(pixels); RL_FREE(pixels);
pixels = NULL; pixels = NULL;
// In case original image had mipmaps, generate mipmaps for formated image // In case original image had mipmaps, generate mipmaps for formatted image
// NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost
if (image->mipmaps > 1) if (image->mipmaps > 1)
{ {
@ -1269,7 +1269,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
int size = (int)strlen(text); // Get size in bytes of text int size = (int)strlen(text); // Get size in bytes of text
int textOffsetX = 0; // Image drawing position X int textOffsetX = 0; // Image drawing position X
int textOffsetY = 0; // Offset between lines (on line break '\n') int textOffsetY = 0; // Offset between lines (on linebreak '\n')
// NOTE: Text image is generated at font base size, later scaled to desired font size // NOTE: Text image is generated at font base size, later scaled to desired font size
Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); // WARNING: Module required: rtext Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); // WARNING: Module required: rtext
@ -1286,7 +1286,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
int index = GetGlyphIndex(font, codepoint); // WARNING: Module required: rtext int index = GetGlyphIndex(font, codepoint); // WARNING: Module required: rtext
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte // but we need to draw all the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1; if (codepoint == 0x3f) codepointByteCount = 1;
if (codepoint == '\n') if (codepoint == '\n')
@ -1331,7 +1331,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
} }
// Crop image depending on alpha value // Crop image depending on alpha value
// NOTE: Threshold is defined as a percentatge: 0.0f -> 1.0f // NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f
void ImageAlphaCrop(Image *image, float threshold) void ImageAlphaCrop(Image *image, float threshold)
{ {
// Security check to avoid program crash // Security check to avoid program crash
@ -1711,7 +1711,7 @@ void ImageResize(Image *image, int newWidth, int newHeight)
Color *pixels = LoadImageColors(*image); Color *pixels = LoadImageColors(*image);
Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
// NOTE: Color data is casted to (unsigned char *), there shouldn't been any problem... // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem...
stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4); stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4);
int format = image->format; int format = image->format;
@ -1891,7 +1891,7 @@ void ImageMipmaps(Image *image)
} }
// Dither image data to 16bpp or lower (Floyd-Steinberg dithering) // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
// NOTE: In case selected bpp do not represent an known 16bit format, // NOTE: In case selected bpp do not represent a known 16bit format,
// dithered data is stored in the LSB part of the unsigned short // dithered data is stored in the LSB part of the unsigned short
void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
{ {
@ -2531,7 +2531,7 @@ void UnloadImagePalette(Color *colors)
} }
// Get image alpha border rectangle // Get image alpha border rectangle
// NOTE: Threshold is defined as a percentatge: 0.0f -> 1.0f // NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f
Rectangle GetImageAlphaBorder(Image image, float threshold) Rectangle GetImageAlphaBorder(Image image, float threshold)
{ {
Rectangle crop = { 0 }; Rectangle crop = { 0 };
@ -3049,7 +3049,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
if ((srcRec.y + srcRec.height) > src.height) srcRec.height = src.height - srcRec.y; if ((srcRec.y + srcRec.height) > src.height) srcRec.height = src.height - srcRec.y;
// Check if source rectangle needs to be resized to destination rectangle // Check if source rectangle needs to be resized to destination rectangle
// In that case, we make a copy of source and we apply all required transform // In that case, we make a copy of source, and we apply all required transform
if (((int)srcRec.width != (int)dstRec.width) || ((int)srcRec.height != (int)dstRec.height)) if (((int)srcRec.width != (int)dstRec.width) || ((int)srcRec.height != (int)dstRec.height))
{ {
srcMod = ImageFromImage(src, srcRec); // Create image from another image srcMod = ImageFromImage(src, srcRec); // Create image from another image
@ -3273,7 +3273,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
faces = GenImageColor(size, size*6, MAGENTA); faces = GenImageColor(size, size*6, MAGENTA);
ImageFormat(&faces, image.format); ImageFormat(&faces, image.format);
// NOTE: Image formating does not work with compressed textures // NOTE: Image formatting does not work with compressed textures
for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE); for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE);
} }
@ -3606,7 +3606,7 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
// NOTE: Vertex position can be transformed using matrices // NOTE: Vertex position can be transformed using matrices
// but the process is way more costly than just calculating // but the process is way more costly than just calculating
// the vertex positions manually, like done above. // the vertex positions manually, like done above.
// I leave here the old implementation for educational pourposes, // I leave here the old implementation for educational purposes,
// just in case someone wants to do some performance test // just in case someone wants to do some performance test
/* /*
rlSetTexture(texture.id); rlSetTexture(texture.id);

View File

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html lang="en-us"> <html lang="EN-us">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

View File

@ -63,10 +63,10 @@
static int logTypeLevel = LOG_INFO; // Minimum log type level static int logTypeLevel = LOG_INFO; // Minimum log type level
static TraceLogCallback traceLog = NULL; // TraceLog callback function pointer static TraceLogCallback traceLog = NULL; // TraceLog callback function pointer
static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback funtion pointer static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback function pointer
static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback funtion pointer static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback function pointer
static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback funtion pointer static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback function pointer
static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback funtion pointer static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback function pointer
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Functions to set internal callbacks // Functions to set internal callbacks