Big batch of changes, check description:

- Camera system moved to a separate module [camera.c]
- WIP: Added customization functions for camera controls
- Added custom shaders support on batch drawing
- Complete redesign of textures module to support multiple texture
formats (compressed and uncompressed)
This commit is contained in:
raysan5 2015-05-04 23:46:31 +02:00
parent ba257b09f5
commit eae98e1c34
14 changed files with 1487 additions and 876 deletions

View File

@ -0,0 +1,86 @@
/*******************************************************************************************
*
* raylib [models] example - Load and draw a 3d model (OBJ)
*
* This example has been created using raylib 1.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
********************************************************************************************/
#include "raylib.h"
int main()
{
// Initialization
//--------------------------------------------------------------------------------------
int screenWidth = 1280;
int screenHeight = 720;
InitWindow(screenWidth, screenHeight, "raylib [models] example - custom shader");
// Define the camera to look into our 3d world
Camera camera = {{ 10.0, 8.0, 10.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }};
Texture2D texture = LoadTexture("resources/catsham.png"); // Load model texture
Shader shader = LoadShader("resources/shaders/custom.vs", "resources/shaders/custom.fs");
//Shader poste = LoadShader("resources/shaders/custom.vs", "resources/shaders/pixel.fs");
Model cat = LoadModel("resources/cat.obj"); // Load OBJ model
SetModelTexture(&cat, texture); // Bind texture to model
//SetModelShader(&cat, poste);
Vector3 catPosition = { 0.0, 0.0, 0.0 }; // Set model position
SetPostproShader(shader);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyDown(KEY_LEFT)) catPosition.x -= 0.2;
if (IsKeyDown(KEY_RIGHT)) catPosition.x += 0.2;
if (IsKeyDown(KEY_UP)) catPosition.z -= 0.2;
if (IsKeyDown(KEY_DOWN)) catPosition.z += 0.2;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
Begin3dMode(camera);
DrawModel(cat, catPosition, 0.1f, WHITE); // Draw 3d model with texture
DrawGrid(10.0, 1.0); // Draw a grid
DrawGizmo(catPosition); // Draw gizmo
End3dMode();
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadTexture(texture); // Unload texture
UnloadModel(cat); // Unload model
UnloadShader(shader);
//UnloadShader(poste);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -0,0 +1,19 @@
#version 110
attribute vec3 vertexPosition;
attribute vec2 vertexTexCoord;
attribute vec4 vertexColor;
uniform mat4 projectionMatrix;
uniform mat4 modelviewMatrix;
varying vec2 fragTexCoord;
varying vec4 fragColor;
void main()
{
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
gl_Position = projectionMatrix*modelviewMatrix*vec4(vertexPosition, 1.0);
}

View File

@ -0,0 +1,16 @@
#version 330
uniform sampler2D texture0;
varying vec2 fragTexCoord;
uniform vec4 tintColor;
void main()
{
vec4 base = texture2D(texture0, fragTexCoord)*tintColor;
// Convert to grayscale using NTSC conversion weights
float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = vec4(gray, gray, gray, tintColor.a);
}

View File

@ -0,0 +1,16 @@
#version 330
attribute vec3 vertexPosition;
attribute vec2 vertexTexCoord;
attribute vec3 vertexNormal;
uniform mat4 projectionMatrix;
uniform mat4 modelviewMatrix;
varying vec2 fragTexCoord;
void main()
{
fragTexCoord = vertexTexCoord;
gl_Position = projectionMatrix*modelviewMatrix*vec4(vertexPosition, 1.0);
}

View File

@ -0,0 +1,15 @@
#version 110
uniform sampler2D texture0;
varying vec2 fragTexCoord;
varying vec4 fragColor;
void main()
{
vec4 base = texture2D(texture0, fragTexCoord)*fragColor;
// Convert to grayscale using NTSC conversion weights
float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = vec4(gray, gray, gray, base.a);
}

476
src/camera.c Normal file
View File

