diff options
Diffstat (limited to 'src/models.c')
| -rw-r--r-- | src/models.c | 2113 |
1 files changed, 2113 insertions, 0 deletions
diff --git a/src/models.c b/src/models.c new file mode 100644 index 0000000..17683b8 --- /dev/null +++ b/src/models.c @@ -0,0 +1,2113 @@ +#include "main.h" +#include "state.h" +#include "models.h" +#include "lua_core.h" +#include "rmath.h" +#include "textures.h" +#include "core.h" + +static void checkMeshRealloc( int i ) { + if ( i == state->meshCount ) { + state->meshCount++; + } + + if ( state->meshCount == state->meshAlloc ) { + state->meshAlloc += ALLOC_PAGE_SIZE; + state->meshes = realloc( state->meshes, state->meshAlloc * sizeof( Mesh* ) ); + + for ( i = state->meshCount; i < state->meshAlloc; i++ ) { + state->meshes[i] = NULL; + } + } +} + +static void checkMaterialRealloc( int i ) { + if ( i == state->materialCount ) { + state->materialCount++; + } + + if ( state->materialCount == state->materialAlloc ) { + state->materialAlloc += ALLOC_PAGE_SIZE; + state->materials = realloc( state->materials, state->materialAlloc * sizeof( Material* ) ); + + for ( i = state->materialCount; i < state->materialAlloc; i++ ) { + state->materials[i] = NULL; + } + } +} + +static void checkModelRealloc( int i ) { + if ( i == state->modelCount ) { + state->modelCount++; + } + + if ( state->modelCount == state->modelAlloc ) { + state->modelAlloc += ALLOC_PAGE_SIZE; + state->models = realloc( state->models, state->modelAlloc * sizeof( Model* ) ); + + for ( i = state->modelCount; i < state->modelAlloc; i++ ) { + state->models[i] = NULL; + } + } +} + +static void checkAnimationRealloc( int i ) { + if ( i == state->animationCount ) { + state->animationCount++; + } + + if ( state->animationCount == state->animationAlloc ) { + state->animationAlloc += ALLOC_PAGE_SIZE; + state->animations = realloc( state->animations, state->animationAlloc * sizeof( ModelAnimations* ) ); + + for ( i = state->animationCount; i < state->animationAlloc; i++ ) { + state->animations[i] = NULL; + } + } +} + +static bool validMesh( size_t id ) { + if ( id < 0 || state->meshCount < id || state->meshes[ id ] == NULL ) { + TraceLog( LOG_WARNING, "%s %d", "Invalid mesh", id ); + return false; + } + else { + return true; + } +} + +static bool validMaterial( size_t id ) { + if ( id < 0 || state->materialCount < id || state->materials[ id ] == NULL ) { + TraceLog( LOG_WARNING, "%s %d", "Invalid material", id ); + return false; + } + else { + return true; + } +} + +static bool validModel( size_t id ) { + if ( id < 0 || state->modelCount < id || state->models[ id ] == NULL ) { + TraceLog( LOG_WARNING, "%s %d", "Invalid model", id ); + return false; + } + else { + return true; + } +} + +static bool validAnimation( size_t id ) { + if ( id < 0 || state->animationCount < id || state->animations[ id ] == NULL ) { + TraceLog( LOG_WARNING, "%s %d", "Invalid animation", id ); + return false; + } + else { + return true; + } +} + +/* +## Models - Basic +*/ + +/* +> success = RL_DrawLine3D( Vector3 startPos, Vector3 endPos, Color color ) + +Draw a line in 3D world space + +- Failure return false +- Success return true +*/ +int lmodelsDrawLine3D( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawLine3D( Vector3 startPos, Vector3 endPos, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector3 endPos = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 startPos = uluaGetVector3( L ); + + DrawLine3D( startPos, endPos, color); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawPoint3D( Vector3 position, Color color ) + +Draw a point in 3D space, actually a small line + +- Failure return false +- Success return true +*/ +int lmodelsDrawPoint3D( lua_State *L ) { + if ( !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawPoint3D( Vector3 position, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector3 position = uluaGetVector3( L ); + + DrawPoint3D( position, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawCircle3D( Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color ) + +Draw a circle in 3D world space + +- Failure return false +- Success return true +*/ +int lmodelsDrawCircle3D( lua_State *L ) { + if ( !lua_istable( L, -5 ) || !lua_isnumber( L, -4 ) || !lua_istable( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawCircle3D( Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + float rotationAngle = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 rotationAxis = uluaGetVector3( L ); + lua_pop( L, 1 ); + float radius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 center = uluaGetVector3( L ); + + DrawCircle3D( center, radius, rotationAxis, rotationAngle, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawTriangle3D( Vector3 v1, Vector3 v2, Vector3 v3, Color color ) + +Draw a color-filled triangle ( Vertex in counter-clockwise order! ) + +- Failure return false +- Success return true +*/ +int lmodelsDrawTriangle3D( lua_State *L ) { + if ( !lua_istable( L, -4 ) || !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawTriangle3D( Vector3 v1, Vector3 v2, Vector3 v3, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector3 v3 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 v2 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 v1 = uluaGetVector3( L ); + + DrawTriangle3D( v1, v2, v3, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawCube( Vector3 position, Vector3 size, Color color ) + +Draw cube + +- Failure return false +- Success return true +*/ +int lmodelsDrawCube( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawCube( Vector3 position, Vector3 size, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector3 size = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 pos = uluaGetVector3( L ); + + DrawCubeV( pos, size, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawCubeWires( Vector3 position, Vector3 size, Color color ) + +Draw cube wires + +- Failure return false +- Success return true +*/ +int lmodelsDrawCubeWires( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawCubeWires( Vector3 position, Vector3 size, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector3 size = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 pos = uluaGetVector3( L ); + + DrawCubeWiresV( pos, size, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawCubeTexture( Texture2D texture, Vector3 position, Vector3 size, Color color ) + +Draw cube textured + +- Failure return false +- Success return true +*/ +int lmodelsDrawCubeTexture( lua_State *L ) { + if ( !lua_isnumber( L, -4 ) || !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawCubeTexture( Texture2D texture, Vector3 position, Vector3 size, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector3 size = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 pos = uluaGetVector3( L ); + lua_pop( L, 1 ); + size_t texId = lua_tointeger( L, -1 ); + + if ( !validSourceTexture( texId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + DrawCubeTexture( *texturesGetSourceTexture( texId ), pos, size.x, size.y, size.z, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawSphere( Vector3 centerPos, float radius, Color color ) + +Draw sphere + +- Failure return false +- Success return true +*/ +int lmodelsDrawSphere( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawSphere( Vector3 centerPos, float radius, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + float radius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 centerPos = uluaGetVector3( L ); + + DrawSphere( centerPos, radius, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawSphereEx( Vector3 centerPos, float radius, int rings, int slices, Color color ) + +Draw sphere with extended parameters + +- Failure return false +- Success return true +*/ +int lmodelsDrawSphereEx( lua_State *L ) { + if ( !lua_istable( L, -5 ) || !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawSphereEx( Vector3 centerPos, float radius, int rings, int slices, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + int slices = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + int rings = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + float radius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 centerPos = uluaGetVector3( L ); + + DrawSphereEx( centerPos, radius, rings, slices, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawSphereWires( Vector3 centerPos, float radius, int rings, int slices, Color color ) + +Draw sphere wires + +- Failure return false +- Success return true +*/ +int lmodelsDrawSphereWires( lua_State *L ) { + if ( !lua_istable( L, -5 ) || !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawSphereWires( Vector3 centerPos, float radius, int rings, int slices, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + int slices = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + int rings = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + float radius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 centerPos = uluaGetVector3( L ); + + DrawSphereWires( centerPos, radius, rings, slices, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawCylinder( Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color ) + +Draw a cylinder/cone + +- Failure return false +- Success return true +*/ +int lmodelsDrawCylinder( lua_State *L ) { + if ( !lua_istable( L, -6 ) || !lua_isnumber( L, -5 ) || !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawCylinder( Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + int slices = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + float height = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + float radiusBottom = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + float radiusTop = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 position = uluaGetVector3( L ); + + DrawCylinder( position, radiusTop, radiusBottom, height, slices, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawCylinderEx( Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color ) + +Draw a cylinder with base at startPos and top at endPos + +- Failure return false +- Success return true +*/ +int lmodelsDrawCylinderEx( lua_State *L ) { + if ( !lua_istable( L, -6 ) || !lua_istable( L, -5 ) || !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawCylinderEx( Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + int sides = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + float endRadius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + float startRadius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 endPos = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 startPos = uluaGetVector3( L ); + + DrawCylinderEx( startPos, endPos, startRadius, endRadius, sides, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawCylinderWires( Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color ) + +Draw a cylinder/cone wires + +- Failure return false +- Success return true +*/ +int lmodelsDrawCylinderWires( lua_State *L ) { + if ( !lua_istable( L, -6 ) || !lua_isnumber( L, -5 ) || !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawCylinderWires( Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + int slices = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + float height = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + float radiusBottom = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + float radiusTop = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 position = uluaGetVector3( L ); + + DrawCylinderWires( position, radiusTop, radiusBottom, height, slices, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawCylinderWiresEx( Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color ) + +Draw a cylinder wires with base at startPos and top at endPos + +- Failure return false +- Success return true +*/ +int lmodelsDrawCylinderWiresEx( lua_State *L ) { + if ( !lua_istable( L, -6 ) || !lua_istable( L, -5 ) || !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawCylinderWiresEx( Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + int sides = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + float endRadius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + float startRadius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 endPos = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 startPos = uluaGetVector3( L ); + + DrawCylinderWiresEx( startPos, endPos, startRadius, endRadius, sides, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawPlane( Vector3 centerPos, Vector2 size, Color color ) + +Draw a plane XZ + +- Failure return false +- Success return true +*/ +int lmodelsDrawPlane( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawPlane( Vector3 centerPos, Vector2 size, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector2 size = uluaGetVector2( L ); + lua_pop( L, 1 ); + Vector3 centerPos = uluaGetVector3( L ); + + DrawPlane( centerPos, size, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawQuad3DTexture( texture, Vector3{} vertices, Vector2{} texCoords, Color color ) + +Draw 3D quad texture using vertices and texture coordinates. Texture coordinates opengl style 0.0 - 1.0. +Note! Could be replaced something like "DrawPlaneTextureRec" + +- Failure return false +- Success return true +*/ +int lmodelDrawQuad3DTexture( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawQuad3DTexture( texture, Vector3{} vertices, Vector2{} texCoords, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + + /* TexCoords. */ + Vector2 texcoords[4] = { 0 }; + + int t = lua_gettop( L ), i = 0; + lua_pushnil( L ); + + while ( lua_next( L, t ) != 0 ) { + if ( lua_istable( L, -1 ) && i < 4 ) { + texcoords[i] = uluaGetVector2( L ); + } + i++; + lua_pop( L, 1 ); + } + lua_pop( L, 1 ); + + /* Vertices. */ + Vector3 vertices[4] = { 0 }; + + t = lua_gettop( L ); + i = 0; + lua_pushnil( L ); + + while ( lua_next( L, t ) != 0 ) { + if ( lua_istable( L, -1 ) && i < 4 ) { + vertices[i] = uluaGetVector3( L ); + } + i++; + lua_pop( L, 1 ); + } + lua_pop( L, 1 ); + size_t texId = lua_tointeger( L, -1 ); + + if ( !validSourceTexture( texId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + // Draw. + rlCheckRenderBatchLimit( 4 ); + rlSetTexture( texturesGetSourceTexture( texId )->id ); + + //TODO Normals. maybe something like Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA))); + + rlBegin( RL_QUADS ); + rlColor4ub( color.r, color.g, color.b, color.a ); + + for ( i = 0; i < 4; ++i ) { + rlTexCoord2f( texcoords[i].x, texcoords[i].y ); + rlVertex3f( vertices[i].x, vertices[i].y, vertices[i].z ); + } + rlEnd(); + rlSetTexture( 0 ); + + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawRay( Ray ray, Color color ) + +Draw a ray line + +- Failure return false +- Success return true +*/ +int lmodelsDrawRay( lua_State *L ) { + if ( !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawRay( Ray ray, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + Ray ray = uluaGetRay( L ); + + DrawRay( ray, color ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawGrid( int slices, float spacing ) + +Draw a grid ( Centered at ( 0, 0, 0 ) ) + +- Failure return false +- Success return true +*/ +int lmodelsDrawGrid( lua_State *L ) { + if ( !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawGrid( int slices, float spacing )" ); + lua_pushboolean( L, false ); + return 1; + } + DrawGrid( lua_tointeger( L, -2 ), lua_tonumber( L, -1 ) ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +## Models - Mesh +*/ + +/* +> mesh = RL_GenMeshPoly( int sides, float radius ) + +Generate polygonal mesh + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshPoly( lua_State *L ) { + if ( !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshPoly( int sides, float radius )" ); + lua_pushinteger( L, -1 ); + return 1; + } + float radius = lua_tonumber( L, -1 ); + int sides = lua_tointeger( L, -2 ); + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshPoly( sides, radius ); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshPlane( float width, float length, int resX, int resZ ) + +Generate plane mesh ( With subdivisions ) + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshPlane( lua_State *L ) { + if ( !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshPlane( float width, float length, int resX, int resZ )" ); + lua_pushinteger( L, -1 ); + return 1; + } + int resZ = lua_tointeger( L, -1 ); + int resX = lua_tointeger( L, -2 ); + float length = lua_tonumber( L, -3 ); + float width = lua_tonumber( L, -4 ); + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshPlane( width, length, resX, resZ ); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshCube( Vector3 size ) + +Generate cuboid mesh + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshCube( lua_State *L ) { + if ( !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshCube( Vector3 size )" ); + lua_pushinteger( L, -1 ); + return 1; + } + Vector3 size = uluaGetVector3( L ); + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshCube( size.x, size.y, size.z ); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshSphere( float radius, int rings, int slices ) + +Generate sphere mesh ( Standard sphere ) + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshSphere( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshSphere( float radius, int rings, int slices )" ); + lua_pushinteger( L, -1 ); + return 1; + } + int slices = lua_tointeger( L, -1 ); + int rings = lua_tointeger( L, -2 ); + float radius = lua_tonumber( L, -3 ); + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshSphere( radius, rings, slices ); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshCylinder( float radius, float height, int slices ) + +Generate cylinder mesh + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshCylinder( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshCylinder( float radius, float height, int slices )" ); + lua_pushinteger( L, -1 ); + return 1; + } + int slices = lua_tointeger( L, -1 ); + float height = lua_tonumber( L, -2 ); + float radius = lua_tonumber( L, -3 ); + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshCylinder( radius, height, slices); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshCone( float radius, float height, int slices ) + +Generate cone/pyramid mesh + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshCone( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshCone( float radius, float height, int slices )" ); + lua_pushinteger( L, -1 ); + return 1; + } + int slices = lua_tointeger( L, -1 ); + float height = lua_tonumber( L, -2 ); + float radius = lua_tonumber( L, -3 ); + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshCone( radius, height, slices); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshTorus( float radius, float size, int radSeg, int sides ) + +Generate torus mesh + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshTorus( lua_State *L ) { + if ( !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshTorus( float radius, float size, int radSeg, int sides )" ); + lua_pushinteger( L, -1 ); + return 1; + } + int sides = lua_tointeger( L, -1 ); + int radSeg = lua_tointeger( L, -2 ); + float size = lua_tonumber( L, -3 ); + float radius = lua_tonumber( L, -4 ); + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshTorus( radius, size, radSeg, sides ); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshKnot( float radius, float size, int radSeg, int sides ) + +Generate torus mesh + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshKnot( lua_State *L ) { + if ( !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshKnot( float radius, float size, int radSeg, int sides )" ); + lua_pushinteger( L, -1 ); + return 1; + } + int sides = lua_tointeger( L, -1 ); + int radSeg = lua_tointeger( L, -2 ); + float size = lua_tonumber( L, -3 ); + float radius = lua_tonumber( L, -4 ); + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshKnot( radius, size, radSeg, sides ); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshHeightmap( Image heightmap, Vector3 size ) + +Generate heightmap mesh from image data + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshHeightmap( lua_State *L ) { + if ( !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshHeightmap( Image heightmap, Vector3 size )" ); + lua_pushinteger( L, -1 ); + return 1; + } + Vector3 size = uluaGetVector3( L ); + lua_pop( L, 1 ); + Image *heightmap = state->images[ lua_tointeger( L, -1 ) ]; + int i = 0; + + for ( i = 0; i < state->meshCount; i++ ) { + if ( state->meshes[i] == NULL ) { + break; + } + } + state->meshes[i] = malloc( sizeof( Mesh ) ); + *state->meshes[i] = GenMeshHeightmap( *heightmap, size ); + lua_pushinteger( L, i ); + checkMeshRealloc( i ); + + return 1; +} + +/* +> mesh = RL_GenMeshCustom( Vector3{} vertices, Vector2{} texCoords, Vector3{} normals ) + +Generate custom mesh + +- Failure return -1 +- Success return int +*/ +int lmodelsGenMeshCustom( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GenMeshCustom( Vector3{} vertices, Vector2{} texCoords, Vector3{} normals )" ); + lua_pushinteger( L, -1 ); + return 1; + } + Mesh mesh = { 0 }; + size_t len = uluaGetTableLen( L ); + + mesh.vertexCount = len * 3; + mesh.triangleCount = len; + + mesh.vertices = (float*)MemAlloc( mesh.vertexCount * 3 * sizeof(float) ); + mesh.texcoords = (float*)MemAlloc( mesh.vertexCount * 2 * sizeof(float) ); + mesh.normals = (float*)MemAlloc( mesh.vertexCount * 3 * sizeof(float) ); + mesh.colors = (unsigned char*)MemAlloc( mesh.vertexCount * 4 * sizeof(unsigned char) ); + + /* Normals. */ + + int t = lua_gettop( L ), i = 0; + lua_pushnil( L ); + + while ( lua_next( L, t ) != 0 ) { + if ( lua_istable( L, -1 ) ) { + Vector3 vec = uluaGetVector3( L ); + mesh.normals[(i*3)+0] = vec.x; + mesh.normals[(i*3)+1] = vec.y; + mesh.normals[(i*3)+2] = vec.z; + } + i++; + lua_pop( L, 1 ); + } + lua_pop( L, 1 ); + + /* TexCoords. */ + + t = lua_gettop( L ); + i = 0; + lua_pushnil( L ); + + while ( lua_next( L, t ) != 0 ) { + if ( lua_istable( L, -1 ) ) { + Vector2 vec = uluaGetVector2( L ); + mesh.texcoords[(i*2)+0] = vec.x; + mesh.texcoords[(i*2)+1] = vec.y; + } + i++; + lua_pop( L, 1 ); + } + lua_pop( L, 1 ); + + /* Vertices. */ + + t = lua_gettop( L ); + i = 0; + lua_pushnil( L ); + + while ( lua_next( L, t ) != 0 ) { + if ( lua_istable( L, -1 ) ) { + Vector3 vec = uluaGetVector3( L ); + mesh.vertices[(i*3)+0] = vec.x; + mesh.vertices[(i*3)+1] = vec.y; + mesh.vertices[(i*3)+2] = vec.z; + + mesh.colors[(i*4)+0] = (unsigned char)255; + mesh.colors[(i*4)+1] = (unsigned char)255; + mesh.colors[(i*4)+2] = (unsigned char)255; + mesh.colors[(i*4)+3] = (unsigned char)255; + } + i++; + lua_pop( L, 1 ); + } + lua_pop( L, 1 ); + + UploadMesh( &mesh, false ); + + int j = 0; + + for ( j = 0; j < state->meshCount; j++ ) { + if ( state->meshes[j] == NULL ) { + break; + } + } + state->meshes[j] = malloc( sizeof( Mesh ) ); + *state->meshes[j] = mesh; + lua_pushinteger( L, j ); + checkMeshRealloc( j ); + + return 1; +} + +/* +> success = RL_UnloadMesh( Mesh mesh ) + +Unload mesh data from CPU and GPU + +- Failure return false +- Success return true +*/ +int lmodelsUnloadMesh( lua_State *L ) { + if ( !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_UnloadMesh( Mesh mesh )" ); + lua_pushboolean( L, false ); + return 1; + } + size_t id = lua_tointeger( L, -1 ); + + if ( !validMesh( id ) ) { + lua_pushboolean( L, false ); + return 1; + } + UnloadMesh( *state->meshes[ id ] ); + state->meshes[ id ] = NULL; + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawMesh( Mesh mesh, Material material, Matrix transform ) + +Draw a 3d mesh with material and transform + +- Failure return false +- Success return true +*/ +int lmodelsDrawMesh( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawMesh( Mesh mesh, Material material, Matrix transform )" ); + lua_pushboolean( L, false ); + return 1; + } + Matrix matrix = uluaGetMatrix( L ); + lua_pop( L, 1 ); + size_t materialId = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + size_t meshId = lua_tointeger( L, -1 ); + + if ( !validMesh( meshId ) || !validMaterial( materialId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + DrawMesh( *state->meshes[ meshId ], *state->materials[ materialId ], matrix ); + lua_pushboolean( L, true ); + + return 1; +} + +/* TODO Needs shader to work. Test it when we have shaders. */ +/* +> success = RL_DrawMeshInstanced( Mesh mesh, Material material, Matrix{} transforms, int instances ) + +Draw multiple mesh instances with material and different transforms + +- Failure return false +- Success return true +*/ +int lmodelsDrawMeshInstanced( lua_State *L ) { + if ( !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_istable( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawMeshInstanced( Mesh mesh, Material material, Matrix{} transforms, int instances )" ); + lua_pushboolean( L, false ); + return 1; + } + int instances = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + Matrix matrises[ instances ]; + + int t = lua_gettop( L ), i = 0; + lua_pushnil( L ); + + while ( lua_next( L, t ) != 0 ) { + if ( lua_istable( L, -1 ) ) { + matrises[i] = uluaGetMatrix( L ); + } + i++; + lua_pop( L, 1 ); + } + lua_pop( L, 1 ); + size_t materialId = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + size_t meshId = lua_tointeger( L, -1 ); + + if ( !validMesh( meshId ) || !validMaterial( materialId ) ) { + lua_pushboolean( L, false ); + return 1; + } + DrawMeshInstanced( *state->meshes[ meshId ], *state->materials[ materialId ], matrises, instances ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_SetMeshColor( Mesh mesh, Color color ) + +Updades mesh color vertex attribute buffer +NOTE: Currently only works on custom mesh + +- Failure return false +- Success return true +*/ +int lmodelsSetMeshColor( lua_State *L ) { + if ( !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_SetMeshColor( Mesh mesh, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + size_t meshId = lua_tointeger( L, -1 ); + + if ( !validMesh( meshId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + Mesh *mesh = state->meshes[ meshId ]; + + if ( mesh->colors == NULL ) { + TraceLog( LOG_WARNING, "Mesh %d %s", meshId, "Mesh doesn't have vertex colors allocated" ); + lua_pushboolean( L, false ); + return 1; + } + + for ( int i = 0; i < mesh->vertexCount; ++i ) { + mesh->colors[(i*4)+0] = (unsigned char)color.r; + mesh->colors[(i*4)+1] = (unsigned char)color.g; + mesh->colors[(i*4)+2] = (unsigned char)color.b; + mesh->colors[(i*4)+3] = (unsigned char)color.a; + } + /* Update vertex attribute: color */ + rlUpdateVertexBuffer( mesh->vboId[3], mesh->colors, mesh->vertexCount * 4 * sizeof( unsigned char ), 0 ); + + lua_pushboolean( L, true ); + + return 1; +} + +/* +## Models - Material +*/ + +/* +> material = RL_LoadMaterialDefault() + +Load default material + +- Success return int +*/ +int lmodelsLoadMaterialDefault( lua_State *L ) { + int i = 0; + + for ( i = 0; i < state->materialCount; i++ ) { + if ( state->materials[i] == NULL ) { + break; + } + } + state->materials[i] = malloc( sizeof( Material ) ); + *state->materials[i] = LoadMaterialDefault(); + lua_pushinteger( L, i ); + checkMaterialRealloc( i ); + + return 1; +} + +/* +> material = RL_CreateMaterial( material{} ) + +Load material from table. See material table definition + +- Failure return false +- Success return int +*/ +int lmodelsCreateMaterial( lua_State *L ) { + if ( !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_CreateMaterial( material{} )" ); + lua_pushboolean( L, false ); + return 1; + } + int i = 0; + + for ( i = 0; i < state->materialCount; i++ ) { + if ( state->materials[i] == NULL ) { + break; + } + } + state->materials[i] = malloc( sizeof( Material ) ); + *state->materials[i] = LoadMaterialDefault(); + + int t = lua_gettop( L ); + lua_pushnil( L ); + + while ( lua_next( L, t ) != 0 ) { + if ( strcmp( "maps", (char*)lua_tostring( L, -2 ) ) == 0 && lua_istable( L, -1 ) ) { + int t2 = lua_gettop( L ); + lua_pushnil( L ); + + while ( lua_next( L, t2 ) != 0 ) { + /* Loop maps. Array where we don't care about the index value. */ + if ( lua_istable( L, -1 ) ) { + int t3 = lua_gettop( L ), j = 0, map = 0; + lua_pushnil( L ); + + while ( lua_next( L, t3 ) != 0 ) { + switch ( j ) { + case 0: /* Map */ + map = lua_tointeger( L, -1 ); + break; + case 1: /* Parameters */ + { + int t4 = lua_gettop( L ); + lua_pushnil( L ); + + while ( lua_next( L, t4 ) != 0 ) { + if ( strcmp( "texture", (char*)lua_tostring( L, -2 ) ) == 0 && lua_isnumber( L, -1 ) ) { + state->materials[i]->maps[map].texture = *state->textures[ lua_tointeger( L, -1 ) ]; + } + else if ( strcmp( "color", (char*)lua_tostring( L, -2 ) ) == 0 && lua_istable( L, -1 ) ) { + state->materials[i]->maps[map].color = uluaGetColor( L ); + } + else if ( strcmp( "value", (char*)lua_tostring( L, -2 ) ) == 0 && lua_isnumber( L, -1 ) ) { + state->materials[i]->maps[map].value = lua_tonumber( L, -1 ); + } + lua_pop( L, 1 ); + } + } + break; + default: + break; + } + j++; + lua_pop( L, 1 ); + } + } + lua_pop( L, 1 ); + } + } + else if ( strcmp( "params", (char*)lua_tostring( L, -2 ) ) == 0 && lua_istable( L, -1 ) ) { + int t2 = lua_gettop( L ), j = 0; + lua_pushnil( L ); + + while ( lua_next( L, t2 ) != 0 ) { + if ( j <= 3 ) { + state->materials[i]->params[j] = lua_tonumber( L, -1 ); + } + j++; + lua_pop( L, 1 ); + } + } + else if ( strcmp( "shader", (char*)lua_tostring( L, -2 ) ) == 0 && lua_isnumber( L, -1 ) ) { + /* TODO Shader when implemented. */ + } + lua_pop( L, 1 ); + } + lua_pushinteger( L, i ); + checkMaterialRealloc( i ); + + return 1; +} + +/* +> success = RL_UnloadMaterial( Material material ) + +Unload material from GPU memory ( VRAM ) + +- Failure return false +- Success return true +*/ +int lmodelsUnloadMaterial( lua_State *L ) { + if ( !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_UnloadMaterial( Material material )" ); + lua_pushboolean( L, false ); + return 1; + } + size_t id = lua_tointeger( L, -1 ); + + if ( !validMaterial( id ) ) { + lua_pushboolean( L, false ); + return 1; + } + UnloadMaterial( *state->materials[ id ] ); + state->materials[ id ] = NULL; + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_SetMaterialTexture( Material material, int mapType, Texture2D texture ) + +Set texture for a material map type ( MATERIAL_MAP_ALBEDO, MATERIAL_MAP_METALNESS... ) + +- Failure return false +- Success return true +*/ +int lmodelsSetMaterialTexture( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_SetMaterialTexture( Material material, int mapType, Texture2D texture )" ); + lua_pushboolean( L, false ); + return 1; + } + size_t texId = lua_tointeger( L, -1 ); + size_t materialId = lua_tointeger( L, -3 ); + + if ( !validMaterial( materialId ) || !validSourceTexture( texId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + // SetMaterialTexture( state->materials[ lua_tointeger( L, -3 ) ], lua_tointeger( L, -2 ), *state->textures[ lua_tointeger( L, -1 ) ] ); + SetMaterialTexture( state->materials[ materialId ], lua_tointeger( L, -2 ), *texturesGetSourceTexture( texId ) ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_SetMaterialColor( Material material, int mapType, Color color ) + +Set color for a material map type + +- Failure return false +- Success return true +*/ +int lmodelsSetMaterialColor( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_SetMaterialColor( Material material, int mapType, Color color )" ); + lua_pushboolean( L, false ); + return 1; + } + Color color = uluaGetColor( L ); + lua_pop( L, 1 ); + size_t mapType = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + size_t materialId = lua_tointeger( L, -1 ); + + if ( !validMaterial( materialId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + state->materials[ materialId ]->maps[ mapType ].color = color; + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_SetMaterialValue( Material material, int mapType, float value ) + +Set value for a material map type + +- Failure return false +- Success return true +*/ +int lmodelsSetMaterialValue( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_SetMaterialValue( Material material, int mapType, float value )" ); + lua_pushboolean( L, false ); + return 1; + } + float value = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + size_t mapType = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + size_t materialId = lua_tointeger( L, -1 ); + + if ( !validMaterial( materialId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + state->materials[ materialId ]->maps[ mapType ].value = value; + lua_pushboolean( L, true ); + + return 1; +} + +/* +## Models - Model +*/ + +/* +> model = RL_LoadModel( string fileName ) + +Load model from files ( Meshes and materials ) + +- Failure return -1 +- Success return int +*/ +int lmodelsLoadModel( lua_State *L ) { + if ( !lua_isstring( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_LoadModel( string fileName )" ); + lua_pushinteger( L, -1 ); + return 1; + } + int i = 0; + + for ( i = 0; i < state->modelCount; i++ ) { + if ( state->models[i] == NULL ) { + break; + } + } + state->models[i] = malloc( sizeof( Model ) ); + *state->models[i] = LoadModel( lua_tostring( L, -1 ) ); + lua_pushinteger( L, i ); + checkModelRealloc( i ); + + return 1; +} + +/* +> model = RL_LoadModelFromMesh( Mesh mesh ) + +Load model from generated mesh ( Default material ) + +- Failure return -1 +- Success return int +*/ +int lmodelsLoadModelFromMesh( lua_State *L ) { + if ( !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_LoadModelFromMesh( Mesh mesh )" ); + lua_pushinteger( L, -1 ); + return 1; + } + size_t meshId = lua_tointeger( L, -1 ); + + if ( !validMesh( meshId ) ) { + lua_pushinteger( L, -1 ); + return 1; + } + int i = 0; + + for ( i = 0; i < state->modelCount; i++ ) { + if ( state->models[i] == NULL ) { + break; + } + } + state->models[i] = malloc( sizeof( Model ) ); + *state->models[i] = LoadModelFromMesh( *state->meshes[ meshId ] ); + lua_pushinteger( L, i ); + checkModelRealloc( i ); + + return 1; +} + +/* +> success = RL_UnloadModel( Model model ) + +Unload model ( Including meshes ) from memory ( RAM and/or VRAM ) + +- Failure return false +- Success return true +*/ +int lmodelsUnloadModel( lua_State *L ) { + if ( !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_UnloadModel( Model model )" ); + lua_pushboolean( L, false ); + return 1; + } + size_t modelId = lua_tointeger( L, -1 ); + + if ( !validModel( modelId ) ) { + lua_pushboolean( L, false ); + return 1; + } + UnloadModel( *state->models[ modelId ] ); + state->models[ modelId ] = NULL; + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawModel( Model model, Vector3 position, float scale, Color tint ) + +Draw a model ( With texture if set ) + +- Failure return false +- Success return true +*/ +int lmodelsDrawModel( lua_State *L ) { + if ( !lua_isnumber( L, -4 ) || !lua_istable( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawModel( Model model, Vector3 position, float scale, Color tint )" ); + lua_pushboolean( L, false ); + return 1; + } + Color tint = uluaGetColor( L ); + lua_pop( L, 1 ); + float scale = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 position = uluaGetVector3( L ); + lua_pop( L, 1 ); + size_t modelId = lua_tointeger( L, -1 ); + + if ( !validModel( modelId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + DrawModel( *state->models[ modelId ], position, scale, tint ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawModelEx( Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint ) + +Draw a model with extended parameters + +- Failure return false +- Success return true +*/ +int lmodelsDrawModelEx( lua_State *L ) { + if ( !lua_isnumber( L, -6 ) || !lua_istable( L, -5 ) || !lua_istable( L, -4 ) + || !lua_isnumber( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawModelEx( Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint )" ); + lua_pushboolean( L, false ); + return 1; + } + Color tint = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector3 scale = uluaGetVector3( L ); + lua_pop( L, 1 ); + float rotationAngle = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 rotationAxis = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 position = uluaGetVector3( L ); + lua_pop( L, 1 ); + size_t modelId = lua_tointeger( L, -1 ); + + if ( !validModel( modelId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + DrawModelEx( *state->models[ modelId ], position, rotationAxis, rotationAngle, scale, tint ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_SetModelMaterial( Model model, Material modelMaterial, Material material ) + +Copies material to model material. ( Model material is the material id in models. Material can be deleted if not used elsewhere ) + +- Failure return false +- Success return true +*/ +int lmodelsSetModelMaterial( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_SetModelMaterial( Model model, Material modelMaterial, Material material )" ); + lua_pushboolean( L, false ); + return 1; + } + size_t materialId = lua_tointeger( L, -1 ); + size_t modelId = lua_tointeger( L, -3 ); + + if ( !validModel( modelId ) || !validMaterial( materialId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + Model *model = state->models[ modelId ]; + int modelMaterialId = lua_tointeger( L, -2 ); + Material *material = state->materials[ materialId ]; + + /* Copy material data instead of using pointer. Pointer would result in double free error. */ + model->materials[ modelMaterialId ].shader = material->shader; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_DIFFUSE ] = material->maps[ MATERIAL_MAP_DIFFUSE ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_METALNESS ] = material->maps[ MATERIAL_MAP_METALNESS ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_NORMAL ] = material->maps[ MATERIAL_MAP_NORMAL ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_ROUGHNESS ] = material->maps[ MATERIAL_MAP_ROUGHNESS ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_OCCLUSION ] = material->maps[ MATERIAL_MAP_OCCLUSION ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_EMISSION ] = material->maps[ MATERIAL_MAP_EMISSION ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_HEIGHT ] = material->maps[ MATERIAL_MAP_HEIGHT ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_CUBEMAP ] = material->maps[ MATERIAL_MAP_CUBEMAP ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_IRRADIANCE ] = material->maps[ MATERIAL_MAP_IRRADIANCE ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_PREFILTER ] = material->maps[ MATERIAL_MAP_PREFILTER ]; + model->materials[ modelMaterialId ].maps[ MATERIAL_MAP_BRDF ] = material->maps[ MATERIAL_MAP_BRDF ]; + + for ( int i = 0; i < 4; i++ ) { + model->materials[ modelMaterialId ].params[i] = material->params[i]; + } + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_SetModelMaterial( Model model, Material modelMaterial, Material material ) + +Set material for a mesh ( Mesh and material on this model ) + +- Failure return false +- Success return true +*/ +int lmodelsSetModelMeshMaterial( lua_State *L ) { + if ( !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_SetModelMeshMaterial( Model model, int meshId, int materialId )" ); + lua_pushboolean( L, false ); + return 1; + } + int materialId = lua_tointeger( L, -1 ); + int meshId = lua_tointeger( L, -2 ); + size_t modelId = lua_tointeger( L, -3 ); + + if ( !validModel( modelId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + SetModelMeshMaterial( state->models[ modelId ], meshId, materialId ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawBillboard( Camera camera, Texture2D texture, Vector3 position, float size, Color tint ) + +Draw a billboard texture + +- Failure return false +- Success return true +*/ +int lmodelsDrawBillboard( lua_State *L ) { + if ( !lua_isnumber( L, -5 ) || !lua_isnumber( L, -4 ) || !lua_istable( L, -3 ) + || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawBillboard( Camera camera, Texture2D texture, Vector3 position, float size, Color tint )" ); + lua_pushboolean( L, false ); + return 1; + } + Color tint = uluaGetColor( L ); + lua_pop( L, 1 ); + float size = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 position = uluaGetVector3( L ); + lua_pop( L, 1 ); + size_t texId = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + size_t cameraId = lua_tointeger( L, -1 ); + + if ( !validSourceTexture( texId ) || !validCamera3D( cameraId ) ) { + lua_pushboolean( L, false ); + return 1; + } + DrawBillboard( *state->camera3Ds[ cameraId ], *texturesGetSourceTexture( texId ), position, size, tint ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> success = RL_DrawBillboardRec( Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint ) + +Draw a billboard texture defined by source + +- Failure return false +- Success return true +*/ +int lmodelsDrawBillboardRec( lua_State *L ) { + if ( !lua_isnumber( L, -6 ) || !lua_isnumber( L, -5 ) || !lua_istable( L, -4 ) + || !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_DrawBillboardRec( Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint )" ); + lua_pushboolean( L, false ); + return 1; + } + Color tint = uluaGetColor( L ); + lua_pop( L, 1 ); + Vector2 size = uluaGetVector2( L ); + lua_pop( L, 1 ); + Vector3 position = uluaGetVector3( L ); + lua_pop( L, 1 ); + Rectangle source = uluaGetRectangle( L ); + lua_pop( L, 1 ); + size_t texId = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + size_t cameraId = lua_tointeger( L, -1 ); + + if ( !validSourceTexture( texId ) || !validCamera3D( cameraId ) ) { + lua_pushboolean( L, false ); + return 1; + } + DrawBillboardRec( *state->camera3Ds[ cameraId ], *texturesGetSourceTexture( texId ), source, position, size, tint ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +## Model - Animations +*/ + +/* +> animations, animationCount = RL_LoadModelAnimations( string fileName ) + +Load model animations from file + +- Failure return -1 +- Success return int, int +*/ +int lmodelsLoadModelAnimations( lua_State *L ) { + if ( !lua_isstring( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_LoadModelAnimations( string fileName )" ); + lua_pushinteger( L, -1 ); + return 1; + } + int i = 0; + + for ( i = 0; i < state->animationCount; i++ ) { + if ( state->animations[i] == NULL ) { + break; + } + } + state->animations[i] = malloc( sizeof( ModelAnimations ) ); + state->animations[i]->animations = LoadModelAnimations( lua_tostring( L, -1 ), &state->animations[i]->animCount ); + checkAnimationRealloc( i ); + + lua_pushinteger( L, i ); + lua_pushinteger( L, state->animations[i]->animCount ); + + return 2; +} + +/* +> success = RL_UpdateModelAnimation( Model model, ModelAnimations animations, int animation, int frame ) + +Update model animation pose + +- Failure return false +- Success return true +*/ +int lmodelsUpdateModelAnimation( lua_State *L ) { + if ( !lua_isnumber( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_UpdateModelAnimation( Model model, ModelAnimations animations, int animation, int frame )" ); + lua_pushboolean( L, false ); + return 1; + } + int frame = imax( 0, lua_tointeger( L, -1 ) ); + size_t animId = lua_tointeger( L, -3 ); + size_t modelId = lua_tointeger( L, -4 ); + + if ( !validModel( modelId ) || !validAnimation( animId ) ) { + lua_pushboolean( L, false ); + return 1; + } + + UpdateModelAnimation( *state->models[ modelId ], state->animations[ animId ]->animations[ lua_tointeger( L, -2 ) ], frame ); + lua_pushboolean( L, true ); + + return 1; +} + +/* +> boneCount = RL_GetModelAnimationBoneCount( ModelAnimations animations, int animation ) + +Return modelAnimation bone count + +- Failure return false +- Success return int +*/ +int lmodelsGetModelAnimationBoneCount( lua_State *L ) { + if ( !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GetModelAnimationBoneCount( ModelAnimations animations, int animation )" ); + lua_pushboolean( L, false ); + return 1; + } + size_t animId = lua_tointeger( L, -2 ); + + if ( !validAnimation( animId ) ) { + lua_pushboolean( L, false ); + return 1; + } + lua_pushinteger( L, state->animations[ animId ]->animations[ lua_tointeger( L, -1 ) ].boneCount ); + + return 1; +} + +/* +> frameCount = RL_GetModelAnimationFrameCount( ModelAnimations animations, int animation ) + +Return modelAnimation frame count + +- Failure return false +- Success return int +*/ +int lmodelsGetModelAnimationFrameCount( lua_State *L ) { + if ( !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GetModelAnimationFrameCount( ModelAnimations animations, int animation )" ); + lua_pushboolean( L, false ); + return 1; + } + size_t animId = lua_tointeger( L, -2 ); + + if ( !validAnimation( animId ) ) { + lua_pushboolean( L, false ); + return 1; + } + lua_pushinteger( L, state->animations[ animId ]->animations[ lua_tointeger( L, -1 ) ].frameCount ); + + return 1; +} + +/* +## Model - Collision +*/ + +/* +> collision = RL_CheckCollisionSpheres( Vector3 center1, float radius1, Vector3 center2, float radius2 ) + +Check collision between two spheres + +- Failure return nil +- Success return bool +*/ +int lmodelsCheckCollisionSpheres( lua_State *L ) { + if ( !lua_istable( L, -4 ) || !lua_isnumber( L, -3 ) || !lua_istable( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_CheckCollisionSpheres( Vector3 center1, float radius1, Vector3 center2, float radius2 )" ); + lua_pushnil( L ); + return 1; + } + float radius2 = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 center2 = uluaGetVector3( L ); + lua_pop( L, 1 ); + float radius1 = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 center1 = uluaGetVector3( L ); + + lua_pushboolean( L, CheckCollisionSpheres( center1, radius1, center2, radius2 ) ); + + return 1; +} + +/* +> collision = RL_CheckCollisionBoxes( BoundingBox box1, BoundingBox box2 ) + +Check collision between two bounding boxes + +- Failure return nil +- Success return bool +*/ +int lmodelsCheckCollisionBoxes( lua_State *L ) { + if ( !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_CheckCollisionBoxes( BoundingBox box1, BoundingBox box2 )" ); + lua_pushnil( L ); + return 1; + } + BoundingBox box2 = uluaGetBoundingBox( L ); + lua_pop( L, 1 ); + BoundingBox box1 = uluaGetBoundingBox( L ); + + lua_pushboolean( L, CheckCollisionBoxes( box1, box2 ) ); + + return 1; +} + +/* +> collision = RL_CheckCollisionBoxSphere( BoundingBox box, Vector3 center, float radius ) + +Check collision between box and sphere + +- Failure return nil +- Success return bool +*/ +int lmodelsCheckCollisionBoxSphere( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_CheckCollisionBoxSphere( BoundingBox box, Vector3 center, float radius )" ); + lua_pushnil( L ); + return 1; + } + float radius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 center = uluaGetVector3( L ); + lua_pop( L, 1 ); + BoundingBox box = uluaGetBoundingBox( L ); + + lua_pushboolean( L, CheckCollisionBoxSphere( box, center, radius ) ); + + return 1; +} + +/* +> rayCollision = RL_GetRayCollisionSphere( Ray ray, Vector3 center, float radius ) + +Get collision info between ray and sphere. ( RayCollision is Lua table of { hit, distance, point, normal } ) + +- Failure return nil +- Success return RayCollision +*/ +int lmodelsGetRayCollisionSphere( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GetRayCollisionSphere( Ray ray, Vector3 center, float radius )" ); + lua_pushnil( L ); + return 1; + } + float radius = lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + Vector3 center = uluaGetVector3( L ); + lua_pop( L, 1 ); + Ray ray = uluaGetRay( L ); + + uluaPushRayCollision( L, GetRayCollisionSphere( ray, center, radius ) ); + + return 1; +} + +/* +> rayCollision = RL_GetRayCollisionBox( Ray ray, BoundingBox box ) + +Get collision info between ray and box + +- Failure return nil +- Success return RayCollision +*/ +int lmodelsGetRayCollisionBox( lua_State *L ) { + if ( !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GetRayCollisionBox( Ray ray, BoundingBox box )" ); + lua_pushnil( L ); + return 1; + } + BoundingBox box = uluaGetBoundingBox( L ); + lua_pop( L, 1 ); + Ray ray = uluaGetRay( L ); + + uluaPushRayCollision( L, GetRayCollisionBox( ray, box ) ); + + return 1; +} + +/* +> rayCollision = RL_GetRayCollisionModel( Ray ray, Model model ) + +Get collision info between ray and model + +- Failure return nil +- Success return RayCollision +*/ +int lmodelsGetRayCollisionModel( lua_State *L ) { + if ( !lua_istable( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GetRayCollisionModel( Ray ray, Model model )" ); + lua_pushnil( L ); + return 1; + } + size_t modelId = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + Ray ray = uluaGetRay( L ); + + if ( !validModel( modelId ) ) { + lua_pushnil( L ); + return 1; + } + uluaPushRayCollision( L, GetRayCollisionModel( ray, *state->models[ modelId ] ) ); + + return 1; +} + +/* +> rayCollision = RL_GetRayCollisionMesh( Ray ray, Mesh mesh, Matrix transform ) + +Get collision info between ray and mesh + +- Failure return nil +- Success return RayCollision +*/ +int lmodelsGetRayCollisionMesh( lua_State *L ) { + if ( !lua_istable( L, -3 ) || !lua_isnumber( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GetRayCollisionMesh( Ray ray, Mesh mesh, Matrix transform )" ); + lua_pushnil( L ); + return 1; + } + Matrix transform = uluaGetMatrix( L ); + lua_pop( L, 1 ); + size_t meshId = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + Ray ray = uluaGetRay( L ); + + if ( !validMesh( meshId ) ) { + lua_pushnil( L ); + return 1; + } + uluaPushRayCollision( L, GetRayCollisionMesh( ray, *state->meshes[ meshId ], transform ) ); + + return 1; +} + +/* +> rayCollision = RL_GetRayCollisionTriangle( Ray ray, Vector3 p1, Vector3 p2, Vector3 p3 ) + +Get collision info between ray and triangle + +- Failure return nil +- Success return RayCollision +*/ +int lmodelsGetRayCollisionTriangle( lua_State *L ) { + if ( !lua_istable( L, -4 ) || !lua_istable( L, -3 ) || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GetRayCollisionTriangle( Ray ray, Vector3 p1, Vector3 p2, Vector3 p3 )" ); + lua_pushnil( L ); + return 1; + } + Vector3 p3 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 p2 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 p1 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Ray ray = uluaGetRay( L ); + + uluaPushRayCollision( L, GetRayCollisionTriangle( ray, p1, p2, p3 ) ); + + return 1; +} + +/* +> rayCollision = RL_GetRayCollisionQuad( Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4 ) + +Get collision info between ray and quad + +- Failure return nil +- Success return RayCollision +*/ +int lmodelsGetRayCollisionQuad( lua_State *L ) { + if ( !lua_istable( L, -5 ) || !lua_istable( L, -4 ) || !lua_istable( L, -3 ) + || !lua_istable( L, -2 ) || !lua_istable( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_GetRayCollisionQuad( Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4 )" ); + lua_pushnil( L ); + return 1; + } + Vector3 p4 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 p3 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 p2 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Vector3 p1 = uluaGetVector3( L ); + lua_pop( L, 1 ); + Ray ray = uluaGetRay( L ); + + uluaPushRayCollision( L, GetRayCollisionQuad( ray, p1, p2, p3, p4 ) ); + + return 1; +} + |
