From 5b8af05e96b33f2d032cc31a329b89e1231d5502 Mon Sep 17 00:00:00 2001 From: jussi Date: Mon, 2 Jun 2025 20:49:51 +0300 Subject: Frustum math from raylib extras. --- API.md | 38 ++++++- ReiLua_API.lua | 33 +++++- changelog | 1 + examples/basic_lighting/main.lua | 7 ++ include/frustum.h | 62 ++++++++++++ include/rmath.h | 5 + src/frustum.c | 212 +++++++++++++++++++++++++++++++++++++++ src/lua_core.c | 5 + src/rmath.c | 101 +++++++++++++++++++ 9 files changed, 462 insertions(+), 2 deletions(-) create mode 100644 include/frustum.h create mode 100644 src/frustum.c diff --git a/API.md b/API.md index 4786403..a2ef74a 100644 --- a/API.md +++ b/API.md @@ -3682,7 +3682,7 @@ Default projection matrix near cull distance --- -> RL_CULL_DISTANCE_FAR = 1000 +> RL_CULL_DISTANCE_FAR = 1000.0 Default projection matrix far cull distance @@ -10746,6 +10746,42 @@ Check whether two given quaternions are almost equal --- +## Math - Frustum + +--- + +> frustum = RL.ExtractFrustum( Matrix projection, Matrix modelview ) + +Extract frustum from projection and modelView matrices. + +- Success return Vector4{} + +--- + +> inFrustum = RL.PointInFrustum( Vector4{} frustum, Vector3 position ) + +Check if point inside frustum + +- Success return bool + +--- + +> inFrustum = RL.SphereInFrustum( Vector4{} frustum, Vector3 position ) + +Check if sphere inside frustum + +- Success return bool + +--- + +> inFrustum = RL.AABBInFrustum( Vector4{} frustum, Vector3 min, Vector3 max ) + +Check if AABB inside frustum + +- Success return bool + +--- + ## Gui - Global gui state control functions --- diff --git a/ReiLua_API.lua b/ReiLua_API.lua index 406c038..dec0d17 100644 --- a/ReiLua_API.lua +++ b/ReiLua_API.lua @@ -1167,7 +1167,7 @@ RL.RL_MAX_SHADER_LOCATIONS=32 ---Default projection matrix near cull distance RL.RL_CULL_DISTANCE_NEAR=0.01 ---Default projection matrix far cull distance -RL.RL_CULL_DISTANCE_FAR=1000 +RL.RL_CULL_DISTANCE_FAR=1000.0 -- Defines - RLGL Texture parameters @@ -6985,6 +6985,37 @@ function RL.QuaternionTransform( q, mat ) end ---@return any result function RL.QuaternionEquals( q1, q2 ) end +-- Math - Frustum + +---Extract frustum from projection and modelView matrices. +---- Success return Vector4{} +---@param projection table +---@param modelview table +---@return any frustum +function RL.ExtractFrustum( projection, modelview ) end + +---Check if point inside frustum +---- Success return bool +---@param frustum table +---@param position table +---@return any inFrustum +function RL.PointInFrustum( frustum, position ) end + +---Check if sphere inside frustum +---- Success return bool +---@param frustum table +---@param position table +---@return any inFrustum +function RL.SphereInFrustum( frustum, position ) end + +---Check if AABB inside frustum +---- Success return bool +---@param frustum table +---@param min table +---@param max table +---@return any inFrustum +function RL.AABBInFrustum( frustum, min, max ) end + -- Gui - Global gui state control functions ---Enable gui controls (global state) diff --git a/changelog b/changelog index 8780974..7689b94 100644 --- a/changelog +++ b/changelog @@ -51,6 +51,7 @@ DETAILED CHANGES: - ADDED: DrawTextBoxed Color change escape sequence. - ADDED: RL.load and RL.unload functions for memory leak debugging. - ADDED: SoundAlias garbage collection. + - ADDED: Frustum math from raylib extras. ------------------------------------------------------------------------ Release: ReiLua version 0.8.0 Using Raylib 5.0 and Forked Raygui 4.0 diff --git a/examples/basic_lighting/main.lua b/examples/basic_lighting/main.lua index 52552c3..8c5aed0 100644 --- a/examples/basic_lighting/main.lua +++ b/examples/basic_lighting/main.lua @@ -22,6 +22,7 @@ function RL.init() local mSize = Vec2:newT( RL.GetMonitorSize( monitor ) ) local winSize = Vec2:new( 1028, 720 ) + RL.SetGCUnload( false ) RL.SetWindowTitle( "Simple Lighting" ) RL.SetWindowState( RL.FLAG_WINDOW_RESIZABLE ) RL.SetWindowState( RL.FLAG_VSYNC_HINT ) @@ -138,3 +139,9 @@ function RL.draw() RL.DrawText( "Use keys [Y][R][G][B] to toggle lights", { 10, 10 }, 20, RL.DARKGRAY ) end + +function RL.exit() + RL.UnloadMaterial( material, true ) + RL.UnloadMesh( plane ) + RL.UnloadMesh( cube ) +end diff --git a/include/frustum.h b/include/frustum.h new file mode 100644 index 0000000..370074c --- /dev/null +++ b/include/frustum.h @@ -0,0 +1,62 @@ +/********************************************************************************************** +* +* raylibExtras * Utilities and Shared Components for Raylib +* +* RLSprite * Simple Sprite Managment System for Raylib +* +* LICENSE: MIT +* +* Copyright (c) 2020 Jeffery Myers +* +* 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. +* +**********************************************************************************************/ + +#pragma once +#ifndef FRUSTUM_H +#define FRUSTUM_H + +#include "raylib.h" +#include "raymath.h" +#include "frustum.h" + +typedef enum +{ + Back = 0, + Front = 1, + Bottom = 2, + Top = 3, + Right = 4, + Left = 5, + MAX = 6 +}FrustumPlanes; + +typedef struct +{ + Vector4 Planes[6]; +}Frustum; + +// RLAPI void ExtractFrustum(Frustum* frustrum); +RLAPI void ExtractFrustum(Frustum* frustum, Matrix projection, Matrix modelview); +RLAPI bool PointInFrustumV(Frustum* frustrum, Vector3 position); +RLAPI bool SphereInFrustumV(Frustum* frustrum, Vector3 position, float radius); + +RLAPI bool AABBoxInFrustum(Frustum* frustrum, Vector3 min, Vector3 max); + +#endif //FRUSTUM_H diff --git a/include/rmath.h b/include/rmath.h index 20c4049..7b96f14 100644 --- a/include/rmath.h +++ b/include/rmath.h @@ -152,3 +152,8 @@ int lmathQuaternionFromEuler( lua_State* L ); int lmathQuaternionToEuler( lua_State* L ); int lmathQuaternionTransform( lua_State* L ); int lmathQuaternionEquals( lua_State* L ); +/* Frustum */ +int lmathExtractFrustum( lua_State* L ); +int lmathPointInFrustum( lua_State* L ); +int lmathSphereInFrustum( lua_State* L ); +int lmathAABBInFrustum( lua_State* L ); diff --git a/src/frustum.c b/src/frustum.c new file mode 100644 index 0000000..4c63e38 --- /dev/null +++ b/src/frustum.c @@ -0,0 +1,212 @@ +/********************************************************************************************** +* +* raylibExtras * Utilities and Shared Components for Raylib +* +* RLAssets * Simple Asset Managment System for Raylib +* +* LICENSE: MIT +* +* Copyright (c) 2020 Jeffery Myers +* +* 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. +* +**********************************************************************************************/ + + +#include "frustum.h" +#include "rlgl.h" +#include "raymath.h" + +#include +#include + +void NormalizePlane(Vector4* plane) +{ + if (plane == NULL) + return; + + float magnitude = sqrtf(plane->x * plane->x + plane->y * plane->y + plane->z * plane->z); + + plane->x /= magnitude; + plane->y /= magnitude; + plane->z /= magnitude; + plane->w /= magnitude; +} + +// void ExtractFrustum(Frustum* frustum) +void ExtractFrustum(Frustum* frustum, Matrix projection, Matrix modelview) +{ + if (frustum == NULL) + return; + + // Matrix projection = rlGetMatrixProjection(); + // Matrix modelview = rlGetMatrixModelview(); + + Matrix planes = { 0 }; + + planes.m0 = modelview.m0 * projection.m0 + modelview.m1 * projection.m4 + modelview.m2 * projection.m8 + modelview.m3 * projection.m12; + planes.m1 = modelview.m0 * projection.m1 + modelview.m1 * projection.m5 + modelview.m2 * projection.m9 + modelview.m3 * projection.m13; + planes.m2 = modelview.m0 * projection.m2 + modelview.m1 * projection.m6 + modelview.m2 * projection.m10 + modelview.m3 * projection.m14; + planes.m3 = modelview.m0 * projection.m3 + modelview.m1 * projection.m7 + modelview.m2 * projection.m11 + modelview.m3 * projection.m15; + planes.m4 = modelview.m4 * projection.m0 + modelview.m5 * projection.m4 + modelview.m6 * projection.m8 + modelview.m7 * projection.m12; + planes.m5 = modelview.m4 * projection.m1 + modelview.m5 * projection.m5 + modelview.m6 * projection.m9 + modelview.m7 * projection.m13; + planes.m6 = modelview.m4 * projection.m2 + modelview.m5 * projection.m6 + modelview.m6 * projection.m10 + modelview.m7 * projection.m14; + planes.m7 = modelview.m4 * projection.m3 + modelview.m5 * projection.m7 + modelview.m6 * projection.m11 + modelview.m7 * projection.m15; + planes.m8 = modelview.m8 * projection.m0 + modelview.m9 * projection.m4 + modelview.m10 * projection.m8 + modelview.m11 * projection.m12; + planes.m9 = modelview.m8 * projection.m1 + modelview.m9 * projection.m5 + modelview.m10 * projection.m9 + modelview.m11 * projection.m13; + planes.m10 = modelview.m8 * projection.m2 + modelview.m9 * projection.m6 + modelview.m10 * projection.m10 + modelview.m11 * projection.m14; + planes.m11 = modelview.m8 * projection.m3 + modelview.m9 * projection.m7 + modelview.m10 * projection.m11 + modelview.m11 * projection.m15; + planes.m12 = modelview.m12 * projection.m0 + modelview.m13 * projection.m4 + modelview.m14 * projection.m8 + modelview.m15 * projection.m12; + planes.m13 = modelview.m12 * projection.m1 + modelview.m13 * projection.m5 + modelview.m14 * projection.m9 + modelview.m15 * projection.m13; + planes.m14 = modelview.m12 * projection.m2 + modelview.m13 * projection.m6 + modelview.m14 * projection.m10 + modelview.m15 * projection.m14; + planes.m15 = modelview.m12 * projection.m3 + modelview.m13 * projection.m7 + modelview.m14 * projection.m11 + modelview.m15 * projection.m15; + + frustum->Planes[Right] = (Vector4){ planes.m3 - planes.m0, planes.m7 - planes.m4, planes.m11 - planes.m8, planes.m15 - planes.m12 }; + NormalizePlane(&frustum->Planes[Right]); + + frustum->Planes[Left] = (Vector4){ planes.m3 + planes.m0, planes.m7 + planes.m4, planes.m11 + planes.m8, planes.m15 + planes.m12 }; + NormalizePlane(&frustum->Planes[Left]); + + frustum->Planes[Top] = (Vector4){ planes.m3 - planes.m1, planes.m7 - planes.m5, planes.m11 - planes.m9, planes.m15 - planes.m13 }; + NormalizePlane(&frustum->Planes[Top]); + + frustum->Planes[Bottom] = (Vector4){ planes.m3 + planes.m1, planes.m7 + planes.m5, planes.m11 + planes.m9, planes.m15 + planes.m13 }; + NormalizePlane(&frustum->Planes[Bottom]); + + frustum->Planes[Back] = (Vector4){ planes.m3 - planes.m2, planes.m7 - planes.m6, planes.m11 - planes.m10, planes.m15 - planes.m14 }; + NormalizePlane(&frustum->Planes[Back]); + + frustum->Planes[Front] = (Vector4){ planes.m3 + planes.m2, planes.m7 + planes.m6, planes.m11 + planes.m10, planes.m15 + planes.m14 }; + NormalizePlane(&frustum->Planes[Front]); +} + +float DistanceToPlaneV(const Vector4* plane, const Vector3* position) +{ + return (plane->x * position->x + plane->y * position->y + plane->z * position->z + plane->w); +} + +float DistanceToPlane(const Vector4* plane, float x, float y, float z) +{ + return (plane->x * x + plane->y * y + plane->z * z + plane->w); +} + +bool PointInFrustumV(Frustum* frustum, Vector3 position) +{ + if (frustum == NULL) + return false; + + for (int i = 0; i < 6; i++) + { + if (DistanceToPlaneV(&frustum->Planes[i], &position) <= 0) // point is behind plane + return false; + } + + return true; +} + +bool PointInFrustum(Frustum* frustum, float x, float y, float z) +{ + if (frustum == NULL) + return false; + + for (int i = 0; i < 6; i++) + { + if (DistanceToPlane(&frustum->Planes[i], x, y, z) <= 0) // point is behind plane + return false; + } + + return true; +} + +bool SphereInFrustumV(Frustum* frustum, Vector3 position, float radius) +{ + if (frustum == NULL) + return false; + + for (int i = 0; i < 6; i++) + { + if (DistanceToPlaneV(&frustum->Planes[i], &position) < -radius) // center is behind plane by more than the radius + return false; + } + + return true; +} +bool AABBoxInFrustum(Frustum* frustum, Vector3 min, Vector3 max) +{ + // if any point is in and we are good + if (PointInFrustum(frustum, min.x, min.y, min.z)) + return true; + + if (PointInFrustum(frustum, min.x, max.y, min.z)) + return true; + + if (PointInFrustum(frustum, max.x, max.y, min.z)) + return true; + + if (PointInFrustum(frustum, max.x, min.y, min.z)) + return true; + + if (PointInFrustum(frustum, min.x, min.y, max.z)) + return true; + + if (PointInFrustum(frustum, min.x, max.y, max.z)) + return true; + + if (PointInFrustum(frustum, max.x, max.y, max.z)) + return true; + + if (PointInFrustum(frustum, max.x, min.y, max.z)) + return true; + + // check to see if all points are outside of any one plane, if so the entire box is outside + for (int i = 0; i < 6; i++) + { + bool oneInside = false; + + if (DistanceToPlane(&frustum->Planes[i], min.x, min.y, min.z) >= 0) + oneInside = true; + + if (DistanceToPlane(&frustum->Planes[i], max.x, min.y, min.z) >= 0) + oneInside = true; + + if (DistanceToPlane(&frustum->Planes[i], max.x, max.y, min.z) >= 0) + oneInside = true; + + if (DistanceToPlane(&frustum->Planes[i], min.x, max.y, min.z) >= 0) + oneInside = true; + + if (DistanceToPlane(&frustum->Planes[i], min.x, min.y, max.z) >= 0) + oneInside = true; + + if (DistanceToPlane(&frustum->Planes[i], max.x, min.y, max.z) >= 0) + oneInside = true; + + if (DistanceToPlane(&frustum->Planes[i], max.x, max.y, max.z) >= 0) + oneInside = true; + + if (DistanceToPlane(&frustum->Planes[i], min.x, max.y, max.z) >= 0) + oneInside = true; + + if (!oneInside) + return false; + } + + // the box extends outside the frustum but crosses it + return true; +} diff --git a/src/lua_core.c b/src/lua_core.c index 035685d..253d9e5 100644 --- a/src/lua_core.c +++ b/src/lua_core.c @@ -2470,6 +2470,11 @@ void luaRegister() { assingGlobalFunction( "QuaternionToEuler", lmathQuaternionToEuler ); assingGlobalFunction( "QuaternionTransform", lmathQuaternionTransform ); assingGlobalFunction( "QuaternionEquals", lmathQuaternionEquals ); + /* Frustum. */ + assingGlobalFunction( "ExtractFrustum", lmathExtractFrustum ); + assingGlobalFunction( "PointInFrustum", lmathPointInFrustum ); + assingGlobalFunction( "SphereInFrustum", lmathSphereInFrustum ); + assingGlobalFunction( "AABBInFrustum", lmathAABBInFrustum ); /* Gui. */ /* Global gui state control functions. */ diff --git a/src/rmath.c b/src/rmath.c index 40e8cb8..d1e14f0 100644 --- a/src/rmath.c +++ b/src/rmath.c @@ -2,6 +2,7 @@ #include "state.h" #include "rmath.h" #include "lua_core.h" +#include "frustum.h" int imin( int a, int b ) { return a < b ? a : b; @@ -2343,3 +2344,103 @@ int lmathQuaternionEquals( lua_State* L ) { return 1; } + +/* +## Math - Frustum +*/ + +static Frustum getFrustum( lua_State* L, int index ) { + luaL_checktype( L, index, LUA_TTABLE ); + Frustum frustum = { 0 }; + + int t = index, i = 0; + lua_pushnil( L ); + + while ( lua_next( L, t ) != 0 && i < 6 ) { + frustum.Planes[i] = uluaGetVector4( L, lua_gettop( L ) ); + i++; + lua_pop( L, 1 ); + } + + return frustum; +} + +static int pushFrustum( lua_State* L, Frustum* frustum ) { + lua_createtable( L, 6, 0 ); + + for ( int i = 0; i < 6; i++ ) { + uluaPushVector4( L, frustum->Planes[i] ); + lua_rawseti( L, -2, 1 + i ); + } + + return 1; +} + +/* +> frustum = RL.ExtractFrustum( Matrix projection, Matrix modelview ) + +Extract frustum from projection and modelView matrices. + +- Success return Vector4{} +*/ +int lmathExtractFrustum( lua_State* L ) { + Matrix projection = uluaGetMatrix( L, 1 ); + Matrix modelview = uluaGetMatrix( L, 2 ); + + Frustum frustum = { 0 }; + ExtractFrustum( &frustum, projection, modelview ); + + pushFrustum( L, &frustum ); + + return 1; +} + +/* +> inFrustum = RL.PointInFrustum( Vector4{} frustum, Vector3 position ) + +Check if point inside frustum + +- Success return bool +*/ +int lmathPointInFrustum( lua_State* L ) { + Frustum frustum = getFrustum( L, 1 ); + Vector3 position = uluaGetVector3( L, 2 ); + + lua_pushboolean( L, PointInFrustumV( &frustum, position ) ); + + return 1; +} + +/* +> inFrustum = RL.SphereInFrustum( Vector4{} frustum, Vector3 position ) + +Check if sphere inside frustum + +- Success return bool +*/ +int lmathSphereInFrustum( lua_State* L ) { + Frustum frustum = getFrustum( L, 1 ); + Vector3 position = uluaGetVector3( L, 2 ); + float radius = luaL_checknumber( L, 3 ); + + lua_pushboolean( L, SphereInFrustumV( &frustum, position, radius ) ); + + return 1; +} + +/* +> inFrustum = RL.AABBInFrustum( Vector4{} frustum, Vector3 min, Vector3 max ) + +Check if AABB inside frustum + +- Success return bool +*/ +int lmathAABBInFrustum( lua_State* L ) { + Frustum frustum = getFrustum( L, 1 ); + Vector3 min = uluaGetVector3( L, 2 ); + Vector3 max = uluaGetVector3( L, 3 ); + + lua_pushboolean( L, AABBoxInFrustum( &frustum, min, max ) ); + + return 1; +} -- cgit v1.2.3