2014-09-17 00:51:31 +04:00
/**********************************************************************************************
2013-11-19 02:38:44 +04:00
*
2013-11-23 16:30:54 +04:00
* raylib . models
2013-11-19 02:38:44 +04:00
*
2013-11-23 16:30:54 +04:00
* Basic functions to draw 3 d shapes and load / draw 3 d models ( . OBJ )
2013-11-19 02:38:44 +04:00
*
2015-07-29 22:43:30 +03:00
* Copyright ( c ) 2014 Ramon Santamaria ( @ raysan5 )
2014-09-03 18:51:28 +04:00
*
* This software is provided " as-is " , without any express or implied warranty . In no event
2013-11-23 16:30:54 +04:00
* will the authors be held liable for any damages arising from the use of this software .
2013-11-19 02:38:44 +04:00
*
2014-09-03 18:51:28 +04:00
* Permission is granted to anyone to use this software for any purpose , including commercial
2013-11-23 16:30:54 +04:00
* applications , and to alter it and redistribute it freely , subject to the following restrictions :
2013-11-19 02:38:44 +04:00
*
2014-09-03 18:51:28 +04:00
* 1. The origin of this software must not be misrepresented ; you must not claim that you
* wrote the original software . If you use this software in a product , an acknowledgment
2013-11-23 16:30:54 +04:00
* in the product documentation would be appreciated but is not required .
2013-11-19 02:38:44 +04:00
*
2013-11-23 16:30:54 +04:00
* 2. Altered source versions must be plainly marked as such , and must not be misrepresented
* as being the original software .
2013-11-19 02:38:44 +04:00
*
2013-11-23 16:30:54 +04:00
* 3. This notice may not be removed or altered from any source distribution .
2013-11-19 02:38:44 +04:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "raylib.h"
2014-09-17 00:51:31 +04:00
# if defined(PLATFORM_ANDROID)
# include "utils.h" // Android fopen function map
# endif
# include <stdio.h> // Standard input/output functions, used to read model files data
# include <stdlib.h> // Declares malloc() and free() for memory management
# include <string.h> // Required for strcmp()
# include <math.h> // Used for sin, cos, tan
2014-03-25 15:40:35 +04:00
2014-09-17 00:51:31 +04:00
# include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
2016-01-20 20:20:05 +03:00
# include "raymath.h" // Required for data type Matrix and Matrix functions
2013-11-19 02:38:44 +04:00
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
2015-03-02 22:52:58 +03:00
# define CUBIC_MAP_HALF_BLOCK_SIZE 0.5
2013-11-19 02:38:44 +04:00
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
2014-04-04 22:11:57 +04:00
// ...
2013-11-19 02:38:44 +04:00
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
2014-12-31 20:03:32 +03:00
extern unsigned int whiteTexture ;
2013-11-19 02:38:44 +04:00
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
2016-01-18 15:36:18 +03:00
static Mesh LoadOBJ ( const char * fileName ) ;
2013-11-19 02:38:44 +04:00
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Draw cube
2014-03-16 23:59:02 +04:00
// NOTE: Cube position is the center position
2015-12-21 18:42:13 +03:00
void DrawCube ( Vector3 position , float width , float height , float length , Color color )
2013-11-19 02:38:44 +04:00
{
2014-12-16 13:15:56 +03:00
float x = 0.0f ;
float y = 0.0f ;
float z = 0.0f ;
2013-11-23 16:30:54 +04:00
2014-03-25 15:40:35 +04:00
rlPushMatrix ( ) ;
2014-04-04 22:11:57 +04:00
2014-04-19 18:36:49 +04:00
// NOTE: Be careful! Function order matters (rotate -> scale -> translate)
2014-12-16 13:15:56 +03:00
rlTranslatef ( position . x , position . y , position . z ) ;
2014-04-19 18:36:49 +04:00
//rlScalef(2.0f, 2.0f, 2.0f);
2014-04-04 22:11:57 +04:00
//rlRotatef(45, 0, 1, 0);
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlBegin ( RL_TRIANGLES ) ;
2014-09-03 18:51:28 +04:00
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2014-04-04 22:11:57 +04:00
// Front Face -----------------------------------------------------
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left
rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right
rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left
2014-09-03 18:51:28 +04:00
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Top Right
rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left
rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Back Face ------------------------------------------------------
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Left
rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left
rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right
2014-09-03 18:51:28 +04:00
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right
rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right
rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Top Face -------------------------------------------------------
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left
rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Bottom Left
rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Bottom Right
2014-09-03 18:51:28 +04:00
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right
rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left
rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Bottom Right
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Bottom Face ----------------------------------------------------
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Top Left
rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right
rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left
2014-09-03 18:51:28 +04:00
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Top Right
rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right
rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Top Left
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Right face -----------------------------------------------------
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right
rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right
rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left
2014-09-03 18:51:28 +04:00
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left
rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right
rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Left Face ------------------------------------------------------
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right
rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left
rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right
2014-09-03 18:51:28 +04:00
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left
rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left
rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right
2014-04-04 22:11:57 +04:00
rlEnd ( ) ;
rlPopMatrix ( ) ;
}
// Draw cube (Vector version)
void DrawCubeV ( Vector3 position , Vector3 size , Color color )
{
DrawCube ( position , size . x , size . y , size . z , color ) ;
}
// Draw cube wires
2015-12-21 18:42:13 +03:00
void DrawCubeWires ( Vector3 position , float width , float height , float length , Color color )
2014-04-04 22:11:57 +04:00
{
2014-12-16 13:15:56 +03:00
float x = 0.0f ;
float y = 0.0f ;
float z = 0.0f ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlPushMatrix ( ) ;
2014-12-16 13:15:56 +03:00
rlTranslatef ( position . x , position . y , position . z ) ;
2014-04-04 22:11:57 +04:00
//rlRotatef(45, 0, 1, 0);
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlBegin ( RL_LINES ) ;
2014-09-03 18:51:28 +04:00
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2014-04-04 22:11:57 +04:00
// Front Face -----------------------------------------------------
// Bottom Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left
rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Left Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right
rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Top Right
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Top Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Top Right
rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Right Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left
rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Back Face ------------------------------------------------------
// Bottom Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Left
rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Left Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right
rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Top Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right
rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Right Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left
rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Left
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Top Face -------------------------------------------------------
// Left Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left Front
rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left Back
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Right Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Top Right Front
rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right Back
2014-04-04 22:11:57 +04:00
// Bottom Face ---------------------------------------------------
// Left Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Top Left Front
rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Top Left Back
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Right Line
2015-12-21 18:42:13 +03:00
rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Top Right Front
rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Top Right Back
2014-04-04 22:11:57 +04:00
rlEnd ( ) ;
rlPopMatrix ( ) ;
}
// Draw cube
// NOTE: Cube position is the center position
2015-12-21 18:42:13 +03:00
void DrawCubeTexture ( Texture2D texture , Vector3 position , float width , float height , float length , Color color )
2014-04-04 22:11:57 +04:00
{
float x = position . x ;
float y = position . y ;
float z = position . z ;
2014-04-19 18:36:49 +04:00
rlEnableTexture ( texture . id ) ;
2014-09-03 18:51:28 +04:00
//rlPushMatrix();
2014-03-25 15:40:35 +04:00
// NOTE: Be careful! Function order matters (scale, translate, rotate)
//rlScalef(2.0f, 2.0f, 2.0f);
//rlTranslatef(2.0f, 0.0f, 0.0f);
2014-04-04 22:11:57 +04:00
//rlRotatef(45, 0, 1, 0);
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
rlBegin ( RL_QUADS ) ;
2014-09-03 18:51:28 +04:00
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2013-11-23 16:30:54 +04:00
// Front Face
2014-03-25 15:40:35 +04:00
rlNormal3f ( 0.0f , 0.0f , 1.0f ) ; // Normal Pointing Towards Viewer
2015-12-21 18:42:13 +03:00
rlTexCoord2f ( 0.0f , 0.0f ) ; rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left Of The Texture and Quad
rlTexCoord2f ( 1.0f , 0.0f ) ; rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right Of The Texture and Quad
rlTexCoord2f ( 1.0f , 1.0f ) ; rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Top Right Of The Texture and Quad
rlTexCoord2f ( 0.0f , 1.0f ) ; rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left Of The Texture and Quad
2013-11-23 16:30:54 +04:00
// Back Face
2014-03-25 15:40:35 +04:00
rlNormal3f ( 0.0f , 0.0f , - 1.0f ) ; // Normal Pointing Away From Viewer
2015-12-21 18:42:13 +03:00
rlTexCoord2f ( 1.0f , 0.0f ) ; rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right Of The Texture and Quad
rlTexCoord2f ( 1.0f , 1.0f ) ; rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right Of The Texture and Quad
rlTexCoord2f ( 0.0f , 1.0f ) ; rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left Of The Texture and Quad
rlTexCoord2f ( 0.0f , 0.0f ) ; rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Left Of The Texture and Quad
2013-11-23 16:30:54 +04:00
// Top Face
2014-03-25 15:40:35 +04:00
rlNormal3f ( 0.0f , 1.0f , 0.0f ) ; // Normal Pointing Up
2015-12-21 18:42:13 +03:00
rlTexCoord2f ( 0.0f , 1.0f ) ; rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left Of The Texture and Quad
rlTexCoord2f ( 0.0f , 0.0f ) ; rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Bottom Left Of The Texture and Quad
rlTexCoord2f ( 1.0f , 0.0f ) ; rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Bottom Right Of The Texture and Quad
rlTexCoord2f ( 1.0f , 1.0f ) ; rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right Of The Texture and Quad
2013-11-23 16:30:54 +04:00
// Bottom Face
2014-03-25 15:40:35 +04:00
rlNormal3f ( 0.0f , - 1.0f , 0.0f ) ; // Normal Pointing Down
2015-12-21 18:42:13 +03:00
rlTexCoord2f ( 1.0f , 1.0f ) ; rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Top Right Of The Texture and Quad
rlTexCoord2f ( 0.0f , 1.0f ) ; rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Top Left Of The Texture and Quad
rlTexCoord2f ( 0.0f , 0.0f ) ; rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left Of The Texture and Quad
rlTexCoord2f ( 1.0f , 0.0f ) ; rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right Of The Texture and Quad
2013-11-23 16:30:54 +04:00
// Right face
2014-03-25 15:40:35 +04:00
rlNormal3f ( 1.0f , 0.0f , 0.0f ) ; // Normal Pointing Right
2015-12-21 18:42:13 +03:00
rlTexCoord2f ( 1.0f , 0.0f ) ; rlVertex3f ( x + width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Right Of The Texture and Quad
rlTexCoord2f ( 1.0f , 1.0f ) ; rlVertex3f ( x + width / 2 , y + height / 2 , z - length / 2 ) ; // Top Right Of The Texture and Quad
rlTexCoord2f ( 0.0f , 1.0f ) ; rlVertex3f ( x + width / 2 , y + height / 2 , z + length / 2 ) ; // Top Left Of The Texture and Quad
rlTexCoord2f ( 0.0f , 0.0f ) ; rlVertex3f ( x + width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Left Of The Texture and Quad
2013-11-23 16:30:54 +04:00
// Left Face
2014-03-25 15:40:35 +04:00
rlNormal3f ( - 1.0f , 0.0f , 0.0f ) ; // Normal Pointing Left
2015-12-21 18:42:13 +03:00
rlTexCoord2f ( 0.0f , 0.0f ) ; rlVertex3f ( x - width / 2 , y - height / 2 , z - length / 2 ) ; // Bottom Left Of The Texture and Quad
rlTexCoord2f ( 1.0f , 0.0f ) ; rlVertex3f ( x - width / 2 , y - height / 2 , z + length / 2 ) ; // Bottom Right Of The Texture and Quad
rlTexCoord2f ( 1.0f , 1.0f ) ; rlVertex3f ( x - width / 2 , y + height / 2 , z + length / 2 ) ; // Top Right Of The Texture and Quad
rlTexCoord2f ( 0.0f , 1.0f ) ; rlVertex3f ( x - width / 2 , y + height / 2 , z - length / 2 ) ; // Top Left Of The Texture and Quad
2014-03-25 15:40:35 +04:00
rlEnd ( ) ;
2014-04-19 18:36:49 +04:00
//rlPopMatrix();
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlDisableTexture ( ) ;
2013-11-19 02:38:44 +04:00
}
// Draw sphere
void DrawSphere ( Vector3 centerPos , float radius , Color color )
{
2013-11-23 16:30:54 +04:00
DrawSphereEx ( centerPos , radius , 16 , 16 , color ) ;
2013-11-19 02:38:44 +04:00
}
// Draw sphere with extended parameters
void DrawSphereEx ( Vector3 centerPos , float radius , int rings , int slices , Color color )
{
2014-03-25 15:40:35 +04:00
rlPushMatrix ( ) ;
rlTranslatef ( centerPos . x , centerPos . y , centerPos . z ) ;
rlScalef ( radius , radius , radius ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlBegin ( RL_TRIANGLES ) ;
2014-03-25 15:40:35 +04:00
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2014-09-03 18:51:28 +04:00
2014-06-15 02:50:09 +04:00
for ( int i = 0 ; i < ( rings + 2 ) ; i + + )
2013-11-23 16:30:54 +04:00
{
2014-04-04 22:11:57 +04:00
for ( int j = 0 ; j < slices ; j + + )
2013-11-23 16:30:54 +04:00
{
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) * sin ( DEG2RAD * ( j * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) ,
2014-06-09 18:33:53 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) * cos ( DEG2RAD * ( j * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * sin ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) ,
2014-06-09 18:33:53 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * cos ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * sin ( DEG2RAD * ( j * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) ,
2014-06-09 18:33:53 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * cos ( DEG2RAD * ( j * 360 / slices ) ) ) ;
2014-04-04 22:11:57 +04:00
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) * sin ( DEG2RAD * ( j * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) ,
2014-06-09 18:33:53 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) * cos ( DEG2RAD * ( j * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i ) ) ) * sin ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i ) ) ) ,
2014-06-09 18:33:53 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i ) ) ) * cos ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * sin ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) ,
2014-06-09 18:33:53 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * cos ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ) ;
2013-11-23 16:30:54 +04:00
}
}
2014-03-25 15:40:35 +04:00
rlEnd ( ) ;
rlPopMatrix ( ) ;
2013-11-19 02:38:44 +04:00
}
// Draw sphere wires
2014-04-04 22:11:57 +04:00
void DrawSphereWires ( Vector3 centerPos , float radius , int rings , int slices , Color color )
2013-11-19 02:38:44 +04:00
{
2014-04-04 22:11:57 +04:00
rlPushMatrix ( ) ;
2014-06-09 18:33:53 +04:00
rlTranslatef ( centerPos . x , centerPos . y , centerPos . z ) ;
2014-06-15 02:50:09 +04:00
rlScalef ( radius , radius , radius ) ;
2015-04-06 15:02:29 +03:00
2014-04-04 22:11:57 +04:00
rlBegin ( RL_LINES ) ;
2014-03-25 15:40:35 +04:00
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2014-09-03 18:51:28 +04:00
2014-06-09 18:33:53 +04:00
for ( int i = 0 ; i < ( rings + 2 ) ; i + + )
2014-03-25 15:40:35 +04:00
{
2014-04-04 22:11:57 +04:00
for ( int j = 0 ; j < slices ; j + + )
{
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) * sin ( DEG2RAD * ( j * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) ,
2014-06-15 02:50:09 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) * cos ( DEG2RAD * ( j * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * sin ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) ,
2014-06-15 02:50:09 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * cos ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * sin ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) ,
2014-06-15 02:50:09 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * cos ( DEG2RAD * ( ( j + 1 ) * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * sin ( DEG2RAD * ( j * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) ,
2014-06-15 02:50:09 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * cos ( DEG2RAD * ( j * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * sin ( DEG2RAD * ( j * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) ,
2014-06-15 02:50:09 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * ( i + 1 ) ) ) * cos ( DEG2RAD * ( j * 360 / slices ) ) ) ;
2014-09-03 18:51:28 +04:00
rlVertex3f ( cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) * sin ( DEG2RAD * ( j * 360 / slices ) ) ,
sin ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) ,
2014-06-15 02:50:09 +04:00
cos ( DEG2RAD * ( 270 + ( 180 / ( rings + 1 ) ) * i ) ) * cos ( DEG2RAD * ( j * 360 / slices ) ) ) ;
2014-04-04 22:11:57 +04:00
}
2014-03-25 15:40:35 +04:00
}
rlEnd ( ) ;
2014-04-04 22:11:57 +04:00
rlPopMatrix ( ) ;
}
// Draw a cylinder
// NOTE: It could be also used for pyramid and cone
void DrawCylinder ( Vector3 position , float radiusTop , float radiusBottom , float height , int sides , Color color )
{
if ( sides < 3 ) sides = 3 ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlPushMatrix ( ) ;
rlTranslatef ( position . x , position . y , position . z ) ;
rlBegin ( RL_TRIANGLES ) ;
2014-03-25 15:40:35 +04:00
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2014-04-04 22:11:57 +04:00
if ( radiusTop > 0 )
2014-03-25 15:40:35 +04:00
{
2014-04-04 22:11:57 +04:00
// Draw Body -------------------------------------------------------------------------------------
for ( int i = 0 ; i < 360 ; i + = 360 / sides )
{
rlVertex3f ( sin ( DEG2RAD * i ) * radiusBottom , 0 , cos ( DEG2RAD * i ) * radiusBottom ) ; //Bottom Left
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom , 0 , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom ) ; //Bottom Right
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop , height , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop ) ; //Top Right
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlVertex3f ( sin ( DEG2RAD * i ) * radiusTop , height , cos ( DEG2RAD * i ) * radiusTop ) ; //Top Left
rlVertex3f ( sin ( DEG2RAD * i ) * radiusBottom , 0 , cos ( DEG2RAD * i ) * radiusBottom ) ; //Bottom Left
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop , height , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop ) ; //Top Right
}
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Draw Cap --------------------------------------------------------------------------------------
for ( int i = 0 ; i < 360 ; i + = 360 / sides )
{
rlVertex3f ( 0 , height , 0 ) ;
rlVertex3f ( sin ( DEG2RAD * i ) * radiusTop , height , cos ( DEG2RAD * i ) * radiusTop ) ;
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop , height , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop ) ;
}
2014-03-25 15:40:35 +04:00
}
2014-04-04 22:11:57 +04:00
else
2014-03-25 15:40:35 +04:00
{
2014-04-04 22:11:57 +04:00
// Draw Cone -------------------------------------------------------------------------------------
for ( int i = 0 ; i < 360 ; i + = 360 / sides )
{
rlVertex3f ( 0 , height , 0 ) ;
rlVertex3f ( sin ( DEG2RAD * i ) * radiusBottom , 0 , cos ( DEG2RAD * i ) * radiusBottom ) ;
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom , 0 , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom ) ;
}
2014-03-25 15:40:35 +04:00
}
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// Draw Base -----------------------------------------------------------------------------------------
for ( int i = 0 ; i < 360 ; i + = 360 / sides )
2014-03-25 15:40:35 +04:00
{
2014-04-04 22:11:57 +04:00
rlVertex3f ( 0 , 0 , 0 ) ;
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom , 0 , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom ) ;
rlVertex3f ( sin ( DEG2RAD * i ) * radiusBottom , 0 , cos ( DEG2RAD * i ) * radiusBottom ) ;
2014-03-25 15:40:35 +04:00
}
2014-09-03 18:51:28 +04:00
rlEnd ( ) ;
2014-04-04 22:11:57 +04:00
rlPopMatrix ( ) ;
}
// Draw a wired cylinder
// NOTE: It could be also used for pyramid and cone
void DrawCylinderWires ( Vector3 position , float radiusTop , float radiusBottom , float height , int sides , Color color )
{
if ( sides < 3 ) sides = 3 ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlPushMatrix ( ) ;
rlTranslatef ( position . x , position . y , position . z ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlBegin ( RL_LINES ) ;
2014-03-25 15:40:35 +04:00
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
for ( int i = 0 ; i < 360 ; i + = 360 / sides )
2014-03-25 15:40:35 +04:00
{
2014-04-04 22:11:57 +04:00
rlVertex3f ( sin ( DEG2RAD * i ) * radiusBottom , 0 , cos ( DEG2RAD * i ) * radiusBottom ) ;
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom , 0 , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom , 0 , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusBottom ) ;
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop , height , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlVertex3f ( sin ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop , height , cos ( DEG2RAD * ( i + 360 / sides ) ) * radiusTop ) ;
rlVertex3f ( sin ( DEG2RAD * i ) * radiusTop , height , cos ( DEG2RAD * i ) * radiusTop ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlVertex3f ( sin ( DEG2RAD * i ) * radiusTop , height , cos ( DEG2RAD * i ) * radiusTop ) ;
rlVertex3f ( sin ( DEG2RAD * i ) * radiusBottom , 0 , cos ( DEG2RAD * i ) * radiusBottom ) ;
2014-03-25 15:40:35 +04:00
}
rlEnd ( ) ;
2014-04-04 22:11:57 +04:00
rlPopMatrix ( ) ;
2013-11-19 02:38:44 +04:00
}
// Draw a plane
2015-04-06 15:02:29 +03:00
void DrawPlane ( Vector3 centerPos , Vector2 size , Color color )
2013-11-19 02:38:44 +04:00
{
2015-04-06 15:02:29 +03:00
// NOTE: Plane is always created on XZ ground
2014-03-25 15:40:35 +04:00
rlPushMatrix ( ) ;
rlTranslatef ( centerPos . x , centerPos . y , centerPos . z ) ;
2014-04-19 18:36:49 +04:00
rlScalef ( size . x , 1.0f , size . y ) ;
2014-09-03 18:51:28 +04:00
2016-03-01 21:00:12 +03:00
rlBegin ( RL_TRIANGLES ) ;
2014-03-25 15:40:35 +04:00
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2014-09-03 18:51:28 +04:00
rlNormal3f ( 0.0f , 1.0f , 0.0f ) ;
2014-09-17 00:51:31 +04:00
2016-03-01 21:00:12 +03:00
rlVertex3f ( 0.5f , 0.0f , - 0.5f ) ;
rlVertex3f ( - 0.5f , 0.0f , - 0.5f ) ;
rlVertex3f ( - 0.5f , 0.0f , 0.5f ) ;
2013-11-19 02:38:44 +04:00
2016-03-01 21:00:12 +03:00
rlVertex3f ( - 0.5f , 0.0f , 0.5f ) ;
rlVertex3f ( 0.5f , 0.0f , 0.5f ) ;
rlVertex3f ( 0.5f , 0.0f , - 0.5f ) ;
rlEnd ( ) ;
rlPopMatrix ( ) ;
2013-11-19 02:38:44 +04:00
}
2015-04-06 15:02:29 +03:00
// Draw a ray line
2015-03-02 22:52:58 +03:00
void DrawRay ( Ray ray , Color color )
{
float scale = 10000 ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
rlBegin ( RL_LINES ) ;
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
rlVertex3f ( ray . position . x , ray . position . y , ray . position . z ) ;
rlVertex3f ( ray . position . x + ray . direction . x * scale , ray . position . y + ray . direction . y * scale , ray . position . z + ray . direction . z * scale ) ;
rlEnd ( ) ;
}
2013-11-19 02:38:44 +04:00
// Draw a grid centered at (0, 0, 0)
void DrawGrid ( int slices , float spacing )
{
2013-11-23 16:30:54 +04:00
int halfSlices = slices / 2 ;
2014-03-25 15:40:35 +04:00
rlBegin ( RL_LINES ) ;
for ( int i = - halfSlices ; i < = halfSlices ; i + + )
{
if ( i = = 0 )
2013-11-23 16:30:54 +04:00
{
2014-03-25 15:40:35 +04:00
rlColor3f ( 0.5f , 0.5f , 0.5f ) ;
rlColor3f ( 0.5f , 0.5f , 0.5f ) ;
rlColor3f ( 0.5f , 0.5f , 0.5f ) ;
rlColor3f ( 0.5f , 0.5f , 0.5f ) ;
2013-11-23 16:30:54 +04:00
}
2014-03-25 15:40:35 +04:00
else
{
rlColor3f ( 0.75f , 0.75f , 0.75f ) ;
rlColor3f ( 0.75f , 0.75f , 0.75f ) ;
rlColor3f ( 0.75f , 0.75f , 0.75f ) ;
rlColor3f ( 0.75f , 0.75f , 0.75f ) ;
}
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
rlVertex3f ( ( float ) i * spacing , 0.0f , ( float ) - halfSlices * spacing ) ;
rlVertex3f ( ( float ) i * spacing , 0.0f , ( float ) halfSlices * spacing ) ;
rlVertex3f ( ( float ) - halfSlices * spacing , 0.0f , ( float ) i * spacing ) ;
rlVertex3f ( ( float ) halfSlices * spacing , 0.0f , ( float ) i * spacing ) ;
}
rlEnd ( ) ;
2013-11-19 02:38:44 +04:00
}
2014-04-04 22:11:57 +04:00
// Draw gizmo
void DrawGizmo ( Vector3 position )
2013-11-19 02:38:44 +04:00
{
2013-11-23 16:30:54 +04:00
// NOTE: RGB = XYZ
2015-12-21 18:42:13 +03:00
float length = 1.0f ;
2014-04-04 22:11:57 +04:00
2014-03-25 15:40:35 +04:00
rlPushMatrix ( ) ;
rlTranslatef ( position . x , position . y , position . z ) ;
2014-04-04 22:11:57 +04:00
//rlRotatef(rotation, 0, 1, 0);
2015-12-21 18:42:13 +03:00
rlScalef ( length , length , length ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlBegin ( RL_LINES ) ;
rlColor3f ( 1.0f , 0.0f , 0.0f ) ; rlVertex3f ( 0.0f , 0.0f , 0.0f ) ;
rlColor3f ( 1.0f , 0.0f , 0.0f ) ; rlVertex3f ( 1.0f , 0.0f , 0.0f ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlColor3f ( 0.0f , 1.0f , 0.0f ) ; rlVertex3f ( 0.0f , 0.0f , 0.0f ) ;
rlColor3f ( 0.0f , 1.0f , 0.0f ) ; rlVertex3f ( 0.0f , 1.0f , 0.0f ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlColor3f ( 0.0f , 0.0f , 1.0f ) ; rlVertex3f ( 0.0f , 0.0f , 0.0f ) ;
rlColor3f ( 0.0f , 0.0f , 1.0f ) ; rlVertex3f ( 0.0f , 0.0f , 1.0f ) ;
2014-09-03 18:51:28 +04:00
rlEnd ( ) ;
2014-04-04 22:11:57 +04:00
rlPopMatrix ( ) ;
}
2015-04-06 15:02:29 +03:00
// Load a 3d model (from file)
2014-09-03 18:51:28 +04:00
Model LoadModel ( const char * fileName )
2013-11-19 02:38:44 +04:00
{
2016-01-23 15:22:13 +03:00
Model model = { 0 } ;
2016-01-18 15:36:18 +03:00
Mesh mesh = { 0 } ;
2015-08-03 18:27:04 +03:00
2015-11-05 14:28:45 +03:00
// NOTE: Initialize default data for model in case loading fails, maybe a cube?
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
if ( strcmp ( GetExtension ( fileName ) , " obj " ) = = 0 ) mesh = LoadOBJ ( fileName ) ;
2014-09-03 18:51:28 +04:00
else TraceLog ( WARNING , " [%s] Model extension not recognized, it can't be loaded " , fileName ) ;
2014-04-04 22:11:57 +04:00
2016-01-18 15:36:18 +03:00
// NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct
2015-08-03 18:27:04 +03:00
2016-01-18 15:36:18 +03:00
if ( mesh . vertexCount = = 0 )
2015-08-03 18:27:04 +03:00
{
TraceLog ( WARNING , " Model could not be loaded " ) ;
}
else
2015-01-18 12:57:30 +03:00
{
2015-08-03 18:27:04 +03:00
// NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel()
2016-01-18 15:36:18 +03:00
model = rlglLoadModel ( mesh ) ; // Upload vertex data to GPU
2015-08-03 18:27:04 +03:00
2016-03-01 17:37:01 +03:00
// Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM
2015-12-30 15:35:03 +03:00
// NOTE 1: We don't need CPU vertex data on OpenGL 3.3 or ES2... for static meshes...
// NOTE 2: ...but we could keep CPU vertex data in case we need to update the mesh
/*
2015-08-03 18:27:04 +03:00
if ( rlGetVersion ( ) ! = OPENGL_11 )
{
2016-01-18 15:36:18 +03:00
free ( mesh . vertices ) ;
free ( mesh . texcoords ) ;
free ( mesh . normals ) ;
free ( mesh . colors ) ;
2015-08-03 18:27:04 +03:00
}
2015-12-30 15:35:03 +03:00
*/
2015-01-18 12:57:30 +03:00
}
2014-03-25 15:40:35 +04:00
2013-11-23 16:30:54 +04:00
return model ;
2013-11-19 02:38:44 +04:00
}
2015-04-06 15:02:29 +03:00
// Load a 3d model (from vertex data)
2016-01-18 15:36:18 +03:00
Model LoadModelEx ( Mesh data )
2015-04-06 15:02:29 +03:00
{
Model model ;
// NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel()
model = rlglLoadModel ( data ) ; // Upload vertex data to GPU
// NOTE: Vertex data is managed externally, must be deallocated manually
return model ;
}
2013-11-30 21:12:40 +04:00
// Load a heightmap image as a 3d model
2016-02-11 17:51:04 +03:00
// NOTE: model map size is defined in generic units
Model LoadHeightmap ( Image heightmap , Vector3 size )
2013-11-30 21:12:40 +04:00
{
2016-02-11 17:51:04 +03:00
# define GRAY_VALUE(c) ((c.r+c.g+c.b) / 3)
2016-01-18 15:36:18 +03:00
Mesh mesh ;
2014-04-04 22:11:57 +04:00
2013-11-30 21:12:40 +04:00
int mapX = heightmap . width ;
2014-03-16 23:59:02 +04:00
int mapZ = heightmap . height ;
2015-05-05 00:46:31 +03:00
2016-02-11 17:51:04 +03:00
Color * pixels = GetImageData ( heightmap ) ;
2014-09-03 18:51:28 +04:00
2013-11-30 21:12:40 +04:00
// NOTE: One vertex per pixel
int numTriangles = ( mapX - 1 ) * ( mapZ - 1 ) * 2 ; // One quad every four pixels
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
mesh . vertexCount = numTriangles * 3 ;
2013-11-30 21:12:40 +04:00
2016-01-18 15:36:18 +03:00
mesh . vertices = ( float * ) malloc ( mesh . vertexCount * 3 * sizeof ( float ) ) ;
mesh . normals = ( float * ) malloc ( mesh . vertexCount * 3 * sizeof ( float ) ) ;
mesh . texcoords = ( float * ) malloc ( mesh . vertexCount * 2 * sizeof ( float ) ) ;
mesh . colors = ( unsigned char * ) malloc ( mesh . vertexCount * 4 * sizeof ( unsigned char ) ) ; // Not used...
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
int vCounter = 0 ; // Used to count vertices float by float
int tcCounter = 0 ; // Used to count texcoords float by float
int nCounter = 0 ; // Used to count normals float by float
2014-09-03 18:51:28 +04:00
2014-01-29 00:21:29 +04:00
int trisCounter = 0 ;
2014-09-03 18:51:28 +04:00
2016-02-11 17:51:04 +03:00
Vector3 scaleFactor = { size . x / mapX , size . y / 255.0f , size . z / mapZ } ;
2013-11-30 21:12:40 +04:00
2014-03-16 23:59:02 +04:00
for ( int z = 0 ; z < mapZ - 1 ; z + + )
{
for ( int x = 0 ; x < mapX - 1 ; x + + )
{
// Fill vertices array with data
2014-01-29 00:21:29 +04:00
//----------------------------------------------------------
2014-09-03 18:51:28 +04:00
2014-01-29 00:21:29 +04:00
// one triangle - 3 vertex
2016-02-11 17:51:04 +03:00
mesh . vertices [ vCounter ] = ( float ) x * scaleFactor . x ;
mesh . vertices [ vCounter + 1 ] = ( float ) GRAY_VALUE ( pixels [ x + z * mapX ] ) * scaleFactor . y ;
mesh . vertices [ vCounter + 2 ] = ( float ) z * scaleFactor . z ;
2014-09-03 18:51:28 +04:00
2016-02-11 17:51:04 +03:00
mesh . vertices [ vCounter + 3 ] = ( float ) x * scaleFactor . x ;
mesh . vertices [ vCounter + 4 ] = ( float ) GRAY_VALUE ( pixels [ x + ( z + 1 ) * mapX ] ) * scaleFactor . y ;
mesh . vertices [ vCounter + 5 ] = ( float ) ( z + 1 ) * scaleFactor . z ;
2014-09-03 18:51:28 +04:00
2016-02-11 17:51:04 +03:00
mesh . vertices [ vCounter + 6 ] = ( float ) ( x + 1 ) * scaleFactor . x ;
mesh . vertices [ vCounter + 7 ] = ( float ) GRAY_VALUE ( pixels [ ( x + 1 ) + z * mapX ] ) * scaleFactor . y ;
mesh . vertices [ vCounter + 8 ] = ( float ) z * scaleFactor . z ;
2014-09-03 18:51:28 +04:00
2014-01-29 00:21:29 +04:00
// another triangle - 3 vertex
2016-01-18 15:36:18 +03:00
mesh . vertices [ vCounter + 9 ] = mesh . vertices [ vCounter + 6 ] ;
mesh . vertices [ vCounter + 10 ] = mesh . vertices [ vCounter + 7 ] ;
mesh . vertices [ vCounter + 11 ] = mesh . vertices [ vCounter + 8 ] ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
mesh . vertices [ vCounter + 12 ] = mesh . vertices [ vCounter + 3 ] ;
mesh . vertices [ vCounter + 13 ] = mesh . vertices [ vCounter + 4 ] ;
mesh . vertices [ vCounter + 14 ] = mesh . vertices [ vCounter + 5 ] ;
2014-09-03 18:51:28 +04:00
2016-02-11 17:51:04 +03:00
mesh . vertices [ vCounter + 15 ] = ( float ) ( x + 1 ) * scaleFactor . x ;
mesh . vertices [ vCounter + 16 ] = ( float ) GRAY_VALUE ( pixels [ ( x + 1 ) + ( z + 1 ) * mapX ] ) * scaleFactor . y ;
mesh . vertices [ vCounter + 17 ] = ( float ) ( z + 1 ) * scaleFactor . z ;
2014-04-04 22:11:57 +04:00
vCounter + = 18 ; // 6 vertex, 18 floats
2014-09-03 18:51:28 +04:00
2014-01-29 00:21:29 +04:00
// Fill texcoords array with data
//--------------------------------------------------------------
2016-02-11 17:51:04 +03:00
mesh . texcoords [ tcCounter ] = ( float ) x / ( mapX - 1 ) ;
mesh . texcoords [ tcCounter + 1 ] = ( float ) z / ( mapZ - 1 ) ;
2014-09-03 18:51:28 +04:00
2016-02-11 17:51:04 +03:00
mesh . texcoords [ tcCounter + 2 ] = ( float ) x / ( mapX - 1 ) ;
mesh . texcoords [ tcCounter + 3 ] = ( float ) ( z + 1 ) / ( mapZ - 1 ) ;
2014-09-03 18:51:28 +04:00
2016-02-11 17:51:04 +03:00
mesh . texcoords [ tcCounter + 4 ] = ( float ) ( x + 1 ) / ( mapX - 1 ) ;
mesh . texcoords [ tcCounter + 5 ] = ( float ) z / ( mapZ - 1 ) ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
mesh . texcoords [ tcCounter + 6 ] = mesh . texcoords [ tcCounter + 4 ] ;
mesh . texcoords [ tcCounter + 7 ] = mesh . texcoords [ tcCounter + 5 ] ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
mesh . texcoords [ tcCounter + 8 ] = mesh . texcoords [ tcCounter + 2 ] ;
mesh . texcoords [ tcCounter + 9 ] = mesh . texcoords [ tcCounter + 3 ] ;
2014-09-03 18:51:28 +04:00
2016-02-11 17:51:04 +03:00
mesh . texcoords [ tcCounter + 10 ] = ( float ) ( x + 1 ) / ( mapX - 1 ) ;
mesh . texcoords [ tcCounter + 11 ] = ( float ) ( z + 1 ) / ( mapZ - 1 ) ;
2014-04-04 22:11:57 +04:00
tcCounter + = 12 ; // 6 texcoords, 12 floats
2014-09-03 18:51:28 +04:00
2014-01-29 00:21:29 +04:00
// Fill normals array with data
//--------------------------------------------------------------
2014-04-04 22:11:57 +04:00
for ( int i = 0 ; i < 18 ; i + = 3 )
{
2016-01-18 15:36:18 +03:00
mesh . normals [ nCounter + i ] = 0.0f ;
mesh . normals [ nCounter + i + 1 ] = 1.0f ;
mesh . normals [ nCounter + i + 2 ] = 0.0f ;
2014-04-04 22:11:57 +04:00
}
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
// TODO: Calculate normals in an efficient way
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
nCounter + = 18 ; // 6 vertex, 18 floats
2014-01-29 00:21:29 +04:00
trisCounter + = 2 ;
2014-03-16 23:59:02 +04:00
}
}
2015-05-05 00:46:31 +03:00
2016-02-11 17:51:04 +03:00
free ( pixels ) ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Fill color data
2015-01-02 22:59:54 +03:00
// NOTE: Not used any more... just one plain color defined at DrawModel()
2016-01-18 15:36:18 +03:00
for ( int i = 0 ; i < ( 4 * mesh . vertexCount ) ; i + + ) mesh . colors [ i ] = 255 ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
// NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
Model model = rlglLoadModel ( mesh ) ;
2014-03-25 15:40:35 +04:00
2016-03-01 17:37:01 +03:00
// Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM...
// ...but we keep CPU RAM vertex data in case we need to update the mesh
2013-11-30 21:12:40 +04:00
return model ;
}
2014-07-23 02:06:24 +04:00
// Load a map image as a 3d model (cubes based)
2015-05-05 00:46:31 +03:00
Model LoadCubicmap ( Image cubicmap )
2014-07-23 02:06:24 +04:00
{
2016-01-18 15:36:18 +03:00
Mesh mesh ;
2014-07-23 02:06:24 +04:00
2015-07-13 19:19:29 +03:00
Color * cubicmapPixels = GetImageData ( cubicmap ) ;
2015-05-05 00:46:31 +03:00
2014-07-23 02:06:24 +04:00
// Map cube size will be 1.0
float mapCubeSide = 1.0f ;
2016-01-13 21:30:35 +03:00
int mapWidth = cubicmap . width * ( int ) mapCubeSide ;
int mapHeight = cubicmap . height * ( int ) mapCubeSide ;
2014-09-03 18:51:28 +04:00
// NOTE: Max possible number of triangles numCubes * (12 triangles by cube)
2015-05-05 00:46:31 +03:00
int maxTriangles = cubicmap . width * cubicmap . height * 12 ;
2014-07-23 02:06:24 +04:00
int vCounter = 0 ; // Used to count vertices
int tcCounter = 0 ; // Used to count texcoords
int nCounter = 0 ; // Used to count normals
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
float w = mapCubeSide ;
float h = mapCubeSide ;
2016-01-13 21:30:35 +03:00
float h2 = mapCubeSide * 1.5f ; // TODO: Review walls height...
2014-09-03 18:51:28 +04:00
2016-01-13 21:30:35 +03:00
Vector3 * mapVertices = ( Vector3 * ) malloc ( maxTriangles * 3 * sizeof ( Vector3 ) ) ;
Vector2 * mapTexcoords = ( Vector2 * ) malloc ( maxTriangles * 3 * sizeof ( Vector2 ) ) ;
Vector3 * mapNormals = ( Vector3 * ) malloc ( maxTriangles * 3 * sizeof ( Vector3 ) ) ;
2015-04-06 15:02:29 +03:00
2015-02-02 22:05:18 +03:00
// Define the 6 normals of the cube, we will combine them accordingly later...
Vector3 n1 = { 1.0f , 0.0f , 0.0f } ;
Vector3 n2 = { - 1.0f , 0.0f , 0.0f } ;
Vector3 n3 = { 0.0f , 1.0f , 0.0f } ;
Vector3 n4 = { 0.0f , - 1.0f , 0.0f } ;
Vector3 n5 = { 0.0f , 0.0f , 1.0f } ;
Vector3 n6 = { 0.0f , 0.0f , - 1.0f } ;
2015-02-09 20:29:32 +03:00
// NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
2015-02-02 22:05:18 +03:00
typedef struct RectangleF {
float x ;
float y ;
float width ;
float height ;
} RectangleF ;
2015-04-06 15:02:29 +03:00
2016-01-13 21:30:35 +03:00
RectangleF rightTexUV = { 0.0f , 0.0f , 0.5f , 0.5f } ;
RectangleF leftTexUV = { 0.5f , 0.0f , 0.5f , 0.5f } ;
RectangleF frontTexUV = { 0.0f , 0.0f , 0.5f , 0.5f } ;
RectangleF backTexUV = { 0.5f , 0.0f , 0.5f , 0.5f } ;
RectangleF topTexUV = { 0.0f , 0.5f , 0.5f , 0.5f } ;
RectangleF bottomTexUV = { 0.5f , 0.5f , 0.5f , 0.5f } ;
2015-04-06 15:02:29 +03:00
2014-07-23 02:06:24 +04:00
for ( int z = 0 ; z < mapHeight ; z + = mapCubeSide )
{
for ( int x = 0 ; x < mapWidth ; x + = mapCubeSide )
2014-09-03 18:51:28 +04:00
{
2014-07-23 02:06:24 +04:00
// Define the 8 vertex of the cube, we will combine them accordingly later...
Vector3 v1 = { x - w / 2 , h2 , z - h / 2 } ;
Vector3 v2 = { x - w / 2 , h2 , z + h / 2 } ;
Vector3 v3 = { x + w / 2 , h2 , z + h / 2 } ;
Vector3 v4 = { x + w / 2 , h2 , z - h / 2 } ;
Vector3 v5 = { x + w / 2 , 0 , z - h / 2 } ;
Vector3 v6 = { x - w / 2 , 0 , z - h / 2 } ;
Vector3 v7 = { x - w / 2 , 0 , z + h / 2 } ;
Vector3 v8 = { x + w / 2 , 0 , z + h / 2 } ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// We check pixel color to be WHITE, we will full cubes
2015-05-05 00:46:31 +03:00
if ( ( cubicmapPixels [ z * cubicmap . width + x ] . r = = 255 ) & &
( cubicmapPixels [ z * cubicmap . width + x ] . g = = 255 ) & &
( cubicmapPixels [ z * cubicmap . width + x ] . b = = 255 ) )
2014-07-23 02:06:24 +04:00
{
// Define triangles (Checking Collateral Cubes!)
//----------------------------------------------
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
mapVertices [ vCounter ] = v1 ;
2014-09-03 18:51:28 +04:00
mapVertices [ vCounter + 1 ] = v2 ;
mapVertices [ vCounter + 2 ] = v3 ;
mapVertices [ vCounter + 3 ] = v1 ;
mapVertices [ vCounter + 4 ] = v3 ;
2014-07-23 02:06:24 +04:00
mapVertices [ vCounter + 5 ] = v4 ;
vCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter ] = n3 ;
2014-09-03 18:51:28 +04:00
mapNormals [ nCounter + 1 ] = n3 ;
mapNormals [ nCounter + 2 ] = n3 ;
mapNormals [ nCounter + 3 ] = n3 ;
mapNormals [ nCounter + 4 ] = n3 ;
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter + 5 ] = n3 ;
nCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2015-02-02 22:05:18 +03:00
mapTexcoords [ tcCounter ] = ( Vector2 ) { topTexUV . x , topTexUV . y } ;
mapTexcoords [ tcCounter + 1 ] = ( Vector2 ) { topTexUV . x , topTexUV . y + topTexUV . height } ;
mapTexcoords [ tcCounter + 2 ] = ( Vector2 ) { topTexUV . x + topTexUV . width , topTexUV . y + topTexUV . height } ;
mapTexcoords [ tcCounter + 3 ] = ( Vector2 ) { topTexUV . x , topTexUV . y } ;
mapTexcoords [ tcCounter + 4 ] = ( Vector2 ) { topTexUV . x + topTexUV . width , topTexUV . y + topTexUV . height } ;
mapTexcoords [ tcCounter + 5 ] = ( Vector2 ) { topTexUV . x + topTexUV . width , topTexUV . y } ;
2014-07-23 02:06:24 +04:00
tcCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
mapVertices [ vCounter ] = v6 ;
2014-09-03 18:51:28 +04:00
mapVertices [ vCounter + 1 ] = v8 ;
mapVertices [ vCounter + 2 ] = v7 ;
mapVertices [ vCounter + 3 ] = v6 ;
mapVertices [ vCounter + 4 ] = v5 ;
2014-07-23 02:06:24 +04:00
mapVertices [ vCounter + 5 ] = v8 ;
vCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter ] = n4 ;
2014-09-03 18:51:28 +04:00
mapNormals [ nCounter + 1 ] = n4 ;
mapNormals [ nCounter + 2 ] = n4 ;
mapNormals [ nCounter + 3 ] = n4 ;
mapNormals [ nCounter + 4 ] = n4 ;
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter + 5 ] = n4 ;
nCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2015-02-02 22:05:18 +03:00
mapTexcoords [ tcCounter ] = ( Vector2 ) { bottomTexUV . x + bottomTexUV . width , bottomTexUV . y } ;
mapTexcoords [ tcCounter + 1 ] = ( Vector2 ) { bottomTexUV . x , bottomTexUV . y + bottomTexUV . height } ;
mapTexcoords [ tcCounter + 2 ] = ( Vector2 ) { bottomTexUV . x + bottomTexUV . width , bottomTexUV . y + bottomTexUV . height } ;
mapTexcoords [ tcCounter + 3 ] = ( Vector2 ) { bottomTexUV . x + bottomTexUV . width , bottomTexUV . y } ;
mapTexcoords [ tcCounter + 4 ] = ( Vector2 ) { bottomTexUV . x , bottomTexUV . y } ;
mapTexcoords [ tcCounter + 5 ] = ( Vector2 ) { bottomTexUV . x , bottomTexUV . y + bottomTexUV . height } ;
2014-07-23 02:06:24 +04:00
tcCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2015-05-05 00:46:31 +03:00
if ( ( ( z < cubicmap . height - 1 ) & &
( cubicmapPixels [ ( z + 1 ) * cubicmap . width + x ] . r = = 0 ) & &
( cubicmapPixels [ ( z + 1 ) * cubicmap . width + x ] . g = = 0 ) & &
( cubicmapPixels [ ( z + 1 ) * cubicmap . width + x ] . b = = 0 ) ) | | ( z = = cubicmap . height - 1 ) )
2014-07-23 02:06:24 +04:00
{
// Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
// NOTE: Collateral occluded faces are not generated
mapVertices [ vCounter ] = v2 ;
2014-09-03 18:51:28 +04:00
mapVertices [ vCounter + 1 ] = v7 ;
mapVertices [ vCounter + 2 ] = v3 ;
mapVertices [ vCounter + 3 ] = v3 ;
mapVertices [ vCounter + 4 ] = v7 ;
2014-07-23 02:06:24 +04:00
mapVertices [ vCounter + 5 ] = v8 ;
vCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter ] = n6 ;
2014-09-03 18:51:28 +04:00
mapNormals [ nCounter + 1 ] = n6 ;
mapNormals [ nCounter + 2 ] = n6 ;
mapNormals [ nCounter + 3 ] = n6 ;
mapNormals [ nCounter + 4 ] = n6 ;
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter + 5 ] = n6 ;
nCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2015-02-02 22:05:18 +03:00
mapTexcoords [ tcCounter ] = ( Vector2 ) { frontTexUV . x , frontTexUV . y } ;
mapTexcoords [ tcCounter + 1 ] = ( Vector2 ) { frontTexUV . x , frontTexUV . y + frontTexUV . height } ;
mapTexcoords [ tcCounter + 2 ] = ( Vector2 ) { frontTexUV . x + frontTexUV . width , frontTexUV . y } ;
mapTexcoords [ tcCounter + 3 ] = ( Vector2 ) { frontTexUV . x + frontTexUV . width , frontTexUV . y } ;
mapTexcoords [ tcCounter + 4 ] = ( Vector2 ) { frontTexUV . x , frontTexUV . y + frontTexUV . height } ;
mapTexcoords [ tcCounter + 5 ] = ( Vector2 ) { frontTexUV . x + frontTexUV . width , frontTexUV . y + frontTexUV . height } ;
2014-07-23 02:06:24 +04:00
tcCounter + = 6 ;
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
if ( ( ( z > 0 ) & &
2015-05-05 00:46:31 +03:00
( cubicmapPixels [ ( z - 1 ) * cubicmap . width + x ] . r = = 0 ) & &
( cubicmapPixels [ ( z - 1 ) * cubicmap . width + x ] . g = = 0 ) & &
( cubicmapPixels [ ( z - 1 ) * cubicmap . width + x ] . b = = 0 ) ) | | ( z = = 0 ) )
2014-07-23 02:06:24 +04:00
{
// Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
// NOTE: Collateral occluded faces are not generated
mapVertices [ vCounter ] = v1 ;
2014-09-03 18:51:28 +04:00
mapVertices [ vCounter + 1 ] = v5 ;
mapVertices [ vCounter + 2 ] = v6 ;
mapVertices [ vCounter + 3 ] = v1 ;
mapVertices [ vCounter + 4 ] = v4 ;
2014-07-23 02:06:24 +04:00
mapVertices [ vCounter + 5 ] = v5 ;
vCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter ] = n5 ;
2014-09-03 18:51:28 +04:00
mapNormals [ nCounter + 1 ] = n5 ;
mapNormals [ nCounter + 2 ] = n5 ;
mapNormals [ nCounter + 3 ] = n5 ;
mapNormals [ nCounter + 4 ] = n5 ;
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter + 5 ] = n5 ;
nCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2015-02-02 22:05:18 +03:00
mapTexcoords [ tcCounter ] = ( Vector2 ) { backTexUV . x + backTexUV . width , backTexUV . y } ;
mapTexcoords [ tcCounter + 1 ] = ( Vector2 ) { backTexUV . x , backTexUV . y + backTexUV . height } ;
mapTexcoords [ tcCounter + 2 ] = ( Vector2 ) { backTexUV . x + backTexUV . width , backTexUV . y + backTexUV . height } ;
mapTexcoords [ tcCounter + 3 ] = ( Vector2 ) { backTexUV . x + backTexUV . width , backTexUV . y } ;
mapTexcoords [ tcCounter + 4 ] = ( Vector2 ) { backTexUV . x , backTexUV . y } ;
mapTexcoords [ tcCounter + 5 ] = ( Vector2 ) { backTexUV . x , backTexUV . y + backTexUV . height } ;
2014-07-23 02:06:24 +04:00
tcCounter + = 6 ;
}
2014-09-03 18:51:28 +04:00
2015-05-05 00:46:31 +03:00
if ( ( ( x < cubicmap . width - 1 ) & &
( cubicmapPixels [ z * cubicmap . width + ( x + 1 ) ] . r = = 0 ) & &
( cubicmapPixels [ z * cubicmap . width + ( x + 1 ) ] . g = = 0 ) & &
( cubicmapPixels [ z * cubicmap . width + ( x + 1 ) ] . b = = 0 ) ) | | ( x = = cubicmap . width - 1 ) )
2014-07-23 02:06:24 +04:00
{
// Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
// NOTE: Collateral occluded faces are not generated
mapVertices [ vCounter ] = v3 ;
2014-09-03 18:51:28 +04:00
mapVertices [ vCounter + 1 ] = v8 ;
mapVertices [ vCounter + 2 ] = v4 ;
mapVertices [ vCounter + 3 ] = v4 ;
mapVertices [ vCounter + 4 ] = v8 ;
2014-07-23 02:06:24 +04:00
mapVertices [ vCounter + 5 ] = v5 ;
vCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter ] = n1 ;
2014-09-03 18:51:28 +04:00
mapNormals [ nCounter + 1 ] = n1 ;
mapNormals [ nCounter + 2 ] = n1 ;
mapNormals [ nCounter + 3 ] = n1 ;
mapNormals [ nCounter + 4 ] = n1 ;
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter + 5 ] = n1 ;
nCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2015-02-02 22:05:18 +03:00
mapTexcoords [ tcCounter ] = ( Vector2 ) { rightTexUV . x , rightTexUV . y } ;
mapTexcoords [ tcCounter + 1 ] = ( Vector2 ) { rightTexUV . x , rightTexUV . y + rightTexUV . height } ;
mapTexcoords [ tcCounter + 2 ] = ( Vector2 ) { rightTexUV . x + rightTexUV . width , rightTexUV . y } ;
mapTexcoords [ tcCounter + 3 ] = ( Vector2 ) { rightTexUV . x + rightTexUV . width , rightTexUV . y } ;
mapTexcoords [ tcCounter + 4 ] = ( Vector2 ) { rightTexUV . x , rightTexUV . y + rightTexUV . height } ;
mapTexcoords [ tcCounter + 5 ] = ( Vector2 ) { rightTexUV . x + rightTexUV . width , rightTexUV . y + rightTexUV . height } ;
2014-07-23 02:06:24 +04:00
tcCounter + = 6 ;
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
if ( ( ( x > 0 ) & &
2015-05-05 00:46:31 +03:00
( cubicmapPixels [ z * cubicmap . width + ( x - 1 ) ] . r = = 0 ) & &
( cubicmapPixels [ z * cubicmap . width + ( x - 1 ) ] . g = = 0 ) & &
( cubicmapPixels [ z * cubicmap . width + ( x - 1 ) ] . b = = 0 ) ) | | ( x = = 0 ) )
2014-07-23 02:06:24 +04:00
{
// Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
// NOTE: Collateral occluded faces are not generated
mapVertices [ vCounter ] = v1 ;
2014-09-03 18:51:28 +04:00
mapVertices [ vCounter + 1 ] = v7 ;
mapVertices [ vCounter + 2 ] = v2 ;
mapVertices [ vCounter + 3 ] = v1 ;
mapVertices [ vCounter + 4 ] = v6 ;
2014-07-23 02:06:24 +04:00
mapVertices [ vCounter + 5 ] = v7 ;
vCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter ] = n2 ;
2014-09-03 18:51:28 +04:00
mapNormals [ nCounter + 1 ] = n2 ;
mapNormals [ nCounter + 2 ] = n2 ;
mapNormals [ nCounter + 3 ] = n2 ;
mapNormals [ nCounter + 4 ] = n2 ;
2014-07-23 02:06:24 +04:00
mapNormals [ nCounter + 5 ] = n2 ;
nCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2015-02-02 22:05:18 +03:00
mapTexcoords [ tcCounter ] = ( Vector2 ) { leftTexUV . x , leftTexUV . y } ;
mapTexcoords [ tcCounter + 1 ] = ( Vector2 ) { leftTexUV . x + leftTexUV . width , leftTexUV . y + leftTexUV . height } ;
mapTexcoords [ tcCounter + 2 ] = ( Vector2 ) { leftTexUV . x + leftTexUV . width , leftTexUV . y } ;
mapTexcoords [ tcCounter + 3 ] = ( Vector2 ) { leftTexUV . x , leftTexUV . y } ;
mapTexcoords [ tcCounter + 4 ] = ( Vector2 ) { leftTexUV . x , leftTexUV . y + leftTexUV . height } ;
mapTexcoords [ tcCounter + 5 ] = ( Vector2 ) { leftTexUV . x + leftTexUV . width , leftTexUV . y + leftTexUV . height } ;
2014-07-23 02:06:24 +04:00
tcCounter + = 6 ;
}
}
// We check pixel color to be BLACK, we will only draw floor and roof
2015-05-05 00:46:31 +03:00
else if ( ( cubicmapPixels [ z * cubicmap . width + x ] . r = = 0 ) & &
( cubicmapPixels [ z * cubicmap . width + x ] . g = = 0 ) & &
( cubicmapPixels [ z * cubicmap . width + x ] . b = = 0 ) )
2014-07-23 02:06:24 +04:00
{
2015-02-02 22:05:18 +03:00
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
mapVertices [ vCounter ] = v1 ;
mapVertices [ vCounter + 1 ] = v3 ;
mapVertices [ vCounter + 2 ] = v2 ;
mapVertices [ vCounter + 3 ] = v1 ;
mapVertices [ vCounter + 4 ] = v4 ;
mapVertices [ vCounter + 5 ] = v3 ;
vCounter + = 6 ;
mapNormals [ nCounter ] = n4 ;
mapNormals [ nCounter + 1 ] = n4 ;
mapNormals [ nCounter + 2 ] = n4 ;
mapNormals [ nCounter + 3 ] = n4 ;
mapNormals [ nCounter + 4 ] = n4 ;
mapNormals [ nCounter + 5 ] = n4 ;
nCounter + = 6 ;
mapTexcoords [ tcCounter ] = ( Vector2 ) { topTexUV . x , topTexUV . y } ;
mapTexcoords [ tcCounter + 1 ] = ( Vector2 ) { topTexUV . x + topTexUV . width , topTexUV . y + topTexUV . height } ;
mapTexcoords [ tcCounter + 2 ] = ( Vector2 ) { topTexUV . x , topTexUV . y + topTexUV . height } ;
mapTexcoords [ tcCounter + 3 ] = ( Vector2 ) { topTexUV . x , topTexUV . y } ;
mapTexcoords [ tcCounter + 4 ] = ( Vector2 ) { topTexUV . x + topTexUV . width , topTexUV . y } ;
mapTexcoords [ tcCounter + 5 ] = ( Vector2 ) { topTexUV . x + topTexUV . width , topTexUV . y + topTexUV . height } ;
tcCounter + = 6 ;
2015-04-06 15:02:29 +03:00
2015-02-02 22:05:18 +03:00
// Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
mapVertices [ vCounter ] = v6 ;
mapVertices [ vCounter + 1 ] = v7 ;
mapVertices [ vCounter + 2 ] = v8 ;
mapVertices [ vCounter + 3 ] = v6 ;
mapVertices [ vCounter + 4 ] = v8 ;
mapVertices [ vCounter + 5 ] = v5 ;
vCounter + = 6 ;
2014-09-03 18:51:28 +04:00
2015-02-02 22:05:18 +03:00
mapNormals [ nCounter ] = n3 ;
mapNormals [ nCounter + 1 ] = n3 ;
mapNormals [ nCounter + 2 ] = n3 ;
mapNormals [ nCounter + 3 ] = n3 ;
mapNormals [ nCounter + 4 ] = n3 ;
mapNormals [ nCounter + 5 ] = n3 ;
nCounter + = 6 ;
mapTexcoords [ tcCounter ] = ( Vector2 ) { bottomTexUV . x + bottomTexUV . width , bottomTexUV . y } ;
mapTexcoords [ tcCounter + 1 ] = ( Vector2 ) { bottomTexUV . x + bottomTexUV . width , bottomTexUV . y + bottomTexUV . height } ;
mapTexcoords [ tcCounter + 2 ] = ( Vector2 ) { bottomTexUV . x , bottomTexUV . y + bottomTexUV . height } ;
mapTexcoords [ tcCounter + 3 ] = ( Vector2 ) { bottomTexUV . x + bottomTexUV . width , bottomTexUV . y } ;
mapTexcoords [ tcCounter + 4 ] = ( Vector2 ) { bottomTexUV . x , bottomTexUV . y + bottomTexUV . height } ;
mapTexcoords [ tcCounter + 5 ] = ( Vector2 ) { bottomTexUV . x , bottomTexUV . y } ;
tcCounter + = 6 ;
2014-07-23 02:06:24 +04:00
}
2014-09-03 18:51:28 +04:00
}
2014-07-23 02:06:24 +04:00
}
// Move data from mapVertices temp arays to vertices float array
2016-01-18 15:36:18 +03:00
mesh . vertexCount = vCounter ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
mesh . vertices = ( float * ) malloc ( mesh . vertexCount * 3 * sizeof ( float ) ) ;
mesh . normals = ( float * ) malloc ( mesh . vertexCount * 3 * sizeof ( float ) ) ;
mesh . texcoords = ( float * ) malloc ( mesh . vertexCount * 2 * sizeof ( float ) ) ;
mesh . colors = ( unsigned char * ) malloc ( mesh . vertexCount * 4 * sizeof ( unsigned char ) ) ; // Not used...
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Fill color data
2015-01-02 22:59:54 +03:00
// NOTE: Not used any more... just one plain color defined at DrawModel()
2016-01-18 15:36:18 +03:00
for ( int i = 0 ; i < ( 4 * mesh . vertexCount ) ; i + + ) mesh . colors [ i ] = 255 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
int fCounter = 0 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Move vertices data
for ( int i = 0 ; i < vCounter ; i + + )
{
2016-01-18 15:36:18 +03:00
mesh . vertices [ fCounter ] = mapVertices [ i ] . x ;
mesh . vertices [ fCounter + 1 ] = mapVertices [ i ] . y ;
mesh . vertices [ fCounter + 2 ] = mapVertices [ i ] . z ;
2014-07-23 02:06:24 +04:00
fCounter + = 3 ;
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
fCounter = 0 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Move normals data
for ( int i = 0 ; i < nCounter ; i + + )
{
2016-01-18 15:36:18 +03:00
mesh . normals [ fCounter ] = mapNormals [ i ] . x ;
mesh . normals [ fCounter + 1 ] = mapNormals [ i ] . y ;
mesh . normals [ fCounter + 2 ] = mapNormals [ i ] . z ;
2014-07-23 02:06:24 +04:00
fCounter + = 3 ;
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
fCounter = 0 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Move texcoords data
for ( int i = 0 ; i < tcCounter ; i + + )
{
2016-01-18 15:36:18 +03:00
mesh . texcoords [ fCounter ] = mapTexcoords [ i ] . x ;
mesh . texcoords [ fCounter + 1 ] = mapTexcoords [ i ] . y ;
2014-07-23 02:06:24 +04:00
fCounter + = 2 ;
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
free ( mapVertices ) ;
free ( mapNormals ) ;
free ( mapTexcoords ) ;
2015-05-05 00:46:31 +03:00
free ( cubicmapPixels ) ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
// NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
Model model = rlglLoadModel ( mesh ) ;
2014-07-23 02:06:24 +04:00
2016-03-01 17:37:01 +03:00
// Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM...
// ...but we keep CPU RAM vertex data in case we need to update the mesh
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
return model ;
}
2013-11-19 02:38:44 +04:00
// Unload 3d model from memory
void UnloadModel ( Model model )
{
2016-03-01 17:37:01 +03:00
// Unload mesh data
free ( model . mesh . vertices ) ;
free ( model . mesh . texcoords ) ;
free ( model . mesh . normals ) ;
if ( model . mesh . texcoords2 ! = NULL ) free ( model . mesh . texcoords2 ) ;
if ( model . mesh . tangents ! = NULL ) free ( model . mesh . tangents ) ;
if ( model . mesh . colors ! = NULL ) free ( model . mesh . colors ) ;
rlDeleteBuffers ( model . mesh . vboId [ 0 ] ) ; // vertex
rlDeleteBuffers ( model . mesh . vboId [ 1 ] ) ; // texcoords
rlDeleteBuffers ( model . mesh . vboId [ 2 ] ) ; // normals
rlDeleteBuffers ( model . mesh . vboId [ 3 ] ) ; // texcoords2
rlDeleteBuffers ( model . mesh . vboId [ 4 ] ) ; // tangents
rlDeleteBuffers ( model . mesh . vboId [ 5 ] ) ; // colors
2014-09-17 00:51:31 +04:00
2015-04-06 15:02:29 +03:00
rlDeleteVertexArrays ( model . mesh . vaoId ) ;
2015-08-05 20:17:56 +03:00
2015-09-02 02:08:41 +03:00
if ( model . mesh . vaoId > 0 ) TraceLog ( INFO , " [VAO ID %i] Unloaded model data from VRAM (GPU) " , model . mesh . vaoId ) ;
else TraceLog ( INFO , " [VBO ID %i][VBO ID %i][VBO ID %i] Unloaded model data from VRAM (GPU) " , model.mesh.vboId[0], model.mesh.vboId[1], model.mesh.vboId[2]) ;
2013-11-19 02:38:44 +04:00
}
2015-04-13 21:15:28 +03:00
// Link a texture to a model
2014-04-19 18:36:49 +04:00
void SetModelTexture ( Model * model , Texture2D texture )
2013-11-19 02:38:44 +04:00
{
2015-06-16 21:02:01 +03:00
if ( texture . id < = 0 )
{
2015-07-13 19:19:29 +03:00
// Use default white texture (use mesh color)
model - > texture . id = whiteTexture ; // OpenGL 1.1
model - > shader . texDiffuseId = whiteTexture ; // OpenGL 3.3 / ES 2.0
2015-06-16 21:02:01 +03:00
}
else
{
model - > texture = texture ;
model - > shader . texDiffuseId = texture . id ;
}
2013-11-19 02:38:44 +04:00
}
2014-04-19 18:36:49 +04:00
// Draw a model (with texture if set)
void DrawModel ( Model model , Vector3 position , float scale , Color tint )
2013-11-19 02:38:44 +04:00
{
2014-04-19 18:36:49 +04:00
Vector3 vScale = { scale , scale , scale } ;
2016-01-13 21:30:35 +03:00
Vector3 rotationAxis = { 0.0f , 0.0f , 0.0f } ;
2014-04-19 18:36:49 +04:00
2016-02-02 20:41:01 +03:00
DrawModelEx ( model , position , rotationAxis , 0.0f , vScale , tint ) ;
2013-11-19 02:38:44 +04:00
}
2014-04-19 18:36:49 +04:00
// Draw a model with extended parameters
2016-02-02 20:41:01 +03:00
void DrawModelEx ( Model model , Vector3 position , Vector3 rotationAxis , float rotationAngle , Vector3 scale , Color tint )
2014-04-19 18:36:49 +04:00
{
2015-02-02 02:53:49 +03:00
// NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel()
2016-02-02 20:41:01 +03:00
rlglDrawModel ( model , position , rotationAxis , rotationAngle , scale , tint , false ) ;
2014-04-19 18:36:49 +04:00
}
// Draw a model wires (with texture if set)
2013-11-19 02:38:44 +04:00
void DrawModelWires ( Model model , Vector3 position , float scale , Color color )
{
2014-04-19 18:36:49 +04:00
Vector3 vScale = { scale , scale , scale } ;
2016-01-13 21:30:35 +03:00
Vector3 rotationAxis = { 0.0f , 0.0f , 0.0f } ;
2014-04-19 18:36:49 +04:00
2016-02-02 20:41:01 +03:00
rlglDrawModel ( model , position , rotationAxis , 0.0f , vScale , color , true ) ;
2013-11-19 02:38:44 +04:00
}
2015-12-21 18:42:13 +03:00
// Draw a model wires (with texture if set) with extended parameters
2016-02-02 20:41:01 +03:00
void DrawModelWiresEx ( Model model , Vector3 position , Vector3 rotationAxis , float rotationAngle , Vector3 scale , Color tint )
2015-12-21 18:42:13 +03:00
{
// NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel()
2016-02-02 20:41:01 +03:00
rlglDrawModel ( model , position , rotationAxis , rotationAngle , scale , tint , true ) ;
2015-12-21 18:42:13 +03:00
}
2013-11-19 02:38:44 +04:00
// Draw a billboard
2014-03-16 23:59:02 +04:00
void DrawBillboard ( Camera camera , Texture2D texture , Vector3 center , float size , Color tint )
2013-11-19 02:38:44 +04:00
{
2016-03-01 21:00:12 +03:00
Rectangle sourceRec = { 0 , 0 , texture . width , texture . height } ;
2015-06-02 10:54:51 +03:00
2016-03-01 21:00:12 +03:00
DrawBillboardRec ( camera , texture , sourceRec , center , size , tint ) ;
2013-11-19 02:38:44 +04:00
}
// Draw a billboard (part of a texture defined by a rectangle)
2014-03-16 23:59:02 +04:00
void DrawBillboardRec ( Camera camera , Texture2D texture , Rectangle sourceRec , Vector3 center , float size , Color tint )
2013-11-19 02:38:44 +04:00
{
2014-03-16 23:59:02 +04:00
// NOTE: Billboard size will maintain sourceRec aspect ratio, size will represent billboard width
2016-03-01 21:00:12 +03:00
Vector2 sizeRatio = { size , size * ( float ) sourceRec . height / sourceRec . width } ;
2014-03-16 23:59:02 +04:00
Matrix viewMatrix = MatrixLookAt ( camera . position , camera . target , camera . up ) ;
MatrixTranspose ( & viewMatrix ) ;
2014-09-03 18:51:28 +04:00
2014-03-16 23:59:02 +04:00
Vector3 right = { viewMatrix . m0 , viewMatrix . m4 , viewMatrix . m8 } ;
2016-03-01 21:00:12 +03:00
//Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 };
// NOTE: Billboard locked on axis-Y
Vector3 up = { 0.0f , 1.0f , 0.0f } ;
2014-09-03 18:51:28 +04:00
/*
2014-11-24 19:23:05 +03:00
a - - - - - - - b
2014-03-16 23:59:02 +04:00
| |
| * |
| |
2014-11-24 19:23:05 +03:00
d - - - - - - - c
2014-09-03 18:51:28 +04:00
*/
2014-03-16 23:59:02 +04:00
VectorScale ( & right , sizeRatio . x / 2 ) ;
VectorScale ( & up , sizeRatio . y / 2 ) ;
Vector3 p1 = VectorAdd ( right , up ) ;
Vector3 p2 = VectorSubtract ( right , up ) ;
Vector3 a = VectorSubtract ( center , p2 ) ;
Vector3 b = VectorAdd ( center , p1 ) ;
Vector3 c = VectorAdd ( center , p2 ) ;
Vector3 d = VectorSubtract ( center , p1 ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
rlEnableTexture ( texture . id ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
rlBegin ( RL_QUADS ) ;
rlColor4ub ( tint . r , tint . g , tint . b , tint . a ) ;
2014-09-03 18:51:28 +04:00
2014-03-16 23:59:02 +04:00
// Bottom-left corner for texture and quad
2014-09-03 18:51:28 +04:00
rlTexCoord2f ( ( float ) sourceRec . x / texture . width , ( float ) sourceRec . y / texture . height ) ;
2014-03-25 15:40:35 +04:00
rlVertex3f ( a . x , a . y , a . z ) ;
2015-02-02 02:53:49 +03:00
2014-11-24 19:23:05 +03:00
// Top-left corner for texture and quad
rlTexCoord2f ( ( float ) sourceRec . x / texture . width , ( float ) ( sourceRec . y + sourceRec . height ) / texture . height ) ;
rlVertex3f ( d . x , d . y , d . z ) ;
2015-02-02 02:53:49 +03:00
2014-03-16 23:59:02 +04:00
// Top-right corner for texture and quad
2014-09-03 18:51:28 +04:00
rlTexCoord2f ( ( float ) ( sourceRec . x + sourceRec . width ) / texture . width , ( float ) ( sourceRec . y + sourceRec . height ) / texture . height ) ;
2014-03-25 15:40:35 +04:00
rlVertex3f ( c . x , c . y , c . z ) ;
2014-09-03 18:51:28 +04:00
2014-11-24 19:23:05 +03:00
// Bottom-right corner for texture and quad
rlTexCoord2f ( ( float ) ( sourceRec . x + sourceRec . width ) / texture . width , ( float ) sourceRec . y / texture . height ) ;
rlVertex3f ( b . x , b . y , b . z ) ;
2014-03-25 15:40:35 +04:00
rlEnd ( ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
rlDisableTexture ( ) ;
2013-11-19 02:38:44 +04:00
}
2016-01-25 13:12:31 +03:00
// Draw a bounding box with wires
void DrawBoundingBox ( BoundingBox box )
{
Vector3 size ;
size . x = fabsf ( box . max . x - box . min . x ) ;
size . y = fabsf ( box . max . y - box . min . y ) ;
size . z = fabsf ( box . max . z - box . min . z ) ;
Vector3 center = { box . min . x + size . x / 2.0f , box . min . y + size . y / 2.0f , box . min . z + size . z / 2.0f } ;
DrawCubeWires ( center , size . x , size . y , size . z , GREEN ) ;
}
2015-07-13 19:19:29 +03:00
// Detect collision between two spheres
2015-02-09 20:35:25 +03:00
bool CheckCollisionSpheres ( Vector3 centerA , float radiusA , Vector3 centerB , float radiusB )
{
bool collision = false ;
float dx = centerA . x - centerB . x ; // X distance between centers
float dy = centerA . y - centerB . y ; // Y distance between centers
float dz = centerA . z - centerB . z ; // Y distance between centers
float distance = sqrt ( dx * dx + dy * dy + dz * dz ) ; // Distance between centers
if ( distance < = ( radiusA + radiusB ) ) collision = true ;
2015-04-06 15:02:29 +03:00
2015-02-09 20:35:25 +03:00
return collision ;
}
2015-07-13 19:19:29 +03:00
// Detect collision between two boxes
// NOTE: Boxes are defined by two points minimum and maximum
2015-02-09 20:35:25 +03:00
bool CheckCollisionBoxes ( Vector3 minBBox1 , Vector3 maxBBox1 , Vector3 minBBox2 , Vector3 maxBBox2 )
{
bool collision = true ;
2015-04-06 15:02:29 +03:00
2015-02-09 20:35:25 +03:00
if ( ( maxBBox1 . x > = minBBox2 . x ) & & ( minBBox1 . x < = maxBBox2 . x ) )
{
if ( ( maxBBox1 . y < minBBox2 . y ) | | ( minBBox1 . y > maxBBox2 . y ) ) collision = false ;
if ( ( maxBBox1 . z < minBBox2 . z ) | | ( minBBox1 . z > maxBBox2 . z ) ) collision = false ;
}
else collision = false ;
return collision ;
}
2015-07-13 19:19:29 +03:00
// Detect collision between box and sphere
2015-02-09 20:35:25 +03:00
bool CheckCollisionBoxSphere ( Vector3 minBBox , Vector3 maxBBox , Vector3 centerSphere , float radiusSphere )
{
bool collision = false ;
2015-04-06 15:02:29 +03:00
2015-02-09 20:35:25 +03:00
if ( ( centerSphere . x - minBBox . x > radiusSphere ) & & ( centerSphere . y - minBBox . y > radiusSphere ) & & ( centerSphere . z - minBBox . z > radiusSphere ) & &
( maxBBox . x - centerSphere . x > radiusSphere ) & & ( maxBBox . y - centerSphere . y > radiusSphere ) & & ( maxBBox . z - centerSphere . z > radiusSphere ) )
{
collision = true ;
}
else
{
float dmin = 0 ;
2015-07-13 19:19:29 +03:00
if ( centerSphere . x - minBBox . x < = radiusSphere ) dmin + = ( centerSphere . x - minBBox . x ) * ( centerSphere . x - minBBox . x ) ;
else if ( maxBBox . x - centerSphere . x < = radiusSphere ) dmin + = ( centerSphere . x - maxBBox . x ) * ( centerSphere . x - maxBBox . x ) ;
2015-02-09 20:35:25 +03:00
2015-07-13 19:19:29 +03:00
if ( centerSphere . y - minBBox . y < = radiusSphere ) dmin + = ( centerSphere . y - minBBox . y ) * ( centerSphere . y - minBBox . y ) ;
else if ( maxBBox . y - centerSphere . y < = radiusSphere ) dmin + = ( centerSphere . y - maxBBox . y ) * ( centerSphere . y - maxBBox . y ) ;
2015-02-09 20:35:25 +03:00
2015-07-13 19:19:29 +03:00
if ( centerSphere . z - minBBox . z < = radiusSphere ) dmin + = ( centerSphere . z - minBBox . z ) * ( centerSphere . z - minBBox . z ) ;
else if ( maxBBox . z - centerSphere . z < = radiusSphere ) dmin + = ( centerSphere . z - maxBBox . z ) * ( centerSphere . z - maxBBox . z ) ;
2015-02-09 20:35:25 +03:00
2015-07-13 19:19:29 +03:00
if ( dmin < = radiusSphere * radiusSphere ) collision = true ;
2015-02-09 20:35:25 +03:00
}
return collision ;
}
2016-01-19 22:27:41 +03:00
// Detect collision between ray and sphere
bool CheckCollisionRaySphere ( Ray ray , Vector3 spherePosition , float sphereRadius )
{
bool collision = false ;
2016-01-20 21:28:47 +03:00
Vector3 raySpherePos = VectorSubtract ( spherePosition , ray . position ) ;
float distance = VectorLength ( raySpherePos ) ;
float vector = VectorDotProduct ( raySpherePos , ray . direction ) ;
float d = sphereRadius * sphereRadius - ( distance * distance - vector * vector ) ;
if ( d > = 0.0f ) collision = true ;
return collision ;
}
// Detect collision between ray and sphere with extended parameters and collision point detection
bool CheckCollisionRaySphereEx ( Ray ray , Vector3 spherePosition , float sphereRadius , Vector3 * collisionPoint )
{
bool collision = false ;
Vector3 raySpherePos = VectorSubtract ( spherePosition , ray . position ) ;
float distance = VectorLength ( raySpherePos ) ;
float vector = VectorDotProduct ( raySpherePos , ray . direction ) ;
float d = sphereRadius * sphereRadius - ( distance * distance - vector * vector ) ;
if ( d > = 0.0f ) collision = true ;
// Calculate collision point
Vector3 offset = ray . direction ;
float collisionDistance = 0 ;
// Check if ray origin is inside the sphere to calculate the correct collision point
if ( distance < sphereRadius ) collisionDistance = vector + sqrt ( d ) ;
else collisionDistance = vector - sqrt ( d ) ;
VectorScale ( & offset , collisionDistance ) ;
Vector3 cPoint = VectorAdd ( ray . position , offset ) ;
collisionPoint - > x = cPoint . x ;
collisionPoint - > y = cPoint . y ;
collisionPoint - > z = cPoint . z ;
2016-01-19 22:27:41 +03:00
return collision ;
}
// Detect collision between ray and bounding box
2016-01-07 18:18:24 +03:00
bool CheckCollisionRayBox ( Ray ray , Vector3 minBBox , Vector3 maxBBox )
{
bool collision = false ;
float t [ 8 ] ;
2016-01-19 22:27:41 +03:00
t [ 0 ] = ( minBBox . x - ray . position . x ) / ray . direction . x ;
t [ 1 ] = ( maxBBox . x - ray . position . x ) / ray . direction . x ;
t [ 2 ] = ( minBBox . y - ray . position . y ) / ray . direction . y ;
t [ 3 ] = ( maxBBox . y - ray . position . y ) / ray . direction . y ;
t [ 4 ] = ( minBBox . z - ray . position . z ) / ray . direction . z ;
t [ 5 ] = ( maxBBox . z - ray . position . z ) / ray . direction . z ;
2016-01-07 18:18:24 +03:00
t [ 6 ] = fmax ( fmax ( fmin ( t [ 0 ] , t [ 1 ] ) , fmin ( t [ 2 ] , t [ 3 ] ) ) , fmin ( t [ 4 ] , t [ 5 ] ) ) ;
t [ 7 ] = fmin ( fmin ( fmax ( t [ 0 ] , t [ 1 ] ) , fmax ( t [ 2 ] , t [ 3 ] ) ) , fmax ( t [ 4 ] , t [ 5 ] ) ) ;
collision = ! ( t [ 7 ] < 0 | | t [ 6 ] > t [ 7 ] ) ;
return collision ;
}
2016-01-19 22:27:41 +03:00
// Calculate mesh bounding box limits
2016-01-25 13:12:31 +03:00
// NOTE: minVertex and maxVertex should be transformed by model transform matrix (position, scale, rotate)
2016-01-19 22:27:41 +03:00
BoundingBox CalculateBoundingBox ( Mesh mesh )
{
// Get min and max vertex to construct bounds (AABB)
2016-01-20 20:20:05 +03:00
Vector3 minVertex = ( Vector3 ) { mesh . vertices [ 0 ] , mesh . vertices [ 1 ] , mesh . vertices [ 2 ] } ;
Vector3 maxVertex = ( Vector3 ) { mesh . vertices [ 0 ] , mesh . vertices [ 1 ] , mesh . vertices [ 2 ] } ;
2016-01-19 22:27:41 +03:00
for ( int i = 1 ; i < mesh . vertexCount ; i + + )
{
2016-01-25 13:12:31 +03:00
minVertex = VectorMin ( minVertex , ( Vector3 ) { mesh . vertices [ i * 3 ] , mesh . vertices [ i * 3 + 1 ] , mesh . vertices [ i * 3 + 2 ] } ) ;
maxVertex = VectorMax ( maxVertex , ( Vector3 ) { mesh . vertices [ i * 3 ] , mesh . vertices [ i * 3 + 1 ] , mesh . vertices [ i * 3 + 2 ] } ) ;
2016-01-19 22:27:41 +03:00
}
2016-01-25 13:12:31 +03:00
2016-01-19 22:27:41 +03:00
// Create the bounding box
BoundingBox box ;
box . min = minVertex ;
box . max = maxVertex ;
return box ;
}
2015-02-09 20:35:25 +03:00
// Detect and resolve cubicmap collisions
// NOTE: player position (or camera) is modified inside this function
2015-03-02 22:52:58 +03:00
Vector3 ResolveCollisionCubicmap ( Image cubicmap , Vector3 mapPosition , Vector3 * playerPosition , float radius )
2015-02-09 20:35:25 +03:00
{
2015-07-13 19:19:29 +03:00
Color * cubicmapPixels = GetImageData ( cubicmap ) ;
2015-05-05 00:46:31 +03:00
2015-02-09 20:35:25 +03:00
// Detect the cell where the player is located
2016-01-13 21:30:35 +03:00
Vector3 impactDirection = { 0.0f , 0.0f , 0.0f } ;
2015-04-06 15:02:29 +03:00
2015-02-09 20:35:25 +03:00
int locationCellX = 0 ;
int locationCellY = 0 ;
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
locationCellX = floor ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) ;
locationCellY = floor ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) ;
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
if ( locationCellX > = 0 & & locationCellY > = 0 & & locationCellX < cubicmap . width & & locationCellY < cubicmap . height )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
// Multiple Axis --------------------------------------------------------------------------------------------
// Axis x-, y-
if ( locationCellX > 0 & & locationCellY > 0 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX - 1 ) ] . r ! = 0 ) & &
( cubicmapPixels [ ( locationCellY - 1 ) * cubicmap . width + ( locationCellX ) ] . r ! = 0 ) )
{
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX < radius ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY < radius ) )
{
playerPosition - > x = locationCellX + mapPosition . x - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
playerPosition - > z = locationCellY + mapPosition . z - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-02-09 20:35:25 +03:00
}
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Axis x-, y+
if ( locationCellX > 0 & & locationCellY < cubicmap . height - 1 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX - 1 ) ] . r ! = 0 ) & &
( cubicmapPixels [ ( locationCellY + 1 ) * cubicmap . width + ( locationCellX ) ] . r ! = 0 ) )
{
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX < radius ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY > 1 - radius ) )
{
playerPosition - > x = locationCellX + mapPosition . x - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
playerPosition - > z = locationCellY + mapPosition . z + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-02-09 20:35:25 +03:00
}
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Axis x+, y-
if ( locationCellX < cubicmap . width - 1 & & locationCellY > 0 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX + 1 ) ] . r ! = 0 ) & &
( cubicmapPixels [ ( locationCellY - 1 ) * cubicmap . width + ( locationCellX ) ] . r ! = 0 ) )
{
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX > 1 - radius ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY < radius ) )
{
playerPosition - > x = locationCellX + mapPosition . x + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
playerPosition - > z = locationCellY + mapPosition . z - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-02-09 20:35:25 +03:00
}
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Axis x+, y+
if ( locationCellX < cubicmap . width - 1 & & locationCellY < cubicmap . height - 1 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX + 1 ) ] . r ! = 0 ) & &
( cubicmapPixels [ ( locationCellY + 1 ) * cubicmap . width + ( locationCellX ) ] . r ! = 0 ) )
{
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX > 1 - radius ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY > 1 - radius ) )
{
playerPosition - > x = locationCellX + mapPosition . x + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
playerPosition - > z = locationCellY + mapPosition . z + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-02-09 20:35:25 +03:00
}
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Single Axis ---------------------------------------------------------------------------------------------------
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Axis x-
if ( locationCellX > 0 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX - 1 ) ] . r ! = 0 )
{
if ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX < radius )
{
playerPosition - > x = locationCellX + mapPosition . x - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 0.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-02-09 20:35:25 +03:00
}
2015-06-02 10:54:51 +03:00
// Axis x+
if ( locationCellX < cubicmap . width - 1 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX + 1 ) ] . r ! = 0 )
{
if ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX > 1 - radius )
{
playerPosition - > x = locationCellX + mapPosition . x + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 0.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-02-09 20:35:25 +03:00
}
2015-06-02 10:54:51 +03:00
// Axis y-
if ( locationCellY > 0 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( cubicmapPixels [ ( locationCellY - 1 ) * cubicmap . width + ( locationCellX ) ] . r ! = 0 )
{
if ( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY < radius )
{
playerPosition - > z = locationCellY + mapPosition . z - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 0.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-02-09 20:35:25 +03:00
}
2015-06-02 10:54:51 +03:00
// Axis y+
if ( locationCellY < cubicmap . height - 1 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( cubicmapPixels [ ( locationCellY + 1 ) * cubicmap . width + ( locationCellX ) ] . r ! = 0 )
{
if ( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY > 1 - radius )
{
playerPosition - > z = locationCellY + mapPosition . z + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 0.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-02-09 20:35:25 +03:00
}
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Diagonals -------------------------------------------------------------------------------------------------------
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Axis x-, y-
if ( locationCellX > 0 & & locationCellY > 0 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX - 1 ) ] . r = = 0 ) & &
( cubicmapPixels [ ( locationCellY - 1 ) * cubicmap . width + ( locationCellX ) ] . r = = 0 ) & &
( cubicmapPixels [ ( locationCellY - 1 ) * cubicmap . width + ( locationCellX - 1 ) ] . r ! = 0 ) )
2015-03-02 22:52:58 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX < radius ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY < radius ) )
{
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX ) > ( ( playerPosition - > z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY ) ) playerPosition - > x = locationCellX + mapPosition . x - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
else playerPosition - > z = locationCellY + mapPosition . z - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
// Return ricochet
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX < radius / 3 ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY < radius / 3 ) )
{
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-03-02 22:52:58 +03:00
}
2015-02-09 20:35:25 +03:00
}
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Axis x-, y+
if ( locationCellX > 0 & & locationCellY < cubicmap . height - 1 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX - 1 ) ] . r = = 0 ) & &
( cubicmapPixels [ ( locationCellY + 1 ) * cubicmap . width + ( locationCellX ) ] . r = = 0 ) & &
( cubicmapPixels [ ( locationCellY + 1 ) * cubicmap . width + ( locationCellX - 1 ) ] . r ! = 0 ) )
2015-03-02 22:52:58 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX < radius ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY > 1 - radius ) )
{
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX ) > ( 1 - ( ( playerPosition - > z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY ) ) ) playerPosition - > x = locationCellX + mapPosition . x - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
else playerPosition - > z = locationCellY + mapPosition . z + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
// Return ricochet
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX < radius / 3 ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY > 1 - radius / 3 ) )
{
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-03-02 22:52:58 +03:00
}
2015-02-09 20:35:25 +03:00
}
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Axis x+, y-
if ( locationCellX < cubicmap . width - 1 & & locationCellY > 0 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX + 1 ) ] . r = = 0 ) & &
( cubicmapPixels [ ( locationCellY - 1 ) * cubicmap . width + ( locationCellX ) ] . r = = 0 ) & &
( cubicmapPixels [ ( locationCellY - 1 ) * cubicmap . width + ( locationCellX + 1 ) ] . r ! = 0 ) )
2015-03-02 22:52:58 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX > 1 - radius ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY < radius ) )
{
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX ) < ( 1 - ( ( playerPosition - > z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY ) ) ) playerPosition - > x = locationCellX + mapPosition . x + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
else playerPosition - > z = locationCellY + mapPosition . z - ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
// Return ricochet
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX > 1 - radius / 3 ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY < radius / 3 ) )
{
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-03-02 22:52:58 +03:00
}
2015-02-09 20:35:25 +03:00
}
2015-04-06 15:02:29 +03:00
2015-06-02 10:54:51 +03:00
// Axis x+, y+
if ( locationCellX < cubicmap . width - 1 & & locationCellY < cubicmap . height - 1 )
2015-02-09 20:35:25 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( cubicmapPixels [ locationCellY * cubicmap . width + ( locationCellX + 1 ) ] . r = = 0 ) & &
( cubicmapPixels [ ( locationCellY + 1 ) * cubicmap . width + ( locationCellX ) ] . r = = 0 ) & &
( cubicmapPixels [ ( locationCellY + 1 ) * cubicmap . width + ( locationCellX + 1 ) ] . r ! = 0 ) )
2015-03-02 22:52:58 +03:00
{
2015-06-02 10:54:51 +03:00
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX > 1 - radius ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY > 1 - radius ) )
{
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX ) < ( ( playerPosition - > z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY ) ) playerPosition - > x = locationCellX + mapPosition . x + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
else playerPosition - > z = locationCellY + mapPosition . z + ( CUBIC_MAP_HALF_BLOCK_SIZE - radius ) ;
// Return ricochet
if ( ( ( playerPosition - > x - mapPosition . x + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellX > 1 - radius / 3 ) & &
( ( playerPosition - > z - mapPosition . z + CUBIC_MAP_HALF_BLOCK_SIZE ) - locationCellY > 1 - radius / 3 ) )
{
2016-01-13 21:30:35 +03:00
impactDirection = ( Vector3 ) { 1.0f , 0.0f , 1.0f } ;
2015-06-02 10:54:51 +03:00
}
}
2015-03-02 22:52:58 +03:00
}
2015-02-09 20:35:25 +03:00
}
}
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
// Floor collision
if ( playerPosition - > y < = radius )
{
2016-01-13 21:30:35 +03:00
playerPosition - > y = radius + 0.01f ;
2015-03-02 22:52:58 +03:00
impactDirection = ( Vector3 ) { impactDirection . x , 1 , impactDirection . z } ;
}
// Roof collision
2016-01-13 21:30:35 +03:00
else if ( playerPosition - > y > = ( 1.5f - radius ) )
2015-03-02 22:52:58 +03:00
{
2016-01-13 21:30:35 +03:00
playerPosition - > y = ( 1.5f - radius ) - 0.01f ;
2015-03-02 22:52:58 +03:00
impactDirection = ( Vector3 ) { impactDirection . x , 1 , impactDirection . z } ;
}
2015-05-05 00:46:31 +03:00
free ( cubicmapPixels ) ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
return impactDirection ;
2015-02-09 20:35:25 +03:00
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
2014-04-19 18:36:49 +04:00
// Load OBJ mesh data
2016-01-18 15:36:18 +03:00
static Mesh LoadOBJ ( const char * fileName )
2014-04-19 18:36:49 +04:00
{
2016-01-18 15:36:18 +03:00
Mesh mesh = { 0 } ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
char dataType ;
char comments [ 200 ] ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
int numVertex = 0 ;
int numNormals = 0 ;
int numTexCoords = 0 ;
int numTriangles = 0 ;
2014-09-17 00:51:31 +04:00
FILE * objFile ;
2014-04-19 18:36:49 +04:00
objFile = fopen ( fileName , " rt " ) ;
2015-02-02 02:53:49 +03:00
2014-12-17 21:32:54 +03:00
if ( objFile = = NULL )
{
TraceLog ( WARNING , " [%s] OBJ file could not be opened " , fileName ) ;
2016-01-18 15:36:18 +03:00
return mesh ;
2014-12-17 21:32:54 +03:00
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles
2014-04-19 18:36:49 +04:00
// NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
2016-03-01 21:00:12 +03:00
// NOTE: faces MUST be defined as TRIANGLES (3 vertex per face)
2014-04-19 18:36:49 +04:00
while ( ! feof ( objFile ) )
{
fscanf ( objFile , " %c " , & dataType ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
switch ( dataType )
{
2014-07-23 02:06:24 +04:00
case ' # ' : // Comments
case ' o ' : // Object name (One OBJ file can contain multible named meshes)
case ' g ' : // Group name
case ' s ' : // Smoothing level
case ' m ' : // mtllib [external .mtl file name]
case ' u ' : // usemtl [material name]
2014-04-19 18:36:49 +04:00
{
2014-09-03 18:51:28 +04:00
fgets ( comments , 200 , objFile ) ;
} break ;
2014-04-19 18:36:49 +04:00
case ' v ' :
{
fscanf ( objFile , " %c " , & dataType ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
if ( dataType = = ' t ' ) // Read texCoord
{
2014-07-23 02:06:24 +04:00
numTexCoords + + ;
2014-04-19 18:36:49 +04:00
fgets ( comments , 200 , objFile ) ;
}
else if ( dataType = = ' n ' ) // Read normals
{
2014-07-23 02:06:24 +04:00
numNormals + + ;
2014-04-19 18:36:49 +04:00
fgets ( comments , 200 , objFile ) ;
}
else // Read vertex
{
2014-07-23 02:06:24 +04:00
numVertex + + ;
2014-04-19 18:36:49 +04:00
fgets ( comments , 200 , objFile ) ;
}
} break ;
case ' f ' :
{
2014-07-23 02:06:24 +04:00
numTriangles + + ;
2014-04-19 18:36:49 +04:00
fgets ( comments , 200 , objFile ) ;
} break ;
default : break ;
}
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
TraceLog ( DEBUG , " [%s] Model num vertices: %i " , fileName , numVertex ) ;
TraceLog ( DEBUG , " [%s] Model num texcoords: %i " , fileName , numTexCoords ) ;
TraceLog ( DEBUG , " [%s] Model num normals: %i " , fileName , numNormals ) ;
TraceLog ( DEBUG , " [%s] Model num triangles: %i " , fileName , numTriangles ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
// Once we know the number of vertices to store, we create required arrays
Vector3 * midVertices = ( Vector3 * ) malloc ( numVertex * sizeof ( Vector3 ) ) ;
2014-09-17 00:51:31 +04:00
Vector3 * midNormals = NULL ;
2014-07-23 02:06:24 +04:00
if ( numNormals > 0 ) midNormals = ( Vector3 * ) malloc ( numNormals * sizeof ( Vector3 ) ) ;
2014-09-17 00:51:31 +04:00
Vector2 * midTexCoords = NULL ;
2014-07-23 02:06:24 +04:00
if ( numTexCoords > 0 ) midTexCoords = ( Vector2 * ) malloc ( numTexCoords * sizeof ( Vector2 ) ) ;
2014-04-19 18:36:49 +04:00
int countVertex = 0 ;
int countNormals = 0 ;
int countTexCoords = 0 ;
2014-07-23 02:06:24 +04:00
2014-04-19 18:36:49 +04:00
rewind ( objFile ) ; // Return to the beginning of the file, to read again
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Second reading pass: Get vertex data to fill intermediate arrays
// NOTE: This second pass is required in case of multiple meshes defined in same OBJ
2015-07-13 19:19:29 +03:00
// TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals)
2014-04-19 18:36:49 +04:00
while ( ! feof ( objFile ) )
{
fscanf ( objFile , " %c " , & dataType ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
switch ( dataType )
{
2014-09-03 18:51:28 +04:00
case ' # ' : case ' o ' : case ' g ' : case ' s ' : case ' m ' : case ' u ' : case ' f ' : fgets ( comments , 200 , objFile ) ; break ;
case ' v ' :
2014-04-19 18:36:49 +04:00
{
fscanf ( objFile , " %c " , & dataType ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
if ( dataType = = ' t ' ) // Read texCoord
{
float useless = 0 ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
fscanf ( objFile , " %f %f %f " , & midTexCoords [ countTexCoords ] . x , & midTexCoords [ countTexCoords ] . y , & useless ) ;
countTexCoords + + ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
fscanf ( objFile , " %c " , & dataType ) ;
}
else if ( dataType = = ' n ' ) // Read normals
{
fscanf ( objFile , " %f %f %f " , & midNormals [ countNormals ] . x , & midNormals [ countNormals ] . y , & midNormals [ countNormals ] . z ) ;
countNormals + + ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
fscanf ( objFile , " %c " , & dataType ) ;
}
else // Read vertex
{
fscanf ( objFile , " %f %f %f " , & midVertices [ countVertex ] . x , & midVertices [ countVertex ] . y , & midVertices [ countVertex ] . z ) ;
countVertex + + ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
fscanf ( objFile , " %c " , & dataType ) ;
}
} break ;
2014-07-23 02:06:24 +04:00
default : break ;
}
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// At this point all vertex data (v, vt, vn) has been gathered on midVertices, midTexCoords, midNormals
2016-01-18 15:36:18 +03:00
// Now we can organize that data into our Mesh struct
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
mesh . vertexCount = numTriangles * 3 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Additional arrays to store vertex data as floats
2016-01-18 15:36:18 +03:00
mesh . vertices = ( float * ) malloc ( mesh . vertexCount * 3 * sizeof ( float ) ) ;
mesh . texcoords = ( float * ) malloc ( mesh . vertexCount * 2 * sizeof ( float ) ) ;
mesh . normals = ( float * ) malloc ( mesh . vertexCount * 3 * sizeof ( float ) ) ;
mesh . colors = ( unsigned char * ) malloc ( mesh . vertexCount * 4 * sizeof ( unsigned char ) ) ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
int vCounter = 0 ; // Used to count vertices float by float
int tcCounter = 0 ; // Used to count texcoords float by float
int nCounter = 0 ; // Used to count normals float by float
2014-09-03 18:51:28 +04:00
2015-09-02 21:36:05 +03:00
int vNum [ 3 ] , vtNum [ 3 ] , vnNum [ 3 ] ; // Used to store triangle indices for v, vt, vn
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
rewind ( objFile ) ; // Return to the beginning of the file, to read again
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
if ( numNormals = = 0 ) TraceLog ( INFO , " [%s] No normals data on OBJ, normals will be generated from faces data " , fileName ) ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Third reading pass: Get faces (triangles) data and fill VertexArray
while ( ! feof ( objFile ) )
{
fscanf ( objFile , " %c " , & dataType ) ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
switch ( dataType )
{
2014-09-03 18:51:28 +04:00
case ' # ' : case ' o ' : case ' g ' : case ' s ' : case ' m ' : case ' u ' : case ' v ' : fgets ( comments , 200 , objFile ) ; break ;
2014-04-19 18:36:49 +04:00
case ' f ' :
{
2014-07-23 02:06:24 +04:00
// NOTE: It could be that OBJ does not have normals or texcoords defined!
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
if ( ( numNormals = = 0 ) & & ( numTexCoords = = 0 ) ) fscanf ( objFile , " %i %i %i " , & vNum [ 0 ] , & vNum [ 1 ] , & vNum [ 2 ] ) ;
else if ( numNormals = = 0 ) fscanf ( objFile , " %i/%i %i/%i %i/%i " , & vNum [ 0 ] , & vtNum [ 0 ] , & vNum [ 1 ] , & vtNum [ 1 ] , & vNum [ 2 ] , & vtNum [ 2 ] ) ;
else fscanf ( objFile , " %i/%i/%i %i/%i/%i %i/%i/%i " , & vNum [ 0 ] , & vtNum [ 0 ] , & vnNum [ 0 ] , & vNum [ 1 ] , & vtNum [ 1 ] , & vnNum [ 1 ] , & vNum [ 2 ] , & vtNum [ 2 ] , & vnNum [ 2 ] ) ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
mesh . vertices [ vCounter ] = midVertices [ vNum [ 0 ] - 1 ] . x ;
mesh . vertices [ vCounter + 1 ] = midVertices [ vNum [ 0 ] - 1 ] . y ;
mesh . vertices [ vCounter + 2 ] = midVertices [ vNum [ 0 ] - 1 ] . z ;
2014-04-19 18:36:49 +04:00
vCounter + = 3 ;
2016-01-18 15:36:18 +03:00
mesh . vertices [ vCounter ] = midVertices [ vNum [ 1 ] - 1 ] . x ;
mesh . vertices [ vCounter + 1 ] = midVertices [ vNum [ 1 ] - 1 ] . y ;
mesh . vertices [ vCounter + 2 ] = midVertices [ vNum [ 1 ] - 1 ] . z ;
2014-07-23 02:06:24 +04:00
vCounter + = 3 ;
2016-01-18 15:36:18 +03:00
mesh . vertices [ vCounter ] = midVertices [ vNum [ 2 ] - 1 ] . x ;
mesh . vertices [ vCounter + 1 ] = midVertices [ vNum [ 2 ] - 1 ] . y ;
mesh . vertices [ vCounter + 2 ] = midVertices [ vNum [ 2 ] - 1 ] . z ;
2014-04-19 18:36:49 +04:00
vCounter + = 3 ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
if ( numNormals > 0 )
{
2016-01-18 15:36:18 +03:00
mesh . normals [ nCounter ] = midNormals [ vnNum [ 0 ] - 1 ] . x ;
mesh . normals [ nCounter + 1 ] = midNormals [ vnNum [ 0 ] - 1 ] . y ;
mesh . normals [ nCounter + 2 ] = midNormals [ vnNum [ 0 ] - 1 ] . z ;
2014-07-23 02:06:24 +04:00
nCounter + = 3 ;
2016-01-18 15:36:18 +03:00
mesh . normals [ nCounter ] = midNormals [ vnNum [ 1 ] - 1 ] . x ;
mesh . normals [ nCounter + 1 ] = midNormals [ vnNum [ 1 ] - 1 ] . y ;
mesh . normals [ nCounter + 2 ] = midNormals [ vnNum [ 1 ] - 1 ] . z ;
2014-07-23 02:06:24 +04:00
nCounter + = 3 ;
2016-01-18 15:36:18 +03:00
mesh . normals [ nCounter ] = midNormals [ vnNum [ 2 ] - 1 ] . x ;
mesh . normals [ nCounter + 1 ] = midNormals [ vnNum [ 2 ] - 1 ] . y ;
mesh . normals [ nCounter + 2 ] = midNormals [ vnNum [ 2 ] - 1 ] . z ;
2014-07-23 02:06:24 +04:00
nCounter + = 3 ;
}
else
{
// If normals not defined, they are calculated from the 3 vertices [N = (V2 - V1) x (V3 - V1)]
Vector3 norm = VectorCrossProduct ( VectorSubtract ( midVertices [ vNum [ 1 ] - 1 ] , midVertices [ vNum [ 0 ] - 1 ] ) , VectorSubtract ( midVertices [ vNum [ 2 ] - 1 ] , midVertices [ vNum [ 0 ] - 1 ] ) ) ;
VectorNormalize ( & norm ) ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
mesh . normals [ nCounter ] = norm . x ;
mesh . normals [ nCounter + 1 ] = norm . y ;
mesh . normals [ nCounter + 2 ] = norm . z ;
2014-07-23 02:06:24 +04:00
nCounter + = 3 ;
2016-01-18 15:36:18 +03:00
mesh . normals [ nCounter ] = norm . x ;
mesh . normals [ nCounter + 1 ] = norm . y ;
mesh . normals [ nCounter + 2 ] = norm . z ;
2014-07-23 02:06:24 +04:00
nCounter + = 3 ;
2016-01-18 15:36:18 +03:00
mesh . normals [ nCounter ] = norm . x ;
mesh . normals [ nCounter + 1 ] = norm . y ;
mesh . normals [ nCounter + 2 ] = norm . z ;
2014-07-23 02:06:24 +04:00
nCounter + = 3 ;
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
if ( numTexCoords > 0 )
{
2015-09-02 21:36:05 +03:00
// NOTE: If using negative texture coordinates with a texture filter of GL_CLAMP_TO_EDGE doesn't work!
// NOTE: Texture coordinates are Y flipped upside-down
2016-01-18 15:36:18 +03:00
mesh . texcoords [ tcCounter ] = midTexCoords [ vtNum [ 0 ] - 1 ] . x ;
mesh . texcoords [ tcCounter + 1 ] = 1.0f - midTexCoords [ vtNum [ 0 ] - 1 ] . y ;
2014-07-23 02:06:24 +04:00
tcCounter + = 2 ;
2016-01-18 15:36:18 +03:00
mesh . texcoords [ tcCounter ] = midTexCoords [ vtNum [ 1 ] - 1 ] . x ;
mesh . texcoords [ tcCounter + 1 ] = 1.0f - midTexCoords [ vtNum [ 1 ] - 1 ] . y ;
2014-07-23 02:06:24 +04:00
tcCounter + = 2 ;
2016-01-18 15:36:18 +03:00
mesh . texcoords [ tcCounter ] = midTexCoords [ vtNum [ 2 ] - 1 ] . x ;
mesh . texcoords [ tcCounter + 1 ] = 1.0f - midTexCoords [ vtNum [ 2 ] - 1 ] . y ;
2014-07-23 02:06:24 +04:00
tcCounter + = 2 ;
}
2014-04-19 18:36:49 +04:00
} break ;
default : break ;
}
}
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
fclose ( objFile ) ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
// Security check, just in case no normals or no texcoords defined in OBJ
2016-01-18 15:36:18 +03:00
if ( numTexCoords = = 0 ) for ( int i = 0 ; i < ( 2 * mesh . vertexCount ) ; i + + ) mesh . texcoords [ i ] = 0.0f ;
2015-09-02 21:36:05 +03:00
2014-04-19 18:36:49 +04:00
// NOTE: We set all vertex colors to white
2015-01-02 22:59:54 +03:00
// NOTE: Not used any more... just one plain color defined at DrawModel()
2016-01-18 15:36:18 +03:00
for ( int i = 0 ; i < ( 4 * mesh . vertexCount ) ; i + + ) mesh . colors [ i ] = 255 ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
// Now we can free temp mid* arrays
free ( midVertices ) ;
free ( midNormals ) ;
free ( midTexCoords ) ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
// NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct
2014-04-19 18:36:49 +04:00
TraceLog ( INFO , " [%s] Model loaded successfully in RAM (CPU) " , fileName ) ;
2014-09-03 18:51:28 +04:00
2016-01-18 15:36:18 +03:00
return mesh ;
2014-12-31 20:03:32 +03:00
}