diff options
| author | Ray <raysan5@gmail.com> | 2016-11-15 18:00:02 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-11-15 18:00:02 +0100 |
| commit | 4123233f7873cf157c92f4990e56b83da47b9d7f (patch) | |
| tree | 95a52d661abc832c8c30095b2c4c661cf52ae30f /src | |
| parent | a9315fc422a3a036891f50f0c2be5059c3db8b31 (diff) | |
| parent | a3d71dd58d993d15d695b0cd58b434ef2604185b (diff) | |
| download | raylib-4123233f7873cf157c92f4990e56b83da47b9d7f.tar.gz raylib-4123233f7873cf157c92f4990e56b83da47b9d7f.zip | |
Merge pull request #192 from raysan5/develop
Integrate Develop branch
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio.c | 6 | ||||
| -rw-r--r-- | src/core.c | 317 | ||||
| -rw-r--r-- | src/external/openal_soft/lib/win32/libOpenAL32dll.a (renamed from src/external/openal_soft/lib/win32/libOpenAL32.dll.a) | bin | 100246 -> 100246 bytes | |||
| -rw-r--r-- | src/models.c | 144 | ||||
| -rw-r--r-- | src/raylib.h | 129 | ||||
| -rw-r--r-- | src/rlgl.c | 104 | ||||
| -rw-r--r-- | src/rlgl.h | 40 | ||||
| -rw-r--r-- | src/shapes.c | 37 | ||||
| -rw-r--r-- | src/text.c | 237 | ||||
| -rw-r--r-- | src/textures.c | 143 | ||||
| -rw-r--r-- | src/utils.c | 2 |
11 files changed, 747 insertions, 412 deletions
diff --git a/src/audio.c b/src/audio.c index 9d2eeb47..3684e10a 100644 --- a/src/audio.c +++ b/src/audio.c @@ -706,7 +706,7 @@ Music LoadMusicStream(const char *fileName) else { music->stream = InitAudioStream(music->ctxFlac->sampleRate, music->ctxFlac->bitsPerSample, music->ctxFlac->channels); - music->totalSamples = music->ctxFlac->totalSampleCount; + music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount; music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_FLAC; music->loop = true; // We loop by default @@ -853,7 +853,7 @@ void UpdateMusicStream(Music music) int pcmi[AUDIO_BUFFER_SIZE]; // NOTE: Returns the number of samples to process (should be the same as numSamples) - int numSamplesFlac = drflac_read_s32(music->ctxFlac, numSamples, pcmi); + unsigned int numSamplesFlac = (unsigned int)drflac_read_s32(music->ctxFlac, numSamples, pcmi); UpdateAudioStream(music->stream, pcmi, numSamplesFlac*music->stream.channels); music->samplesLeft -= (numSamples*music->stream.channels); @@ -1237,7 +1237,7 @@ static Wave LoadOGG(const char *fileName) 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); - int totalSamples = totalSeconds*info.sample_rate*info.channels; + int totalSamples = (int)(totalSeconds*info.sample_rate*info.channels); wave.sampleCount = totalSamples; wave.data = (short *)malloc(totalSamplesLength*sizeof(short)); @@ -22,7 +22,7 @@ * * RL_LOAD_DEFAULT_FONT - Use external module functions to load default raylib font (module: text) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 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. @@ -58,12 +58,12 @@ #endif #include <stdio.h> // Standard input / output lib -#include <stdlib.h> // Declares malloc() and free() for memory management, rand(), atexit() -#include <stdint.h> // Required for typedef unsigned long long int uint64_t, used by hi-res timer -#include <time.h> // Useful to initialize random seed - Android/RPI hi-res timer (NOTE: Linux only!) -#include <math.h> // Math related functions, tan() used to set perspective -#include <string.h> // String function definitions, memset() -#include <errno.h> // Macros for reporting and retrieving error conditions through error codes +#include <stdlib.h> // Required for: malloc(), free(), rand(), atexit() +#include <stdint.h> // Required for: typedef unsigned long long int uint64_t, used by hi-res timer +#include <time.h> // Required for: time() - Android/RPI hi-res timer (NOTE: Linux only!) +#include <math.h> // Required for: tan() [Used in Begin3dMode() to set perspective] +#include <string.h> // Required for: strcmp() +//#include <errno.h> // Macros for reporting and retrieving error conditions through error codes #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 @@ -79,8 +79,7 @@ #endif #if defined(PLATFORM_ANDROID) - #include <jni.h> // Java native interface - #include <android/sensor.h> // Android sensors functions + //#include <android/sensor.h> // Android sensors functions (accelerometer, gyroscope, light...) #include <android/window.h> // Defines AWINDOW_FLAG_FULLSCREEN and others #include <android_native_app_glue.h> // Defines basic app state struct and manages activity @@ -97,8 +96,8 @@ #include <sys/ioctl.h> // UNIX System call for device-specific input/output operations - ioctl() #include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition #include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...) - #include <linux/joystick.h> - + #include <linux/joystick.h> // Linux: Joystick support library + #include "bcm_host.h" // Raspberry Pi VideoCore IV access functions #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions @@ -131,7 +130,7 @@ #endif #define MAX_GAMEPADS 4 // Max number of gamepads supported -#define MAX_GAMEPAD_BUTTONS 11 // Max bumber of buttons supported (per gamepad) +#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) #define RL_LOAD_DEFAULT_FONT // Load default font on window initialization (module: text) @@ -158,9 +157,6 @@ static const char *internalDataPath; // Android internal data path to static bool windowReady = false; // Used to detect display initialization static bool appEnabled = true; // Used to detec if app is active static bool contextRebindRequired = false; // Used to know context rebind required - -static int previousButtonState[128] = { 1 }; // Required to check if button pressed/released once -static int currentButtonState[128] = { 1 }; // Required to check if button pressed/released once #endif #if defined(PLATFORM_RPI) @@ -179,6 +175,7 @@ static pthread_t mouseThreadId; // Mouse reading thread id // Gamepad input variables static int gamepadStream[MAX_GAMEPADS] = { -1 };// Gamepad device file descriptor static pthread_t gamepadThreadId; // Gamepad reading thread id +static char gamepadName[64]; // Gamepad name holder #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -202,10 +199,7 @@ static Matrix downscaleView; // Matrix to downscale view (in case #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) static const char *windowTitle; // Window text title... static bool cursorOnScreen = false; // Tracks if cursor is inside client area - -// Register keyboard states -static char previousKeyState[512] = { 0 }; // Registers previous frame key state -static char currentKeyState[512] = { 0 }; // Registers current frame key state +static bool cursorHidden = false; // Track if cursor is hidden // Register mouse states static char previousMouseState[3] = { 0 }; // Registers previous mouse button state @@ -216,16 +210,21 @@ static int currentMouseWheelY = 0; // Registers current mouse wheel var // Register gamepads states static bool gamepadReady[MAX_GAMEPADS] = { false }; // Flag to know if gamepad is ready static float gamepadAxisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state -static char previousGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS] = { 0 }; -static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS] = { 0 }; +static char previousGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state +static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state // Keyboard configuration static int exitKey = KEY_ESCAPE; // Default exit key (ESC) -static int lastKeyPressed = -1; // Register last key pressed - -static bool cursorHidden; // Track if cursor is hidden #endif +// Register keyboard states +static char previousKeyState[512] = { 0 }; // Registers previous frame key state +static char currentKeyState[512] = { 0 }; // Registers current frame key state + +static int lastKeyPressed = -1; // Register last key pressed +static int lastGamepadButtonPressed = -1; // Register last gamepad button pressed +static int gamepadAxisCount = 0; // Register number of available gamepad axis + static Vector2 mousePosition; // Mouse position on screen static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen @@ -363,7 +362,7 @@ void InitWindow(int width, int height, const char *title) #if defined(PLATFORM_ANDROID) // Android activity initialization -void InitWindow(int width, int height, struct android_app *state) +void InitWindow(int width, int height, void *state) { TraceLog(INFO, "Initializing raylib (v1.6.0)"); @@ -372,7 +371,7 @@ void InitWindow(int width, int height, struct android_app *state) screenWidth = width; screenHeight = height; - app = state; + app = (struct android_app *)state; internalDataPath = app->activity->internalDataPath; // Set desired windows flags before initializing anything @@ -466,6 +465,9 @@ void CloseWindow(void) // Wait for mouse and gamepad threads to finish before closing // NOTE: Those threads should already have finished at this point // because they are controlled by windowShouldClose variable + + windowShouldClose = true; // Added to force threads to exit when the close window is called + pthread_join(mouseThreadId, NULL); pthread_join(gamepadThreadId, NULL); #endif @@ -526,6 +528,65 @@ int GetScreenHeight(void) return screenHeight; } +#if !defined(PLATFORM_ANDROID) +// Show mouse cursor +void ShowCursor() +{ +#if defined(PLATFORM_DESKTOP) + #ifdef __linux + XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window)); + #else + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + #endif +#endif + cursorHidden = false; +} + +// Hide mouse cursor +void HideCursor() +{ +#if defined(PLATFORM_DESKTOP) + #ifdef __linux + XColor Col; + const char Nil[] = {0}; + + Pixmap Pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), Nil, 1, 1); + Cursor Cur = XCreatePixmapCursor(glfwGetX11Display(), Pix, Pix, &Col, &Col, 0, 0); + + XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), Cur); + XFreeCursor(glfwGetX11Display(), Cur); + #else + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + #endif +#endif + cursorHidden = true; +} + +// Check if mouse cursor is hidden +bool IsCursorHidden() +{ + return cursorHidden; +} + +// Enable mouse cursor +void EnableCursor() +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +#endif + cursorHidden = false; +} + +// Disable mouse cursor +void DisableCursor() +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); +#endif + cursorHidden = true; +} +#endif // !defined(PLATFORM_ANDROID) + // Sets Background Color void ClearBackground(Color color) { @@ -1044,7 +1105,6 @@ Matrix GetCameraMatrix(Camera camera) //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //---------------------------------------------------------------------------------- -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Detect if a key has been pressed once bool IsKeyPressed(int key) { @@ -1067,7 +1127,7 @@ bool IsKeyDown(int key) bool IsKeyReleased(int key) { bool released = false; - + if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true; else released = false; @@ -1091,64 +1151,9 @@ int GetKeyPressed(void) // NOTE: default exitKey is ESCAPE void SetExitKey(int key) { +#if !defined(PLATFORM_ANDROID) exitKey = key; -} - -// Hide mouse cursor -void HideCursor() -{ -#if defined(PLATFORM_DESKTOP) - #ifdef __linux - XColor Col; - const char Nil[] = {0}; - - Pixmap Pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), Nil, 1, 1); - Cursor Cur = XCreatePixmapCursor(glfwGetX11Display(), Pix, Pix, &Col, &Col, 0, 0); - - XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), Cur); - XFreeCursor(glfwGetX11Display(), Cur); - #else - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - #endif #endif - cursorHidden = true; -} - -// Show mouse cursor -void ShowCursor() -{ -#if defined(PLATFORM_DESKTOP) - #ifdef __linux - XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window)); - #else - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - #endif -#endif - cursorHidden = false; -} - -// Disable mouse cursor -void DisableCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); -#endif - cursorHidden = true; -} - -// Enable mouse cursor -void EnableCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); -#endif - cursorHidden = false; -} - -// Check if mouse cursor is hidden -bool IsCursorHidden() -{ - return cursorHidden; } // NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) @@ -1157,32 +1162,61 @@ bool IsCursorHidden() bool IsGamepadAvailable(int gamepad) { bool result = false; - + +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) result = true; +#endif return result; } +// Check gamepad name (if available) +bool IsGamepadName(int gamepad, const char *name) +{ + bool result = false; + const char *gamepadName = NULL; + + if (gamepadReady[gamepad]) gamepadName = GetGamepadName(gamepad); + + if ((name != NULL) && (gamepadName != NULL)) result = (strcmp(name, gamepadName) == 0); + + return result; +} + // Return gamepad internal name id const char *GetGamepadName(int gamepad) { #if defined(PLATFORM_DESKTOP) - if (glfwJoystickPresent(gamepad) == 1) return glfwGetJoystickName(gamepad); + if (gamepadReady[gamepad]) return glfwGetJoystickName(gamepad); else return NULL; +#elif defined(PLATFORM_RPI) + if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGNAME(64), &gamepadName); + + return gamepadName; #else return NULL; #endif } +// Return gamepad axis count +int GetGamepadAxisCount(int gamepad) +{ +#if defined(PLATFORM_RPI) + int axisCount = 0; + if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGAXES, &axisCount); + gamepadAxisCount = axisCount; +#endif + return gamepadAxisCount; +} + // Return axis movement vector for a gamepad float GetGamepadAxisMovement(int gamepad, int axis) { float value = 0; - - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (axis < MAX_GAMEPAD_AXIS)) - { - value = gamepadAxisState[gamepad][axis]; - } + +#if !defined(PLATFORM_ANDROID) + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (axis < MAX_GAMEPAD_AXIS)) value = gamepadAxisState[gamepad][axis]; +#endif return value; } @@ -1191,10 +1225,12 @@ float GetGamepadAxisMovement(int gamepad, int axis) bool IsGamepadButtonPressed(int gamepad, int button) { bool pressed = false; - + +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && (currentGamepadState[gamepad][button] == 1)) pressed = true; +#endif return pressed; } @@ -1204,8 +1240,10 @@ bool IsGamepadButtonDown(int gamepad, int button) { bool result = false; - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && +#if !defined(PLATFORM_ANDROID) + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] == 1)) result = true; +#endif return result; } @@ -1215,9 +1253,11 @@ bool IsGamepadButtonReleased(int gamepad, int button) { bool released = false; +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && (currentGamepadState[gamepad][button] == 0)) released = true; +#endif return released; } @@ -1227,13 +1267,19 @@ bool IsGamepadButtonUp(int gamepad, int button) { bool result = false; +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] == 0)) result = true; +#endif return result; } -#endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) +// Get the last gamepad button pressed +int GetGamepadButtonPressed(void) +{ + return lastGamepadButtonPressed; +} // Detect if a mouse button has been pressed once bool IsMouseButtonPressed(int button) @@ -1387,37 +1433,6 @@ Vector2 GetTouchPosition(int index) return position; } -#if defined(PLATFORM_ANDROID) -// Detect if a button has been pressed once -bool IsButtonPressed(int button) -{ - bool pressed = false; - - if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 0)) pressed = true; - else pressed = false; - - return pressed; -} - -// Detect if a button is being pressed (button held down) -bool IsButtonDown(int button) -{ - if (currentButtonState[button] == 0) return true; - else return false; -} - -// Detect if a button has been released once -bool IsButtonReleased(int button) -{ - bool released = false; - - if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 1)) released = true; - else released = false; - - return released; -} -#endif - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -1900,8 +1915,9 @@ static bool GetKeyStatus(int key) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetKey(window, key); #elif defined(PLATFORM_ANDROID) - // TODO: Check for virtual keyboard - return false; + // NOTE: Android supports up to 260 keys + if (key < 0 || key > 260) return false; + else return currentKeyState[key]; #elif defined(PLATFORM_RPI) // NOTE: Keys states are filled in PollInputEvents() if (key < 0 || key > 511) return false; @@ -1929,6 +1945,15 @@ static void PollInputEvents(void) // NOTE: Gestures update must be called every frame to reset gestures correctly // because ProcessGestureEvent() is just called on an event, not every frame UpdateGestures(); + + // Reset last key pressed registered + lastKeyPressed = -1; + +#if !defined(PLATFORM_RPI) + // Reset last gamepad button/axis registered state + lastGamepadButtonPressed = -1; + gamepadAxisCount = 0; +#endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -1939,9 +1964,8 @@ static void PollInputEvents(void) mousePosition.x = (float)mouseX; mousePosition.y = (float)mouseY; - + // Keyboard input polling (automatically managed by GLFW3 through callback) - lastKeyPressed = -1; // Register previous keys states for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i]; @@ -1952,13 +1976,19 @@ static void PollInputEvents(void) previousMouseWheelY = currentMouseWheelY; currentMouseWheelY = 0; + // Check if gamepads are ready + // NOTE: We do it here in case of disconection + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (glfwJoystickPresent(i)) gamepadReady[i] = true; + else gamepadReady[i] = false; + } + // Register gamepads buttons events for (int i = 0; i < MAX_GAMEPADS; i++) { - if (glfwJoystickPresent(i)) // Check if gamepad is available + if (gamepadReady[i]) // Check if gamepad is available { - gamepadReady[i] = true; - // Register previous gamepad states for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k]; @@ -1971,7 +2001,11 @@ static void PollInputEvents(void) for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++) { - if (buttons[i] == GLFW_PRESS) currentGamepadState[i][k] = 1; + if (buttons[k] == GLFW_PRESS) + { + currentGamepadState[i][k] = 1; + lastGamepadButtonPressed = k; + } else currentGamepadState[i][k] = 0; } @@ -1985,8 +2019,9 @@ static void PollInputEvents(void) { gamepadAxisState[i][k] = axes[k]; } + + gamepadAxisCount = axisCount; } - else gamepadReady[i] = false; } glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events! @@ -1994,7 +2029,8 @@ static void PollInputEvents(void) #if defined(PLATFORM_ANDROID) // Register previous keys states - for (int i = 0; i < 128; i++) previousButtonState[i] = currentButtonState[i]; + // NOTE: Android supports up to 260 keys + for (int i = 0; i < 260; i++) previousKeyState[i] = currentKeyState[i]; // Poll Events (registered events) // NOTE: Activity is paused if not enabled (appEnabled) @@ -2371,7 +2407,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) //int32_t AKeyEvent_getMetaState(event); // Save current button and its state - currentButtonState[keycode] = AKeyEvent_getAction(event); // Down = 0, Up = 1 + // NOTE: Android key action is 0 for down and 1 for up + if (AKeyEvent_getAction(event) == 0) + { + currentKeyState[keycode] = 1; // Key down + lastKeyPressed = keycode; + } + else currentKeyState[keycode] = 0; // Key up if (keycode == AKEYCODE_POWER) { @@ -2818,6 +2860,9 @@ static void *GamepadThread(void *arg) { // 1 - button pressed, 0 - button released currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value; + + if ((int)gamepadEvent.value == 1) lastGamepadButtonPressed = gamepadEvent.number; + else lastGamepadButtonPressed = -1; } } else if (gamepadEvent.type == JS_EVENT_AXIS) diff --git a/src/external/openal_soft/lib/win32/libOpenAL32.dll.a b/src/external/openal_soft/lib/win32/libOpenAL32dll.a Binary files differindex 1c4c63c8..1c4c63c8 100644 --- a/src/external/openal_soft/lib/win32/libOpenAL32.dll.a +++ b/src/external/openal_soft/lib/win32/libOpenAL32dll.a diff --git a/src/models.c b/src/models.c index 822da6e9..b7e36b8a 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 (@raysan5) +* Copyright (c) 2014-2016 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. @@ -87,8 +87,8 @@ void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rot { rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex3f(sin(DEG2RAD*i)*radius, cos(DEG2RAD*i)*radius, 0.0f); - rlVertex3f(sin(DEG2RAD*(i + 10))*radius, cos(DEG2RAD*(i + 10))*radius, 0.0f); + rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f); + rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f); } rlEnd(); rlPopMatrix(); @@ -325,25 +325,25 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color { for (int j = 0; j < slices; j++) { - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*(j*360/slices))); - - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); + + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); } } rlEnd(); @@ -364,26 +364,26 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col { for (int j = 0; j < slices; j++) { - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); - - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*(j*360/slices))); - - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); + + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); + + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); } } rlEnd(); @@ -407,21 +407,21 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h // Draw Body ------------------------------------------------------------------------------------- for (int i = 0; i < 360; i += 360/sides) { - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); //Bottom Left - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); //Bottom Right - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); //Top Right + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); //Bottom Right + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); //Top Right - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); //Top Left - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); //Bottom Left - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); //Top Right + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); //Top Left + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); //Top Right } // Draw Cap -------------------------------------------------------------------------------------- for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, height, 0); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); } } else @@ -430,8 +430,8 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, height, 0); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); } } @@ -439,8 +439,8 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, 0, 0); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); } rlEnd(); rlPopMatrix(); @@ -460,17 +460,17 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl for (int i = 0; i < 360; i += 360/sides) { - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); } rlEnd(); rlPopMatrix(); @@ -1411,7 +1411,7 @@ bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, floa float dy = centerA.y - centerB.y; // Y distance between centers float dz = centerA.z - centerB.z; // Y distance between centers - float distance = sqrt(dx*dx + dy*dy + dz*dz); // Distance between centers + float distance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance between centers if (distance <= (radiusA + radiusB)) collision = true; @@ -1441,14 +1441,14 @@ bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radius float dmin = 0; - if (centerSphere.x < box.min.x) dmin += pow(centerSphere.x - box.min.x, 2); - else if (centerSphere.x > box.max.x) dmin += pow(centerSphere.x - box.max.x, 2); + if (centerSphere.x < box.min.x) dmin += powf(centerSphere.x - box.min.x, 2); + else if (centerSphere.x > box.max.x) dmin += powf(centerSphere.x - box.max.x, 2); - if (centerSphere.y < box.min.y) dmin += pow(centerSphere.y - box.min.y, 2); - else if (centerSphere.y > box.max.y) dmin += pow(centerSphere.y - box.max.y, 2); + if (centerSphere.y < box.min.y) dmin += powf(centerSphere.y - box.min.y, 2); + else if (centerSphere.y > box.max.y) dmin += powf(centerSphere.y - box.max.y, 2); - if (centerSphere.z < box.min.z) dmin += pow(centerSphere.z - box.min.z, 2); - else if (centerSphere.z > box.max.z) dmin += pow(centerSphere.z - box.max.z, 2); + if (centerSphere.z < box.min.z) dmin += powf(centerSphere.z - box.min.z, 2); + else if (centerSphere.z > box.max.z) dmin += powf(centerSphere.z - box.max.z, 2); if (dmin <= (radiusSphere*radiusSphere)) collision = true; @@ -1487,8 +1487,8 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi float collisionDistance = 0; // Check if ray origin is inside the sphere to calculate the correct collision point - if (distance < sphereRadius) collisionDistance = vector + sqrt(d); - else collisionDistance = vector - sqrt(d); + if (distance < sphereRadius) collisionDistance = vector + sqrtf(d); + else collisionDistance = vector - sqrtf(d); VectorScale(&offset, collisionDistance); Vector3 cPoint = VectorAdd(ray.position, offset); @@ -1811,7 +1811,7 @@ static Material LoadMTL(const char *fileName) char buffer[MAX_BUFFER_SIZE]; Vector3 color = { 1.0f, 1.0f, 1.0f }; - char *mapFileName = NULL; + char mapFileName[128]; FILE *mtlFile; diff --git a/src/raylib.h b/src/raylib.h index 5834d1c9..f6243304 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -77,10 +77,6 @@ #define PLATFORM_DESKTOP #endif -#if defined(PLATFORM_ANDROID) - typedef struct android_app; // Define android_app struct (android_native_app_glue.h) -#endif - #if defined(_WIN32) && defined(BUILDING_DLL) #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 DLL #elif defined(_WIN32) && defined(RAYLIB_DLL) @@ -93,7 +89,7 @@ // Some basic Defines //---------------------------------------------------------------------------------- #ifndef PI - #define PI 3.14159265358979323846 + #define PI 3.14159265358979323846f #endif #define DEG2RAD (PI/180.0f) @@ -174,6 +170,14 @@ #define KEY_Y 89 #define KEY_Z 90 +#if defined(PLATFORM_ANDROID) + // Android Physical Buttons + #define KEY_BACK 4 + #define KEY_MENU 82 + #define KEY_VOLUME_UP 24 + #define KEY_VOLUME_DOWN 25 +#endif + // Mouse Buttons #define MOUSE_LEFT_BUTTON 0 #define MOUSE_RIGHT_BUTTON 1 @@ -188,21 +192,32 @@ #define GAMEPAD_PLAYER3 2 #define GAMEPAD_PLAYER4 3 -// Gamepad Buttons +// Gamepad Buttons/Axis -// PS3 USB Controller -#define GAMEPAD_PS3_BUTTON_A 2 -#define GAMEPAD_PS3_BUTTON_B 1 -#define GAMEPAD_PS3_BUTTON_X 3 -#define GAMEPAD_PS3_BUTTON_Y 4 +// PS3 USB Controller Buttons +#define GAMEPAD_PS3_BUTTON_TRIANGLE 0 +#define GAMEPAD_PS3_BUTTON_CIRCLE 1 +#define GAMEPAD_PS3_BUTTON_CROSS 2 +#define GAMEPAD_PS3_BUTTON_SQUARE 3 +#define GAMEPAD_PS3_BUTTON_L1 6 #define GAMEPAD_PS3_BUTTON_R1 7 +#define GAMEPAD_PS3_BUTTON_L2 4 #define GAMEPAD_PS3_BUTTON_R2 5 -#define GAMEPAD_PS3_BUTTON_L1 6 -#define GAMEPAD_PS3_BUTTON_L2 8 +#define GAMEPAD_PS3_BUTTON_START 8 #define GAMEPAD_PS3_BUTTON_SELECT 9 -#define GAMEPAD_PS3_BUTTON_START 10 - -// TODO: Add PS3 d-pad axis +#define GAMEPAD_PS3_BUTTON_UP 24 +#define GAMEPAD_PS3_BUTTON_RIGHT 25 +#define GAMEPAD_PS3_BUTTON_DOWN 26 +#define GAMEPAD_PS3_BUTTON_LEFT 27 +#define GAMEPAD_PS3_BUTTON_PS 12 + +// PS3 USB Controller Axis +#define GAMEPAD_PS3_AXIS_LEFT_X 0 +#define GAMEPAD_PS3_AXIS_LEFT_Y 1 +#define GAMEPAD_PS3_AXIS_RIGHT_X 2 +#define GAMEPAD_PS3_AXIS_RIGHT_Y 5 +#define GAMEPAD_PS3_AXIS_L2 3 // [1..-1] (pressure-level) +#define GAMEPAD_PS3_AXIS_R2 4 // [1..-1] (pressure-level) // Xbox360 USB Controller Buttons #define GAMEPAD_XBOX_BUTTON_A 0 @@ -213,33 +228,30 @@ #define GAMEPAD_XBOX_BUTTON_RB 5 #define GAMEPAD_XBOX_BUTTON_SELECT 6 #define GAMEPAD_XBOX_BUTTON_START 7 - +#define GAMEPAD_XBOX_BUTTON_UP 10 +#define GAMEPAD_XBOX_BUTTON_RIGHT 11 +#define GAMEPAD_XBOX_BUTTON_DOWN 12 +#define GAMEPAD_XBOX_BUTTON_LEFT 13 +#define GAMEPAD_XBOX_BUTTON_HOME 8 + +// Xbox360 USB Controller Axis +// NOTE: For Raspberry Pi, axis must be reconfigured #if defined(PLATFORM_RPI) - #define GAMEPAD_XBOX_AXIS_DPAD_X 7 - #define GAMEPAD_XBOX_AXIS_DPAD_Y 6 - #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 - #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 - #define GAMEPAD_XBOX_AXIS_LT 2 - #define GAMEPAD_XBOX_AXIS_RT 5 + #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [-1..1] (up->down) + #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 // [-1..1] (up->down) + #define GAMEPAD_XBOX_AXIS_LT 2 // [-1..1] (pressure-level) + #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) #else - #define GAMEPAD_XBOX_BUTTON_UP 10 - #define GAMEPAD_XBOX_BUTTON_DOWN 12 - #define GAMEPAD_XBOX_BUTTON_LEFT 13 - #define GAMEPAD_XBOX_BUTTON_RIGHT 11 - #define GAMEPAD_XBOX_AXIS_RIGHT_X 4 - #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 - #define GAMEPAD_XBOX_AXIS_LT_RT 2 + #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down) + #define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down) + #define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level) + #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) #endif -#define GAMEPAD_XBOX_AXIS_LEFT_X 0 -#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 - -// Android Physic Buttons -#define ANDROID_BACK 4 -#define ANDROID_MENU 82 -#define ANDROID_VOLUME_UP 24 -#define ANDROID_VOLUME_DOWN 25 - // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. #ifdef __cplusplus @@ -535,6 +547,21 @@ typedef enum { COMPRESSED_ASTC_8x8_RGBA // 2 bpp } TextureFormat; +// Texture parameters: filter mode +// NOTE 1: Filtering considers mipmaps if available in the texture +// NOTE 2: Filter is accordingly set for minification and magnification +typedef enum { + FILTER_POINT = 0, // No filter, just pixel aproximation + FILTER_BILINEAR, // Linear filtering + FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x +} TextureFilterMode; + +// Texture parameters: wrap mode +typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; + // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; @@ -589,7 +616,7 @@ extern "C" { // Prevents name mangling of functions // Window and Graphics Device Functions (Module: core) //------------------------------------------------------------------------------------ #if defined(PLATFORM_ANDROID) -RLAPI void InitWindow(int width, int height, struct android_app *state); // Init Android Activity and OpenGL Graphics +RLAPI void InitWindow(int width, int height, void *state); // Init Android Activity and OpenGL Graphics (struct android_app) #elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics #endif @@ -601,11 +628,13 @@ RLAPI void ToggleFullscreen(void); // Fullscreen RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height +#if !defined(PLATFORM_ANDROID) RLAPI void ShowCursor(void); // Shows cursor RLAPI void HideCursor(void); // Hides cursor RLAPI bool IsCursorHidden(void); // Returns true if cursor is not visible RLAPI void EnableCursor(void); // Enables cursor RLAPI void DisableCursor(void); // Disables cursor +#endif RLAPI void ClearBackground(Color color); // Sets Background Color RLAPI void BeginDrawing(void); // Setup drawing canvas to start drawing @@ -648,7 +677,6 @@ RLAPI int StorageLoadValue(int position); // Storage loa //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) //------------------------------------------------------------------------------------ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI bool IsKeyPressed(int key); // Detect if a key has been pressed once RLAPI bool IsKeyDown(int key); // Detect if a key is being pressed RLAPI bool IsKeyReleased(int key); // Detect if a key has been released once @@ -657,13 +685,15 @@ RLAPI int GetKeyPressed(void); // Get latest key RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available +RLAPI bool IsGamepadName(int gamepad, const char *name); // Check gamepad name (if available) RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id -RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed -#endif +RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed +RLAPI int GetGamepadAxisCount(int gamepad); // Return gamepad axis count for a gamepad +RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed @@ -679,12 +709,6 @@ RLAPI int GetTouchX(void); // Returns touch p RLAPI int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) RLAPI Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) -#if defined(PLATFORM_ANDROID) -bool IsButtonPressed(int button); // Detect if an android physic button has been pressed -bool IsButtonDown(int button); // Detect if an android physic button is being pressed -bool IsButtonReleased(int button); // Detect if an android physic button has been released -#endif - //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ @@ -758,6 +782,7 @@ RLAPI void UnloadTexture(Texture2D texture); RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image +RLAPI void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image @@ -779,7 +804,8 @@ RLAPI void ImageColorGrayscale(Image *image); RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) RLAPI void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture -RLAPI void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data +RLAPI void SetTextureFilter(Texture2D texture, int filterMode); // Set texture scaling filter mode +RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); // Set texture wrapping mode RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 @@ -793,13 +819,14 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest //------------------------------------------------------------------------------------ RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory +RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load a SpriteFont from TTF font with parameters RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) RLAPI void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters float fontSize, int spacing, Color tint); RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font -RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing); // Measure string size for SpriteFont +RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing); // Measure string size for SpriteFont RLAPI void DrawFPS(int posX, int posY); // Shows current FPS on top-left corner RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' @@ -35,7 +35,7 @@ #include <math.h> // Required for: atan2() #ifndef RLGL_STANDALONE - #include "raymath.h" // Required for Vector3 and Matrix functions + #include "raymath.h" // Required for: Vector3 and Matrix functions #endif #if defined(GRAPHICS_API_OPENGL_11) @@ -140,6 +140,14 @@ #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 #endif +#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#endif + #if defined(GRAPHICS_API_OPENGL_11) #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 @@ -283,14 +291,21 @@ static Shader standardShader; // Shader with support for lighting static Shader currentShader; // Shader to be used on rendering (by default, defaultShader) static bool standardShaderLoaded = false; // Flag to track if standard shader has been loaded -// Flags for supported extensions +// Extension supported flag: VAO static bool vaoSupported = false; // VAO support (OpenGL ES2 could not support VAO extension) -// Compressed textures support flags +// Extension supported flag: Compressed textures static bool texCompETC1Supported = false; // ETC1 texture compression support static bool texCompETC2Supported = false; // ETC2/EAC texture compression support static bool texCompPVRTSupported = false; // PVR texture compression support static bool texCompASTCSupported = false; // ASTC texture compression support + +// Extension supported flag: Anisotropic filtering +static bool texAnisotropicFilterSupported = false; // Anisotropic texture filtering support +static float maxAnisotropicLevel = 0.0f; // Maximum anisotropy level supported (minimum is 2.0f) + +// Extension supported flag: Clamp mirror wrap mode +static bool texClampMirrorSupported = false; // Clamp mirror wrap mode supported #endif #if defined(RLGL_OCULUS_SUPPORT) @@ -372,11 +387,11 @@ static char *ReadTextFile(const char *fileName); // Read chars array from #if defined(RLGL_OCULUS_SUPPORT) #if !defined(RLGL_STANDALONE) -static bool InitOculusDevice(void); // Initialize Oculus device (returns true if success) -static void CloseOculusDevice(void); // Close Oculus device -static void UpdateOculusTracking(void); // Update Oculus head position-orientation tracking -static void BeginOculusDrawing(void); // Setup Oculus buffers for drawing -static void EndOculusDrawing(void); // Finish Oculus drawing and blit framebuffer to mirror +static bool InitOculusDevice(void); // Initialize Oculus device (returns true if success) +static void CloseOculusDevice(void); // Close Oculus device +static void UpdateOculusTracking(Camera *camera); // Update Oculus head position-orientation tracking +static void BeginOculusDrawing(void); // Setup Oculus buffers for drawing +static void EndOculusDrawing(void); // Finish Oculus drawing and blit framebuffer to mirror #endif static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height); // Load Oculus required buffers @@ -871,6 +886,37 @@ void rlDisableTexture(void) #endif } +// Set texture parameters (wrap mode/filter mode) +void rlTextureParameters(unsigned int id, int param, int value) +{ + glBindTexture(GL_TEXTURE_2D, id); + + switch (param) + { + case RL_TEXTURE_WRAP_S: + case RL_TEXTURE_WRAP_T: + { + if ((value == RL_WRAP_CLAMP_MIRROR) && !texClampMirrorSupported) TraceLog(WARNING, "Clamp mirror wrap mode not supported"); + else glTexParameteri(GL_TEXTURE_2D, param, value); + } break; + case RL_TEXTURE_MAG_FILTER: + case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break; + case RL_TEXTURE_ANISOTROPIC_FILTER: + { + if (value <= maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value); + else if (maxAnisotropicLevel > 0.0f) + { + TraceLog(WARNING, "[TEX ID %i] Maximum anisotropic filter level supported is %iX", id, maxAnisotropicLevel); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value); + } + else TraceLog(WARNING, "Anisotropic filtering not supported"); + } break; + default: break; + } + + glBindTexture(GL_TEXTURE_2D, 0); +} + // Enable rendering to texture (fbo) void rlEnableRenderTexture(unsigned int id) { @@ -1124,7 +1170,7 @@ void rlglInit(int width, int height) // Check NPOT textures support // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) npotSupported = true; -#endif +#endif // DDS texture compression support if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || @@ -1143,6 +1189,16 @@ void rlglInit(int width, int height) // ASTC texture compression support if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) texCompASTCSupported = true; + + // Anisotropic texture filter support + if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) + { + texAnisotropicFilterSupported = true; + glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + } + + // Clamp mirror wrap mode supported + if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; } #ifdef _MSC_VER @@ -1162,6 +1218,9 @@ void rlglInit(int width, int height) if (texCompETC2Supported) TraceLog(INFO, "[EXTENSION] ETC2/EAC compressed textures supported"); if (texCompPVRTSupported) TraceLog(INFO, "[EXTENSION] PVRT compressed textures supported"); if (texCompASTCSupported) TraceLog(INFO, "[EXTENSION] ASTC compressed textures supported"); + + if (texAnisotropicFilterSupported) TraceLog(INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel); + if (texClampMirrorSupported) TraceLog(INFO, "[EXTENSION] Clamp mirror wrap texture mode supported"); // Initialize buffers, default shaders and default textures //---------------------------------------------------------- @@ -1687,6 +1746,7 @@ void rlglGenerateMipmaps(Texture2D texture) #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture.id); @@ -2653,7 +2713,7 @@ void InitVrDevice(int vrDevice) hmd.hResolution = 2160; // HMD horizontal resolution in pixels hmd.vResolution = 1200; // HMD vertical resolution in pixels hmd.hScreenSize = 0.133793f; // HMD horizontal size in meters - hmd.vScreenSize = 0.0669; // HMD vertical size in meters + hmd.vScreenSize = 0.0669f; // HMD vertical size in meters hmd.vScreenCenter = 0.04678f; // HMD screen center in meters hmd.eyeToScreenDistance = 0.041f; // HMD distance between eye and display in meters hmd.lensSeparationDistance = 0.07f; // HMD lens separation distance in meters @@ -2735,15 +2795,11 @@ void ToggleVrMode(void) } // Update VR tracking (position and orientation) and camera +// NOTE: Camera (position, target, up) gets update with head tracking information void UpdateVrTracking(Camera *camera) { #if defined(RLGL_OCULUS_SUPPORT) - if (vrDeviceReady) - { - UpdateOculusTracking(); - - // TODO: Update camera data (position, target, up) with tracking data - } + if (vrDeviceReady) UpdateOculusTracking(camera); #endif } @@ -3786,8 +3842,8 @@ static void SetStereoConfig(VrDeviceInfo hmd) // Compute lens parameters float lensShift = (hmd.hScreenSize*0.25f - hmd.lensSeparationDistance*0.5f)/hmd.hScreenSize; - float leftLensCenter[2] = { 0.25 + lensShift, 0.5f }; - float rightLensCenter[2] = { 0.75 - lensShift, 0.5f }; + float leftLensCenter[2] = { 0.25f + lensShift, 0.5f }; + float rightLensCenter[2] = { 0.75f - lensShift, 0.5f }; float leftScreenCenter[2] = { 0.25f, 0.5f }; float rightScreenCenter[2] = { 0.75f, 0.5f }; @@ -3804,8 +3860,8 @@ static void SetStereoConfig(VrDeviceInfo hmd) float normScreenWidth = 0.5f; float normScreenHeight = 1.0f; - float scaleIn[2] = { 2/normScreenWidth, 2/normScreenHeight/aspect }; - float scale[2] = { normScreenWidth*0.5/distortionScale, normScreenHeight*0.5*aspect/distortionScale }; + float scaleIn[2] = { 2.0f/normScreenWidth, 2.0f/normScreenHeight/aspect }; + float scale[2] = { normScreenWidth*0.5f/distortionScale, normScreenHeight*0.5f*aspect/distortionScale }; TraceLog(DEBUG, "VR: Distortion Shader: LeftLensCenter = { %f, %f }", leftLensCenter[0], leftLensCenter[1]); TraceLog(DEBUG, "VR: Distortion Shader: RightLensCenter = { %f, %f }", rightLensCenter[0], rightLensCenter[1]); @@ -3826,7 +3882,7 @@ static void SetStereoConfig(VrDeviceInfo hmd) // Fovy is normally computed with: 2*atan2(hmd.vScreenSize, 2*hmd.eyeToScreenDistance)*RAD2DEG // ...but with lens distortion it is increased (see Oculus SDK Documentation) //float fovy = 2.0f*atan2(hmd.vScreenSize*0.5f*distortionScale, hmd.eyeToScreenDistance)*RAD2DEG; // Really need distortionScale? - float fovy = 2.0f*atan2(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance)*RAD2DEG; + float fovy = 2.0f*(float)atan2(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance)*RAD2DEG; // Compute camera projection matrices float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1] @@ -4083,7 +4139,7 @@ OCULUSAPI void CloseOculusDevice(void) } // Update Oculus head position-orientation tracking -OCULUSAPI void UpdateOculusTracking(void) +OCULUSAPI void UpdateOculusTracking(Camera *camera) { frameIndex++; @@ -4093,6 +4149,10 @@ OCULUSAPI void UpdateOculusTracking(void) layer.eyeLayer.RenderPose[0] = eyePoses[0]; layer.eyeLayer.RenderPose[1] = eyePoses[1]; + // TODO: Update external camera with eyePoses data (position, orientation) + // NOTE: We can simplify to simple camera if we consider IPD and HMD device configuration again later + // it will be useful for the user to draw, lets say, billboards oriented to camera + // Get session status information ovrSessionStatus sessionStatus; ovr_GetSessionStatus(session, &sessionStatus); @@ -90,15 +90,33 @@ #define MAX_QUADS_BATCH 1024 // Be careful with text, every letter maps a quad #endif +// Texture parameters (equivalent to OpenGL defines) +#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S +#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T +#define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER +#define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER +#define RL_TEXTURE_ANISOTROPIC_FILTER 0x3000 // Anisotropic filter (custom identifier) + +#define RL_FILTER_NEAREST 0x2600 // GL_NEAREST +#define RL_FILTER_LINEAR 0x2601 // GL_LINEAR +#define RL_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST +#define RL_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR +#define RL_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST +#define RL_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR + +#define RL_WRAP_REPEAT 0x2901 // GL_REPEAT +#define RL_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE +#define RL_WRAP_CLAMP_MIRROR 0x8742 // GL_MIRROR_CLAMP_EXT + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- +typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; + typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode; typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode; -typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; - #if defined(RLGL_STANDALONE) #ifndef __cplusplus // Boolean type @@ -236,6 +254,21 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; // Light types typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; + + // Texture parameters: filter mode + // NOTE 1: Filtering considers mipmaps if available in the texture + // NOTE 2: Filter is accordingly set for minification and magnification + typedef enum { + FILTER_POINT = 0, // No filter, just pixel aproximation + FILTER_BILINEAR, // Linear filtering + FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x + } TextureFilterMode; + + // Texture parameters: wrap mode + typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; @@ -296,6 +329,7 @@ void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) //------------------------------------------------------------------------------------ void rlEnableTexture(unsigned int id); // Enable texture usage void rlDisableTexture(void); // Disable texture usage +void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap) void rlEnableRenderTexture(unsigned int id); // Enable render texture (fbo) void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer void rlEnableDepthTest(void); // Enable depth test @@ -381,7 +415,7 @@ void ToggleVrMode(void); // Enable/Disable VR experience (dev // Oculus Rift API for direct access the device (no simulator) bool InitOculusDevice(void); // Initialize Oculus device (returns true if success) void CloseOculusDevice(void); // Close Oculus device -void UpdateOculusTracking(void); // Update Oculus head position-orientation tracking +void UpdateOculusTracking(Camera *camera); // Update Oculus head position-orientation tracking (and camera) void BeginOculusDrawing(void); // Setup Oculus buffers for drawing void EndOculusDrawing(void); // Finish Oculus drawing and blit framebuffer to mirror #endif diff --git a/src/shapes.c b/src/shapes.c index 9fcbeff7..79cf567a 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 (@raysan5) +* Copyright (c) 2014-2016 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. @@ -25,9 +25,8 @@ #include "raylib.h" -#include <stdlib.h> // Required for abs() function -#include <math.h> // Math related functions, sin() and cos() used on DrawCircle* - // sqrt() and pow() and abs() used on CheckCollision* +#include <stdlib.h> // Required for: abs() +#include <math.h> // Required for: sinf(), cosf(), sqrtf() #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 @@ -71,7 +70,7 @@ void DrawPixelV(Vector2 position, Color color) rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(position.x, position.y); - rlVertex2i(position.x + 1, position.y + 1); + rlVertex2f(position.x + 1.0f, position.y + 1.0f); rlEnd(); } @@ -98,7 +97,7 @@ void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) // Draw a color-filled circle void DrawCircle(int centerX, int centerY, float radius, Color color) { - DrawCircleV((Vector2){ centerX, centerY }, radius, color); + DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color); } // Draw a gradient-filled circle @@ -111,9 +110,9 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(centerX, centerY); rlColor4ub(color2.r, color2.g, color2.b, color2.a); - rlVertex2f(centerX + sin(DEG2RAD*i)*radius, centerY + cos(DEG2RAD*i)*radius); + rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); rlColor4ub(color2.r, color2.g, color2.b, color2.a); - rlVertex2f(centerX + sin(DEG2RAD*(i + 10))*radius, centerY + cos(DEG2RAD*(i + 10))*radius); + rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); } rlEnd(); } @@ -130,8 +129,8 @@ void DrawCircleV(Vector2 center, float radius, Color color) rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(center.x, center.y); - rlVertex2f(center.x + sin(DEG2RAD*i)*radius, center.y + cos(DEG2RAD*i)*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 10))*radius, center.y + cos(DEG2RAD*(i + 10))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); } rlEnd(); } @@ -145,9 +144,9 @@ void DrawCircleV(Vector2 center, float radius, Color color) rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(center.x, center.y); - rlVertex2f(center.x + sin(DEG2RAD*i)*radius, center.y + cos(DEG2RAD*i)*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 10))*radius, center.y + cos(DEG2RAD*(i + 10))*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 20))*radius, center.y + cos(DEG2RAD*(i + 20))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 20))*radius, center.y + cosf(DEG2RAD*(i + 20))*radius); } rlEnd(); @@ -164,8 +163,8 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color) // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) for (int i = 0; i < 360; i += 10) { - rlVertex2f(centerX + sin(DEG2RAD*i)*radius, centerY + cos(DEG2RAD*i)*radius); - rlVertex2f(centerX + sin(DEG2RAD*(i + 10))*radius, centerY + cos(DEG2RAD*(i + 10))*radius); + rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); + rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); } rlEnd(); } @@ -331,8 +330,8 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(0, 0); - rlVertex2f(sin(DEG2RAD*i)*radius, cos(DEG2RAD*i)*radius); - rlVertex2f(sin(DEG2RAD*(i + 360/sides))*radius, cos(DEG2RAD*(i + 360/sides))*radius); + rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius); + rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius); } rlEnd(); rlPopMatrix(); @@ -434,7 +433,7 @@ bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, floa float dx = center2.x - center1.x; // X distance between centers float dy = center2.y - center1.y; // Y distance between centers - float distance = sqrt(dx*dx + dy*dy); // Distance between centers + float distance = sqrtf(dx*dx + dy*dy); // Distance between centers if (distance <= (radius1 + radius2)) collision = true; @@ -457,7 +456,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) if (dx <= (rec.width/2)) { return true; } if (dy <= (rec.height/2)) { return true; } - float cornerDistanceSq = pow(dx - rec.width/2, 2) + pow(dy - rec.height/2, 2); + float cornerDistanceSq = (dx - rec.width/2)*(dx - rec.width/2) + (dy - rec.height/2)*(dy - rec.height/2); return (cornerDistanceSq <= (radius*radius)); } @@ -4,7 +4,7 @@ * * Basic functions to load SpriteFonts and draw Text * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 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. @@ -30,9 +30,10 @@ #include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() #include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets() -#include "utils.h" // Required for: GetExtension() +#include "utils.h" // Required for: GetExtension(), GetNextPOT() // Following libs are used on LoadTTF() +//#define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION #include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() @@ -43,7 +44,6 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FONT_FIRST_CHAR 32 // NOTE: Expected first char for a sprite font #define MAX_FORMATTEXT_LENGTH 64 #define MAX_SUBTEXT_LENGTH 64 @@ -68,12 +68,12 @@ static SpriteFont defaultFont; // Default font provided by raylib //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- +static int GetCharIndex(SpriteFont font, int letter); + static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) - -// Generate a sprite font image from TTF data -static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int numChars); +static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load spritefont from TTF data extern void LoadDefaultFont(void); extern void UnloadDefaultFont(void); @@ -198,7 +198,7 @@ extern void LoadDefaultFont(void) for (int i = 0; i < defaultFont.numChars; i++) { - defaultFont.charValues[i] = FONT_FIRST_CHAR + i; // First char is 32 + defaultFont.charValues[i] = 32 + i; // First char is 32 defaultFont.charRecs[i].x = currentPosX; defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); @@ -249,17 +249,18 @@ SpriteFont LoadSpriteFont(const char *fileName) // Default hardcoded values for ttf file loading #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs + #define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont SpriteFont spriteFont = { 0 }; // Check file extension if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); - else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadTTF(fileName, DEFAULT_TTF_FONTSIZE, FONT_FIRST_CHAR, DEFAULT_TTF_NUMCHARS); + else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadSpriteFontTTF(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); else if (strcmp(GetExtension(fileName),"fnt") == 0) spriteFont = LoadBMFont(fileName); else { Image image = LoadImage(fileName); - if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, FONT_FIRST_CHAR); + if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); UnloadImage(image); } @@ -268,6 +269,38 @@ SpriteFont LoadSpriteFont(const char *fileName) TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName); spriteFont = GetDefaultFont(); } + else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance) + + return spriteFont; +} + +// Load SpriteFont from TTF file with custom parameters +// NOTE: You can pass an array with desired characters, those characters should be available in the font +// if array is NULL, default char set is selected 32..126 +SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars) +{ + SpriteFont spriteFont = { 0 }; + + if (strcmp(GetExtension(fileName),"ttf") == 0) + { + if ((fontChars == NULL) || (numChars == 0)) + { + int totalChars = 95; // Default charset [32..126] + + int *defaultFontChars = (int *)malloc(totalChars*sizeof(int)); + + for (int i = 0; i < totalChars; i++) defaultFontChars[i] = i + 32; // Default first character: SPACE[32] + + spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars); + } + else spriteFont = LoadTTF(fileName, fontSize, numChars, fontChars); + } + + if (spriteFont.texture.id == 0) + { + TraceLog(WARNING, "[%s] SpriteFont could not be generated, using default font", fileName); + spriteFont = GetDefaultFont(); + } return spriteFont; } @@ -311,13 +344,13 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color) void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float fontSize, int spacing, Color tint) { int length = strlen(text); - int textOffsetX = 0; - int textOffsetY = 0; // Line break! + int textOffsetX = 0; // Offset between characters + int textOffsetY = 0; // Required for line break! float scaleFactor; - unsigned char letter; - - Rectangle rec; - + + unsigned char letter; // Current character + int index; // Index position in sprite font + scaleFactor = fontSize/spriteFont.size; // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly @@ -325,44 +358,38 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float for (int i = 0; i < length; i++) { - // TODO: Right now we are supposing characters that follow a continous order and start at FONT_FIRST_CHAR, - // this sytem can be improved to support any characters order and init value... - // An intermediate table could be created to link char values with predefined char position index in chars rectangle array - - if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! - { - // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) - letter = (unsigned char)text[i + 1]; - rec = spriteFont.charRecs[letter - FONT_FIRST_CHAR]; - i++; - } - else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! + if ((unsigned char)text[i] == '\n') { - // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) - letter = (unsigned char)text[i + 1]; - rec = spriteFont.charRecs[letter - FONT_FIRST_CHAR + 64]; - i++; + // NOTE: Fixed line spacing of 1.5 lines + textOffsetY += ((spriteFont.size + spriteFont.size/2)*scaleFactor); + textOffsetX = 0; } else { - if ((unsigned char)text[i] == '\n') + if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! { - // NOTE: Fixed line spacing of 1.5 lines - textOffsetY += ((spriteFont.size + spriteFont.size/2)*scaleFactor); - textOffsetX = 0; - rec.x = -1; + // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) + letter = (unsigned char)text[i + 1]; + index = GetCharIndex(spriteFont, (int)letter); + i++; } - else rec = spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR]; - } + else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! + { + // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) + letter = (unsigned char)text[i + 1]; + index = GetCharIndex(spriteFont, (int)letter + 64); + i++; + } + else index = GetCharIndex(spriteFont, (int)text[i]); - if (rec.x > 0) - { - DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x*scaleFactor, - position.y + textOffsetY + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].y*scaleFactor, - rec.width*scaleFactor, rec.height*scaleFactor} , (Vector2){ 0, 0 }, 0.0f, tint); + DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index], + (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor, + position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor, + spriteFont.charRecs[index].width*scaleFactor, + spriteFont.charRecs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); - if (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR] == 0) textOffsetX += (rec.width*scaleFactor + spacing); - else textOffsetX += (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR]*scaleFactor + spacing); + if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (spriteFont.charRecs[index].width*scaleFactor + spacing); + else textOffsetX += (spriteFont.charAdvanceX[index]*scaleFactor + spacing); } } } @@ -417,14 +444,14 @@ int MeasureText(const char *text, int fontSize) if (fontSize < defaultFontSize) fontSize = defaultFontSize; int spacing = fontSize/defaultFontSize; - vec = MeasureTextEx(GetDefaultFont(), text, fontSize, spacing); + vec = MeasureTextEx(GetDefaultFont(), text, (float)fontSize, spacing); } return (int)vec.x; } // Measure string size for SpriteFont -Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing) +Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing) { int len = strlen(text); int tempLen = 0; // Used to count longer text line num chars @@ -434,7 +461,7 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int int tempTextWidth = 0; // Used to count longer text line width int textHeight = spriteFont.size; - float scaleFactor; + float scaleFactor = fontSize/spriteFont.size; for (int i = 0; i < len; i++) { @@ -442,8 +469,10 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int if (text[i] != '\n') { - if (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR] != 0) textWidth += spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR]; - else textWidth += (spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR].width + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x); + int index = GetCharIndex(spriteFont, (int)text[i]); + + if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index]; + else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x); } else { @@ -458,9 +487,6 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int if (tempTextWidth < textWidth) tempTextWidth = textWidth; - if (fontSize <= spriteFont.size) scaleFactor = 1.0f; - else scaleFactor = (float)fontSize/spriteFont.size; - Vector2 vec; vec.x = (float)tempTextWidth*scaleFactor + (tempLen - 1)*spacing; // Adds chars spacing to measure vec.y = (float)textHeight*scaleFactor; @@ -500,7 +526,28 @@ void DrawFPS(int posX, int posY) // Module specific Functions Definition //---------------------------------------------------------------------------------- -// Load a Image font file (XNA style) +static int GetCharIndex(SpriteFont font, int letter) +{ +#define UNORDERED_CHARSET +#if defined(UNORDERED_CHARSET) + int index = 0; + + for (int i = 0; i < font.numChars; i++) + { + if (font.charValues[i] == letter) + { + index = i; + break; + } + } + + return index; +#else + return (letter - 32); +#endif +} + +// Load an Image font file (XNA style) static SpriteFont LoadImageFont(Image image, Color key, int firstChar) { #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) @@ -511,8 +558,8 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) int x = 0; int y = 0; - // Default number of characters expected supported - #define MAX_FONTCHARS 128 + // Default number of characters supported + #define MAX_FONTCHARS 256 // We allocate a temporal arrays for chars data measures, // once we get the actual number of chars, we copy data to a sized arrays @@ -573,15 +620,24 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) xPosToRead = charSpacing; } - free(pixels); - TraceLog(DEBUG, "SpriteFont data parsed correctly from image"); + + // NOTE: We need to remove key color borders from image to avoid weird + // artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR + for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK; + + // Create a new image with the processed color data (key color replaced by BLANK) + Image fontClear = LoadImageEx(pixels, image.width, image.height); + + free(pixels); // Free pixels array memory // Create spritefont with all data parsed from image SpriteFont spriteFont = { 0 }; - spriteFont.texture = LoadTextureFromImage(image); // Convert loaded image to OpenGL texture + spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture spriteFont.numChars = index; + + UnloadImage(fontClear); // Unload processed image once converted to texture // We got tempCharValues and tempCharsRecs populated with chars data // Now we move temp data to sized charValues and charRecs arrays @@ -811,8 +867,13 @@ static SpriteFont LoadBMFont(const char *fileName) strncat(texPath, texFileName, strlen(texFileName)); TraceLog(DEBUG, "[%s] Font texture loading path: %s", fileName, texPath); + + Image imFont = LoadImage(texPath); - font.texture = LoadTexture(texPath); + if (imFont.format == UNCOMPRESSED_GRAYSCALE) ImageAlphaMask(&imFont, imFont); + + font.texture = LoadTextureFromImage(imFont); + font.size = fontSize; font.numChars = numChars; font.charValues = (int *)malloc(numChars*sizeof(int)); @@ -820,22 +881,18 @@ static SpriteFont LoadBMFont(const char *fileName) font.charOffsets = (Vector2 *)malloc(numChars*sizeof(Vector2)); font.charAdvanceX = (int *)malloc(numChars*sizeof(int)); + UnloadImage(imFont); + free(texPath); int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; - bool unorderedChars = false; - int firstChar = 0; - for (int i = 0; i < numChars; i++) { fgets(buffer, MAX_BUFFER_SIZE, fntFile); sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); - if (i == 0) firstChar = charId; - else if (i != (charId - firstChar)) unorderedChars = true; - // Save data properly in sprite font font.charValues[i] = charId; font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight }; @@ -845,11 +902,7 @@ static SpriteFont LoadBMFont(const char *fileName) fclose(fntFile); - if (firstChar != FONT_FIRST_CHAR) TraceLog(WARNING, "BMFont not supported: expected SPACE(32) as first character, falling back to default font"); - else if (unorderedChars) TraceLog(WARNING, "BMFont not supported: unordered chars data, falling back to default font"); - - // NOTE: Font data could be not ordered by charId: 32,33,34,35... raylib does not support unordered BMFonts - if ((firstChar != FONT_FIRST_CHAR) || (unorderedChars) || (font.texture.id == 0)) + if (font.texture.id == 0) { UnloadSpriteFont(font); font = GetDefaultFont(); @@ -861,14 +914,17 @@ static SpriteFont LoadBMFont(const char *fileName) // Generate a sprite font from TTF file data (font size required) // TODO: Review texture packing method and generation (use oversampling) -static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int numChars) +static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars) { - // NOTE: Generated font uses some hardcoded values - #define FONT_TEXTURE_WIDTH 512 // Font texture width - #define FONT_TEXTURE_HEIGHT 512 // Font texture height + // NOTE: Font texture size is predicted (being as much conservative as possible) + // Predictive method consist of supposing same number of chars by line-column (sqrtf) + // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... + int textureSize = GetNextPOT(ceil((float)fontSize*3/4)*ceil(sqrtf((float)numChars))); + + TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25); - unsigned char *dataBitmap = (unsigned char *)malloc(FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*sizeof(unsigned char)); // One channel bitmap returned! + unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*numChars); SpriteFont font = { 0 }; @@ -877,40 +933,47 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int if (ttfFile == NULL) { - TraceLog(WARNING, "[%s] FNT file could not be opened", fileName); + TraceLog(WARNING, "[%s] TTF file could not be opened", fileName); return font; } fread(ttfBuffer, 1, 1<<25, ttfFile); + + if (fontChars[0] != 32) TraceLog(WARNING, "TTF spritefont loading: first character is not SPACE(32) character"); // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... - stbtt_BakeFontBitmap(ttfBuffer,0, fontSize, dataBitmap, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, firstChar, numChars, charData); + // TODO: Replace this function by a proper packing method and support random chars order, + // we already receive a list (fontChars) with the ordered expected characters + int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], numChars, charData); + //if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); + if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font"); + free(ttfBuffer); // Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA - unsigned char *dataGrayAlpha = (unsigned char *)malloc(FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*sizeof(unsigned char)*2); // Two channels - int k = 0; + unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels - for (int i = 0; i < FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT; i++) + for (int i = 0, k = 0; i < textureSize*textureSize; i++, k += 2) { dataGrayAlpha[k] = 255; dataGrayAlpha[k + 1] = dataBitmap[i]; - - k += 2; } free(dataBitmap); // Sprite font generation from TTF extracted data Image image; - image.width = FONT_TEXTURE_WIDTH; - image.height = FONT_TEXTURE_HEIGHT; + image.width = textureSize; + image.height = textureSize; image.mipmaps = 1; image.format = UNCOMPRESSED_GRAY_ALPHA; image.data = dataGrayAlpha; - + font.texture = LoadTextureFromImage(image); + + //WritePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2); + UnloadImage(image); // Unloads dataGrayAlpha font.size = fontSize; @@ -922,7 +985,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int for (int i = 0; i < font.numChars; i++) { - font.charValues[i] = i + firstChar; + font.charValues[i] = fontChars[i]; font.charRecs[i].x = (int)charData[i].x0; font.charRecs[i].y = (int)charData[i].y0; diff --git a/src/textures.c b/src/textures.c index fd5bdd80..5354a74f 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 (@raysan5) +* Copyright (c) 2014-2016 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. @@ -442,6 +442,96 @@ void UnloadRenderTexture(RenderTexture2D target) if (target.id != 0) rlDeleteRenderTextures(target); } +// Set texture scaling filter mode +void SetTextureFilter(Texture2D texture, int filterMode) +{ + switch (filterMode) + { + case FILTER_POINT: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST); + + // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); + } + else + { + // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); + } + } break; + case FILTER_BILINEAR: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps) + // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST); + + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + else + { + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + } break; + case FILTER_TRILINEAR: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR); + + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + else + { + TraceLog(WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id); + + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + } break; + case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break; + case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break; + case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break; + default: break; + } +} + +// Set texture wrapping mode +void SetTextureWrap(Texture2D texture, int wrapMode) +{ + switch (wrapMode) + { + case WRAP_REPEAT: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT); + } break; + case WRAP_CLAMP: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP); + } break; + case WRAP_MIRROR: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR); + } break; + default: break; + } +} + // Get pixel data from image in the form of Color struct array Color *GetImageData(Image image) { @@ -694,28 +784,45 @@ void ImageFormat(Image *image, int newFormat) } // Apply alpha mask to image -// NOTE 1: Returned image is RGBA - 32bit +// NOTE 1: Returned image is GRAY_ALPHA (16bit) or RGBA (32bit) // NOTE 2: alphaMask should be same size as image void ImageAlphaMask(Image *image, Image alphaMask) { - if (image->format >= COMPRESSED_DXT1_RGB) + if ((image->width != alphaMask.width) || (image->height != alphaMask.height)) + { + TraceLog(WARNING, "Alpha mask must be same size as image"); + } + else if (image->format >= COMPRESSED_DXT1_RGB) { TraceLog(WARNING, "Alpha mask can not be applied to compressed data formats"); - return; } else { // Force mask to be Grayscale Image mask = ImageCopy(alphaMask); - ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE); + if (mask.format != UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE); - // Convert image to RGBA - if (image->format != UNCOMPRESSED_R8G8B8A8) ImageFormat(image, UNCOMPRESSED_R8G8B8A8); - - // Apply alpha mask to alpha channel - for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4) + // In case image is only grayscale, we just add alpha channel + if (image->format == UNCOMPRESSED_GRAYSCALE) { - ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; + ImageFormat(image, UNCOMPRESSED_GRAY_ALPHA); + + // Apply alpha mask to alpha channel + for (int i = 0, k = 1; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2) + { + ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; + } + } + else + { + // Convert image to RGBA + if (image->format != UNCOMPRESSED_R8G8B8A8) ImageFormat(image, UNCOMPRESSED_R8G8B8A8); + + // Apply alpha mask to alpha channel + for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4) + { + ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; + } } UnloadImage(mask); @@ -1118,7 +1225,7 @@ Image ImageText(const char *text, int fontSize, Color color) if (fontSize < defaultFontSize) fontSize = defaultFontSize; int spacing = fontSize/defaultFontSize; - Image imText = ImageTextEx(GetDefaultFont(), text, fontSize, spacing, color); + Image imText = ImageTextEx(GetDefaultFont(), text, (float)fontSize, spacing, color); return imText; } @@ -1134,7 +1241,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing // NOTE: GetTextureData() not available in OpenGL ES Image imFont = GetTextureData(font.texture); - ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Required for color tint + ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Convert to 32 bit for color tint ImageColorTint(&imFont, tint); // Apply color tint to font Color *fontPixels = GetImageData(imFont); @@ -1183,7 +1290,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color) { // NOTE: For default font, sapcing is set to desired font size / default font size (10) - ImageDrawTextEx(dst, position, GetDefaultFont(), text, fontSize, fontSize/10, color); + ImageDrawTextEx(dst, position, GetDefaultFont(), text, (float)fontSize, fontSize/10, color); } // Draw text (custom sprite font) within an image (destination) @@ -1317,7 +1424,7 @@ void ImageColorContrast(Image *image, float contrast) if (contrast < -100) contrast = -100; if (contrast > 100) contrast = 100; - contrast = (100.0 + contrast)/100.0; + contrast = (100.0f + contrast)/100.0f; contrast *= contrast; Color *pixels = GetImageData(*image); @@ -1326,7 +1433,7 @@ void ImageColorContrast(Image *image, float contrast) { for (int x = 0; x < image->width; x++) { - float pR = (float)pixels[y*image->width + x].r/255.0; + float pR = (float)pixels[y*image->width + x].r/255.0f; pR -= 0.5; pR *= contrast; pR += 0.5; @@ -1334,7 +1441,7 @@ void ImageColorContrast(Image *image, float contrast) if (pR < 0) pR = 0; if (pR > 255) pR = 255; - float pG = (float)pixels[y*image->width + x].g/255.0; + float pG = (float)pixels[y*image->width + x].g/255.0f; pG -= 0.5; pG *= contrast; pG += 0.5; @@ -1342,7 +1449,7 @@ void ImageColorContrast(Image *image, float contrast) if (pG < 0) pG = 0; if (pG > 255) pG = 255; - float pB = (float)pixels[y*image->width + x].b/255.0; + float pB = (float)pixels[y*image->width + x].b/255.0f; pB -= 0.5; pB *= contrast; pB += 0.5; diff --git a/src/utils.c b/src/utils.c index 36b06f0f..b96e2c70 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 (@raysan5) +* Copyright (c) 2014-2016 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. |
