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 3d shapes and load/draw 3d models (.OBJ)
|
2013-11-19 02:38:44 +04:00
|
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
|
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
|
|
|
|
|
*
|
|
|
|
|
* This software is provided "as-is", without any express or implied warranty. In no event
|
|
|
|
|
* will the authors be held liable for any damages arising from the use of this software.
|
2013-11-19 02:38:44 +04:00
|
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
|
* Permission is granted to anyone to use this software for any purpose, including commercial
|
|
|
|
|
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
2013-11-19 02:38:44 +04:00
|
|
|
|
*
|
2013-11-23 16:30:54 +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
|
|
|
|
|
* 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"
|
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
|
#include <GL/gl.h> // OpenGL functions
|
|
|
|
|
#include <stdio.h> // Standard input/output functions, used to read model files data
|
|
|
|
|
#include <stdlib.h> // Declares malloc() and free() for memory management
|
|
|
|
|
#include <math.h> // Used for sin, cos, tan
|
2014-03-25 15:40:35 +04:00
|
|
|
|
|
|
|
|
|
#include "raymath.h" // Required for data type Matrix and Matrix functions
|
|
|
|
|
|
|
|
|
|
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
|
2013-11-19 02:38:44 +04:00
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
// Defines and Macros
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
// Nop...
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
// Types and Structures Definition
|
|
|
|
|
//----------------------------------------------------------------------------------
|
2014-03-25 15:40:35 +04:00
|
|
|
|
#ifdef USE_OPENGL_11
|
|
|
|
|
struct Model {
|
|
|
|
|
int numVertices;
|
|
|
|
|
Vector3 *vertices;
|
|
|
|
|
Vector2 *texcoords;
|
|
|
|
|
Vector3 *normals;
|
|
|
|
|
};
|
|
|
|
|
#else
|
|
|
|
|
struct Model {
|
|
|
|
|
int numVertices;
|
|
|
|
|
Vector3 *vertices;
|
|
|
|
|
Vector2 *texcoords;
|
|
|
|
|
Vector3 *normals;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
struct Model
|
|
|
|
|
{
|
|
|
|
|
GLUint vaoId;
|
|
|
|
|
Matrix transform;
|
|
|
|
|
int polyMode;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
#endif
|
2013-11-19 02:38:44 +04:00
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
// Global Variables Definition
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
// It's lonely here...
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
// Module specific Functions Declaration
|
|
|
|
|
//----------------------------------------------------------------------------------
|
2014-01-29 00:21:29 +04:00
|
|
|
|
static float GetHeightValue(Color pixel);
|
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
|
2013-11-19 02:38:44 +04:00
|
|
|
|
void DrawCube(Vector3 position, float width, float height, float lenght, Color color)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// THIS WORKS!
|
|
|
|
|
/*
|
|
|
|
|
Matrix mat = MatrixTranslate(2.0, 0.0, 0.0);
|
|
|
|
|
MatrixTranspose(&mat);
|
|
|
|
|
VectorTransform(&position, mat);
|
|
|
|
|
|
|
|
|
|
PrintMatrix(mat);
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
float x = position.x;
|
|
|
|
|
float y = position.y;
|
|
|
|
|
float z = position.z;
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlPushMatrix();
|
|
|
|
|
|
|
|
|
|
// NOTE: Be careful! Function order matters (scale, translate, rotate)
|
|
|
|
|
//rlScalef(2.0f, 2.0f, 2.0f);
|
|
|
|
|
//rlTranslatef(2.0f, 0.0f, 0.0f);
|
|
|
|
|
rlRotatef(45, 0, 1, 0);
|
|
|
|
|
|
|
|
|
|
rlBegin(RL_QUADS);
|
|
|
|
|
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
|
|
|
|
|
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Left Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/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
|
|
|
|
|
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Left Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z-lenght/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
|
|
|
|
|
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Bottom Left Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Bottom Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z-lenght/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
|
|
|
|
|
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Top Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Top Left Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Left Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z+lenght/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
|
|
|
|
|
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Left Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z+lenght/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
|
|
|
|
|
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Left Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Right Of The Texture and Quad
|
|
|
|
|
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left Of The Texture and Quad
|
|
|
|
|
rlEnd();
|
|
|
|
|
rlPopMatrix();
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw cube (Vector version)
|
|
|
|
|
void DrawCubeV(Vector3 position, Vector3 size, Color color)
|
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
|
DrawCube(position, size.x, size.y, size.z, color);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw cube wires
|
|
|
|
|
void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// TODO: Draw cube using RL_LINES!
|
|
|
|
|
|
|
|
|
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
|
|
|
//DrawCube(position, width, height, lenght, color);
|
|
|
|
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
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)
|
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
|
float lat0, z0, zr0;
|
|
|
|
|
float lat1, z1, zr1;
|
|
|
|
|
float lng, x, y;
|
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// TODO: Review vertex translate/rotate/scale mechanism
|
|
|
|
|
|
|
|
|
|
rlPushMatrix();
|
|
|
|
|
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
|
|
|
|
|
rlRotatef(90, 1, 0, 0);
|
|
|
|
|
rlScalef(radius, radius, radius);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlBegin(GL_QUAD_STRIP);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
for(int i = 0; i <= rings; i++)
|
|
|
|
|
{
|
|
|
|
|
lat0 = PI * (-0.5 + (float)(i - 1) / rings);
|
|
|
|
|
z0 = sin(lat0);
|
|
|
|
|
zr0 = cos(lat0);
|
|
|
|
|
|
|
|
|
|
lat1 = PI * (-0.5 + (float)i / rings);
|
|
|
|
|
z1 = sin(lat1);
|
|
|
|
|
zr1 = cos(lat1);
|
|
|
|
|
|
|
|
|
|
for(int j = 0; j <= slices; j++)
|
|
|
|
|
{
|
|
|
|
|
lng = 2 * PI * (float)(j - 1) / slices;
|
|
|
|
|
x = cos(lng);
|
|
|
|
|
y = sin(lng);
|
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlNormal3f(x * zr0, y * zr0, z0);
|
|
|
|
|
rlVertex3f(x * zr0, y * zr0, z0);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlNormal3f(x * zr1, y * zr1, z1);
|
|
|
|
|
rlVertex3f(x * zr1, y * zr1, z1);
|
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
|
|
|
|
|
void DrawSphereWires(Vector3 centerPos, float radius, Color color)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// TODO: Draw sphere using RL_LINES!
|
|
|
|
|
|
|
|
|
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
|
|
|
//DrawSphere(centerPos, radius, color);
|
|
|
|
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw a cylinder/cone
|
2013-11-23 16:30:54 +04:00
|
|
|
|
void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color) // Could be used for pyramid and cone!
|
2013-11-19 02:38:44 +04:00
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
|
Vector3 a = { position.x, position.y + height, position.z };
|
|
|
|
|
Vector3 d = { 0.0f, 1.0f, 0.0f };
|
|
|
|
|
Vector3 p;
|
|
|
|
|
Vector3 c = { a.x + (-d.x * height), a.y + (-d.y * height), a.z + (-d.z * height) }; //= a + (-d * h);
|
|
|
|
|
Vector3 e0 = VectorPerpendicular(d);
|
|
|
|
|
Vector3 e1 = VectorCrossProduct(e0, d);
|
|
|
|
|
float angInc = 360.0 / slices * DEG2RAD;
|
|
|
|
|
|
|
|
|
|
if (radiusTop == 0) // Draw pyramid or cone
|
|
|
|
|
{
|
|
|
|
|
//d – axis defined as a normalized vector from base to apex
|
|
|
|
|
//a – position of apex (top point)
|
|
|
|
|
//h – height
|
|
|
|
|
//rd – radius of directrix
|
|
|
|
|
//n – number of radial "slices"
|
2014-03-25 15:40:35 +04:00
|
|
|
|
|
|
|
|
|
// TODO: Review drawing to use RL_TRIANGLES
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// Draw cone top
|
|
|
|
|
rlBegin(GL_TRIANGLE_FAN);
|
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
|
|
|
|
rlVertex3f(a.x, a.y, a.z);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
for (int i = 0; i <= slices; i++)
|
|
|
|
|
{
|
|
|
|
|
float rad = angInc * i;
|
|
|
|
|
p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusBottom);
|
|
|
|
|
p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusBottom);
|
|
|
|
|
p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusBottom);
|
|
|
|
|
rlVertex3f(p.x, p.y, p.z);
|
|
|
|
|
}
|
|
|
|
|
rlEnd();
|
|
|
|
|
|
|
|
|
|
// Draw cone bottom
|
|
|
|
|
rlBegin(GL_TRIANGLE_FAN);
|
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
|
|
|
|
rlVertex3f(c.x, c.y, c.z);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
for (int i = slices; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
float rad = angInc * i;
|
|
|
|
|
p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusBottom);
|
|
|
|
|
p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusBottom);
|
|
|
|
|
p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusBottom);
|
|
|
|
|
rlVertex3f(p.x, p.y, p.z);
|
|
|
|
|
}
|
|
|
|
|
rlEnd();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else // Draw cylinder
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
|
|
|
|
|
// TODO: Review drawing to use RL_TRIANGLES
|
|
|
|
|
|
|
|
|
|
// Draw cylinder top (pointed cap)
|
|
|
|
|
rlBegin(GL_TRIANGLE_FAN);
|
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
|
|
|
|
rlVertex3f(c.x, c.y + height, c.z);
|
|
|
|
|
for (int i = slices; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
float rad = angInc * i;
|
|
|
|
|
p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusTop);
|
|
|
|
|
p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusTop) + height;
|
|
|
|
|
p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusTop);
|
|
|
|
|
rlVertex3f(p.x, p.y, p.z);
|
|
|
|
|
}
|
|
|
|
|
rlEnd();
|
|
|
|
|
|
|
|
|
|
// Draw cylinder sides
|
|
|
|
|
rlBegin(GL_TRIANGLE_STRIP);
|
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
|
|
|
|
for (int i = slices; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
float rad = angInc * i;
|
|
|
|
|
p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusTop);
|
|
|
|
|
p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusTop) + height;
|
|
|
|
|
p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusTop);
|
|
|
|
|
rlVertex3f(p.x, p.y, p.z);
|
|
|
|
|
|
|
|
|
|
p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusBottom);
|
|
|
|
|
p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusBottom);
|
|
|
|
|
p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusBottom);
|
|
|
|
|
rlVertex3f(p.x, p.y, p.z);
|
|
|
|
|
}
|
|
|
|
|
rlEnd();
|
|
|
|
|
|
|
|
|
|
// Draw cylinder bottom
|
|
|
|
|
rlBegin(GL_TRIANGLE_FAN);
|
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
|
|
|
|
rlVertex3f(c.x, c.y, c.z);
|
|
|
|
|
for (int i = slices; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
float rad = angInc * i;
|
|
|
|
|
p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusBottom);
|
|
|
|
|
p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusBottom);
|
|
|
|
|
p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusBottom);
|
|
|
|
|
rlVertex3f(p.x, p.y, p.z);
|
|
|
|
|
}
|
|
|
|
|
rlEnd();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw a cylinder/cone wires
|
|
|
|
|
void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// TODO: Draw sphere using RL_LINES!
|
|
|
|
|
|
|
|
|
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
DrawCylinder(position, radiusTop, radiusBottom, height, slices, color);
|
2014-03-25 15:40:35 +04:00
|
|
|
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw a plane
|
|
|
|
|
void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// TODO: Review vertex translate/rotate/scale mechanism
|
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
|
// NOTE: Plane is always created on XZ ground and then rotated
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlPushMatrix();
|
|
|
|
|
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
// TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions...
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlRotatef(rotation.x, 1, 0, 0);
|
|
|
|
|
rlRotatef(rotation.y, 0, 1, 0);
|
|
|
|
|
rlRotatef(rotation.z, 0, 0, 1);
|
|
|
|
|
rlScalef(size.x, 1.0f, size.y);
|
|
|
|
|
|
|
|
|
|
rlBegin(GL_QUADS);
|
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
|
|
|
|
rlNormal3f(0.0f, 1.0f, 0.0f);
|
|
|
|
|
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(-0.5f, 0.0f, -0.5f);
|
|
|
|
|
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(0.5f, 0.0f, -0.5f);
|
|
|
|
|
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(0.5f, 0.0f, 0.5f);
|
|
|
|
|
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(-0.5f, 0.0f, 0.5f);
|
|
|
|
|
rlEnd();
|
|
|
|
|
rlPopMatrix();
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw a plane with divisions
|
|
|
|
|
void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color)
|
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
|
float quadWidth = size.x / slicesX;
|
|
|
|
|
float quadLenght = size.y / slicesZ;
|
|
|
|
|
|
|
|
|
|
float texPieceW = 1 / size.x;
|
|
|
|
|
float texPieceH = 1 / size.y;
|
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// TODO: Review vertex translate/rotate/scale mechanism
|
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
|
// NOTE: Plane is always created on XZ ground and then rotated
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlPushMatrix();
|
|
|
|
|
rlTranslatef(-size.x / 2, 0.0f, -size.y / 2);
|
|
|
|
|
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
// TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions...
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlRotatef(rotation.x, 1, 0, 0);
|
|
|
|
|
rlRotatef(rotation.y, 0, 1, 0);
|
|
|
|
|
rlRotatef(rotation.z, 0, 0, 1);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlBegin(RL_QUADS);
|
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
|
|
|
|
rlNormal3f(0.0f, 1.0f, 0.0f);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
for (int z = 0; z < slicesZ; z++)
|
|
|
|
|
{
|
|
|
|
|
for (int x = 0; x < slicesX; x++)
|
|
|
|
|
{
|
|
|
|
|
// Draw the plane quad by quad (with textcoords)
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlTexCoord2f((float)x * texPieceW, (float)z * texPieceH);
|
|
|
|
|
rlVertex3f((float)x * quadWidth, 0.0f, (float)z * quadLenght);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlTexCoord2f((float)x * texPieceW + texPieceW, (float)z * texPieceH);
|
|
|
|
|
rlVertex3f((float)x * quadWidth + quadWidth, 0.0f, (float)z * quadLenght);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlTexCoord2f((float)x * texPieceW + texPieceW, (float)z * texPieceH + texPieceH);
|
|
|
|
|
rlVertex3f((float)x * quadWidth + quadWidth, 0.0f, (float)z * quadLenght + quadLenght);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlTexCoord2f((float)x * texPieceW, (float)z * texPieceH + texPieceH);
|
|
|
|
|
rlVertex3f((float)x * quadWidth, 0.0f, (float)z * quadLenght + quadLenght);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlEnd();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlPopMatrix();
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw gizmo (with or without orbits)
|
|
|
|
|
void DrawGizmo(Vector3 position, bool orbits)
|
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
|
// NOTE: RGB = XYZ
|
|
|
|
|
float lenght = 1.0f;
|
|
|
|
|
float radius = 1.0f;
|
|
|
|
|
|
|
|
|
|
//glEnable(GL_LINE_SMOOTH); // Smoothies circle outline (anti-aliasing applied)
|
|
|
|
|
//glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Best quality for line smooth (anti-aliasing best algorithm)
|
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// GL_LINE_SMOOTH is very poorly supported on desktop GL.
|
|
|
|
|
// A lot of drivers ignore it, so most people avoid using...
|
|
|
|
|
|
|
|
|
|
rlPushMatrix();
|
|
|
|
|
rlTranslatef(position.x, position.y, position.z);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
//glRotatef(rotation, 0, 1, 0);
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlScalef(lenght, lenght, lenght);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlBegin(GL_LINES);
|
|
|
|
|
rlColor3f(1.0f, 0.0f, 0.0f);
|
|
|
|
|
rlVertex3f(0.0f, 0.0f, 0.0f);
|
|
|
|
|
rlVertex3f(1.0f, 0.0f, 0.0f);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlColor3f(0.0f, 1.0f, 0.0f);
|
|
|
|
|
rlVertex3f(0.0f, 0.0f, 0.0f);
|
|
|
|
|
rlVertex3f(0.0f, 1.0f, 0.0f);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlColor3f(0.0f, 0.0f, 1.0f);
|
|
|
|
|
rlVertex3f(0.0f, 0.0f, 0.0f);
|
|
|
|
|
rlVertex3f(0.0f, 0.0f, 1.0f);
|
|
|
|
|
rlEnd();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
if (orbits)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlBegin(GL_LINE_LOOP);
|
|
|
|
|
rlColor4f(1.0f, 0.0f, 0.0f, 0.4f);
|
|
|
|
|
for (int i=0; i < 360; i++) rlVertex3f(sin(DEG2RAD*i) * radius, 0, cos(DEG2RAD*i) * radius);
|
|
|
|
|
rlEnd();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlBegin(GL_LINE_LOOP);
|
|
|
|
|
rlColor4f(0.0f, 1.0f, 0.0f, 0.4f);
|
|
|
|
|
for (int i=0; i < 360; i++) rlVertex3f(sin(DEG2RAD*i) * radius, cos(DEG2RAD*i) * radius, 0);
|
|
|
|
|
rlEnd();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlBegin(GL_LINE_LOOP);
|
|
|
|
|
rlColor4f(0.0f, 0.0f, 1.0f, 0.4f);
|
|
|
|
|
for (int i=0; i < 360; i++) rlVertex3f(0, sin(DEG2RAD*i) * radius, cos(DEG2RAD*i) * radius);
|
|
|
|
|
rlEnd();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlPopMatrix();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
//glDisable(GL_LINE_SMOOTH);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load a 3d model (.OBJ)
|
|
|
|
|
// TODO: Add comments explaining this function process
|
|
|
|
|
Model LoadModel(const char *fileName)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
struct Model model;
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
char dataType;
|
|
|
|
|
char comments[200];
|
|
|
|
|
|
|
|
|
|
int numVertex = 0;
|
|
|
|
|
int numNormals = 0;
|
|
|
|
|
int numTexCoords = 0;
|
|
|
|
|
int numTriangles = 0;
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
FILE* objFile;
|
2013-11-19 02:38:44 +04:00
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
objFile = fopen(fileName, "rt");
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
while(!feof(objFile))
|
2013-11-23 16:30:54 +04:00
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
switch(dataType)
|
|
|
|
|
{
|
|
|
|
|
case '#': // It's a comment
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
} break;
|
|
|
|
|
case 'v':
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
if (dataType == 't') // Read texCoord
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
while (dataType == 'v')
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataType == '#')
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%i", &numTexCoords);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else printf("Ouch! Something was wrong...");
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else if (dataType == 'n') // Read normals
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
while (dataType == 'v')
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataType == '#')
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%i", &numNormals);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else printf("Ouch! Something was wrong...");
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else // Read vertex
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
while (dataType == 'v')
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataType == '#')
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%i", &numVertex);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else printf("Ouch! Something was wrong...");
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
case 'f':
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
while (dataType == 'f')
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataType == '#')
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%i", &numTriangles);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else printf("Ouch! Something was wrong...");
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector3 midVertices[numVertex];
|
|
|
|
|
Vector3 midNormals[numNormals];
|
|
|
|
|
Vector2 midTexCoords[numTexCoords];
|
|
|
|
|
|
|
|
|
|
model.numVertices = numTriangles*3;
|
|
|
|
|
|
|
|
|
|
model.vertices = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
|
|
|
|
|
model.normals = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
|
|
|
|
|
model.texcoords = (Vector2 *)malloc(model.numVertices * sizeof(Vector2));
|
|
|
|
|
|
|
|
|
|
int countVertex = 0;
|
|
|
|
|
int countNormals = 0;
|
|
|
|
|
int countTexCoords = 0;
|
|
|
|
|
|
|
|
|
|
int countMaxVertex = 0;
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
rewind(objFile);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
while(!feof(objFile))
|
2013-11-23 16:30:54 +04:00
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
switch(dataType)
|
|
|
|
|
{
|
|
|
|
|
case '#':
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fgets(comments, 200, objFile);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
} break;
|
|
|
|
|
case 'v':
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
if (dataType == 't') // Read texCoord
|
|
|
|
|
{
|
|
|
|
|
float useless = 0;
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%f %f %f", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y, &useless);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
countTexCoords++;
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else if (dataType == 'n') // Read normals
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z );
|
2013-11-23 16:30:54 +04:00
|
|
|
|
countNormals++;
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
else // Read vertex
|
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z );
|
2013-11-23 16:30:54 +04:00
|
|
|
|
countVertex++;
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
case 'f':
|
|
|
|
|
{
|
|
|
|
|
int vNum, vtNum, vnNum;
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%c", &dataType);
|
|
|
|
|
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
model.vertices[countMaxVertex] = midVertices[vNum-1];
|
|
|
|
|
model.normals[countMaxVertex] = midNormals[vnNum-1];
|
|
|
|
|
model.texcoords[countMaxVertex].x = midTexCoords[vtNum-1].x;
|
|
|
|
|
model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
|
|
|
|
|
countMaxVertex++;
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
model.vertices[countMaxVertex] = midVertices[vNum-1];
|
|
|
|
|
model.normals[countMaxVertex] = midNormals[vnNum-1];
|
|
|
|
|
model.texcoords[countMaxVertex].x = midTexCoords[vtNum-1].x;
|
|
|
|
|
model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
|
|
|
|
|
countMaxVertex++;
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
model.vertices[countMaxVertex] = midVertices[vNum-1];
|
|
|
|
|
model.normals[countMaxVertex] = midNormals[vnNum-1];
|
|
|
|
|
model.texcoords[countMaxVertex].x = midTexCoords[vtNum-1].x;
|
|
|
|
|
model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
|
|
|
|
|
countMaxVertex++;
|
|
|
|
|
} break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
fclose(objFile);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
#ifdef USE_OPENGL_33
|
|
|
|
|
|
|
|
|
|
// TODO: Use loaded data to generate VAO
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
|
return model;
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-30 21:12:40 +04:00
|
|
|
|
// Load a heightmap image as a 3d model
|
2014-01-29 00:21:29 +04:00
|
|
|
|
Model LoadHeightmap(Image heightmap, float maxHeight)
|
2013-11-30 21:12:40 +04:00
|
|
|
|
{
|
|
|
|
|
Model model;
|
|
|
|
|
|
|
|
|
|
int mapX = heightmap.width;
|
2014-03-16 23:59:02 +04:00
|
|
|
|
int mapZ = heightmap.height;
|
2013-11-30 21:12:40 +04:00
|
|
|
|
|
|
|
|
|
// NOTE: One vertex per pixel
|
|
|
|
|
// TODO: Consider resolution when generating model data?
|
|
|
|
|
int numTriangles = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
|
|
|
|
|
|
|
|
|
|
model.numVertices = numTriangles*3;
|
|
|
|
|
|
|
|
|
|
model.vertices = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
|
|
|
|
|
model.normals = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
|
|
|
|
|
model.texcoords = (Vector2 *)malloc(model.numVertices * sizeof(Vector2));
|
2014-01-29 00:21:29 +04:00
|
|
|
|
|
|
|
|
|
int vCounter = 0;
|
|
|
|
|
int trisCounter = 0;
|
|
|
|
|
|
|
|
|
|
float scaleFactor = maxHeight/255; // TODO: Review scaleFactor calculation
|
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
|
|
|
|
//----------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// one triangle - 3 vertex
|
|
|
|
|
model.vertices[vCounter].x = x;
|
|
|
|
|
model.vertices[vCounter].y = GetHeightValue(heightmap.pixels[x + z*mapX])*scaleFactor;
|
|
|
|
|
model.vertices[vCounter].z = z;
|
|
|
|
|
|
|
|
|
|
model.vertices[vCounter+1].x = x;
|
|
|
|
|
model.vertices[vCounter+1].y = GetHeightValue(heightmap.pixels[x + (z+1)*mapX])*scaleFactor;
|
|
|
|
|
model.vertices[vCounter+1].z = z+1;
|
|
|
|
|
|
|
|
|
|
model.vertices[vCounter+2].x = x+1;
|
|
|
|
|
model.vertices[vCounter+2].y = GetHeightValue(heightmap.pixels[(x+1) + z*mapX])*scaleFactor;
|
|
|
|
|
model.vertices[vCounter+2].z = z;
|
|
|
|
|
|
|
|
|
|
// another triangle - 3 vertex
|
|
|
|
|
model.vertices[vCounter+3] = model.vertices[vCounter+2];
|
|
|
|
|
model.vertices[vCounter+4] = model.vertices[vCounter+1];
|
|
|
|
|
|
|
|
|
|
model.vertices[vCounter+5].x = x+1;
|
|
|
|
|
model.vertices[vCounter+5].y = GetHeightValue(heightmap.pixels[(x+1) + (z+1)*mapX])*scaleFactor;
|
|
|
|
|
model.vertices[vCounter+5].z = z+1;
|
|
|
|
|
|
|
|
|
|
// Fill texcoords array with data
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
model.texcoords[vCounter].x = (float)x / (mapX-1);
|
|
|
|
|
model.texcoords[vCounter].y = (float)z / (mapZ-1);
|
|
|
|
|
|
|
|
|
|
model.texcoords[vCounter+1].x = (float)x / (mapX-1);
|
|
|
|
|
model.texcoords[vCounter+1].y = (float)(z+1) / (mapZ-1);
|
|
|
|
|
|
|
|
|
|
model.texcoords[vCounter+2].x = (float)(x+1) / (mapX-1);
|
|
|
|
|
model.texcoords[vCounter+2].y = (float)z / (mapZ-1);
|
|
|
|
|
|
|
|
|
|
model.texcoords[vCounter+3] = model.texcoords[vCounter+2];
|
|
|
|
|
model.texcoords[vCounter+4] = model.texcoords[vCounter+1];
|
|
|
|
|
|
|
|
|
|
model.texcoords[vCounter+5].x = (float)(x+1) / (mapX-1);
|
|
|
|
|
model.texcoords[vCounter+5].y = (float)(z+1) / (mapZ-1);
|
|
|
|
|
|
|
|
|
|
// Fill normals array with data
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
// TODO: Review normals calculation
|
|
|
|
|
model.normals[vCounter] = (Vector3){ 0.0f, 1.0f, 0.0f };
|
|
|
|
|
model.normals[vCounter+1] = (Vector3){ 0.0f, 1.0f, 0.0f };
|
|
|
|
|
model.normals[vCounter+2] = (Vector3){ 0.0f, 1.0f, 0.0f };
|
|
|
|
|
model.normals[vCounter+3] = (Vector3){ 0.0f, 1.0f, 0.0f };
|
|
|
|
|
model.normals[vCounter+4] = (Vector3){ 0.0f, 1.0f, 0.0f };
|
|
|
|
|
model.normals[vCounter+5] = (Vector3){ 0.0f, 1.0f, 0.0f };
|
|
|
|
|
|
|
|
|
|
vCounter += 6;
|
|
|
|
|
trisCounter += 2;
|
2014-03-16 23:59:02 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-25 15:40:35 +04:00
|
|
|
|
|
|
|
|
|
#ifdef USE_OPENGL_33
|
|
|
|
|
|
|
|
|
|
// TODO: Use loaded data to generate VAO
|
|
|
|
|
|
|
|
|
|
#endif
|
2013-11-30 21:12:40 +04:00
|
|
|
|
|
|
|
|
|
return model;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
|
// Unload 3d model from memory
|
|
|
|
|
void UnloadModel(Model model)
|
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
|
free(model.vertices);
|
|
|
|
|
free(model.texcoords);
|
|
|
|
|
free(model.normals);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw a model
|
|
|
|
|
void DrawModel(Model model, Vector3 position, float scale, Color color)
|
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
|
// NOTE: For models we use Vertex Arrays (OpenGL 1.1)
|
2014-01-29 00:21:29 +04:00
|
|
|
|
//static int rotation = 0;
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// NOTE: Add OpenGL 3.3+ VAOs-based drawing! --> Move this stuff to rlgl?
|
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array
|
|
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array
|
|
|
|
|
glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array
|
|
|
|
|
|
|
|
|
|
glVertexPointer(3, GL_FLOAT, 0, model.vertices); // Pointer to vertex coords array
|
|
|
|
|
glTexCoordPointer(2, GL_FLOAT, 0, model.texcoords); // Pointer to texture coords array
|
|
|
|
|
glNormalPointer(GL_FLOAT, 0, model.normals); // Pointer to normals array
|
|
|
|
|
//glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.colors); // Pointer to colors array (NOT USED)
|
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlPushMatrix();
|
|
|
|
|
rlTranslatef(position.x, position.y, position.z);
|
2013-11-24 23:30:34 +04:00
|
|
|
|
//glRotatef(rotation * GetFrameTime(), 0, 1, 0);
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlScalef(scale, scale, scale);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, model.numVertices);
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlPopMatrix();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array
|
|
|
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array
|
|
|
|
|
glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array
|
2014-01-29 00:21:29 +04:00
|
|
|
|
|
|
|
|
|
//rotation += 10;
|
2014-03-25 15:40:35 +04:00
|
|
|
|
|
|
|
|
|
// Model drawing in OpenGL 3.3+, transform is passed to shader
|
|
|
|
|
/*
|
|
|
|
|
glUseProgram(shaderProgram); // Use our shader
|
|
|
|
|
|
|
|
|
|
Matrix modelview = MatrixMultiply(model.transform, view);
|
|
|
|
|
|
|
|
|
|
glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection));
|
|
|
|
|
glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelview));
|
|
|
|
|
glUniform1i(textureLoc, 0);
|
|
|
|
|
|
|
|
|
|
glBindVertexArray(model.vaoId);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, model.texId);
|
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, model.numVertices);
|
|
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
|
|
|
|
|
glBindVertexArray(0); // Unbind VAO
|
|
|
|
|
*/
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw a textured model
|
|
|
|
|
void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlEnableTexture(texture.glId);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
|
|
DrawModel(model, position, scale, tint);
|
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlDisableTexture();
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw a model wires
|
|
|
|
|
void DrawModelWires(Model model, Vector3 position, float scale, Color color)
|
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
|
// TODO: Draw model using RL_LINES... or look for a way to deal with polygon mode!
|
|
|
|
|
|
|
|
|
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
DrawModel(model, position, scale, color);
|
2014-03-25 15:40:35 +04:00
|
|
|
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
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
|
|
|
|
{
|
2014-03-16 23:59:02 +04:00
|
|
|
|
// NOTE: Billboard size will maintain texture aspect ratio, size will be billboard width
|
2013-11-23 16:30:54 +04:00
|
|
|
|
Vector2 sizeRatio = { size, size * (float)texture.height/texture.width };
|
|
|
|
|
|
2014-03-16 23:59:02 +04:00
|
|
|
|
Matrix viewMatrix = MatrixLookAt(camera.position, camera.target, camera.up);
|
|
|
|
|
MatrixTranspose(&viewMatrix);
|
|
|
|
|
|
|
|
|
|
Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 };
|
|
|
|
|
Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 };
|
|
|
|
|
/*
|
|
|
|
|
d-------c
|
|
|
|
|
| |
|
|
|
|
|
| * |
|
|
|
|
|
| |
|
|
|
|
|
a-------b
|
|
|
|
|
*/
|
|
|
|
|
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-03-25 15:40:35 +04:00
|
|
|
|
rlEnableTexture(texture.glId);
|
2014-03-16 23:59:02 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlBegin(RL_QUADS);
|
|
|
|
|
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
|
|
|
|
rlNormal3f(0.0f, 1.0f, 0.0f);
|
|
|
|
|
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(a.x, a.y, a.z);
|
|
|
|
|
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(b.x, b.y, b.z);
|
|
|
|
|
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(c.x, c.y, c.z);
|
|
|
|
|
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(d.x, d.y, d.z);
|
|
|
|
|
rlEnd();
|
|
|
|
|
|
|
|
|
|
rlDisableTexture();
|
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
|
|
|
|
|
Vector2 sizeRatio = { size, size * (float)sourceRec.height/sourceRec.width };
|
|
|
|
|
|
|
|
|
|
Matrix viewMatrix = MatrixLookAt(camera.position, camera.target, camera.up);
|
|
|
|
|
MatrixTranspose(&viewMatrix);
|
|
|
|
|
|
|
|
|
|
Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 };
|
|
|
|
|
Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 };
|
|
|
|
|
/*
|
|
|
|
|
d-------c
|
|
|
|
|
| |
|
|
|
|
|
| * |
|
|
|
|
|
| |
|
|
|
|
|
a-------b
|
|
|
|
|
*/
|
|
|
|
|
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-03-25 15:40:35 +04:00
|
|
|
|
rlEnableTexture(texture.glId);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlBegin(RL_QUADS);
|
|
|
|
|
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
2014-03-16 23:59:02 +04:00
|
|
|
|
|
|
|
|
|
// Bottom-left corner for texture and quad
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
|
|
|
|
|
rlVertex3f(a.x, a.y, a.z);
|
2014-03-16 23:59:02 +04:00
|
|
|
|
|
|
|
|
|
// Bottom-right corner for texture and quad
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
|
|
|
|
|
rlVertex3f(b.x, b.y, b.z);
|
2014-03-16 23:59:02 +04:00
|
|
|
|
|
|
|
|
|
// Top-right corner for texture and quad
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
|
|
|
|
|
rlVertex3f(c.x, c.y, c.z);
|
2014-03-16 23:59:02 +04:00
|
|
|
|
|
|
|
|
|
// Top-left corner for texture and quad
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
|
|
|
|
|
rlVertex3f(d.x, d.y, d.z);
|
|
|
|
|
rlEnd();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
|
rlDisableTexture();
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
|
// Get current vertex y altitude (proportional to pixel colors in grayscale)
|
|
|
|
|
static float GetHeightValue(Color pixel)
|
2013-11-19 02:38:44 +04:00
|
|
|
|
{
|
2014-01-29 00:21:29 +04:00
|
|
|
|
return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
}
|