aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorraysan5 <raysan5@gmail.com>2014-09-16 22:51:31 +0200
committerraysan5 <raysan5@gmail.com>2014-09-16 22:51:31 +0200
commitfc6081fe70ab7c3b037c0ab9f38478904d3cdde2 (patch)
tree6635fd800fa673ef3fb568c6f47ebc76a2b8ad6e /src
parent01651af08a494b1ac08c897695891ad7cf44ad47 (diff)
downloadraylib-fc6081fe70ab7c3b037c0ab9f38478904d3cdde2.tar.gz
raylib-fc6081fe70ab7c3b037c0ab9f38478904d3cdde2.zip
raylib 1.2
This is a huge update. Check CHANGELOG for details
Diffstat (limited to 'src')
-rw-r--r--src/audio.c65
-rw-r--r--src/core.c1422
-rw-r--r--src/makefile130
-rw-r--r--src/models.c76
-rw-r--r--src/raylib.h68
-rw-r--r--src/raymath.c41
-rw-r--r--src/raymath.h10
-rw-r--r--src/resourcesbin0 -> 107204 bytes
-rw-r--r--src/rlgl.c695
-rw-r--r--src/rlgl.h77
-rw-r--r--src/shapes.c70
-rw-r--r--src/stb_image.c9
-rw-r--r--src/stb_image.h6
-rw-r--r--src/stb_vorbis.h5
-rw-r--r--src/text.c85
-rw-r--r--src/textures.c145
-rw-r--r--src/utils.c130
-rw-r--r--src/utils.h23
18 files changed, 2362 insertions, 695 deletions
diff --git a/src/audio.c b/src/audio.c
index 03f72a2e..cc1d9f9a 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -1,14 +1,14 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raylib.audio
*
* Basic functions to manage Audio: InitAudioDevice, LoadAudioFiles, PlayAudioFiles
*
* Uses external lib:
-* OpenAL - Audio device management lib
-* stb_vorbis - Ogg audio files loading
+* OpenAL Soft - Audio device management lib (http://kcat.strangesoft.net/openal.html)
+* stb_vorbis - Ogg audio files loading (http://www.nothings.org/stb_vorbis/)
*
-* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -29,22 +29,25 @@
#include "raylib.h"
-#include <AL/al.h> // OpenAL basic header
-#include <AL/alc.h> // OpenAL context header (like OpenGL, OpenAL requires a context to work)
+#include "AL/al.h" // OpenAL basic header
+#include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work)
-#include <stdlib.h> // Declares malloc() and free() for memory management
-#include <string.h> // Required for strcmp()
-#include <stdio.h> // Used for .WAV loading
+#include <stdlib.h> // Declares malloc() and free() for memory management
+#include <string.h> // Required for strcmp()
+#include <stdio.h> // Used for .WAV loading
-#include "utils.h" // rRES data decompression utility function
+#include "utils.h" // rRES data decompression utility function
+ // NOTE: Includes Android fopen function map
-#include "stb_vorbis.h" // OGG loading functions
+#include "stb_vorbis.h" // OGG loading functions
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define MUSIC_STREAM_BUFFERS 2
-#define MUSIC_BUFFER_SIZE 4096*8 //4096*32
+#define MUSIC_BUFFER_SIZE 4096*2 // PCM data buffer (short) - 16Kb
+ // NOTE: Reduced to avoid frame-stalls on RPI
+//#define MUSIC_BUFFER_SIZE 4096*8 // PCM data buffer (short) - 64Kb
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -85,9 +88,9 @@ static Music currentMusic; // Current music loaded
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
-static Wave LoadWAV(const char *fileName);
-static Wave LoadOGG(char *fileName);
-static void UnloadWave(Wave wave);
+static Wave LoadWAV(const char *fileName); // Load WAV file
+static Wave LoadOGG(char *fileName); // Load OGG file
+static void UnloadWave(Wave wave); // Unload wave data
static bool BufferMusicStream(ALuint buffer); // Fill music buffers with data
static void EmptyMusicStream(void); // Empty music buffers
@@ -116,7 +119,7 @@ void InitAudioDevice(void)
TraceLog(ERROR, "Could not setup audio context");
}
- TraceLog(INFO, "Audio device and context initialized successfully: %s\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
+ TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
// Listener definition (just for 2D)
alListener3f(AL_POSITION, 0, 0, 0);
@@ -151,6 +154,13 @@ Sound LoadSound(char *fileName)
Sound sound;
Wave wave;
+ // Init some default values for wave...
+ wave.data = NULL;
+ wave.dataSize = 0;
+ wave.sampleRate = 0;
+ wave.bitsPerSample = 0;
+ wave.channels = 0;
+
// NOTE: The entire file is loaded to memory to play it all at once (no-streaming)
// Audio file loading
@@ -297,7 +307,6 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16;
}
-
// Create an audio source
ALuint source;
alGenSources(1, &source); // Generate pointer to audio source
@@ -506,8 +515,23 @@ void StopMusicStream(void)
// Pause music playing
void PauseMusicStream(void)
{
- // TODO: Record music is paused or check if music available!
- alSourcePause(currentMusic.source);
+ // Pause music stream if music available!
+ if (musicEnabled)
+ {
+ TraceLog(INFO, "Pausing music stream");
+ alSourcePause(currentMusic.source);
+ }
+}
+
+// Resume music playing
+void ResumeMusicStream(void)
+{
+ // Resume music playing... if music available!
+ if (musicEnabled)
+ {
+ TraceLog(INFO, "Resume music stream");
+ alSourcePlay(currentMusic.source);
+ }
}
// Check if music is playing
@@ -570,7 +594,7 @@ static bool BufferMusicStream(ALuint buffer)
else break;
}
- TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
+ //TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
}
if (size > 0)
@@ -754,6 +778,7 @@ static Wave LoadWAV(const char *fileName)
}
// Load OGG file into Wave structure
+// NOTE: Using stb_vorbis library
static Wave LoadOGG(char *fileName)
{
Wave wave;
diff --git a/src/core.c b/src/core.c
index c9784238..5bea82f9 100644
--- a/src/core.c
+++ b/src/core.c
@@ -1,13 +1,22 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raylib.core
*
-* Basic functions to manage Windows, OpenGL context and Input
+* Basic functions to manage windows, OpenGL context and input on multiple platforms
*
-* Uses external lib:
-* GLFW3 - Window, context and Input management (static lib version)
+* The following platforms are supported:
+* PLATFORM_DESKTOP - Windows, Linux, Mac (OSX)
+* PLATFORM_ANDROID - Only OpenGL ES 2.0 devices
+* PLATFORM_RPI - Rapsberry Pi (tested on Raspbian)
*
-* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+* On PLATFORM_DESKTOP, the external lib GLFW3 (www.glfw.com) is used to manage graphic
+* device, OpenGL context and input on multiple operating systems (Windows, Linux, OSX).
+*
+* On PLATFORM_ANDROID, graphic device is managed by EGL and input system by Android activity.
+*
+* On PLATFORM_RPI, graphic device is managed by EGL and input system is coded in raw mode.
+*
+* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
* 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.
@@ -26,27 +35,63 @@
*
**********************************************************************************************/
-#include "raylib.h"
-
+#include "raylib.h" // raylib main header
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
+#include "raymath.h" // Required for data type Matrix and Matrix functions
+#include "utils.h" // TraceLog() function
+ // NOTE: Includes Android fopen map, InitAssetManager()
-#include <GLFW/glfw3.h> // GLFW3 lib: Windows, OpenGL context and Input management
-//#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h)
#include <stdio.h> // Standard input / output lib
-#include <stdlib.h> // Declares malloc() and free() for memory management, rand()
-#include <time.h> // Useful to initialize random seed
+#include <stdlib.h> // Declares malloc() and free() for memory management, rand(), atexit()
+#include <stdint.h> // Required for typedef unsigned long long int uint64_t, used by hi-res timer
+#include <time.h> // Useful to initialize random seed - Android/RPI hi-res timer
#include <math.h> // Math related functions, tan() used to set perspective
-//#include "vector3.h" // Basic Vector3 functions, not required any more, replaced by raymath
-#include "utils.h" // WritePNG() function
+#include <string.h> // String function definitions, memset()
+#include <errno.h> // Macros for reporting and retrieving error conditions through error codes
-#include "raymath.h" // Required for data type Matrix and Matrix functions
+#if defined(PLATFORM_DESKTOP)
+ #include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
+ //#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h)
+ //#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version!
+#endif
+
+#if defined(PLATFORM_ANDROID)
+ #include <jni.h> // Java native interface
+ #include <android/sensor.h> // Android sensors functions
+ #include <android/window.h> // Defines AWINDOW_FLAG_FULLSCREEN and others
+ //#include <android_native_app_glue.h> // Defines basic app state struct and manages activity
-//#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version!
+ #include <EGL/egl.h> // Khronos EGL library - Native platform display device control functions
+ #include <GLES2/gl2.h> // Khronos OpenGL ES 2.0 library
+#endif
+
+#if defined(PLATFORM_RPI)
+ #include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
+ #include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
+ #include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
+ #include <pthread.h> // POSIX threads management (mouse input)
+
+ #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 "bcm_host.h" // Raspberry Pi VideoCore IV access functions
+
+ #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions
+ #include "EGL/eglext.h" // Khronos EGL library - Extensions
+ #include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library
+
+ #define DEFAULT_KEYBOARD_DEV "/dev/input/event0" // Not used, keyboard inputs are read raw from stdin
+ #define DEFAULT_MOUSE_DEV "/dev/input/event1"
+ //#define DEFAULT_MOUSE_DEV "/dev/input/mouse0"
+ #define DEFAULT_GAMEPAD_DEV "/dev/input/js0"
+#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-// Nop...
+// ...
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -56,22 +101,64 @@
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
-static GLFWwindow* window; // Main window
-static bool fullscreen; // Fullscreen mode track
+#if defined(PLATFORM_DESKTOP)
+static GLFWwindow *window; // Native window (graphic device)
+#elif defined(PLATFORM_ANDROID)
+static struct android_app *app; // Android activity
+static struct android_poll_source *source; // Android events polling source
+static int ident, events;
+static bool windowReady = false; // Used to detect display initialization
+#elif defined(PLATFORM_RPI)
+static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device)
+
+// Input variables (mouse/keyboard)
+static int mouseStream = -1; // Mouse device file descriptor
+static bool mouseReady = false; // Flag to know if mouse is ready
+pthread_t mouseThreadId; // Mouse reading thread id
+
+// NOTE: For keyboard we will use the standard input (but reconfigured...)
+static int defaultKeyboardMode; // Used to store default keyboard mode
+static struct termios defaultKeyboardSettings; // Used to staore default keyboard settings
+
+static int keyboardMode = 0; // Keyboard mode: 1 (KEYCODES), 2 (ASCII)
+
+// This array maps Unix keycodes to ASCII equivalent and to GLFW3 equivalent for special function keys (>256)
+const short UnixKeycodeToASCII[128] = { 256, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 259, 9, 81, 87, 69, 82, 84, 89, 85, 73, 79, 80, 91, 93, 257, 341, 65, 83, 68,
+ 70, 71, 72, 74, 75, 76, 59, 39, 96, 340, 92, 90, 88, 67, 86, 66, 78, 77, 44, 46, 47, 344, -1, 342, 32, -1, 290, 291, 292, 293, 294, 295, 296,
+ 297, 298, 299, -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 257, 345, 47, -1,
+ 346, -1, -1, 265, -1, 263, 262, -1, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+static int gamepadStream = -1; // Gamepad device file descriptor
+#endif
-static double currentTime, previousTime; // Used to track timmings
-static double updateTime, drawTime; // Time measures for update and draw
-static double frameTime; // Time measure for one frame
-static double targetTime = 0; // Desired time for one frame, if 0 not applied
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+static EGLDisplay display; // Native display device (physical screen connection)
+static EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
+static EGLContext context; // Graphic context, mode in which drawing can be done
+
+static uint64_t baseTime; // Base time measure for hi-res timer
+static bool windowShouldClose = false; // Flag to set window for closing
+#endif
+
+static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...)
+static int screenWidth, screenHeight; // Screen width and height (used render area)
+static int renderWidth, renderHeight; // Framebuffer width and height (render area)
+ // NOTE: Framebuffer could include black bars
-static int windowWidth, windowHeight; // Required to switch between windowed/fullscren mode (F11)
-static const char *windowTitle; // Required to switch between windowed/fullscren mode (F11)
-static int exitKey = GLFW_KEY_ESCAPE; // Default exit key (ESC)
+static int renderOffsetX = 0; // Offset X from render area (must be divided by 2)
+static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2)
+static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP)
+static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size)
+
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
+static const char *windowTitle; // Window text title...
static bool customCursor = false; // Tracks if custom cursor has been set
static bool cursorOnScreen = false; // Tracks if cursor is inside client area
static Texture2D cursor; // Cursor texture
+static Vector2 mousePosition;
+
static char previousKeyState[512] = { 0 }; // Required to check if key pressed/released once
static char currentKeyState[512] = { 0 }; // Required to check if key pressed/released once
@@ -84,126 +171,227 @@ static char currentGamepadState[32] = {0}; // Required to check if gamepad btn
static int previousMouseWheelY = 0; // Required to track mouse wheel variation
static int currentMouseWheelY = 0; // Required to track mouse wheel variation
-static Color background = { 0, 0, 0, 0 }; // Screen background color
+static int exitKey = KEY_ESCAPE; // Default exit key (ESC)
+#endif
+
+#if defined(PLATFORM_ANDROID)
+static float touchX; // Touch position X
+static float touchY; // Touch position Y
+#endif
+
+static double currentTime, previousTime; // Used to track timmings
+static double updateTime, drawTime; // Time measures for update and draw
+static double frameTime; // Time measure for one frame
+static double targetTime = 0.0; // Desired time for one frame, if 0 not applied
static bool showLogo = false;
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by core)
//----------------------------------------------------------------------------------
-extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow()
-extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory
+extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow()
+extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory
-extern void UpdateMusicStream(void); // [Module: audio] Updates buffers for music streaming
+extern void UpdateMusicStream(void); // [Module: audio] Updates buffers for music streaming
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
+static void InitDisplay(int width, int height); // Initialize display device and framebuffer
+static void InitGraphics(void); // Initialize OpenGL graphics
+static void InitTimer(void); // Initialize timer
+static double GetTime(void); // Returns time since InitTimer() was run
+static bool GetKeyStatus(int key); // Returns if a key has been pressed
+static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed
+static void SwapBuffers(void); // Copy back buffer to front buffers
+static void PollInputEvents(void); // Register user events
+static void LogoAnimation(void); // Plays raylib logo appearing animation
+static void SetupFramebufferSize(int displayWidth, int displayHeight);
+#if defined(PLATFORM_RPI)
+static void InitMouse(void); // Mouse initialization (including mouse thread)
+static void *MouseThread(void *arg); // Mouse reading thread
+static void InitKeyboard(void); // Init raw keyboard system (standard input reading)
+static void RestoreKeyboard(void); // Restore keyboard system
+static void InitGamepad(void); // Init raw gamepad input
+#endif
+
+#if defined(PLATFORM_DESKTOP)
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
-static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
-static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
-static void CursorEnterCallback(GLFWwindow* window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
-static void WindowSizeCallback(GLFWwindow* window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
+static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
+static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
+static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
+static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void TakeScreenshot(void); // Takes a screenshot and saves it in the same folder as executable
-static void LogoAnimation(void); // Plays raylib logo appearing animation
+#endif
+
+#if defined(PLATFORM_ANDROID)
+static int32_t InputCallback(struct android_app *app, AInputEvent *event); // Process Android activity input events
+static void CommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands
+#endif
//----------------------------------------------------------------------------------
// Module Functions Definition - Window and OpenGL Context Functions
//----------------------------------------------------------------------------------
-
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
// Initialize Window and Graphics Context (OpenGL)
void InitWindow(int width, int height, const char *title)
{
- InitWindowEx(width, height, title, true, NULL);
-}
+ // Store window title (could be useful...)
+ windowTitle = title;
-// Initialize Window and Graphics Context (OpenGL) with extended parameters
-void InitWindowEx(int width, int height, const char* title, bool resizable, const char *cursorImage)
-{
- glfwSetErrorCallback(ErrorCallback);
+ // Init device display (monitor, LCD, ...)
+ InitDisplay(width, height);
- if (!glfwInit()) TraceLog(ERROR, "Failed to initialize GLFW");
+ // Init OpenGL graphics
+ InitGraphics();
- //glfwDefaultWindowHints() // Set default windows hints
+ // Load default font for convenience
+ // NOTE: External function (defined in module: text)
+ LoadDefaultFont();
- if (!resizable) glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
+ // Init hi-res timer
+ InitTimer();
-#ifdef USE_OPENGL_33
- //glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
- glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
+#if defined(PLATFORM_RPI)
+ // Init raw input system
+ InitMouse(); // Mouse init
+ InitKeyboard(); // Keyboard init
+ InitGamepad(); // Gamepad init
#endif
+ mousePosition.x = screenWidth/2;
+ mousePosition.y = screenHeight/2;
- window = glfwCreateWindow(width, height, title, NULL, NULL);
-
- windowWidth = width;
- windowHeight = height;
- windowTitle = title;
-
- if (!window)
+ // raylib logo appearing animation (if enabled)
+ if (showLogo)
{
- glfwTerminate();
- TraceLog(ERROR, "Failed to initialize Window");
+ SetTargetFPS(60);
+ LogoAnimation();
}
+}
- glfwSetWindowSizeCallback(window, WindowSizeCallback);
- glfwSetCursorEnterCallback(window, CursorEnterCallback);
+#elif defined(PLATFORM_ANDROID)
+// Android activity initialization
+void InitWindow(int width, int height, struct android_app *state)
+{
+ app_dummy();
- glfwMakeContextCurrent(window);
- glfwSetKeyCallback(window, KeyCallback);
- glfwSetScrollCallback(window, ScrollCallback);
- glfwSwapInterval(0); // Disables GPU v-sync (if set), so frames are not limited to screen refresh rate (60Hz -> 60 FPS)
- // If not set, swap interval uses GPU v-sync configuration
- // Framerate can be setup using SetTargetFPS()
+ screenWidth = width;
+ screenHeight = height;
- //------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- rlglInit(); // Init rlgl
-#endif
- //------------------------------------------------------
+ app = state;
- int fbWidth, fbHeight;
- glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
+ // Set desired windows flags before initializing anything
+ ANativeActivity_setWindowFlags(app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
+ //ANativeActivity_setWindowFlags(app->activity, AWINDOW_FLAG_FORCE_NOT_FULLSCREEN, AWINDOW_FLAG_FULLSCREEN);
- //------------------------------------------------------
- rlglInitGraphicsDevice(fbWidth, fbHeight);
- //------------------------------------------------------
+ int orientation = AConfiguration_getOrientation(app->config);
- previousTime = glfwGetTime();
+ if (orientation == ACONFIGURATION_ORIENTATION_PORT) TraceLog(INFO, "PORTRAIT window orientation");
+ else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TraceLog(INFO, "LANDSCAPE window orientation");
- LoadDefaultFont(); // NOTE: External function (defined in module: text)
+ // TODO: Review, it doesn't work...
+ if (width <= height)
+ {
+ AConfiguration_setOrientation(app->config, ACONFIGURATION_ORIENTATION_PORT);
+ TraceLog(WARNING, "Window set to portraid mode");
+ }
+ else
+ {
+ AConfiguration_setOrientation(app->config, ACONFIGURATION_ORIENTATION_LAND);
+ TraceLog(WARNING, "Window set to landscape mode");
+ }
- if (cursorImage != NULL) SetCustomCursor(cursorImage);
+ //AConfiguration_getDensity(app->config);
+ //AConfiguration_getKeyboard(app->config);
+ //AConfiguration_getScreenSize(app->config);
+ //AConfiguration_getScreenLong(app->config);
- srand(time(NULL)); // Initialize random seed
+ //state->userData = &engine;
+ app->onAppCmd = CommandCallback;
+ app->onInputEvent = InputCallback;
- ClearBackground(RAYWHITE); // Default background color for raylib games :P
+ InitAssetManager(app->activity->assetManager);
- // raylib logo appearing animation
- if (showLogo)
+ TraceLog(INFO, "Android app initialized successfully");
+
+ while (!windowReady)
{
- SetTargetFPS(60);
- LogoAnimation();
+ // Wait for window to be initialized (display and context)
+ // Process events loop
+ while ((ident = ALooper_pollAll(0, NULL, &events,(void**)&source)) >= 0)
+ {
+ // Process this event
+ if (source != NULL) source->process(app, source);
+
+ // Check if we are exiting
+ if (app->destroyRequested != 0) windowShouldClose = true;
+ }
}
}
+#endif
// Close Window and Terminate Context
void CloseWindow(void)
{
UnloadDefaultFont();
- //------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- rlglClose(); // De-init rlgl
-#endif
- //------------------------------------------------------
+ rlglClose(); // De-init rlgl
+#if defined(PLATFORM_DESKTOP)
glfwDestroyWindow(window);
glfwTerminate();
+#elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ // Close surface, context and display
+ if (display != EGL_NO_DISPLAY)
+ {
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ if (surface != EGL_NO_SURFACE)
+ {
+ eglDestroySurface(display, surface);
+ surface = EGL_NO_SURFACE;
+ }
+
+ if (context != EGL_NO_CONTEXT)
+ {
+ eglDestroyContext(display, context);
+ context = EGL_NO_CONTEXT;
+ }
+
+ eglTerminate(display);
+ display = EGL_NO_DISPLAY;
+ }
+#endif
+
+ TraceLog(INFO, "Window closed successfully");
}
+// Detect if KEY_ESCAPE pressed or Close icon pressed
+bool WindowShouldClose(void)
+{
+#if defined(PLATFORM_DESKTOP)
+ return (glfwWindowShouldClose(window));
+#elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ return windowShouldClose;
+#endif
+}
+
+// Fullscreen toggle
+void ToggleFullscreen(void)
+{
+#if defined(PLATFORM_DESKTOP)
+ fullscreen = !fullscreen; // Toggle fullscreen flag
+
+ rlglClose(); // De-init rlgl
+ glfwDestroyWindow(window); // Destroy the current window (we will recreate it!)
+
+ InitWindow(screenWidth, screenHeight, windowTitle);
+#elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ TraceLog(WARNING, "Could not toggle to windowed mode");
+#endif
+}
+
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
// Set a custom cursor icon/image
void SetCustomCursor(const char *cursorImage)
{
@@ -211,7 +399,9 @@ void SetCustomCursor(const char *cursorImage)
cursor = LoadTexture(cursorImage);
+#if defined(PLATFORM_DESKTOP)
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+#endif
customCursor = true;
}
@@ -221,71 +411,31 @@ void SetExitKey(int key)
{
exitKey = key;
}
+#endif
-// Detect if KEY_ESCAPE pressed or Close icon pressed
-bool WindowShouldClose(void)
+// Get current screen width
+int GetScreenWidth(void)
{
- return (glfwWindowShouldClose(window));
+ return screenWidth;
}
-// Fullscreen toggle (by default F11)
-void ToggleFullscreen(void)
+// Get current screen height
+int GetScreenHeight(void)
{
- if (glfwGetKey(window, GLFW_KEY_F11))
- {
- fullscreen = !fullscreen; // Toggle fullscreen flag
-
- UnloadDefaultFont();
-
- glfwDestroyWindow(window); // Destroy the current window (we will recreate it!)
-
- // TODO: WARNING! All loaded resources are lost, we loose Context!
-
- // NOTE: Window aspect ratio is always windowWidth / windowHeight
- if (fullscreen)
- {
- // TODO: Get desktop window size and adapt aspect-ratio (?)
- //const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
- //windowWidth = mode->width;
- //windowHeight = mode->height;
-
- window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); // Fullscreen mode
- }
- else window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, NULL, NULL);
-
- if (!window)
- {
- glfwTerminate();
- TraceLog(ERROR, "Failed to initialize Window when switching fullscreen mode");
- }
-
- glfwMakeContextCurrent(window);
- glfwSetKeyCallback(window, KeyCallback);
-
- int fbWidth, fbHeight;
- glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
-
- rlglInitGraphicsDevice(fbWidth, fbHeight);
-
- LoadDefaultFont();
- }
+ return screenHeight;
}
// Sets Background Color
void ClearBackground(Color color)
{
- if ((color.r != background.r) || (color.g != background.g) || (color.b != background.b) || (color.a != background.a))
- {
- rlClearColor(color.r, color.g, color.b, color.a);
-
- background = color;
- }
+ // TODO: Review "clearing area", full framebuffer vs render area
+ rlClearColor(color.r, color.g, color.b, color.a);
}
// Setup drawing canvas to start drawing
void BeginDrawing(void)
{
- currentTime = glfwGetTime(); // glfwGetTime() returns a 'double' containing the number of elapsed seconds since glfwInit() was called
+ currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called
updateTime = currentTime - previousTime;
previousTime = currentTime;
@@ -293,40 +443,34 @@ void BeginDrawing(void)
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
-//#ifdef USE_OPENGL_11
-// rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL
+ rlMultMatrixf(GetMatrixVector(downscaleView)); // If downscale required, apply it here
+
+// rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL 1.1
// NOTE: Not required with OpenGL 3.3+
-//#endif
}
// End canvas drawing and Swap Buffers (Double Buffering)
void EndDrawing(void)
{
- if (customCursor && cursorOnScreen) DrawTexture(cursor, GetMouseX(), GetMouseY(), WHITE);
-
- //------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- rlglDraw(); // Draw Buffers
-#endif
- //------------------------------------------------------
+ rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
- glfwSwapBuffers(window); // Swap back and front buffers
- glfwPollEvents(); // Register keyboard/mouse events
+ SwapBuffers(); // Copy back buffer to front buffer
+ PollInputEvents(); // Poll user events
- UpdateMusicStream(); // NOTE: Function checks if music is enabled
+ UpdateMusicStream(); // NOTE: Function checks if music is enabled
- currentTime = glfwGetTime();
+ currentTime = GetTime();
drawTime = currentTime - previousTime;
previousTime = currentTime;
frameTime = updateTime + drawTime;
- double extraTime = 0;
+ double extraTime = 0.0;
while (frameTime < targetTime)
{
// Implement a delay
- currentTime = glfwGetTime();
+ currentTime = GetTime();
extraTime = currentTime - previousTime;
previousTime = currentTime;
frameTime += extraTime;
@@ -336,11 +480,7 @@ void EndDrawing(void)
// Initializes 3D mode for drawing (Camera setup)
void Begin3dMode(Camera camera)
{
- //------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- rlglDraw(); // Draw Buffers
-#endif
- //------------------------------------------------------
+ rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
@@ -348,11 +488,11 @@ void Begin3dMode(Camera camera)
rlLoadIdentity(); // Reset current matrix (PROJECTION)
// Setup perspective projection
- float aspect = (GLfloat)windowWidth/(GLfloat)windowHeight;
- double top = 0.1f*tan(45.0f*PI / 360.0);
+ float aspect = (GLfloat)screenWidth/(GLfloat)screenHeight;
+ double top = 0.1f*tan(45.0f*PI / 360.0f);
double right = top*aspect;
- rlFrustum(-right, right, -top, top, 0.1f, 100.0f);
+ rlFrustum(-right, right, -top, top, 0.1f, 1000.0f);
rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
@@ -365,11 +505,7 @@ void Begin3dMode(Camera camera)
// Ends 3D mode and returns to default 2D orthographic mode
void End3dMode(void)
{
- //------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- rlglDraw(); // Draw Buffers
-#endif
- //------------------------------------------------------
+ rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack
@@ -440,8 +576,8 @@ int GetRandomValue(int min, int max)
// Fades color by a percentadge
Color Fade(Color color, float alpha)
{
- if (alpha < 0.0) alpha = 0.0;
- else if (alpha > 1.0) alpha = 1.0;
+ if (alpha < 0.0f) alpha = 0.0f;
+ else if (alpha > 1.0f) alpha = 1.0f;
return (Color){color.r, color.g, color.b, color.a*alpha};
}
@@ -455,7 +591,7 @@ void ShowLogo(void)
//----------------------------------------------------------------------------------
// Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions
//----------------------------------------------------------------------------------
-
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
// Detect if a key has been pressed once
bool IsKeyPressed(int key)
{
@@ -476,7 +612,7 @@ bool IsKeyPressed(int key)
// Detect if a key is being pressed (key held down)
bool IsKeyDown(int key)
{
- if (glfwGetKey(window, key) == GLFW_PRESS) return true;
+ if (GetKeyStatus(key) == 1) return true;
else return false;
}
@@ -500,7 +636,7 @@ bool IsKeyReleased(int key)
// Detect if a key is NOT being pressed (key not held down)
bool IsKeyUp(int key)
{
- if (glfwGetKey(window, key) == GLFW_RELEASE) return true;
+ if (GetKeyStatus(key) == 0) return true;
else return false;
}
@@ -524,7 +660,7 @@ bool IsMouseButtonPressed(int button)
// Detect if a mouse button is being pressed
bool IsMouseButtonDown(int button)
{
- if (glfwGetMouseButton(window, button) == GLFW_PRESS) return true;
+ if (GetMouseButtonStatus(button) == 1) return true;
else return false;
}
@@ -548,43 +684,26 @@ bool IsMouseButtonReleased(int button)
// Detect if a mouse button is NOT being pressed
bool IsMouseButtonUp(int button)
{
- if (glfwGetMouseButton(window, button) == GLFW_RELEASE) return true;
+ if (GetMouseButtonStatus(button) == 0) return true;
else return false;
}
// Returns mouse position X
int GetMouseX(void)
{
- double mouseX;
- double mouseY;
-
- glfwGetCursorPos(window, &mouseX, &mouseY);
-
- return (int)mouseX;
+ return (int)mousePosition.x;
}
// Returns mouse position Y
int GetMouseY(void)
{
- double mouseX;
- double mouseY;
-
- glfwGetCursorPos(window, &mouseX, &mouseY);
-
- return (int)mouseY;
+ return (int)mousePosition.y;
}
// Returns mouse position XY
Vector2 GetMousePosition(void)
{
- double mouseX;
- double mouseY;
-
- glfwGetCursorPos(window, &mouseX, &mouseY);
-
- Vector2 position = { (float)mouseX, (float)mouseY };
-
- return position;
+ return mousePosition;
}
// Returns mouse wheel movement Y
@@ -596,7 +715,10 @@ int GetMouseWheelMove(void)
return previousMouseWheelY;
}
+#endif
+// TODO: Enable gamepad usage on Rapsberr Pi
+#if defined(PLATFORM_DESKTOP)
// Detect if a gamepad is available
bool IsGamepadAvailable(int gamepad)
{
@@ -628,7 +750,7 @@ Vector2 GetGamepadMovement(int gamepad)
return vec;
}
-// Detect if a gamepad button is being pressed
+// Detect if a gamepad button has been pressed once
bool IsGamepadButtonPressed(int gamepad, int button)
{
bool pressed = false;
@@ -645,9 +767,10 @@ bool IsGamepadButtonPressed(int gamepad, int button)
return pressed;
}
+// Detect if a gamepad button is being pressed
bool IsGamepadButtonDown(int gamepad, int button)
{
- const unsigned char* buttons;
+ const unsigned char *buttons;
int buttonsCount;
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
@@ -659,7 +782,7 @@ bool IsGamepadButtonDown(int gamepad, int button)
else return false;
}
-// Detect if a gamepad button is NOT being pressed
+// Detect if a gamepad button has NOT been pressed once
bool IsGamepadButtonReleased(int gamepad, int button)
{
bool released = false;
@@ -676,9 +799,10 @@ bool IsGamepadButtonReleased(int gamepad, int button)
return released;
}
+// Detect if a mouse button is NOT being pressed
bool IsGamepadButtonUp(int gamepad, int button)
{
- const unsigned char* buttons;
+ const unsigned char *buttons;
int buttonsCount;
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
@@ -689,11 +813,276 @@ bool IsGamepadButtonUp(int gamepad, int button)
}
else return false;
}
+#endif
+
+#if defined(PLATFORM_ANDROID)
+// Returns touch position X
+int GetTouchX(void)
+{
+ return (int)touchX;
+}
+
+// Returns touch position Y
+int GetTouchY(void)
+{
+ return (int)touchY;
+}
+
+// Returns touch position XY
+Vector2 GetTouchPosition(void)
+{
+ Vector2 position = { touchX, touchY };
+
+ return position;
+}
+#endif
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
+// Initialize display device and framebuffer
+// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size
+// If width or height are 0, default display size will be used for framebuffer size
+static void InitDisplay(int width, int height)
+{
+ screenWidth = width; // User desired width
+ screenHeight = height; // User desired height
+
+ // NOTE: Framebuffer (render area - renderWidth, renderHeight) could include black bars...
+ // ...in top-down or left-right to match display aspect ratio (no weird scalings)
+
+ // Downscale matrix is required in case desired screen area is bigger than display area
+ downscaleView = MatrixIdentity();
+
+#if defined(PLATFORM_DESKTOP)
+ glfwSetErrorCallback(ErrorCallback);
+
+ if (!glfwInit()) TraceLog(ERROR, "Failed to initialize GLFW");
+
+ // Find monitor resolution
+ const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
+
+ displayWidth = mode->width;
+ displayHeight = mode->height;
+
+ // Screen size security check
+ if (screenWidth <= 0) screenWidth = displayWidth;
+ if (screenHeight <= 0) screenHeight = displayHeight;
+
+ glfwDefaultWindowHints(); // Set default windows hints
+
+ glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
+ //glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window
+ //glfwWindowHint(GLFW_RED_BITS, 8); // Bit depths of color components for default framebuffer
+ //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window
+ //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // Default OpenGL API to use. Alternative: GLFW_OPENGL_ES_API
+ //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers
+
+ // NOTE: When asking for an OpenGL context version, most drivers provide highest supported version
+ // with forward compatibility to older OpenGL versions.
+ // For example, if using OpenGL 1.1, driver can provide a 3.3 context fordward compatible.
+
+ if (rlGetVersion() == OPENGL_33)
+ {
+ //glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.2 and above!
+ // Other values: GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); // Fordward Compatibility Hint: Only 3.0 and above!
+ }
+
+ if (fullscreen)
+ {
+ // At this point we need to manage render size vs screen size
+ // NOTE: This function use and modify global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView
+ SetupFramebufferSize(displayWidth, displayHeight);
+
+ window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, glfwGetPrimaryMonitor(), NULL);
+ }
+ else
+ {
+ // No-fullscreen window creation
+ window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, NULL, NULL);
+
+ renderWidth = screenWidth;
+ renderHeight = screenHeight;
+ }
+
+ if (!window)
+ {
+ glfwTerminate();
+ TraceLog(ERROR, "GLFW Failed to initialize Window");
+ }
+ else
+ {
+ TraceLog(INFO, "Display device initialized successfully");
+ TraceLog(INFO, "Display size: %i x %i", displayWidth, displayHeight);
+ TraceLog(INFO, "Render size: %i x %i", renderWidth, renderHeight);
+ TraceLog(INFO, "Screen size: %i x %i", screenWidth, screenHeight);
+ TraceLog(INFO, "Viewport offsets: %i, %i", renderOffsetX, renderOffsetY);
+ }
+
+ glfwSetWindowSizeCallback(window, WindowSizeCallback);
+ glfwSetCursorEnterCallback(window, CursorEnterCallback);
+ glfwSetKeyCallback(window, KeyCallback);
+ glfwSetScrollCallback(window, ScrollCallback);
+
+ glfwMakeContextCurrent(window);
+
+ //glfwSwapInterval(0); // Disables GPU v-sync (if set), so frames are not limited to screen refresh rate (60Hz -> 60 FPS)
+ // If not set, swap interval uses GPU v-sync configuration
+ // Framerate can be setup using SetTargetFPS()
+
+ //glfwGetFramebufferSize(window, &renderWidth, &renderHeight); // Get framebuffer size of current window
+
+#elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ fullscreen = true;
+
+ // Screen size security check
+ if (screenWidth <= 0) screenWidth = displayWidth;
+ if (screenHeight <= 0) screenHeight = displayHeight;
+
+#if defined(PLATFORM_RPI)
+ bcm_host_init();
+
+ DISPMANX_ELEMENT_HANDLE_T dispmanElement;
+ DISPMANX_DISPLAY_HANDLE_T dispmanDisplay;
+ DISPMANX_UPDATE_HANDLE_T dispmanUpdate;
+ VC_RECT_T dstRect;
+ VC_RECT_T srcRect;
+#endif
+
+ const EGLint framebufferAttribs[] =
+ {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Type of context support -> Required on RPI?
+ //EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android!
+ EGL_BLUE_SIZE, 8, // Alternative: 5
+ EGL_GREEN_SIZE, 8, // Alternative: 6
+ EGL_RED_SIZE, 8, // Alternative: 5
+ //EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 8, // NOTE: Required to use Depth testing!
+ //EGL_SAMPLES, 4, // 4x Antialiasing (Free on MALI GPUs)
+ EGL_NONE
+ };
+
+ EGLint contextAttribs[] =
+ {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ EGLint numConfigs;
+ EGLConfig config;
+
+ // Get an EGL display connection
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ // Initialize the EGL display connection
+ eglInitialize(display, NULL, NULL);
+
+ // Get an appropriate EGL framebuffer configuration
+ eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs);
+
+ // Set rendering API
+ eglBindAPI(EGL_OPENGL_ES_API);
+
+ // Create an EGL rendering context
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+
+ // Create an EGL window surface
+ //---------------------------------------------------------------------------------
+#if defined(PLATFORM_ANDROID)
+ EGLint displayFormat;
+
+ displayWidth = ANativeWindow_getWidth(app->window);
+ displayHeight = ANativeWindow_getHeight(app->window);
+
+ // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry()
+ // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
+ eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &displayFormat);
+
+ // At this point we need to manage render size vs screen size
+ // NOTE: This function use and modify global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView
+ SetupFramebufferSize(displayWidth, displayHeight);
+
+ ANativeWindow_setBuffersGeometry(app->window, renderWidth, renderHeight, displayFormat);
+ //ANativeWindow_setBuffersGeometry(app->window, 0, 0, displayFormat); // Force use of native display size
+
+ surface = eglCreateWindowSurface(display, config, app->window, NULL);
+
+#elif defined(PLATFORM_RPI)
+ graphics_get_display_size(0, &displayWidth, &displayHeight);
+
+ // At this point we need to manage render size vs screen size
+ // NOTE: This function use and modify global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView
+ SetupFramebufferSize(displayWidth, displayHeight);
+
+ dstRect.x = 0;
+ dstRect.y = 0;
+ dstRect.width = displayWidth;
+ dstRect.height = displayHeight;
+
+ srcRect.x = 0;
+ srcRect.y = 0;
+ srcRect.width = renderWidth << 16;
+ srcRect.height = renderHeight << 16;
+
+ // NOTE: RPI dispmanx windowing system takes care of srcRec scaling to dstRec by hardware (no cost)
+ // Take care that renderWidth/renderHeight fit on displayWidth/displayHeight aspect ratio
+
+ dispmanDisplay = vc_dispmanx_display_open(0);
+ dispmanUpdate = vc_dispmanx_update_start(0);
+
+ dispmanElement = vc_dispmanx_element_add(dispmanUpdate, dispmanDisplay, 0/*layer*/, &dstRect, 0/*src*/,
+ &srcRect, DISPMANX_PROTECTION_NONE, 0/*alpha*/, 0/*clamp*/, 0/*transform*/);
+
+ nativeWindow.element = dispmanElement;
+ nativeWindow.width = renderWidth;
+ nativeWindow.height = renderHeight;
+ vc_dispmanx_update_submit_sync(dispmanUpdate);
+
+ surface = eglCreateWindowSurface(display, config, &nativeWindow, NULL);
+ //---------------------------------------------------------------------------------
+#endif
+ // There must be at least one frame displayed before the buffers are swapped
+ //eglSwapInterval(display, 1);
+
+ if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
+ {
+ TraceLog(ERROR, "Unable to attach EGL rendering context to EGL surface");
+ }
+ else
+ {
+ // Grab the width and height of the surface
+ //eglQuerySurface(display, surface, EGL_WIDTH, &renderWidth);
+ //eglQuerySurface(display, surface, EGL_HEIGHT, &renderHeight);
+
+ TraceLog(INFO, "Display device initialized successfully");
+ TraceLog(INFO, "Display size: %i x %i", displayWidth, displayHeight);
+ TraceLog(INFO, "Render size: %i x %i", renderWidth, renderHeight);
+ TraceLog(INFO, "Screen size: %i x %i", screenWidth, screenHeight);
+ TraceLog(INFO, "Viewport offsets: %i, %i", renderOffsetX, renderOffsetY);
+ }
+#endif
+}
+
+// Initialize OpenGL graphics
+void InitGraphics(void)
+{
+ rlglInit(); // Init rlgl
+
+ rlglInitGraphics(renderOffsetX, renderOffsetY, renderWidth, renderHeight); // Init graphics (OpenGL stuff)
+
+ ClearBackground(RAYWHITE); // Default background color for raylib games :P
+
+#if defined(PLATFORM_ANDROID)
+ windowReady = true; // IMPORTANT!
+#endif
+}
+
+#if defined(PLATFORM_DESKTOP)
// GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback(int error, const char *description)
{
@@ -701,13 +1090,13 @@ static void ErrorCallback(int error, const char *description)
}
// GLFW3 Srolling Callback, runs on mouse wheel
-static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
+static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset)
{
currentMouseWheelY = (int)yoffset;
}
// GLFW3 Keyboard Callback, runs on key pressed
-static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
+static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if (key == exitKey && action == GLFW_PRESS)
{
@@ -715,54 +1104,179 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i
// NOTE: Before closing window, while loop must be left!
}
- else if (key == GLFW_KEY_F11 && action == GLFW_PRESS)
- {
- ToggleFullscreen();
- }
else if (key == GLFW_KEY_F12 && action == GLFW_PRESS)
{
TakeScreenshot();
}
}
-static void CursorEnterCallback(GLFWwindow* window, int enter)
+// GLFW3 CursorEnter Callback, when cursor enters the window
+static void CursorEnterCallback(GLFWwindow *window, int enter)
{
- if (enter == GL_TRUE) cursorOnScreen = true;
+ if (enter == true) cursorOnScreen = true;
else cursorOnScreen = false;
}
// GLFW3 WindowSize Callback, runs when window is resized
-static void WindowSizeCallback(GLFWwindow* window, int width, int height)
+static void WindowSizeCallback(GLFWwindow *window, int width, int height)
{
- int fbWidth, fbHeight;
- glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
-
// If window is resized, graphics device is re-initialized (but only ortho mode)
- rlglInitGraphicsDevice(fbWidth, fbHeight);
+ rlglInitGraphics(0, 0, width, height);
// Window size must be updated to be used on 3D mode to get new aspect ratio (Begin3dMode())
- windowWidth = fbWidth;
- windowHeight = fbHeight;
+ screenWidth = width;
+ screenHeight = height;
+
+ // TODO: Update render size?
// Background must be also re-cleared
- rlClearColor(background.r, background.g, background.b, background.a);
+ ClearBackground(RAYWHITE);
+}
+#endif
+
+#if defined(PLATFORM_ANDROID)
+// Android: Process activity input events
+static int32_t InputCallback(struct android_app *app, AInputEvent *event)
+{
+ int type = AInputEvent_getType(event);
+ //int32_t key = 0;
+
+ if (type == AINPUT_EVENT_TYPE_MOTION)
+ {
+ if ((screenWidth > displayWidth) || (screenHeight > displayHeight))
+ {
+ // TODO: Seems to work ok but... review!
+ touchX = AMotionEvent_getX(event, 0) * ((float)screenWidth / (float)(displayWidth - renderOffsetX)) - renderOffsetX/2;
+ touchY = AMotionEvent_getY(event, 0) * ((float)screenHeight / (float)(displayHeight - renderOffsetY)) - renderOffsetY/2;
+ }
+ else
+ {
+ touchX = AMotionEvent_getX(event, 0) * ((float)renderWidth / (float)displayWidth) - renderOffsetX/2;
+ touchY = AMotionEvent_getY(event, 0) * ((float)renderHeight / (float)displayHeight) - renderOffsetY/2;
+ }
+
+ //float AMotionEvent_getX(event, size_t pointer_index);
+ //int32_t AMotionEvent_getButtonState(event); // Pressed buttons
+ //int32_t AMotionEvent_getPointerId(event, size_t pointer_index);
+ //size_t pointerCount = AMotionEvent_getPointerCount(event);
+ //float AMotionEvent_getPressure(const AInputEvent *motion_event, size_t pointer_index); // 0 to 1
+ //float AMotionEvent_getSize(const AInputEvent *motion_event, size_t pointer_index); // Pressed area
+
+ return 1;
+ }
+ else if (type == AINPUT_EVENT_TYPE_KEY)
+ {
+ //key = AKeyEvent_getKeyCode(event);
+ //int32_t AKeyEvent_getMetaState(event);
+ }
+
+ return 0;
}
-// Takes a bitmap (BMP) screenshot and saves it in the same folder as executable
+// Android: Process activity lifecycle commands
+static void CommandCallback(struct android_app *app, int32_t cmd)
+{
+ switch (cmd)
+ {
+ case APP_CMD_START:
+ {
+ //rendering = true;
+ TraceLog(INFO, "APP_CMD_START");
+ } break;
+ case APP_CMD_RESUME:
+ {
+ TraceLog(INFO, "APP_CMD_RESUME");
+ } break;
+ case APP_CMD_INIT_WINDOW:
+ {
+ TraceLog(INFO, "APP_CMD_INIT_WINDOW");
+
+ if (app->window != NULL)
+ {
+ // Init device display (monitor, LCD, ...)
+ InitDisplay(screenWidth, screenHeight);
+
+ // Init OpenGL graphics
+ InitGraphics();
+
+ // Load default font for convenience
+ // NOTE: External function (defined in module: text)
+ LoadDefaultFont();
+
+ // Init hi-res timer
+ InitTimer();
+
+ // raylib logo appearing animation (if enabled)
+ if (showLogo)
+ {
+ SetTargetFPS(60);
+ LogoAnimation();
+ }
+ }
+ } break;
+ case APP_CMD_GAINED_FOCUS:
+ {
+ TraceLog(INFO, "APP_CMD_GAINED_FOCUS");
+ ResumeMusicStream();
+ } break;
+ case APP_CMD_PAUSE:
+ {
+ TraceLog(INFO, "APP_CMD_PAUSE");
+ } break;
+ case APP_CMD_LOST_FOCUS:
+ {
+ //DrawFrame();
+ TraceLog(INFO, "APP_CMD_LOST_FOCUS");
+ PauseMusicStream();
+ } break;
+ case APP_CMD_TERM_WINDOW:
+ {
+ // TODO: Do display destruction here? -> Yes but only display, don't free buffers!
+
+ TraceLog(INFO, "APP_CMD_TERM_WINDOW");
+ } break;
+ case APP_CMD_SAVE_STATE:
+ {
+ TraceLog(INFO, "APP_CMD_SAVE_STATE");
+ } break;
+ case APP_CMD_STOP:
+ {
+ TraceLog(INFO, "APP_CMD_STOP");
+ } break;
+ case APP_CMD_DESTROY:
+ {
+ // TODO: Finish activity?
+ //ANativeActivity_finish(app->activity);
+
+ TraceLog(INFO, "APP_CMD_DESTROY");
+ } break;
+ case APP_CMD_CONFIG_CHANGED:
+ {
+ //AConfiguration_fromAssetManager(app->config, app->activity->assetManager);
+ //print_cur_config(app);
+
+ // Check screen orientation here!
+
+ TraceLog(INFO, "APP_CMD_CONFIG_CHANGED");
+ } break;
+ default: break;
+ }
+}
+#endif
+
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
+// Takes a screenshot and saves it in the same folder as executable
static void TakeScreenshot(void)
{
static int shotNum = 0; // Screenshot number, increments every screenshot take during program execution
-
char buffer[20]; // Buffer to store file name
- int fbWidth, fbHeight; // Frame buffer width and height
- glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
-
- unsigned char *imgData = rlglReadScreenPixels(fbWidth, fbHeight);
+ unsigned char *imgData = rlglReadScreenPixels(renderWidth, renderHeight);
sprintf(buffer, "screenshot%03i.png", shotNum);
- WritePNG(buffer, imgData, fbWidth, fbHeight);
+ // Save image as PNG
+ WritePNG(buffer, imgData, renderWidth, renderHeight);
free(imgData);
@@ -770,11 +1284,447 @@ static void TakeScreenshot(void)
TraceLog(INFO, "[%s] Screenshot taken!", buffer);
}
+#endif
+
+// Initialize hi-resolution timer
+static void InitTimer(void)
+{
+ srand(time(NULL)); // Initialize random seed
+
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ struct timespec now;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
+ {
+ baseTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec;
+ }
+ else TraceLog(WARNING, "No hi-resolution timer available");
+#endif
+
+ previousTime = GetTime(); // Get time as double
+}
+
+// Get current time measure since InitTimer()
+static double GetTime(void)
+{
+#if defined(PLATFORM_DESKTOP)
+ return glfwGetTime();
+#elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ uint64_t time = ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec;
+
+ return (double)(time - baseTime) * 1e-9;
+#endif
+}
+
+// Get one key state
+static bool GetKeyStatus(int key)
+{
+#if defined(PLATFORM_DESKTOP)
+ return glfwGetKey(window, key);
+#elif defined(PLATFORM_ANDROID)
+ // TODO: Check virtual keyboard (?)
+ return false;
+#elif defined(PLATFORM_RPI)
+ // NOTE: Keys states are filled in PollInputEvents()
+ if (key < 0 || key > 511) return false;
+ else return currentKeyState[key];
+#endif
+}
+
+// Get one mouse button state
+static bool GetMouseButtonStatus(int button)
+{
+#if defined(PLATFORM_DESKTOP)
+ return glfwGetMouseButton(window, button);
+#elif defined(PLATFORM_ANDROID)
+ // TODO: Check virtual keyboard (?)
+ return false;
+#elif defined(PLATFORM_RPI)
+ // NOTE: mouse buttons array is filled on PollInputEvents()
+ return currentMouseState[button];
+#endif
+}
+
+// Poll (store) all input events
+static void PollInputEvents(void)
+{
+#if defined(PLATFORM_DESKTOP)
+ // Mouse input polling
+ double mouseX;
+ double mouseY;
+
+ glfwGetCursorPos(window, &mouseX, &mouseY);
+
+ mousePosition.x = (float)mouseX;
+ mousePosition.y = (float)mouseY;
+
+ // Keyboard polling
+ // Automatically managed by GLFW3 through callback
+
+ glfwPollEvents(); // Register keyboard/mouse events
+#elif defined(PLATFORM_ANDROID)
+
+ // TODO: Check virtual keyboard (?)
+
+ // Poll Events (registered events)
+ while ((ident = ALooper_pollAll(0, NULL, &events,(void**)&source)) >= 0)
+ {
+ // Process this event
+ if (source != NULL) source->process(app, source);
+
+ // Check if we are exiting
+ if (app->destroyRequested != 0)
+ {
+ TraceLog(INFO, "Closing Window...");
+ //CloseWindow();
+ windowShouldClose = true;
+ //ANativeActivity_finish(app->activity);
+ }
+ }
+#elif defined(PLATFORM_RPI)
+
+ // NOTE: Mouse input events polling is done asynchonously in another pthread - MouseThread()
+
+ // NOTE: Keyboard reading could be done using input_event(s) reading or just read from stdin,
+ // we use method 2 (stdin) but maybe in a future we should change to method 1...
+
+ // Keyboard input polling (fill keys[256] array with status)
+ int numKeysBuffer = 0; // Keys available on buffer
+ char keysBuffer[32]; // Max keys to be read at a time
+
+ // Reset pressed keys array
+ for (int i = 0; i < 512; i++) currentKeyState[i] = 0;
+
+ // Read availables keycodes from stdin
+ numKeysBuffer = read(STDIN_FILENO, keysBuffer, 32); // POSIX system call
+
+ // Fill array with pressed keys
+ for (int i = 0; i < numKeysBuffer; i++)
+ {
+ //TraceLog(INFO, "Bytes on keysBuffer: %i", numKeysBuffer);
+
+ int key = keysBuffer[i];
+
+ if (keyboardMode == 2)
+ {
+ // NOTE: If (key == 0x1b), depending on next key, it could be a special keymap code!
+ // Up -> 1b 5b 41 / Left -> 1b 5b 44 / Right -> 1b 5b 43 / Down -> 1b 5b 42
+ if (key == 0x1b)
+ {
+ if (keysBuffer[i+1] == 0x5b) // Special function key
+ {
+ switch (keysBuffer[i+2])
+ {
+ case 0x41: currentKeyState[265] = 1; break;
+ case 0x42: currentKeyState[264] = 1; break;
+ case 0x43: currentKeyState[262] = 1; break;
+ case 0x44: currentKeyState[263] = 1; break;
+ default: break;
+ }
+
+ i += 2; // Jump to next key
+
+ // NOTE: Other special function keys (F1, F2...) are not contempled for this keyboardMode...
+ // ...or they are just not directly keymapped (CTRL, ALT, SHIFT)
+ }
+ }
+ else if (key == 0x0a) currentKeyState[257] = 1; // raylib KEY_ENTER (don't mix with <linux/input.h> KEY_*)
+ else if (key == 0x7f) currentKeyState[259] = 1;
+ else
+ {
+ TraceLog(INFO, "Pressed key (ASCII): 0x%02x", key);
+
+ currentKeyState[key] = 1;
+ }
+
+ // Detect ESC to stop program
+ if ((key == 0x1b) && (numKeysBuffer == 1)) windowShouldClose = true;
+ }
+ else if (keyboardMode == 1)
+ {
+ TraceLog(INFO, "Pressed key (keycode): 0x%02x", key);
+
+ int asciiKey = -1;
+
+ // Convert keycode to some recognized key (ASCII or GLFW3 equivalent)
+ if (key < 128) asciiKey = (int)UnixKeycodeToASCII[key];
+
+ // Record equivalent key state
+ if ((asciiKey >= 0) && (asciiKey < 512)) currentKeyState[asciiKey] = 1;
+
+ // In case of letter, we also activate lower case version
+ if ((asciiKey >= 65) && (asciiKey <=90)) currentKeyState[asciiKey + 32] = 1;
+
+ // Detect KEY_ESC to stop program
+ if (key == 0x01) windowShouldClose = true;
+ }
+
+
+ // Same fucnionality as GLFW3 KeyCallback()
+ /*
+ if (asciiKey == exitKey) windowShouldClose = true;
+ else if (key == GLFW_KEY_F12 && action == GLFW_PRESS)
+ {
+ TakeScreenshot();
+ }
+ */
+ }
+
+ // TODO: Gamepad support (use events, easy!)
+/*
+ struct js_event gamepadEvent;
+
+ read(gamepadStream, &gamepadEvent, sizeof(struct js_event));
+
+ if (gamepadEvent.type == JS_EVENT_BUTTON)
+ {
+ switch (gamepadEvent.number)
+ {
+ case 0: // 1st Axis X
+ case 1: // 1st Axis Y
+ case 2: // 2st Axis X
+ case 3: // 2st Axis Y
+ case 4:
+ {
+ if (gamepadEvent.value == 1) // Button pressed, 0 release
+
+ } break;
+ // Buttons is similar, variable for every joystick
+ }
+ }
+ else if (gamepadEvent.type == JS_EVENT_AXIS)
+ {
+ switch (gamepadEvent.number)
+ {
+ case 0: // 1st Axis X
+ case 1: // 1st Axis Y
+ case 2: // 2st Axis X
+ case 3: // 2st Axis Y
+ // Buttons is similar, variable for every joystick
+ }
+ }
+*/
+#endif
+}
-static void LogoAnimation()
+#if defined(PLATFORM_RPI)
+// Mouse initialization (including mouse thread)
+static void InitMouse(void)
{
- int logoPositionX = windowWidth/2 - 128;
- int logoPositionY = windowHeight/2 - 128;
+ // NOTE: We can use /dev/input/mice to read from all available mice
+ if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Could not open mouse device, no mouse available");
+ else
+ {
+ mouseReady = true;
+
+ int err = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL);
+
+ if (err != 0) TraceLog(WARNING, "Error creating mouse input event thread");
+ else TraceLog(INFO, "Mouse device initialized successfully");
+ }
+}
+
+// Mouse reading thread
+// NOTE: We need a separate thread to avoid loosing mouse events,
+// if too much time passes between reads, queue gets full and new events override older wants...
+static void *MouseThread(void *arg)
+{
+ struct input_event mouseEvent;
+
+ while(1)
+ {
+ // NOTE: read() will return -1 if the events queue is empty
+ read(mouseStream, &mouseEvent, sizeof(struct input_event));
+
+ // Check event types
+ if (mouseEvent.type == EV_REL) // Relative motion event
+ {
+ if (mouseEvent.code == REL_X)
+ {
+ mousePosition.x += (float)mouseEvent.value;
+
+ // Screen limits X check
+ if (mousePosition.x < 0) mousePosition.x = 0;
+ if (mousePosition.x > screenWidth) mousePosition.x = screenWidth;
+ }
+
+ if (mouseEvent.code == REL_Y)
+ {
+ mousePosition.y += (float)mouseEvent.value;
+
+ // Screen limits Y check
+ if (mousePosition.y < 0) mousePosition.y = 0;
+ if (mousePosition.y > screenHeight) mousePosition.y = screenHeight;
+ }
+
+ if (mouseEvent.code == REL_WHEEL)
+ {
+ // mouseEvent.value give 1 or -1 (direction)
+ }
+ }
+ else if (mouseEvent.type == EV_KEY) // Mouse button event
+ {
+ if (mouseEvent.code == BTN_LEFT) currentMouseState[0] = mouseEvent.value;
+ if (mouseEvent.code == BTN_RIGHT) currentMouseState[1] = mouseEvent.value;
+ if (mouseEvent.code == BTN_MIDDLE) currentMouseState[2] = mouseEvent.value;
+ }
+ }
+
+ return NULL;
+}
+
+// Initialize Keyboard system (using standard input)
+static void InitKeyboard(void)
+{
+ // NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor
+
+ // Make stdin non-blocking (not enough, need to configure to non-canonical mode)
+ int flags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags
+ fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified
+
+ // Save terminal keyboard settings and reconfigure terminal with new settings
+ struct termios keyboardNewSettings;
+ tcgetattr(STDIN_FILENO, &defaultKeyboardSettings); // Get current keyboard settings
+ keyboardNewSettings = defaultKeyboardSettings;
+
+ // New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
+ // NOTE: ISIG controls if ^C and ^Z generate break signals or not
+ keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
+ //keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
+ keyboardNewSettings.c_cc[VMIN] = 1;
+ keyboardNewSettings.c_cc[VTIME] = 0;
+
+ // Set new keyboard settings (change occurs immediately)
+ tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings);
+
+ // NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE, we change that!
+
+ // Save old keyboard mode to restore it at the end
+ if (ioctl(STDIN_FILENO, KDGKBMODE, &defaultKeyboardMode) < 0)
+ {
+ // NOTE: It could mean we are using a remote keyboard through ssh!
+ TraceLog(WARNING, "Could not change keyboard mode (SSH keyboard?)");
+
+ keyboardMode = 2; // ASCII
+ }
+ else
+ {
+ // We reconfigure keyboard mode to get scancodes (K_RAW) or keycodes (K_MEDIUMRAW)
+ ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW); // ASCII chars (K_XLATE), UNICODE chars (K_UNICODE)
+
+ keyboardMode = 1; // keycodes
+ }
+
+ // Register keyboard restore when program finishes
+ atexit(RestoreKeyboard);
+}
+
+// Restore default keyboard input
+static void RestoreKeyboard(void)
+{
+ tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings);
+ ioctl(STDIN_FILENO, KDSKBMODE, defaultKeyboardMode);
+}
+
+// Init gamepad system
+static void InitGamepad(void)
+{
+ // TODO: Gamepad support
+ if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Could not open gamepad device, no gamepad available");
+ else TraceLog(INFO, "Gamepad device initialized successfully");
+}
+#endif
+
+// Copy back buffer to front buffers
+static void SwapBuffers(void)
+{
+#if defined(PLATFORM_DESKTOP)
+ glfwSwapBuffers(window);
+#elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ eglSwapBuffers(display, surface);
+#endif
+}
+
+// Compute framebuffer size relative to screen size and display size
+// NOTE: Global variables renderWidth/renderHeight can be modified
+static void SetupFramebufferSize(int displayWidth, int displayHeight)
+{
+ // Calculate renderWidth and renderHeight, we have the display size (input params) and the desired screen size (global var)
+ if ((screenWidth > displayWidth) || (screenHeight > displayHeight))
+ {
+ TraceLog(WARNING, "DOWNSCALING: Required screen size (%i x %i) is bigger than display size (%i x %i)", screenWidth, screenHeight, displayWidth, displayHeight);
+
+ // Downscaling to fit display with border-bars
+ float widthRatio = (float)displayWidth/(float)screenWidth;
+ float heightRatio = (float)displayHeight/(float)screenHeight;
+
+ if (widthRatio <= heightRatio)
+ {
+ renderWidth = displayWidth;
+ renderHeight = (int)((float)screenHeight*widthRatio);
+ renderOffsetX = 0;
+ renderOffsetY = (displayHeight - renderHeight);
+ }
+ else
+ {
+ renderWidth = (int)((float)screenWidth*heightRatio);
+ renderHeight = displayHeight;
+ renderOffsetX = (displayWidth - renderWidth);
+ renderOffsetY = 0;
+ }
+
+ // NOTE: downscale matrix required!
+ float scaleRatio = (float)renderWidth/(float)screenWidth;
+
+ downscaleView = MatrixScale(scaleRatio, scaleRatio, scaleRatio);
+
+ // NOTE: We render to full display resolution!
+ // We just need to calculate above parameters for downscale matrix and offsets
+ renderWidth = displayWidth;
+ renderHeight = displayHeight;
+
+ TraceLog(WARNING, "Downscale matrix generated, content will be rendered at: %i x %i", renderWidth, renderHeight);
+ }
+ else if ((screenWidth < displayWidth) || (screenHeight < displayHeight))
+ {
+ // Required screen size is smaller than display size
+ TraceLog(INFO, "UPSCALING: Required screen size: %i x %i -> Display size: %i x %i", screenWidth, screenHeight, displayWidth, displayHeight);
+
+ // Upscaling to fit display with border-bars
+ float displayRatio = (float)displayWidth/(float)displayHeight;
+ float screenRatio = (float)screenWidth/(float)screenHeight;
+
+ if (displayRatio <= screenRatio)
+ {
+ renderWidth = screenWidth;
+ renderHeight = (int)((float)screenWidth/displayRatio);
+ renderOffsetX = 0;
+ renderOffsetY = (renderHeight - screenHeight);
+ }
+ else
+ {
+ renderWidth = (int)((float)screenHeight*displayRatio);
+ renderHeight = screenHeight;
+ renderOffsetX = (renderWidth - screenWidth);
+ renderOffsetY = 0;
+ }
+ }
+ else // screen == display
+ {
+ renderWidth = screenWidth;
+ renderHeight = screenHeight;
+ renderOffsetX = 0;
+ renderOffsetY = 0;
+ }
+}
+
+// Plays raylib logo appearing animation
+static void LogoAnimation(void)
+{
+ int logoPositionX = screenWidth/2 - 128;
+ int logoPositionY = screenHeight/2 - 128;
int framesCounter = 0;
int lettersCount = 0;
@@ -787,7 +1737,7 @@ static void LogoAnimation()
char raylib[8] = " "; // raylib text array, max 8 letters
int state = 0; // Tracking animation states (State Machine)
- float alpha = 1.0; // Useful for fading
+ float alpha = 1.0f; // Useful for fading
while (!WindowShouldClose() && (state != 4)) // Detect window close button or ESC key
{
@@ -840,11 +1790,11 @@ static void LogoAnimation()
if (lettersCount >= 10) // When all letters have appeared, just fade out everything
{
- alpha -= 0.02;
+ alpha -= 0.02f;
- if (alpha <= 0)
+ if (alpha <= 0.0f)
{
- alpha = 0;
+ alpha = 0.0f;
state = 4;
}
}
@@ -855,6 +1805,8 @@ static void LogoAnimation()
//----------------------------------------------------------------------------------
BeginDrawing();
+ ClearBackground(RAYWHITE);
+
if (state == 0)
{
if ((framesCounter/12)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK);
@@ -880,12 +1832,14 @@ static void LogoAnimation()
DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha));
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha));
- DrawRectangle(windowWidth/2 - 112, windowHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha));
+ DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha));
- DrawText(raylib, windowWidth/2 - 44, windowHeight/2 + 48, 50, Fade(BLACK, alpha));
+ DrawText(raylib, screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha));
}
EndDrawing();
//----------------------------------------------------------------------------------
}
-} \ No newline at end of file
+
+ showLogo = false; // Prevent for repeating when reloading window (Android)
+}
diff --git a/src/makefile b/src/makefile
new file mode 100644
index 00000000..6f0179ab
--- /dev/null
+++ b/src/makefile
@@ -0,0 +1,130 @@
+#**************************************************************************************************
+#
+# raylib for Raspberry Pi and Windows desktop
+#
+# makefile for library compilation (raylib.a)
+#
+# Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+#
+# This software is provided "as-is", without any express or implied warranty. In no event
+# will the authors be held liable for any damages arising from the use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose, including commercial
+# applications, and to alter it and redistribute it freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not claim that you
+# wrote the original software. If you use this software in a product, an acknowledgment
+# in the product documentation would be appreciated but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be misrepresented
+# as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+#
+#**************************************************************************************************
+
+# define raylib platform (by default, compile for RPI)
+# Other possible platform: PLATFORM_DESKTOP
+PLATFORM ?= PLATFORM_RPI
+
+# define raylib graphics api depending on selected platform
+ifeq ($(PLATFORM),PLATFORM_RPI)
+ # define raylib graphics api to use (on RPI, OpenGL ES 2.0 must be used)
+ GRAPHICS = GRAPHICS_API_OPENGL_ES2
+else
+ # define raylib graphics api to use (on Windows desktop, OpenGL 1.1 by default)
+ GRAPHICS = GRAPHICS_API_OPENGL_11
+ #GRAPHICS = GRAPHICS_API_OPENGL_33 # Uncomment to use OpenGL 3.3
+endif
+
+# NOTE: makefiles targets require tab indentation
+
+# define compiler: gcc for C program, define as g++ for C++
+CC = gcc
+
+# define compiler flags:
+# -O2 defines optimization level
+# -Wall turns on most, but not all, compiler warnings
+# -std=c99 use standard C from 1999 revision
+ifeq ($(PLATFORM),PLATFORM_RPI)
+ CFLAGS = -O2 -Wall -std=gnu99 -fgnu89-inline
+else
+ CFLAGS = -O2 -Wall -std=c99
+endif
+#CFLAGSEXTRA = -Wextra -Wmissing-prototypes -Wstrict-prototypes
+
+# define any directories containing required header files
+ifeq ($(PLATFORM),PLATFORM_RPI)
+ INCLUDES = -I. -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads
+else
+ INCLUDES = -I.
+endif
+
+# define all object files required
+OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o stb_image.o stb_vorbis.o
+
+# typing 'make' will invoke the first target entry in the file,
+# in this case, the 'default' target entry is raylib
+default: raylib
+
+# compile raylib library
+raylib: $(OBJS)
+ ar rcs libraylib.a $(OBJS)
+
+# compile core module
+core.o: core.c
+ $(CC) -c core.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# compile rlgl module
+rlgl.o: rlgl.c
+ $(CC) -c rlgl.c $(CFLAGS) $(INCLUDES) -D$(GRAPHICS)
+
+# compile raymath module
+raymath.o: raymath.c
+ $(CC) -c raymath.c $(CFLAGS) $(INCLUDES)
+
+# compile shapes module
+shapes.o: shapes.c
+ $(CC) -c shapes.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# compile textures module
+textures.o: textures.c
+ $(CC) -c textures.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# compile text module
+text.o: text.c
+ $(CC) -c text.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# compile models module
+models.o: models.c
+ $(CC) -c models.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# compile audio module
+audio.o: audio.c
+ $(CC) -c audio.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# compile utils module
+utils.o: utils.c
+ $(CC) -c utils.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# compile stb_image library
+stb_image.o: stb_image.c
+ $(CC) -c stb_image.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# compile stb_vorbis library
+stb_vorbis.o: stb_vorbis.c
+ $(CC) -c stb_vorbis.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
+
+# clean everything
+clean:
+ifeq ($(PLATFORM),PLATFORM_RPI)
+ rm -f *.o libraylib.a
+else
+ del *.o libraylib.a
+endif
+ @echo Cleaning done
+
+# instead of defining every module one by one, we can define a pattern
+# this pattern below will automatically compile every module defined on $(OBJS)
+#%.o : %.c
+# $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(GRAPHICS)
diff --git a/src/models.c b/src/models.c
index 95dbae7c..ab6abb55 100644
--- a/src/models.c
+++ b/src/models.c
@@ -1,10 +1,10 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raylib.models
*
* Basic functions to draw 3d shapes and load/draw 3d models (.OBJ)
*
-* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -25,13 +25,17 @@
#include "raylib.h"
-#include <stdio.h> // Standard input/output functions, used to read model files data
-#include <stdlib.h> // Declares malloc() and free() for memory management
-#include <string.h> // Required for strcmp()
-#include <math.h> // Used for sin, cos, tan
+#if defined(PLATFORM_ANDROID)
+ #include "utils.h" // Android fopen function map
+#endif
+
+#include <stdio.h> // Standard input/output functions, used to read model files data
+#include <stdlib.h> // Declares malloc() and free() for memory management
+#include <string.h> // Required for strcmp()
+#include <math.h> // Used for sin, cos, tan
-#include "raymath.h" // Required for data type Matrix and Matrix functions
-#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
+#include "raymath.h" // Required for data type Matrix and Matrix functions
+#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
//----------------------------------------------------------------------------------
// Defines and Macros
@@ -442,9 +446,11 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
}
// Draw a plane
-// TODO: Test this function
void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color)
{
+ // NOTE: QUADS usage require defining a texture
+ rlEnableTexture(1); // Default white texture
+
// NOTE: Plane is always created on XZ ground and then rotated
rlPushMatrix();
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
@@ -459,11 +465,13 @@ void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color)
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 1.0f, 0.0f);
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(-0.5f, 0.0f, -0.5f);
- rlTexCoord2f(1.0f, 0.0f); rlVertex3f(0.5f, 0.0f, -0.5f);
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(-0.5f, 0.0f, 0.5f);
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(0.5f, 0.0f, 0.5f);
- rlTexCoord2f(0.0f, 1.0f); rlVertex3f(-0.5f, 0.0f, 0.5f);
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(0.5f, 0.0f, -0.5f);
rlEnd();
rlPopMatrix();
+
+ rlDisableTexture();
}
// Draw a plane with divisions
@@ -646,20 +654,15 @@ Model LoadModel(const char *fileName)
if (strcmp(GetExtension(fileName),"obj") == 0) vData = LoadOBJ(fileName);
else TraceLog(WARNING, "[%s] Model extension not recognized, it can't be loaded", fileName);
- Model model;
-
- model.mesh = vData; // Model mesh is vertex data
- model.textureId = 0;
+ // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- model.vaoId = rlglLoadModel(vData); // Use loaded data to generate VAO
- model.textureId = 1; // Default whiteTexture
+ Model model = rlglLoadModel(vData); // Upload vertex data to GPU
// Now that vertex data is uploaded to GPU, we can free arrays
+ // NOTE: Despite vertex data is useless on OpenGL 3.3 or ES2, we will keep it...
//free(vData.vertices);
//free(vData.texcoords);
//free(vData.normals);
-#endif
return model;
}
@@ -764,25 +767,19 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
}
}
- // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
-
// Fill color data
for (int i = 0; i < (4*vData.vertexCount); i++) vData.colors[i] = 255;
- Model model;
- model.mesh = vData; // Model mesh is vertex data
- model.textureId = 0;
+ // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- model.vaoId = rlglLoadModel(vData); // Use loaded data to generate VAO
- model.textureId = 1; // Default whiteTexture
+ Model model = rlglLoadModel(vData);
// Now that vertex data is uploaded to GPU, we can free arrays
+ // NOTE: Despite vertex data is useless on OpenGL 3.3 or ES2, we will keep it...
//free(vData.vertices);
//free(vData.texcoords);
//free(vData.normals);
-#endif
return model;
}
@@ -1092,20 +1089,13 @@ Model LoadCubesmap(Image cubesmap)
// NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
- Model model;
-
- model.mesh = vData; // Model mesh is vertex data
- model.textureId = 0;
-
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- model.vaoId = rlglLoadModel(vData); // Use loaded data to generate VAO
- model.textureId = 1; // Default whiteTexture
+ Model model = rlglLoadModel(vData);
// Now that vertex data is uploaded to GPU, we can free arrays
+ // NOTE: Despite vertex data is useless on OpenGL 3.3 or ES2, we will keep it...
//free(vData.vertices);
//free(vData.texcoords);
//free(vData.normals);
-#endif
return model;
}
@@ -1117,9 +1107,11 @@ void UnloadModel(Model model)
free(model.mesh.texcoords);
free(model.mesh.normals);
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+ rlDeleteBuffers(model.vboId[0]);
+ rlDeleteBuffers(model.vboId[1]);
+ rlDeleteBuffers(model.vboId[2]);
+
rlDeleteVertexArrays(model.vaoId);
-#endif
}
void SetModelTexture(Model *model, Texture2D texture)
@@ -1268,7 +1260,7 @@ static VertexData LoadOBJ(const char *fileName)
int numTexCoords = 0;
int numTriangles = 0;
- FILE* objFile;
+ FILE *objFile;
objFile = fopen(fileName, "rt");
@@ -1326,9 +1318,9 @@ static VertexData LoadOBJ(const char *fileName)
// Once we know the number of vertices to store, we create required arrays
Vector3 *midVertices = (Vector3 *)malloc(numVertex*sizeof(Vector3));
- Vector3 *midNormals;
+ Vector3 *midNormals = NULL;
if (numNormals > 0) midNormals = (Vector3 *)malloc(numNormals*sizeof(Vector3));
- Vector2 *midTexCoords;
+ Vector2 *midTexCoords = NULL;
if (numTexCoords > 0) midTexCoords = (Vector2 *)malloc(numTexCoords*sizeof(Vector2));
int countVertex = 0;
diff --git a/src/raylib.h b/src/raylib.h
index a3fccfdb..9c754952 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -1,6 +1,6 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
-* raylib 1.1 (www.raylib.com)
+* raylib 1.2 (www.raylib.com)
*
* A simple and easy-to-use library to learn videogames programming
*
@@ -31,7 +31,7 @@
* One custom default font is loaded automatically when InitWindow()
* If using OpenGL 3.3+ or ES2, one default shader is loaded automatically (internally defined)
*
-* -- LICENSE (raylib v1.1, April 2014) --
+* -- LICENSE (raylib v1.2, September 2014) --
*
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software:
@@ -58,6 +58,15 @@
#ifndef RAYLIB_H
#define RAYLIB_H
+// Choose your platform here or just define it at compile time: -DPLATFORM_DESKTOP
+//#define PLATFORM_DESKTOP // Windows, Linux or OSX
+//#define PLATFORM_ANDROID // Android device
+//#define PLATFORM_RPI // Raspberry Pi
+
+#if defined(PLATFORM_ANDROID)
+ #include <android_native_app_glue.h> // Defines android_app struct
+#endif
+
//----------------------------------------------------------------------------------
// Some basic Defines
//----------------------------------------------------------------------------------
@@ -65,10 +74,10 @@
#define PI 3.14159265358979323846
#endif
-#define DEG2RAD (PI / 180.0)
-#define RAD2DEG (180.0 / PI)
+#define DEG2RAD (PI / 180.0f)
+#define RAD2DEG (180.0f / PI)
-// Keyboard Function Keys
+// Keyboard Function Keys
#define KEY_SPACE 32
#define KEY_ESCAPE 256
#define KEY_ENTER 257
@@ -107,16 +116,16 @@
// Gamepad Buttons
// NOTE: Adjusted for a PS3 USB Controller
-#define GAMEPAD_BUTTON_A 2
-#define GAMEPAD_BUTTON_B 1
-#define GAMEPAD_BUTTON_X 3
-#define GAMEPAD_BUTTON_Y 4
-#define GAMEPAD_BUTTON_R1 7
-#define GAMEPAD_BUTTON_R2 5
-#define GAMEPAD_BUTTON_L1 6
-#define GAMEPAD_BUTTON_L2 8
-#define GAMEPAD_BUTTON_SELECT 9
-#define GAMEPAD_BUTTON_START 10
+#define GAMEPAD_BUTTON_A 2
+#define GAMEPAD_BUTTON_B 1
+#define GAMEPAD_BUTTON_X 3
+#define GAMEPAD_BUTTON_Y 4
+#define GAMEPAD_BUTTON_R1 7
+#define GAMEPAD_BUTTON_R2 5
+#define GAMEPAD_BUTTON_L1 6
+#define GAMEPAD_BUTTON_L2 8
+#define GAMEPAD_BUTTON_SELECT 9
+#define GAMEPAD_BUTTON_START 10
// TODO: Review Xbox360 USB Controller Buttons
@@ -234,6 +243,7 @@ typedef struct VertexData {
typedef struct Model {
VertexData mesh;
unsigned int vaoId;
+ unsigned int vboId[4];
unsigned int textureId;
//Matrix transform;
} Model;
@@ -256,14 +266,21 @@ extern "C" { // Prevents name mangling of functions
//------------------------------------------------------------------------------------
// Window and Graphics Device Functions (Module: core)
//------------------------------------------------------------------------------------
-void InitWindow(int width, int height, const char *title); // Initialize Window and Graphics Context (OpenGL)
-void InitWindowEx(int width, int height, const char* title, // Initialize Window and Graphics Context (OpenGL),...
- bool resizable, const char *cursorImage); // ...define if windows-resizable and custom cursor
+#if defined(PLATFORM_ANDROID)
+void InitWindow(int width, int height, struct android_app *state); // Init Android activity
+#elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
+void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics
+#endif
+
void CloseWindow(void); // Close Window and Terminate Context
bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed
-void ToggleFullscreen(void); // Fullscreen toggle (by default F11)
+void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP)
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
void SetCustomCursor(const char *cursorImage); // Set a custom cursor icon/image
void SetExitKey(int key); // Set a custom key to exit program (default is ESC)
+#endif
+int GetScreenWidth(void); // Get current screen width
+int GetScreenHeight(void); // Get current screen height
void ClearBackground(Color color); // Sets Background Color
void BeginDrawing(void); // Setup drawing canvas to start drawing
@@ -280,13 +297,14 @@ Color GetColor(int hexValue); // Returns a Color s
int GetHexValue(Color color); // Returns hexadecimal value for a Color
int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
-Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0 to 1.0
+Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
void ShowLogo(void); // Activates raylib logo at startup
//------------------------------------------------------------------------------------
// Input Handling Functions (Module: core)
//------------------------------------------------------------------------------------
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
bool IsKeyPressed(int key); // Detect if a key has been pressed once
bool IsKeyDown(int key); // Detect if a key is being pressed
bool IsKeyReleased(int key); // Detect if a key has been released once
@@ -307,6 +325,13 @@ bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad b
bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed
bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once
bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed
+#endif
+
+#if defined(PLATFORM_ANDROID)
+int GetTouchX(void); // Returns touch position X
+int GetTouchY(void); // Returns touch position Y
+Vector2 GetTouchPosition(void); // Returns touch position XY
+#endif
//------------------------------------------------------------------------------------
// Basic Shapes Drawing Functions (Module: shapes)
@@ -427,6 +452,7 @@ void SetSoundPitch(Sound sound, float pitch); // Set pitch for
void PlayMusicStream(char *fileName); // Start music playing (open stream)
void StopMusicStream(void); // Stop music playing (close stream)
void PauseMusicStream(void); // Pause music playing
+void ResumeMusicStream(void); // Resume playing paused music
bool MusicIsPlaying(void); // Check if music is playing
void SetMusicVolume(float volume); // Set volume for music (1.0 is max level)
float GetMusicTimeLength(void); // Get current music time length (in seconds)
diff --git a/src/raymath.c b/src/raymath.c
index b3706b25..e598b381 100644
--- a/src/raymath.c
+++ b/src/raymath.c
@@ -1,4 +1,4 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raymath
*
@@ -85,17 +85,17 @@ Vector3 VectorPerpendicular(Vector3 v)
Vector3 result;
float min = fabs(v.x);
- Vector3 cardinalAxis = {1.0, 0.0, 0.0};
+ Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f};
if (fabs(v.y) < min)
{
min = fabs(v.y);
- cardinalAxis = (Vector3){0.0, 1.0, 0.0};
+ cardinalAxis = (Vector3){0.0f, 1.0f, 0.0f};
}
if(fabs(v.z) < min)
{
- cardinalAxis = (Vector3){0.0, 0.0, 1.0};
+ cardinalAxis = (Vector3){0.0f, 0.0f, 1.0f};
}
result = VectorCrossProduct(v, cardinalAxis);
@@ -216,7 +216,7 @@ void VectorTransform(Vector3 *v, Matrix mat)
// Return a Vector3 init to zero
Vector3 VectorZero(void)
{
- Vector3 zero = { 0.0, 0.0, 0.0 };
+ Vector3 zero = { 0.0f, 0.0f, 0.0f };
return zero;
}
@@ -377,7 +377,7 @@ void MatrixNormalize(Matrix *mat)
}
// Returns identity matrix
-Matrix MatrixIdentity()
+Matrix MatrixIdentity(void)
{
Matrix result = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
@@ -494,6 +494,7 @@ Matrix MatrixRotate(float angleX, float angleY, float angleZ)
// Create rotation matrix from axis and angle
// TODO: Test this function
+// NOTE: NO prototype defined!
Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
{
Matrix result;
@@ -549,6 +550,7 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
// Create rotation matrix from axis and angle (version 2)
// TODO: Test this function
+// NOTE: NO prototype defined!
Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
{
Matrix result;
@@ -725,21 +727,24 @@ Matrix MatrixFrustum(double left, double right, double bottom, double top, doubl
float tb = (top - bottom);
float fn = (far - near);
- result.m0 = (near*2) / rl;
+ result.m0 = (near*2.0f) / rl;
result.m1 = 0;
result.m2 = 0;
result.m3 = 0;
+
result.m4 = 0;
- result.m5 = (near*2) / tb;
+ result.m5 = (near*2.0f) / tb;
result.m6 = 0;
result.m7 = 0;
+
result.m8 = (right + left) / rl;
result.m9 = (top + bottom) / tb;
result.m10 = -(far + near) / fn;
- result.m11 = -1;
+ result.m11 = -1.0f;
+
result.m12 = 0;
result.m13 = 0;
- result.m14 = -(far*near*2) / fn;
+ result.m14 = -(far*near*2.0f) / fn;
result.m15 = 0;
return result;
@@ -748,7 +753,7 @@ Matrix MatrixFrustum(double left, double right, double bottom, double top, doubl
// Returns perspective projection matrix
Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
{
- double top = near*tan(fovy*PI / 360.0);
+ double top = near*tanf(fovy*PI / 360.0f);
double right = top*aspect;
return MatrixFrustum(-right, right, -top, top, near, far);
@@ -876,18 +881,18 @@ Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
- if (abs(cosHalfTheta) >= 1.0) result = q1;
+ if (abs(cosHalfTheta) >= 1.0f) result = q1;
else
{
float halfTheta = acos(cosHalfTheta);
- float sinHalfTheta = sqrt(1.0 - cosHalfTheta*cosHalfTheta);
+ float sinHalfTheta = sqrt(1.0f - cosHalfTheta*cosHalfTheta);
- if (abs(sinHalfTheta) < 0.001)
+ if (abs(sinHalfTheta) < 0.001f)
{
- result.x = (q1.x*0.5 + q2.x*0.5);
- result.y = (q1.y*0.5 + q2.y*0.5);
- result.z = (q1.z*0.5 + q2.z*0.5);
- result.w = (q1.w*0.5 + q2.w*0.5);
+ result.x = (q1.x*0.5f + q2.x*0.5f);
+ result.y = (q1.y*0.5f + q2.y*0.5f);
+ result.z = (q1.z*0.5f + q2.z*0.5f);
+ result.w = (q1.w*0.5f + q2.w*0.5f);
}
else
{
diff --git a/src/raymath.h b/src/raymath.h
index 5dcfe061..c396a347 100644
--- a/src/raymath.h
+++ b/src/raymath.h
@@ -1,4 +1,4 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raymath
*
@@ -39,8 +39,8 @@
#define PI 3.14159265358979323846
#endif
-#define DEG2RAD (PI / 180.0)
-#define RAD2DEG (180.0 / PI)
+#define DEG2RAD (PI / 180.0f)
+#define RAD2DEG (180.0f / PI)
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -101,9 +101,9 @@ float *GetMatrixVector(Matrix mat); // Returns an OpenGL-rea
float MatrixDeterminant(Matrix mat); // Compute matrix determinant
float MatrixTrace(Matrix mat); // Returns the trace of the matrix (sum of the values along the diagonal)
void MatrixTranspose(Matrix *mat); // Transposes provided matrix
-void MatrixInvert(Matrix *mat); // Invert provided matrix
+void MatrixInvert(Matrix *mat); // Invert provided matrix
void MatrixNormalize(Matrix *mat); // Normalize provided matrix
-Matrix MatrixIdentity(); // Returns identity matrix
+Matrix MatrixIdentity(void); // Returns identity matrix
Matrix MatrixAdd(Matrix left, Matrix right); // Add two matrices
Matrix MatrixSubstract(Matrix left, Matrix right); // Substract two matrices (left - right)
Matrix MatrixTranslate(float x, float y, float z); // Returns translation matrix
diff --git a/src/resources b/src/resources
new file mode 100644
index 00000000..2038c07a
--- /dev/null
+++ b/src/resources
Binary files differ
diff --git a/src/rlgl.c b/src/rlgl.c
index b76a7b27..8f8d67e7 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -1,4 +1,4 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* rlgl - raylib OpenGL abstraction layer
*
@@ -31,32 +31,21 @@
#include <stdio.h> // Standard input / output lib
#include <stdlib.h> // Declares malloc() and free() for memory management, rand()
-// Security check in case no USE_OPENGL_* defined
-#if !defined(USE_OPENGL_11) && !defined(USE_OPENGL_33) && !defined(USE_OPENGL_ES2)
- #define USE_OPENGL_11
-#endif
-
-// Security check in case multiple USE_OPENGL_* defined
-#ifdef USE_OPENGL_11
- #ifdef USE_OPENGL_33
- #undef USE_OPENGL_33
- #endif
-
- #ifdef USE_OPENGL_ES2
- #undef USE_OPENGL_ES2
- #endif
-#endif
-
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
#include <GL/gl.h> // Basic OpenGL include
#endif
-#ifdef USE_OPENGL_33
+#if defined(GRAPHICS_API_OPENGL_33)
#define GLEW_STATIC
#include <GL/glew.h> // Extensions loading lib
+ //#include "glad.h" // TODO: Other extensions loading lib? --> REVIEW
#endif
-//#include "glad.h" // Other extensions loading lib? --> REVIEW
+#if defined(GRAPHICS_API_OPENGL_ES2)
+ #include <EGL/egl.h>
+ #include <GLES2/gl2.h>
+ #include <GLES2/gl2ext.h>
+#endif
//----------------------------------------------------------------------------------
// Defines and Macros
@@ -64,6 +53,7 @@
#define MATRIX_STACK_SIZE 16 // Matrix stack max size
#define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes
#define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations)
+ // NOTE: Every vertex are 3 floats (12 bytes)
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -98,6 +88,7 @@ typedef struct {
float *vertices; // 3 components per vertex
float *texcoords; // 2 components per vertex
float *normals; // 3 components per vertex
+ //short *normals; // NOTE: Less data load... but padding issues and normalizing required!
} VertexPositionTextureNormalBuffer;
// Vertex buffer (position + texcoords + colors + indices arrays)
@@ -109,7 +100,12 @@ typedef struct {
float *vertices; // 3 components per vertex
float *texcoords; // 2 components per vertex
unsigned char *colors; // 4 components per vertex
- unsigned int *indices; // 6 indices per quad
+#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
+ unsigned int *indices; // 6 indices per quad (could be int)
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ unsigned short *indices; // 6 indices per quad (must be short)
+ // NOTE: 6*2 byte = 12 byte, not alignment problem!
+#endif
} VertexPositionColorTextureIndexBuffer;
// Draw call type
@@ -131,7 +127,7 @@ typedef struct {
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
static Matrix stack[MATRIX_STACK_SIZE];
static int stackCounter = 0;
@@ -173,15 +169,26 @@ static bool useTempBuffer = false;
// White texture useful for plain color polys (required by shader)
static GLuint whiteTexture;
+
+// Support for VAOs (OpenGL ES2 could not support VAO extensions)
+static bool vaoSupported = false;
+#endif
+
+#if defined(GRAPHICS_API_OPENGL_ES2)
+// NOTE: VAO functionality is exposed through extensions (OES)
+static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays;
+static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray;
+static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays;
+static PFNGLISVERTEXARRAYOESPROC glIsVertexArray;
#endif
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
static GLuint LoadDefaultShaders(void);
static void InitializeBuffers(void);
-static void InitializeVAOs(void);
+static void InitializeBuffersGPU(void);
static void UpdateBuffers(void);
// Shader files loading (external) - Not used but useful...
@@ -189,7 +196,7 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName);
static char *TextFileRead(char *fn);
#endif
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight);
static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight);
#endif
@@ -198,7 +205,7 @@ static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight);
// Module Functions Definition - Matrix operations
//----------------------------------------------------------------------------------
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
// Fallback to OpenGL 1.1 function calls
//---------------------------------------
@@ -231,7 +238,7 @@ void rlRotatef(float angleDeg, float x, float y, float z) { glRotatef(angleDeg,
void rlScalef(float x, float y, float z) { glScalef(x, y, z); }
void rlMultMatrixf(float *mat) { glMultMatrixf(mat); }
-#else
+#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Choose the current matrix to be transformed
void rlMatrixMode(int mode)
@@ -343,7 +350,7 @@ void rlOrtho(double left, double right, double bottom, double top, double near,
//----------------------------------------------------------------------------------
// Module Functions Definition - Vertex level operations
//----------------------------------------------------------------------------------
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
// Fallback to OpenGL 1.1 function calls
//---------------------------------------
@@ -358,7 +365,7 @@ void rlBegin(int mode)
}
}
-void rlEnd(void) { glEnd(); }
+void rlEnd() { glEnd(); }
void rlVertex2i(int x, int y) { glVertex2i(x, y); }
void rlVertex2f(float x, float y) { glVertex2f(x, y); }
void rlVertex3f(float x, float y, float z) { glVertex3f(x, y, z); }
@@ -368,7 +375,7 @@ void rlColor4ub(byte r, byte g, byte b, byte a) { glColor4ub(r, g, b, a); }
void rlColor3f(float x, float y, float z) { glColor3f(x, y, z); }
void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); }
-#else
+#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Initialize drawing mode (how to organize vertex)
void rlBegin(int mode)
@@ -492,31 +499,46 @@ void rlVertex3f(float x, float y, float z)
{
case RL_LINES:
{
- lines.vertices[3*lines.vCounter] = x;
- lines.vertices[3*lines.vCounter + 1] = y;
- lines.vertices[3*lines.vCounter + 2] = z;
+ // Verify that MAX_LINES_BATCH limit not reached
+ if (lines.vCounter / 2 < MAX_LINES_BATCH)
+ {
+ lines.vertices[3*lines.vCounter] = x;
+ lines.vertices[3*lines.vCounter + 1] = y;
+ lines.vertices[3*lines.vCounter + 2] = z;
- lines.vCounter++;
+ lines.vCounter++;
+ }
+ else TraceLog(ERROR, "MAX_LINES_BATCH overflow");
} break;
case RL_TRIANGLES:
{
- triangles.vertices[3*triangles.vCounter] = x;
- triangles.vertices[3*triangles.vCounter + 1] = y;
- triangles.vertices[3*triangles.vCounter + 2] = z;
+ // Verify that MAX_TRIANGLES_BATCH limit not reached
+ if (triangles.vCounter / 3 < MAX_TRIANGLES_BATCH)
+ {
+ triangles.vertices[3*triangles.vCounter] = x;
+ triangles.vertices[3*triangles.vCounter + 1] = y;
+ triangles.vertices[3*triangles.vCounter + 2] = z;
- triangles.vCounter++;
+ triangles.vCounter++;
+ }
+ else TraceLog(ERROR, "MAX_TRIANGLES_BATCH overflow");
} break;
case RL_QUADS:
{
- quads.vertices[3*quads.vCounter] = x;
- quads.vertices[3*quads.vCounter + 1] = y;
- quads.vertices[3*quads.vCounter + 2] = z;
+ // Verify that MAX_QUADS_BATCH limit not reached
+ if (quads.vCounter / 4 < MAX_QUADS_BATCH)
+ {
+ quads.vertices[3*quads.vCounter] = x;
+ quads.vertices[3*quads.vCounter + 1] = y;
+ quads.vertices[3*quads.vCounter + 2] = z;
- quads.vCounter++;
+ quads.vCounter++;
- draws[drawsCounter - 1].vertexCount++;
+ draws[drawsCounter - 1].vertexCount++;
+ }
+ else TraceLog(ERROR, "MAX_QUADS_BATCH overflow");
} break;
default: break;
@@ -527,17 +549,17 @@ void rlVertex3f(float x, float y, float z)
// Define one vertex (position)
void rlVertex2f(float x, float y)
{
- rlVertex3f(x, y, 0.0);
+ rlVertex3f(x, y, 0.0f);
}
// Define one vertex (position)
void rlVertex2i(int x, int y)
{
- rlVertex3f((float)x, (float)y, 0.0);
+ rlVertex3f((float)x, (float)y, 0.0f);
}
// Define one vertex (texture coordinate)
-// NOTE: Texture coordinates are limited to TRIANGLES only
+// NOTE: Texture coordinates are limited to QUADS only
void rlTexCoord2f(float x, float y)
{
if (currentDrawMode == RL_QUADS)
@@ -616,12 +638,12 @@ void rlColor3f(float x, float y, float z)
// Enable texture usage
void rlEnableTexture(unsigned int id)
{
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, id);
#endif
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if (draws[drawsCounter - 1].textureId != id)
{
if (draws[drawsCounter - 1].vertexCount > 0) drawsCounter++;
@@ -635,7 +657,7 @@ void rlEnableTexture(unsigned int id)
// Disable texture usage
void rlDisableTexture(void)
{
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
#endif
@@ -647,11 +669,19 @@ void rlDeleteTextures(unsigned int id)
glDeleteTextures(1, &id);
}
-// Unload vertex data from GPU memory
+// Unload vertex data (VAO) from GPU memory
void rlDeleteVertexArrays(unsigned int id)
{
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- glDeleteVertexArrays(1, &id);
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+ if (vaoSupported) glDeleteVertexArrays(1, &id);
+#endif
+}
+
+// Unload vertex data (VBO) from GPU memory
+void rlDeleteBuffers(unsigned int id)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+ glDeleteBuffers(1, &id);
#endif
}
@@ -674,40 +704,109 @@ void rlClearScreenBuffers(void)
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used...
}
+// Returns current OpenGL version
+int rlGetVersion(void)
+{
+#if defined(GRAPHICS_API_OPENGL_11)
+ return OPENGL_11;
+#elif defined(GRAPHICS_API_OPENGL_33)
+ return OPENGL_33;
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ return OPENGL_ES_20;
+#endif
+}
+
//----------------------------------------------------------------------------------
// Module Functions Definition - rlgl Functions
//----------------------------------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
-
// Init OpenGL 3.3+ required data
void rlglInit(void)
{
- // Initialize GLEW
+#if defined(GRAPHICS_API_OPENGL_33)
+ // Loading extensions the hard way (Example)
+/*
+ GLint numExt;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
+
+ for (int i = 0; i < numExt; i++)
+ {
+ const GLubyte *extensionName = glGetStringi(GL_EXTENSIONS, i);
+ if (strcmp(extensionName, (const GLubyte *)"GL_ARB_vertex_array_object") == 0)
+ {
+ // The extension is supported by our hardware and driver, try to get related functions popinters
+ glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)wglGetProcAddress("glGenVertexArrays");
+ glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)wglGetProcAddress("glBindVertexArray");
+ glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)wglGetProcAddress("glDeleteVertexArrays");
+ glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)wglGetProcAddress("glIsVertexArray");
+ }
+ }
+*/
+
+ // Initialize extensions using GLEW
glewExperimental = 1; // Needed for core profile
GLenum error = glewInit();
- if (error != GLEW_OK)
+ if (error != GLEW_OK) TraceLog(ERROR, "Failed to initialize GLEW - Error Code: %s\n", glewGetErrorString(error));
+
+ if (glewIsSupported("GL_VERSION_3_3")) TraceLog(INFO, "OpenGL 3.3 extensions supported");
+
+ // NOTE: GLEW is a big library that loads ALL extensions, using glad we can only load required ones...
+ //if (!gladLoadGL()) TraceLog("ERROR: Failed to initialize glad\n");
+
+ vaoSupported = true;
+#endif
+
+#if defined(GRAPHICS_API_OPENGL_ES2)
+ glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
+ glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
+ glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");
+ glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES");
+
+ if (glGenVertexArrays == NULL) TraceLog(WARNING, "Could not initialize VAO extensions, VAOs not supported");
+ else
{
- TraceLog(ERROR, "Failed to initialize GLEW - Error Code: %s\n", glewGetErrorString(error));
+ vaoSupported = true;
+ TraceLog(INFO, "VAO extensions initialized successfully");
}
+#endif
- if (glewIsSupported("GL_VERSION_3_3")) TraceLog(INFO, "OpenGL 3.3 initialized successfully\n");
+ // Print current OpenGL and GLSL version
+ TraceLog(INFO, "GPU: Vendor: %s", glGetString(GL_VENDOR));
+ TraceLog(INFO, "GPU: Renderer: %s", glGetString(GL_RENDERER));
+ TraceLog(INFO, "GPU: Version: %s", glGetString(GL_VERSION));
+ TraceLog(INFO, "GPU: GLSL: %s", glGetString(0x8B8C)); //GL_SHADING_LANGUAGE_VERSION
- // Print OpenGL and GLSL version
- TraceLog(INFO, "Vendor: %s", glGetString(GL_VENDOR));
- TraceLog(INFO, "Renderer: %s", glGetString(GL_RENDERER));
- TraceLog(INFO, "Version: %s", glGetString(GL_VERSION));
- TraceLog(INFO, "GLSL: %s\n", glGetString(0x8B8C)); //GL_SHADING_LANGUAGE_VERSION
+ // NOTE: We can get a bunch of extra information about GPU capabilities (glGet*)
+ //int maxTexSize;
+ //glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
+ //TraceLog(INFO, "GL_MAX_TEXTURE_SIZE: %i", maxTexSize);
+ //int numAuxBuffers;
+ //glGetIntegerv(GL_AUX_BUFFERS, &numAuxBuffers);
+ //TraceLog(INFO, "GL_AUX_BUFFERS: %i", numAuxBuffers);
+
+ // Show supported extensions
+ // NOTE: We don't need that much data on screen... right now...
/*
- // TODO: GLEW is a big library that loads ALL extensions, maybe using glad we can only load required ones...
- if (!gladLoadGL())
+#if defined(GRAPHICS_API_OPENGL_33)
+ GLint numExt;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
+
+ for (int i = 0; i < numExt; i++)
{
- TraceLog("ERROR: Failed to initialize glad\n");
+ TraceLog(INFO, "Supported extension: %s", glGetStringi(GL_EXTENSIONS, i));
}
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big string
+
+ // NOTE: String could be splitted using strtok() function (string.h)
+ TraceLog(INFO, "Supported extension: %s", extensions);
+#endif
*/
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Set default draw mode
currentDrawMode = RL_TRIANGLES;
@@ -735,8 +834,8 @@ void rlglInit(void)
// Get handles to GLSL uniform vars locations (fragment-shader)
textureLoc = glGetUniformLocation(shaderProgram, "texture0");
- InitializeBuffers(); // Init vertex arrays
- InitializeVAOs(); // Init VBO and VAO
+ InitializeBuffers(); // Init vertex arrays
+ InitializeBuffersGPU(); // Init VBO and VAO
// Init temp vertex buffer, used when transformation required (translate, rotate, scale)
tempBuffer = (Vector3 *)malloc(sizeof(Vector3)*TEMP_VERTEX_BUFFER_SIZE);
@@ -748,7 +847,7 @@ void rlglInit(void)
whiteTexture = rlglLoadTexture(pixels, 1, 1, false);
- if (whiteTexture != 0) TraceLog(INFO, "[ID %i] Base white texture created successfully", whiteTexture);
+ if (whiteTexture != 0) TraceLog(INFO, "[TEX ID %i] Base white texture created successfully", whiteTexture);
else TraceLog(WARNING, "Base white texture could not be created");
// Init draw calls tracking system
@@ -762,13 +861,15 @@ void rlglInit(void)
drawsCounter = 1;
draws[drawsCounter - 1].textureId = whiteTexture;
+#endif
}
// Vertex Buffer Object deinitialization (memory free)
void rlglClose(void)
{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Unbind everything
- glBindVertexArray(0);
+ if (vaoSupported) glBindVertexArray(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
@@ -778,7 +879,7 @@ void rlglClose(void)
glUseProgram(0);
- // Delete VAOs and VBOs
+ // Delete VBOs
glDeleteBuffers(1, &linesBuffer[0]);
glDeleteBuffers(1, &linesBuffer[1]);
glDeleteBuffers(1, &trianglesBuffer[0]);
@@ -788,9 +889,13 @@ void rlglClose(void)
glDeleteBuffers(1, &quadsBuffer[2]);
glDeleteBuffers(1, &quadsBuffer[3]);
- glDeleteVertexArrays(1, &vaoLines);
- glDeleteVertexArrays(1, &vaoTriangles);
- glDeleteVertexArrays(1, &vaoQuads);
+ if (vaoSupported)
+ {
+ // Delete VAOs
+ glDeleteVertexArrays(1, &vaoLines);
+ glDeleteVertexArrays(1, &vaoTriangles);
+ glDeleteVertexArrays(1, &vaoQuads);
+ }
//glDetachShader(shaderProgram, v);
//glDetachShader(shaderProgram, f);
@@ -808,15 +913,18 @@ void rlglClose(void)
free(quads.vertices);
free(quads.texcoords);
free(quads.colors);
+ free(quads.indices);
// Free GPU texture
glDeleteTextures(1, &whiteTexture);
free(draws);
+#endif
}
void rlglDraw(void)
{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
UpdateBuffers();
glUseProgram(shaderProgram); // Use our shader
@@ -831,9 +939,24 @@ void rlglDraw(void)
{
glBindTexture(GL_TEXTURE_2D, whiteTexture);
- glBindVertexArray(vaoTriangles);
+ if (vaoSupported)
+ {
+ glBindVertexArray(vaoTriangles);
+ }
+ else
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+ glEnableVertexAttribArray(vertexLoc);
+
+ glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]);
+ glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
+ glEnableVertexAttribArray(colorLoc);
+ }
+
glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter);
+ if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
@@ -843,7 +966,27 @@ void rlglDraw(void)
int numIndicesToProcess = 0;
int indicesOffset = 0;
- glBindVertexArray(vaoQuads);
+ if (vaoSupported)
+ {
+ glBindVertexArray(vaoQuads);
+ }
+ else
+ {
+ // Enable vertex attributes
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+ glEnableVertexAttribArray(vertexLoc);
+
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]);
+ glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
+ glEnableVertexAttribArray(texcoordLoc);
+
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
+ glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
+ glEnableVertexAttribArray(colorLoc);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);
+ }
//TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter);
@@ -857,11 +1000,23 @@ void rlglDraw(void)
glBindTexture(GL_TEXTURE_2D, draws[i].textureId);
// NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process
+#if defined(GRAPHICS_API_OPENGL_33)
glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset));
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * indicesOffset));
+#endif
+ //GLenum err;
+ //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM!
indicesOffset += draws[i].vertexCount/4*6;
}
+ if (!vaoSupported)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
}
@@ -869,13 +1024,28 @@ void rlglDraw(void)
{
glBindTexture(GL_TEXTURE_2D, whiteTexture);
- glBindVertexArray(vaoLines);
+ if (vaoSupported)
+ {
+ glBindVertexArray(vaoLines);
+ }
+ else
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+ glEnableVertexAttribArray(vertexLoc);
+
+ glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
+ glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
+ glEnableVertexAttribArray(colorLoc);
+ }
+
glDrawArrays(GL_LINES, 0, lines.vCounter);
+ if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
- glBindVertexArray(0); // Unbind VAO
+ if (vaoSupported) glBindVertexArray(0); // Unbind VAO
// Reset draws counter
drawsCounter = 1;
@@ -892,16 +1062,18 @@ void rlglDraw(void)
quads.vCounter = 0;
quads.tcCounter = 0;
quads.cCounter = 0;
+#endif
}
-#endif // End for OpenGL 3.3+ and ES2 only functions
-
// Draw a 3d model
void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires)
{
+#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
+ // NOTE: glPolygonMode() not available on OpenGL ES
if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+#endif
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, model.textureId);
@@ -937,7 +1109,7 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal
glBindTexture(GL_TEXTURE_2D, 0);
#endif
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glUseProgram(shaderProgram); // Use our shader
// Get transform matrix (rotation -> scale -> translation)
@@ -964,7 +1136,7 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal
}
// Update colors buffer in CPU (using Shader)
- glBindVertexArray(model.vaoId);
+ if (vaoSupported) glBindVertexArray(model.vaoId);
GLuint colorVboId;
glGetVertexAttribIuiv(2, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &colorVboId); // NOTE: Color VBO is buffer index 2
glBindBuffer(GL_ARRAY_BUFFER, colorVboId);
@@ -977,23 +1149,47 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal
//TraceLog(DEBUG, "ShaderProgram: %i, VAO ID: %i, VertexCount: %i", shaderProgram, model.vaoId, model.mesh.vertexCount);
- glBindVertexArray(model.vaoId);
+ if (vaoSupported)
+ {
+ glBindVertexArray(model.vaoId);
+ }
+ else
+ {
+ // Bind model VBOs data
+ glBindBuffer(GL_ARRAY_BUFFER, model.vboId[0]);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+ glEnableVertexAttribArray(vertexLoc);
+
+ glBindBuffer(GL_ARRAY_BUFFER, model.vboId[1]);
+ glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
+ glEnableVertexAttribArray(texcoordLoc);
+
+ glBindBuffer(GL_ARRAY_BUFFER, model.vboId[2]);
+ glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
+ glEnableVertexAttribArray(colorLoc);
+ }
+
glBindTexture(GL_TEXTURE_2D, model.textureId);
glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount);
- glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
- glBindVertexArray(0); // Unbind VAO
+ glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
+
+ if (vaoSupported) glBindVertexArray(0); // Unbind VAO
+ else glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBOs
#endif
+#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
+ // NOTE: glPolygonMode() not available on OpenGL ES
if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+#endif
}
// Initialize Graphics Device (OpenGL stuff)
-void rlglInitGraphicsDevice(int fbWidth, int fbHeight)
+void rlglInitGraphics(int offsetX, int offsetY, int width, int height)
{
- glViewport(0, 0, fbWidth, fbHeight); // Set viewport width and height
- // NOTE: Required! viewport must be recalculated if screen resized!
+ // NOTE: Required! viewport must be recalculated if screen resized!
+ glViewport(offsetX/2, offsetY/2, width - offsetX, height - offsetY); // Set viewport width and height
// NOTE: Don't confuse glViewport with the transformation matrix
// NOTE: glViewport just defines the area of the context that you will actually draw to.
@@ -1008,7 +1204,7 @@ void rlglInitGraphicsDevice(int fbWidth, int fbHeight)
glEnable(GL_BLEND); // Enable color blending (required to work with transparencies)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed)
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation (Deprecated in OGL 3.0)
// Other options: GL_FASTEST, GL_DONT_CARE (default)
#endif
@@ -1016,7 +1212,7 @@ void rlglInitGraphicsDevice(int fbWidth, int fbHeight)
rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix
rlLoadIdentity(); // Reset current matrix (PROJECTION)
- rlOrtho(0, fbWidth, fbHeight, 0, 0, 1); // Config orthographic mode: top-left corner --> (0,0)
+ rlOrtho(0, width - offsetX, height - offsetY, 0, 0, 1); // Config orthographic mode: top-left corner --> (0,0)
rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
@@ -1027,12 +1223,12 @@ void rlglInitGraphicsDevice(int fbWidth, int fbHeight)
//glCullFace(GL_BACK); // Cull the Back face (default)
//glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) (Deprecated on OpenGL 3.3+)
// Possible options: GL_SMOOTH (Color interpolation) or GL_FLAT (no interpolation)
#endif
- TraceLog(INFO, "OpenGL Graphics Device initialized successfully");
+ TraceLog(INFO, "OpenGL Graphics initialized successfully");
}
// Convert image data to OpenGL texture (returns OpenGL valid Id)
@@ -1057,7 +1253,7 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool ge
if (genMipmaps && !texIsPOT)
{
- TraceLog(WARNING, "[ID %i] Texture is not power-of-two, mipmaps can not be generated", id);
+ TraceLog(WARNING, "[TEX ID %i] Texture is not power-of-two, mipmaps can not be generated", id);
genMipmaps = false;
}
@@ -1076,10 +1272,10 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool ge
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
}
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
if (genMipmaps)
{
- TraceLog(WARNING, "[ID %i] Mipmaps generated manually on CPU side", id);
+ TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", id);
// Compute required mipmaps
// NOTE: data size is reallocated to fit mipmaps data
@@ -1106,17 +1302,20 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool ge
else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
#endif
-
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
-
+#if defined(GRAPHICS_API_OPENGL_33)
+ // NOTE: We define internal (GPU) format as GL_RGBA8 (probably BGRA8 in practice, driver takes care)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ // NOTE: On embedded systems, we let the driver choose the best internal format
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+#endif
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if (genMipmaps)
{
glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
- TraceLog(INFO, "[ID %i] Mipmaps generated automatically for new texture", id);
+ TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically for new texture", id);
}
-
#endif
// At this point we have the image converted to texture and uploaded to GPU
@@ -1124,23 +1323,102 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool ge
// Unbind current texture
glBindTexture(GL_TEXTURE_2D, 0);
- TraceLog(INFO, "[ID %i] New texture created (%i x %i)", id, width, height);
+ TraceLog(INFO, "[TEX ID %i] Texture created successfully (%i x %i)", id, width, height);
return id;
}
+// Load vertex data into a VAO (if supported) and VBO
+Model rlglLoadModel(VertexData mesh)
+{
+ Model model;
+
+ model.mesh = mesh;
+
+#if defined(GRAPHICS_API_OPENGL_11)
+ model.textureId = 0; // No texture required
+ model.vaoId = 0; // Vertex Array Object
+ model.vboId[0] = 0; // Vertex position VBO
+ model.vboId[1] = 0; // Texcoords VBO
+ //model.vboId[2] = 0; // Normals VBO (not used)
+ model.vboId[2] = 0; // Colors VBO
+
+#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+ model.textureId = 1; // Default whiteTexture
+
+ GLuint vaoModel; // Vertex Array Objects (VAO)
+ GLuint vertexBuffer[3]; // Vertex Buffer Objects (VBO)
+
+ if (vaoSupported)
+ {
+ // Initialize Quads VAO (Buffer A)
+ glGenVertexArrays(1, &vaoModel);
+ glBindVertexArray(vaoModel);
+ }
+
+ // Create buffers for our vertex data (positions, texcoords, normals)
+ glGenBuffers(3, vertexBuffer);
+
+ // Enable vertex attributes: position
+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(vertexLoc);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+
+ // Enable vertex attributes: texcoords
+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(texcoordLoc);
+ glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
+
+ // TODO: Normals support -> Lighting
+
+ // Enable vertex attributes: normals
+ //glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW);
+ //glEnableVertexAttribArray(normalLoc);
+ //glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
+
+ // Enable vertex attributes: colors
+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh.vertexCount, mesh.colors, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(colorLoc);
+ glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
+
+ if (vaoSupported)
+ {
+ if (vaoModel > 0)
+ {
+ model.vaoId = vaoModel;
+ TraceLog(INFO, "[VAO ID %i] Model uploaded successfully to VRAM (GPU)", vaoModel);
+ }
+ else TraceLog(WARNING, "Model could not be uploaded to VRAM (GPU)");
+ }
+ else
+ {
+ model.vboId[0] = vertexBuffer[0]; // Vertex position VBO
+ model.vboId[1] = vertexBuffer[1]; // Texcoords VBO
+ //model.vboId[2] = 0; // Normals VBO (not used)
+ model.vboId[2] = vertexBuffer[2]; // Colors VBO
+
+ TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Model uploaded successfully to VRAM (GPU)", model.vboId[0], model.vboId[1], model.vboId[2]);
+ }
+#endif
-#ifdef USE_OPENGL_33
+ return model;
+}
// Convert image data to OpenGL texture (returns OpenGL valid Id)
// NOTE: Expected compressed image data and POT image
unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compFormat)
{
- // Create one OpenGL texture
GLuint id;
- glGenTextures(1, &id);
+#if defined(GRAPHICS_API_OPENGL_11)
+ id = 0;
+ TraceLog(WARNING, "GPU compressed textures not supported on OpenGL 1.1");
+#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
TraceLog(DEBUG, "Compressed texture width: %i", width);
TraceLog(DEBUG, "Compressed texture height: %i", height);
TraceLog(DEBUG, "Compressed texture mipmap levels: %i", mipmapCount);
@@ -1148,15 +1426,35 @@ unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int heigh
if (compFormat == 0)
{
- TraceLog(WARNING, "[ID %i] Texture compressed format not recognized", id);
id = 0;
+ TraceLog(WARNING, "Texture compressed format not recognized", id);
}
else
{
+ glGenTextures(1, &id);
+
// Bind the texture
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ // Set texture parameters
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ // If mipmaps are being used, we configure mag-min filters accordingly
+ if (mipmapCount > 1)
+ {
+ // Trilinear filtering with mipmaps
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate use of mipmaps (must be available)
+ }
+ else
+ {
+ // Not using mipmappings
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
+ }
+
int blockSize = 0;
int offset = 0;
@@ -1166,9 +1464,13 @@ unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int heigh
// Load the mipmaps
for (int level = 0; level < mipmapCount && (width || height); level++)
{
- // NOTE: size specifies the number of bytes of image data (S3TC/DXTC)
- unsigned int size = ((width + 3)/4)*((height + 3)/4)*blockSize;
+ unsigned int size = 0;
+ // NOTE: size specifies the number of bytes of image data (S3TC/DXTC)
+ if (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) size = ((width + 3)/4)*((height + 3)/4)*blockSize; // S3TC/DXTC
+#if defined(GRAPHICS_API_OPENGL_ES2)
+ else if (compFormat == GL_ETC1_RGB8_OES) size = 8*((width + 3) >> 2)*((height + 3) >> 2); // ETC1
+#endif
glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset);
offset += size;
@@ -1180,54 +1482,11 @@ unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int heigh
if (height < 1) height = 1;
}
}
+#endif
return id;
}
-// Load vertex data into a VAO
-unsigned int rlglLoadModel(VertexData mesh)
-{
- GLuint vaoModel; // Vertex Array Objects (VAO)
- GLuint vertexBuffer[3]; // Vertex Buffer Objects (VBO)
-
- // Initialize Quads VAO (Buffer A)
- glGenVertexArrays(1, &vaoModel);
- glBindVertexArray(vaoModel);
-
- // Create buffers for our vertex data (positions, texcoords, normals)
- glGenBuffers(3, vertexBuffer);
-
- // Enable vertex attributes: position
- glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW);
- glEnableVertexAttribArray(vertexLoc);
- glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
-
- // Enable vertex attributes: texcoords
- glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW);
- glEnableVertexAttribArray(texcoordLoc);
- glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
-
- // Enable vertex attributes: normals
- //glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
- //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW);
- //glEnableVertexAttribArray(normalLoc);
- //glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
-
- // Enable vertex attributes: colors
- glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh.vertexCount, mesh.colors, GL_STATIC_DRAW);
- glEnableVertexAttribArray(colorLoc);
- glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
-
- if (vaoModel > 0) TraceLog(INFO, "[ID %i] Model uploaded successfully to VRAM (GPU)", vaoModel);
- else TraceLog(WARNING, "Model could not be uploaded to VRAM (GPU)");
-
- return vaoModel;
-}
-#endif
-
// Read screen pixel data (color buffer)
unsigned char *rlglReadScreenPixels(int width, int height)
{
@@ -1252,14 +1511,14 @@ unsigned char *rlglReadScreenPixels(int width, int height)
return imgData; // NOTE: image data should be freed
}
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-void PrintProjectionMatrix(void)
+void PrintProjectionMatrix()
{
PrintMatrix(projection);
}
-void PrintModelviewMatrix(void)
+void PrintModelviewMatrix()
{
PrintMatrix(modelview);
}
@@ -1270,7 +1529,7 @@ void PrintModelviewMatrix(void)
// Module specific Functions Definition
//----------------------------------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Load Shaders (Vertex and Fragment)
static GLuint LoadDefaultShaders(void)
@@ -1278,7 +1537,11 @@ static GLuint LoadDefaultShaders(void)
// NOTE: Shaders are written using GLSL 110 (desktop), that is equivalent to GLSL 100 on ES2
// Vertex shader directly defined, no external file required
- char vShaderStr[] = " #version 110 \n" // Equivalent to version 100 on ES2
+#if defined(GRAPHICS_API_OPENGL_33)
+ char vShaderStr[] = " #version 110 \n" // NOTE: Equivalent to version 100 on ES2
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ char vShaderStr[] = " #version 100 \n" // NOTE: Must be defined this way! 110 doesn't work!
+#endif
"uniform mat4 projectionMatrix; \n"
"uniform mat4 modelviewMatrix; \n"
"attribute vec3 vertexPosition; \n"
@@ -1294,7 +1557,11 @@ static GLuint LoadDefaultShaders(void)
"} \n";
// Fragment shader directly defined, no external file required
- char fShaderStr[] = " #version 110 \n" // Equivalent to version 100 on ES2
+#if defined(GRAPHICS_API_OPENGL_33)
+ char fShaderStr[] = " #version 110 \n" // NOTE: Equivalent to version 100 on ES2
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ char fShaderStr[] = " #version 100 \n" // NOTE: Must be defined this way! 110 doesn't work!
+#endif
"uniform sampler2D texture0; \n"
"varying vec2 fragTexCoord; \n"
"varying vec4 fragColor; \n"
@@ -1316,11 +1583,21 @@ static GLuint LoadDefaultShaders(void)
glShaderSource(vertexShader, 1, &pvs, NULL);
glShaderSource(fragmentShader, 1, &pfs, NULL);
+ GLint success = 0;
+
glCompileShader(vertexShader);
+
+ glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
+
+ if (success != GL_TRUE) TraceLog(WARNING, "[VSHDR ID %i] Failed to compile default vertex shader...", vertexShader);
+ else TraceLog(INFO, "[VSHDR ID %i] Default vertex shader compiled successfully", vertexShader);
+
glCompileShader(fragmentShader);
- TraceLog(INFO, "[ID %i] Default vertex shader compiled successfully", vertexShader);
- TraceLog(INFO, "[ID %i] Default fragment shader compiled successfully", fragmentShader);
+ glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
+
+ if (success != GL_TRUE) TraceLog(WARNING, "[FSHDR ID %i] Failed to compile default fragment shader...", fragmentShader);
+ else TraceLog(INFO, "[FSHDR ID %i] Default fragment shader compiled successfully", fragmentShader);
program = glCreateProgram();
@@ -1329,11 +1606,26 @@ static GLuint LoadDefaultShaders(void)
glLinkProgram(program);
+ glGetProgramiv(program, GL_LINK_STATUS, &success);
+
+ if (success == GL_FALSE)
+ {
+ int maxLength;
+ int length;
+
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
+
+ char log[maxLength];
+
+ glGetProgramInfoLog(program, maxLength, &length, log);
+
+ TraceLog(INFO, "Shader program fail log: %s", log);
+ }
+ else TraceLog(INFO, "[SHDR ID %i] Default shader program loaded successfully", program);
+
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
- TraceLog(INFO, "[ID %i] Default shader program loaded successfully", program);
-
return program;
}
@@ -1361,8 +1653,8 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName)
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
- TraceLog(INFO, "[ID %i] Vertex shader compiled successfully", vertexShader);
- TraceLog(INFO, "[ID %i] Fragment shader compiled successfully", fragmentShader);
+ TraceLog(INFO, "[VSHDR ID %i] Vertex shader compiled successfully", vertexShader);
+ TraceLog(INFO, "[FSHDR ID %i] Fragment shader compiled successfully", fragmentShader);
program = glCreateProgram();
@@ -1374,7 +1666,7 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName)
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
- TraceLog(INFO, "[ID %i] Shader program loaded successfully", program);
+ TraceLog(INFO, "[SHDR ID %i] Shader program loaded successfully", program);
return program;
}
@@ -1417,7 +1709,7 @@ static void InitializeBuffers(void)
lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line
lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line
- for (int i = 0; i < (3*2*MAX_LINES_BATCH); i++) lines.vertices[i] = 0.0;
+ for (int i = 0; i < (3*2*MAX_LINES_BATCH); i++) lines.vertices[i] = 0.0f;
for (int i = 0; i < (4*2*MAX_LINES_BATCH); i++) lines.colors[i] = 0;
lines.vCounter = 0;
@@ -1427,7 +1719,7 @@ static void InitializeBuffers(void)
triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH); // 3 float by vertex, 3 vertex by triangle
triangles.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH); // 4 float by color, 3 colors by triangle
- for (int i = 0; i < (3*3*MAX_TRIANGLES_BATCH); i++) triangles.vertices[i] = 0.0;
+ for (int i = 0; i < (3*3*MAX_TRIANGLES_BATCH); i++) triangles.vertices[i] = 0.0f;
for (int i = 0; i < (4*3*MAX_TRIANGLES_BATCH); i++) triangles.colors[i] = 0;
triangles.vCounter = 0;
@@ -1437,10 +1729,15 @@ static void InitializeBuffers(void)
quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH); // 3 float by vertex, 4 vertex by quad
quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH); // 2 float by texcoord, 4 texcoord by quad
quads.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_QUADS_BATCH); // 4 float by color, 4 colors by quad
+#if defined(GRAPHICS_API_OPENGL_33)
quads.indices = (unsigned int *)malloc(sizeof(int)*6*MAX_QUADS_BATCH); // 6 int by quad (indices)
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ quads.indices = (unsigned short *)malloc(sizeof(short)*6*MAX_QUADS_BATCH); // 6 int by quad (indices)
+#endif
+
- for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0;
- for (int i = 0; i < (2*4*MAX_QUADS_BATCH); i++) quads.texcoords[i] = 0.0;
+ for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0f;
+ for (int i = 0; i < (2*4*MAX_QUADS_BATCH); i++) quads.texcoords[i] = 0.0f;
for (int i = 0; i < (4*4*MAX_QUADS_BATCH); i++) quads.colors[i] = 0;
int k = 0;
@@ -1461,14 +1758,19 @@ static void InitializeBuffers(void)
quads.vCounter = 0;
quads.tcCounter = 0;
quads.cCounter = 0;
+
+ TraceLog(INFO, "CPU buffers (lines, triangles, quads) initialized successfully");
}
// Initialize Vertex Array Objects (Contain VBO)
-static void InitializeVAOs(void)
+static void InitializeBuffersGPU(void)
{
- // Initialize Lines VAO
- glGenVertexArrays(1, &vaoLines);
- glBindVertexArray(vaoLines);
+ if (vaoSupported)
+ {
+ // Initialize Lines VAO
+ glGenVertexArrays(1, &vaoLines);
+ glBindVertexArray(vaoLines);
+ }
// Create buffers for our vertex data
glGenBuffers(2, linesBuffer);
@@ -1485,12 +1787,16 @@ static void InitializeVAOs(void)
glEnableVertexAttribArray(colorLoc);
glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
- TraceLog(INFO, "[ID %i] Lines VAO initialized successfully", vaoLines);
+ if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Lines VAO initialized successfully", vaoLines);
+ else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Lines VBOs initialized successfully", linesBuffer[0], linesBuffer[1]);
//--------------------------------------------------------------
- // Initialize Triangles VAO
- glGenVertexArrays(1, &vaoTriangles);
- glBindVertexArray(vaoTriangles);
+ if (vaoSupported)
+ {
+ // Initialize Triangles VAO
+ glGenVertexArrays(1, &vaoTriangles);
+ glBindVertexArray(vaoTriangles);
+ }
// Create buffers for our vertex data
glGenBuffers(2, trianglesBuffer);
@@ -1506,12 +1812,16 @@ static void InitializeVAOs(void)
glEnableVertexAttribArray(colorLoc);
glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
- TraceLog(INFO, "[ID %i] Triangles VAO initialized successfully", vaoTriangles);
+ if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Triangles VAO initialized successfully", vaoTriangles);
+ else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Triangles VBOs initialized successfully", trianglesBuffer[0], trianglesBuffer[1]);
//--------------------------------------------------------------
- // Initialize Quads VAO (Buffer A)
- glGenVertexArrays(1, &vaoQuads);
- glBindVertexArray(vaoQuads);
+ if (vaoSupported)
+ {
+ // Initialize Quads VAO
+ glGenVertexArrays(1, &vaoQuads);
+ glBindVertexArray(vaoQuads);
+ }
// Create buffers for our vertex data
glGenBuffers(4, quadsBuffer);
@@ -1534,19 +1844,24 @@ static void InitializeVAOs(void)
// Fill index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);
+#if defined(GRAPHICS_API_OPENGL_33)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
+#endif
- TraceLog(INFO, "[ID %i] Quads VAO initialized successfully", vaoQuads);
+ if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Quads VAO initialized successfully", vaoQuads);
+ else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Quads VBOs initialized successfully", quadsBuffer[0], quadsBuffer[1], quadsBuffer[2], quadsBuffer[3]);
// Unbind the current VAO
- glBindVertexArray(0);
+ if (vaoSupported) glBindVertexArray(0);
}
// Update VBOs with vertex array data
static void UpdateBuffers(void)
{
// Activate Lines VAO
- glBindVertexArray(vaoLines);
+ if (vaoSupported) glBindVertexArray(vaoLines);
// Lines - vertex positions buffer
glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]);
@@ -1561,7 +1876,7 @@ static void UpdateBuffers(void)
//--------------------------------------------------------------
// Activate Triangles VAO
- glBindVertexArray(vaoTriangles);
+ if (vaoSupported) glBindVertexArray(vaoTriangles);
// Triangles - vertex positions buffer
glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]);
@@ -1576,7 +1891,7 @@ static void UpdateBuffers(void)
//--------------------------------------------------------------
// Activate Quads VAO
- glBindVertexArray(vaoQuads);
+ if (vaoSupported) glBindVertexArray(vaoQuads);
// Quads - vertex positions buffer
glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
@@ -1601,12 +1916,12 @@ static void UpdateBuffers(void)
//--------------------------------------------------------------
// Unbind the current VAO
- glBindVertexArray(0);
+ if (vaoSupported) glBindVertexArray(0);
}
-#endif //defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+#endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-#ifdef USE_OPENGL_11
+#if defined(GRAPHICS_API_OPENGL_11)
// Mipmaps data is generated after image data
static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight)
@@ -1735,7 +2050,7 @@ static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight)
#endif
-#ifdef RLGL_STANDALONE
+#if defined(RLGL_STANDALONE)
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
diff --git a/src/rlgl.h b/src/rlgl.h
index 7675963b..7c8eb74b 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -1,11 +1,11 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* rlgl - raylib OpenGL abstraction layer
*
* raylib now uses OpenGL 1.1 style functions (rlVertex) that are mapped to selected OpenGL version:
* OpenGL 1.1 - Direct map rl* -> gl*
* OpenGL 3.3+ - Vertex data is stored in VAOs, call rlglDraw() to render
-* OpenGL ES 2 - Same behaviour as OpenGL 3.3+ (NOT TESTED)
+* OpenGL ES 2 - Same behaviour as OpenGL 3.3+
*
* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
@@ -39,16 +39,49 @@
#include "raymath.h" // Required for data type Matrix and Matrix functions
// Select desired OpenGL version
-//#define USE_OPENGL_11
-//#define USE_OPENGL_33
-//#define USE_OPENGL_ES2
+// NOTE: Those preprocessor defines are only used on rlgl module,
+// if OpenGL version is required by any other module, it uses rlGetVersion()
+
+// Choose opengl version here or just define it at compile time: -DGRAPHICS_API_OPENGL_33
+//#define GRAPHICS_API_OPENGL_11 // Only available on PLATFORM_DESKTOP
+//#define GRAPHICS_API_OPENGL_33 // Only available on PLATFORM_DESKTOP
+//#define GRAPHICS_API_OPENGL_ES2 // Only available on PLATFORM_ANDROID or PLATFORM_RPI
+
+// Security check in case no GRAPHICS_API_OPENGL_* defined
+#if !defined(GRAPHICS_API_OPENGL_11) && !defined(GRAPHICS_API_OPENGL_33) && !defined(GRAPHICS_API_OPENGL_ES2)
+ #define GRAPHICS_API_OPENGL_11
+#endif
+
+// Security check in case no GRAPHICS_API_OPENGL_* defined
+#if !defined(GRAPHICS_API_OPENGL_11) && !defined(GRAPHICS_API_OPENGL_33) && !defined(GRAPHICS_API_OPENGL_ES2)
+ #define GRAPHICS_API_OPENGL_11
+#endif
+
+// Security check in case multiple GRAPHICS_API_OPENGL_* defined
+#if defined(GRAPHICS_API_OPENGL_11)
+ #if defined(GRAPHICS_API_OPENGL_33)
+ #undef GRAPHICS_API_OPENGL_33
+ #endif
+
+ #if defined(GRAPHICS_API_OPENGL_ES2)
+ #undef GRAPHICS_API_OPENGL_ES2
+ #endif
+#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-#define MAX_LINES_BATCH 8192 // NOTE: Be careful with limits!
-#define MAX_TRIANGLES_BATCH 4096 // NOTE: Be careful with limits!
-#define MAX_QUADS_BATCH 8192 // NOTE: Be careful with limits!
+#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
+ // NOTE: This is the maximum amount of lines, triangles and quads per frame, be careful!
+ #define MAX_LINES_BATCH 8192
+ #define MAX_TRIANGLES_BATCH 4096
+ #define MAX_QUADS_BATCH 4096
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+ // NOTE: Reduce memory sizes for embedded systems (RPI)
+ #define MAX_LINES_BATCH 2048 // Critical for wire shapes (sphere)
+ #define MAX_TRIANGLES_BATCH 2048 // Critical for some shapes (sphere)
+ #define MAX_QUADS_BATCH 1024 // Be careful with text, every letter maps a quad
+#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -59,6 +92,8 @@ typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode;
typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
+typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
+
#ifdef RLGL_STANDALONE
typedef struct {
int vertexCount;
@@ -71,6 +106,7 @@ typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
typedef struct Model {
VertexData mesh;
unsigned int vaoId;
+ unsigned int vboId[4];
unsigned int textureId;
//Matrix transform;
} Model;
@@ -112,31 +148,32 @@ void rlColor4f(float x, float y, float z, float w); // Define one vertex (color)
// Functions Declaration - OpenGL equivalent functions (common to 1.1, 3.3+, ES2)
// NOTE: This functions are used to completely abstract raylib code from OpenGL layer
//------------------------------------------------------------------------------------
-void rlEnableTexture(unsigned int id); // Enable texture usage
-void rlDisableTexture(void); // Disable texture usage
-void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
-void rlDeleteVertexArrays(unsigned int id); // Unload vertex data from GPU memory
+void rlEnableTexture(unsigned int id); // Enable texture usage
+void rlDisableTexture(void); // Disable texture usage
+void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
+void rlDeleteVertexArrays(unsigned int id); // Unload vertex data (VAO) from GPU memory
+void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from GPU memory
void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color
-void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
+void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
+int rlGetVersion(void); // Returns current OpenGL version
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
//------------------------------------------------------------------------------------
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
void rlglInit(void); // Initialize rlgl (shaders, VAO, VBO...)
void rlglClose(void); // De-init rlgl
-void rlglDraw(void); // Draw VAOs
-unsigned int rlglLoadModel(VertexData mesh);
+void rlglDraw(void); // Draw VAO/VBO
+void rlglInitGraphics(int offsetX, int offsetY, int width, int height); // Initialize Graphics (OpenGL stuff)
+
+unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps); // Load in GPU OpenGL texture
unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format);
-#endif
+Model rlglLoadModel(VertexData mesh); // Upload vertex data into GPU and provided VAO/VBO ids
void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires);
-void rlglInitGraphicsDevice(int fbWidth, int fbHeight); // Initialize Graphics Device (OpenGL stuff)
-unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps); // Load in GPU OpenGL texture
byte *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
void PrintProjectionMatrix(void); // DEBUG: Print projection matrix
void PrintModelviewMatrix(void); // DEBUG: Print modelview matrix
#endif
diff --git a/src/shapes.c b/src/shapes.c
index 17210f21..6fa26bee 100644
--- a/src/shapes.c
+++ b/src/shapes.c
@@ -1,10 +1,10 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raylib.shapes
*
* Basic functions to draw 2d Shapes and check collisions
*
-* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -31,11 +31,6 @@
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
-// Security check in case no USE_OPENGL_* defined
-#if !defined(USE_OPENGL_11) && !defined(USE_OPENGL_33) && !defined(USE_OPENGL_ES2)
- #define USE_OPENGL_11
-#endif
-
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@@ -185,43 +180,44 @@ void DrawRectangleGradient(int posX, int posY, int width, int height, Color colo
// Draw a color-filled rectangle (Vector version)
void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{
-#ifdef USE_OPENGL_11
- rlBegin(RL_TRIANGLES);
- rlColor4ub(color.r, color.g, color.b, color.a);
-
- rlVertex2i(position.x, position.y);
- rlVertex2i(position.x, position.y + size.y);
- rlVertex2i(position.x + size.x, position.y + size.y);
+ if (rlGetVersion() == OPENGL_11)
+ {
+ rlBegin(RL_TRIANGLES);
+ rlColor4ub(color.r, color.g, color.b, color.a);
- rlVertex2i(position.x, position.y);
- rlVertex2i(position.x + size.x, position.y + size.y);
- rlVertex2i(position.x + size.x, position.y);
- rlEnd();
-#endif
+ rlVertex2i(position.x, position.y);
+ rlVertex2i(position.x, position.y + size.y);
+ rlVertex2i(position.x + size.x, position.y + size.y);
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
- // NOTE: This shape uses QUADS to avoid drawing order issues (view rlglDraw)
- rlEnableTexture(1); // Default white texture
+ rlVertex2i(position.x, position.y);
+ rlVertex2i(position.x + size.x, position.y + size.y);
+ rlVertex2i(position.x + size.x, position.y);
+ rlEnd();
+ }
+ else if ((rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
+ {
+ // NOTE: This shape uses QUADS to avoid drawing order issues (view rlglDraw)
+ rlEnableTexture(1); // Default white texture
- rlBegin(RL_QUADS);
- rlColor4ub(color.r, color.g, color.b, color.a);
- rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
+ rlBegin(RL_QUADS);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
- rlTexCoord2f(0.0f, 0.0f);
- rlVertex2f(position.x, position.y);
+ rlTexCoord2f(0.0f, 0.0f);
+ rlVertex2f(position.x, position.y);
- rlTexCoord2f(0.0f, 1.0f);
- rlVertex2f(position.x, position.y + size.y);
+ rlTexCoord2f(0.0f, 1.0f);
+ rlVertex2f(position.x, position.y + size.y);
- rlTexCoord2f(1.0f, 1.0f);
- rlVertex2f(position.x + size.x, position.y + size.y);
+ rlTexCoord2f(1.0f, 1.0f);
+ rlVertex2f(position.x + size.x, position.y + size.y);
- rlTexCoord2f(1.0f, 0.0f);
- rlVertex2f(position.x + size.x, position.y);
- rlEnd();
+ rlTexCoord2f(1.0f, 0.0f);
+ rlVertex2f(position.x + size.x, position.y);
+ rlEnd();
- rlDisableTexture();
-#endif
+ rlDisableTexture();
+ }
}
// Draw rectangle outline
@@ -457,4 +453,4 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
}
return retRec;
-}
+} \ No newline at end of file
diff --git a/src/stb_image.c b/src/stb_image.c
index b11e44ff..b9e1b304 100644
--- a/src/stb_image.c
+++ b/src/stb_image.c
@@ -151,14 +151,15 @@ static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp);
static int stbi_tga_info(stbi *s, int *x, int *y, int *comp);
static int stbi_psd_test(stbi *s);
static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-static int stbi_hdr_test(stbi *s);
-static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp);
static int stbi_pic_test(stbi *s);
static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp);
static int stbi_gif_test(stbi *s);
static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp);
static int stbi_gif_info(stbi *s, int *x, int *y, int *comp);
+// RAY: Commented because not used
+//static int stbi_hdr_test(stbi *s);
+//static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp);
// this is not threadsafe
static const char *failure_reason;
@@ -2619,7 +2620,7 @@ static int shiftsigned(int v, int shift, int bits)
static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp)
{
uint8 *out;
- unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0;
+ unsigned int mr=0,mg=0,mb=0,ma=0; //fake_a=0;
stbi_uc pal[256][4];
int psize=0,i,j,compress=0,width;
int bpp, flip_vertically, pad, target, offset, hsz;
@@ -2668,7 +2669,7 @@ static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp)
mg = 0xffu << 8;
mb = 0xffu << 0;
ma = 0xffu << 24;
- fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255
+ //fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255
} else {
mr = 31u << 10;
mg = 31u << 5;
diff --git a/src/stb_image.h b/src/stb_image.h
index 900e0c20..0eeece13 100644
--- a/src/stb_image.h
+++ b/src/stb_image.h
@@ -183,7 +183,6 @@
// The three functions you must define are "read" (reads some bytes of data),
// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
-
#define STBI_NO_HDR // RaySan: not required by raylib
#ifndef STBI_NO_STDIO
@@ -195,6 +194,11 @@
#include <stdio.h>
#endif
+// NOTE: Added to work with raylib on Android
+#if defined(PLATFORM_ANDROID)
+ #include "utils.h" // Android fopen function map
+#endif
+
#define STBI_VERSION 1
enum
diff --git a/src/stb_vorbis.h b/src/stb_vorbis.h
index 2d7b61e5..bff27496 100644
--- a/src/stb_vorbis.h
+++ b/src/stb_vorbis.h
@@ -37,6 +37,11 @@
#include <stdio.h>
#endif
+// NOTE: Added to work with raylib on Android
+#if defined(PLATFORM_ANDROID)
+ #include "utils.h" // Android fopen function map
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/text.c b/src/text.c
index 54294b14..b42d7d11 100644
--- a/src/text.c
+++ b/src/text.c
@@ -1,13 +1,10 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raylib.text
*
* Basic functions to load SpriteFonts and draw Text
*
-* Uses external lib:
-* stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC)
-*
-* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -31,10 +28,9 @@
#include <stdlib.h> // Declares malloc() and free() for memory management
#include <string.h> // String management functions (just strlen() is used)
#include <stdarg.h> // Used for functions with variable number of parameters (FormatText())
-#include "stb_image.h" // Used to read image data (multiple formats support)
+#include <stdio.h> // Standard input / output lib
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
-
#include "utils.h" // Required for function GetExtendion()
//----------------------------------------------------------------------------------
@@ -79,6 +75,9 @@ static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Char
static int GetNextPOT(int num); // Calculate next power-of-two value for a given value
static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font)
+extern void LoadDefaultFont(void);
+extern void UnloadDefaultFont(void);
+
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
@@ -188,53 +187,29 @@ extern void UnloadDefaultFont(void)
}
// Get the default font, useful to be used with extended parameters
-SpriteFont GetDefaultFont(void)
+SpriteFont GetDefaultFont()
{
return defaultFont;
}
// Load a SpriteFont image into GPU memory
-SpriteFont LoadSpriteFont(const char* fileName)
+SpriteFont LoadSpriteFont(const char *fileName)
{
SpriteFont spriteFont;
- Image image;
-
// Check file extension
if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName);
else
{
- // Use stb_image to load image data!
- int imgWidth;
- int imgHeight;
- int imgBpp;
-
- byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); // Force loading to 4 components (RGBA)
-
- // Convert array to pixel array for working convenience
- Color *imgDataPixel = (Color *)malloc(imgWidth * imgHeight * sizeof(Color));
- Color *imgDataPixelPOT = NULL;
-
- int pix = 0;
-
- for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4)
- {
- imgDataPixel[pix].r = imgData[i];
- imgDataPixel[pix].g = imgData[i+1];
- imgDataPixel[pix].b = imgData[i+2];
- imgDataPixel[pix].a = imgData[i+3];
- pix++;
- }
-
- stbi_image_free(imgData);
+ Image image = LoadImage(fileName);
// At this point we have a pixel array with all the data...
- TraceLog(INFO, "[%s] SpriteFont image loaded: %i x %i", fileName, imgWidth, imgHeight);
+ TraceLog(INFO, "[%s] SpriteFont image loaded: %i x %i", fileName, image.width, image.height);
// Process bitmap Font pixel data to get measures (Character array)
// spriteFont.charSet data is filled inside the function and memory is allocated!
- int numChars = ParseImageData(imgDataPixel, imgWidth, imgHeight, &spriteFont.charSet);
+ int numChars = ParseImageData(image.pixels, image.width, image.height, &spriteFont.charSet);
TraceLog(INFO, "[%s] SpriteFont data parsed correctly", fileName);
TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", fileName, numChars);
@@ -242,13 +217,17 @@ SpriteFont LoadSpriteFont(const char* fileName)
spriteFont.numChars = numChars;
// Convert image font to POT image before conversion to texture
+ // NOTE: Not required, we skip this step
+/*
// Just add the required amount of pixels at the right and bottom sides of image...
- int potWidth = GetNextPOT(imgWidth);
- int potHeight = GetNextPOT(imgHeight);
+ int potWidth = GetNextPOT(image.width);
+ int potHeight = GetNextPOT(image.height);
// Check if POT texture generation is required (if texture is not already POT)
- if ((potWidth != imgWidth) || (potHeight != imgHeight))
+ if ((potWidth != image.width) || (potHeight != image.height))
{
+ Color *imgDataPixelPOT = NULL;
+
// Generate POT array from NPOT data
imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color));
@@ -256,20 +235,20 @@ SpriteFont LoadSpriteFont(const char* fileName)
{
for (int i = 0; i < potWidth; i++)
{
- if ((j < imgHeight) && (i < imgWidth)) imgDataPixelPOT[j*potWidth + i] = imgDataPixel[j*imgWidth + i];
+ if ((j < image.height) && (i < image.width)) imgDataPixelPOT[j*potWidth + i] = image.pixels[j*image.width + i];
else imgDataPixelPOT[j*potWidth + i] = MAGENTA;
}
}
TraceLog(WARNING, "SpriteFont texture converted to POT: %ix%i", potWidth, potHeight);
- }
- free(imgDataPixel);
-
- image.pixels = imgDataPixelPOT;
- image.width = potWidth;
- image.height = potHeight;
+ free(image.pixels);
+ image.pixels = imgDataPixelPOT;
+ image.width = potWidth;
+ image.height = potHeight;
+ }
+*/
spriteFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture
UnloadImage(image);
}
@@ -287,7 +266,7 @@ void UnloadSpriteFont(SpriteFont spriteFont)
// Draw text (using default font)
// NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used
// NOTE: chars spacing is proportional to fontSize
-void DrawText(const char* text, int posX, int posY, int fontSize, Color color)
+void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
{
Vector2 position = { (float)posX, (float)posY };
@@ -303,7 +282,7 @@ void DrawText(const char* text, int posX, int posY, int fontSize, Color color)
// Draw text using SpriteFont
// NOTE: If font size is lower than base size, base size is used
// NOTE: chars spacing is NOT proportional to fontSize
-void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int fontSize, int spacing, Color tint)
+void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int fontSize, int spacing, Color tint)
{
int length = strlen(text);
int positionX = (int)position.x;
@@ -398,12 +377,14 @@ int GetFontBaseSize(SpriteFont spriteFont)
// NOTE: Uses default font
void DrawFPS(int posX, int posY)
{
+ char buffer[20];
+
// NOTE: We are rendering fps every second for better viewing on high framerates
- static float fps;
- static int counter = 0;
- static int refreshRate = 0;
+ // TODO: Not working properly on ANDROID and RPI
- char buffer[20];
+ static float fps = 0.0f;
+ static int counter = 0;
+ static int refreshRate = 20;
if (counter < refreshRate)
{
diff --git a/src/textures.c b/src/textures.c
index 39947d12..e342e21b 100644
--- a/src/textures.c
+++ b/src/textures.c
@@ -1,4 +1,4 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raylib.textures
*
@@ -6,8 +6,9 @@
*
* Uses external lib:
* 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) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -30,15 +31,12 @@
#include <stdlib.h> // Declares malloc() and free() for memory management
#include <string.h> // Required for strcmp(), strrchr(), strncmp()
-#include "stb_image.h" // Used to read image data (multiple formats support)
-#include "utils.h" // rRES data decompression utility function
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
+#include "utils.h" // rRES data decompression utility function
+ // NOTE: Includes Android fopen function map
-// Security check in case no USE_OPENGL_* defined
-#if !defined(USE_OPENGL_11) && !defined(USE_OPENGL_33) && !defined(USE_OPENGL_ES2)
- #define USE_OPENGL_11
-#endif
+#include "stb_image.h" // Used to read image data (multiple formats support)
//----------------------------------------------------------------------------------
// Defines and Macros
@@ -73,7 +71,8 @@ typedef struct {
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
-static ImageEx LoadDDS(const char *fileName);
+static ImageEx LoadDDS(const char *fileName); // Load DDS file
+static ImageEx LoadPKM(const char *fileName); // Load PKM file
//----------------------------------------------------------------------------------
// Module Functions Definition
@@ -155,14 +154,18 @@ Image LoadImage(const char *fileName)
free(imageDDS.data);
- TraceLog(INFO, "[%s] Image loaded successfully", fileName);
+ TraceLog(INFO, "[%s] DDS Image loaded successfully (uncompressed, no mipmaps)", fileName);
}
- else TraceLog(WARNING, "[%s] Compressed image data could not be loaded", fileName);
+ else TraceLog(WARNING, "[%s] DDS Compressed image data could not be loaded", fileName);
+ }
+ else if (strcmp(GetExtension(fileName),"pkm") == 0)
+ {
+ TraceLog(INFO, "[%s] PKM Compressed image data could not be loaded", fileName);
}
else TraceLog(WARNING, "[%s] Image extension not recognized, it can't be loaded", fileName);
// ALTERNATIVE: We can load pixel data directly into Color struct pixels array,
- // to do that struct data alignment should be the right one (4 byte); it is.
+ // to do that, struct data alignment should be the right one (4 byte); it is.
//image.pixels = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4);
return image;
@@ -302,9 +305,7 @@ Texture2D LoadTexture(const char *fileName)
}
else
{
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
texture.id = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.compFormat);
-#endif
}
texture.width = image.width;
@@ -315,6 +316,20 @@ Texture2D LoadTexture(const char *fileName)
free(image.data);
}
+ else if (strcmp(GetExtension(fileName),"pkm") == 0)
+ {
+ ImageEx image = LoadPKM(fileName);
+
+ texture.id = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.compFormat);
+
+ texture.width = image.width;
+ texture.height = image.height;
+
+ if (texture.id == 0) TraceLog(WARNING, "[%s] PKM texture could not be loaded", fileName);
+ else TraceLog(INFO, "[%s] PKM texture loaded successfully", fileName);
+
+ free(image.data);
+ }
else
{
Image image = LoadImage(fileName);
@@ -453,8 +468,6 @@ Texture2D CreateTexture(Image image, bool genMipmaps)
texture.width = image.width;
texture.height = image.height;
- TraceLog(INFO, "[ID %i] Texture created successfully", texture.id);
-
free(imgData);
}
else TraceLog(WARNING, "Texture could not be created, image data is not valid");
@@ -471,15 +484,15 @@ ImageEx LoadDDS(const char *fileName)
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
- #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+ #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
- #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+ #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
- #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+ #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif
// DDS Pixel Format
@@ -582,11 +595,9 @@ ImageEx LoadDDS(const char *fileName)
}
else if ((header.ddspf.flags == 0x04) && (header.ddspf.fourCC > 0))
{
-#ifdef USE_OPENGL_11
- TraceLog(WARNING, "[%s] DDS image uses compression, not supported by current OpenGL version", fileName);
+ TraceLog(WARNING, "[%s] DDS image uses compression, not supported on OpenGL 1.1", fileName);
TraceLog(WARNING, "[%s] DDS compressed files require OpenGL 3.2+ or ES 2.0", fileName);
- fclose(ddsFile);
-#else
+
int bufsize;
// Calculate data size, including all mipmaps
@@ -614,10 +625,96 @@ ImageEx LoadDDS(const char *fileName)
// NOTE: Image num color components not required... for now...
//if (fourCC == FOURCC_DXT1) image.components = 3;
//else image.components = 4;
-#endif
}
}
}
return image;
+}
+
+// Loading PKM image data (ETC1/ETC2 compression)
+// NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps)
+// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps)
+ImageEx LoadPKM(const char *fileName)
+{
+ // If OpenGL ES 2.0. the following format could be supported (ETC1):
+ //GL_ETC1_RGB8_OES
+
+ #ifndef GL_ETC1_RGB8_OES
+ #define GL_ETC1_RGB8_OES 0x8D64
+ #endif
+
+ // If OpenGL ES 3.0, the following formats are supported (ETC2/EAC):
+ //GL_COMPRESSED_RGB8_ETC2
+ //GL_COMPRESSED_RGBA8_ETC2
+ //GL_COMPRESSED_RG11_EAC
+ //...
+
+ // PKM file (ETC1) Header (16 bytes)
+ typedef struct {
+ char id[4]; // "PKM "
+ char version[2]; // "10"
+ unsigned short format; // Format = number of mipmaps = 0 (ETC1_RGB_NO_MIPMAPS)
+ unsigned short extWidth; // Texture width (big-endian)
+ unsigned short extHeight; // Texture height (big-endian)
+ unsigned short origWidth; // Original width (big-endian)
+ unsigned short origHeight; // Original height (big-endian)
+ } pkmHeader;
+
+ // NOTE: The extended width and height are the widths rounded up to a multiple of 4.
+ // NOTE: ETC is always 4bit per pixel (64 bits for each 4x4 block of pixels)
+
+ // Bytes Swap (little-endian <-> big-endian)
+ //unsigned short data;
+ //unsigned short swap = ((data & 0x00FF) << 8) | ((data & 0xFF00) >> 8);
+
+ ImageEx image;
+
+ unsigned short width;
+ unsigned short height;
+ unsigned short useless;
+
+ FILE *pkmFile = fopen(fileName, "rb");
+
+ if (pkmFile == NULL)
+ {
+ TraceLog(WARNING, "[%s] PKM File could not be opened", fileName);
+ }
+ else
+ {
+ // Verify the type of file
+ char filecode[4];
+
+ fread(filecode, 1, 4, pkmFile);
+
+ if (strncmp(filecode, "PKM ", 4) != 0)
+ {
+ TraceLog(WARNING, "[%s] PKM File does not seem to be valid", fileName);
+ fclose(pkmFile);
+ }
+ else
+ {
+ // Get the surface descriptor
+ fread(&useless, sizeof(unsigned short), 1, pkmFile); // Discard version
+ fread(&useless, sizeof(unsigned short), 1, pkmFile); // Discard format
+
+ fread(&width, sizeof(unsigned short), 1, pkmFile); // Read extended width
+ fread(&height, sizeof(unsigned short), 1, pkmFile); // Read extended height
+
+ int size = (width/4)*(height/4)*8; // Total data size in bytes
+
+ image.data = (unsigned char*)malloc(size * sizeof(unsigned char));
+
+ fread(image.data, 1, size, pkmFile);
+
+ fclose(pkmFile); // Close file pointer
+
+ image.width = width;
+ image.height = height;
+ image.mipmaps = 1;
+ image.compFormat = GL_ETC1_RGB8_OES;
+ }
+ }
+
+ return image;
} \ No newline at end of file
diff --git a/src/utils.c b/src/utils.c
index 254cc955..b5112111 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,4 +1,4 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raylib.utils
*
@@ -8,7 +8,7 @@
* tinfl - zlib DEFLATE algorithm decompression lib
* stb_image_write - PNG writting functions
*
-* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -29,20 +29,40 @@
#include "utils.h"
+#if defined(PLATFORM_ANDROID)
+ #include <errno.h>
+ #include <android/log.h>
+ #include <android/asset_manager.h>
+#endif
+
#include <stdlib.h> // malloc(), free()
#include <stdio.h> // printf(), fprintf()
#include <stdarg.h> // Used for functions with variable number of parameters (TraceLog())
//#include <string.h> // String management functions: strlen(), strrchr(), strcmp()
-#define STB_IMAGE_WRITE_IMPLEMENTATION
-#include "stb_image_write.h" // Create PNG file
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
+ #define STB_IMAGE_WRITE_IMPLEMENTATION
+ #include "stb_image_write.h" // Create PNG file
+#endif
#include "tinfl.c"
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
-static FILE *logstream = NULL;
+#if defined(PLATFORM_ANDROID)
+AAssetManager *assetManager;
+#endif
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Declaration
+//----------------------------------------------------------------------------------
+#if defined(PLATFORM_ANDROID)
+static int android_read(void *cookie, char *buf, int size);
+static int android_write(void *cookie, const char *buf, int size);
+static fpos_t android_seek(void *cookie, fpos_t offset, int whence);
+static int android_close(void *cookie);
+#endif
//----------------------------------------------------------------------------------
// Module Functions Definition - Utilities
@@ -87,6 +107,7 @@ unsigned char *DecompressData(const unsigned char *data, unsigned long compSize,
return pUncomp;
}
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
// Creates a bitmap (BMP) file from an array of pixel data
// NOTE: This function is not explicitly available to raylib users
void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height)
@@ -148,52 +169,90 @@ void TraceLog(int msgType, const char *text, ...)
traceDebugMsgs = 0;
#endif
- // NOTE: If trace log file not set, output redirected to stdout
- if (logstream == NULL) logstream = stdout;
-
switch(msgType)
{
- case INFO: fprintf(logstream, "INFO: "); break;
- case ERROR: fprintf(logstream, "ERROR: "); break;
- case WARNING: fprintf(logstream, "WARNING: "); break;
- case DEBUG: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break;
+ case INFO: fprintf(stdout, "INFO: "); break;
+ case ERROR: fprintf(stdout, "ERROR: "); break;
+ case WARNING: fprintf(stdout, "WARNING: "); break;
+ case DEBUG: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break;
default: break;
}
if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs)))
{
va_start(args, text);
- vfprintf(logstream, text, args);
+ vfprintf(stdout, text, args);
va_end(args);
- fprintf(logstream, "\n");
+ fprintf(stdout, "\n");
}
if (msgType == ERROR) exit(1); // If ERROR message, exit program
}
+#endif
-// Open a trace log file (if desired)
-void TraceLogOpen(const char *logFileName)
+#if defined(PLATFORM_ANDROID)
+void TraceLog(int msgType, const char *text, ...)
{
- // stdout redirected to stream file
- FILE *logstream = fopen(logFileName, "w");
+ static char buffer[100];
+
+ switch(msgType)
+ {
+ case INFO: strcpy(buffer, "INFO: "); break;
+ case ERROR: strcpy(buffer, "ERROR: "); break;
+ case WARNING: strcpy(buffer, "WARNING: "); break;
+ case DEBUG: strcpy(buffer, "DEBUG: "); break;
+ default: break;
+ }
+
+ strcat(buffer, text);
+ strcat(buffer, "\n");
+
+ va_list args;
+ va_start(args, buffer);
+
+ switch(msgType)
+ {
+ case INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break;
+ case ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break;
+ case WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break;
+ case DEBUG: __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break;
+ default: break;
+ }
+
+ va_end(args);
+
+ if (msgType == ERROR) exit(1);
+}
- if (logstream == NULL) TraceLog(WARNING, "Unable to open log file");
+// Initialize asset manager from android app
+void InitAssetManager(AAssetManager *manager)
+{
+ assetManager = manager;
}
-// Close the trace log file
-void TraceLogClose()
+// Replacement for fopen
+FILE *android_fopen(const char *fileName, const char *mode)
{
- if (logstream != NULL) fclose(logstream);
+ if (mode[0] == 'w') return NULL;
+
+ AAsset *asset = AAssetManager_open(assetManager, fileName, 0);
+
+ if(!asset) return NULL;
+
+ return funopen(asset, android_read, android_write, android_seek, android_close);
}
+#endif
// Keep track of memory allocated
// NOTE: mallocType defines the type of data allocated
+/*
void RecordMalloc(int mallocType, int mallocSize, const char *msg)
{
// TODO: Investigate how to record memory allocation data...
// Maybe creating my own malloc function...
}
+*/
// Get the extension for a filename
const char *GetExtension(const char *fileName)
@@ -203,3 +262,30 @@ const char *GetExtension(const char *fileName)
return (dot + 1);
}
+//----------------------------------------------------------------------------------
+// Module specific Functions Definition
+//----------------------------------------------------------------------------------
+#if defined(PLATFORM_ANDROID)
+static int android_read(void *cookie, char *buf, int size)
+{
+ return AAsset_read((AAsset *)cookie, buf, size);
+}
+
+static int android_write(void *cookie, const char *buf, int size)
+{
+ TraceLog(ERROR, "Can't provide write access to the APK");
+
+ return EACCES;
+}
+
+static fpos_t android_seek(void *cookie, fpos_t offset, int whence)
+{
+ return AAsset_seek((AAsset *)cookie, offset, whence);
+}
+
+static int android_close(void *cookie)
+{
+ AAsset_close((AAsset *)cookie);
+ return 0;
+}
+#endif
diff --git a/src/utils.h b/src/utils.h
index ac8d55b1..784c7926 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,10 +1,10 @@
-/*********************************************************************************************
+/**********************************************************************************************
*
* raylib.utils
*
* Some utility functions: rRES files data decompression
*
-* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
+* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -26,11 +26,20 @@
#ifndef UTILS_H
#define UTILS_H
+#if defined(PLATFORM_ANDROID)
+ #include <stdio.h> // Defines FILE struct
+ #include <android/asset_manager.h> // defines AAssetManager struct
+#endif
+
//----------------------------------------------------------------------------------
// Some basic Defines
//----------------------------------------------------------------------------------
#define DO_NOT_TRACE_DEBUG_MSGS // Use this define to avoid DEBUG tracing
+#if defined(PLATFORM_ANDROID)
+ #define fopen(name, mode) android_fopen(name, mode)
+#endif
+
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@@ -61,14 +70,18 @@ extern "C" { // Prevents name mangling of functions
//----------------------------------------------------------------------------------
unsigned char *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize);
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height);
void WritePNG(const char *fileName, unsigned char *imgData, int width, int height);
+#endif
void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message
-void TraceLogOpen(const char *logFileName); // Open a trace log file (if desired)
-void TraceLogClose(); // Close the trace log file
+const char *GetExtension(const char *fileName); // Returns extension of a filename
-const char *GetExtension(const char *fileName);
+#if defined(PLATFORM_ANDROID)
+void InitAssetManager(AAssetManager *manager); // Initialize asset manager from android app
+FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen()
+#endif
#ifdef __cplusplus
}