diff options
| author | raysan5 <raysan5@gmail.com> | 2015-08-27 16:32:06 +0200 |
|---|---|---|
| committer | raysan5 <raysan5@gmail.com> | 2015-08-27 16:32:06 +0200 |
| commit | 3a9ed0e8462570e30d92e2aa8c0ff3cf655ef863 (patch) | |
| tree | 9e2593de39f6daab0dc283837e325937cbf41f1c /src | |
| parent | 8b3a82688e82922819d24494c08e24570c03bdc4 (diff) | |
| parent | 997170a317bb8077cb96d3fc757c6cde0c0ea466 (diff) | |
| download | raylib-3a9ed0e8462570e30d92e2aa8c0ff3cf655ef863.tar.gz raylib-3a9ed0e8462570e30d92e2aa8c0ff3cf655ef863.zip | |
Merged master fixed conflict.
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio.c | 143 | ||||
| -rw-r--r-- | src/audio.h | 102 | ||||
| -rw-r--r-- | src/camera.c | 315 | ||||
| -rw-r--r-- | src/camera.h | 51 | ||||
| -rw-r--r-- | src/core.c | 208 | ||||
| -rw-r--r-- | src/gestures.c | 225 | ||||
| -rw-r--r-- | src/gestures.h | 107 | ||||
| -rw-r--r-- | src/makefile | 6 | ||||
| -rw-r--r-- | src/models.c | 35 | ||||
| -rw-r--r-- | src/raylib.h | 80 | ||||
| -rw-r--r-- | src/rlgl.c | 543 | ||||
| -rw-r--r-- | src/rlgl.h | 94 | ||||
| -rw-r--r-- | src/shapes.c | 2 | ||||
| -rw-r--r-- | src/text.c | 6 | ||||
| -rw-r--r-- | src/textures.c | 279 | ||||
| -rw-r--r-- | src/utils.c | 2 |
16 files changed, 1365 insertions, 833 deletions
diff --git a/src/audio.c b/src/audio.c index 9653c091..b8025ad6 100644 --- a/src/audio.c +++ b/src/audio.c @@ -8,7 +8,7 @@ * OpenAL Soft - Audio device management lib (http://kcat.strangesoft.net/openal.html) * stb_vorbis - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. @@ -27,7 +27,13 @@ * **********************************************************************************************/ -#include "raylib.h" +//#define AUDIO_STANDALONE // NOTE: To use the audio module as standalone lib, just uncomment this line + +#if defined(AUDIO_STANDALONE) + #include "audio.h" +#else + #include "raylib.h" +#endif #include "AL/al.h" // OpenAL basic header #include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) @@ -36,8 +42,12 @@ #include <string.h> // Required for strcmp() #include <stdio.h> // Used for .WAV loading -#include "utils.h" // rRES data decompression utility function +#if defined(AUDIO_STANDALONE) + #include <stdarg.h> // Used for functions with variable number of parameters (TraceLog()) +#else + #include "utils.h" // rRES data decompression utility function // NOTE: Includes Android fopen function map +#endif //#define STB_VORBIS_HEADER_ONLY #include "stb_vorbis.h" // OGG loading functions @@ -75,6 +85,10 @@ typedef struct Music { } Music; +#if defined(AUDIO_STANDALONE) +typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; +#endif + //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -85,13 +99,18 @@ static Music currentMusic; // Current music loaded //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static Wave LoadWAV(const char *fileName); // Load WAV file -static Wave LoadOGG(char *fileName); // Load OGG file -static void UnloadWave(Wave wave); // Unload wave data +static Wave LoadWAV(const char *fileName); // Load WAV file +static Wave LoadOGG(char *fileName); // Load OGG file +static void UnloadWave(Wave wave); // Unload wave data -static bool BufferMusicStream(ALuint buffer); // Fill music buffers with data -static void EmptyMusicStream(void); // Empty music buffers -extern void UpdateMusicStream(void); // Updates buffers (refill) for music streaming +static bool BufferMusicStream(ALuint buffer); // Fill music buffers with data +static void EmptyMusicStream(void); // Empty music buffers +extern void UpdateMusicStream(void); // Updates buffers (refill) for music streaming + +#if defined(AUDIO_STANDALONE) +const char *GetExtension(const char *fileName); // Get the extension for a filename +void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message (INFO, ERROR, WARNING) +#endif //---------------------------------------------------------------------------------- // Module Functions Definition - Audio Device initialization and Closing @@ -273,8 +292,13 @@ Sound LoadSoundFromRES(const char *rresName, int resId) { // NOTE: rresName could be directly a char array with all the data!!! --> TODO Sound sound; - bool found = false; +#if defined(AUDIO_STANDALONE) + TraceLog(WARNING, "Sound loading from rRES resource file not supported on standalone mode"); +#else + + bool found = false; + char id[4]; // rRES file identifier unsigned char version; // rRES file version and subversion char useless; // rRES header reserved data @@ -416,7 +440,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) } if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId); - +#endif return sound; } @@ -425,6 +449,8 @@ void UnloadSound(Sound sound) { alDeleteSources(1, &sound.source); alDeleteBuffers(1, &sound.buffer); + + TraceLog(INFO, "Unloaded sound data"); } // Play a sound @@ -777,6 +803,7 @@ static Wave LoadWAV(const char *fileName) if (wavFile == NULL) { TraceLog(WARNING, "[%s] WAV file could not be opened", fileName); + wave.data = NULL; } else { @@ -846,40 +873,49 @@ static Wave LoadOGG(char *fileName) Wave wave; stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL); - stb_vorbis_info info = stb_vorbis_get_info(oggFile); - wave.sampleRate = info.sample_rate; - wave.bitsPerSample = 16; - wave.channels = info.channels; + if (oggFile == NULL) + { + TraceLog(WARNING, "[%s] OGG file could not be opened", fileName); + wave.data = NULL; + } + else + { + stb_vorbis_info info = stb_vorbis_get_info(oggFile); - TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); - TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); + wave.sampleRate = info.sample_rate; + wave.bitsPerSample = 16; + wave.channels = info.channels; - int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile) * info.channels); + TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); + TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); - wave.dataSize = totalSamplesLength*sizeof(short); // Size must be in bytes + int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile) * info.channels); - TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength); + wave.dataSize = totalSamplesLength*sizeof(short); // Size must be in bytes - float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); + TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength); - TraceLog(DEBUG, "[%s] Total seconds: %f", fileName, totalSeconds); + float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); - if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); + TraceLog(DEBUG, "[%s] Total seconds: %f", fileName, totalSeconds); - int totalSamples = totalSeconds*info.sample_rate*info.channels; + if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); - TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples); + int totalSamples = totalSeconds*info.sample_rate*info.channels; - wave.data = malloc(sizeof(short)*totalSamplesLength); + TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples); - int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength); + wave.data = malloc(sizeof(short)*totalSamplesLength); - TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained); + int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength); - TraceLog(INFO, "[%s] OGG file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels); + TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained); - stb_vorbis_close(oggFile); + TraceLog(INFO, "[%s] OGG file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels); + + stb_vorbis_close(oggFile); + } return wave; } @@ -888,4 +924,49 @@ static Wave LoadOGG(char *fileName) static void UnloadWave(Wave wave) { free(wave.data); -}
\ No newline at end of file + + TraceLog(INFO, "Unloaded wave data"); +} + +// Some required functions for audio standalone module version +#if defined(AUDIO_STANDALONE) +// Get the extension for a filename +const char *GetExtension(const char *fileName) +{ + const char *dot = strrchr(fileName, '.'); + if(!dot || dot == fileName) return ""; + return (dot + 1); +} + +// Outputs a trace log message (INFO, ERROR, WARNING) +// NOTE: If a file has been init, output log is written there +void TraceLog(int msgType, const char *text, ...) +{ + va_list args; + int traceDebugMsgs = 0; + +#ifdef DO_NOT_TRACE_DEBUG_MSGS + traceDebugMsgs = 0; +#endif + + switch(msgType) + { + case INFO: fprintf(stdout, "INFO: "); break; + case ERROR: fprintf(stdout, "ERROR: "); break; + case WARNING: fprintf(stdout, "WARNING: "); break; + case DEBUG: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break; + default: break; + } + + if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs))) + { + va_start(args, text); + vfprintf(stdout, text, args); + va_end(args); + + fprintf(stdout, "\n"); + } + + if (msgType == ERROR) exit(1); // If ERROR message, exit program +} +#endif
\ No newline at end of file diff --git a/src/audio.h b/src/audio.h new file mode 100644 index 00000000..ed156532 --- /dev/null +++ b/src/audio.h @@ -0,0 +1,102 @@ +/********************************************************************************************** +* +* raylib.audio +* +* Basic functions to manage Audio: InitAudioDevice, LoadAudioFiles, PlayAudioFiles +* +* Uses external lib: +* OpenAL Soft - Audio device management lib (http://kcat.strangesoft.net/openal.html) +* stb_vorbis - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +* 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. +* +**********************************************************************************************/ + +#ifndef AUDIO_H +#define AUDIO_H + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Below types are required for CAMERA_STANDALONE usage +//---------------------------------------------------------------------------------- +#ifndef __cplusplus +// Boolean type +typedef enum { false, true } bool; +#endif + +// Sound source type +typedef struct Sound { + unsigned int source; + unsigned int buffer; +} Sound; + +// Wave type, defines audio wave data +typedef struct Wave { + void *data; // Buffer data pointer + unsigned int dataSize; // Data size in bytes + unsigned int sampleRate; + short bitsPerSample; + short channels; +} Wave; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +void InitAudioDevice(void); // Initialize audio device and context +void CloseAudioDevice(void); // Close the audio device and context (and music stream) + +Sound LoadSound(char *fileName); // Load sound to memory +Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data +Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) +void UnloadSound(Sound sound); // Unload sound +void PlaySound(Sound sound); // Play a sound +void PauseSound(Sound sound); // Pause a sound +void StopSound(Sound sound); // Stop playing a sound +bool SoundIsPlaying(Sound sound); // Check if a sound is currently playing +void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) +void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) + +void PlayMusicStream(char *fileName); // Start music playing (open stream) +void UpdateMusicStream(void); // Updates buffers for music streaming +void StopMusicStream(void); // Stop music playing (close stream) +void PauseMusicStream(void); // Pause music playing +void ResumeMusicStream(void); // Resume playing paused music +bool MusicIsPlaying(void); // Check if music is playing +void SetMusicVolume(float volume); // Set volume for music (1.0 is max level) +float GetMusicTimeLength(void); // Get current music time length (in seconds) +float GetMusicTimePlayed(void); // Get current music time played (in seconds) + +#ifdef __cplusplus +} +#endif + +#endif // AUDIO_H
\ No newline at end of file diff --git a/src/camera.c b/src/camera.c index cde118c9..627451fe 100644 --- a/src/camera.c +++ b/src/camera.c @@ -1,8 +1,6 @@ /********************************************************************************************** * -* raylib.camera -* -* Camera Modes Setup and Control Functions +* raylib Camera System - Camera Modes Setup and Control Functions * * Copyright (c) 2015 Marc Palau and Ramon Santamaria * @@ -23,7 +21,14 @@ * **********************************************************************************************/ -#include "camera.h" +//#define CAMERA_STANDALONE // NOTE: To use the camera module as standalone lib, just uncomment this line + // NOTE: ProcessCamera() should be reviewed to adapt inputs to other systems + +#if defined(CAMERA_STANDALONE) + #include "camera.h" +#else + #include "raylib.h" +#endif #include <math.h> @@ -49,7 +54,7 @@ //#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_MAX_CLAMP -85 #define FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0 #define FIRST_PERSON_STEP_DIVIDER 30.0 @@ -61,7 +66,7 @@ //#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_MAX_CLAMP -85 #define THIRD_PERSON_OFFSET (Vector3){ 0.4, 0, 0 } // PLAYER (used by camera) @@ -71,22 +76,26 @@ #define PLAYER_MOVEMENT_DIVIDER 20.0 //---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Camera move modes (first person and third person cameras) +typedef enum { MOVE_FRONT = 0, MOVE_LEFT, MOVE_BACK, MOVE_RIGHT, MOVE_UP, MOVE_DOWN } CameraMove; + +//---------------------------------------------------------------------------------- // 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 cameraMoveControl[6] = { 'W', 'A', 'S', 'D', 'E', 'Q' }; +static int cameraMoveCounter = 0; +static int cameraUseGravity = 1; +static int panControlKey = 2; // raylib: MOUSE_MIDDLE_BUTTON +static int altControlKey = 342; // raylib: KEY_LEFT_ALT +static int smoothZoomControlKey = 341; // raylib: KEY_LEFT_CONTROL static int cameraMode = CAMERA_CUSTOM; @@ -95,6 +104,20 @@ static int cameraMode = CAMERA_CUSTOM; //---------------------------------------------------------------------------------- static void ProcessCamera(Camera *camera, Vector3 *playerPosition); +#if defined(CAMERA_STANDALONE) +// NOTE: Camera controls depend on some raylib input functions +// TODO: Set your own input functions (used in ProcessCamera()) +static Vector2 GetMousePosition() { return (Vector2){ 0, 0}; } +static void SetMousePosition(Vector2 pos) {} +static int IsMouseButtonDown(int button) { return 0;} +static int GetMouseWheelMove() { return 0; } +static int GetScreenWidth() { return 1280; } +static int GetScreenHeight() { return 720; } +static void ShowCursor() {} +static void HideCursor() {} +static int IsKeyDown(int key) { return 0; } +#endif + //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- @@ -123,6 +146,8 @@ void SetCameraMode(int mode) cameraAngle.y = -40 * DEG2RAD; internalCamera.target = (Vector3){ 0, 0, 0}; ProcessCamera(&internalCamera, &internalCamera.position); + + ShowCursor(); } else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_ORBITAL)) { @@ -145,48 +170,37 @@ Camera UpdateCamera(Vector3 *position) return internalCamera; } - -void SetCameraControls(int frontKey, int leftKey, int backKey, int rightKey, int upKey, int downKey) +void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, int upKey, int downKey) { - cameraMovementController[0] = frontKey; - cameraMovementController[1] = leftKey; - cameraMovementController[2] = backKey; - cameraMovementController[3] = rightKey; - cameraMovementController[4] = upKey; - cameraMovementController[5] = downKey; + cameraMoveControl[MOVE_FRONT] = frontKey; + cameraMoveControl[MOVE_LEFT] = leftKey; + cameraMoveControl[MOVE_BACK] = backKey; + cameraMoveControl[MOVE_RIGHT] = rightKey; + cameraMoveControl[MOVE_UP] = upKey; + cameraMoveControl[MOVE_DOWN] = downKey; } void SetCameraMouseSensitivity(float sensitivity) { mouseSensitivity = (sensitivity / 10000.0); } - -void SetCameraResetPosition(Vector3 resetPosition) -{ - resetingPosition = resetPosition; -} - -void SetCameraResetControl(int resetKey) -{ - resetingKey = resetKey; -} -void SetCameraPawnControl(int pawnControlKey) +void SetCameraPanControl(int panKey) { - pawnControllingKey = pawnControlKey; + panControlKey = panKey; } -void SetCameraFnControl(int fnControlKey) +void SetCameraAltControl(int altKey) { - fnControllingKey = fnControlKey; + altControlKey = altKey; } -void SetCameraSmoothZoomControl(int smoothZoomControlKey) +void SetCameraSmoothZoomControl(int szKey) { - smoothZoomControllingKey = smoothZoomControlKey; + smoothZoomControlKey = szKey; } -void SetCameraOrbitalTarget(Vector3 target) +void SetCameraTarget(Vector3 target) { internalCamera.target = target; } @@ -197,33 +211,43 @@ void SetCameraOrbitalTarget(Vector3 target) //---------------------------------------------------------------------------------- // Process desired camera mode and controls +// NOTE: Camera controls depend on some raylib functions: +// Mouse: GetMousePosition(), SetMousePosition(), IsMouseButtonDown(), GetMouseWheelMove() +// System: GetScreenWidth(), GetScreenHeight(), ShowCursor(), HideCursor() +// Keys: IsKeyDown() static void ProcessCamera(Camera *camera, Vector3 *playerPosition) { -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI) // Mouse movement detection + Vector2 mousePosition = GetMousePosition(); + int mouseWheelMove = GetMouseWheelMove(); + int panKey = IsMouseButtonDown(panControlKey); // bool value + + int screenWidth = GetScreenWidth(); + int screenHeight = GetScreenHeight(); + if ((cameraMode != CAMERA_FREE) && (cameraMode != CAMERA_ORBITAL)) { 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}); + + if (mousePosition.x < screenHeight/3) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y}); + else if (mousePosition.y < screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3}); + else if (mousePosition.x > screenWidth - screenHeight/3) SetMousePosition((Vector2) { screenHeight/3, mousePosition.y}); + else if (mousePosition.y > screenHeight - screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3}); else { - cameraMouseVariation.x = GetMousePosition().x - cameraMousePosition.x; - cameraMouseVariation.y = GetMousePosition().y - cameraMousePosition.y; + cameraMouseVariation.x = mousePosition.x - cameraMousePosition.x; + cameraMouseVariation.y = mousePosition.y - cameraMousePosition.y; } } else { ShowCursor(); - - cameraMouseVariation.x = GetMousePosition().x - cameraMousePosition.x; - cameraMouseVariation.y = GetMousePosition().y - cameraMousePosition.y; + + cameraMouseVariation.x = mousePosition.x - cameraMousePosition.x; + cameraMouseVariation.y = mousePosition.y - cameraMousePosition.y; } - cameraMousePosition = GetMousePosition(); + cameraMousePosition = mousePosition; // Support for multiple automatic camera modes switch (cameraMode) @@ -231,92 +255,93 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) case CAMERA_FREE: { // Camera zoom - if ((cameraTargetDistance < FREE_CAMERA_DISTANCE_MAX_CLAMP) && (GetMouseWheelMove() < 0)) + if ((cameraTargetDistance < FREE_CAMERA_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) { - cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove*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)) + else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == FREE_CAMERA_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 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; + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.z += mouseWheelMove*(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; + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.z += mouseWheelMove*(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)) + else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) { - cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove*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)) + else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == FREE_CAMERA_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 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; + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.z += mouseWheelMove*(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; + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.z += mouseWheelMove*(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)) + else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) { - cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove * CAMERA_SCROLL_SENSITIVITY); if (cameraTargetDistance < FREE_CAMERA_DISTANCE_MIN_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MIN_CLAMP; } // Inputs - if (IsKeyDown(fnControllingKey)) + if (IsKeyDown(altControlKey)) { - if (IsKeyDown(smoothZoomControllingKey)) + if (IsKeyDown(smoothZoomControlKey)) { // Camera smooth zoom - if (IsMouseButtonDown(pawnControllingKey)) cameraTargetDistance += (cameraMouseVariation.y * FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY); + if (panKey) cameraTargetDistance += (cameraMouseVariation.y*FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY); } // Camera orientation calculation - else if (IsMouseButtonDown(pawnControllingKey)) + else if (panKey) { // Camera orientation calculation // Get the mouse sensitivity - cameraAngle.x += cameraMouseVariation.x * -FREE_CAMERA_MOUSE_SENSITIVITY; - cameraAngle.y += cameraMouseVariation.y * -FREE_CAMERA_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; + 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)) + else if (panKey) { - 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); + 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; + // TODO: Move this function out of the module? + 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; + 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; + 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; + camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; } break; case CAMERA_ORBITAL: @@ -324,126 +349,126 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) cameraAngle.x += ORBITAL_CAMERA_SPEED; // Camera zoom - cameraTargetDistance -= (GetMouseWheelMove() * CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove*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 }; + 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; + 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; + 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; + 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; + int isMoving = 0; // Keyboard inputs - if (IsKeyDown(cameraMovementController[0])) + if (IsKeyDown(cameraMoveControl[MOVE_FRONT])) { - 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; + 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; + isMoving = 1; } - else if (IsKeyDown(cameraMovementController[2])) + else if (IsKeyDown(cameraMoveControl[MOVE_BACK])) { - 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; + 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; + isMoving = 1; } - if (IsKeyDown(cameraMovementController[1])) + if (IsKeyDown(cameraMoveControl[MOVE_LEFT])) { - playerPosition->x -= cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER; - playerPosition->z += sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER; + playerPosition->x -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; + playerPosition->z += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - isMoving = true; + isMoving = 1; } - else if (IsKeyDown(cameraMovementController[3])) + else if (IsKeyDown(cameraMoveControl[MOVE_RIGHT])) { - playerPosition->x += cos(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER; - playerPosition->z -= sin(cameraAngle.x) / PLAYER_MOVEMENT_DIVIDER; + playerPosition->x += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; + playerPosition->z -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - isMoving = true; + isMoving = 1; } - if (IsKeyDown(cameraMovementController[4])) + if (IsKeyDown(cameraMoveControl[MOVE_UP])) { - if (!cameraUseGravity) playerPosition->y += 1 / PLAYER_MOVEMENT_DIVIDER; + if (!cameraUseGravity) playerPosition->y += 1/PLAYER_MOVEMENT_DIVIDER; } - else if (IsKeyDown(cameraMovementController[5])) + else if (IsKeyDown(cameraMoveControl[MOVE_DOWN])) { - if (!cameraUseGravity) playerPosition->y -= 1 / PLAYER_MOVEMENT_DIVIDER; + 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; + 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; + 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); + cameraTargetDistance -= (mouseWheelMove*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->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; + 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; + 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; + camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; } - else + else // CAMERA_FIRST_PERSON { - if (isMoving) cameraMovementCounter++; + if (isMoving) cameraMoveCounter++; // Camera orientation calculation - // Get the mouse sensitivity - cameraAngle.x += cameraMouseVariation.x * -mouseSensitivity; - cameraAngle.y += cameraMouseVariation.y * -mouseSensitivity; + 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; + 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->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.y = (playerPosition->y + PLAYER_HEIGHT*FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION) - sin(cameraMoveCounter/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; + camera->up.x = sin(cameraMoveCounter/(FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/FIRST_PERSON_WAVING_DIVIDER; + camera->up.z = -sin(cameraMoveCounter/(FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/FIRST_PERSON_WAVING_DIVIDER; } } break; default: break; } -#endif -} +}
\ No newline at end of file diff --git a/src/camera.h b/src/camera.h index cb5f2bde..63d8f786 100644 --- a/src/camera.h +++ b/src/camera.h @@ -24,7 +24,12 @@ #ifndef CAMERA_H #define CAMERA_H -#include "raylib.h" +#ifndef PI + #define PI 3.14159265358979323846 +#endif + +#define DEG2RAD (PI / 180.0f) +#define RAD2DEG (180.0f / PI) //---------------------------------------------------------------------------------- // Defines and Macros @@ -33,10 +38,30 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition +// NOTE: Below types are required for CAMERA_STANDALONE usage //---------------------------------------------------------------------------------- // Camera modes typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; +// Vector2 type +typedef struct Vector2 { + float x; + float y; +} Vector2; + +// Vector3 type +typedef struct Vector3 { + float x; + float y; + float z; +} Vector3; + +// Camera type, defines a camera position/orientation in 3d space +typedef struct Camera { + Vector3 position; + Vector3 target; + Vector3 up; +} Camera; #ifdef __cplusplus extern "C" { // Prevents name mangling of functions @@ -50,17 +75,19 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -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 SetCameraMouseSensitivity(float sensitivity); -void SetCameraResetPosition(Vector3 resetPosition); -void SetCameraResetControl(int resetKey); -void SetCameraPawnControl(int pawnControlKey); -void SetCameraFnControl(int fnControlKey); -void SetCameraSmoothZoomControl(int smoothZoomControlKey); -void SetCameraOrbitalTarget(Vector3 target); +void SetCameraMode(int mode); // Set camera mode (multiple camera modes available) +Camera UpdateCamera(Vector3 *playerPosition); // Update camera and player position (1st person and 3rd person cameras) + +void SetCameraMoveControls(int frontKey, int backKey, + int leftKey, int rightKey, + int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) + +void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) +void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) +void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) + +void SetCameraMouseSensitivity(float sensitivity); // Set camera mouse sensitivity (1st person and 3rd person cameras) +void SetCameraTarget(Vector3 target); // Set internal camera target #ifdef __cplusplus } @@ -17,7 +17,7 @@ * * On PLATFORM_RPI, graphic device is managed by EGL and input system is coded in raw mode. * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. @@ -164,7 +164,7 @@ static bool customCursor = false; // Tracks if custom cursor has been static bool cursorOnScreen = false; // Tracks if cursor is inside client area static Texture2D cursor; // Cursor texture -static Vector2 mousePosition; +static Vector2 mousePosition; // Mouse position on screen 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 @@ -179,9 +179,12 @@ static int previousMouseWheelY = 0; // Required to track mouse wheel var static int currentMouseWheelY = 0; // Required to track mouse wheel variation static int exitKey = KEY_ESCAPE; // Default exit key (ESC) -static int lastKeyPressed = -1; +static int lastKeyPressed = -1; // Register last key pressed -static bool cursorHidden; +static bool cursorHidden; // Track if cursor is hidden + +static char **dropFilesPath; // Store dropped files paths as strings +static int dropFilesCount = 0; // Count stored strings #endif static double currentTime, previousTime; // Used to track timmings @@ -189,8 +192,8 @@ static double updateTime, drawTime; // Time measures for update and draw static double frameTime; // Time measure for one frame static double targetTime = 0.0; // Desired time for one frame, if 0 not applied -static char configFlags = 0; -static bool showLogo = false; +static char configFlags = 0; // Configuration flags (bit based) +static bool showLogo = false; // Track if showing logo at init is enabled //---------------------------------------------------------------------------------- // Other Modules Functions Declaration (required by core) @@ -198,19 +201,6 @@ static bool showLogo = false; extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow() extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory -extern void UpdateMusicStream(void); // [Module: audio] Updates buffers for music streaming - -extern Vector2 GetRawPosition(void); -extern void ResetGestures(void); - -#if defined(PLATFORM_ANDROID) -extern void InitAndroidGestures(struct android_app *app); -#endif - -#if defined(PLATFORM_WEB) -extern void InitWebGestures(void); // [Module: gestures] Initializes emscripten gestures for web -#endif - //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- @@ -241,7 +231,11 @@ static void CharCallback(GLFWwindow *window, unsigned int key); static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized -static void WindowIconifyCallback(GLFWwindow* window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored +static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored +#endif + +#if defined(PLATFORM_DESKTOP) +static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window #endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) @@ -284,10 +278,6 @@ void InitWindow(int width, int height, const char *title) InitGamepad(); // Gamepad init #endif -#if defined(PLATFORM_WEB) - InitWebGestures(); // Init touch input events for web -#endif - mousePosition.x = screenWidth/2; mousePosition.y = screenHeight/2; @@ -341,7 +331,7 @@ void InitWindow(int width, int height, struct android_app *state) //state->userData = &engine; app->onAppCmd = AndroidCommandCallback; - InitAndroidGestures(app); + //InitGesturesSystem(app); // NOTE: Must be called by user InitAssetManager(app->activity->assetManager); @@ -412,6 +402,16 @@ bool WindowShouldClose(void) #endif } +// Detect if window has been minimized (or lost focus) +bool IsWindowMinimized(void) +{ +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + return windowMinimized; +#else + return false; +#endif +} + // Fullscreen toggle void ToggleFullscreen(void) { @@ -497,14 +497,8 @@ void EndDrawing(void) SwapBuffers(); // Copy back buffer to front buffer -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) - ResetGestures(); -#endif - PollInputEvents(); // Poll user events - UpdateMusicStream(); // NOTE: Function checks if music is enabled - currentTime = GetTime(); drawTime = currentTime - previousTime; previousTime = currentTime; @@ -538,6 +532,7 @@ void Begin3dMode(Camera camera) double top = 0.1f*tan(45.0f*PI / 360.0f); double right = top*aspect; + // NOTE: zNear and zFar values are important when computing depth buffer values rlFrustum(-right, right, -top, top, 0.1f, 1000.0f); rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix @@ -565,7 +560,7 @@ void End3dMode(void) // Set target FPS for the game void SetTargetFPS(int fps) { - targetTime = 1 / (float)fps; + targetTime = 1 / (double)fps; TraceLog(INFO, "Target time per frame: %02.03f milliseconds", (float)targetTime*1000); } @@ -573,16 +568,16 @@ void SetTargetFPS(int fps) // Returns current FPS float GetFPS(void) { - return (1/(float)frameTime); + return (float)(1/frameTime); } // Returns time in seconds for one frame float GetFrameTime(void) { - // As we are operating quite a lot with frameTime, it could be no stable - // so we round it before before passing around to be used + // As we are operate quite a lot with frameTime, + // it could be no stable, so we round it before passing it around // NOTE: There are still problems with high framerates (>500fps) - double roundedFrameTime = round(frameTime*10000) / 10000; + double roundedFrameTime = round(frameTime*10000)/10000; return (float)roundedFrameTime; // Time in seconds to run a frame } @@ -643,6 +638,34 @@ void ShowLogo(void) showLogo = true; } +// Check if a file have been dropped into window +bool IsFileDropped(void) +{ + if (dropFilesCount > 0) return true; + else return false; +} + +// Retrieve dropped files into window +char **GetDroppedFiles(int *count) +{ + *count = dropFilesCount; + return dropFilesPath; +} + +// Clear dropped files paths buffer +void ClearDroppedFiles(void) +{ + if (dropFilesCount > 0) + { + for (int i = 0; i < dropFilesCount; i++) free(dropFilesPath[i]); + + free(dropFilesPath); + + dropFilesCount = 0; + } +} + +// TODO: Gives the ray trace from mouse position Ray GetMouseRay(Vector2 mousePosition, Camera camera) { Ray ray; @@ -650,24 +673,28 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) Matrix proj = MatrixIdentity(); Matrix view = MatrixLookAt(camera.position, camera.target, camera.up); + // Calculate projection matrix for the camera float aspect = (GLfloat)GetScreenWidth()/(GLfloat)GetScreenHeight(); - double top = 0.1f*tanf(45.0f*PI / 360.0f); + double top = 0.1f*tanf(45.0f*PI/360.0f); double right = top*aspect; + // NOTE: zNear and zFar values are important for depth proj = MatrixFrustum(-right, right, -top, top, 0.01f, 1000.0f); MatrixTranspose(&proj); - float realy = (float)GetScreenHeight() - mousePosition.y; + // NOTE: Our screen origin is top-left instead of bottom-left: transform required! + float invertedMouseY = (float)GetScreenHeight() - mousePosition.y; + // NOTE: Do I really need to get z value from depth buffer? //float z; - // glReadPixels(mousePosition.x, mousePosition.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z); + //glReadPixels(mousePosition.x, mousePosition.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z); //http://www.bfilipek.com/2012/06/select-mouse-opengl.html - Vector3 nearPoint = { mousePosition.x, realy, 0.0f }; - Vector3 farPoint = { mousePosition.x, realy, 1.0f }; + Vector3 nearPoint = { mousePosition.x, invertedMouseY, 0.0f }; + Vector3 farPoint = { mousePosition.x, invertedMouseY, 1.0f }; - //nearPoint = internalCamera.position; - farPoint = rlglUnproject(farPoint, proj, view); + nearPoint = rlglUnproject(nearPoint, proj, view); + farPoint = rlglUnproject(farPoint, proj, view); // TODO: it seems it doesn't work... Vector3 direction = VectorSubtract(farPoint, nearPoint); VectorNormalize(&direction); @@ -791,7 +818,11 @@ void SetMousePosition(Vector2 position) // Returns mouse wheel movement Y int GetMouseWheelMove(void) { +#if defined(PLATFORM_WEB) + return previousMouseWheelY/100; +#else return previousMouseWheelY; +#endif } // Hide mouse cursor @@ -933,40 +964,6 @@ bool IsGamepadButtonUp(int gamepad, int button) } #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) -// Returns touch position X -int GetTouchX(void) -{ - return (int)GetRawPosition().x; -} - -// Returns touch position Y -int GetTouchY(void) -{ - return (int)GetRawPosition().y; -} - -// Returns touch position XY -Vector2 GetTouchPosition(void) -{ - Vector2 position = GetRawPosition(); - - if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) - { - // TODO: Seems to work ok but... review! - position.x = position.x*((float)screenWidth / (float)(displayWidth - renderOffsetX)) - renderOffsetX/2; - position.y = position.y*((float)screenHeight / (float)(displayHeight - renderOffsetY)) - renderOffsetY/2; - } - else - { - position.x = position.x*((float)renderWidth / (float)displayWidth) - renderOffsetX/2; - position.y = position.y*((float)renderHeight / (float)displayHeight) - renderOffsetY/2; - } - - return position; -} -#endif - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -1010,7 +1007,8 @@ static void InitDisplay(int width, int height) glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable //glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window - //glfwWindowHint(GLFW_RED_BITS, 8); // Bit depths of color components for default framebuffer + //glfwWindowHint(GLFW_RED_BITS, 8); // Color framebuffer red component bits + //glfwWindowHint(GLFW_DEPTH_BITS, 16); // Depth buffer bits (24 by default) //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // Default OpenGL API to use. Alternative: GLFW_OPENGL_ES_API //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers @@ -1074,6 +1072,9 @@ static void InitDisplay(int width, int height) glfwSetCharCallback(window, CharCallback); glfwSetScrollCallback(window, ScrollCallback); glfwSetWindowIconifyCallback(window, WindowIconifyCallback); +#if defined(PLATFORM_DESKTOP) + glfwSetDropCallback(window, WindowDropCallback); +#endif glfwMakeContextCurrent(window); @@ -1106,7 +1107,14 @@ static void InitDisplay(int width, int height) VC_RECT_T srcRect; #endif - // TODO: if (configFlags & FLAG_MSAA_4X_HINT) activate (EGL_SAMPLES, 4) + EGLint samples = 0; + EGLint sampleBuffer = 0; + if (configFlags & FLAG_MSAA_4X_HINT) + { + samples = 4; + sampleBuffer = 1; + } + const EGLint framebufferAttribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Type of context support -> Required on RPI? @@ -1115,10 +1123,10 @@ static void InitDisplay(int width, int height) EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) //EGL_ALPHA_SIZE, 8, // ALPHA bit depth - EGL_DEPTH_SIZE, 8, // Depth buffer size (Required to use Depth testing!) + EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!) //EGL_STENCIL_SIZE, 8, // Stencil buffer size - //EGL_SAMPLE_BUFFERS, 1, // Activate MSAA - //EGL_SAMPLES, 4, // 4x Antialiasing (Free on MALI GPUs) + EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA + EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs) EGL_NONE }; @@ -1317,20 +1325,28 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height) // GLFW3 WindowIconify Callback, runs when window is minimized/restored static void WindowIconifyCallback(GLFWwindow* window, int iconified) { - if (iconified) - { - // The window was iconified - PauseMusicStream(); + if (iconified) windowMinimized = true; // The window was iconified + else windowMinimized = false; // The window was restored +} +#endif - windowMinimized = true; - } - else +#if defined(PLATFORM_DESKTOP) +// GLFW3 Window Drop Callback, runs when drop files into window +// NOTE: Paths are stored in dinamic memory for further retrieval +// Everytime new files are dropped, old ones are discarded +static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) +{ + ClearDroppedFiles(); + + dropFilesPath = (char **)malloc(sizeof(char *)*count); + + for (int i = 0; i < count; i++) { - // The window was restored - ResumeMusicStream(); - - windowMinimized = false; + dropFilesPath[i] = (char *)malloc(sizeof(char)*256); // Max path length set to 256 char + strcpy(dropFilesPath[i], paths[i]); } + + dropFilesCount = count; } #endif @@ -1379,7 +1395,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) case APP_CMD_GAINED_FOCUS: { TraceLog(INFO, "APP_CMD_GAINED_FOCUS"); - ResumeMusicStream(); + //ResumeMusicStream(); } break; case APP_CMD_PAUSE: { @@ -1389,7 +1405,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) { //DrawFrame(); TraceLog(INFO, "APP_CMD_LOST_FOCUS"); - PauseMusicStream(); + //PauseMusicStream(); } break; case APP_CMD_TERM_WINDOW: { @@ -1476,7 +1492,7 @@ static double GetTime(void) clock_gettime(CLOCK_MONOTONIC, &ts); uint64_t time = ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec; - return (double)(time - baseTime) * 1e-9; + return (double)(time - baseTime)*1e-9; #endif } diff --git a/src/gestures.c b/src/gestures.c index ad8ac9f6..27e3830a 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -1,8 +1,6 @@ /********************************************************************************************** * -* raylib.gestures -* -* Gestures Detection and Usage Functions Definitions +* raylib Gestures System - Gestures Detection and Usage Functions (Android and HTML5) * * Copyright (c) 2015 Marc Palau and Ramon Santamaria * @@ -23,8 +21,13 @@ * **********************************************************************************************/ -#include "raylib.h" -#include "utils.h" +//#define GESTURES_STANDALONE // NOTE: To use the gestures module as standalone lib, just uncomment this line + +#if defined(GESTURES_STANDALONE) + #include "gestures.h" +#else + #include "raylib.h" // Required for typedef(s): Vector2, Gestures +#endif #include <stdlib.h> // malloc(), free() #include <stdio.h> // printf(), fprintf() @@ -53,9 +56,11 @@ //---------------------------------------------------------------------------------- #define FORCE_TO_SWIPE 20 #define TAP_TIMEOUT 300 - #define MAX_TOUCH_POINTS 4 +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- typedef enum { TYPE_MOTIONLESS, TYPE_DRAG, @@ -75,72 +80,56 @@ typedef struct { Vector2 position[MAX_TOUCH_POINTS]; } GestureEvent; + //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- - static GestureType gestureType = TYPE_MOTIONLESS; static double eventTime = 0; -//static int32_t touchId; // Not used... +//static int32_t touchId; // Not used... -// Tap -// Our initial press position on tap +// Tap gesture variables static Vector2 initialTapPosition = { 0, 0 }; -// Double tap -// If we are double tapping or not +// Double Tap gesture variables static bool doubleTapping = false; -// If we recently made a tap -static bool untap = false; +static bool untap = false; // Check if recently done a tap -// Drag -// Our initial press position on drag +// Drag gesture variables static Vector2 initialDragPosition = { 0, 0 }; -// Position that will compare itself with the mouse one static Vector2 endDragPosition = { 0, 0 }; -// Position of the last event detection static Vector2 lastDragPosition = { 0, 0 }; -// The total drag vector static Vector2 dragVector = { 0, 0 }; -// The distance traveled dragging -static float magnitude = 0; -// The angle direction of the drag -static float angle = 0; -// A magnitude to calculate how fast we did the drag ( pixels per frame ) -static float intensity = 0; -// Time that have passed while dragging -static int draggingTimeCounter = 0; - -// Pinch -// First initial pinch position + +static float magnitude = 0; // Distance traveled dragging +static float angle = 0; // Angle direction of the drag +static float intensity = 0; // How fast we did the drag (pixels per frame) +static int draggingTimeCounter = 0; // Time that have passed while dragging + +// Pinch gesture variables static Vector2 firstInitialPinchPosition = { 0, 0 }; -// Second initial pinch position static Vector2 secondInitialPinchPosition = { 0, 0 }; -// First end pinch position static Vector2 firstEndPinchPosition = { 0, 0 }; -// Second end pinch position static Vector2 secondEndPinchPosition = { 0, 0 }; -// Delta Displacement -static float pinchDelta = 0; +static float pinchDelta = 0; // Pinch delta displacement -// Detected gesture +// Detected gestures +static int previousGesture = GESTURE_NONE; static int currentGesture = GESTURE_NONE; -unsigned int enabledGestures = 0; // TODO: Currently not in use... + +static unsigned int enabledGestures = 0; // TODO: Currently not in use... static Vector2 touchPosition; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -extern void ResetGestures(void); -extern Vector2 GetRawPosition(void); - static void ProcessMotionEvent(GestureEvent event); + +static void InitPinchGesture(Vector2 posA, Vector2 posB); static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, float magnitude); -static float OnPinch(); -static void SetDualInput(GestureEvent event); -static float Distance(Vector2 v1, Vector2 v2); -static float DotProduct(Vector2 v1, Vector2 v2); +static float VectorDistance(Vector2 v1, Vector2 v2); +static float VectorDotProduct(Vector2 v1, Vector2 v2); static double GetCurrentTime(); #if defined(PLATFORM_WEB) @@ -155,15 +144,43 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) // Module Functions Definition //---------------------------------------------------------------------------------- -// Returns tap position XY -extern Vector2 GetRawPosition(void) +// Returns touch position X +int GetTouchX(void) { - return touchPosition; + return (int)touchPosition.x; +} + +// Returns touch position Y +int GetTouchY(void) +{ + return (int)touchPosition.y; +} + +// Returns touch position XY +// TODO: touch position should be scaled depending on display size and render size +Vector2 GetTouchPosition(void) +{ + Vector2 position = touchPosition; +/* + if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) + { + // TODO: Seems to work ok but... review! + position.x = position.x*((float)screenWidth / (float)(displayWidth - renderOffsetX)) - renderOffsetX/2; + position.y = position.y*((float)screenHeight / (float)(displayHeight - renderOffsetY)) - renderOffsetY/2; + } + else + { + position.x = position.x*((float)renderWidth / (float)displayWidth) - renderOffsetX/2; + position.y = position.y*((float)renderHeight / (float)displayHeight) - renderOffsetY/2; + } +*/ + return position; } // Check if a gesture have been detected bool IsGestureDetected(void) { +/* if (currentGesture == GESTURE_DRAG) TraceLog(INFO, "DRAG"); else if (currentGesture == GESTURE_TAP) TraceLog(INFO, "TAP"); else if (currentGesture == GESTURE_DOUBLETAP) TraceLog(INFO, "DOUBLE"); @@ -174,6 +191,7 @@ bool IsGestureDetected(void) else if (currentGesture == GESTURE_SWIPE_DOWN) TraceLog(INFO, "DOWN"); else if (currentGesture == GESTURE_PINCH_IN) TraceLog(INFO, "PINCH IN"); else if (currentGesture == GESTURE_PINCH_OUT) TraceLog(INFO, "PINCH OUT"); +*/ if (currentGesture != GESTURE_NONE) return true; else return false; @@ -228,33 +246,24 @@ float GetGesturePinchAngle(void) return 0; } -extern void ResetGestures(void) -{ - if (currentGesture == GESTURE_TAP) currentGesture = GESTURE_HOLD; - else if (currentGesture != GESTURE_HOLD) currentGesture = GESTURE_NONE; -} - #if defined(PLATFORM_WEB) -extern void InitWebGestures(void) +// Init gestures system (web) +void InitGesturesSystem(void) { - /* - emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch); - emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch); - emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch); - emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch); - */ - + // Init gestures system web (emscripten) + + // NOTE: Some code examples //emscripten_set_touchstart_callback(0, NULL, 1, Emscripten_HandleTouch); + //emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch); emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenInputCallback); emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenInputCallback); emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback); emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback); } -#endif - -#if defined(PLATFORM_ANDROID) -extern void InitAndroidGestures(struct android_app *app) +#elif defined(PLATFORM_ANDROID) +// Init gestures system (android) +void InitGesturesSystem(struct android_app *app) { app->onInputEvent = AndroidInputCallback; @@ -262,6 +271,15 @@ extern void InitAndroidGestures(struct android_app *app) } #endif +// Update gestures detected (must be called every frame) +void UpdateGestures(void) +{ + // NOTE: Gestures are processed through system callbacks on touch events + + if ((previousGesture == GESTURE_TAP) && (currentGesture == GESTURE_TAP)) currentGesture = GESTURE_HOLD; + else if (currentGesture != GESTURE_HOLD) currentGesture = GESTURE_NONE; +} + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -271,13 +289,15 @@ static void ProcessMotionEvent(GestureEvent event) dragVector = (Vector2){ 0, 0 }; pinchDelta = 0; + previousGesture = currentGesture; + switch (gestureType) { case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events { if (event.action == DOWN) { - if (event.pointCount > 1) SetDualInput(event); + if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); else { // Set the press position @@ -317,7 +337,7 @@ static void ProcessMotionEvent(GestureEvent event) // Begin dragging else if (event.action == MOVE) { - if (event.pointCount > 1) SetDualInput(event); + if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); else { // Set the drag starting position @@ -354,7 +374,7 @@ static void ProcessMotionEvent(GestureEvent event) // Update while we are dragging else if (event.action == MOVE) { - if (event.pointCount > 1) SetDualInput(event); + if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); else { lastDragPosition = endDragPosition; @@ -395,8 +415,17 @@ static void ProcessMotionEvent(GestureEvent event) // If there is no more than two inputs if (event.pointCount == 2) { - // Detect pinch delta - pinchDelta = OnPinch(); + // Calculate distances + float initialDistance = VectorDistance(firstInitialPinchPosition, secondInitialPinchPosition); + float endDistance = VectorDistance(firstEndPinchPosition, secondEndPinchPosition); + + // Calculate Vectors + Vector2 firstTouchVector = { firstEndPinchPosition.x - firstInitialPinchPosition.x, firstEndPinchPosition.y - firstInitialPinchPosition.y }; + Vector2 secondTouchVector = { secondEndPinchPosition.x - secondInitialPinchPosition.x, secondEndPinchPosition.y - secondInitialPinchPosition.y }; + + // Detect the pinch gesture + if (VectorDotProduct(firstTouchVector, secondTouchVector) < -0.5) pinchDelta = initialDistance - endDistance; + else pinchDelta = 0; // Pinch gesture resolution if (pinchDelta != 0) @@ -422,36 +451,30 @@ static void ProcessMotionEvent(GestureEvent event) //-------------------------------------------------------------------- } -static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, float magnitude) +static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, float magnitude) { float angle; - // Calculate arcsinus of the movement ( Our sinus is (actualPosition.y - initialPosition.y) / magnitude) - angle = asin((actualPosition.y - initialPosition.y) / magnitude); + // Calculate arcsinus of the movement + angle = asin((finalPosition.y - initialPosition.y)/magnitude); angle *= RAD2DEG; // Calculate angle depending on the sector - if (actualPosition.x - initialPosition.x >= 0) + if ((finalPosition.x - initialPosition.x) >= 0) { // Sector 4 - if (actualPosition.y - initialPosition.y >= 0) + if ((finalPosition.y - initialPosition.y) >= 0) { angle *= -1; angle += 360; } // Sector 1 - else - { - angle *= -1; - } + else angle *= -1; } else { // Sector 3 - if (actualPosition.y - initialPosition.y >= 0) - { - angle += 180; - } + if ((finalPosition.y - initialPosition.y) >= 0) angle += 180; // Sector 2 else { @@ -463,31 +486,15 @@ static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, flo return angle; } -static float OnPinch() -{ - // Calculate distances - float initialDistance = Distance(firstInitialPinchPosition, secondInitialPinchPosition); - float endDistance = Distance(firstEndPinchPosition, secondEndPinchPosition); - - // Calculate Vectors - Vector2 firstTouchVector = { firstEndPinchPosition.x - firstInitialPinchPosition.x, firstEndPinchPosition.y - firstInitialPinchPosition.y }; - Vector2 secondTouchVector = { secondEndPinchPosition.x - secondInitialPinchPosition.x, secondEndPinchPosition.y - secondInitialPinchPosition.y }; - - // Detect the pinch gesture - // Calculate Distances - if (DotProduct(firstTouchVector, secondTouchVector) < -0.5) return initialDistance - endDistance; - else return 0; -} - -static void SetDualInput(GestureEvent event) +static void InitPinchGesture(Vector2 posA, Vector2 posB) { initialDragPosition = (Vector2){ 0, 0 }; endDragPosition = (Vector2){ 0, 0 }; lastDragPosition = (Vector2){ 0, 0 }; // Initialize positions - firstInitialPinchPosition = event.position[0]; - secondInitialPinchPosition = event.position[1]; + firstInitialPinchPosition = posA; + secondInitialPinchPosition = posB; firstEndPinchPosition = firstInitialPinchPosition; secondEndPinchPosition = secondInitialPinchPosition; @@ -500,7 +507,7 @@ static void SetDualInput(GestureEvent event) gestureType = TYPE_DUAL_INPUT; } -static float Distance(Vector2 v1, Vector2 v2) +static float VectorDistance(Vector2 v1, Vector2 v2) { float result; @@ -512,7 +519,7 @@ static float Distance(Vector2 v1, Vector2 v2) return result; } -static float DotProduct(Vector2 v1, Vector2 v2) +static float VectorDotProduct(Vector2 v1, Vector2 v2) { float result; @@ -569,7 +576,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) //int32_t key = AKeyEvent_getKeyCode(event); //int32_t AKeyEvent_getMetaState(event); - int32_t code = AKeyEvent_getKeyCode((const AInputEvent *)event); + //int32_t code = AKeyEvent_getKeyCode((const AInputEvent *)event); // If we are in active mode, we eat the back button and move into pause mode. // If we are already in pause mode, we allow the back button to be handled by the OS, which means we'll be shut down. @@ -652,10 +659,4 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent return 1; } -#endif - - - - - - +#endif
\ No newline at end of file diff --git a/src/gestures.h b/src/gestures.h new file mode 100644 index 00000000..896f3028 --- /dev/null +++ b/src/gestures.h @@ -0,0 +1,107 @@ +/********************************************************************************************** +* +* raylib Gestures System - Gestures Detection and Usage Functions (Android and HTML5) +* +* 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. +* +**********************************************************************************************/ + +#ifndef GESTURES_H +#define GESTURES_H + +#ifndef PI + #define PI 3.14159265358979323846 +#endif + +#define DEG2RAD (PI / 180.0f) +#define RAD2DEG (180.0f / PI) + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Below types are required for GESTURES_STANDALONE usage +//---------------------------------------------------------------------------------- +#ifndef __cplusplus + // Boolean type + typedef enum { false, true } bool; +#endif + +// Vector2 type +typedef struct Vector2 { + float x; + float y; +} Vector2; + +// Gestures type +// NOTE: It could be used as flags to enable only some gestures +typedef enum { + GESTURE_NONE = 1, + GESTURE_TAP = 2, + GESTURE_DOUBLETAP = 4, + GESTURE_HOLD = 8, + GESTURE_DRAG = 16, + GESTURE_SWIPE_RIGHT = 32, + GESTURE_SWIPE_LEFT = 64, + GESTURE_SWIPE_UP = 128, + GESTURE_SWIPE_DOWN = 256, + GESTURE_PINCH_IN = 512, + GESTURE_PINCH_OUT = 1024 +} Gestures; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +int GetTouchX(void); // Returns touch position X (relative to screen size) +int GetTouchY(void); // Returns touch position Y (relative to screen size) +Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size) + +#if defined(PLATFORM_WEB) +void InitGesturesSystem(void); // Init gestures system (web) +#elif defined(PLATFORM_ANDROID) +void InitGesturesSystem(struct android_app *app); // Init gestures system (android) +#endif +void UpdateGestures(void); // Update gestures detected (must be called every frame) +bool IsGestureDetected(void); // Check if a gesture have been detected +int GetGestureType(void); // Get latest detected gesture +void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags + +float GetGestureDragIntensity(void); // Get gesture drag intensity +float GetGestureDragAngle(void); // Get gesture drag angle +Vector2 GetGestureDragVector(void); // Get gesture drag vector +int GetGestureHoldDuration(void); // Get gesture hold time in frames +float GetGesturePinchDelta(void); // Get gesture pinch delta +float GetGesturePinchAngle(void); // Get gesture pinch angle + +#ifdef __cplusplus +} +#endif + +#endif // GESTURES_H diff --git a/src/makefile b/src/makefile index 11bbea9d..67123a9a 100644 --- a/src/makefile +++ b/src/makefile @@ -93,7 +93,7 @@ else endif # define all object files required -OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o camera.o gestures.o +OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o camera.o gestures.o stb_vorbis.o # typing 'make' will invoke the first target entry in the file, # in this case, the 'default' target entry is raylib @@ -139,6 +139,10 @@ models.o: models.c # compile audio module audio.o: audio.c $(CC) -c audio.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile stb_vorbis library +stb_vorbis.o: stb_vorbis.c + $(CC) -c stb_vorbis.c -O1 $(INCLUDES) -D$(PLATFORM) # compile utils module utils.o: utils.c diff --git a/src/models.c b/src/models.c index c45e18c8..054febcf 100644 --- a/src/models.c +++ b/src/models.c @@ -4,7 +4,7 @@ * * Basic functions to draw 3d shapes and load/draw 3d models (.OBJ) * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. @@ -558,22 +558,33 @@ void DrawGizmo(Vector3 position) Model LoadModel(const char *fileName) { VertexData vData; + + Model model; + + // TODO: Initialize default data for model in case loading fails, maybe a cube? if (strcmp(GetExtension(fileName),"obj") == 0) vData = LoadOBJ(fileName); else TraceLog(WARNING, "[%s] Model extension not recognized, it can't be loaded", fileName); // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct - - // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() - Model model = rlglLoadModel(vData); // Upload vertex data to GPU - - // Now that vertex data is uploaded to GPU, we can free arrays - // NOTE: We don't need CPU vertex data on OpenGL 3.3 or ES2 - if (rlGetVersion() != OPENGL_11) + + if (vData.vertexCount == 0) { - free(vData.vertices); - free(vData.texcoords); - free(vData.normals); + TraceLog(WARNING, "Model could not be loaded"); + } + else + { + // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() + model = rlglLoadModel(vData); // Upload vertex data to GPU + + // Now that vertex data is uploaded to GPU, we can free arrays + // NOTE: We don't need CPU vertex data on OpenGL 3.3 or ES2 + if (rlGetVersion() != OPENGL_11) + { + free(vData.vertices); + free(vData.texcoords); + free(vData.normals); + } } return model; @@ -1105,6 +1116,8 @@ void UnloadModel(Model model) rlDeleteBuffers(model.mesh.vboId[2]); rlDeleteVertexArrays(model.mesh.vaoId); + + TraceLog(INFO, "Unloaded model data"); } // Link a texture to a model diff --git a/src/raylib.h b/src/raylib.h index 228d3e58..f5220e2e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -36,7 +36,7 @@ * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2013 Ramon Santamaria (@raysan5) * * 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. @@ -176,7 +176,6 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- - #ifndef __cplusplus // Boolean type typedef enum { false, true } bool; @@ -354,6 +353,9 @@ typedef enum { COMPRESSED_ASTC_8x8_RGBA // 2 bpp } TextureFormat; +// Color blending modes (pre-defined) +typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; + // Gestures type // NOTE: It could be used as flags to enable only some gestures typedef enum { @@ -370,6 +372,9 @@ typedef enum { GESTURE_PINCH_OUT = 1024 } Gestures; +// Camera system modes +typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -383,13 +388,14 @@ extern "C" { // Prevents name mangling of functions // Window and Graphics Device Functions (Module: core) //------------------------------------------------------------------------------------ #if defined(PLATFORM_ANDROID) -void InitWindow(int width, int height, struct android_app *state); // Init Android activity +void InitWindow(int width, int height, struct android_app *state); // Init Android Activity and OpenGL Graphics #elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics #endif void CloseWindow(void); // Close Window and Terminate Context bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed +bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) void SetCustomCursor(const char *cursorImage); // Set a custom cursor icon/image @@ -418,6 +424,10 @@ Color Fade(Color color, float alpha); // Color fade-in or void SetConfigFlags(char flags); // Enable some window configurations void ShowLogo(void); // Activates raylib logo at startup (can be done with flags) +bool IsFileDropped(void); // Check if a file have been dropped into window +char **GetDroppedFiles(int *count); // Retrieve dropped files into window +void ClearDroppedFiles(void); // Clear dropped files paths buffer + Ray GetMouseRay(Vector2 mousePosition, Camera camera); // TODO: Gives the ray trace from mouse position //------------------------------------------------------------------------------------ @@ -441,6 +451,8 @@ void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D textu void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture); // Specular map texture shader assignment void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textureUnit); // TODO: Generic shader map assignment +void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) + //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) //------------------------------------------------------------------------------------ @@ -461,9 +473,9 @@ Vector2 GetMousePosition(void); // Returns mouse positio void SetMousePosition(Vector2 position); // Set mouse position XY int GetMouseWheelMove(void); // Returns mouse wheel movement Y -void ShowCursor(void); // Shows cursor -void HideCursor(void); // Hides cursor -bool IsCursorHidden(void); // Returns true if cursor is not visible +void ShowCursor(void); // Shows cursor +void HideCursor(void); // Hides cursor +bool IsCursorHidden(void); // Returns true if cursor is not visible #endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) @@ -476,22 +488,47 @@ bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad b #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) -int GetTouchX(void); // Returns touch position X -int GetTouchY(void); // Returns touch position Y -Vector2 GetTouchPosition(void); // Returns touch position XY - -// Gestures System (module: gestures) -bool IsGestureDetected(void); -int GetGestureType(void); -void SetGesturesEnabled(unsigned int gestureFlags); - -float GetGestureDragIntensity(void); -float GetGestureDragAngle(void); -Vector2 GetGestureDragVector(void); -int GetGestureHoldDuration(void); // Hold time in frames -float GetGesturePinchDelta(void); -float GetGesturePinchAngle(void); +//------------------------------------------------------------------------------------ +// Gestures and Touch Handling Functions (Module: gestures) +//------------------------------------------------------------------------------------ +int GetTouchX(void); // Returns touch position X (relative to screen size) +int GetTouchY(void); // Returns touch position Y (relative to screen size) +Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size) + +#if defined(PLATFORM_WEB) +void InitGesturesSystem(void); // Init gestures system (web) +#elif defined(PLATFORM_ANDROID) +void InitGesturesSystem(struct android_app *app); // Init gestures system (android) #endif +void UpdateGestures(void); // Update gestures detected (must be called every frame) +bool IsGestureDetected(void); // Check if a gesture have been detected +int GetGestureType(void); // Get latest detected gesture +void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags + +float GetGestureDragIntensity(void); // Get gesture drag intensity +float GetGestureDragAngle(void); // Get gesture drag angle +Vector2 GetGestureDragVector(void); // Get gesture drag vector +int GetGestureHoldDuration(void); // Get gesture hold time in frames +float GetGesturePinchDelta(void); // Get gesture pinch delta +float GetGesturePinchAngle(void); // Get gesture pinch angle +#endif + +//------------------------------------------------------------------------------------ +// Camera System Functions (Module: camera) +//------------------------------------------------------------------------------------ +void SetCameraMode(int mode); // Set camera mode (multiple camera modes available) +Camera UpdateCamera(Vector3 *playerPosition); // Update camera and player position (1st person and 3rd person cameras) + +void SetCameraMoveControls(int frontKey, int backKey, + int leftKey, int rightKey, + int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) + +void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) +void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) +void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) + +void SetCameraMouseSensitivity(float sensitivity); // Set camera mouse sensitivity (1st person and 3rd person cameras) +void SetCameraTarget(Vector3 target); // Set internal camera target //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) @@ -625,6 +662,7 @@ void SetSoundVolume(Sound sound, float volume); // Set volume fo void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) void PlayMusicStream(char *fileName); // Start music playing (open stream) +void UpdateMusicStream(void); // Updates buffers for music streaming void StopMusicStream(void); // Stop music playing (close stream) void PauseMusicStream(void); // Pause music playing void ResumeMusicStream(void); // Resume playing paused music @@ -7,7 +7,7 @@ * OpenGL 3.3+ - Vertex data is stored in VAOs, call rlglDraw() to render * OpenGL ES 2 - Same behaviour as OpenGL 3.3+ * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. @@ -33,20 +33,21 @@ #include <string.h> // Declares strcmp(), strlen(), strtok() #if defined(GRAPHICS_API_OPENGL_11) - #ifdef __APPLE__ // OpenGL include for OSX + #ifdef __APPLE__ // OpenGL include for OSX #include <OpenGL/gl.h> #else - #include <GL/gl.h> // Basic OpenGL include + #include <GL/gl.h> // Basic OpenGL include #endif #endif #if defined(GRAPHICS_API_OPENGL_33) #define GLEW_STATIC - #ifdef __APPLE__ // OpenGL include for OSX + #ifdef __APPLE__ // OpenGL include for OSX #include <OpenGL/gl3.h> #else - #include <GL/glew.h> // Extensions loading lib - //#include "glad.h" // TODO: Other extensions loading lib? --> REVIEW + #include <GL/glew.h> // GLEW extensions loading lib + //#include "glad.h" // glad extensions loading lib: ERRORS: windows.h + //#include "gl_core_3_3.h" // glLoadGen extension loading lib: ERRORS: windows.h #endif #endif @@ -56,6 +57,10 @@ #include <GLES2/gl2ext.h> #endif +#if defined(RLGL_STANDALONE) + #include <stdarg.h> // Used for functions with variable number of parameters (TraceLog()) +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -177,6 +182,10 @@ typedef struct { unsigned char a; } pixel; +#if defined(RLGL_STANDALONE) +typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; +#endif + //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -218,7 +227,6 @@ static bool useTempBuffer = false; // Flags for supported extensions static bool vaoSupported = false; // VAO support (OpenGL ES2 could not support VAO extension) -static bool npotSupported = false; // NPOT textures full support // Compressed textures support flags //static bool texCompDXTSupported = false; // DDS texture compression support @@ -236,7 +244,8 @@ static bool enabledPostpro = false; #endif // Compressed textures support flags -static bool texCompDXTSupported = false; // DDS texture compression support +static bool texCompDXTSupported = false; // DDS texture compression support +static bool npotSupported = false; // NPOT textures full support #if defined(GRAPHICS_API_OPENGL_ES2) // NOTE: VAO functionality is exposed through extensions (OES) @@ -246,6 +255,11 @@ static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays; //static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted #endif +// Save screen size data (render size), required for postpro quad +static int screenWidth, screenHeight; + +static int blendMode = 0; + // White texture useful for plain color polys (required by shader) // NOTE: It's required in shapes and models modules! unsigned int whiteTexture; @@ -273,6 +287,10 @@ static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight); static char** StringSplit(char *baseString, const char delimiter, int *numExt); #endif +#if defined(RLGL_STANDALONE) +static void TraceLog(int msgType, const char *text, ...); +#endif + //---------------------------------------------------------------------------------- // Module Functions Definition - Matrix operations //---------------------------------------------------------------------------------- @@ -838,35 +856,69 @@ void rlglInit(void) //for (int i = 0; i < numComp; i++) TraceLog(INFO, "Supported compressed format: 0x%x", format[i]); // NOTE: We don't need that much data on screen... right now... + +#if defined(GRAPHICS_API_OPENGL_11) + TraceLog(INFO, "OpenGL 1.1 profile initialized"); +#endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Get supported extensions list GLint numExt; #if defined(GRAPHICS_API_OPENGL_33) + +#define GLEW_EXTENSIONS_LOADER +#if defined(GLEW_EXTENSIONS_LOADER) // Initialize extensions using GLEW glewExperimental = 1; // Needed for core profile - GLenum error = glewInit(); if (error != GLEW_OK) TraceLog(ERROR, "Failed to initialize GLEW - Error Code: %s\n", glewGetErrorString(error)); - + if (glewIsSupported("GL_VERSION_3_3")) { - TraceLog(INFO, "OpenGL 3.3 Core profile"); + TraceLog(INFO, "OpenGL 3.3 Core profile supported"); vaoSupported = true; npotSupported = true; } + else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); + + // With GLEW, we can check if an extension has been loaded in two ways: + //if (GLEW_ARB_vertex_array_object) { } + //if (glewIsSupported("GL_ARB_vertex_array_object")) { } // NOTE: GLEW is a big library that loads ALL extensions, we can use some alternative to load only required ones // Alternatives: glLoadGen, glad, libepoxy - //if (!gladLoadGL()) TraceLog("ERROR: Failed to initialize glad\n"); + +#elif defined(GLAD_EXTENSIONS_LOADER) + // NOTE: glad is generated and contains only required OpenGL version and core extensions + if (!gladLoadGL()) TraceLog(ERROR, "Failed to initialize glad\n"); + //if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) TraceLog(ERROR, "Failed to initialize glad\n"); - // With GLEW we can check if an extension has been loaded in two ways: - //if (GLEW_ARB_vertex_array_object) { } - //if (glewIsSupported("GL_ARB_vertex_array_object")) { } + if (GLAD_GL_VERSION_3_3) + { + TraceLog(INFO, "OpenGL 3.3 Core profile supported"); + + vaoSupported = true; + npotSupported = true; + } + else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); + + // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans + //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object +#elif defined(GLLOADGEN_EXTENSIONS_LOADER) + // NOTE: glLoadGen already generates a header with required OpenGL version and core extensions + if (ogl_LoadFunctions() != ogl_LOAD_FAILED) + { + TraceLog(INFO, "OpenGL 3.3 Core profile supported"); + + vaoSupported = true; + npotSupported = true; + } + else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); +#endif // NOTE: We don't need to check again supported extensions but we do (in case GLEW is replaced sometime) // We get a list of available extensions and we check for some of them (compressed textures) @@ -995,6 +1047,7 @@ void rlglInit(void) } // Init postpro system +// NOTE: Uses global variables screenWidth and screenHeight void rlglInitPostpro(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -1003,57 +1056,82 @@ void rlglInitPostpro(void) glBindTexture(GL_TEXTURE_2D, fboColorTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GetScreenWidth(), GetScreenHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screenWidth, screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, 0); - // Create the texture that will serve as the depth attachment for the framebuffer. + // Create the renderbuffer that will serve as the depth attachment for the framebuffer. + glGenRenderbuffers(1, &fboDepthTexture); + glBindRenderbuffer(GL_RENDERBUFFER, fboDepthTexture); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screenWidth, screenHeight); + + // NOTE: We can also use a texture for depth buffer (GL_ARB_depth_texture/GL_OES_depth_texture extensions) + // A renderbuffer is simpler than a texture and could offer better performance on embedded devices +/* glGenTextures(1, &fboDepthTexture); glBindTexture(GL_TEXTURE_2D, fboDepthTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GetScreenWidth(), GetScreenHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, 0); +*/ // Create the framebuffer object glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); - // Attach color texture and depth texture to FBO + // Attach color texture and depth renderbuffer to FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboColorTexture, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fboDepthTexture, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboDepthTexture); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) TraceLog(WARNING, "Framebuffer object could not be created..."); - else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo); + if (status != GL_FRAMEBUFFER_COMPLETE) + { + TraceLog(WARNING, "Framebuffer object could not be created..."); + + switch(status) + { + case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break; +#if defined(GRAPHICS_API_OPENGL_ES2) + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TraceLog(WARNING, "Framebuffer incomplete dimensions"); break; +#endif + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete missing attachment"); break; + default: break; + } + } + else + { + TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - // Create a simple quad model to render fbo texture - VertexData quadData; - - quadData.vertexCount = 6; - - float w = GetScreenWidth(); - float h = GetScreenHeight(); - - float quadPositions[6*3] = { w, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, h, 0.0, 0, h, 0.0, w, h, 0.0, w, 0.0, 0.0 }; - float quadTexcoords[6*2] = { 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 }; - float quadNormals[6*3] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0 }; - unsigned char quadColors[6*4] = { 255 }; - - quadData.vertices = quadPositions; - quadData.texcoords = quadTexcoords; - quadData.normals = quadNormals; - quadData.colors = quadColors; - - postproQuad = rlglLoadModel(quadData); - - // NOTE: fboColorTexture id must be assigned to postproQuad model shader + // Create a simple quad model to render fbo texture + VertexData quadData; + + quadData.vertexCount = 6; + + float w = screenWidth; + float h = screenHeight; + + float quadPositions[6*3] = { w, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, h, 0.0, 0, h, 0.0, w, h, 0.0, w, 0.0, 0.0 }; + float quadTexcoords[6*2] = { 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 }; + float quadNormals[6*3] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0 }; + unsigned char quadColors[6*4] = { 255 }; + + quadData.vertices = quadPositions; + quadData.texcoords = quadTexcoords; + quadData.normals = quadNormals; + quadData.colors = quadColors; + + postproQuad = rlglLoadModel(quadData); + + // NOTE: fboColorTexture id must be assigned to postproQuad model shader + } #endif } @@ -1116,7 +1194,20 @@ void rlglClose(void) { glDeleteFramebuffers(1, &fbo); - UnloadModel(postproQuad); + // Unload postpro quad model data +#if defined(GRAPHICS_API_OPENGL_11) + free(postproQuad.mesh.vertices); + free(postproQuad.mesh.texcoords); + free(postproQuad.mesh.normals); +#endif + + rlDeleteBuffers(postproQuad.mesh.vboId[0]); + rlDeleteBuffers(postproQuad.mesh.vboId[1]); + rlDeleteBuffers(postproQuad.mesh.vboId[2]); + + rlDeleteVertexArrays(postproQuad.mesh.vaoId); + + TraceLog(INFO, "Unloaded postpro quad data"); } free(draws); @@ -1287,7 +1378,7 @@ void rlglDrawPostpro(void) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glBindFramebuffer(GL_FRAMEBUFFER, 0); - rlglDrawModel(postproQuad, (Vector3){0,0,0}, 0.0f, (Vector3){0,0,0}, (Vector3){1.0f, 1.0f, 1.0f}, WHITE, false); + rlglDrawModel(postproQuad, (Vector3){0,0,0}, 0.0f, (Vector3){0,0,0}, (Vector3){1.0f, 1.0f, 1.0f}, (Color){ 255, 255, 255, 255 }, false); #endif } @@ -1352,15 +1443,16 @@ 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)); - + // Apply color tinting to model // NOTE: Just update one uniform on fragment shader float vColor[4] = { (float)color.r/255, (float)color.g/255, (float)color.b/255, (float)color.a/255 }; glUniform4fv(model.shader.tintColorLoc, 1, vColor); - + // Set shader textures (diffuse, normal, specular) glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, model.shader.texDiffuseId); + glUniform1i(model.shader.mapDiffuseLoc, 0); if (model.shader.texNormalId != 0) { @@ -1390,14 +1482,21 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r glEnableVertexAttribArray(model.shader.texcoordLoc); // Add normals support - glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[2]); - glVertexAttribPointer(model.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.shader.normalLoc); + if (model.shader.normalLoc != -1) + { + glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[2]); + glVertexAttribPointer(model.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.shader.normalLoc); + } } // Draw call! glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount); + //glDisableVertexAttribArray(model.shader.vertexLoc); + //glDisableVertexAttribArray(model.shader.texcoordLoc); + //if (model.shader.normalLoc != -1) glDisableVertexAttribArray(model.shader.normalLoc); + if (model.shader.texNormalId != 0) { glActiveTexture(GL_TEXTURE1); @@ -1426,17 +1525,23 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r } // Initialize Graphics Device (OpenGL stuff) +// NOTE: Stores global variables screenWidth and screenHeight void rlglInitGraphics(int offsetX, int offsetY, int width, int height) { + // Save screen size data (global vars), required on postpro quad + // NOTE: Size represents render size, it could differ from screen size! + screenWidth = width; + screenHeight = height; + // NOTE: Required! viewport must be recalculated if screen resized! glViewport(offsetX/2, offsetY/2, width - offsetX, height - offsetY); // Set viewport width and height // NOTE: Don't confuse glViewport with the transformation matrix // NOTE: glViewport just defines the area of the context that you will actually draw to. - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers, depth buffer is used for 3D glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color (black) //glClearDepth(1.0f); // Clear depth buffer (default) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers, depth buffer is used for 3D glEnable(GL_DEPTH_TEST); // Enables depth testing (required for 3D) glDepthFunc(GL_LEQUAL); // Type of depth testing to apply @@ -1468,170 +1573,61 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height) // Possible options: GL_SMOOTH (Color interpolation) or GL_FLAT (no interpolation) #endif - TraceLog(INFO, "OpenGL Graphics initialized successfully"); + TraceLog(INFO, "OpenGL graphic device initialized successfully"); } // Get world coordinates from screen coordinates // TODO: It doesn't work! It drives me crazy! +// NOTE: Using global variables: screenWidth, screenHeight Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view) { + Vector3 result = { 0, 0, 0 }; // Object coordinates + //GLint viewport[4]; - //glGetIntegerv(GL_VIEWPORT, viewport); + //glGetIntegerv(GL_VIEWPORT, viewport); // Not available on OpenGL ES 2.0 // Viewport data -/* - int x = 0; - int y = 0; - int width = GetScreenWidth(); - int height = GetScreenHeight(); - float minDepth = 0.0f; - float maxDepth = 1.0f; -*/ -/* - Matrix modelviewprojection = MatrixMultiply(modelview, projection); + int x = 0; // viewport[0] + int y = 0; // viewport[1] + int width = screenWidth; // viewport[2] + int height = screenHeight; // viewport[3] + + Matrix modelviewprojection = MatrixMultiply(view, proj); MatrixInvert(&modelviewprojection); - - Vector3 vector; - - vector.x = (((source.x - x) / ((float)width)) * 2.0f) - 1.0f; - vector.y = -((((source.y - y) / ((float)height)) * 2.0f) - 1.0f); - vector.z = (source.z - minDepth) / (maxDepth - minDepth); - - //float a = (((vector.x * matrix.M14) + (vector.y * matrix.M24)) + (vector.z * matrix.M34)) + matrix.M44; - //float a = (((vector.x * modelviewprojection.m3) + (vector.y * modelviewprojection.m7)) + (vector.z * modelviewprojection.m11)) + modelviewprojection.m15; - VectorTransform(&vector, modelviewprojection); - - //if (!MathUtil.IsOne(a)) vector = (vector / a); - //VectorScale(&vector, 1/a); - - return vector; -*/ /* - Vector3 worldPoint; - - // Transformation matrices - Matrix modelviewprojection = MatrixIdentity(); - Quaternion quat; - - // Calculation for inverting a matrix, compute projection x modelview - modelviewprojection = MatrixMultiply(proj, view); - MatrixInvert(&modelviewprojection); + // NOTE: Compute unproject using Vector3 // Transformation of normalized coordinates between -1 and 1 - quat.x = ((source.x - (float)x)/(float)width*2.0) - 1.0f; - quat.y = ((source.y - (float)y)/(float)height*2.0) - 1.0f; - quat.z = 2.0*source.z - 1.0; - quat.w = 1.0; - - // Objects coordinates - QuaternionTransform(&quat, modelviewprojection); - - //if (quat.w == 0.0) return 0; - - worldPoint.x = quat.x/quat.w; - worldPoint.y = quat.y/quat.w; - worldPoint.z = quat.z/quat.w; + result.x = ((source.x - (float)x)/(float)width)*2.0f - 1.0f; + result.y = ((source.y - (float)y)/(float)height)*2.0f - 1.0f; + result.z = source.z*2.0f - 1.0f; - return worldPoint; - */ -/* - Quaternion quat; - Vector3 vec; - - quat.x = 2.0f * GetMousePosition().x / (float)width - 1; - quat.y = -(2.0f * GetMousePosition().y / (float)height - 1); - quat.z = 0; - quat.w = 1; - - Matrix invView; - MatrixInvert(&view); - Matrix invProj; - MatrixInvert(&proj); - - quat.x = invProj.m0 * quat.x + invProj.m4 * quat.y + invProj.m8 * quat.z + invProj.m12 * quat.w; - quat.y = invProj.m1 * quat.x + invProj.m5 * quat.y + invProj.m9 * quat.z + invProj.m13 * quat.w; - quat.z = invProj.m2 * quat.x + invProj.m6 * quat.y + invProj.m10 * quat.z + invProj.m14 * quat.w; - quat.w = invProj.m3 * quat.x + invProj.m7 * quat.y + invProj.m11 * quat.z + invProj.m15 * quat.w; - - quat.x = invView.m0 * quat.x + invView.m4 * quat.y + invView.m8 * quat.z + invView.m12 * quat.w; - quat.y = invView.m1 * quat.x + invView.m5 * quat.y + invView.m9 * quat.z + invView.m13 * quat.w; - quat.z = invView.m2 * quat.x + invView.m6 * quat.y + invView.m10 * quat.z + invView.m14 * quat.w; - quat.w = invView.m3 * quat.x + invView.m7 * quat.y + invView.m11 * quat.z + invView.m15 * quat.w; - - vec.x /= quat.w; - vec.y /= quat.w; - vec.z /= quat.w; - - return vec; - */ -/* - Vector3 worldPoint; - - // Transformation matrices - Matrix modelviewprojection; + // Object coordinates (multiply vector by matrix) + VectorTransform(&result, modelviewprojection); +*/ + + // NOTE: Compute unproject using Quaternion (Vector4) Quaternion quat; - - // Calculation for inverting a matrix, compute projection x modelview - modelviewprojection = MatrixMultiply(view, proj); - - // Now compute the inverse of matrix A - MatrixInvert(&modelviewprojection); - - // Transformation of normalized coordinates between -1 and 1 - quat.x = ((source.x - (float)x)/(float)width*2.0) - 1.0f; - quat.y = ((source.y - (float)y)/(float)height*2.0) - 1.0f; - quat.z = 2.0*source.z - 1.0; + + quat.x = ((source.x - (float)x)/(float)width)*2.0f - 1.0f; + quat.y = ((source.y - (float)y)/(float)height)*2.0f - 1.0f; + quat.z = source.z*2.0f - 1.0f; quat.w = 1.0; + + QuaternionTransform(&quat, modelviewprojection); - // Traspose quaternion and multiply - Quaternion result; - result.x = modelviewprojection.m0 * quad.x + modelviewprojection.m4 * quad.y + modelviewprojection.m8 * quad.z + modelviewprojection.m12 * quad.w; - result.y = modelviewprojection.m1 * quad.x + modelviewprojection.m5 * quad.y + modelviewprojection.m9 * quad.z + modelviewprojection.m13 * quad.w; - result.z = modelviewprojection.m2 * quad.x + modelviewprojection.m6 * quad.y + modelviewprojection.m10 * quad.z + modelviewprojection.m14 * quad.w; - result.w = modelviewprojection.m3 * quad.x + modelviewprojection.m7 * quad.y + modelviewprojection.m11 * quad.z + modelviewprojection.m15 * quad.w; - - // Invert - result.w = 1.0f / result.w; - - //if (quat.w == 0.0) return 0; - - worldPoint.x = quat.x * quat.w; - worldPoint.y = quat.y * quat.w; - worldPoint.z = quat.z * quat.w; - - return worldPoint; - */ -/* - // Needed Vectors - Vector3 normalDeviceCoordinates; - Quaternion rayClip; - Quaternion rayEye; - Vector3 rayWorld; - - // Getting normal device coordinates - float x = (2.0 * mousePosition.x) / GetScreenWidth() - 1.0; - float y = 1.0 - (2.0 * mousePosition.y) / GetScreenHeight(); - float z = 1.0; - normalDeviceCoordinates = (Vector3){ x, y, z }; - - // Getting clip vector - rayClip = (Quaternion){ normalDeviceCoordinates.x, normalDeviceCoordinates.y, -1, 1 }; - - Matrix invProjection = projection; - MatrixInvert(&invProjection); - - rayEye = MatrixQuaternionMultiply(invProjection, rayClip); - rayEye = (Quaternion){ rayEye.x, rayEye.y, -1, 0 }; - - Matrix invModelview = modelview; - MatrixInvert(&invModelview); + if (quat.w != 0.0) + { + quat.x /= quat.w; + quat.y /= quat.w; + quat.z /= quat.w; + } - rayWorld = MatrixVector3Multiply(invModelview, (Vector3){rayEye.x, rayEye.y, rayEye.z} ); - VectorNormalize(&rayWorld); + result.x = quat.x; + result.y = quat.y; + result.z = quat.z; - return rayWorld; -*/ - return (Vector3){ 0, 0, 0 }; + return result; } // Convert image data to OpenGL texture (returns OpenGL valid Id) @@ -1780,9 +1776,9 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma #endif // Magnification and minification filters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR + #if defined(GRAPHICS_API_OPENGL_33) if (mipmapCount > 1) { @@ -1883,9 +1879,10 @@ Model rlglLoadModel(VertexData mesh) model.shader.id = 0; // No shader used #elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - model.texture.id = whiteTexture; // Default whiteTexture - model.texture.width = 1; // Default whiteTexture width - model.texture.height = 1; // Default whiteTexture height + model.texture.id = whiteTexture; // Default whiteTexture + model.texture.width = 1; // Default whiteTexture width + model.texture.height = 1; // Default whiteTexture height + model.shader = simpleShader; // Default model shader GLuint vaoModel = 0; // Vertex Array Objects (VAO) GLuint vertexBuffer[3]; // Vertex Buffer Objects (VBO) @@ -1903,22 +1900,20 @@ Model rlglLoadModel(VertexData mesh) // Enable vertex attributes: position glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW); - glEnableVertexAttribArray(simpleShader.vertexLoc); - glVertexAttribPointer(simpleShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glVertexAttribPointer(model.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.shader.vertexLoc); // Enable vertex attributes: texcoords glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW); - glEnableVertexAttribArray(simpleShader.texcoordLoc); - glVertexAttribPointer(simpleShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glVertexAttribPointer(model.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.shader.texcoordLoc); // Enable vertex attributes: normals glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW); - glEnableVertexAttribArray(simpleShader.normalLoc); - glVertexAttribPointer(simpleShader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - - model.shader = simpleShader; // By default, simple shader will be used + glVertexAttribPointer(model.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.shader.normalLoc); model.mesh.vboId[0] = vertexBuffer[0]; // Vertex position VBO model.mesh.vboId[1] = vertexBuffer[1]; // Texcoords VBO @@ -1975,6 +1970,8 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) int width, height; + glBindTexture(GL_TEXTURE_2D, textureId); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); @@ -1995,15 +1992,13 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) case UNCOMPRESSED_R8G8B8A8: pixels = (unsigned char *)malloc(size*4); glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; break; // 32 bpp default: TraceLog(WARNING, "Texture format not suported"); break; } - - glBindTexture(GL_TEXTURE_2D, textureId); // NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding. // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting. // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.) // GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.) glPixelStorei(GL_PACK_ALIGNMENT, 1); - + glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels); glBindTexture(GL_TEXTURE_2D, 0); @@ -2027,39 +2022,54 @@ Shader LoadShader(char *vsFileName, char *fsFileName) // Shaders loading from external text file char *vShaderStr = TextFileRead(vsFileName); char *fShaderStr = TextFileRead(fsFileName); - - shader.id = LoadShaderProgram(vShaderStr, fShaderStr); - - if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Custom shader loaded successfully", shader.id); - else TraceLog(WARNING, "[SHDR ID %i] Custom shader could not be loaded", shader.id); - - // Shader strings must be freed - free(vShaderStr); - free(fShaderStr); - // Set shader textures ids (all 0 by default) - shader.texDiffuseId = 0; - shader.texNormalId = 0; - shader.texSpecularId = 0; - - // Get handles to GLSL input attibute locations - //------------------------------------------------------------------- - shader.vertexLoc = glGetAttribLocation(shader.id, "vertexPosition"); - shader.texcoordLoc = glGetAttribLocation(shader.id, "vertexTexCoord"); - shader.normalLoc = glGetAttribLocation(shader.id, "vertexNormal"); - // NOTE: custom shader does not use colorLoc - shader.colorLoc = -1; - - // Get handles to GLSL uniform locations (vertex shader) - shader.modelviewLoc = glGetUniformLocation(shader.id, "modelviewMatrix"); - shader.projectionLoc = glGetUniformLocation(shader.id, "projectionMatrix"); + if ((vShaderStr != NULL) && (fShaderStr != NULL)) + { + shader.id = LoadShaderProgram(vShaderStr, fShaderStr); - // Get handles to GLSL uniform locations (fragment shader) - shader.tintColorLoc = glGetUniformLocation(shader.id, "tintColor"); - shader.mapDiffuseLoc = glGetUniformLocation(shader.id, "texture0"); - shader.mapNormalLoc = -1; // It can be set later - shader.mapSpecularLoc = -1; // It can be set later - //-------------------------------------------------------------------- + if (shader.id != 0) + { + TraceLog(INFO, "[SHDR ID %i] Custom shader loaded successfully", shader.id); + + // Set shader textures ids (all 0 by default) + shader.texDiffuseId = 0; + shader.texNormalId = 0; + shader.texSpecularId = 0; + + // Get handles to GLSL input attibute locations + //------------------------------------------------------------------- + shader.vertexLoc = glGetAttribLocation(shader.id, "vertexPosition"); + shader.texcoordLoc = glGetAttribLocation(shader.id, "vertexTexCoord"); + shader.normalLoc = glGetAttribLocation(shader.id, "vertexNormal"); + // NOTE: custom shader does not use colorLoc + shader.colorLoc = -1; + + // Get handles to GLSL uniform locations (vertex shader) + shader.modelviewLoc = glGetUniformLocation(shader.id, "modelviewMatrix"); + shader.projectionLoc = glGetUniformLocation(shader.id, "projectionMatrix"); + + // Get handles to GLSL uniform locations (fragment shader) + shader.tintColorLoc = glGetUniformLocation(shader.id, "tintColor"); + shader.mapDiffuseLoc = glGetUniformLocation(shader.id, "texture0"); + shader.mapNormalLoc = -1; // It can be set later + shader.mapSpecularLoc = -1; // It can be set later + //-------------------------------------------------------------------- + } + else + { + TraceLog(WARNING, "Custom shader could not be loaded"); + shader = simpleShader; + } + + // Shader strings must be freed + free(vShaderStr); + free(fShaderStr); + } + else + { + TraceLog(WARNING, "Custom shader could not be loaded"); + shader = simpleShader; + } #endif return shader; @@ -2169,6 +2179,8 @@ unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) void UnloadShader(Shader shader) { rlDeleteShader(shader.id); + + TraceLog(INFO, "[SHDR ID %i] Unloaded shader program data", shader.id); } // Set custom shader to be used on batch draw @@ -2205,6 +2217,7 @@ void SetCustomShader(Shader shader) } // Set postprocessing shader +// NOTE: Uses global variables screenWidth and screenHeight void SetPostproShader(Shader shader) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -2218,8 +2231,8 @@ void SetPostproShader(Shader shader) Texture2D texture; texture.id = fboColorTexture; - texture.width = GetScreenWidth(); - texture.height = GetScreenHeight(); + texture.width = screenWidth; + texture.height = screenHeight; SetShaderMapDiffuse(&postproQuad.shader, texture); @@ -2236,9 +2249,12 @@ void SetDefaultShader(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) SetCustomShader(defaultShader); - SetPostproShader(defaultShader); - enabledPostpro = false; + if (enabledPostpro) + { + SetPostproShader(defaultShader); + enabledPostpro = false; + } #endif } @@ -2267,7 +2283,8 @@ void SetModelShader(Model *model, Shader shader) if (vaoSupported) glBindVertexArray(0); // Unbind VAO - //if (model->texture.id > 0) model->shader.texDiffuseId = model->texture.id; + // NOTE: If SetModelTexture() is called previously, texture is not assigned to new shader + if (model->texture.id > 0) model->shader.texDiffuseId = model->texture.id; #endif } @@ -2423,6 +2440,26 @@ void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textur */ } +// Set blending mode (alpha, additive, multiplied) +// NOTE: Only 3 blending modes predefined +void SetBlendMode(int mode) +{ + if ((blendMode != mode) && (mode < 3)) + { + rlglDraw(); + + switch (mode) + { + case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; + case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; // Alternative: glBlendFunc(GL_ONE, GL_ONE); + case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; + default: break; + } + + blendMode = mode; + } +} + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) void PrintProjectionMatrix(void) { @@ -3026,7 +3063,7 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; // Output a trace log message // NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning -void TraceLog(int msgType, const char *text, ...) +static void TraceLog(int msgType, const char *text, ...) { va_list args; va_start(args, text); @@ -7,7 +7,7 @@ * OpenGL 3.3+ - Vertex data is stored in VAOs, call rlglDraw() to render * OpenGL ES 2 - Vertex data is stored in VBOs or VAOs (when available), call rlglDraw() to render * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. @@ -36,6 +36,10 @@ #include "utils.h" // Required for function TraceLog() #endif +#if defined(RLGL_STANDALONE) + #define RAYMATH_STANDALONE +#endif + #include "raymath.h" // Required for data type Matrix and Matrix functions // Select desired OpenGL version @@ -89,9 +93,26 @@ typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode; typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; #ifdef RLGL_STANDALONE + #ifndef __cplusplus + // Boolean type + typedef enum { false, true } bool; + #endif + + // byte type + typedef unsigned char byte; + + // Color type, RGBA (32bit) + typedef struct Color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } Color; + // Texture formats (support depends on OpenGL version) typedef enum { UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) + UNCOMPRESSED_GRAY_ALPHA, UNCOMPRESSED_R5G6B5, // 16 bpp UNCOMPRESSED_R8G8B8, // 24 bpp UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) @@ -106,7 +127,8 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; 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; // VertexData type @@ -123,21 +145,36 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; // Shader type typedef struct Shader { - unsigned int id; // Shader program id + unsigned int id; // Shader program id + // TODO: This should be Texture2D objects + unsigned int texDiffuseId; // Diffuse texture id + unsigned int texNormalId; // Normal texture id + unsigned int texSpecularId; // Specular texture id + // Variable attributes - unsigned int vertexLoc; // Vertex attribute location point (vertex shader) - unsigned int texcoordLoc; // Texcoord attribute location point (vertex shader) - unsigned int normalLoc; // Normal attribute location point (vertex shader) - unsigned int colorLoc; // Color attibute location point (vertex shader) + int vertexLoc; // Vertex attribute location point (vertex shader) + int texcoordLoc; // Texcoord attribute location point (vertex shader) + int normalLoc; // Normal attribute location point (vertex shader) + int colorLoc; // Color attibute location point (vertex shader) // Uniforms - unsigned int projectionLoc; // Projection matrix uniform location point (vertex shader) - unsigned int modelviewLoc; // ModeView matrix uniform location point (vertex shader) - unsigned int textureLoc; // Texture uniform location point (fragment shader) - unsigned int tintColorLoc; // Color uniform location point (fragment shader) + int projectionLoc; // Projection matrix uniform location point (vertex shader) + int modelviewLoc; // ModeView matrix uniform location point (vertex shader) + int tintColorLoc; // Color uniform location point (fragment shader) + + int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader) + int mapNormalLoc; // Normal map texture uniform location point (fragment shader) + int mapSpecularLoc; // Specular map texture uniform location point (fragment shader) } Shader; + // Texture2D type + typedef struct Texture2D { + unsigned int id; // Texture id + int width; + int height; + } Texture2D; + // 3d Model type typedef struct Model { VertexData mesh; @@ -145,13 +182,9 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; Texture2D texture; Shader shader; } Model; - - // Texture2D type - typedef struct Texture2D { - unsigned int id; // Texture id - int width; - int height; - } Texture2D; + + // Color blending modes (pre-defined) + typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; #endif #ifdef __cplusplus @@ -231,6 +264,31 @@ void PrintProjectionMatrix(void); // DEBUG: Print projection matrix void PrintModelviewMatrix(void); // DEBUG: Print modelview matrix #endif +#if defined(RLGL_STANDALONE) +//------------------------------------------------------------------------------------ +// Shaders System Functions (Module: rlgl) +// NOTE: This functions are useless when using OpenGL 1.1 +//------------------------------------------------------------------------------------ +Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations +unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load a custom shader and return program id +void UnloadShader(Shader shader); // Unload a custom shader from memory +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 +void SetModelShader(Model *model, Shader shader); // Link a shader to a model +bool IsPosproShaderEnabled(void); // Check if postprocessing shader is enabled + +int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location +void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) +void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) +void SetShaderMapDiffuse(Shader *shader, Texture2D texture); // Default diffuse shader map texture assignment +void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture); // Normal map texture shader assignment +void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture); // Specular map texture shader assignment +void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textureUnit); // TODO: Generic shader map assignment + +void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) +#endif + #ifdef __cplusplus } #endif diff --git a/src/shapes.c b/src/shapes.c index 6e6c9dd7..071fa63c 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -4,7 +4,7 @@ * * Basic functions to draw 2d Shapes and check collisions * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. @@ -4,7 +4,7 @@ * * Basic functions to load SpriteFonts and draw Text * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. @@ -216,6 +216,8 @@ extern void UnloadDefaultFont(void) { UnloadTexture(defaultFont.texture); free(defaultFont.charSet); + + TraceLog(INFO, "Unloaded default font data"); } // Get the default font, useful to be used with extended parameters @@ -266,6 +268,8 @@ void UnloadSpriteFont(SpriteFont spriteFont) { UnloadTexture(spriteFont.texture); free(spriteFont.charSet); + + TraceLog(INFO, "Unloaded sprite font data"); } // Draw text (using default font) diff --git a/src/textures.c b/src/textures.c index b7ab1f7e..69456701 100644 --- a/src/textures.c +++ b/src/textures.c @@ -8,7 +8,7 @@ * stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) * NOTE: stb_image has been slightly modified, original library: https://github.com/nothings/stb * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. @@ -330,7 +330,6 @@ Texture2D LoadTexture(const char *fileName) else { TraceLog(WARNING, "Texture could not be created"); - texture.id = 0; } @@ -390,12 +389,17 @@ Texture2D LoadTextureFromImage(Image image) void UnloadImage(Image image) { free(image.data); + + // NOTE: It becomes anoying every time a texture is loaded + //TraceLog(INFO, "Unloaded image data"); } // Unload texture from GPU memory void UnloadTexture(Texture2D texture) { rlDeleteTextures(texture.id); + + TraceLog(INFO, "[TEX ID %i] Unloaded texture data", texture.id); } // Get pixel data from image in the form of Color struct array @@ -486,20 +490,28 @@ Color *GetImageData(Image image) } // Get pixel data from GPU texture and return an Image +// NOTE: Compressed texture formats not supported Image GetTextureData(Texture2D texture) { Image image; + image.data = NULL; - image.data = rlglReadTexturePixels(texture.id, texture.format); - - if (image.data != NULL) + if (texture.format < 8) { - image.width = texture.width; - image.height = texture.height; - image.format = texture.format; - image.mipmaps = 1; + image.data = rlglReadTexturePixels(texture.id, texture.format); + + if (image.data != NULL) + { + image.width = texture.width; + image.height = texture.height; + image.format = texture.format; + image.mipmaps = 1; + + TraceLog(INFO, "Texture pixel data obtained successfully"); + } + else TraceLog(WARNING, "Texture pixel data could not be obtained"); } - else TraceLog(WARNING, "Texture pixel data could not be obtained"); + else TraceLog(WARNING, "Compressed texture data could not be obtained"); return image; } @@ -507,136 +519,139 @@ Image GetTextureData(Texture2D texture) // Convert image data to desired format void ImageConvertFormat(Image *image, int newFormat) { - if ((image->format != newFormat) && (image->format < 8) && (newFormat < 8)) + if (image->format != newFormat) { - Color *pixels = GetImageData(*image); - - free(image->data); - - image->format = newFormat; - - int k = 0; - - switch (image->format) + if ((image->format < 8) && (newFormat < 8)) { - case UNCOMPRESSED_GRAYSCALE: + Color *pixels = GetImageData(*image); + + free(image->data); + + image->format = newFormat; + + int k = 0; + + switch (image->format) { - image->data = (unsigned char *)malloc(image->width*image->height*sizeof(unsigned char)); - - for (int i = 0; i < image->width*image->height; i++) + case UNCOMPRESSED_GRAYSCALE: { - ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f); - k++; - } - - } break; - case UNCOMPRESSED_GRAY_ALPHA: - { - image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); - - for (int i = 0; i < image->width*image->height*2; i += 2) + image->data = (unsigned char *)malloc(image->width*image->height*sizeof(unsigned char)); + + for (int i = 0; i < image->width*image->height; i++) + { + ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f); + k++; + } + + } break; + case UNCOMPRESSED_GRAY_ALPHA: { - ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f); - ((unsigned char *)image->data)[i + 1] = pixels[k].a; - k++; - } + image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); + + for (int i = 0; i < image->width*image->height*2; i += 2) + { + ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f); + ((unsigned char *)image->data)[i + 1] = pixels[k].a; + k++; + } - } break; - case UNCOMPRESSED_R5G6B5: - { - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - - unsigned char r; - unsigned char g; - unsigned char b; - - for (int i = 0; i < image->width*image->height; i++) + } break; + case UNCOMPRESSED_R5G6B5: { - r = (unsigned char)(round((float)pixels[k].r*31/255)); - g = (unsigned char)(round((float)pixels[k].g*63/255)); - b = (unsigned char)(round((float)pixels[k].b*31/255)); + image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b; + unsigned char r; + unsigned char g; + unsigned char b; + + for (int i = 0; i < image->width*image->height; i++) + { + r = (unsigned char)(round((float)pixels[k].r*31/255)); + g = (unsigned char)(round((float)pixels[k].g*63/255)); + b = (unsigned char)(round((float)pixels[k].b*31/255)); + + ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b; - k++; - } + k++; + } - } break; - case UNCOMPRESSED_R8G8B8: - { - image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char)); - - for (int i = 0; i < image->width*image->height*3; i += 3) + } break; + case UNCOMPRESSED_R8G8B8: { - ((unsigned char *)image->data)[i] = pixels[k].r; - ((unsigned char *)image->data)[i + 1] = pixels[k].g; - ((unsigned char *)image->data)[i + 2] = pixels[k].b; - k++; - } - } break; - case UNCOMPRESSED_R5G5B5A1: - { - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a = 1; - - for (int i = 0; i < image->width*image->height; i++) + image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char)); + + for (int i = 0; i < image->width*image->height*3; i += 3) + { + ((unsigned char *)image->data)[i] = pixels[k].r; + ((unsigned char *)image->data)[i + 1] = pixels[k].g; + ((unsigned char *)image->data)[i + 2] = pixels[k].b; + k++; + } + } break; + case UNCOMPRESSED_R5G5B5A1: { - r = (unsigned char)(round((float)pixels[k].r*31/255)); - g = (unsigned char)(round((float)pixels[k].g*31/255)); - b = (unsigned char)(round((float)pixels[k].b*31/255)); - a = (pixels[k].a > 50) ? 1 : 0; + image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); + + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a = 1; - ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1| (unsigned short)a; + for (int i = 0; i < image->width*image->height; i++) + { + r = (unsigned char)(round((float)pixels[k].r*31/255)); + g = (unsigned char)(round((float)pixels[k].g*31/255)); + b = (unsigned char)(round((float)pixels[k].b*31/255)); + a = (pixels[k].a > 50) ? 1 : 0; + + ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1| (unsigned short)a; - k++; - } + k++; + } - } break; - case UNCOMPRESSED_R4G4B4A4: - { - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; - - for (int i = 0; i < image->width*image->height; i++) + } break; + case UNCOMPRESSED_R4G4B4A4: { - r = (unsigned char)(round((float)pixels[k].r*15/255)); - g = (unsigned char)(round((float)pixels[k].g*15/255)); - b = (unsigned char)(round((float)pixels[k].b*15/255)); - a = (unsigned char)(round((float)pixels[k].a*15/255)); + image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8| (unsigned short)b << 4| (unsigned short)a; + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + + for (int i = 0; i < image->width*image->height; i++) + { + r = (unsigned char)(round((float)pixels[k].r*15/255)); + g = (unsigned char)(round((float)pixels[k].g*15/255)); + b = (unsigned char)(round((float)pixels[k].b*15/255)); + a = (unsigned char)(round((float)pixels[k].a*15/255)); + + ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8| (unsigned short)b << 4| (unsigned short)a; - k++; - } - - } break; - case UNCOMPRESSED_R8G8B8A8: - { - image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char)); - - for (int i = 0; i < image->width*image->height*4; i += 4) + k++; + } + + } break; + case UNCOMPRESSED_R8G8B8A8: { - ((unsigned char *)image->data)[i] = pixels[k].r; - ((unsigned char *)image->data)[i + 1] = pixels[k].g; - ((unsigned char *)image->data)[i + 2] = pixels[k].b; - ((unsigned char *)image->data)[i + 3] = pixels[k].a; - k++; - } - } break; - default: break; + image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char)); + + for (int i = 0; i < image->width*image->height*4; i += 4) + { + ((unsigned char *)image->data)[i] = pixels[k].r; + ((unsigned char *)image->data)[i + 1] = pixels[k].g; + ((unsigned char *)image->data)[i + 2] = pixels[k].b; + ((unsigned char *)image->data)[i + 3] = pixels[k].a; + k++; + } + } break; + default: break; + } + + free(pixels); } - - free(pixels); + else TraceLog(WARNING, "Image data format is compressed, can not be converted"); } - else TraceLog(WARNING, "Image data format is compressed, can not be converted"); } @@ -644,8 +659,8 @@ void ImageConvertFormat(Image *image, int newFormat) // NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5) void ImageConvertToPOT(Image *image, Color fillColor) { - // TODO: Review for new image struct - /* + Color *pixels = GetImageData(*image); // Get pixels data + // Just add the required amount of pixels at the right and bottom sides of image... int potWidth = GetNextPOT(image->width); int potHeight = GetNextPOT(image->height); @@ -653,29 +668,33 @@ void ImageConvertToPOT(Image *image, Color fillColor) // Check if POT texture generation is required (if texture is not already POT) if ((potWidth != image->width) || (potHeight != image->height)) { - Color *imgDataPixelPOT = NULL; + Color *pixelsPOT = NULL; // Generate POT array from NPOT data - imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color)); + pixelsPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color)); for (int j = 0; j < potHeight; j++) { for (int i = 0; i < potWidth; i++) { - if ((j < image->height) && (i < image->width)) imgDataPixelPOT[j*potWidth + i] = image->data[j*image->width + i]; - else imgDataPixelPOT[j*potWidth + i] = fillColor; + if ((j < image->height) && (i < image->width)) pixelsPOT[j*potWidth + i] = pixels[j*image->width + i]; + else pixelsPOT[j*potWidth + i] = fillColor; } } TraceLog(WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); - free(image->pixels); + free(pixels); // Free pixels data + free(image->data); // Free old image data + + int format = image->format; // Store image data format to reconvert later + + *image = LoadImageEx(pixelsPOT, potWidth, potHeight); + + free(pixelsPOT); // Free POT pixels data - image->pixels = imgDataPixelPOT; - image->width = potWidth; - image->height = potHeight; + ImageConvertFormat(image, format); // Reconvert image to previous format } - */ } // Copy an image to a new image diff --git a/src/utils.c b/src/utils.c index 8e42e533..b8e8bc1a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -8,7 +8,7 @@ * tinfl - zlib DEFLATE algorithm decompression lib * stb_image_write - PNG writting functions * -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* Copyright (c) 2014 Ramon Santamaria (@raysan5) * * 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. |