@ -0,0 +1,476 @@
/**********************************************************************************************
*
* raylib.camera
*
* Camera Modes Setup and Control Functions
*
* Copyright (c) 2015 Marc Palau and Ramon Santamaria
*
* 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.
*
* 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:
*
* 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.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#include "raylib.h"
#include <math.h>
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// CAMERA_GENERIC
#define CAMERA_SCROLL_SENSITIVITY 1.5
// FREE_CAMERA
#define FREE_CAMERA_MOUSE_SENSITIVITY 0.01
#define FREE_CAMERA_DISTANCE_MIN_CLAMP 0.3
#define FREE_CAMERA_DISTANCE_MAX_CLAMP 12
#define FREE_CAMERA_MIN_CLAMP 85
#define FREE_CAMERA_MAX_CLAMP -85
#define FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY 0.05
#define FREE_CAMERA_PANNING_DIVIDER 5.1
// ORBITAL_CAMERA
#define ORBITAL_CAMERA_SPEED 0.01
// FIRST_PERSON
//#define FIRST_PERSON_MOUSE_SENSITIVITY 0.003
#define FIRST_PERSON_FOCUS_DISTANCE 25
#define FIRST_PERSON_MIN_CLAMP 85
#define FIRST_PERSON_MAX_CLAMP -85
#define FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0
#define FIRST_PERSON_STEP_DIVIDER 30.0
#define FIRST_PERSON_WAVING_DIVIDER 200.0
#define FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION 0.85
// THIRD_PERSON
//#define THIRD_PERSON_MOUSE_SENSITIVITY 0.003
#define THIRD_PERSON_DISTANCE_CLAMP 1.2
#define THIRD_PERSON_MIN_CLAMP 5
#define THIRD_PERSON_MAX_CLAMP -85
#define THIRD_PERSON_OFFSET (Vector3){ 0.4, 0, 0 }
// PLAYER (used by camera)
#define PLAYER_WIDTH 0.4
#define PLAYER_HEIGHT 0.9
#define PLAYER_DEPTH 0.4
#define PLAYER_MOVEMENT_DIVIDER 20.0
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static Camera internalCamera = {{2,0,2},{0,0,0},{0,1,0}};
static Vector2 cameraAngle = { 0, 0 };
static float cameraTargetDistance = 5;
static Vector3 resetingPosition = { 0, 0, 0 };
static int resetingKey = 'Z';
static Vector2 cameraMousePosition = { 0, 0 };
static Vector2 cameraMouseVariation = { 0, 0 };
static float mouseSensitivity = 0.003;
static int cameraMovementController[6] = { 'W', 'A', 'S', 'D', 'E', 'Q' };
static int cameraMovementCounter = 0;
static bool cameraUseGravity = true;
static int pawnControllingKey = MOUSE_MIDDLE_BUTTON;
static int fnControllingKey = KEY_LEFT_ALT;
static int smoothZoomControllingKey = KEY_LEFT_CONTROL;
static int cameraMode = CAMERA_CUSTOM;
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static void ProcessCamera(Camera *camera, Vector3 *playerPosition);
/*
static void SetCameraControls(int front, int left, int back, right, up, down);
static void SetMouseSensitivity(int sensitivity);
static void SetResetPosition(Vector3 resetPosition);
static void SetResetControl(int resetKey);
static void SetPawnControl(int pawnControlKey);
static void SetFnControl(int fnControlKey);
static void SetSmoothZoomControl(int smoothZoomControlKey);
*/
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Select camera mode (multiple camera modes available)
void SetCameraMode(int mode)
{
if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_FREE))
{
cameraMode = CAMERA_THIRD_PERSON;
cameraTargetDistance = 5;
cameraAngle.y = -40 * DEG2RAD;
ProcessCamera(&internalCamera, &internalCamera.position);
}
else if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_ORBITAL))
{
cameraMode = CAMERA_THIRD_PERSON;
cameraTargetDistance = 5;
cameraAngle.y = -40 * DEG2RAD;
ProcessCamera(&internalCamera, &internalCamera.position);
}
else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_FREE))
{
cameraTargetDistance = 10;
cameraAngle.x = 45 * DEG2RAD;
cameraAngle.y = -40 * DEG2RAD;
internalCamera.target = (Vector3){ 0, 0, 0};
ProcessCamera(&internalCamera, &internalCamera.position);
}
else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_ORBITAL))
{
cameraTargetDistance = 10;
cameraAngle.x = 225 * DEG2RAD;
cameraAngle.y = -40 * DEG2RAD;
internalCamera.target = (Vector3){ 3, 0, 3};
ProcessCamera(&internalCamera, &internalCamera.position);
}
cameraMode = mode;
}
// Update camera with position
Camera UpdateCamera(Vector3 *position)
{
// Calculate camera
if (cameraMode != CAMERA_CUSTOM) ProcessCamera(&internalCamera, position);
return internalCamera;
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
// Process desired camera mode and controls
static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
{
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI)
// Mouse movement detection
if (cameraMode != CAMERA_FREE)
{
HideCursor();
if (GetMousePosition().x < GetScreenHeight() / 3) SetMousePosition((Vector2){ GetScreenWidth() - GetScreenHeight() / 3, GetMousePosition().y});
else if (GetMousePosition().y < GetScreenHeight() / 3) SetMousePosition((Vector2){ GetMousePosition().x, GetScreenHeight() - GetScreenHeight() / 3});
else if (GetMousePosition().x > GetScreenWidth() - GetScreenHeight() / 3) SetMousePosition((Vector2) { GetScreenHeight() / 3, GetMousePosition().y});
else if (GetMousePosition().y > GetScreenHeight() - GetScreenHeight() / 3) SetMousePosition((Vector2){ GetMousePosition().x, GetScreenHeight() / 3});
else
{
cameraMouseVariation.x = GetMousePosition().x - cameraMousePosition.x;
cameraMouseVariation.y = GetMousePosition().y - cameraMousePosition.y;
}
}
else
{
ShowCursor();
cameraMouseVariation.x = GetMousePosition().x - cameraMousePosition.x;
cameraMouseVariation.y = GetMousePosition().y - cameraMousePosition.y;
}
cameraMousePosition = GetMousePosition();
// Support for multiple automatic camera modes
switch (cameraMode)
{
case CAMERA_FREE:
{
// Camera zoom
if ((cameraTargetDistance < FREE_CAMERA_DISTANCE_MAX_CLAMP) && (GetMouseWheelMove() < 0))
{
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
if (cameraTargetDistance > FREE_CAMERA_DISTANCE_MAX_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MAX_CLAMP;
}
// Camera looking down
else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == FREE_CAMERA_DISTANCE_MAX_CLAMP) && (GetMouseWheelMove() < 0))
{
camera->target.x += GetMouseWheelMove() * (camera->target.x - camera->position.x) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.y += GetMouseWheelMove() * (camera->target.y - camera->position.y) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.z += GetMouseWheelMove() * (camera->target.z - camera->position.z) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
}
else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
{
camera->target.x += GetMouseWheelMove() * (camera->target.x - camera->position.x) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.y += GetMouseWheelMove() * (camera->target.y - camera->position.y) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.z += GetMouseWheelMove() * (camera->target.z - camera->position.z) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
if (camera->target.y < 0) camera->target.y = -0.001;
}
else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (GetMouseWheelMove() > 0))
{
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
if (cameraTargetDistance < FREE_CAMERA_DISTANCE_MIN_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MIN_CLAMP;
}
// Camera looking up
else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == FREE_CAMERA_DISTANCE_MAX_CLAMP) && (GetMouseWheelMove() < 0))
{
camera->target.x += GetMouseWheelMove() * (camera->target.x - camera->position.x) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.y += GetMouseWheelMove() * (camera->target.y - camera->position.y) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.z += GetMouseWheelMove() * (camera->target.z - camera->position.z) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
}
else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
{
camera->target.x += GetMouseWheelMove() * (camera->target.x - camera->position.x) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.y += GetMouseWheelMove() * (camera->target.y - camera->position.y) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.z += GetMouseWheelMove() * (camera->target.z - camera->position.z) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
if (camera->target.y > 0) camera->target.y = 0.001;
}
else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (GetMouseWheelMove() > 0))
{
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
if (cameraTargetDistance < FREE_CAMERA_DISTANCE_MIN_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MIN_CLAMP;
}
// Inputs
if (IsKeyDown(fnControllingKey))
{
if (IsKeyDown(smoothZoomControllingKey))
{
// Camera smooth zoom
if (IsMouseButtonDown(pawnControllingKey)) cameraTargetDistance += (cameraMouseVariation.y * FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY);
}
// Camera orientation calculation
else if (IsMouseButtonDown(pawnControllingKey))
{
// Camera orientation calculation
// Get the mouse sensitivity
cameraAngle.x += cameraMouseVariation.x * -FREE_CAMERA_MOUSE_SENSITIVITY;
cameraAngle.y += cameraMouseVariation.y * -FREE_CAMERA_MOUSE_SENSITIVITY;
// Angle clamp
if (cameraAngle.y > FREE_CAMERA_MIN_CLAMP * DEG2RAD) cameraAngle.y = FREE_CAMERA_MIN_CLAMP * DEG2RAD;
else if (cameraAngle.y < FREE_CAMERA_MAX_CLAMP * DEG2RAD) cameraAngle.y = FREE_CAMERA_MAX_CLAMP * DEG2RAD;
}
}
// Paning
else if (IsMouseButtonDown(pawnControllingKey))
{
camera->target.x += ((cameraMouseVariation.x * -FREE_CAMERA_MOUSE_SENSITIVITY) * cos(cameraAngle.x) + (cameraMouseVariation.y * FREE_CAMERA_MOUSE_SENSITIVITY) * sin(cameraAngle.x) * sin(cameraAngle.y)) * (cameraTargetDistance / FREE_CAMERA_PANNING_DIVIDER);
camera->target.y += ((cameraMouseVariation.y * FREE_CAMERA_MOUSE_SENSITIVITY) * cos(cameraAngle.y)) * (cameraTargetDistance / FREE_CAMERA_PANNING_DIVIDER);
camera->target.z += ((cameraMouseVariation.x * FREE_CAMERA_MOUSE_SENSITIVITY) * sin(cameraAngle.x) + (cameraMouseVariation.y * FREE_CAMERA_MOUSE_SENSITIVITY) * cos(cameraAngle.x) * sin(cameraAngle.y)) * (cameraTargetDistance / FREE_CAMERA_PANNING_DIVIDER);
}
// Focus to center
if (IsKeyDown(resetingKey)) camera->target = resetingPosition;
// Camera position update
camera->position.x = sin(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.x;
if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.z;
} break;
case CAMERA_ORBITAL:
{
cameraAngle.x += ORBITAL_CAMERA_SPEED;
// Camera zoom
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
// Camera distance clamp
if (cameraTargetDistance < THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = THIRD_PERSON_DISTANCE_CLAMP;
// Focus to center
if (IsKeyDown('Z')) camera->target = (Vector3) { 0, 0, 0 };
// Camera position update
camera->position.x = sin(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.x;
if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.z;
} break;
case CAMERA_FIRST_PERSON:
case CAMERA_THIRD_PERSON:
{
bool isMoving = false;
// Keyboard inputs
if (IsKeyDown(cameraMovementController[0]))
{
playerPosition->x -= sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
playerPosition->z -= cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
if (!cameraUseGravity) camera->position.y += sin(cameraAngle.y) / PLAYER_MOVEMENT_DIVIDER;
isMoving = true;
}
else if (IsKeyDown(cameraMovementController[2]))
{
playerPosition->x += sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
playerPosition->z += cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
if (!cameraUseGravity) camera->position.y -= sin(cameraAngle.y) / PLAYER_MOVEMENT_DIVIDER;
isMoving = true;
}
if (IsKeyDown(cameraMovementController[1]))
{
playerPosition->x -= cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
playerPosition->z += sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
isMoving = true;
}
else if (IsKeyDown(cameraMovementController[3]))
{
playerPosition->x += cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
playerPosition->z -= sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
isMoving = true;
}
if (IsKeyDown(cameraMovementController[4]))
{
if (!cameraUseGravity) playerPosition->y += 1 / PLAYER_MOVEMENT_DIVIDER;
}
else if (IsKeyDown(cameraMovementController[5]))
{
if (!cameraUseGravity) playerPosition->y -= 1 / PLAYER_MOVEMENT_DIVIDER;
}
if (cameraMode == CAMERA_THIRD_PERSON)
{
// Camera orientation calculation
// Get the mouse sensitivity
cameraAngle.x += cameraMouseVariation.x * -mouseSensitivity;
cameraAngle.y += cameraMouseVariation.y * -mouseSensitivity;
// Angle clamp
if (cameraAngle.y > THIRD_PERSON_MIN_CLAMP * DEG2RAD) cameraAngle.y = THIRD_PERSON_MIN_CLAMP * DEG2RAD;
else if (cameraAngle.y < THIRD_PERSON_MAX_CLAMP * DEG2RAD) cameraAngle.y = THIRD_PERSON_MAX_CLAMP * DEG2RAD;
// Camera zoom
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
// Camera distance clamp
if (cameraTargetDistance < THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = THIRD_PERSON_DISTANCE_CLAMP;
// Camera is always looking at player
camera->target.x = playerPosition->x + THIRD_PERSON_OFFSET.x * cos(cameraAngle.x) + THIRD_PERSON_OFFSET.z * sin(cameraAngle.x);
camera->target.y = playerPosition->y + PLAYER_HEIGHT * FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION + THIRD_PERSON_OFFSET.y;
camera->target.z = playerPosition->z + THIRD_PERSON_OFFSET.z * sin(cameraAngle.x) - THIRD_PERSON_OFFSET.x * sin(cameraAngle.x);
// Camera position update
camera->position.x = sin(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.x;
if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.z;
}
else
{
if (isMoving) cameraMovementCounter++;
// Camera orientation calculation
// Get the mouse sensitivity
cameraAngle.x += cameraMouseVariation.x * -mouseSensitivity;
cameraAngle.y += cameraMouseVariation.y * -mouseSensitivity;
// Angle clamp
if (cameraAngle.y > FIRST_PERSON_MIN_CLAMP * DEG2RAD) cameraAngle.y = FIRST_PERSON_MIN_CLAMP * DEG2RAD;
else if (cameraAngle.y < FIRST_PERSON_MAX_CLAMP * DEG2RAD) cameraAngle.y = FIRST_PERSON_MAX_CLAMP * DEG2RAD;
// Camera is always looking at player
camera->target.x = camera->position.x - sin(cameraAngle.x) * FIRST_PERSON_FOCUS_DISTANCE;
camera->target.y = camera->position.y + sin(cameraAngle.y) * FIRST_PERSON_FOCUS_DISTANCE;
camera->target.z = camera->position.z - cos(cameraAngle.x) * FIRST_PERSON_FOCUS_DISTANCE;
camera->position.x = playerPosition->x;
camera->position.y = (playerPosition->y + PLAYER_HEIGHT * FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION) - sin(cameraMovementCounter / FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER) / FIRST_PERSON_STEP_DIVIDER;
camera->position.z = playerPosition->z;
camera->up.x = sin(cameraMovementCounter / (FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER * 2)) / FIRST_PERSON_WAVING_DIVIDER;
camera->up.z = -sin(cameraMovementCounter / (FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER * 2)) / FIRST_PERSON_WAVING_DIVIDER;
}
} break;
default: break;
}
#endif
}
void SetCameraControls(int frontKey, int leftKey, int backKey, int rightKey, int upKey, int downKey)
{
cameraMovementController[0] = frontKey;
cameraMovementController[1] = leftKey;
cameraMovementController[2] = backKey;
cameraMovementController[3] = rightKey;
cameraMovementController[4] = upKey;
cameraMovementController[5] = downKey;
}
void SetMouseSensitivity(float sensitivity)
{
mouseSensitivity = (sensitivity / 10000.0);
}
void SetResetPosition(Vector3 resetPosition)
{
resetingPosition = resetPosition;
}
void SetResetControl(int resetKey)
{
resetingKey = resetKey;
}
void SetPawnControl(int pawnControlKey)
{
pawnControllingKey = pawnControlKey;
}
void SetFnControl(int fnControlKey)
{
fnControllingKey = fnControlKey;
}
void SetSmoothZoomControl(int smoothZoomControlKey)
{
smoothZoomControllingKey = smoothZoomControlKey;
}

View File

@ -45,7 +45,7 @@
#include <stdio.h> // Standard input / output lib
#include <stdlib.h> // Declares malloc() and free() for memory management, rand(), atexit()
#include <stdint.h> // Required for typedef unsigned long long int uint64_t, used by hi-res timer
#include <time.h> // Useful to initialize random seed - Android/RPI hi-res timer
#include <time.h> // Useful to initialize random seed - Android/RPI hi-res timer (NOTE: Linux only!)
#include <math.h> // Math related functions, tan() used to set perspective
#include <string.h> // String function definitions, memset()
#include <errno.h> // Macros for reporting and retrieving error conditions through error codes
@ -99,48 +99,6 @@
//----------------------------------------------------------------------------------
#define MAX_TOUCH_POINTS 256
// Camera System configuration
//----------------------------------------------------------------------------------
// CAMERA_GENERIC
#define CAMERA_SCROLL_SENSITIVITY 1.5
// FREE_CAMERA
#define FREE_CAMERA_MOUSE_SENSITIVITY 0.01
#define FREE_CAMERA_DISTANCE_MIN_CLAMP 0.3
#define FREE_CAMERA_DISTANCE_MAX_CLAMP 12
#define FREE_CAMERA_MIN_CLAMP 85
#define FREE_CAMERA_MAX_CLAMP -85
#define FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY 0.05
#define FREE_CAMERA_PANNING_DIVIDER 5.1
// ORBITAL_CAMERA
#define ORBITAL_CAMERA_SPEED 0.01
// FIRST_PERSON
#define FIRST_PERSON_MOUSE_SENSITIVITY 0.003
#define FIRST_PERSON_FOCUS_DISTANCE 25
#define FIRST_PERSON_MIN_CLAMP 85
#define FIRST_PERSON_MAX_CLAMP -85
#define FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0
#define FIRST_PERSON_STEP_DIVIDER 30.0
#define FIRST_PERSON_WAVING_DIVIDER 200.0
#define FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION 0.85
// THIRD_PERSON
#define THIRD_PERSON_MOUSE_SENSITIVITY 0.003
#define THIRD_PERSON_DISTANCE_CLAMP 1.2
#define THIRD_PERSON_MIN_CLAMP 5
#define THIRD_PERSON_MAX_CLAMP -85
#define THIRD_PERSON_OFFSET (Vector3){ 0.4, 0, 0 }
// PLAYER (used by camera)
#define PLAYER_WIDTH 0.4
#define PLAYER_HEIGHT 0.9
#define PLAYER_DEPTH 0.4
#define PLAYER_MOVEMENT_DIVIDER 20.0
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@ -207,7 +165,6 @@ static bool cursorOnScreen = false; // Tracks if cursor is inside client
static Texture2D cursor; // Cursor texture
static Vector2 mousePosition;
static bool cursorHidden;
static char previousKeyState[512] = { 0 }; // Required to check if key pressed/released once
static char currentKeyState[512] = { 0 }; // Required to check if key pressed/released once
@ -225,6 +182,8 @@ static int exitKey = KEY_ESCAPE; // Default exit key (ESC)
static int lastKeyPressed = -1;
#endif
static bool cursorHidden;
static double currentTime, previousTime; // Used to track timmings
static double updateTime, drawTime; // Time measures for update and draw
static double frameTime; // Time measure for one frame
@ -233,17 +192,6 @@ static double targetTime = 0.0; // Desired time for one frame, if 0
static char configFlags = 0;
static bool showLogo = false;
// Camera variables
static int cameraMode = CAMERA_CUSTOM;
static Camera currentCamera;
static Camera internalCamera = {{2,0,2},{0,0,0},{0,1,0}};
static Vector2 cameraAngle = { 0, 0 };
static float cameraTargetDistance = 5;
static Vector2 cameraMousePosition = { 0, 0 };
static Vector2 cameraMouseVariation = { 0, 0 };
static int cameraMovementCounter = 0;
static bool cameraUseGravity = true;
// Shaders variables
static bool enabledPostpro = false;
@ -306,8 +254,6 @@ static void TakeScreenshot(void);
static void AndroidCommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands
#endif
static void ProcessCamera(Camera *camera, Vector3 *playerPosition);
//----------------------------------------------------------------------------------
// Module Functions Definition - Window and OpenGL Context Functions
//----------------------------------------------------------------------------------
@ -600,10 +546,7 @@ void Begin3dMode(Camera camera)
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
// Setup Camera view
if (cameraMode == CAMERA_CUSTOM) currentCamera = camera;
else currentCamera = internalCamera;
Matrix view = MatrixLookAt(currentCamera.position, currentCamera.target, currentCamera.up);
Matrix view = MatrixLookAt(camera.position, camera.target, camera.up);
rlMultMatrixf(GetMatrixVector(view)); // Multiply MODELVIEW matrix by view matrix (camera)
}
@ -707,7 +650,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
Ray ray;
Matrix proj = MatrixIdentity();
Matrix view = MatrixLookAt(currentCamera.position, currentCamera.target, currentCamera.up);
Matrix view = MatrixLookAt(camera.position, camera.target, camera.up);
float aspect = (GLfloat)GetScreenWidth()/(GLfloat)GetScreenHeight();
double top = 0.1f*tanf(45.0f*PI / 360.0f);
@ -725,7 +668,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
Vector3 nearPoint = { mousePosition.x, realy, 0.0f };
Vector3 farPoint = { mousePosition.x, realy, 1.0f };
nearPoint = internalCamera.position;
//nearPoint = internalCamera.position;
farPoint = rlglUnproject(farPoint, proj, view);
Vector3 direction = VectorSubtract(farPoint, nearPoint);
@ -734,72 +677,9 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
ray.position = nearPoint;
ray.direction = direction;
// Test
Vector2 screenPos;
screenPos.x = (mousePosition.x / (float)GetScreenWidth() * 2.0) - 1.0f;
screenPos.y = (mousePosition.y / (float)GetScreenHeight() * 2.0) - 1.0f;
direction = VectorSubtract(internalCamera.target, internalCamera.position);
printf("/nScreenPos %f, %f", screenPos.x, screenPos.y);
Matrix rotate;
rotate = MatrixIdentity();
rotate = MatrixRotate(0, 45*DEG2RAD*screenPos.y, 0);
VectorTransform(&direction, rotate);
VectorNormalize(&direction);
ray.position = internalCamera.position;
ray.direction = direction;
return ray;
}
void SetCameraMode(int mode)
{
if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_FREE))
{
cameraMode = CAMERA_THIRD_PERSON;
cameraTargetDistance = 5;
cameraAngle.y = -40 * DEG2RAD;
ProcessCamera(&internalCamera, &internalCamera.position);
}
else if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_ORBITAL))
{
cameraMode = CAMERA_THIRD_PERSON;
cameraTargetDistance = 5;
cameraAngle.y = -40 * DEG2RAD;
ProcessCamera(&internalCamera, &internalCamera.position);
}
else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_FREE))
{
cameraTargetDistance = 10;
cameraAngle.x = 45 * DEG2RAD;
cameraAngle.y = -40 * DEG2RAD;
internalCamera.target = (Vector3){ 0, 0, 0};
ProcessCamera(&internalCamera, &internalCamera.position);
}
else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_ORBITAL))
{
cameraTargetDistance = 10;
cameraAngle.x = 225 * DEG2RAD;
cameraAngle.y = -40 * DEG2RAD;
internalCamera.target = (Vector3){ 3, 0, 3};
ProcessCamera(&internalCamera, &internalCamera.position);
}
cameraMode = mode;
}
Camera UpdateCamera(Vector3 *position)
{
// Calculate camera
if (cameraMode != CAMERA_CUSTOM) ProcessCamera(&internalCamera, position);
return internalCamera;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions
//----------------------------------------------------------------------------------
@ -915,8 +795,8 @@ int GetMouseWheelMove(void)
{
return previousMouseWheelY;
}
#endif
// Hide mouse cursor
void HideCursor()
{
#if defined(PLATFORM_DESKTOP)
@ -936,6 +816,7 @@ void HideCursor()
cursorHidden = true;
}
// Show mouse cursor
void ShowCursor()
{
#if defined(PLATFORM_DESKTOP)
@ -948,10 +829,12 @@ void ShowCursor()
cursorHidden = false;
}
// Check if mouse cursor is hidden
bool IsCursorHidden()
{
return cursorHidden;
}
#endif
// TODO: Enable gamepad usage on Rapsberry Pi
// NOTE: emscripten not implemented
@ -1105,6 +988,18 @@ void SetPostproShader(Shader shader)
}
}
// Set custom shader to be used in batch draw
void SetCustomShader(Shader shader)
{
rlglSetCustomShader(shader);
}
// Set default shader to be used in batch draw
void SetDefaultShader(void)
{
rlglSetDefaultShader();
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
@ -2161,260 +2056,3 @@ static void LogoAnimation(void)
showLogo = false; // Prevent for repeating when reloading window (Android)
}
// Process desired camera mode and controls
static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
{
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI)
// Mouse movement detection
if (cameraMode != CAMERA_FREE)
{
HideCursor();
if (GetMousePosition().x < GetScreenHeight() / 3) SetMousePosition((Vector2){ screenWidth - GetScreenHeight() / 3, GetMousePosition().y});
else if (GetMousePosition().y < GetScreenHeight() / 3) SetMousePosition((Vector2){ GetMousePosition().x, screenHeight - GetScreenHeight() / 3});
else if (GetMousePosition().x > screenWidth - GetScreenHeight() / 3) SetMousePosition((Vector2) { GetScreenHeight() / 3, GetMousePosition().y});
else if (GetMousePosition().y > screenHeight - GetScreenHeight() / 3) SetMousePosition((Vector2){ GetMousePosition().x, GetScreenHeight() / 3});
else
{
cameraMouseVariation.x = GetMousePosition().x - cameraMousePosition.x;
cameraMouseVariation.y = GetMousePosition().y - cameraMousePosition.y;
}
}
else
{
ShowCursor();
cameraMouseVariation.x = GetMousePosition().x - cameraMousePosition.x;
cameraMouseVariation.y = GetMousePosition().y - cameraMousePosition.y;
}
cameraMousePosition = GetMousePosition();
// Support for multiple automatic camera modes
switch (cameraMode)
{
case CAMERA_FREE:
{
// Pass to orbiting camera
if (IsKeyPressed('O')) cameraMode = CAMERA_ORBITAL;
// Camera zoom
if ((cameraTargetDistance < FREE_CAMERA_DISTANCE_MAX_CLAMP) && (GetMouseWheelMove() < 0))
{
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
if (cameraTargetDistance > FREE_CAMERA_DISTANCE_MAX_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MAX_CLAMP;
}
// Camera looking down
else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == FREE_CAMERA_DISTANCE_MAX_CLAMP) && (GetMouseWheelMove() < 0))
{
camera->target.x += GetMouseWheelMove() * (camera->target.x - camera->position.x) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.y += GetMouseWheelMove() * (camera->target.y - camera->position.y) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.z += GetMouseWheelMove() * (camera->target.z - camera->position.z) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
}
else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
{
camera->target.x += GetMouseWheelMove() * (camera->target.x - camera->position.x) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.y += GetMouseWheelMove() * (camera->target.y - camera->position.y) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.z += GetMouseWheelMove() * (camera->target.z - camera->position.z) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
if (camera->target.y < 0) camera->target.y = -0.001;
}
else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (GetMouseWheelMove() > 0))
{
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
if (cameraTargetDistance < FREE_CAMERA_DISTANCE_MIN_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MIN_CLAMP;
}
// Camera looking up
else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == FREE_CAMERA_DISTANCE_MAX_CLAMP) && (GetMouseWheelMove() < 0))
{
camera->target.x += GetMouseWheelMove() * (camera->target.x - camera->position.x) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.y += GetMouseWheelMove() * (camera->target.y - camera->position.y) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.z += GetMouseWheelMove() * (camera->target.z - camera->position.z) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
}
else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
{
camera->target.x += GetMouseWheelMove() * (camera->target.x - camera->position.x) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.y += GetMouseWheelMove() * (camera->target.y - camera->position.y) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
camera->target.z += GetMouseWheelMove() * (camera->target.z - camera->position.z) * CAMERA_SCROLL_SENSITIVITY / cameraTargetDistance;
if (camera->target.y > 0) camera->target.y = 0.001;
}
else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (GetMouseWheelMove() > 0))
{
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
if (cameraTargetDistance < FREE_CAMERA_DISTANCE_MIN_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MIN_CLAMP;
}
// Inputs
if (IsKeyDown(KEY_LEFT_ALT))
{
if (IsKeyDown(KEY_LEFT_CONTROL))
{
// Camera smooth zoom
if (IsMouseButtonDown(MOUSE_MIDDLE_BUTTON)) cameraTargetDistance += (cameraMouseVariation.y * FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY);
}
// Camera orientation calculation
else if (IsMouseButtonDown(MOUSE_MIDDLE_BUTTON))
{
// Camera orientation calculation
// Get the mouse sensitivity
cameraAngle.x += cameraMouseVariation.x * -FREE_CAMERA_MOUSE_SENSITIVITY;
cameraAngle.y += cameraMouseVariation.y * -FREE_CAMERA_MOUSE_SENSITIVITY;
// Angle clamp
if (cameraAngle.y > FREE_CAMERA_MIN_CLAMP * DEG2RAD) cameraAngle.y = FREE_CAMERA_MIN_CLAMP * DEG2RAD;
else if (cameraAngle.y < FREE_CAMERA_MAX_CLAMP * DEG2RAD) cameraAngle.y = FREE_CAMERA_MAX_CLAMP * DEG2RAD;
}
}
// Paning
else if (IsMouseButtonDown(MOUSE_MIDDLE_BUTTON))
{
camera->target.x += ((cameraMouseVariation.x * -FREE_CAMERA_MOUSE_SENSITIVITY) * cos(cameraAngle.x) + (cameraMouseVariation.y * FREE_CAMERA_MOUSE_SENSITIVITY) * sin(cameraAngle.x) * sin(cameraAngle.y)) * (cameraTargetDistance / FREE_CAMERA_PANNING_DIVIDER);
camera->target.y += ((cameraMouseVariation.y * FREE_CAMERA_MOUSE_SENSITIVITY) * cos(cameraAngle.y)) * (cameraTargetDistance / FREE_CAMERA_PANNING_DIVIDER);
camera->target.z += ((cameraMouseVariation.x * FREE_CAMERA_MOUSE_SENSITIVITY) * sin(cameraAngle.x) + (cameraMouseVariation.y * FREE_CAMERA_MOUSE_SENSITIVITY) * cos(cameraAngle.x) * sin(cameraAngle.y)) * (cameraTargetDistance / FREE_CAMERA_PANNING_DIVIDER);
}
// Focus to center
if (IsKeyDown('Z')) camera->target = (Vector3) { 0, 0, 0 };
// Camera position update
camera->position.x = sin(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.x;
if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.z;
} break;
case CAMERA_ORBITAL:
{
// Pass to free camera
if (IsKeyPressed('O')) cameraMode = CAMERA_FREE;
cameraAngle.x += ORBITAL_CAMERA_SPEED;
// Camera zoom
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
// Camera distance clamp
if (cameraTargetDistance < THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = THIRD_PERSON_DISTANCE_CLAMP;
// Focus to center
if (IsKeyDown('Z')) camera->target = (Vector3) { 0, 0, 0 };
// Camera position update
camera->position.x = sin(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.x;
if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.z;
} break;
case CAMERA_FIRST_PERSON:
case CAMERA_THIRD_PERSON:
{
bool isMoving = false;
// Keyboard inputs
if (IsKeyDown('W'))
{
playerPosition->x -= sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
playerPosition->z -= cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
if (!cameraUseGravity) camera->position.y += sin(cameraAngle.y) / PLAYER_MOVEMENT_DIVIDER;
isMoving = true;
}
else if (IsKeyDown('S'))
{
playerPosition->x += sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
playerPosition->z += cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
if (!cameraUseGravity) camera->position.y -= sin(cameraAngle.y) / PLAYER_MOVEMENT_DIVIDER;
isMoving = true;
}
if (IsKeyDown('A'))
{
playerPosition->x -= cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
playerPosition->z += sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
isMoving = true;
}
else if (IsKeyDown('D'))
{
playerPosition->x += cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
playerPosition->z -= sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER;
isMoving = true;
}
if (IsKeyDown('E'))
{
if (!cameraUseGravity) playerPosition->y += 1 / PLAYER_MOVEMENT_DIVIDER;
}
else if (IsKeyDown('Q'))
{
if (!cameraUseGravity) playerPosition->y -= 1 / PLAYER_MOVEMENT_DIVIDER;
}
if (cameraMode == CAMERA_THIRD_PERSON)
{
// Camera orientation calculation
// Get the mouse sensitivity
cameraAngle.x += cameraMouseVariation.x * -THIRD_PERSON_MOUSE_SENSITIVITY;
cameraAngle.y += cameraMouseVariation.y * -THIRD_PERSON_MOUSE_SENSITIVITY;
// Angle clamp
if (cameraAngle.y > THIRD_PERSON_MIN_CLAMP * DEG2RAD) cameraAngle.y = THIRD_PERSON_MIN_CLAMP * DEG2RAD;
else if (cameraAngle.y < THIRD_PERSON_MAX_CLAMP * DEG2RAD) cameraAngle.y = THIRD_PERSON_MAX_CLAMP * DEG2RAD;
// Camera zoom
cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY);
// Camera distance clamp
if (cameraTargetDistance < THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = THIRD_PERSON_DISTANCE_CLAMP;
// Camera is always looking at player
camera->target.x = playerPosition->x + THIRD_PERSON_OFFSET.x * cos(cameraAngle.x) + THIRD_PERSON_OFFSET.z * sin(cameraAngle.x);
camera->target.y = playerPosition->y + PLAYER_HEIGHT * FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION + THIRD_PERSON_OFFSET.y;
camera->target.z = playerPosition->z + THIRD_PERSON_OFFSET.z * sin(cameraAngle.x) - THIRD_PERSON_OFFSET.x * sin(cameraAngle.x);
// Camera position update
camera->position.x = sin(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.x;
if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y) * cameraTargetDistance * sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x) * cameraTargetDistance * cos(cameraAngle.y) + camera->target.z;
}
else
{
if (isMoving) cameraMovementCounter++;
// Camera orientation calculation
// Get the mouse sensitivity
cameraAngle.x += cameraMouseVariation.x * -FIRST_PERSON_MOUSE_SENSITIVITY;
cameraAngle.y += cameraMouseVariation.y * -FIRST_PERSON_MOUSE_SENSITIVITY;
// Angle clamp
if (cameraAngle.y > FIRST_PERSON_MIN_CLAMP * DEG2RAD) cameraAngle.y = FIRST_PERSON_MIN_CLAMP * DEG2RAD;
else if (cameraAngle.y < FIRST_PERSON_MAX_CLAMP * DEG2RAD) cameraAngle.y = FIRST_PERSON_MAX_CLAMP * DEG2RAD;
// Camera is always looking at player
camera->target.x = camera->position.x - sin(cameraAngle.x) * FIRST_PERSON_FOCUS_DISTANCE;
camera->target.y = camera->position.y + sin(cameraAngle.y) * FIRST_PERSON_FOCUS_DISTANCE;
camera->target.z = camera->position.z - cos(cameraAngle.x) * FIRST_PERSON_FOCUS_DISTANCE;
camera->position.x = playerPosition->x;
camera->position.y = (playerPosition->y + PLAYER_HEIGHT * FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION) - sin(cameraMovementCounter / FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER) / FIRST_PERSON_STEP_DIVIDER;
camera->position.z = playerPosition->z;
camera->up.x = sin(cameraMovementCounter / (FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER * 2)) / FIRST_PERSON_WAVING_DIVIDER;
camera->up.z = -sin(cameraMovementCounter / (FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER * 2)) / FIRST_PERSON_WAVING_DIVIDER;
}
} break;
default: break;
}
#endif
}

