aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRay <raysan5@gmail.com>2016-11-15 18:00:02 +0100
committerGitHub <noreply@github.com>2016-11-15 18:00:02 +0100
commit4123233f7873cf157c92f4990e56b83da47b9d7f (patch)
tree95a52d661abc832c8c30095b2c4c661cf52ae30f /src
parenta9315fc422a3a036891f50f0c2be5059c3db8b31 (diff)
parenta3d71dd58d993d15d695b0cd58b434ef2604185b (diff)
downloadraylib-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.c6
-rw-r--r--src/core.c317
-rw-r--r--src/external/openal_soft/lib/win32/libOpenAL32dll.a (renamed from src/external/openal_soft/lib/win32/libOpenAL32.dll.a)bin100246 -> 100246 bytes
-rw-r--r--src/models.c144
-rw-r--r--src/raylib.h129
-rw-r--r--src/rlgl.c104
-rw-r--r--src/rlgl.h40
-rw-r--r--src/shapes.c37
-rw-r--r--src/text.c237
-rw-r--r--src/textures.c143
-rw-r--r--src/utils.c2
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));
diff --git a/src/core.c b/src/core.c
index 3bd85fdd..8e15eb96 100644
--- a/src/core.c
+++ b/src/core.c
@@ -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
index 1c4c63c8..1c4c63c8 100644
--- a/src/external/openal_soft/lib/win32/libOpenAL32.dll.a
+++ b/src/external/openal_soft/lib/win32/libOpenAL32dll.a
Binary files differ
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'
diff --git a/src/rlgl.c b/src/rlgl.c
index e8607925..d3bba07b 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -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);
diff --git a/src/rlgl.h b/src/rlgl.h
index 3a47b4c8..9be73f36 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -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));
}
diff --git a/src/text.c b/src/text.c
index d1d7602f..72d273d4 100644
--- a/src/text.c
+++ b/src/text.c
@@ -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.