View File

@ -30,9 +30,14 @@
#include <stdlib.h> // malloc(), free()
#include <stdio.h> // printf(), fprintf()
#include <math.h> // Used for ...
#include <time.h> // Used for clock functions
#include <stdint.h> // Defines int32_t, int64_t
#if defined(_WIN32)
//#include <Windows.h>
#elif defined(__linux)
#include <time.h> // Used for clock functions
#endif
#if defined(PLATFORM_ANDROID)
#include <jni.h> // Java native interface
#include <android/sensor.h> // Android sensors functions
@ -75,15 +80,10 @@ typedef struct {
// Global Variables Definition
//----------------------------------------------------------------------------------
// typedef
static GestureType gestureType = TYPE_MOTIONLESS;
// Gestures detection variables
static double eventTime = 0;
//static int32_t touchId; // Not used...
// Event
static int64_t eventTime = 0;
// Tap
// Our initial press position on tap
static Vector2 initialTapPosition = { 0, 0 };
@ -127,7 +127,7 @@ static float pinchDelta = 0;
// Detected gesture
static int currentGesture = GESTURE_NONE;
static float touchX, touchY;
static Vector2 touchPosition;
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
@ -141,7 +141,7 @@ static float OnPinch();
static void SetDualInput(GestureEvent event);
static float Distance(Vector2 v1, Vector2 v2);
static float DotProduct(Vector2 v1, Vector2 v2);
static int GetCurrentTime();
static double GetCurrentTime();
#if defined(PLATFORM_WEB)
static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
@ -158,9 +158,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
// Returns tap position XY
extern Vector2 GetRawPosition(void)
{
Vector2 position = { touchX, touchY };
return position;
return touchPosition;
}
// Check if a gesture have been detected
@ -531,13 +529,27 @@ static float DotProduct(Vector2 v1, Vector2 v2)
return result;
}
static int GetCurrentTime()
static double GetCurrentTime()
{
#if defined(_WIN32)
/*
// NOTE: Requires Windows.h
FILETIME tm;
GetSystemTimePreciseAsFileTime(&tm);
ULONGLONG nowTime = ((ULONGLONG)tm.dwHighDateTime << 32) | (ULONGLONG)tm.dwLowDateTime; // Time provided in 100-nanosecond intervals
return ((double)nowTime/10000000.0); // Return time in seconds
*/
#endif
#if defined(__linux)
// NOTE: Only for Linux-based systems
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time provided in nanoseconds
return nowTime / 1000000; // Return time in miliseconds
return ((double)nowTime/1000000.0); // Return time in miliseconds
#endif
}
#if defined(PLATFORM_ANDROID)
@ -545,23 +557,21 @@ static int GetCurrentTime()
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
{
int type = AInputEvent_getType(event);
//int32_t key = 0;
if (type == AINPUT_EVENT_TYPE_MOTION)
{
touchX = AMotionEvent_getX(event, 0);
touchY = AMotionEvent_getY(event, 0);
touchPosition.x = AMotionEvent_getX(event, 0);
touchPosition.y = AMotionEvent_getY(event, 0);
}
else if (type == AINPUT_EVENT_TYPE_KEY)
{
//key = AKeyEvent_getKeyCode(event);
//int32_t key = AKeyEvent_getKeyCode(event);
//int32_t AKeyEvent_getMetaState(event);
}
int32_t action = AMotionEvent_getAction(event);
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
GestureEvent gestureEvent;
// Action
@ -609,6 +619,8 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent
}
*/
touchPosition = gestureEvent.position[0];
GestureEvent gestureEvent;
// Action

View File

@ -599,6 +599,8 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
int mapX = heightmap.width;
int mapZ = heightmap.height;
Color *heightmapPixels = GetPixelData(heightmap);
// NOTE: One vertex per pixel
// TODO: Consider resolution when generating model data?
@ -628,15 +630,15 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
// one triangle - 3 vertex
vData.vertices[vCounter] = x;
vData.vertices[vCounter + 1] = GetHeightValue(heightmap.pixels[x + z*mapX])*scaleFactor;
vData.vertices[vCounter + 1] = GetHeightValue(heightmapPixels[x + z*mapX])*scaleFactor;
vData.vertices[vCounter + 2] = z;
vData.vertices[vCounter + 3] = x;
vData.vertices[vCounter + 4] = GetHeightValue(heightmap.pixels[x + (z+1)*mapX])*scaleFactor;
vData.vertices[vCounter + 4] = GetHeightValue(heightmapPixels[x + (z+1)*mapX])*scaleFactor;
vData.vertices[vCounter + 5] = z+1;
vData.vertices[vCounter + 6] = x+1;
vData.vertices[vCounter + 7] = GetHeightValue(heightmap.pixels[(x+1) + z*mapX])*scaleFactor;
vData.vertices[vCounter + 7] = GetHeightValue(heightmapPixels[(x+1) + z*mapX])*scaleFactor;
vData.vertices[vCounter + 8] = z;
// another triangle - 3 vertex
@ -649,7 +651,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
vData.vertices[vCounter + 14] = vData.vertices[vCounter + 5];
vData.vertices[vCounter + 15] = x+1;
vData.vertices[vCounter + 16] = GetHeightValue(heightmap.pixels[(x+1) + (z+1)*mapX])*scaleFactor;
vData.vertices[vCounter + 16] = GetHeightValue(heightmapPixels[(x+1) + (z+1)*mapX])*scaleFactor;
vData.vertices[vCounter + 17] = z+1;
vCounter += 18; // 6 vertex, 18 floats
@ -691,6 +693,8 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
trisCounter += 2;
}
}
free(heightmapPixels);
// Fill color data
// NOTE: Not used any more... just one plain color defined at DrawModel()
@ -713,17 +717,19 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
}
// Load a map image as a 3d model (cubes based)
Model LoadCubicmap(Image cubesmap)
Model LoadCubicmap(Image cubicmap)
{
VertexData vData;
Color *cubicmapPixels = GetPixelData(cubicmap);
// Map cube size will be 1.0
float mapCubeSide = 1.0f;
int mapWidth = cubesmap.width * (int)mapCubeSide;
int mapHeight = cubesmap.height * (int)mapCubeSide;
int mapWidth = cubicmap.width * (int)mapCubeSide;
int mapHeight = cubicmap.height * (int)mapCubeSide;
// NOTE: Max possible number of triangles numCubes * (12 triangles by cube)
int maxTriangles = cubesmap.width*cubesmap.height*12;
int maxTriangles = cubicmap.width*cubicmap.height*12;
int vCounter = 0; // Used to count vertices
int tcCounter = 0; // Used to count texcoords
@ -775,9 +781,9 @@ Model LoadCubicmap(Image cubesmap)
Vector3 v8 = { x + w/2, 0, z + h/2 };
// We check pixel color to be WHITE, we will full cubes
if ((cubesmap.pixels[z*cubesmap.width + x].r == 255) &&
(cubesmap.pixels[z*cubesmap.width + x].g == 255) &&
(cubesmap.pixels[z*cubesmap.width + x].b == 255))
if ((cubicmapPixels[z*cubicmap.width + x].r == 255) &&
(cubicmapPixels[z*cubicmap.width + x].g == 255) &&
(cubicmapPixels[z*cubicmap.width + x].b == 255))
{
// Define triangles (Checking Collateral Cubes!)
//----------------------------------------------
@ -832,10 +838,10 @@ Model LoadCubicmap(Image cubesmap)
mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
tcCounter += 6;
if (((z < cubesmap.height - 1) &&
(cubesmap.pixels[(z + 1)*cubesmap.width + x].r == 0) &&
(cubesmap.pixels[(z + 1)*cubesmap.width + x].g == 0) &&
(cubesmap.pixels[(z + 1)*cubesmap.width + x].b == 0)) || (z == cubesmap.height - 1))
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))
{
// Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
// NOTE: Collateral occluded faces are not generated
@ -865,9 +871,9 @@ Model LoadCubicmap(Image cubesmap)
}
if (((z > 0) &&
(cubesmap.pixels[(z - 1)*cubesmap.width + x].r == 0) &&
(cubesmap.pixels[(z - 1)*cubesmap.width + x].g == 0) &&
(cubesmap.pixels[(z - 1)*cubesmap.width + x].b == 0)) || (z == 0))
(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))
{
// Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
// NOTE: Collateral occluded faces are not generated
@ -896,10 +902,10 @@ Model LoadCubicmap(Image cubesmap)
tcCounter += 6;
}
if (((x < cubesmap.width - 1) &&
(cubesmap.pixels[z*cubesmap.width + (x + 1)].r == 0) &&
(cubesmap.pixels[z*cubesmap.width + (x + 1)].g == 0) &&
(cubesmap.pixels[z*cubesmap.width + (x + 1)].b == 0)) || (x == cubesmap.width - 1))
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))
{
// Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
// NOTE: Collateral occluded faces are not generated
@ -929,9 +935,9 @@ Model LoadCubicmap(Image cubesmap)
}
if (((x > 0) &&
(cubesmap.pixels[z*cubesmap.width + (x - 1)].r == 0) &&
(cubesmap.pixels[z*cubesmap.width + (x - 1)].g == 0) &&
(cubesmap.pixels[z*cubesmap.width + (x - 1)].b == 0)) || (x == 0))
(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))
{
// Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
// NOTE: Collateral occluded faces are not generated
@ -961,9 +967,9 @@ Model LoadCubicmap(Image cubesmap)
}
}
// We check pixel color to be BLACK, we will only draw floor and roof
else if ((cubesmap.pixels[z*cubesmap.width + x].r == 0) &&
(cubesmap.pixels[z*cubesmap.width + x].g == 0) &&
(cubesmap.pixels[z*cubesmap.width + x].b == 0))
else if ((cubicmapPixels[z*cubicmap.width + x].r == 0) &&
(cubicmapPixels[z*cubicmap.width + x].g == 0) &&
(cubicmapPixels[z*cubicmap.width + x].b == 0))
{
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
mapVertices[vCounter] = v1;
@ -1065,6 +1071,8 @@ Model LoadCubicmap(Image cubesmap)
free(mapVertices);
free(mapNormals);
free(mapTexcoords);
free(cubicmapPixels);
// NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
@ -1335,6 +1343,8 @@ bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSph
// NOTE: player position (or camera) is modified inside this function
Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius)
{
Color *cubicmapPixels = GetPixelData(cubicmap);
// Detect the cell where the player is located
Vector3 impactDirection = { 0, 0, 0 };
@ -1347,8 +1357,8 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
// Multiple Axis --------------------------------------------------------------------------------------------
// Axis x-, y-
if ((cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX - 1)].r != 0) &&
(cubicmap.pixels[(locationCellY - 1) * cubicmap.width + (locationCellX)].r != 0))
if ((cubicmapPixels[locationCellY * cubicmap.width + (locationCellX - 1)].r != 0) &&
(cubicmapPixels[(locationCellY - 1) * cubicmap.width + (locationCellX)].r != 0))
{
if (((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) &&
((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius))
@ -1360,8 +1370,8 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
// Axis x-, y+
if ((cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX - 1)].r != 0) &&
(cubicmap.pixels[(locationCellY + 1) * cubicmap.width + (locationCellX)].r != 0))
if ((cubicmapPixels[locationCellY * cubicmap.width + (locationCellX - 1)].r != 0) &&
(cubicmapPixels[(locationCellY + 1) * cubicmap.width + (locationCellX)].r != 0))
{
if (((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) &&
((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius))
@ -1373,8 +1383,8 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
// Axis x+, y-
if ((cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX + 1)].r != 0) &&
(cubicmap.pixels[(locationCellY - 1) * cubicmap.width + (locationCellX)].r != 0))
if ((cubicmapPixels[locationCellY * cubicmap.width + (locationCellX + 1)].r != 0) &&
(cubicmapPixels[(locationCellY - 1) * cubicmap.width + (locationCellX)].r != 0))
{
if (((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) &&
((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius))
@ -1386,8 +1396,8 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
// Axis x+, y+
if ((cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX + 1)].r != 0) &&
(cubicmap.pixels[(locationCellY + 1) * cubicmap.width + (locationCellX)].r != 0))
if ((cubicmapPixels[locationCellY * cubicmap.width + (locationCellX + 1)].r != 0) &&
(cubicmapPixels[(locationCellY + 1) * cubicmap.width + (locationCellX)].r != 0))
{
if (((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) &&
((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius))
@ -1401,7 +1411,7 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
// Single Axis ---------------------------------------------------------------------------------------------------
// Axis x-
if (cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX - 1)].r != 0)
if (cubicmapPixels[locationCellY * cubicmap.width + (locationCellX - 1)].r != 0)
{
if ((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius)
{
@ -1410,7 +1420,7 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
}
// Axis x+
if (cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX + 1)].r != 0)
if (cubicmapPixels[locationCellY * cubicmap.width + (locationCellX + 1)].r != 0)
{
if ((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius)
{
@ -1419,7 +1429,7 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
}
// Axis y-
if (cubicmap.pixels[(locationCellY - 1) * cubicmap.width + (locationCellX)].r != 0)
if (cubicmapPixels[(locationCellY - 1) * cubicmap.width + (locationCellX)].r != 0)
{
if ((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius)
{
@ -1428,7 +1438,7 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
}
// Axis y+
if (cubicmap.pixels[(locationCellY + 1) * cubicmap.width + (locationCellX)].r != 0)
if (cubicmapPixels[(locationCellY + 1) * cubicmap.width + (locationCellX)].r != 0)
{
if ((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius)
{
@ -1440,9 +1450,9 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
// Diagonals -------------------------------------------------------------------------------------------------------
// Axis x-, y-
if ((cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX - 1)].r == 0) &&
(cubicmap.pixels[(locationCellY - 1) * cubicmap.width + (locationCellX)].r == 0) &&
(cubicmap.pixels[(locationCellY - 1) * cubicmap.width + (locationCellX - 1)].r != 0))
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))
{
if (((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) &&
((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius))
@ -1460,9 +1470,9 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
// Axis x-, y+
if ((cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX - 1)].r == 0) &&
(cubicmap.pixels[(locationCellY + 1) * cubicmap.width + (locationCellX)].r == 0) &&
(cubicmap.pixels[(locationCellY + 1) * cubicmap.width + (locationCellX - 1)].r != 0))
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))
{
if (((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) &&
((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius))
@ -1480,9 +1490,9 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
// Axis x+, y-
if ((cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX + 1)].r == 0) &&
(cubicmap.pixels[(locationCellY - 1) * cubicmap.width + (locationCellX)].r == 0) &&
(cubicmap.pixels[(locationCellY - 1) * cubicmap.width + (locationCellX + 1)].r != 0))
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))
{
if (((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) &&
((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius))
@ -1500,9 +1510,9 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
}
// Axis x+, y+
if ((cubicmap.pixels[locationCellY * cubicmap.width + (locationCellX + 1)].r == 0) &&
(cubicmap.pixels[(locationCellY + 1) * cubicmap.width + (locationCellX)].r == 0) &&
(cubicmap.pixels[(locationCellY + 1) * cubicmap.width + (locationCellX + 1)].r != 0))
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))
{
if (((playerPosition->x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) &&
((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius))
@ -1531,6 +1541,8 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
playerPosition->y = (1.5 - radius) - 0.01;
impactDirection = (Vector3) { impactDirection.x, 1, impactDirection.z};
}
free(cubicmapPixels);
return impactDirection;
}

View File

@ -27,7 +27,6 @@
*
* Some design decisions:
* 32bit Colors - All defined color are always RGBA
* 32bit Textures - All loaded images are converted automatically to RGBA textures
* SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures
* One custom default font is loaded automatically when InitWindow()
* If using OpenGL 3.3+ or ES2, one default shader is loaded automatically (internally defined)
@ -78,7 +77,7 @@
// Some basic Defines
//----------------------------------------------------------------------------------
#ifndef PI
#define PI 3.14159265358979323846
#define PI 3.14159265358979323846
#endif
#define DEG2RAD (PI / 180.0f)
@ -183,20 +182,6 @@
typedef enum { false, true } bool;
#endif
typedef enum {
GESTURE_NONE = 0,
GESTURE_TAP,
GESTURE_DOUBLETAP,
GESTURE_HOLD,
GESTURE_DRAG,
GESTURE_SWIPE_RIGHT,
GESTURE_SWIPE_LEFT,
GESTURE_SWIPE_UP,
GESTURE_SWIPE_DOWN,
GESTURE_PINCH_IN,
GESTURE_PINCH_OUT
} Gestures;
// byte type
typedef unsigned char byte;
@ -240,17 +225,21 @@ typedef struct Rectangle {
// Image type, bpp always RGBA (32bit)
// NOTE: Data stored in CPU memory (RAM)
typedef struct Image {
Color *pixels;
int width;
int height;
void *data; // Image raw data
int width; // Image base width
int height; // Image base height
int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (TextureFormat)
} Image;
// Texture2D type, bpp always RGBA (32bit)
// NOTE: Data stored in GPU memory
typedef struct Texture2D {
unsigned int id; // OpenGL id
int width;
int height;
unsigned int id; // OpenGL texture id
int width; // Texture base width
int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (TextureFormat)
} Texture2D;
// Character type (one font glyph)
@ -337,9 +326,11 @@ typedef struct Wave {
short channels;
} Wave;
// Texture formats (support depends on OpenGL version)
// Texture formats
// NOTE: Support depends on OpenGL version and platform
typedef enum {
UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
UNCOMPRESSED_GRAY_ALPHA, // 16 bpp (2 channels)
UNCOMPRESSED_R5G6B5, // 16 bpp
UNCOMPRESSED_R8G8B8, // 24 bpp
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
@ -354,9 +345,25 @@ typedef enum {
COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
COMPRESSED_PVRT_RGB, // 4 bpp
COMPRESSED_PVRT_RGBA, // 4 bpp
/*COMPRESSED_ASTC_RGBA_4x4*/ // 8 bpp
COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
COMPRESSED_ASTC_8x8_RGBA // 2 bpp
} TextureFormat;
// Gestures type
typedef enum {
GESTURE_NONE = 0,
GESTURE_TAP,
GESTURE_DOUBLETAP,
GESTURE_HOLD,
GESTURE_DRAG,
GESTURE_SWIPE_RIGHT,
GESTURE_SWIPE_LEFT,
GESTURE_SWIPE_UP,
GESTURE_SWIPE_DOWN,
GESTURE_PINCH_IN,
GESTURE_PINCH_OUT
} Gestures;
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
@ -402,16 +409,27 @@ int GetHexValue(Color color); // Returns hexadecim
int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
void SetCameraMode(int mode); // Multiple camera modes available
Camera UpdateCamera(Vector3 *position); // Update camera with position (when using internal camera)
void SetConfigFlags(char flags); // Enable some window configurations
void ShowLogo(void); // Activates raylib logo at startup (can be done with flags)
void SetPostproShader(Shader shader); // Set fullscreen postproduction shader
void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw
void SetDefaultShader(void); // Set default shader to be used in batch draw
Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Gives the rayTrace from mouse position
// Camera modes setup and control functions (module: camera)
void SetCameraMode(int mode); // Select camera mode (multiple camera modes available)
Camera UpdateCamera(Vector3 *position); // Update camera with position
void SetCameraControls(int front, int left, int back, int right, int up, int down);
void SetMouseSensitivity(float sensitivity);
void SetResetPosition(Vector3 resetPosition);
void SetResetControl(int resetKey);
void SetPawnControl(int pawnControlKey);
void SetFnControl(int fnControlKey);
void SetSmoothZoomControl(int smoothZoomControlKey);
//------------------------------------------------------------------------------------
// Input Handling Functions (Module: core)
//------------------------------------------------------------------------------------
@ -451,6 +469,7 @@ int GetTouchX(void); // Returns touch positio
int GetTouchY(void); // Returns touch position Y
Vector2 GetTouchPosition(void); // Returns touch position XY
// Gestures System (module: gestures)
bool IsGestureDetected(void);
int GetGestureType(void);
float GetDragIntensity(void);
@ -504,6 +523,8 @@ Texture2D CreateTexture(Image image, bool genMipmaps);
void UnloadImage(Image image); // Unload image from CPU memory (RAM)
void UnloadTexture(Texture2D texture); // Unload texture from GPU memory
void ConvertToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
Color *GetPixelData(Image image); // Get pixel data from image as a Color struct array
void SetPixelData(Image *image, Color *pixels, int format); // Set image data from Color struct array
void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D
void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2

View File

@ -143,6 +143,7 @@ typedef struct {
typedef struct {
GLuint textureId;
int vertexCount;
// TODO: DrawState state -> Blending mode, shader
} DrawCall;
// pixel type (same as Color type)
@ -175,6 +176,7 @@ static VertexPositionColorTextureIndexBuffer quads;
// Shader Programs
static Shader defaultShader, simpleShader;
static Shader currentShader; // By default, defaultShader
// Vertex Array Objects (VAO)
static GLuint vaoLines, vaoTriangles, vaoQuads;
@ -330,14 +332,14 @@ void rlRotatef(float angleDeg, float x, float y, float z)
Matrix rotation = MatrixIdentity();
// OPTION 1: It works...
//if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD);
//else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD);
//else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD);
if (x == 1) rotation = MatrixRotateX(angleDeg*DEG2RAD);
else if (y == 1) rotation = MatrixRotateY(angleDeg*DEG2RAD);
else if (z == 1) rotation = MatrixRotateZ(angleDeg*DEG2RAD);
// OPTION 2: Requires review...
Vector3 axis = (Vector3){ x, y, z };
VectorNormalize(&axis);
rotation = MatrixRotateY(angleDeg*DEG2RAD); //MatrixFromAxisAngle(axis, angleDeg*DEG2RAD);
//Vector3 axis = (Vector3){ x, y, z };
//VectorNormalize(&axis);
//rotation = MatrixRotateY(angleDeg*DEG2RAD); //MatrixFromAxisAngle(axis, angleDeg*DEG2RAD);
// OPTION 3: TODO: Review, it doesn't work!
//Vector3 vec = (Vector3){ x, y, z };
@ -921,6 +923,8 @@ void rlglInit(void)
defaultShader = LoadDefaultShader();
simpleShader = LoadSimpleShader();
//customShader = rlglLoadShader("custom.vs", "custom.fs"); // Works ok
currentShader = defaultShader;
InitializeBuffers(); // Init vertex arrays
InitializeBuffersGPU(); // Init VBO and VAO
@ -1094,6 +1098,7 @@ void rlglClose(void)
#endif
}
// Drawing batches: triangles, quads, lines
void rlglDraw(void)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
@ -1101,11 +1106,11 @@ void rlglDraw(void)
if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0))
{
glUseProgram(defaultShader.id);
glUseProgram(currentShader.id);
glUniformMatrix4fv(defaultShader.projectionLoc, 1, false, GetMatrixVector(projection));
glUniformMatrix4fv(defaultShader.modelviewLoc, 1, false, GetMatrixVector(modelview));
glUniform1i(defaultShader.textureLoc, 0);
glUniformMatrix4fv(currentShader.projectionLoc, 1, false, GetMatrixVector(projection));
glUniformMatrix4fv(currentShader.modelviewLoc, 1, false, GetMatrixVector(modelview));
glUniform1i(currentShader.textureLoc, 0);
}
// NOTE: We draw in this order: triangle shapes, textured quads and lines
@ -1121,12 +1126,12 @@ void rlglDraw(void)
else
{
glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]);
glVertexAttribPointer(defaultShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(defaultShader.vertexLoc);
glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(currentShader.vertexLoc);
glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]);
glVertexAttribPointer(defaultShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(defaultShader.colorLoc);
glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(currentShader.colorLoc);
}
glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter);
@ -1149,16 +1154,16 @@ void rlglDraw(void)
{
// Enable vertex attributes
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
glVertexAttribPointer(defaultShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(defaultShader.vertexLoc);
glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(currentShader.vertexLoc);
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]);
glVertexAttribPointer(defaultShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(defaultShader.texcoordLoc);
glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(currentShader.texcoordLoc);
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
glVertexAttribPointer(defaultShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(defaultShader.colorLoc);
glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(currentShader.colorLoc);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);
}
@ -1206,12 +1211,12 @@ void rlglDraw(void)
else
{
glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]);
glVertexAttribPointer(defaultShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(defaultShader.vertexLoc);
glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(currentShader.vertexLoc);
glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
glVertexAttribPointer(defaultShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(defaultShader.colorLoc);
glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(currentShader.colorLoc);
}
glDrawArrays(GL_LINES, 0, lines.vCounter);
@ -1310,7 +1315,7 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r
// NOTE: Drawing in OpenGL 3.3+, transform is passed to shader
glUniformMatrix4fv(model.shader.projectionLoc, 1, false, GetMatrixVector(projection));
glUniformMatrix4fv(model.shader.modelviewLoc, 1, false, GetMatrixVector(modelviewworld));
glUniform1i(model.shader.textureLoc, 0);
glUniform1i(model.shader.textureLoc, 0); // Texture fits in texture unit 0 (Check glActiveTexture())
// Apply color tinting to model
// NOTE: Just update one uniform on fragment shader
@ -1573,16 +1578,18 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
GLuint id;
// TODO: Review compressed textures support by OpenGL version
/* (rlGetVersion() == OPENGL_11)
if ((textureFormat == COMPRESSED_DXT1_RGB) || (textureFormat == COMPRESSED_DXT3_RGBA) || (textureFormat == COMPRESSED_DXT5_RGBA) ||
(textureFormat == COMPRESSED_ETC1_RGB8) || (textureFormat == COMPRESSED_ETC2_RGB8) || (textureFormat == COMPRESSED_ETC2_EAC_RGBA8))
// Check compressed textures support by OpenGL 1.1
if (rlGetVersion() == OPENGL_11)
{
id = 0;
TraceLog(WARNING, "GPU compressed textures not supported on OpenGL 1.1");
return id;
if ((textureFormat == COMPRESSED_ETC1_RGB) || (textureFormat == COMPRESSED_ETC2_RGB) || (textureFormat == COMPRESSED_ETC2_EAC_RGBA) ||
(textureFormat == COMPRESSED_PVRT_RGB) || (textureFormat == COMPRESSED_PVRT_RGBA) ||
(textureFormat == COMPRESSED_ASTC_4x4_RGBA) || (textureFormat == COMPRESSED_ASTC_8x8_RGBA))
{
id = 0;
TraceLog(WARNING, "Required GPU compressed texture format not supported");
return id;
}
}
*/
glGenTextures(1, &id); // Generate Pointer to the texture
@ -1679,10 +1686,17 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
// With swizzleMask we define how a one channel texture will be mapped to RGBA
// Required GL >= 3.3 or EXT_texture_swizzle/ARB_texture_swizzle
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, 1.0f };
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
TraceLog(INFO, "Grayscale texture loaded and swizzled!");
TraceLog(INFO, "[TEX ID %i] Grayscale texture loaded and swizzled", id);
} break;
case UNCOMPRESSED_GRAY_ALPHA:
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, width, height, 0, GL_RG, GL_UNSIGNED_BYTE, (unsigned char *)data);
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
} break;
case UNCOMPRESSED_R5G6B5: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
@ -1711,6 +1725,7 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
switch (textureFormat)
{
case UNCOMPRESSED_GRAYSCALE: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_GRAY_ALPHA: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G6B5: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G5B5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break;
@ -1724,7 +1739,7 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
case COMPRESSED_ETC2_RGB: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB8_ETC2); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA8_ETC2_EAC); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
//case COMPRESSED_ASTC_RGBA_4x4: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_4x4_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
default: TraceLog(WARNING, "Texture format not recognized"); break;
default: TraceLog(WARNING, "Texture format not supported"); break;
}
if ((mipmapCount == 1) && (genMipmaps))
@ -2009,13 +2024,50 @@ void rlglSetModelShader(Model *model, Shader shader)
#endif
}
// Set custom shader to be used on batch draw
void rlglSetCustomShader(Shader shader)
{
if (currentShader.id != shader.id)
{
rlglDraw();
currentShader = shader;
/*
if (vaoSupported) glBindVertexArray(vaoQuads);
// Enable vertex attributes: position
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
glEnableVertexAttribArray(currentShader.vertexLoc);
glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
// Enable vertex attributes: texcoords
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]);
glEnableVertexAttribArray(currentShader.texcoordLoc);
glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
// Enable vertex attributes: colors
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
glEnableVertexAttribArray(currentShader.colorLoc);
glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
if (vaoSupported) glBindVertexArray(0); // Unbind VAO
*/
}
}
// Set default shader to be used on batch draw
void rlglSetDefaultShader(void)
{
rlglSetCustomShader(defaultShader);
}
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
void PrintProjectionMatrix()
void PrintProjectionMatrix(void)
{
PrintMatrix(projection);
}
void PrintModelviewMatrix()
void PrintModelviewMatrix(void)
{
PrintMatrix(modelview);
}
@ -2292,7 +2344,7 @@ static void InitializeBuffers(void)
}
// Initialize Vertex Array Objects (Contain VBO)
// NOTE: lines, triangles and quads buffers use defaultShader
// NOTE: lines, triangles and quads buffers use currentShader
static void InitializeBuffersGPU(void)
{
if (vaoSupported)
@ -2308,14 +2360,14 @@ static void InitializeBuffersGPU(void)
// Lines - Vertex positions buffer binding and attributes enable
glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(defaultShader.vertexLoc);
glVertexAttribPointer(defaultShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(currentShader.vertexLoc);
glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
// Lines - colors buffer
glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(defaultShader.colorLoc);
glVertexAttribPointer(defaultShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(currentShader.colorLoc);
glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Lines VAO initialized successfully", vaoLines);
else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Lines VBOs initialized successfully", linesBuffer[0], linesBuffer[1]);
@ -2334,13 +2386,13 @@ static void InitializeBuffersGPU(void)
// Enable vertex attributes
glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(defaultShader.vertexLoc);
glVertexAttribPointer(defaultShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(currentShader.vertexLoc);
glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(defaultShader.colorLoc);
glVertexAttribPointer(defaultShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(currentShader.colorLoc);
glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Triangles VAO initialized successfully", vaoTriangles);
else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Triangles VBOs initialized successfully", trianglesBuffer[0], trianglesBuffer[1]);
@ -2359,18 +2411,18 @@ static void InitializeBuffersGPU(void)
// Enable vertex attributes
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(defaultShader.vertexLoc);
glVertexAttribPointer(defaultShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(currentShader.vertexLoc);
glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(defaultShader.texcoordLoc);
glVertexAttribPointer(defaultShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(currentShader.texcoordLoc);
glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(defaultShader.colorLoc);
glVertexAttribPointer(defaultShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(currentShader.colorLoc);
glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
// Fill index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);

View File

@ -216,6 +216,8 @@ void rlglInitPostpro(void); // Initialize postprocessing sys
void rlglDrawPostpro(void); // Draw with postprocessing shader
void rlglSetPostproShader(Shader shader); // Set postprocessing shader
void rlglSetModelShader(Model *model, Shader shader); // Set shader for a model
void rlglSetCustomShader(Shader shader); // Set custom shader to be used on batch draw
void rlglSetDefaultShader(void); // Set default shader to be used on batch draw
Model rlglLoadModel(VertexData mesh); // Upload vertex data into GPU and provided VAO/VBO ids
void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires);

View File

@ -87,6 +87,8 @@ extern void LoadDefaultFont(void)
Image image;
image.width = 128; // We know our default font image is 128 pixels width
image.height = 128; // We know our default font image is 128 pixels height
image.mipmaps = 1;
image.format = UNCOMPRESSED_R8G8B8A8;
// Default font is directly defined here (data generated from a sprite font image)
// This way, we reconstruct SpriteFont without creating large global variables
@ -149,9 +151,9 @@ extern void LoadDefaultFont(void)
// Re-construct image from defaultFontData and generate OpenGL texture
//----------------------------------------------------------------------
image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color));
Color *imagePixels = (Color *)malloc(image.width*image.height*sizeof(Color));
for (int i = 0; i < image.width * image.height; i++) image.pixels[i] = BLANK; // Initialize array
for (int i = 0; i < image.width*image.height; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter
@ -160,7 +162,7 @@ extern void LoadDefaultFont(void)
{
for (int j = 31; j >= 0; j--)
{
if (BIT_CHECK(defaultFontData[counter], j)) image.pixels[i+j] = WHITE;
if (BIT_CHECK(defaultFontData[counter], j)) imagePixels[i+j] = WHITE;
}
counter++;
@ -171,6 +173,10 @@ extern void LoadDefaultFont(void)
//FILE *myimage = fopen("default_font.raw", "wb");
//fwrite(image.pixels, 1, 128*128*4, myimage);
//fclose(myimage);
SetPixelData(&image, imagePixels, 0);
free(imagePixels);
defaultFont.texture = LoadTextureFromImage(image, false); // Convert loaded image to OpenGL texture
UnloadImage(image);
@ -232,14 +238,16 @@ SpriteFont LoadSpriteFont(const char *fileName)
{
Image image = LoadImage(fileName);
// At this point we have a pixel array with all the data...
// At this point we have a data array...
Color *imagePixels = GetPixelData(image);
#if defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
ConvertToPOT(&image, MAGENTA);
#endif
// Process bitmap Font pixel data to get measures (Character array)
// spriteFont.charSet data is filled inside the function and memory is allocated!
int numChars = ParseImageData(image.pixels, image.width, image.height, &spriteFont.charSet);
int numChars = ParseImageData(imagePixels, image.width, image.height, &spriteFont.charSet);
TraceLog(INFO, "[%s] SpriteFont data parsed correctly", fileName);
TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", fileName, numChars);
@ -248,6 +256,7 @@ SpriteFont LoadSpriteFont(const char *fileName)
spriteFont.texture = LoadTextureFromImage(image, false); // Convert loaded image to OpenGL texture
free(imagePixels);
UnloadImage(image);
}
@ -522,6 +531,8 @@ static SpriteFont LoadRBMF(const char *fileName)
image.width = (int)rbmfHeader.imgWidth;
image.height = (int)rbmfHeader.imgHeight;
image.mipmaps = 1;
image.format = UNCOMPRESSED_R8G8B8A8;
int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32;
@ -535,9 +546,9 @@ static SpriteFont LoadRBMF(const char *fileName)
// Re-construct image from rbmfFileData
//-----------------------------------------
image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color));
Color *imagePixels = (Color *)malloc(image.width*image.height*sizeof(Color));
for (int i = 0; i < image.width * image.height; i++) image.pixels[i] = BLANK; // Initialize array
for (int i = 0; i < image.width*image.height; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter
@ -546,11 +557,15 @@ static SpriteFont LoadRBMF(const char *fileName)
{
for (int j = 31; j >= 0; j--)
{
if (BIT_CHECK(rbmfFileData[counter], j)) image.pixels[i+j] = WHITE;
if (BIT_CHECK(rbmfFileData[counter], j)) imagePixels[i+j] = WHITE;
}
counter++;
}
SetPixelData(&image, imagePixels, 0);
free(imagePixels);
TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
@ -607,7 +622,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize)
Image image;
image.width = 512;
image.height = 512;
image.pixels = (Color *)malloc(image.width*image.height*sizeof(Color));
//image.pixels = (Color *)malloc(image.width*image.height*sizeof(Color));
unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25);
@ -647,7 +662,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize)
free(ttfBuffer);
// Now we have image data in tempBitmap and chardata filled...
/*
for (int i = 0; i < 512*512; i++)
{
image.pixels[i].r = tempBitmap[i];
@ -655,7 +670,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize)
image.pixels[i].b = tempBitmap[i];
image.pixels[i].a = 255;
}
*/
free(tempBitmap);
// REFERENCE EXAMPLE

File diff suppressed because it is too large Load Diff