Update C sources and add new functions

This commit is contained in:
Milan Nikolic 2018-02-21 21:26:09 +01:00
parent 9784968948
commit 7874621942
24 changed files with 2149 additions and 1316 deletions

File diff suppressed because it is too large Load diff

View file

@ -10,19 +10,24 @@
* - Manage mixing channels * - Manage mixing channels
* - Manage raw audio context * - Manage raw audio context
* *
* LIMITATIONS: * LIMITATIONS (only OpenAL Soft):
* Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS) * Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS)
* Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32) * Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32)
* *
* DEPENDENCIES: * DEPENDENCIES:
* OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) * mini_al - Audio device/context management (https://github.com/dr-soft/mini_al)
* stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) * stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/)
* jar_xm - XM module file loading (#define SUPPORT_FILEFORMAT_XM) * jar_xm - XM module file loading
* jar_mod - MOD audio file loading (#define SUPPORT_FILEFORMAT_MOD) * jar_mod - MOD audio file loading
* dr_flac - FLAC audio file loading (#define SUPPORT_FILEFORMAT_FLAC) * dr_flac - FLAC audio file loading
*
* *OpenAL Soft - Audio device management, still used on HTML5 and OSX platforms
* *
* CONTRIBUTORS: * CONTRIBUTORS:
* Joshua Reisenauer (github: @kd7tck): * David Reid (github: @mackron) (Nov. 2017):
* - Complete port to mini_al library
*
* Joshua Reisenauer (github: @kd7tck) (2015)
* - XM audio module support (jar_xm) * - XM audio module support (jar_xm)
* - MOD audio module support (jar_mod) * - MOD audio module support (jar_mod)
* - Mixing channels support * - Mixing channels support
@ -31,7 +36,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -81,9 +86,11 @@ typedef struct Wave {
// Sound source type // Sound source type
typedef struct Sound { typedef struct Sound {
unsigned int source; // OpenAL audio source id void *audioBuffer; // Pointer to internal data used by the audio system
unsigned int buffer; // OpenAL audio buffer id
int format; // OpenAL audio format specifier unsigned int source; // Audio source id
unsigned int buffer; // Audio buffer id
int format; // Audio format specifier
} Sound; } Sound;
// Music type (file streaming from memory) // Music type (file streaming from memory)
@ -97,9 +104,11 @@ typedef struct AudioStream {
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo) unsigned int channels; // Number of channels (1-mono, 2-stereo)
int format; // OpenAL audio format specifier void *audioBuffer; // Pointer to internal data used by the audio system.
unsigned int source; // OpenAL audio source id
unsigned int buffers[2]; // OpenAL audio buffers (double buffering) int format; // Audio format specifier
unsigned int source; // Audio source id
unsigned int buffers[2]; // Audio buffers (double buffering)
} AudioStream; } AudioStream;
#ifdef __cplusplus #ifdef __cplusplus
@ -147,12 +156,12 @@ void ResumeMusicStream(Music music); // Resume playin
bool IsMusicPlaying(Music music); // Check if music is playing bool IsMusicPlaying(Music music); // Check if music is playing
void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats) void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats)
float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimeLength(Music music); // Get music time length (in seconds)
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
// Raw audio stream functions // AudioStream management functions
AudioStream InitAudioStream(unsigned int sampleRate, AudioStream InitAudioStream(unsigned int sampleRate,
unsigned int sampleSize, unsigned int sampleSize,
unsigned int channels); // Init audio stream (to stream raw audio pcm data) unsigned int channels); // Init audio stream (to stream raw audio pcm data)
void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
@ -161,7 +170,10 @@ bool IsAudioBufferProcessed(AudioStream stream); // Check if any
void PlayAudioStream(AudioStream stream); // Play audio stream void PlayAudioStream(AudioStream stream); // Play audio stream
void PauseAudioStream(AudioStream stream); // Pause audio stream void PauseAudioStream(AudioStream stream); // Pause audio stream
void ResumeAudioStream(AudioStream stream); // Resume audio stream void ResumeAudioStream(AudioStream stream); // Resume audio stream
bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing
void StopAudioStream(AudioStream stream); // Stop audio stream void StopAudioStream(AudioStream stream); // Stop audio stream
void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -1,18 +1,16 @@
// +build !js
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms * raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms
* *
* PLATFORMS SUPPORTED: * PLATFORMS SUPPORTED:
* PLATFORM_DESKTOP: Windows (Win32, Win64) * - PLATFORM_DESKTOP: Windows (Win32, Win64)
* PLATFORM_DESKTOP: Linux (32 and 64 bit) * - PLATFORM_DESKTOP: Linux (X11 desktop mode)
* PLATFORM_DESKTOP: OSX/macOS * - PLATFORM_DESKTOP: FreeBSD (X11 desktop)
* PLATFORM_DESKTOP: FreeBSD * - PLATFORM_DESKTOP: OSX/macOS
* PLATFORM_ANDROID: Android (ARM, ARM64) * - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64)
* PLATFORM_RPI: Raspberry Pi (Raspbian) * - PLATFORM_RPI: Raspberry Pi 0,1,2,3 (Raspbian)
* PLATFORM_WEB: HTML5 (Chrome, Firefox) * - PLATFORM_WEB: HTML5 with asm.js (Chrome, Firefox)
* PLATFORM_UWP: Universal Windows Platform * - PLATFORM_UWP: Windows 10 App, Windows Phone, Xbox One
* *
* CONFIGURATION: * CONFIGURATION:
* *
@ -32,6 +30,10 @@
* Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js * Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js
* using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code. * using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code.
* *
* #define PLATFORM_UWP
* Universal Windows Platform support, using OpenGL ES 2.0 through ANGLE on multiple Windows platforms,
* including Windows 10 App, Windows Phone and Xbox One platforms.
*
* #define SUPPORT_DEFAULT_FONT (default) * #define SUPPORT_DEFAULT_FONT (default)
* Default font is loaded on window initialization to be available for the user to render simple text. * Default font is loaded on window initialization to be available for the user to render simple text.
* NOTE: If enabled, uses external module functions to load default raylib font (module: text) * NOTE: If enabled, uses external module functions to load default raylib font (module: text)
@ -91,7 +93,7 @@
#include "raylib.h" #include "raylib.h"
#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_S_SOURCE < 199309L #if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L
#undef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
#endif #endif
@ -126,7 +128,7 @@
#include <string.h> // Required for: strrchr(), strcmp() #include <string.h> // Required for: strrchr(), strcmp()
//#include <errno.h> // Macros for reporting and retrieving error conditions through error codes //#include <errno.h> // Macros for reporting and retrieving error conditions through error codes
#ifdef _WIN32 #if defined(_WIN32)
#include <direct.h> // Required for: _getch(), _chdir() #include <direct.h> // Required for: _getch(), _chdir()
#define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir()
#define CHDIR _chdir #define CHDIR _chdir
@ -152,11 +154,11 @@
#include <GLFW/glfw3native.h> // which are required for hiding mouse #include <GLFW/glfw3native.h> // which are required for hiding mouse
#endif #endif
//#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h) //#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h)
//#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version!
#if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32)
__stdcall unsigned int timeBeginPeriod(unsigned int uPeriod); // NOTE: Those functions require linking with winmm library
__stdcall unsigned int timeEndPeriod(unsigned int uPeriod); unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
#endif #endif
#endif #endif
@ -187,6 +189,12 @@
#include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library #include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library
#endif #endif
#if defined(PLATFORM_UWP)
#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
#endif
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
#include <emscripten/emscripten.h> #include <emscripten/emscripten.h>
#include <emscripten/html5.h> #include <emscripten/html5.h>
@ -226,16 +234,17 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
static GLFWwindow *window; // Native window (graphic device) static GLFWwindow *window; // Native window (graphic device)
static bool windowMinimized = false;
#endif #endif
static bool windowReady = false; // Check if window has been initialized successfully
static bool windowMinimized = false; // Check if window has been minimized
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
static struct android_app *app; // Android activity static struct android_app *app; // Android activity
static struct android_poll_source *source; // Android events polling source static struct android_poll_source *source; // Android events polling source
static int ident, events; // Android ALooper_pollAll() variables static int ident, events; // Android ALooper_pollAll() variables
static const char *internalDataPath; // Android internal data path to write data (/data/data/<package>/files) static const char *internalDataPath; // Android internal data path to write data (/data/data/<package>/files)
static bool windowReady = false; // Used to detect display initialization
static bool appEnabled = true; // Used to detec if app is active static bool appEnabled = true; // Used to detec if app is active
static bool contextRebindRequired = false; // Used to know context rebind required static bool contextRebindRequired = false; // Used to know context rebind required
#endif #endif
@ -264,7 +273,7 @@ static pthread_t gamepadThreadId; // Gamepad reading thread id
static char gamepadName[64]; // Gamepad name holder static char gamepadName[64]; // Gamepad name holder
#endif #endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
static EGLDisplay display; // Native display device (physical screen connection) static EGLDisplay display; // Native display device (physical screen connection)
static EGLSurface surface; // Surface to draw on, framebuffers (connected to context) static EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
static EGLContext context; // Graphic context, mode in which drawing can be done static EGLContext context; // Graphic context, mode in which drawing can be done
@ -273,6 +282,10 @@ static uint64_t baseTime; // Base time measure for hi-res timer
static bool windowShouldClose = false; // Flag to set window for closing static bool windowShouldClose = false; // Flag to set window for closing
#endif #endif
#if defined(PLATFORM_UWP)
static EGLNativeWindowType uwpWindow;
#endif
// Display size-related data // Display size-related data
static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...) 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 screenWidth, screenHeight; // Screen width and height (used render area)
@ -281,12 +294,11 @@ static int renderOffsetX = 0; // Offset X from render area (must b
static int renderOffsetY = 0; // Offset Y 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 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) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size)
static bool cursorHidden = false; // Track if cursor is hidden static bool cursorHidden = false; // Track if cursor is hidden
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
static const char *windowTitle = NULL; // Window text title...
static bool cursorOnScreen = false; // Tracks if cursor is inside client area static bool cursorOnScreen = false; // Tracks if cursor is inside client area
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
static const char *windowTitle = NULL; // Window text title...
static int screenshotCounter = 0; // Screenshots counter static int screenshotCounter = 0; // Screenshots counter
// Register mouse states // Register mouse states
@ -331,7 +343,7 @@ static double updateTime, drawTime; // Time measures for update and draw
static double frameTime = 0.0; // Time measure for one frame static double frameTime = 0.0; // Time measure for one frame
static double targetTime = 0.0; // Desired time for one frame, if 0 not applied static double targetTime = 0.0; // Desired time for one frame, if 0 not applied
static char configFlags = 0; // Configuration flags (bit based) static unsigned char configFlags = 0; // Configuration flags (bit based)
static bool showLogo = false; // Track if showing logo at init is enabled static bool showLogo = false; // Track if showing logo at init is enabled
#if defined(SUPPORT_GIF_RECORDING) #if defined(SUPPORT_GIF_RECORDING)
@ -350,10 +362,9 @@ extern void UnloadDefaultFont(void); // [Module: text] Unloads default fo
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static void InitGraphicsDevice(int width, int height); // Initialize graphics device static bool InitGraphicsDevice(int width, int height); // Initialize graphics device
static void SetupFramebufferSize(int displayWidth, int displayHeight); static void SetupFramebufferSize(int displayWidth, int displayHeight);
static void InitTimer(void); // Initialize timer static void InitTimer(void); // Initialize timer
static double GetTime(void); // Returns time since InitTimer() was run
static void Wait(float ms); // Wait for some milliseconds (stop program execution) static void Wait(float ms); // Wait for some milliseconds (stop program execution)
static bool GetKeyStatus(int key); // Returns if a key has been pressed 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 bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed
@ -403,6 +414,10 @@ static void InitGamepad(void); // Init raw gamepad inpu
static void *GamepadThread(void *arg); // Mouse reading thread static void *GamepadThread(void *arg); // Mouse reading thread
#endif #endif
#if defined(PLATFORM_UWP)
// Define functions required to manage inputs
#endif
#if defined(_WIN32) #if defined(_WIN32)
// NOTE: We include Sleep() function signature here to avoid windows.h inclusion // NOTE: We include Sleep() function signature here to avoid windows.h inclusion
void __stdcall Sleep(unsigned long msTimeout); // Required for Wait() void __stdcall Sleep(unsigned long msTimeout); // Required for Wait()
@ -411,18 +426,28 @@ static void *GamepadThread(void *arg); // Mouse reading thread
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Window and OpenGL Context Functions // Module Functions Definition - Window and OpenGL Context Functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
// Initialize window and OpenGL context // Initialize window and OpenGL context
// NOTE: data parameter could be used to pass any kind of required data to the initialization // NOTE: data parameter could be used to pass any kind of required data to the initialization
void InitWindow(int width, int height, void *data) void InitWindow(int width, int height, void *data)
{ {
TraceLog(LOG_INFO, "Initializing raylib (v1.9-dev)"); TraceLog(LOG_INFO, "Initializing raylib (v1.9.4-dev)");
// Input data is window title char data #if defined(PLATFORM_DESKTOP)
windowTitle = (char *)data; windowTitle = (char *)data;
#endif
#if defined(PLATFORM_UWP)
uwpWindow = (EGLNativeWindowType)data;
#endif
// Init hi-res timer
InitTimer();
// Init graphics device (display device and OpenGL context) // Init graphics device (display device and OpenGL context)
InitGraphicsDevice(width, height); // NOTE: returns true if window and graphic device has been initialized successfully
windowReady = InitGraphicsDevice(width, height);
if (!windowReady) return;
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
// Load default font // Load default font
@ -430,9 +455,6 @@ void InitWindow(int width, int height, void *data)
LoadDefaultFont(); LoadDefaultFont();
#endif #endif
// Init hi-res timer
InitTimer();
#if defined(PLATFORM_RPI) #if defined(PLATFORM_RPI)
// Init raw input system // Init raw input system
InitMouse(); // Mouse init InitMouse(); // Mouse init
@ -480,7 +502,7 @@ void InitWindow(int width, int height, void *data)
// NOTE: data parameter could be used to pass any kind of required data to the initialization // NOTE: data parameter could be used to pass any kind of required data to the initialization
void InitWindow(int width, int height, void *data) void InitWindow(int width, int height, void *data)
{ {
TraceLog(LOG_INFO, "Initializing raylib (v1.9-dev)"); TraceLog(LOG_INFO, "Initializing raylib (v1.9.4-dev)");
screenWidth = width; screenWidth = width;
screenHeight = height; screenHeight = height;
@ -564,7 +586,7 @@ void CloseWindow(void)
timeEndPeriod(1); // Restore time period timeEndPeriod(1); // Restore time period
#endif #endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
// Close surface, context and display // Close surface, context and display
if (display != EGL_NO_DISPLAY) if (display != EGL_NO_DISPLAY)
{ {
@ -602,25 +624,36 @@ void CloseWindow(void)
TraceLog(LOG_INFO, "Window closed successfully"); TraceLog(LOG_INFO, "Window closed successfully");
} }
// Check if window has been initialized successfully
bool IsWindowReady(void)
{
return windowReady;
}
// Check if KEY_ESCAPE pressed or Close icon pressed // Check if KEY_ESCAPE pressed or Close icon pressed
bool WindowShouldClose(void) bool WindowShouldClose(void)
{ {
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// While window minimized, stop loop execution if (windowReady)
while (windowMinimized) glfwWaitEvents(); {
// While window minimized, stop loop execution
while (windowMinimized) glfwWaitEvents();
return (glfwWindowShouldClose(window)); return (glfwWindowShouldClose(window));
}
else return true;
#endif #endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
return windowShouldClose; if (windowReady) return windowShouldClose;
else return true;
#endif #endif
} }
// Check if window has been minimized (or lost focus) // Check if window has been minimized (or lost focus)
bool IsWindowMinimized(void) bool IsWindowMinimized(void)
{ {
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
return windowMinimized; return windowMinimized;
#else #else
return false; return false;
@ -687,7 +720,7 @@ void SetWindowMonitor(int monitor)
if ((monitor >= 0) && (monitor < monitorCount)) if ((monitor >= 0) && (monitor < monitorCount))
{ {
glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE); //glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE);
TraceLog(LOG_INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); TraceLog(LOG_INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
} }
else TraceLog(LOG_WARNING, "Selected monitor not found"); else TraceLog(LOG_WARNING, "Selected monitor not found");
@ -781,18 +814,17 @@ void DisableCursor()
// Set background color (framebuffer clear color) // Set background color (framebuffer clear color)
void ClearBackground(Color color) void ClearBackground(Color color)
{ {
// Clear full framebuffer (not only render area) to color rlClearColor(color.r, color.g, color.b, color.a); // Set clear color
rlClearColor(color.r, color.g, color.b, color.a); rlClearScreenBuffers(); // Clear current framebuffers
} }
// Setup canvas (framebuffer) to start drawing // Setup canvas (framebuffer) to start drawing
void BeginDrawing(void) void BeginDrawing(void)
{ {
currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called currentTime = GetTime(); // Number of elapsed seconds since InitTimer()
updateTime = currentTime - previousTime; updateTime = currentTime - previousTime;
previousTime = currentTime; previousTime = currentTime;
rlClearScreenBuffers(); // Clear current framebuffers
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
rlMultMatrixf(MatrixToFloat(downscaleView)); // If downscale required, apply it here rlMultMatrixf(MatrixToFloat(downscaleView)); // If downscale required, apply it here
@ -930,7 +962,7 @@ void BeginTextureMode(RenderTexture2D target)
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
rlEnableRenderTexture(target.id); // Enable render target rlEnableRenderTexture(target.id); // Enable render target
rlClearScreenBuffers(); // Clear render texture buffers rlClearScreenBuffers(); // Clear render texture buffers
// Set viewport to framebuffer size // Set viewport to framebuffer size
@ -1062,7 +1094,25 @@ float GetFrameTime(void)
return (float)frameTime; return (float)frameTime;
} }
// Converts Color to float array and normalizes // Get elapsed time measure in seconds since InitTimer()
// NOTE: On PLATFORM_DESKTOP InitTimer() is called on InitWindow()
// NOTE: On PLATFORM_DESKTOP, timer is initialized on glfwInit()
double GetTime(void)
{
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
return glfwGetTime(); // Elapsed time since glfwInit()
#endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
uint64_t time = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec;
return (double)(time - baseTime)*1e-9; // Elapsed time since InitTimer()
#endif
}
// Returns normalized float array for a Color
float *ColorToFloat(Color color) float *ColorToFloat(Color color)
{ {
static float buffer[4]; static float buffer[4];
@ -1075,6 +1125,64 @@ float *ColorToFloat(Color color)
return buffer; return buffer;
} }
// Returns hexadecimal value for a Color
int ColorToInt(Color color)
{
return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
}
// Returns HSV values for a Color
// NOTE: Hue is returned as degrees [0..360]
Vector3 ColorToHSV(Color color)
{
Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
Vector3 hsv = { 0.0f, 0.0f, 0.0f };
float min, max, delta;
min = rgb.x < rgb.y ? rgb.x : rgb.y;
min = min < rgb.z ? min : rgb.z;
max = rgb.x > rgb.y ? rgb.x : rgb.y;
max = max > rgb.z ? max : rgb.z;
hsv.z = max; // Value
delta = max - min;
if (delta < 0.00001f)
{
hsv.y = 0.0f;
hsv.x = 0.0f; // Undefined, maybe NAN?
return hsv;
}
if (max > 0.0f)
{
// NOTE: If max is 0, this divide would cause a crash
hsv.y = (delta/max); // Saturation
}
else
{
// NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
hsv.y = 0.0f;
hsv.x = NAN; // Undefined
return hsv;
}
// NOTE: Comparing float values could not work properly
if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
else
{
if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
}
hsv.x *= 60.0f; // Convert to degrees
if (hsv.x < 0.0f) hsv.x += 360.0f;
return hsv;
}
// Returns a Color struct from hexadecimal value // Returns a Color struct from hexadecimal value
Color GetColor(int hexValue) Color GetColor(int hexValue)
{ {
@ -1088,11 +1196,7 @@ Color GetColor(int hexValue)
return color; return color;
} }
// Returns hexadecimal value for a Color
int GetHexValue(Color color)
{
return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
}
// Returns a random value between min and max (both included) // Returns a random value between min and max (both included)
int GetRandomValue(int min, int max) int GetRandomValue(int min, int max)
@ -1123,7 +1227,7 @@ void ShowLogo(void)
} }
// Setup window configuration flags (view FLAGS) // Setup window configuration flags (view FLAGS)
void SetConfigFlags(char flags) void SetConfigFlags(unsigned char flags)
{ {
configFlags = flags; configFlags = flags;
@ -1159,7 +1263,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
return result; return result;
} }
// Get the extension for a filename // Get pointer to extension for a filename string
const char *GetExtension(const char *fileName) const char *GetExtension(const char *fileName)
{ {
const char *dot = strrchr(fileName, '.'); const char *dot = strrchr(fileName, '.');
@ -1169,6 +1273,17 @@ const char *GetExtension(const char *fileName)
return (dot + 1); return (dot + 1);
} }
// Get pointer to filename for a path string
const char *GetFileName(const char *filePath)
{
const char *fileName = strrchr(filePath, '\\');
if (!fileName || fileName == filePath) return filePath;
return fileName + 1;
}
// Get directory for a given fileName (with path) // Get directory for a given fileName (with path)
const char *GetDirectoryPath(const char *fileName) const char *GetDirectoryPath(const char *fileName)
{ {
@ -1649,7 +1764,8 @@ Vector2 GetTouchPosition(int index)
// Initialize display device and framebuffer // Initialize display device and framebuffer
// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size // 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 // If width or height are 0, default display size will be used for framebuffer size
static void InitGraphicsDevice(int width, int height) // NOTE: returns false in case graphic device could not be created
static bool InitGraphicsDevice(int width, int height)
{ {
screenWidth = width; // User desired width screenWidth = width; // User desired width
screenHeight = height; // User desired height screenHeight = height; // User desired height
@ -1663,12 +1779,22 @@ static void InitGraphicsDevice(int width, int height)
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
glfwSetErrorCallback(ErrorCallback); glfwSetErrorCallback(ErrorCallback);
if (!glfwInit()) TraceLog(LOG_ERROR, "Failed to initialize GLFW"); if (!glfwInit())
{
TraceLog(LOG_WARNING, "Failed to initialize GLFW");
return false;
}
// NOTE: Getting video modes is not implemented in emscripten GLFW3 version // NOTE: Getting video modes is not implemented in emscripten GLFW3 version
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
// Find monitor resolution // Find monitor resolution
const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); GLFWmonitor *monitor = glfwGetPrimaryMonitor();
if (!monitor)
{
TraceLog(LOG_WARNING, "Failed to get monitor");
return false;
}
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
displayWidth = mode->width; displayWidth = mode->width;
displayHeight = mode->height; displayHeight = mode->height;
@ -1774,24 +1900,28 @@ static void InitGraphicsDevice(int width, int height)
// No-fullscreen window creation // No-fullscreen window creation
window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, NULL, NULL); window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, NULL, NULL);
if (window)
{
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
// Center window on screen // Center window on screen
int windowPosX = displayWidth/2 - screenWidth/2; int windowPosX = displayWidth/2 - screenWidth/2;
int windowPosY = displayHeight/2 - screenHeight/2; int windowPosY = displayHeight/2 - screenHeight/2;
if (windowPosX < 0) windowPosX = 0; if (windowPosX < 0) windowPosX = 0;
if (windowPosY < 0) windowPosY = 0; if (windowPosY < 0) windowPosY = 0;
glfwSetWindowPos(window, windowPosX, windowPosY); glfwSetWindowPos(window, windowPosX, windowPosY);
#endif #endif
renderWidth = screenWidth; renderWidth = screenWidth;
renderHeight = screenHeight; renderHeight = screenHeight;
}
} }
if (!window) if (!window)
{ {
glfwTerminate(); glfwTerminate();
TraceLog(LOG_ERROR, "GLFW Failed to initialize Window"); TraceLog(LOG_WARNING, "GLFW Failed to initialize Window");
return false;
} }
else else
{ {
@ -1837,7 +1967,7 @@ static void InitGraphicsDevice(int width, int height)
} }
#endif // defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #endif // defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
fullscreen = true; fullscreen = true;
// Screen size security check // Screen size security check
@ -1880,19 +2010,194 @@ static void InitGraphicsDevice(int width, int height)
EGL_NONE EGL_NONE
}; };
EGLint contextAttribs[] = const EGLint contextAttribs[] =
{ {
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE EGL_NONE
}; };
#if defined(PLATFORM_UWP)
const EGLint surfaceAttributes[] =
{
// EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is part of the same optimization as EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER (see above).
// If you have compilation issues with it then please update your Visual Studio templates.
EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_NONE
};
const EGLint defaultDisplayAttributes[] =
{
// These are the default display attributes, used to request ANGLE's D3D11 renderer.
// eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+.
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
// EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices.
// Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it.
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
// EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call
// the IDXGIDevice3::Trim method on behalf of the application when it gets suspended.
// Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement.
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
EGL_NONE,
};
const EGLint fl9_3DisplayAttributes[] =
{
// These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature Level 9_3.
// These attributes are used if the call to eglInitialize fails with the default display attributes.
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
EGL_NONE,
};
const EGLint warpDisplayAttributes[] =
{
// These attributes can be used to request D3D11 WARP.
// They are used if eglInitialize fails with both the default display attributes and the 9_3 display attributes.
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
EGL_NONE,
};
EGLConfig config = NULL;
// eglGetPlatformDisplayEXT is an alternative to eglGetDisplay. It allows us to pass in display attributes, used to configure D3D11.
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)(eglGetProcAddress("eglGetPlatformDisplayEXT"));
if (!eglGetPlatformDisplayEXT)
{
TraceLog(LOG_WARNING, "Failed to get function eglGetPlatformDisplayEXT");
return false;
}
//
// To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying
// parameters passed to eglGetPlatformDisplayEXT:
// 1) The first calls uses "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 Feature Level 10_0+.
// 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again
// using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level 9_3.
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
//
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
if (display == EGL_NO_DISPLAY)
{
TraceLog(LOG_WARNING, "Failed to initialize EGL display");
return false;
}
if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
{
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices).
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
if (display == EGL_NO_DISPLAY)
{
TraceLog(LOG_WARNING, "Failed to initialize EGL display");
return false;
}
if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
{
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
if (display == EGL_NO_DISPLAY)
{
TraceLog(LOG_WARNING, "Failed to initialize EGL display");
return false;
}
if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
{
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
TraceLog(LOG_WARNING, "Failed to initialize EGL");
return false;
}
}
}
//SetupFramebufferSize(displayWidth, displayHeight);
EGLint numConfigs = 0;
if ((eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs) == EGL_FALSE) || (numConfigs == 0))
{
TraceLog(LOG_WARNING, "Failed to choose first EGLConfig");
return false;
}
// Create a PropertySet and initialize with the EGLNativeWindowType.
//PropertySet^ surfaceCreationProperties = ref new PropertySet();
//surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), window); // CoreWindow^ window
// You can configure the surface to render at a lower resolution and be scaled up to
// the full window size. The scaling is often free on mobile hardware.
//
// One way to configure the SwapChainPanel is to specify precisely which resolution it should render at.
// Size customRenderSurfaceSize = Size(800, 600);
// surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(customRenderSurfaceSize));
//
// Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size.
// e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640
// float customResolutionScale = 0.5f;
// surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(customResolutionScale));
// eglCreateWindowSurface() requires a EGLNativeWindowType parameter,
// In Windows platform: typedef HWND EGLNativeWindowType;
// Property: EGLNativeWindowTypeProperty
// Type: IInspectable
// Description: Set this property to specify the window type to use for creating a surface.
// If this property is missing, surface creation will fail.
//
//const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty";
//https://stackoverflow.com/questions/46550182/how-to-create-eglsurface-using-c-winrt-and-angle
//surface = eglCreateWindowSurface(display, config, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
surface = eglCreateWindowSurface(display, config, uwpWindow, surfaceAttributes);
if (surface == EGL_NO_SURFACE)
{
TraceLog(LOG_WARNING, "Failed to create EGL fullscreen surface");
return false;
}
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (context == EGL_NO_CONTEXT)
{
TraceLog(LOG_WARNING, "Failed to create EGL context");
return false;
}
// Get EGL display window size
eglQuerySurface(display, surface, EGL_WIDTH, &screenWidth);
eglQuerySurface(display, surface, EGL_HEIGHT, &screenHeight);
#else // PLATFORM_ANDROID, PLATFORM_RPI
EGLint numConfigs; EGLint numConfigs;
// Get an EGL display connection // Get an EGL display connection
display = eglGetDisplay(EGL_DEFAULT_DISPLAY); display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY)
{
TraceLog(LOG_WARNING, "Failed to initialize EGL display");
return false;
}
// Initialize the EGL display connection // Initialize the EGL display connection
eglInitialize(display, NULL, NULL); if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
{
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
TraceLog(LOG_WARNING, "Failed to initialize EGL");
return false;
}
// Get an appropriate EGL framebuffer configuration // Get an appropriate EGL framebuffer configuration
eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs); eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs);
@ -1902,6 +2207,12 @@ static void InitGraphicsDevice(int width, int height)
// Create an EGL rendering context // Create an EGL rendering context
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (context == EGL_NO_CONTEXT)
{
TraceLog(LOG_WARNING, "Failed to create EGL context");
return false;
}
#endif
// Create an EGL window surface // Create an EGL window surface
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
@ -1969,7 +2280,8 @@ static void InitGraphicsDevice(int width, int height)
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
{ {
TraceLog(LOG_ERROR, "Unable to attach EGL rendering context to EGL surface"); TraceLog(LOG_WARNING, "Unable to attach EGL rendering context to EGL surface");
return false;
} }
else else
{ {
@ -1985,6 +2297,9 @@ static void InitGraphicsDevice(int width, int height)
} }
#endif // defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) #endif // defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
renderWidth = screenWidth;
renderHeight = screenHeight;
// Initialize OpenGL context (states and resources) // Initialize OpenGL context (states and resources)
// NOTE: screenWidth and screenHeight not used, just stored as globals // NOTE: screenWidth and screenHeight not used, just stored as globals
rlglInit(screenWidth, screenHeight); rlglInit(screenWidth, screenHeight);
@ -2005,6 +2320,7 @@ static void InitGraphicsDevice(int width, int height)
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
windowReady = true; // IMPORTANT! windowReady = true; // IMPORTANT!
#endif #endif
return true;
} }
// Set viewport parameters // Set viewport parameters
@ -2120,22 +2436,6 @@ static void InitTimer(void)
previousTime = GetTime(); // Get time as double previousTime = GetTime(); // Get time as double
} }
// Get current time measure (in seconds) since InitTimer()
static double GetTime(void)
{
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
return glfwGetTime();
#endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
uint64_t time = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec;
return (double)(time - baseTime)*1e-9;
#endif
}
// Wait for some milliseconds (stop program execution) // Wait for some milliseconds (stop program execution)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could // NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop // take longer than expected... for that reason we use the busy wait loop
@ -2369,7 +2669,7 @@ static void SwapBuffers(void)
glfwSwapBuffers(window); glfwSwapBuffers(window);
#endif #endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
eglSwapBuffers(display, surface); eglSwapBuffers(display, surface);
#endif #endif
} }
@ -2433,7 +2733,9 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
else else
{ {
currentKeyState[key] = action; currentKeyState[key] = action;
if (action == GLFW_PRESS) lastKeyPressed = key;
// NOTE: lastKeyPressed already registered on CharCallback()
//if (action == GLFW_PRESS) lastKeyPressed = key;
} }
} }
@ -2499,12 +2801,15 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
#endif #endif
} }
// GLFW3 Char Key Callback, runs on key pressed (get char value) // GLFW3 Char Key Callback, runs on key down (get unicode char value)
static void CharCallback(GLFWwindow *window, unsigned int key) static void CharCallback(GLFWwindow *window, unsigned int key)
{ {
// NOTE: Registers any key down considering OS keyboard layout but
// do not detects action events, those should be managed by user...
// https://github.com/glfw/glfw/issues/668#issuecomment-166794907
// http://www.glfw.org/docs/latest/input_guide.html#input_char
lastKeyPressed = key; lastKeyPressed = key;
//TraceLog(LOG_INFO, "Char Callback Key pressed: %i\n", key);
} }
// GLFW3 CursorEnter Callback, when cursor enters the window // GLFW3 CursorEnter Callback, when cursor enters the window
@ -2604,6 +2909,9 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
{ {
// Init graphics device (display device and OpenGL context) // Init graphics device (display device and OpenGL context)
InitGraphicsDevice(screenWidth, screenHeight); InitGraphicsDevice(screenWidth, screenHeight);
// Init hi-res timer
InitTimer();
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
// Load default font // Load default font
@ -2626,9 +2934,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
} }
*/ */
// Init hi-res timer
InitTimer();
// raylib logo appearing animation (if enabled) // raylib logo appearing animation (if enabled)
if (showLogo) if (showLogo)
{ {

View file

@ -211,6 +211,13 @@ func GetFrameTime() float32 {
return v return v
} }
// GetTime - Return time in seconds
func GetTime() float32 {
ret := C.GetTime()
v := (float32)(ret)
return v
}
// GetColor - Returns a Color struct from hexadecimal value // GetColor - Returns a Color struct from hexadecimal value
func GetColor(hexValue int32) Color { func GetColor(hexValue int32) Color {
chexValue := (C.int)(hexValue) chexValue := (C.int)(hexValue)
@ -219,14 +226,23 @@ func GetColor(hexValue int32) Color {
return v return v
} }
// GetHexValue - Returns hexadecimal value for a Color // ColorToInt - Returns hexadecimal value for a Color
func GetHexValue(color Color) int32 { func ColorToInt(color Color) int32 {
ccolor := color.cptr() ccolor := color.cptr()
ret := C.GetHexValue(*ccolor) ret := C.ColorToInt(*ccolor)
v := (int32)(ret) v := (int32)(ret)
return v return v
} }
// ColorToHSV - Returns HSV values for a Color
// NOTE: Hue is returned as degrees [0..360]
func ColorToHSV(color Color) Vector3 {
ccolor := color.cptr()
ret := C.ColorToHSV(*ccolor)
v := newVector3FromPointer(unsafe.Pointer(&ret))
return v
}
// ColorToFloat - Converts Color to float32 slice and normalizes // ColorToFloat - Converts Color to float32 slice and normalizes
func ColorToFloat(color Color) []float32 { func ColorToFloat(color Color) []float32 {
data := make([]float32, 0) data := make([]float32, 0)
@ -297,7 +313,7 @@ func ShowLogo() {
// SetConfigFlags - Setup some window configuration flags // SetConfigFlags - Setup some window configuration flags
func SetConfigFlags(flags byte) { func SetConfigFlags(flags byte) {
cflags := (C.char)(flags) cflags := (C.uchar)(flags)
C.SetConfigFlags(cflags) C.SetConfigFlags(cflags)
} }

View file

@ -1,5 +1,5 @@
// Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file. // Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file.
// mini_al - v0.x - 2017-xx-xx // mini_al - v0.6b - 2018-02-03
// //
// David Reid - davidreidsoftware@gmail.com // David Reid - davidreidsoftware@gmail.com
@ -59,7 +59,7 @@
// //
// Building (BSD) // Building (BSD)
// -------------- // --------------
// The BSD build uses OSS and should Just Work without any linking nor include path configuration. // BSD build uses OSS. Requires linking to -lossaudio on {Open,Net}BSD, but not FreeBSD.
// //
// Building (Emscripten) // Building (Emscripten)
// --------------------- // ---------------------
@ -1422,12 +1422,13 @@ mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFram
// The same mal_src_read_frames() with extra control over whether or not the internal buffers should be flushed at the end. // The same mal_src_read_frames() with extra control over whether or not the internal buffers should be flushed at the end.
// //
// Internally there exists a buffer that keeps track of the previous and next samples for sample rate conversion. The simple // Internally there exists a buffer that keeps track of the previous and next samples for sample rate conversion. The simple
// version of this function does _not_ flush this buffer because otherwise it causes clitches for streaming based conversion // version of this function does _not_ flush this buffer because otherwise it causes glitches for streaming based conversion
// pipelines. The problem, however, is that sometimes you need those last few samples (such as if you're doing a bulk conversion // pipelines. The problem, however, is that sometimes you need those last few samples (such as if you're doing a bulk conversion
// of a static file). Enabling flushing will fix this for you. // of a static file). Enabling flushing will fix this for you.
mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// DSP // DSP
@ -1465,6 +1466,8 @@ mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 chann
// Helper for initializing a mal_dsp_config object. // Helper for initializing a mal_dsp_config object.
mal_dsp_config mal_dsp_config_init(mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut); mal_dsp_config mal_dsp_config_init(mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// Utiltities // Utiltities
@ -1554,6 +1557,10 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form
#include <string.h> // For memset() #include <string.h> // For memset()
#endif #endif
#if defined(MAL_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
#include <mach/mach_time.h> // For mach_absolute_time()
#endif
#ifdef MAL_POSIX #ifdef MAL_POSIX
#include <unistd.h> #include <unistd.h>
#include <dlfcn.h> #include <dlfcn.h>
@ -1635,7 +1642,14 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form
#define MAL_HAS_OPENSL // Like OSS, OpenSL is the only supported backend for Android. It must be present. #define MAL_HAS_OPENSL // Like OSS, OpenSL is the only supported backend for Android. It must be present.
#endif #endif
#ifdef MAL_ENABLE_OPENAL #ifdef MAL_ENABLE_OPENAL
#define MAL_HAS_OPENAL // mini_al inlines the necessary OpenAL stuff. #define MAL_HAS_OPENAL
#ifdef MAL_NO_RUNTIME_LINKING
#ifdef __has_include
#if !__has_include(<AL/al.h>)
#undef MAL_HAS_OPENAL
#endif
#endif
#endif
#endif #endif
#ifdef MAL_ENABLE_SDL #ifdef MAL_ENABLE_SDL
#define MAL_HAS_SDL #define MAL_HAS_SDL
@ -1764,7 +1778,10 @@ typedef HWND (WINAPI * MAL_PFN_GetDesktopWindow)();
#define mal_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / mal_get_sample_size_in_bytes(format) / (channels)) #define mal_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / mal_get_sample_size_in_bytes(format) / (channels))
// Some of these string utility functions are unused on some platforms. // Some of these string utility functions are unused on some platforms.
#if defined(__GNUC__) #if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4505)
#elif defined(__GNUC__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-function"
#endif #endif
@ -1962,7 +1979,9 @@ static int mal_strcmp(const char* str1, const char* str2)
return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0];
} }
#if defined(__GNUC__) #if defined(_MSC_VER)
#pragma warning(pop)
#elif defined(__GNUC__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
@ -2067,6 +2086,24 @@ double mal_timer_get_time_in_seconds(mal_timer* pTimer)
return (counter.QuadPart - pTimer->counter) / (double)g_mal_TimerFrequency.QuadPart; return (counter.QuadPart - pTimer->counter) / (double)g_mal_TimerFrequency.QuadPart;
} }
#elif defined(MAL_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
static uint64_t g_mal_TimerFrequency = 0;
void mal_timer_init(mal_timer* pTimer)
{
mach_timebase_info_data_t baseTime;
mach_timebase_info(&baseTime);
g_mal_TimerFrequency = (baseTime.denom * 1e9) / baseTime.numer;
pTimer->counter = mach_absolute_time();
}
double mal_timer_get_time_in_seconds(mal_timer* pTimer)
{
uint64_t newTimeCounter = mach_absolute_time();
uint64_t oldTimeCounter = pTimer->counter;
return (newTimeCounter - oldTimeCounter) / g_mal_TimerFrequency;
}
#else #else
void mal_timer_init(mal_timer* pTimer) void mal_timer_init(mal_timer* pTimer)
{ {
@ -2746,10 +2783,10 @@ static mal_result mal_context__try_get_device_name_by_id(mal_context* pContext,
} break; } break;
#endif #endif
#ifdef MAL_HAS_COREAUDIO #ifdef MAL_HAS_COREAUDIO
case mal_backend_coreaudio //case mal_backend_coreaudio:
{ //{
// TODO: Implement me. // // TODO: Implement me.
} break; //} break;
#endif #endif
#ifdef MAL_HAS_OSS #ifdef MAL_HAS_OSS
case mal_backend_oss: case mal_backend_oss:
@ -5486,8 +5523,8 @@ struct
const char* name; const char* name;
float scale; float scale;
} g_malDefaultBufferSizeScalesALSA[] = { } g_malDefaultBufferSizeScalesALSA[] = {
{"bcm2835 IEC958/HDMI", 32}, {"bcm2835 IEC958/HDMI", 20},
{"bcm2835 ALSA", 32} {"bcm2835 ALSA", 20}
}; };
static float mal_find_default_buffer_size_scale__alsa(const char* deviceName) static float mal_find_default_buffer_size_scale__alsa(const char* deviceName)
@ -6697,6 +6734,10 @@ static mal_result mal_device__main_loop__alsa(mal_device* pDevice)
#include <fcntl.h> #include <fcntl.h>
#include <sys/soundcard.h> #include <sys/soundcard.h>
#ifndef SNDCTL_DSP_HALT
#define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
#endif
int mal_open_temp_device__oss() int mal_open_temp_device__oss()
{ {
// The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. // The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same.
@ -8833,6 +8874,8 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal
mal_assert(pConfig != NULL); mal_assert(pConfig != NULL);
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
(void)pContext;
// SDL wants the buffer size to be a power of 2. The SDL_AudioSpec property for this is only a Uint16, so we need // SDL wants the buffer size to be a power of 2. The SDL_AudioSpec property for this is only a Uint16, so we need
// to explicitly clamp this because it will be easy to overflow. // to explicitly clamp this because it will be easy to overflow.
mal_uint32 bufferSize = pConfig->bufferSizeInFrames; mal_uint32 bufferSize = pConfig->bufferSizeInFrames;
@ -10750,7 +10793,7 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
(void)channelMapOut; (void)channelMapOut;
(void)channelMapIn; (void)channelMapIn;
if (mode == mal_channel_mix_mode_basic) {\ if (mode == mal_channel_mix_mode_basic) {
// Basic mode is where we just zero out extra channels. // Basic mode is where we just zero out extra channels.
for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) {
switch (channelsIn) { switch (channelsIn) {
@ -10775,23 +10818,23 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
// Zero out extra channels. // Zero out extra channels.
switch (channelsOut - channelsIn) { switch (channelsOut - channelsIn) {
case 17: pFramesOut[iFrame*channelsOut+16] = 0; case 17: pFramesOut[iFrame*channelsOut+16 + channelsIn] = 0;
case 16: pFramesOut[iFrame*channelsOut+15] = 0; case 16: pFramesOut[iFrame*channelsOut+15 + channelsIn] = 0;
case 15: pFramesOut[iFrame*channelsOut+14] = 0; case 15: pFramesOut[iFrame*channelsOut+14 + channelsIn] = 0;
case 14: pFramesOut[iFrame*channelsOut+13] = 0; case 14: pFramesOut[iFrame*channelsOut+13 + channelsIn] = 0;
case 13: pFramesOut[iFrame*channelsOut+12] = 0; case 13: pFramesOut[iFrame*channelsOut+12 + channelsIn] = 0;
case 12: pFramesOut[iFrame*channelsOut+11] = 0; case 12: pFramesOut[iFrame*channelsOut+11 + channelsIn] = 0;
case 11: pFramesOut[iFrame*channelsOut+10] = 0; case 11: pFramesOut[iFrame*channelsOut+10 + channelsIn] = 0;
case 10: pFramesOut[iFrame*channelsOut+ 9] = 0; case 10: pFramesOut[iFrame*channelsOut+ 9 + channelsIn] = 0;
case 9: pFramesOut[iFrame*channelsOut+ 8] = 0; case 9: pFramesOut[iFrame*channelsOut+ 8 + channelsIn] = 0;
case 8: pFramesOut[iFrame*channelsOut+ 7] = 0; case 8: pFramesOut[iFrame*channelsOut+ 7 + channelsIn] = 0;
case 7: pFramesOut[iFrame*channelsOut+ 6] = 0; case 7: pFramesOut[iFrame*channelsOut+ 6 + channelsIn] = 0;
case 6: pFramesOut[iFrame*channelsOut+ 5] = 0; case 6: pFramesOut[iFrame*channelsOut+ 5 + channelsIn] = 0;
case 5: pFramesOut[iFrame*channelsOut+ 4] = 0; case 5: pFramesOut[iFrame*channelsOut+ 4 + channelsIn] = 0;
case 4: pFramesOut[iFrame*channelsOut+ 3] = 0; case 4: pFramesOut[iFrame*channelsOut+ 3 + channelsIn] = 0;
case 3: pFramesOut[iFrame*channelsOut+ 2] = 0; case 3: pFramesOut[iFrame*channelsOut+ 2 + channelsIn] = 0;
case 2: pFramesOut[iFrame*channelsOut+ 1] = 0; case 2: pFramesOut[iFrame*channelsOut+ 1 + channelsIn] = 0;
case 1: pFramesOut[iFrame*channelsOut+ 0] = 0; case 1: pFramesOut[iFrame*channelsOut+ 0 + channelsIn] = 0;
} }
} }
} else { } else {
@ -10822,10 +10865,10 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
} }
} else if (channelsIn == 2) { } else if (channelsIn == 2) {
// TODO: Implement an optimized stereo conversion. // TODO: Implement an optimized stereo conversion.
mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); mal_dsp_mix_channels__inc(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic);
} else { } else {
// Fall back to basic mixing mode. // Fall back to basic mixing mode.
mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); mal_dsp_mix_channels__inc(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic);
} }
} }
} }
@ -11484,7 +11527,15 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count)
// REVISION HISTORY // REVISION HISTORY
// ================ // ================
// //
// v0.x - 2017-xx-xx // v0.6b - 2018-02-03
// - Fix some warnings when compiling with Visual C++.
//
// v0.6a - 2018-01-26
// - Fix errors with channel mixing when increasing the channel count.
// - Improvements to the build system for the OpenAL backend.
// - Documentation fixes.
//
// v0.6 - 2017-12-08
// - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll // - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll
// need to update. // need to update.
// - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively. // - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively.
@ -11497,7 +11548,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count)
// - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of // - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of
// audio data to a different format. // audio data to a different format.
// - Improvements to f32 -> u8/s16/s24/s32 conversion routines. // - Improvements to f32 -> u8/s16/s24/s32 conversion routines.
// - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL and SDL backends. // - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend.
// - Fixes and improvements for Raspberry Pi. // - Fixes and improvements for Raspberry Pi.
// - Warning fixes. // - Warning fixes.
// //

View file

@ -24,7 +24,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -522,7 +522,7 @@ static double GetCurrentTime(void)
#if defined(_WIN32) #if defined(_WIN32)
unsigned long long int clockFrequency, currentTime; unsigned long long int clockFrequency, currentTime;
QueryPerformanceFrequency(&clockFrequency); QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
QueryPerformanceCounter(&currentTime); QueryPerformanceCounter(&currentTime);
time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds
@ -538,8 +538,8 @@ static double GetCurrentTime(void)
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
//#define CLOCK_REALTIME CALENDAR_CLOCK //#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01
//#define CLOCK_MONOTONIC SYSTEM_CLOCK //#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time
clock_serv_t cclock; clock_serv_t cclock;
mach_timespec_t now; mach_timespec_t now;

View file

@ -1,5 +1,3 @@
// +build !js
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.models - Basic functions to deal with 3d shapes and 3d models * raylib.models - Basic functions to deal with 3d shapes and 3d models
@ -19,7 +17,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -47,9 +45,7 @@
#include "raylib.h" #include "raylib.h"
#if defined(PLATFORM_ANDROID) #include "utils.h" // Required for: fopen() Android mapping
#include "utils.h" // Android fopen function map
#endif
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets() #include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets()
#include <stdlib.h> // Required for: malloc(), free() #include <stdlib.h> // Required for: malloc(), free()
@ -59,7 +55,7 @@
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#define PAR_SHAPES_IMPLEMENTATION #define PAR_SHAPES_IMPLEMENTATION
#include "external/par_shapes.h" #include "external/par_shapes.h" // Shapes 3d parametric generation
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros

View file

@ -178,11 +178,23 @@ const (
KeySpace = 32 KeySpace = 32
KeyEscape = 256 KeyEscape = 256
KeyEnter = 257 KeyEnter = 257
KeyTab = 258
KeyBackspace = 259 KeyBackspace = 259
KeyInsert = 260
KeyDelete = 261
KeyRight = 262 KeyRight = 262
KeyLeft = 263 KeyLeft = 263
KeyDown = 264 KeyDown = 264
KeyUp = 265 KeyUp = 265
KeyPageUp = 266
KeyPageDown = 267
KeyHome = 268
KeyEnd = 269
KeyCapsLock = 280
KeyScrollLock = 281
KeyNumLock = 282
KeyPrintScreen = 283
KeyPause = 284
KeyF1 = 290 KeyF1 = 290
KeyF2 = 291 KeyF2 = 291
KeyF3 = 292 KeyF3 = 292
@ -872,15 +884,15 @@ func newSpriteFontFromPointer(ptr unsafe.Pointer) SpriteFont {
return *(*SpriteFont)(ptr) return *(*SpriteFont)(ptr)
} }
// TextureFormat - Texture format // PixelFormat - Texture format
type TextureFormat int32 type PixelFormat int32
// Texture formats // Texture formats
// NOTE: Support depends on OpenGL version and platform // NOTE: Support depends on OpenGL version and platform
const ( const (
// 8 bit per pixel (no alpha) // 8 bit per pixel (no alpha)
UncompressedGrayscale TextureFormat = iota + 1 UncompressedGrayscale PixelFormat = iota + 1
// 16 bpp (2 channels) // 8*2 bpp (2 channels)
UncompressedGrayAlpha UncompressedGrayAlpha
// 16 bpp // 16 bpp
UncompressedR5g6b5 UncompressedR5g6b5
@ -892,6 +904,12 @@ const (
UncompressedR4g4b4a4 UncompressedR4g4b4a4
// 32 bpp // 32 bpp
UncompressedR8g8b8a8 UncompressedR8g8b8a8
// 32 bpp (1 channel - float)
UncompressedR32
// 32*3 bpp (3 channels - float)
UncompressedR32g32b32
// 32*4 bpp (4 channels - float)
UncompressedR32g32b32a32
// 4 bpp (no alpha) // 4 bpp (no alpha)
CompressedDxt1Rgb CompressedDxt1Rgb
// 4 bpp (1 bit alpha) // 4 bpp (1 bit alpha)
@ -958,8 +976,8 @@ type Image struct {
Height int32 Height int32
// Mipmap levels, 1 by default // Mipmap levels, 1 by default
Mipmaps int32 Mipmaps int32
// Data format (TextureFormat) // Data format (PixelFormat)
Format TextureFormat Format PixelFormat
} }
// ToImage converts a Image to Go image.Image // ToImage converts a Image to Go image.Image
@ -975,7 +993,7 @@ func (i *Image) ToImage() image.Image {
} }
// NewImage - Returns new Image // NewImage - Returns new Image
func NewImage(data []byte, width, height, mipmaps int32, format TextureFormat) *Image { func NewImage(data []byte, width, height, mipmaps int32, format PixelFormat) *Image {
d := unsafe.Pointer(&data[0]) d := unsafe.Pointer(&data[0])
return &Image{d, width, height, mipmaps, format} return &Image{d, width, height, mipmaps, format}
} }
@ -1012,12 +1030,12 @@ type Texture2D struct {
Height int32 Height int32
// Mipmap levels, 1 by default // Mipmap levels, 1 by default
Mipmaps int32 Mipmaps int32
// Data format (TextureFormat) // Data format (PixelFormat)
Format TextureFormat Format PixelFormat
} }
// NewTexture2D - Returns new Texture2D // NewTexture2D - Returns new Texture2D
func NewTexture2D(id uint32, width, height, mipmaps int32, format TextureFormat) Texture2D { func NewTexture2D(id uint32, width, height, mipmaps int32, format PixelFormat) Texture2D {
return Texture2D{id, width, height, mipmaps, format} return Texture2D{id, width, height, mipmaps, format}
} }
@ -1048,15 +1066,11 @@ func newRenderTexture2DFromPointer(ptr unsafe.Pointer) RenderTexture2D {
// Log message types // Log message types
const ( const (
LogInfo = iota LogInfo = 1 << iota
LogWarning LogWarning
LogError LogError
LogDebug LogDebug
LogOther
) )
var traceDebugMsgs = false var logTypeFlags = LogInfo | LogWarning | LogError
// SetDebug - Set debug messages
func SetDebug(enabled bool) {
traceDebugMsgs = enabled
}

View file

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib v1.9-dev * raylib v1.9.4-dev
* *
* A simple and easy-to-use library to learn videogames programming (www.raylib.com) * A simple and easy-to-use library to learn videogames programming (www.raylib.com)
* *
@ -103,11 +103,23 @@
#define KEY_SPACE 32 #define KEY_SPACE 32
#define KEY_ESCAPE 256 #define KEY_ESCAPE 256
#define KEY_ENTER 257 #define KEY_ENTER 257
#define KEY_TAB 258
#define KEY_BACKSPACE 259 #define KEY_BACKSPACE 259
#define KEY_INSERT 260
#define KEY_DELETE 261
#define KEY_RIGHT 262 #define KEY_RIGHT 262
#define KEY_LEFT 263 #define KEY_LEFT 263
#define KEY_DOWN 264 #define KEY_DOWN 264
#define KEY_UP 265 #define KEY_UP 265
#define KEY_PAGE_UP 266
#define KEY_PAGE_DOWN 267
#define KEY_HOME 268
#define KEY_END 269
#define KEY_CAPS_LOCK 280
#define KEY_SCROLL_LOCK 281
#define KEY_NUM_LOCK 282
#define KEY_PRINT_SCREEN 283
#define KEY_PAUSE 284
#define KEY_F1 290 #define KEY_F1 290
#define KEY_F2 291 #define KEY_F2 291
#define KEY_F3 292 #define KEY_F3 292
@ -341,7 +353,7 @@ typedef struct Image {
int width; // Image base width int width; // Image base width
int height; // Image base height int height; // Image base height
int mipmaps; // Mipmap levels, 1 by default int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (TextureFormat type) int format; // Data format (PixelFormat type)
} Image; } Image;
// Texture2D type // Texture2D type
@ -351,7 +363,7 @@ typedef struct Texture2D {
int width; // Texture base width int width; // Texture base width
int height; // Texture base height int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (TextureFormat type) int format; // Data format (PixelFormat type)
} Texture2D; } Texture2D;
// RenderTexture2D type, for texture rendering // RenderTexture2D type, for texture rendering
@ -470,11 +482,11 @@ typedef struct Wave {
// Sound source type // Sound source type
typedef struct Sound { typedef struct Sound {
void* audioBuffer; // A pointer to internal data used by the audio system. void *audioBuffer; // Pointer to internal data used by the audio system
unsigned int source; // OpenAL audio source id unsigned int source; // Audio source id
unsigned int buffer; // OpenAL audio buffer id unsigned int buffer; // Audio buffer id
int format; // OpenAL audio format specifier int format; // Audio format specifier
} Sound; } Sound;
// Music type (file streaming from memory) // Music type (file streaming from memory)
@ -488,29 +500,13 @@ typedef struct AudioStream {
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo) unsigned int channels; // Number of channels (1-mono, 2-stereo)
void* audioBuffer; // A pointer to internal data used by the audio system. void *audioBuffer; // Pointer to internal data used by the audio system.
int format; // OpenAL audio format specifier int format; // Audio format specifier
unsigned int source; // OpenAL audio source id unsigned int source; // Audio source id
unsigned int buffers[2]; // OpenAL audio buffers (double buffering) unsigned int buffers[2]; // Audio buffers (double buffering)
} AudioStream; } AudioStream;
// rRES data returned when reading a resource,
// it contains all required data for user (24 byte)
typedef struct RRESData {
unsigned int type; // Resource type (4 byte)
unsigned int param1; // Resouce parameter 1 (4 byte)
unsigned int param2; // Resouce parameter 2 (4 byte)
unsigned int param3; // Resouce parameter 3 (4 byte)
unsigned int param4; // Resouce parameter 4 (4 byte)
void *data; // Resource data pointer (4 byte)
} RRESData;
// RRES type (pointer to RRESData array)
typedef struct RRESData *RRES;
// Head-Mounted-Display device parameters // Head-Mounted-Display device parameters
typedef struct VrDeviceInfo { typedef struct VrDeviceInfo {
int hResolution; // HMD horizontal resolution in pixels int hResolution; // HMD horizontal resolution in pixels
@ -530,11 +526,11 @@ typedef struct VrDeviceInfo {
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Trace log type // Trace log type
typedef enum { typedef enum {
LOG_INFO = 0, LOG_INFO = 1,
LOG_WARNING, LOG_WARNING = 2,
LOG_ERROR, LOG_ERROR = 4,
LOG_DEBUG, LOG_DEBUG = 8,
LOG_OTHER LOG_OTHER = 16
} LogType; } LogType;
// Shader location point type // Shader location point type
@ -587,17 +583,19 @@ typedef enum {
#define MAP_DIFFUSE MAP_ALBEDO #define MAP_DIFFUSE MAP_ALBEDO
#define MAP_SPECULAR MAP_METALNESS #define MAP_SPECULAR MAP_METALNESS
// Texture formats // Pixel formats
// NOTE: Support depends on OpenGL version and platform // NOTE: Support depends on OpenGL version and platform
typedef enum { typedef enum {
UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
UNCOMPRESSED_GRAY_ALPHA, // 16 bpp (2 channels) UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels)
UNCOMPRESSED_R5G6B5, // 16 bpp UNCOMPRESSED_R5G6B5, // 16 bpp
UNCOMPRESSED_R8G8B8, // 24 bpp UNCOMPRESSED_R8G8B8, // 24 bpp
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp UNCOMPRESSED_R8G8B8A8, // 32 bpp
UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR UNCOMPRESSED_R32, // 32 bpp (1 channel - float)
UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float)
UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float)
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp COMPRESSED_DXT3_RGBA, // 8 bpp
@ -609,7 +607,7 @@ typedef enum {
COMPRESSED_PVRT_RGBA, // 4 bpp COMPRESSED_PVRT_RGBA, // 4 bpp
COMPRESSED_ASTC_4x4_RGBA, // 8 bpp COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
COMPRESSED_ASTC_8x8_RGBA // 2 bpp COMPRESSED_ASTC_8x8_RGBA // 2 bpp
} TextureFormat; } PixelFormat;
// Texture parameters: filter mode // Texture parameters: filter mode
// NOTE 1: Filtering considers mipmaps if available in the texture // NOTE 1: Filtering considers mipmaps if available in the texture
@ -672,18 +670,6 @@ typedef enum {
HMD_SONY_PSVR HMD_SONY_PSVR
} VrDeviceType; } VrDeviceType;
// RRESData type
typedef enum {
RRES_TYPE_RAW = 0,
RRES_TYPE_IMAGE,
RRES_TYPE_WAVE,
RRES_TYPE_VERTEX,
RRES_TYPE_TEXT,
RRES_TYPE_FONT_IMAGE,
RRES_TYPE_FONT_CHARDATA, // CharInfo data array
RRES_TYPE_DIRECTORY
} RRESDataType;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
#endif #endif
@ -700,6 +686,7 @@ extern "C" { // Prevents name mangling of functions
// Window-related functions // Window-related functions
RLAPI void InitWindow(int width, int height, void *data); // Initialize window and OpenGL context RLAPI void InitWindow(int width, int height, void *data); // Initialize window and OpenGL context
RLAPI void CloseWindow(void); // Close window and unload OpenGL context RLAPI void CloseWindow(void); // Close window and unload OpenGL context
RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully
RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed
RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus) RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus)
RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP) RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP)
@ -738,12 +725,14 @@ RLAPI Matrix GetCameraMatrix(Camera camera); // Returns cam
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
RLAPI int GetFPS(void); // Returns current FPS RLAPI int GetFPS(void); // Returns current FPS
RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn
RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow()
// Color-related functions // Color-related functions
RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color RLAPI float *ColorToFloat(Color color); // Returns normalized float array for a Color
RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color
RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color
RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
RLAPI float *ColorToFloat(Color color); // Converts Color to float array and normalizes
// Math useful functions (available from raymath.h) // Math useful functions (available from raymath.h)
RLAPI float *Vector3ToFloat(Vector3 vec); // Returns Vector3 as float array RLAPI float *Vector3ToFloat(Vector3 vec); // Returns Vector3 as float array
@ -754,16 +743,18 @@ RLAPI Matrix MatrixIdentity(void); // Returns ide
// Misc. functions // Misc. functions
RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags) RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags)
RLAPI void SetConfigFlags(char flags); // Setup window configuration flags (view FLAGS) RLAPI void SetConfigFlags(unsigned char flags); // Setup window configuration flags (view FLAGS)
RLAPI void SetTraceLog(unsigned char types); // Enable trace log message types (bit flags based)
RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (saved a .png) RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (saved a .png)
RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
// Files management functions // Files management functions
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
RLAPI const char *GetExtension(const char *fileName); // Get file extension RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string
RLAPI const char *GetDirectoryPath(const char *fileName); // Get directory for a given fileName (with path) RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
RLAPI const char *GetWorkingDirectory(void); // Get current working directory RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string)
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
RLAPI bool ChangeDirectory(const char *dir); // Change working directory, returns true if success RLAPI bool ChangeDirectory(const char *dir); // Change working directory, returns true if success
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
RLAPI char **GetDroppedFiles(int *count); // Get dropped files names RLAPI char **GetDroppedFiles(int *count); // Get dropped files names
@ -855,14 +846,14 @@ RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color colo
RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version)
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version)
RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors
RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version)
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
RLAPI void DrawRectangleT(int posX, int posY, int width, int height, Color color); // Draw rectangle using text character RLAPI void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color); // Draw rectangle outline with extended parameters
RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle
RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version)
@ -894,19 +885,24 @@ RLAPI void UnloadImage(Image image);
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI void SaveImageAs(const char *fileName, Image image); // Save image to a PNG file RLAPI void SaveImageAs(const char *fileName, Image image); // Save image to a PNG file
// Image manipulation functions // Image manipulation functions
RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations)
RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering)
RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm)
RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font)
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image
@ -928,7 +924,7 @@ RLAPI Image GenImageGradientH(int width, int height, Color left, Color right);
RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient
RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked
RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise
RLAPI Image GenImagePerlinNoise(int width, int height, float scale); // Generate image: perlin noise RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise
RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm. Bigger tileSize means bigger cells RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm. Bigger tileSize means bigger cells
// Texture2D configuration functions // Texture2D configuration functions
@ -952,19 +948,20 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest
RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont
RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM) RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM)
RLAPI SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load SpriteFont from file with extended parameters RLAPI SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load SpriteFont from file with extended parameters
RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory (VRAM) RLAPI void UnloadSpriteFont(SpriteFont font); // Unload SpriteFont from GPU memory (VRAM)
// Text drawing functions // Text drawing functions
RLAPI void DrawFPS(int posX, int posY); // Shows current FPS RLAPI void DrawFPS(int posX, int posY); // Shows current FPS
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
RLAPI void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters RLAPI void DrawTextEx(SpriteFont font, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters
float fontSize, int spacing, Color tint); float fontSize, int spacing, Color tint);
// Text misc. functions // Text misc. functions
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing); // Measure string size for SpriteFont RLAPI Vector2 MeasureTextEx(SpriteFont font, const char *text, float fontSize, int spacing); // Measure string size for SpriteFont
RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed'
RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string
RLAPI int GetGlyphIndex(SpriteFont font, int character); // Returns index position for a unicode character on sprite font
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Basic 3d Shapes Drawing Functions (Module: models) // Basic 3d Shapes Drawing Functions (Module: models)
@ -1049,7 +1046,8 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);
// Shader loading/unloading functions // Shader loading/unloading functions
RLAPI char *LoadText(const char *fileName); // Load chars array from text file RLAPI char *LoadText(const char *fileName); // Load chars array from text file
RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Load shader from files and bind default locations RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
RLAPI Shader LoadShaderCode(char *vsCode, char *fsCode); // Load shader from code strings and bind default locations
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
RLAPI Shader GetShaderDefault(void); // Get default shader RLAPI Shader GetShaderDefault(void); // Get default shader
@ -1062,6 +1060,7 @@ RLAPI void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int
RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
RLAPI Matrix GetMatrixModelview(); // Get internal modelview matrix
// Texture maps generation (PBR) // Texture maps generation (PBR)
// NOTE: Required shaders should be provided // NOTE: Required shaders should be provided
@ -1145,8 +1144,8 @@ RLAPI void PauseAudioStream(AudioStream stream); // Pause a
RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream
RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -37,7 +37,42 @@ func LoadWave(fileName string) Wave {
// LoadWaveEx - Load wave data from float array data (32bit) // LoadWaveEx - Load wave data from float array data (32bit)
func LoadWaveEx(data []byte, sampleCount int32, sampleRate int32, sampleSize int32, channels int32) Wave { func LoadWaveEx(data []byte, sampleCount int32, sampleRate int32, sampleSize int32, channels int32) Wave {
return newWaveFromPointer(unsafe.Pointer(js.Global.Get("Module").Call("_LoadWaveEx", data, sampleCount, sampleRate, sampleSize, channels).Unsafe())) defer func() {
e := recover()
if e == nil {
return
}
if e, ok := e.(*js.Error); ok {
println(e)
} else {
panic(e)
}
}()
w := Wave{}
wav := *(*[unsafe.Sizeof(w)]byte)(unsafe.Pointer(&w))
//// Call C from JavaScript
//var result = Module.ccall('c_add', // name of C function
//'number', // return type
//['number', 'number'], // argument types
//[10, 20]); // arguments
println(wav)
//js.Global.Get("Module").Call("_LoadWaveEx", wav, data, sampleCount, sampleRate, sampleSize, channels)
ww := js.Global.Get("Module").Call("ccall", "LoadWaveEx", "number",
[]string{"array", "number", "number", "number", "number"},
[]interface{}{data, sampleCount, sampleRate, sampleSize, channels}).Uint64()
www := newWaveFromPointer(unsafe.Pointer(&ww))
println(www)
return www
//return newWaveFromPointer(unsafe.Pointer(wav.Unsafe()))
} }
// LoadSound - Load sound to memory // LoadSound - Load sound to memory
@ -47,7 +82,10 @@ func LoadSound(fileName string) Sound {
// LoadSoundFromWave - Load sound to memory from wave data // LoadSoundFromWave - Load sound to memory from wave data
func LoadSoundFromWave(wave Wave) Sound { func LoadSoundFromWave(wave Wave) Sound {
return newSoundFromPointer(unsafe.Pointer(js.Global.Get("Module").Call("_LoadSoundFromWave", wave).Unsafe())) s := js.MakeWrapper(Sound{})
js.Global.Get("Module").Call("_LoadSoundFromWave", wave, s)
return s.Interface().(Sound)
//return newSoundFromPointer(unsafe.Pointer())
} }
// UpdateSound - Update sound buffer with new data // UpdateSound - Update sound buffer with new data

View file

@ -227,21 +227,31 @@ RMDEF float Clamp(float value, float min, float max)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Vector with components value 0.0f // Vector with components value 0.0f
RMDEF Vector2 Vector2Zero(void) { return (Vector2){ 0.0f, 0.0f }; } RMDEF Vector2 Vector2Zero(void)
{
Vector2 tmp = {0.0f, 0.0f};
return tmp;
}
// Vector with components value 1.0f // Vector with components value 1.0f
RMDEF Vector2 Vector2One(void) { return (Vector2){ 1.0f, 1.0f }; } RMDEF Vector2 Vector2One(void)
{
Vector2 tmp = {1.0f, 1.0f};
return tmp;
}
// Add two vectors (v1 + v2) // Add two vectors (v1 + v2)
RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2) RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2)
{ {
return (Vector2){ v1.x + v2.x, v1.y + v2.y }; Vector2 tmp = { v1.x + v2.x, v1.y + v2.y };
return tmp;
} }
// Subtract two vectors (v1 - v2) // Subtract two vectors (v1 - v2)
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
{ {
return (Vector2){ v1.x - v2.x, v1.y - v2.y }; Vector2 tmp = { v1.x - v2.x, v1.y - v2.y };
return tmp;
} }
// Calculate vector length // Calculate vector length
@ -289,7 +299,8 @@ RMDEF void Vector2Negate(Vector2 *v)
// Divide vector by a float value // Divide vector by a float value
RMDEF void Vector2Divide(Vector2 *v, float div) RMDEF void Vector2Divide(Vector2 *v, float div)
{ {
*v = (Vector2){v->x/div, v->y/div}; Vector2 tmp = {v->x/div, v->y/div};
*v = tmp;
} }
// Normalize provided vector // Normalize provided vector
@ -303,21 +314,31 @@ RMDEF void Vector2Normalize(Vector2 *v)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Vector with components value 0.0f // Vector with components value 0.0f
RMDEF Vector3 Vector3Zero(void) { return (Vector3){ 0.0f, 0.0f, 0.0f }; } RMDEF Vector3 Vector3Zero(void)
{
Vector3 tmp = { 0.0f, 0.0f, 0.0f };
return tmp;
}
// Vector with components value 1.0f // Vector with components value 1.0f
RMDEF Vector3 Vector3One(void) { return (Vector3){ 1.0f, 1.0f, 1.0f }; } RMDEF Vector3 Vector3One(void)
{
Vector3 tmp = { 1.0f, 1.0f, 1.0f };
return tmp;
}
// Add two vectors // Add two vectors
RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2) RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2)
{ {
return (Vector3){ v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; Vector3 tmp = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
return tmp;
} }
// Substract two vectors // Substract two vectors
RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
{ {
return (Vector3){ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; Vector3 tmp = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
return tmp;
} }
// Multiply vector by scalar // Multiply vector by scalar
@ -365,12 +386,14 @@ RMDEF Vector3 Vector3Perpendicular(Vector3 v)
if (fabsf(v.y) < min) if (fabsf(v.y) < min)
{ {
min = fabsf(v.y); min = fabsf(v.y);
cardinalAxis = (Vector3){0.0f, 1.0f, 0.0f}; Vector3 tmp = {0.0f, 1.0f, 0.0f};
cardinalAxis = tmp;
} }
if (fabsf(v.z) < min) if (fabsf(v.z) < min)
{ {
cardinalAxis = (Vector3){0.0f, 0.0f, 1.0f}; Vector3 tmp = {0.0f, 0.0f, 1.0f};
cardinalAxis = tmp;
} }
result = Vector3CrossProduct(v, cardinalAxis); result = Vector3CrossProduct(v, cardinalAxis);
@ -740,8 +763,6 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
{ {
Matrix result; Matrix result;
Matrix mat = MatrixIdentity();
float x = axis.x, y = axis.y, z = axis.z; float x = axis.x, y = axis.y, z = axis.z;
float length = sqrtf(x*x + y*y + z*z); float length = sqrtf(x*x + y*y + z*z);
@ -758,33 +779,25 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
float cosres = cosf(angle); float cosres = cosf(angle);
float t = 1.0f - cosres; float t = 1.0f - cosres;
// Cache some matrix values (speed optimization) result.m0 = x*x*t + cosres;
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; result.m1 = y*x*t + z*sinres;
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; result.m2 = z*x*t - y*sinres;
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; result.m3 = 0.0f;
// Construct the elements of the rotation matrix result.m4 = x*y*t - z*sinres;
float b00 = x*x*t + cosres, b01 = y*x*t + z*sinres, b02 = z*x*t - y*sinres; result.m5 = y*y*t + cosres;
float b10 = x*y*t - z*sinres, b11 = y*y*t + cosres, b12 = z*y*t + x*sinres; result.m6 = z*y*t + x*sinres;
float b20 = x*z*t + y*sinres, b21 = y*z*t - x*sinres, b22 = z*z*t + cosres; result.m7 = 0.0f;
// Perform rotation-specific matrix multiplication result.m8 = x*z*t + y*sinres;
result.m0 = a00*b00 + a10*b01 + a20*b02; result.m9 = y*z*t - x*sinres;
result.m1 = a01*b00 + a11*b01 + a21*b02; result.m10 = z*z*t + cosres;
result.m2 = a02*b00 + a12*b01 + a22*b02; result.m11 = 0.0f;
result.m3 = a03*b00 + a13*b01 + a23*b02;
result.m4 = a00*b10 + a10*b11 + a20*b12; result.m12 = 0.0f;
result.m5 = a01*b10 + a11*b11 + a21*b12; result.m13 = 0.0f;
result.m6 = a02*b10 + a12*b11 + a22*b12; result.m14 = 0.0f;
result.m7 = a03*b10 + a13*b11 + a23*b12; result.m15 = 1.0f;
result.m8 = a00*b20 + a10*b21 + a20*b22;
result.m9 = a01*b20 + a11*b21 + a21*b22;
result.m10 = a02*b20 + a12*b21 + a22*b22;
result.m11 = a03*b20 + a13*b21 + a23*b22;
result.m12 = mat.m12;
result.m13 = mat.m13;
result.m14 = mat.m14;
result.m15 = mat.m15;
return result; return result;
} }
@ -1011,7 +1024,8 @@ RMDEF float *MatrixToFloat(Matrix mat)
// Returns identity quaternion // Returns identity quaternion
RMDEF Quaternion QuaternionIdentity(void) RMDEF Quaternion QuaternionIdentity(void)
{ {
return (Quaternion){ 0.0f, 0.0f, 0.0f, 1.0f }; Quaternion q = { 0.0f, 0.0f, 0.0f, 1.0f };
return q;
} }
// Computes the length of a quaternion // Computes the length of a quaternion

View file

@ -1,5 +1,3 @@
// +build !js
/********************************************************************************************** /**********************************************************************************************
* *
* rlgl - raylib OpenGL abstraction layer * rlgl - raylib OpenGL abstraction layer
@ -37,7 +35,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -76,8 +74,24 @@
#if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11)
#if defined(__APPLE__) #if defined(__APPLE__)
#include <OpenGL/gl.h> // OpenGL 1.1 library for OSX #include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
#include <OpenGL/glext.h>
#else #else
#include <GL/gl.h> // OpenGL 1.1 library #if defined(_MSC_VER) // Using MSVC compiler, requires some additional definitions
// APIENTRY for OpenGL function pointer declarations is required
#ifndef APIENTRY
#ifdef _WIN32
#define APIENTRY __stdcall
#else
#define APIENTRY
#endif
#endif
// WINGDIAPI definition. Some Windows OpenGL headers need it
#if !defined(WINGDIAPI) && defined(_WIN32)
#define WINGDIAPI __declspec(dllimport)
#endif
#endif
#include <GL/gl.h> // OpenGL 1.1 library
#endif #endif
#endif #endif
@ -88,6 +102,7 @@
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
#if defined(__APPLE__) #if defined(__APPLE__)
#include <OpenGL/gl3.h> // OpenGL 3 library for OSX #include <OpenGL/gl3.h> // OpenGL 3 library for OSX
#include <OpenGL/gl3ext.h>
#else #else
#define GLAD_IMPLEMENTATION #define GLAD_IMPLEMENTATION
#if defined(RLGL_STANDALONE) #if defined(RLGL_STANDALONE)
@ -112,6 +127,7 @@
#include "shader_distortion.h" // Distortion shader to be embedded #include "shader_distortion.h" // Distortion shader to be embedded
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -272,6 +288,7 @@ static bool useTempBuffer = false;
// Shaders // Shaders
static unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program) static unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program)
static unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program) static unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program)
static Shader defaultShader; // Basic shader, support vertex color and diffuse texture static Shader defaultShader; // Basic shader, support vertex color and diffuse texture
static Shader currentShader; // Shader to be used on rendering (by default, defaultShader) static Shader currentShader; // Shader to be used on rendering (by default, defaultShader)
@ -309,6 +326,8 @@ static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays;
//static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted //static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted
#endif #endif
static bool debugMarkerSupported = false;
// Compressed textures support flags // Compressed textures support flags
static bool texCompDXTSupported = false; // DDS texture compression support static bool texCompDXTSupported = false; // DDS texture compression support
static bool texNPOTSupported = false; // NPOT textures full support static bool texNPOTSupported = false; // NPOT textures full support
@ -327,8 +346,6 @@ static int screenHeight; // Default framebuffer height
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
static void LoadTextureCompressed(unsigned char *data, int width, int height, int compressedFormat, int mipmapCount);
static unsigned int CompileShader(const char *shaderStr, int type); // Compile custom shader and return shader id static unsigned int CompileShader(const char *shaderStr, int type); // Compile custom shader and return shader id
static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program
@ -344,6 +361,9 @@ static void UnloadBuffersDefault(void); // Unload default internal buffers v
static void GenDrawCube(void); // Generate and draw cube static void GenDrawCube(void); // Generate and draw cube
static void GenDrawQuad(void); // Generate and draw quad static void GenDrawQuad(void); // Generate and draw quad
// Get OpenGL internal formats and data type from raylib PixelFormat
static void GetGlFormats(int format, int *glInternalFormat, int *glFormat, int *glType);
#if defined(SUPPORT_VR_SIMULATOR) #if defined(SUPPORT_VR_SIMULATOR)
static void SetStereoConfig(VrDeviceInfo info); // Configure stereo rendering (including distortion shader) with HMD device parameters static void SetStereoConfig(VrDeviceInfo info); // Configure stereo rendering (including distortion shader) with HMD device parameters
static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); // Set internal projection and modelview matrix depending on eye static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); // Set internal projection and modelview matrix depending on eye
@ -414,7 +434,7 @@ void rlPushMatrix(void)
} }
stack[stackCounter] = *currentMatrix; stack[stackCounter] = *currentMatrix;
rlLoadIdentity(); rlLoadIdentity(); // TODO: Review matrix stack logic!
stackCounter++; stackCounter++;
if (currentMatrixMode == RL_MODELVIEW) useTempBuffer = true; if (currentMatrixMode == RL_MODELVIEW) useTempBuffer = true;
@ -644,6 +664,14 @@ void rlEnd(void)
// as well as depth buffer bit-depth (16bit or 24bit or 32bit) // as well as depth buffer bit-depth (16bit or 24bit or 32bit)
// Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits) // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
currentDepth += (1.0f/20000.0f); currentDepth += (1.0f/20000.0f);
// TODO: Verify internal buffers limits
// NOTE: Before launching draw, verify no matrix are left in the stack!
// NOTE: Probably a lines/triangles margin should be left, rlEnd could be called
// after an undetermined number of triangles buffered (check shapes::DrawPoly())
if ((lines.vCounter/2 >= MAX_LINES_BATCH - 2) ||
(triangles.vCounter/3 >= MAX_TRIANGLES_BATCH - 16) ||
(quads.vCounter/4 >= MAX_QUADS_BATCH - 2)) rlglDraw();
} }
// Define one vertex (position) // Define one vertex (position)
@ -1109,7 +1137,7 @@ void rlglInit(int width, int height)
if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) texNPOTSupported = true; if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) texNPOTSupported = true;
// Check texture float support // Check texture float support
if (strcmp(extList[i], (const char *)"OES_texture_float") == 0) texFloatSupported = true; if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) texFloatSupported = true;
#endif #endif
// DDS texture compression support // DDS texture compression support
@ -1139,10 +1167,13 @@ void rlglInit(int width, int height)
// Clamp mirror wrap mode supported // Clamp mirror wrap mode supported
if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true;
// Debug marker support
if(strcmp(extList[i], (const char *)"GL_EXT_debug_marker") == 0) debugMarkerSupported = true;
} }
#ifdef _MSC_VER #if defined(_MSC_VER)
free(extList); //free(extList);
#endif #endif
#if defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_ES2)
@ -1162,6 +1193,8 @@ void rlglInit(int width, int height)
if (texAnisotropicFilterSupported) TraceLog(LOG_INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel); if (texAnisotropicFilterSupported) TraceLog(LOG_INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel);
if (texClampMirrorSupported) TraceLog(LOG_INFO, "[EXTENSION] Clamp mirror wrap texture mode supported"); if (texClampMirrorSupported) TraceLog(LOG_INFO, "[EXTENSION] Clamp mirror wrap texture mode supported");
if (debugMarkerSupported) TraceLog(LOG_INFO, "[EXTENSION] Debug Marker supported");
// Initialize buffers, default shaders and default textures // Initialize buffers, default shaders and default textures
//---------------------------------------------------------- //----------------------------------------------------------
@ -1287,6 +1320,14 @@ int rlGetVersion(void)
#endif #endif
} }
// Set debug marker
void rlSetDebugMarker(const char *text)
{
#if defined(GRAPHICS_API_OPENGL_33)
if (debugMarkerSupported) glInsertEventMarkerEXT(0, text);
#endif
}
// Load OpenGL extensions // Load OpenGL extensions
// NOTE: External loader function could be passed as a pointer // NOTE: External loader function could be passed as a pointer
void rlLoadExtensions(void *loader) void rlLoadExtensions(void *loader)
@ -1381,6 +1422,8 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
} }
#endif #endif
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &id); // Generate Pointer to the texture glGenTextures(1, &id); // Generate Pointer to the texture
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
@ -1388,94 +1431,50 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
#endif #endif
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) int mipWidth = width;
// NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA int mipHeight = height;
switch (format) int mipOffset = 0; // Mipmap data offset
TraceLog(LOG_DEBUG, "Load texture from data memory address: 0x%x", data);
// Load the different mipmap levels
for (int i = 0; i < mipmapCount; i++)
{ {
case UNCOMPRESSED_GRAYSCALE: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (unsigned char *)data); break; unsigned int mipSize = GetPixelDataSize(mipWidth, mipHeight, format);
case UNCOMPRESSED_GRAY_ALPHA: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G6B5: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break; int glInternalFormat, glFormat, glType;
case UNCOMPRESSED_R8G8B8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break; GetGlFormats(format, &glInternalFormat, &glFormat, &glType);
case UNCOMPRESSED_R5G5B5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break;
case UNCOMPRESSED_R4G4B4A4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break; TraceLog(LOG_DEBUG, "Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset);
case UNCOMPRESSED_R8G8B8A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
#if defined(GRAPHICS_API_OPENGL_21) if (glInternalFormat != -1)
case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break;
case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mipmapCount); break;
case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mipmapCount); break;
case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, mipmapCount); break;
#endif
#if defined(GRAPHICS_API_OPENGL_ES2)
case UNCOMPRESSED_R32G32B32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float
case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break;
case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mipmapCount); break;
case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mipmapCount); break; // NOTE: Not supported by WebGL
case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, mipmapCount); break; // NOTE: Not supported by WebGL
case COMPRESSED_ETC1_RGB: if (texCompETC1Supported) LoadTextureCompressed((unsigned char *)data, width, height, GL_ETC1_RGB8_OES, mipmapCount); break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB: if (texCompETC2Supported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB8_ETC2, mipmapCount); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA: if (texCompETC2Supported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA8_ETC2_EAC, mipmapCount); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_PVRT_RGB: if (texCompPVRTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, mipmapCount); break; // NOTE: Requires PowerVR GPU
case COMPRESSED_PVRT_RGBA: if (texCompPVRTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, mipmapCount); break; // NOTE: Requires PowerVR GPU
case COMPRESSED_ASTC_4x4_RGBA: if (texCompASTCSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, mipmapCount); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
case COMPRESSED_ASTC_8x8_RGBA: if (texCompASTCSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, mipmapCount); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
#endif
default: TraceLog(LOG_WARNING, "Texture format not supported"); break;
}
#elif defined(GRAPHICS_API_OPENGL_33)
// NOTE: We define internal (GPU) format as GL_RGBA8 (probably BGRA8 in practice, driver takes care)
// NOTE: On embedded systems, we let the driver choose the best internal format
// Support for multiple color modes (16bit color modes and grayscale)
// (sized)internalFormat format type
// GL_R GL_RED GL_UNSIGNED_BYTE
// GL_RGB565 GL_RGB GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5
// GL_RGB5_A1 GL_RGBA GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_5_5_1
// GL_RGBA4 GL_RGBA GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_4_4_4_4
// GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE
// GL_RGB8 GL_RGB GL_UNSIGNED_BYTE
switch (format)
{
case UNCOMPRESSED_GRAYSCALE:
{ {
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, (unsigned char *)data); if (format < COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, (unsigned char *)data + mipOffset);
else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, (unsigned char *)data + mipOffset);
// With swizzleMask we define how a one channel texture will be mapped to RGBA
// Required GL >= 3.3 or EXT_texture_swizzle/ARB_texture_swizzle #if defined(GRAPHICS_API_OPENGL_33)
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; if (format == UNCOMPRESSED_GRAYSCALE)
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); {
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
TraceLog(LOG_INFO, "[TEX ID %i] Grayscale texture loaded and swizzled", id); glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
} break; }
case UNCOMPRESSED_GRAY_ALPHA: else if (format == UNCOMPRESSED_GRAY_ALPHA)
{ {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, width, height, 0, GL_RG, GL_UNSIGNED_BYTE, (unsigned char *)data); GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; }
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); #endif
} break; }
case UNCOMPRESSED_R5G6B5: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break; mipWidth /= 2;
case UNCOMPRESSED_R8G8B8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break; mipHeight /= 2;
case UNCOMPRESSED_R5G5B5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break; mipOffset += mipSize;
case UNCOMPRESSED_R4G4B4A4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break; // Security check for NPOT textures
case UNCOMPRESSED_R32G32B32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; if (mipWidth < 1) mipWidth = 1;
case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break; if (mipHeight < 1) mipHeight = 1;
case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mipmapCount); break;
case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mipmapCount); break;
case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, mipmapCount); break;
case COMPRESSED_ETC1_RGB: if (texCompETC1Supported) LoadTextureCompressed((unsigned char *)data, width, height, GL_ETC1_RGB8_OES, mipmapCount); break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB: if (texCompETC2Supported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB8_ETC2, mipmapCount); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA: if (texCompETC2Supported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA8_ETC2_EAC, mipmapCount); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_PVRT_RGB: if (texCompPVRTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, mipmapCount); break; // NOTE: Requires PowerVR GPU
case COMPRESSED_PVRT_RGBA: if (texCompPVRTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, mipmapCount); break; // NOTE: Requires PowerVR GPU
case COMPRESSED_ASTC_4x4_RGBA: if (texCompASTCSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, mipmapCount); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
case COMPRESSED_ASTC_8x8_RGBA: if (texCompASTCSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, mipmapCount); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
default: TraceLog(LOG_WARNING, "Texture format not recognized"); break;
} }
#endif
// Texture parameters configuration // Texture parameters configuration
// NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used
@ -1504,8 +1503,9 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
if (mipmapCount > 1) if (mipmapCount > 1)
{ {
// Activate Trilinear filtering if mipmaps are available
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps (must be available) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} }
#endif #endif
@ -1516,7 +1516,7 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
// Unbind current texture // Unbind current texture
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
if (id > 0) TraceLog(LOG_INFO, "[TEX ID %i] Texture created successfully (%ix%i)", id, width, height); if (id > 0) TraceLog(LOG_INFO, "[TEX ID %i] Texture created successfully (%ix%i - %i mipmaps)", id, width, height, mipmapCount);
else TraceLog(LOG_WARNING, "Texture could not be created"); else TraceLog(LOG_WARNING, "Texture could not be created");
return id; return id;
@ -1526,33 +1526,15 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data) void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data)
{ {
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
int glInternalFormat, glFormat, glType;
GetGlFormats(format, &glInternalFormat, &glFormat, &glType);
#if defined(GRAPHICS_API_OPENGL_33) if ((glInternalFormat != -1) && (format < COMPRESSED_DXT1_RGB))
switch (format)
{ {
case UNCOMPRESSED_GRAYSCALE: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, (unsigned char *)data); break; glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, glFormat, glType, (unsigned char *)data);
case UNCOMPRESSED_GRAY_ALPHA: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RG, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G6B5: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G5B5A1: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break;
case UNCOMPRESSED_R4G4B4A4: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8A8: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
default: TraceLog(LOG_WARNING, "Texture format updating not supported"); break;
} }
#elif defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_ES2) else TraceLog(LOG_WARNING, "Texture format updating not supported");
// NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
switch (format)
{
case UNCOMPRESSED_GRAYSCALE: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_GRAY_ALPHA: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G6B5: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G5B5A1: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break;
case UNCOMPRESSED_R4G4B4A4: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8A8: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
default: TraceLog(LOG_WARNING, "Texture format updating not supported"); break;
}
#endif
} }
// Unload texture from GPU memory // Unload texture from GPU memory
@ -1687,7 +1669,7 @@ void rlGenerateMipmaps(Texture2D *texture)
// Load the mipmaps // Load the mipmaps
for (int level = 1; level < mipmapCount; level++) for (int level = 1; level < mipmapCount; level++)
{ {
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data + offset); glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data + offset);
size = mipWidth*mipHeight*4; size = mipWidth*mipHeight*4;
offset += size; offset += size;
@ -2170,44 +2152,28 @@ void *rlReadTexturePixels(Texture2D texture)
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format);
// Other texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE // Other texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE
*/ */
int glFormat = 0, glType = 0;
unsigned int size = texture.width*texture.height;
// NOTE: GL_LUMINANCE and GL_LUMINANCE_ALPHA are removed since OpenGL 3.1
// Must be replaced by GL_RED and GL_RG on Core OpenGL 3.3
switch (texture.format)
{
#if defined(GRAPHICS_API_OPENGL_11)
case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_LUMINANCE; glType = GL_UNSIGNED_BYTE; break; // 8 bit per pixel (no alpha)
case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_LUMINANCE_ALPHA; glType = GL_UNSIGNED_BYTE; break; // 16 bpp (2 channels)
#elif defined(GRAPHICS_API_OPENGL_33)
case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_RED; glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_RG; glType = GL_UNSIGNED_BYTE; break;
#endif
case UNCOMPRESSED_R5G6B5: pixels = (unsigned short *)malloc(size); glFormat = GL_RGB; glType = GL_UNSIGNED_SHORT_5_6_5; break; // 16 bpp
case UNCOMPRESSED_R8G8B8: pixels = (unsigned char *)malloc(size*3); glFormat = GL_RGB; glType = GL_UNSIGNED_BYTE; break; // 24 bpp
case UNCOMPRESSED_R5G5B5A1: pixels = (unsigned short *)malloc(size); glFormat = GL_RGBA; glType = GL_UNSIGNED_SHORT_5_5_5_1; break; // 16 bpp (1 bit alpha)
case UNCOMPRESSED_R4G4B4A4: pixels = (unsigned short *)malloc(size); glFormat = GL_RGBA; glType = GL_UNSIGNED_SHORT_4_4_4_4; break; // 16 bpp (4 bit alpha)
case UNCOMPRESSED_R8G8B8A8: pixels = (unsigned char *)malloc(size*4); glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; break; // 32 bpp
default: TraceLog(LOG_WARNING, "Texture data retrieval, format not suported"); break;
}
// NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding. // NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding.
// Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting. // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting.
// GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.) // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.)
// GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.) // GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels); int glInternalFormat, glFormat, glType;
GetGlFormats(texture.format, &glInternalFormat, &glFormat, &glType);
unsigned int size = GetPixelDataSize(texture.width, texture.height, texture.format);
if ((glInternalFormat != -1) && (texture.format < COMPRESSED_DXT1_RGB))
{
pixels = (unsigned char *)malloc(size);
glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels);
}
else TraceLog(LOG_WARNING, "Texture data retrieval not suported for pixel format");
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
#endif #endif
#if defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_ES2)
RenderTexture2D fbo = rlLoadRenderTexture(texture.width, texture.height); RenderTexture2D fbo = rlLoadRenderTexture(texture.width, texture.height);
// NOTE: Two possible Options: // NOTE: Two possible Options:
@ -2358,46 +2324,57 @@ char *LoadText(const char *fileName)
// Load shader from files and bind default locations // Load shader from files and bind default locations
// NOTE: If shader string is NULL, using default vertex/fragment shaders // NOTE: If shader string is NULL, using default vertex/fragment shaders
Shader LoadShader(char *vsFileName, char *fsFileName) Shader LoadShader(const char *vsFileName, const char *fsFileName)
{ {
Shader shader = { 0 }; Shader shader = { 0 };
char *vShaderStr = NULL;
char *fShaderStr = NULL;
if (vsFileName != NULL) vShaderStr = LoadText(vsFileName);
if (fsFileName != NULL) fShaderStr = LoadText(fsFileName);
shader = LoadShaderCode(vShaderStr, fShaderStr);
if (vShaderStr != NULL) free(vShaderStr);
if (fShaderStr != NULL) free(fShaderStr);
return shader;
}
// Load shader from code strings
// NOTE: If shader string is NULL, using default vertex/fragment shaders
Shader LoadShaderCode(char *vsCode, char *fsCode)
{
Shader shader = { 0 };
// NOTE: All locations must be reseted to -1 (no location) // NOTE: All locations must be reseted to -1 (no location)
for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
unsigned int vertexShaderId, fragmentShaderId;
if (vsFileName == NULL) vertexShaderId = defaultVShaderId;
else
{
char *vShaderStr = LoadText(vsFileName);
vertexShaderId = CompileShader(vShaderStr, GL_VERTEX_SHADER);
free(vShaderStr);
}
if (fsFileName == NULL) fragmentShaderId = defaultVShaderId;
else
{
char* fShaderStr = LoadText(fsFileName);
fragmentShaderId = CompileShader(fShaderStr, GL_FRAGMENT_SHADER);
free(fShaderStr);
}
shader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId);
if (vertexShaderId != defaultVShaderId) glDeleteShader(vertexShaderId);
if (fragmentShaderId != defaultFShaderId) glDeleteShader(fragmentShaderId);
if (shader.id == 0)
{
TraceLog(LOG_WARNING, "Custom shader could not be loaded");
shader = defaultShader;
}
// After shader loading, we TRY to set default location names #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if (shader.id > 0) SetShaderDefaultLocations(&shader); unsigned int vertexShaderId = defaultVShaderId;
unsigned int fragmentShaderId = defaultFShaderId;
if (vsCode != NULL) vertexShaderId = CompileShader(vsCode, GL_VERTEX_SHADER);
if (fsCode != NULL) fragmentShaderId = CompileShader(fsCode, GL_FRAGMENT_SHADER);
if ((vertexShaderId == defaultVShaderId) && (fragmentShaderId == defaultFShaderId)) shader = defaultShader;
else
{
shader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId);
if (vertexShaderId != defaultVShaderId) glDeleteShader(vertexShaderId);
if (fragmentShaderId != defaultFShaderId) glDeleteShader(fragmentShaderId);
if (shader.id == 0)
{
TraceLog(LOG_WARNING, "Custom shader could not be loaded");
shader = defaultShader;
}
// After shader loading, we TRY to set default location names
if (shader.id > 0) SetShaderDefaultLocations(&shader);
}
// Get available shader uniforms // Get available shader uniforms
// NOTE: This information is useful for debug... // NOTE: This information is useful for debug...
@ -2423,7 +2400,7 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
TraceLog(LOG_DEBUG, "[SHDR ID %i] Active uniform [%s] set at location: %i", shader.id, name, location); TraceLog(LOG_DEBUG, "[SHDR ID %i] Active uniform [%s] set at location: %i", shader.id, name, location);
} }
#endif #endif
return shader; return shader;
} }
@ -2530,6 +2507,19 @@ void SetMatrixModelview(Matrix view)
#endif #endif
} }
// Return internal modelview matrix
Matrix GetMatrixModelview()
{
Matrix matrix = MatrixIdentity();
#if defined(GRAPHICS_API_OPENGL_11)
float mat[16];
glGetFloatv(GL_MODELVIEW_MATRIX, mat);
#else
matrix = modelview;
#endif
return matrix;
}
// Generate cubemap texture from HDR texture // Generate cubemap texture from HDR texture
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 // TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size) Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
@ -2975,9 +2965,11 @@ bool IsVrSimulatorReady(void)
// TODO: Review VR system to be more flexible, move distortion shader to user side // TODO: Review VR system to be more flexible, move distortion shader to user side
void SetVrDistortionShader(Shader shader) void SetVrDistortionShader(Shader shader)
{ {
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
vrConfig.distortionShader = shader; vrConfig.distortionShader = shader;
//SetStereoConfig(info); // TODO: Must be reviewed to set new distortion shader uniform values... //SetStereoConfig(info); // TODO: Must be reviewed to set new distortion shader uniform values...
#endif
} }
// Enable/Disable VR experience (device or simulator) // Enable/Disable VR experience (device or simulator)
@ -3108,42 +3100,6 @@ void EndVrDrawing(void)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Convert image data to OpenGL texture (returns OpenGL valid Id)
// NOTE: Expected compressed image data and POT image
static void LoadTextureCompressed(unsigned char *data, int width, int height, int compressedFormat, int mipmapCount)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
int blockSize = 0; // Bytes every block
int offset = 0;
if ((compressedFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) ||
(compressedFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ||
#if defined(GRAPHICS_API_OPENGL_ES2)
(compressedFormat == GL_ETC1_RGB8_OES) ||
#endif
(compressedFormat == GL_COMPRESSED_RGB8_ETC2)) blockSize = 8;
else blockSize = 16;
// Load the mipmap levels
for (int level = 0; level < mipmapCount && (width || height); level++)
{
unsigned int size = 0;
size = ((width + 3)/4)*((height + 3)/4)*blockSize;
glCompressedTexImage2D(GL_TEXTURE_2D, level, compressedFormat, width, height, 0, size, data + offset);
offset += size;
width /= 2;
height /= 2;
// Security check for NPOT textures
if (width < 1) width = 1;
if (height < 1) height = 1;
}
}
// Compile custom shader and return shader id // Compile custom shader and return shader id
static unsigned int CompileShader(const char *shaderStr, int type) static unsigned int CompileShader(const char *shaderStr, int type)
{ {
@ -3161,7 +3117,7 @@ static unsigned int CompileShader(const char *shaderStr, int type)
int length; int length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
#ifdef _MSC_VER #if defined(_MSC_VER)
char *log = malloc(maxLength); char *log = malloc(maxLength);
#else #else
char log[maxLength]; char log[maxLength];
@ -3170,7 +3126,7 @@ static unsigned int CompileShader(const char *shaderStr, int type)
TraceLog(LOG_INFO, "%s", log); TraceLog(LOG_INFO, "%s", log);
#ifdef _MSC_VER #if defined(_MSC_VER)
free(log); free(log);
#endif #endif
} }
@ -3377,6 +3333,7 @@ static void UnloadShaderDefault(void)
glDetachShader(defaultShader.id, defaultFShaderId); glDetachShader(defaultShader.id, defaultFShaderId);
glDeleteShader(defaultVShaderId); glDeleteShader(defaultVShaderId);
glDeleteShader(defaultFShaderId); glDeleteShader(defaultFShaderId);
glDeleteProgram(defaultShader.id); glDeleteProgram(defaultShader.id);
} }
@ -3958,6 +3915,58 @@ static void GenDrawCube(void)
glDeleteVertexArrays(1, &cubeVAO); glDeleteVertexArrays(1, &cubeVAO);
} }
// Get OpenGL internal formats and data type from raylib PixelFormat
static void GetGlFormats(int format, int *glInternalFormat, int *glFormat, int *glType)
{
*glInternalFormat = -1;
*glFormat = -1;
*glType = -1;
switch (format)
{
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break;
case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break;
case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break;
case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break;
#if !defined(GRAPHICS_API_OPENGL_11)
case UNCOMPRESSED_R32: if (texFloatSupported) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
case UNCOMPRESSED_R32G32B32: if (texFloatSupported) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
#endif
#elif defined(GRAPHICS_API_OPENGL_33)
case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break;
case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break;
case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break;
case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_R32: if (texFloatSupported) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break;
case UNCOMPRESSED_R32G32B32: if (texFloatSupported) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break;
case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break;
#endif
#if !defined(GRAPHICS_API_OPENGL_11)
case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
case COMPRESSED_ETC1_RGB: if (texCompETC1Supported) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB: if (texCompETC2Supported) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA: if (texCompETC2Supported) *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_PVRT_RGB: if (texCompPVRTSupported) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU
case COMPRESSED_PVRT_RGBA: if (texCompPVRTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU
case COMPRESSED_ASTC_4x4_RGBA: if (texCompASTCSupported) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
case COMPRESSED_ASTC_8x8_RGBA: if (texCompASTCSupported) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
#endif
default: TraceLog(LOG_WARNING, "Texture format not supported"); break;
}
}
#if defined(SUPPORT_VR_SIMULATOR) #if defined(SUPPORT_VR_SIMULATOR)
// Configure stereo rendering (including distortion shader) with HMD device parameters // Configure stereo rendering (including distortion shader) with HMD device parameters
// NOTE: It modifies the global variable: VrStereoConfig vrConfig // NOTE: It modifies the global variable: VrStereoConfig vrConfig

View file

@ -169,7 +169,7 @@ typedef unsigned char byte;
int width; // Texture base width int width; // Texture base width
int height; // Texture base height int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (TextureFormat) int format; // Data format (PixelFormat)
} Texture2D; } Texture2D;
// RenderTexture2D type, for texture rendering // RenderTexture2D type, for texture rendering
@ -259,7 +259,9 @@ typedef unsigned char byte;
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp UNCOMPRESSED_R8G8B8A8, // 32 bpp
UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR UNCOMPRESSED_R32, // 32 bpp (1 channel - float)
UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float)
UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float)
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp COMPRESSED_DXT3_RGBA, // 8 bpp
@ -271,7 +273,7 @@ typedef unsigned char byte;
COMPRESSED_PVRT_RGBA, // 4 bpp COMPRESSED_PVRT_RGBA, // 4 bpp
COMPRESSED_ASTC_4x4_RGBA, // 8 bpp COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
COMPRESSED_ASTC_8x8_RGBA // 2 bpp COMPRESSED_ASTC_8x8_RGBA // 2 bpp
} TextureFormat; } PixelFormat;
// Texture parameters: filter mode // Texture parameters: filter mode
// NOTE 1: Filtering considers mipmaps if available in the texture // NOTE 1: Filtering considers mipmaps if available in the texture
@ -422,6 +424,7 @@ void rlglClose(void); // De-inititialize rlgl (buffers
void rlglDraw(void); // Update and Draw default buffers (lines, triangles, quads) void rlglDraw(void); // Update and Draw default buffers (lines, triangles, quads)
int rlGetVersion(void); // Returns current OpenGL version int rlGetVersion(void); // Returns current OpenGL version
void rlSetDebugMarker(const char *text); // Set debug marker for analysis
void rlLoadExtensions(void *loader); // Load OpenGL extensions void rlLoadExtensions(void *loader); // Load OpenGL extensions
Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
@ -456,11 +459,13 @@ Texture2D GetTextureDefault(void); // Get default texture
// Shader configuration functions // Shader configuration functions
int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size); // Set shader uniform value (float)
void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); // Set shader uniform value (int)
void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
Matrix GetMatrixModelview(); // Get internal modelview matrix
// Texture maps generation (PBR) // Texture maps generation (PBR)
// NOTE: Required shaders should be provided // NOTE: Required shaders should be provided

View file

@ -40,6 +40,20 @@ func LoadShader(vsFileName string, fsFileName string) Shader {
return v return v
} }
// LoadShaderCode - Load shader from code strings and bind default locations
func LoadShaderCode(vsCode string, fsCode string) Shader {
cvsCode := C.CString(vsCode)
defer C.free(unsafe.Pointer(cvsCode))
cfsCode := C.CString(fsCode)
defer C.free(unsafe.Pointer(cfsCode))
ret := C.LoadShaderCode(cvsCode, cfsCode)
v := newShaderFromPointer(unsafe.Pointer(&ret))
return v
}
// UnloadShader - Unload a custom shader from memory // UnloadShader - Unload a custom shader from memory
func UnloadShader(shader Shader) { func UnloadShader(shader Shader) {
cshader := shader.cptr() cshader := shader.cptr()

View file

@ -1,5 +1,3 @@
// +build !js
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.shapes - Basic functions to draw 2d Shapes and check collisions * raylib.shapes - Basic functions to draw 2d Shapes and check collisions
@ -12,10 +10,14 @@
* #define SUPPORT_TRIANGLES_ONLY * #define SUPPORT_TRIANGLES_ONLY
* Draw shapes using only TRIANGLES, vertex are accumulated in TRIANGLES arrays * Draw shapes using only TRIANGLES, vertex are accumulated in TRIANGLES arrays
* *
* #define USE_DEFAULT_FONT_TEXTURE
* Draw rectangle shapes using font texture white character instead of default white texture
* Allows drawing rectangles and text with a single draw call, very useful for GUI systems!
*
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -34,6 +36,8 @@
* *
**********************************************************************************************/ **********************************************************************************************/
#define USE_DEFAULT_FONT_TEXTURE
#include "raylib.h" #include "raylib.h"
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
@ -247,6 +251,78 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color)
DrawRectangleV(position, size, color); DrawRectangleV(position, size, color);
} }
// Draw a color-filled rectangle (Vector version)
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{
if (rlGetVersion() == 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);
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_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
#if defined(USE_DEFAULT_FONT_TEXTURE)
// Draw rectangle using font texture white character
rlEnableTexture(GetDefaultFont().texture.id);
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 0.0f, 1.0f);
// NOTE: Default raylib font character 95 is a white square
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(position.x, position.y);
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(position.x, position.y + size.y);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(position.x + size.x, position.y + size.y);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(position.x + size.x, position.y);
rlEnd();
rlDisableTexture();
#else
rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 0.0f, 1.0f);
rlTexCoord2f(0.0f, 0.0f);
rlVertex2f(position.x, position.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, 0.0f);
rlVertex2f(position.x + size.x, position.y);
rlEnd();
rlDisableTexture();
#endif
}
}
// Draw a color-filled rectangle // Draw a color-filled rectangle
void DrawRectangleRec(Rectangle rec, Color color) void DrawRectangleRec(Rectangle rec, Color color)
{ {
@ -294,6 +370,37 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color col
// NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise // NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise
void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4) void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)
{ {
#if defined(USE_DEFAULT_FONT_TEXTURE)
// Draw rectangle using font texture white character
rlEnableTexture(GetDefaultFont().texture.id);
rlBegin(RL_QUADS);
rlNormal3f(0.0f, 0.0f, 1.0f);
// NOTE: Default raylib font character 95 is a white square
rlColor4ub(col1.r, col1.g, col1.b, col1.a);
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(rec.x, rec.y);
rlColor4ub(col2.r, col2.g, col2.b, col2.a);
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(rec.x, rec.y + rec.height);
rlColor4ub(col3.r, col3.g, col3.b, col3.a);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
rlColor4ub(col4.r, col4.g, col4.b, col4.a);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(rec.x + rec.width, rec.y);
rlEnd();
rlDisableTexture();
#else
rlEnableTexture(GetTextureDefault().id); // Default white texture rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
@ -315,70 +422,9 @@ void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3,
rlTexCoord2f(1.0f, 0.0f); rlTexCoord2f(1.0f, 0.0f);
rlVertex2f(rec.x + rec.width, rec.y); rlVertex2f(rec.x + rec.width, rec.y);
rlEnd(); rlEnd();
// Draw rectangle using font texture white character
/*
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(rec.x, rec.y);
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(rec.x, rec.y + rec.height);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(rec.x + rec.width, rec.y);
*/
rlDisableTexture(); rlDisableTexture();
} #endif
// Draw a color-filled rectangle (Vector version)
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{
if (rlGetVersion() == 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);
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_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 0.0f, 1.0f);
rlTexCoord2f(0.0f, 0.0f);
rlVertex2f(position.x, position.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, 0.0f);
rlVertex2f(position.x + size.x, position.y);
rlEnd();
rlDisableTexture();
}
} }
// Draw rectangle outline // Draw rectangle outline
@ -411,12 +457,19 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
} }
} }
// Draw rectangle using text character (char: 127) // Draw rectangle outline with extended parameters
// NOTE: Useful to avoid changing to default white texture void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color)
void DrawRectangleT(int posX, int posY, int width, int height, Color color) {
{ if (lineThick > rec.width || lineThick > rec.height)
DrawTexturePro(GetDefaultFont().texture, GetDefaultFont().chars[95].rec, {
(Rectangle){ posX, posY, width, height }, (Vector2){ 0, 0 }, 0.0f, color); if(rec.width > rec.height) lineThick = rec.height/2;
else if (rec.width < rec.height) lineThick = rec.width/2;
}
DrawRectangle(rec.x, rec.y, rec.width, lineThick, color);
DrawRectangle(rec.x - lineThick + rec.width, rec.y + lineThick, lineThick, rec.height - lineThick*2, color);
DrawRectangle(rec.x, rec.y + rec.height - lineThick, rec.width, lineThick, color);
DrawRectangle(rec.x, rec.y + lineThick, lineThick, rec.height - lineThick*2, color);
} }
// Draw a triangle // Draw a triangle

View file

@ -172,14 +172,12 @@ func DrawRectangleLines(posX, posY, width, height int32, color Color) {
C.DrawRectangleLines(cposX, cposY, cwidth, cheight, *ccolor) C.DrawRectangleLines(cposX, cposY, cwidth, cheight, *ccolor)
} }
// DrawRectangleT - Draw rectangle using text character // DrawRectangleLinesEx - Draw rectangle outline with extended parameters
func DrawRectangleT(posX, posY, width, height int32, color Color) { func DrawRectangleLinesEx(rec Rectangle, lineThick int32, color Color) {
cposX := (C.int)(posX) crec := rec.cptr()
cposY := (C.int)(posY) clineThick := (C.int)(lineThick)
cwidth := (C.int)(width)
cheight := (C.int)(height)
ccolor := color.cptr() ccolor := color.cptr()
C.DrawRectangleT(cposX, cposY, cwidth, cheight, *ccolor) C.DrawRectangleLinesEx(*crec, clineThick, *ccolor)
} }
// DrawTriangle - Draw a color-filled triangle // DrawTriangle - Draw a color-filled triangle

View file

@ -1,5 +1,3 @@
// +build !js
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.text - Basic functions to load SpriteFonts and draw Text * raylib.text - Basic functions to load SpriteFonts and draw Text
@ -19,7 +17,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -68,8 +66,8 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define MAX_FORMATTEXT_LENGTH 64 #define MAX_FORMATTEXT_LENGTH 256
#define MAX_SUBTEXT_LENGTH 64 #define MAX_SUBTEXT_LENGTH 256
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
@ -92,11 +90,9 @@ static SpriteFont defaultFont; // Default font provided by raylib
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static int GetCharIndex(SpriteFont font, int letter);
static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style)
#if defined(SUPPORT_FILEFORMAT_FNT) #if defined(SUPPORT_FILEFORMAT_FNT)
static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
#endif #endif
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data
@ -290,40 +286,14 @@ SpriteFont LoadSpriteFont(const char *fileName)
SpriteFont spriteFont = { 0 }; SpriteFont spriteFont = { 0 };
// Check file extension
if (IsFileExtension(fileName, ".rres"))
{
// TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA)
RRES rres = LoadResource(fileName, 0);
// Load sprite font texture
if (rres[0].type == RRES_TYPE_FONT_IMAGE)
{
// NOTE: Parameters for RRES_FONT_IMAGE type are: width, height, format, mipmaps
Image image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3);
spriteFont.texture = LoadTextureFromImage(image);
UnloadImage(image);
}
// Load sprite characters data
if (rres[1].type == RRES_TYPE_FONT_CHARDATA)
{
// NOTE: Parameters for RRES_FONT_CHARDATA type are: fontSize, charsCount
spriteFont.baseSize = rres[1].param1;
spriteFont.charsCount = rres[1].param2;
spriteFont.chars = rres[1].data;
}
// TODO: Do not free rres.data memory (chars info data!)
//UnloadResource(rres[0]);
}
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
else if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL);
else
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FNT) #if defined(SUPPORT_FILEFORMAT_FNT)
else if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName);
#endif
else else
#endif
{ {
Image image = LoadImage(fileName); Image image = LoadImage(fileName);
if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR);
@ -346,21 +316,20 @@ SpriteFont LoadSpriteFont(const char *fileName)
SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars) SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars)
{ {
SpriteFont spriteFont = { 0 }; SpriteFont spriteFont = { 0 };
int totalChars = 95; // Default charset [32..126]
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
if (IsFileExtension(fileName, ".ttf")) if (IsFileExtension(fileName, ".ttf"))
{ {
if ((fontChars == NULL) || (charsCount == 0)) if (charsCount != 0) totalChars = charsCount;
if (fontChars == NULL)
{ {
int totalChars = 95; // Default charset [32..126] fontChars = (int *)malloc(totalChars*sizeof(int));
for (int i = 0; i < totalChars; i++) fontChars[i] = i + 32; // Default first character: SPACE[32]
int *defaultFontChars = (int *)malloc(totalChars*sizeof(int));
for (int i = 0; i < totalChars; i++) defaultFontChars[i] = i + 32; // Default first character: SPACE[32]
spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars);
} }
else spriteFont = LoadTTF(fileName, fontSize, charsCount, fontChars);
spriteFont = LoadTTF(fileName, fontSize, totalChars, fontChars);
} }
#endif #endif
@ -374,13 +343,13 @@ SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount,
} }
// Unload SpriteFont from GPU memory (VRAM) // Unload SpriteFont from GPU memory (VRAM)
void UnloadSpriteFont(SpriteFont spriteFont) void UnloadSpriteFont(SpriteFont font)
{ {
// NOTE: Make sure spriteFont is not default font (fallback) // NOTE: Make sure spriteFont is not default font (fallback)
if (spriteFont.texture.id != GetDefaultFont().texture.id) if (font.texture.id != GetDefaultFont().texture.id)
{ {
UnloadTexture(spriteFont.texture); UnloadTexture(font.texture);
free(spriteFont.chars); free(font.chars);
TraceLog(LOG_DEBUG, "Unloaded sprite font data"); TraceLog(LOG_DEBUG, "Unloaded sprite font data");
} }
@ -406,7 +375,7 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
// Draw text using SpriteFont // Draw text using SpriteFont
// NOTE: chars spacing is NOT proportional to fontSize // NOTE: chars spacing is NOT proportional to fontSize
void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float fontSize, int spacing, Color tint) void DrawTextEx(SpriteFont font, const char *text, Vector2 position, float fontSize, int spacing, Color tint)
{ {
int length = strlen(text); int length = strlen(text);
int textOffsetX = 0; // Offset between characters int textOffsetX = 0; // Offset between characters
@ -416,7 +385,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
unsigned char letter; // Current character unsigned char letter; // Current character
int index; // Index position in sprite font int index; // Index position in sprite font
scaleFactor = fontSize/spriteFont.baseSize; scaleFactor = fontSize/font.baseSize;
// NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly
// written in C code files (codified by default as UTF-8) // written in C code files (codified by default as UTF-8)
@ -426,7 +395,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
if ((unsigned char)text[i] == '\n') if ((unsigned char)text[i] == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 lines // NOTE: Fixed line spacing of 1.5 lines
textOffsetY += (int)((spriteFont.baseSize + spriteFont.baseSize/2)*scaleFactor); textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
textOffsetX = 0; textOffsetX = 0;
} }
else else
@ -435,26 +404,29 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
{ {
// Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿)
letter = (unsigned char)text[i + 1]; letter = (unsigned char)text[i + 1];
index = GetCharIndex(spriteFont, (int)letter); index = GetGlyphIndex(font, (int)letter);
i++; i++;
} }
else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK!
{ {
// Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ)
letter = (unsigned char)text[i + 1]; letter = (unsigned char)text[i + 1];
index = GetCharIndex(spriteFont, (int)letter + 64); index = GetGlyphIndex(font, (int)letter + 64);
i++; i++;
} }
else index = GetCharIndex(spriteFont, (unsigned char)text[i]); else index = GetGlyphIndex(font, (unsigned char)text[i]);
if ((unsigned char)text[i] != ' ')
{
DrawTexturePro(font.texture, font.chars[index].rec,
(Rectangle){ position.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
position.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.chars[index].rec.width*scaleFactor,
font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
}
DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec, if (font.chars[index].advanceX == 0) textOffsetX += (int)(font.chars[index].rec.width*scaleFactor + spacing);
(Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor, else textOffsetX += (int)(font.chars[index].advanceX*scaleFactor + spacing);
position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor,
spriteFont.chars[index].rec.width*scaleFactor,
spriteFont.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing);
else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing);
} }
} }
} }
@ -516,7 +488,7 @@ int MeasureText(const char *text, int fontSize)
} }
// Measure string size for SpriteFont // Measure string size for SpriteFont
Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing) Vector2 MeasureTextEx(SpriteFont font, const char *text, float fontSize, int spacing)
{ {
int len = strlen(text); int len = strlen(text);
int tempLen = 0; // Used to count longer text line num chars int tempLen = 0; // Used to count longer text line num chars
@ -525,8 +497,8 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
float textWidth = 0; float textWidth = 0;
float tempTextWidth = 0; // Used to count longer text line width float tempTextWidth = 0; // Used to count longer text line width
float textHeight = (float)spriteFont.baseSize; float textHeight = (float)font.baseSize;
float scaleFactor = fontSize/(float)spriteFont.baseSize; float scaleFactor = fontSize/(float)font.baseSize;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
@ -534,17 +506,17 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
if (text[i] != '\n') if (text[i] != '\n')
{ {
int index = GetCharIndex(spriteFont, (int)text[i]); int index = GetGlyphIndex(font, (int)text[i]);
if (spriteFont.chars[index].advanceX != 0) textWidth += spriteFont.chars[index].advanceX; if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX;
else textWidth += (spriteFont.chars[index].rec.width + spriteFont.chars[index].offsetX); else textWidth += (font.chars[index].rec.width + font.chars[index].offsetX);
} }
else else
{ {
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
lenCounter = 0; lenCounter = 0;
textWidth = 0; textWidth = 0;
textHeight += ((float)spriteFont.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
} }
if (tempLen < lenCounter) tempLen = lenCounter; if (tempLen < lenCounter) tempLen = lenCounter;
@ -559,6 +531,28 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
return vec; return vec;
} }
// Returns index position for a unicode character on spritefont
int GetGlyphIndex(SpriteFont font, int character)
{
#define UNORDERED_CHARSET
#if defined(UNORDERED_CHARSET)
int index = 0;
for (int i = 0; i < font.charsCount; i++)
{
if (font.chars[i].value == character)
{
index = i;
break;
}
}
return index;
#else
return (character - 32);
#endif
}
// Shows current FPS on top-left corner // Shows current FPS on top-left corner
// NOTE: Uses default font // NOTE: Uses default font
void DrawFPS(int posX, int posY) void DrawFPS(int posX, int posY)
@ -585,27 +579,6 @@ void DrawFPS(int posX, int posY)
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static int GetCharIndex(SpriteFont font, int letter)
{
#define UNORDERED_CHARSET
#if defined(UNORDERED_CHARSET)
int index = 0;
for (int i = 0; i < font.charsCount; i++)
{
if (font.chars[i].value == letter)
{
index = i;
break;
}
}
return index;
#else
return (letter - 32);
#endif
}
// Load an Image font file (XNA style) // Load an Image font file (XNA style)
static SpriteFont LoadImageFont(Image image, Color key, int firstChar) static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
{ {

View file

@ -1,5 +1,3 @@
// +build !js
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.textures - Basic functions to load and draw Textures (2d) * raylib.textures - Basic functions to load and draw Textures (2d)
@ -36,7 +34,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -169,18 +167,7 @@ Image LoadImage(const char *fileName)
{ {
Image image = { 0 }; Image image = { 0 };
if (IsFileExtension(fileName, ".rres")) if ((IsFileExtension(fileName, ".png"))
{
RRES rres = LoadResource(fileName, 0);
// NOTE: Parameters for RRES_TYPE_IMAGE are: width, height, format, mipmaps
if (rres[0].type == RRES_TYPE_IMAGE) image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3);
else TraceLog(LOG_WARNING, "[%s] Resource file does not contain image data", fileName);
UnloadResource(rres);
}
else if ((IsFileExtension(fileName, ".png"))
#if defined(SUPPORT_FILEFORMAT_BMP) #if defined(SUPPORT_FILEFORMAT_BMP)
|| (IsFileExtension(fileName, ".bmp")) || (IsFileExtension(fileName, ".bmp"))
#endif #endif
@ -239,11 +226,12 @@ Image LoadImage(const char *fileName)
image.mipmaps = 1; image.mipmaps = 1;
if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32; if (imgBpp == 1) image.format = UNCOMPRESSED_R32;
else if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32;
else if (imgBpp == 4) image.format = UNCOMPRESSED_R32G32B32A32;
else else
{ {
// TODO: Support different number of channels at 32 bit float TraceLog(LOG_WARNING, "[%s] Image fileformat not supported", fileName);
TraceLog(LOG_WARNING, "[%s] Image fileformat not supported (only 3 channel 32 bit floats)", fileName);
UnloadImage(image); UnloadImage(image);
} }
} }
@ -330,20 +318,9 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
{ {
if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET); if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET);
unsigned int size = width*height; unsigned int size = GetPixelDataSize(width, height, format);
switch (format) image.data = malloc(size); // Allocate required memory in bytes
{
case UNCOMPRESSED_GRAYSCALE: image.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha)
case UNCOMPRESSED_GRAY_ALPHA: image.data = (unsigned char *)malloc(size*2); size *= 2; break; // 16 bpp (2 channels)
case UNCOMPRESSED_R5G6B5: image.data = (unsigned short *)malloc(size); break; // 16 bpp
case UNCOMPRESSED_R8G8B8: image.data = (unsigned char *)malloc(size*3); size *= 3; break; // 24 bpp
case UNCOMPRESSED_R5G5B5A1: image.data = (unsigned short *)malloc(size); break; // 16 bpp (1 bit alpha)
case UNCOMPRESSED_R4G4B4A4: image.data = (unsigned short *)malloc(size); break; // 16 bpp (4 bit alpha)
case UNCOMPRESSED_R8G8B8A8: image.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp
case UNCOMPRESSED_R32G32B32: image.data = (float *)malloc(size*12); size *= 12; break; // 4 byte per channel (12 byte)
default: TraceLog(LOG_WARNING, "Image format not suported"); break;
}
// NOTE: fread() returns num read elements instead of bytes, // NOTE: fread() returns num read elements instead of bytes,
// to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element) // to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element)
@ -399,8 +376,6 @@ Texture2D LoadTextureFromImage(Image image)
texture.height = image.height; texture.height = image.height;
texture.mipmaps = image.mipmaps; texture.mipmaps = image.mipmaps;
texture.format = image.format; texture.format = image.format;
TraceLog(LOG_DEBUG, "[TEX ID %i] Parameters: %ix%i, %i mips, format %i", texture.id, texture.width, texture.height, texture.mipmaps, texture.format);
return texture; return texture;
} }
@ -440,24 +415,22 @@ void UnloadRenderTexture(RenderTexture2D target)
} }
// Get pixel data from image in the form of Color struct array // Get pixel data from image in the form of Color struct array
// TODO: Support float pixel data retrieval
Color *GetImageData(Image image) Color *GetImageData(Image image)
{ {
Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color)); Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color));
int k = 0; for (int i = 0, k = 0; i < image.width*image.height; i++)
for (int i = 0; i < image.width*image.height; i++)
{ {
switch (image.format) switch (image.format)
{ {
case UNCOMPRESSED_GRAYSCALE: case UNCOMPRESSED_GRAYSCALE:
{ {
pixels[i].r = ((unsigned char *)image.data)[k]; pixels[i].r = ((unsigned char *)image.data)[i];
pixels[i].g = ((unsigned char *)image.data)[k]; pixels[i].g = ((unsigned char *)image.data)[i];
pixels[i].b = ((unsigned char *)image.data)[k]; pixels[i].b = ((unsigned char *)image.data)[i];
pixels[i].a = 255; pixels[i].a = 255;
k++;
} break; } break;
case UNCOMPRESSED_GRAY_ALPHA: case UNCOMPRESSED_GRAY_ALPHA:
{ {
@ -470,36 +443,33 @@ Color *GetImageData(Image image)
} break; } break;
case UNCOMPRESSED_R5G5B5A1: case UNCOMPRESSED_R5G5B5A1:
{ {
unsigned short pixel = ((unsigned short *)image.data)[k]; unsigned short pixel = ((unsigned short *)image.data)[i];
pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31));
pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31));
pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255); pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255);
k++;
} break; } break;
case UNCOMPRESSED_R5G6B5: case UNCOMPRESSED_R5G6B5:
{ {
unsigned short pixel = ((unsigned short *)image.data)[k]; unsigned short pixel = ((unsigned short *)image.data)[i];
pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63));
pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31));
pixels[i].a = 255; pixels[i].a = 255;
k++;
} break; } break;
case UNCOMPRESSED_R4G4B4A4: case UNCOMPRESSED_R4G4B4A4:
{ {
unsigned short pixel = ((unsigned short *)image.data)[k]; unsigned short pixel = ((unsigned short *)image.data)[i];
pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15)); pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15));
pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15)); pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15));
pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15)); pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15));
pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15)); pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15));
k++;
} break; } break;
case UNCOMPRESSED_R8G8B8A8: case UNCOMPRESSED_R8G8B8A8:
{ {
@ -526,6 +496,44 @@ Color *GetImageData(Image image)
return pixels; return pixels;
} }
// Get pixel data size in bytes (image or texture)
// NOTE: Size depends on pixel format
int GetPixelDataSize(int width, int height, int format)
{
int dataSize = 0; // Size in bytes
int bpp = 0; // Bits per pixel
switch (format)
{
case UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
case UNCOMPRESSED_GRAY_ALPHA:
case UNCOMPRESSED_R5G6B5:
case UNCOMPRESSED_R5G5B5A1:
case UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
case UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
case UNCOMPRESSED_R8G8B8: bpp = 24; break;
case UNCOMPRESSED_R32: bpp = 32; break;
case UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
case UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
case COMPRESSED_DXT1_RGB:
case COMPRESSED_DXT1_RGBA:
case COMPRESSED_ETC1_RGB:
case COMPRESSED_ETC2_RGB:
case COMPRESSED_PVRT_RGB:
case COMPRESSED_PVRT_RGBA: bpp = 4; break;
case COMPRESSED_DXT3_RGBA:
case COMPRESSED_DXT5_RGBA:
case COMPRESSED_ETC2_EAC_RGBA:
case COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
case COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
default: break;
}
dataSize = width*height*bpp/8; // Total data size in bytes
return dataSize;
}
// Get pixel data from GPU texture and return an Image // Get pixel data from GPU texture and return an Image
// NOTE: Compressed texture formats not supported // NOTE: Compressed texture formats not supported
Image GetTextureData(Texture2D texture) Image GetTextureData(Texture2D texture)
@ -565,10 +573,11 @@ void UpdateTexture(Texture2D texture, const void *pixels)
} }
// Save image to a PNG file // Save image to a PNG file
void SaveImageAs(const char* fileName, Image image) void SaveImageAs(const char *fileName, Image image)
{ {
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
unsigned char* imgData = (unsigned char*)GetImageData(image); // this works since Color is just a container for the RGBA values // NOTE: Getting Color array as RGBA unsigned char values
unsigned char *imgData = (unsigned char *)GetImageData(image);
SavePNG(fileName, imgData, image.width, image.height, 4); SavePNG(fileName, imgData, image.width, image.height, 4);
free(imgData); free(imgData);
@ -576,6 +585,88 @@ void SaveImageAs(const char* fileName, Image image)
#endif #endif
} }
// Copy an image to a new image
Image ImageCopy(Image image)
{
Image newImage = { 0 };
int width = image.width;
int height = image.height;
int size = 0;
for (int i = 0; i < image.mipmaps; i++)
{
size += GetPixelDataSize(width, height, image.format);
width /= 2;
height /= 2;
// Security check for NPOT textures
if (width < 1) width = 1;
if (height < 1) height = 1;
}
newImage.data = malloc(size);
if (newImage.data != NULL)
{
// NOTE: Size must be provided in bytes
memcpy(newImage.data, image.data, size);
newImage.width = image.width;
newImage.height = image.height;
newImage.mipmaps = image.mipmaps;
newImage.format = image.format;
}
return newImage;
}
// Convert image to POT (power-of-two)
// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
void ImageToPOT(Image *image, Color fillColor)
{
Color *pixels = GetImageData(*image); // Get pixels data
// Calculate next power-of-two values
// NOTE: Just add the required amount of pixels at the right and bottom sides of image...
int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
// Check if POT texture generation is required (if texture is not already POT)
if ((potWidth != image->width) || (potHeight != image->height))
{
Color *pixelsPOT = NULL;
// Generate POT array from NPOT data
pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color));
for (int j = 0; j < potHeight; j++)
{
for (int i = 0; i < potWidth; i++)
{
if ((j < image->height) && (i < image->width)) pixelsPOT[j*potWidth + i] = pixels[j*image->width + i];
else pixelsPOT[j*potWidth + i] = fillColor;
}
}
TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight);
free(pixels); // Free pixels data
free(image->data); // Free old image data
int format = image->format; // Store image data format to reconvert later
// TODO: Image width and height changes... do we want to store new values or keep the old ones?
// NOTE: Issues when using image.width and image.height for sprite animations...
*image = LoadImageEx(pixelsPOT, potWidth, potHeight);
free(pixelsPOT); // Free POT pixels data
ImageFormat(image, format); // Reconvert image to previous format
}
}
// Convert image data to desired format // Convert image data to desired format
void ImageFormat(Image *image, int newFormat) void ImageFormat(Image *image, int newFormat)
{ {
@ -585,7 +676,7 @@ void ImageFormat(Image *image, int newFormat)
{ {
Color *pixels = GetImageData(*image); Color *pixels = GetImageData(*image);
free(image->data); free(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end...
image->format = newFormat; image->format = newFormat;
@ -607,11 +698,10 @@ void ImageFormat(Image *image, int newFormat)
{ {
image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char));
for (int i = 0; i < image->width*image->height*2; i += 2) for (int i = 0; i < image->width*image->height*2; i += 2, k++)
{ {
((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f); ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f);
((unsigned char *)image->data)[i + 1] = pixels[k].a; ((unsigned char *)image->data)[i + 1] = pixels[k].a;
k++;
} }
} break; } break;
@ -637,12 +727,11 @@ void ImageFormat(Image *image, int newFormat)
{ {
image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char)); image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char));
for (int i = 0; i < image->width*image->height*3; i += 3) for (int i = 0; i < image->width*image->height*3; i += 3, k++)
{ {
((unsigned char *)image->data)[i] = pixels[k].r; ((unsigned char *)image->data)[i] = pixels[k].r;
((unsigned char *)image->data)[i + 1] = pixels[k].g; ((unsigned char *)image->data)[i + 1] = pixels[k].g;
((unsigned char *)image->data)[i + 2] = pixels[k].b; ((unsigned char *)image->data)[i + 2] = pixels[k].b;
k++;
} }
} break; } break;
case UNCOMPRESSED_R5G5B5A1: case UNCOMPRESSED_R5G5B5A1:
@ -691,19 +780,58 @@ void ImageFormat(Image *image, int newFormat)
{ {
image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char)); image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char));
for (int i = 0; i < image->width*image->height*4; i += 4) for (int i = 0; i < image->width*image->height*3; i += 3, k++)
{ {
((unsigned char *)image->data)[i] = pixels[k].r; ((unsigned char *)image->data)[i] = pixels[k].r;
((unsigned char *)image->data)[i + 1] = pixels[k].g; ((unsigned char *)image->data)[i + 1] = pixels[k].g;
((unsigned char *)image->data)[i + 2] = pixels[k].b; ((unsigned char *)image->data)[i + 2] = pixels[k].b;
((unsigned char *)image->data)[i + 3] = pixels[k].a; ((unsigned char *)image->data)[i + 3] = pixels[k].a;
k++; }
} break;
case UNCOMPRESSED_R32:
{
image->data = (float *)malloc(image->width*image->height*sizeof(float));
for (int i = 0; i < image->width*image->height; i++)
{
((float *)image->data)[i] = (float)((float)pixels[i].r*0.299f/255.0f + (float)pixels[i].g*0.587f/255.0f + (float)pixels[i].b*0.114f/255.0f);
}
} break;
case UNCOMPRESSED_R32G32B32:
{
image->data = (float *)malloc(image->width*image->height*3*sizeof(float));
for (int i = 0; i < image->width*image->height*3; i += 3, k++)
{
((float *)image->data)[i] = (float)pixels[k].r/255.0f;
((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f;
((float *)image->data)[i + 2] = (float)pixels[k].b/255.0f;
}
} break;
case UNCOMPRESSED_R32G32B32A32:
{
image->data = (float *)malloc(image->width*image->height*4*sizeof(float));
for (int i = 0; i < image->width*image->height*4; i += 4, k++)
{
((float *)image->data)[i] = (float)pixels[k].r/255.0f;
((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f;
((float *)image->data)[i + 2] = (float)pixels[k].b/255.0f;
((float *)image->data)[i + 3] = (float)pixels[k].a/255.0f;
} }
} break; } break;
default: break; default: break;
} }
free(pixels); free(pixels);
// In case original image had mipmaps, generate mipmaps for formated image
// NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost
if (image->mipmaps > 1)
{
image->mipmaps = 1;
ImageMipmaps(image);
}
} }
else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted"); else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted");
} }
@ -755,99 +883,92 @@ void ImageAlphaMask(Image *image, Image alphaMask)
} }
} }
// Convert image to POT (power-of-two) // Clear alpha channel to desired color
// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) // NOTE: Threshold defines the alpha limit, 0.0f to 1.0f
void ImageToPOT(Image *image, Color fillColor) void ImageAlphaClear(Image *image, Color color, float threshold)
{ {
Color *pixels = GetImageData(*image); // Get pixels data Color *pixels = GetImageData(*image);
for (int i = 0; i < image->width*image->height; i++) if (pixels[i].a <= (unsigned char)(threshold*255.0f)) pixels[i] = color;
// Calculate next power-of-two values UnloadImage(*image);
// NOTE: Just add the required amount of pixels at the right and bottom sides of image...
int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); int prevFormat = image->format;
int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); *image = LoadImageEx(pixels, image->width, image->height);
// Check if POT texture generation is required (if texture is not already POT) ImageFormat(image, prevFormat);
if ((potWidth != image->width) || (potHeight != image->height))
{
Color *pixelsPOT = NULL;
// Generate POT array from NPOT data
pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color));
for (int j = 0; j < potHeight; j++)
{
for (int i = 0; i < potWidth; i++)
{
if ((j < image->height) && (i < image->width)) pixelsPOT[j*potWidth + i] = pixels[j*image->width + i];
else pixelsPOT[j*potWidth + i] = fillColor;
}
}
TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight);
free(pixels); // Free pixels data
free(image->data); // Free old image data
int format = image->format; // Store image data format to reconvert later
// TODO: Image width and height changes... do we want to store new values or keep the old ones?
// NOTE: Issues when using image.width and image.height for sprite animations...
*image = LoadImageEx(pixelsPOT, potWidth, potHeight);
free(pixelsPOT); // Free POT pixels data
ImageFormat(image, format); // Reconvert image to previous format
}
} }
// Crop image depending on alpha value
void ImageAlphaCrop(Image *image, float threshold)
{
Rectangle crop = { 0 };
Color *pixels = GetImageData(*image);
int minx = 0;
int miny = 0;
for (int i = 0; i < image->width*image->height; i++)
{
if (pixels[i].a > (unsigned char)(threshold*255.0f))
{
minx = i%image->width;
miny = -(-((i/image->width) + 1) + 1);
if (crop.y == 0) crop.y = miny;
if (crop.x == 0) crop.x = minx;
else if (minx < crop.x) crop.x = minx;
if (crop.width == 0) crop.width = minx;
else if (crop.width < minx) crop.width = minx;
if (crop.height == 0) crop.height = miny;
else if (crop.height < miny) crop.height = miny;
}
}
crop.width -= (crop.x - 1);
crop.height -= (crop.y - 1);
TraceLog(LOG_INFO, "Crop rectangle: (%i, %i, %i, %i)", crop.x, crop.y, crop.width, crop.height);
free(pixels);
// NOTE: Added this weird check to avoid additional 1px crop to
// image data that has already been cropped...
if ((crop.x != 1) &&
(crop.y != 1) &&
(crop.width != image->width - 1) &&
(crop.height != image->height - 1)) ImageCrop(image, crop);
}
// Premultiply alpha channel
void ImageAlphaPremultiply(Image *image)
{
float alpha = 0.0f;
Color *pixels = GetImageData(*image);
for (int i = 0; i < image->width*image->height; i++)
{
alpha = (float)pixels[i].a/255.0f;
pixels[i].r = (unsigned char)((float)pixels[i].r*alpha);
pixels[i].g = (unsigned char)((float)pixels[i].g*alpha);
pixels[i].b = (unsigned char)((float)pixels[i].b*alpha);
}
UnloadImage(*image);
int prevFormat = image->format;
*image = LoadImageEx(pixels, image->width, image->height);
ImageFormat(image, prevFormat);
}
#if defined(SUPPORT_IMAGE_MANIPULATION) #if defined(SUPPORT_IMAGE_MANIPULATION)
// Copy an image to a new image
Image ImageCopy(Image image)
{
Image newImage = { 0 };
int byteSize = image.width*image.height;
switch (image.format)
{
case UNCOMPRESSED_GRAYSCALE: break; // 8 bpp (1 byte)
case UNCOMPRESSED_GRAY_ALPHA: // 16 bpp
case UNCOMPRESSED_R5G6B5: // 16 bpp
case UNCOMPRESSED_R5G5B5A1: // 16 bpp
case UNCOMPRESSED_R4G4B4A4: byteSize *= 2; break; // 16 bpp (2 bytes)
case UNCOMPRESSED_R8G8B8: byteSize *= 3; break; // 24 bpp (3 bytes)
case UNCOMPRESSED_R8G8B8A8: byteSize *= 4; break; // 32 bpp (4 bytes)
case UNCOMPRESSED_R32G32B32: byteSize *= 12; break; // 4 byte per channel (12 bytes)
case COMPRESSED_DXT3_RGBA:
case COMPRESSED_DXT5_RGBA:
case COMPRESSED_ETC2_EAC_RGBA:
case COMPRESSED_ASTC_4x4_RGBA: break; // 8 bpp (1 byte)
case COMPRESSED_DXT1_RGB:
case COMPRESSED_DXT1_RGBA:
case COMPRESSED_ETC1_RGB:
case COMPRESSED_ETC2_RGB:
case COMPRESSED_PVRT_RGB:
case COMPRESSED_PVRT_RGBA: byteSize /= 2; break; // 4 bpp
case COMPRESSED_ASTC_8x8_RGBA: byteSize /= 4; break;// 2 bpp
default: TraceLog(LOG_WARNING, "Image format not recognized"); break;
}
newImage.data = malloc(byteSize);
if (newImage.data != NULL)
{
// NOTE: Size must be provided in bytes
memcpy(newImage.data, image.data, byteSize);
newImage.width = image.width;
newImage.height = image.height;
newImage.mipmaps = image.mipmaps;
newImage.format = image.format;
}
return newImage;
}
// Crop an image to area defined by a rectangle // Crop an image to area defined by a rectangle
// NOTE: Security checks are performed in case rectangle goes out of bounds // NOTE: Security checks are performed in case rectangle goes out of bounds
void ImageCrop(Image *image, Rectangle crop) void ImageCrop(Image *image, Rectangle crop)
@ -955,6 +1076,190 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight)
free(pixels); free(pixels);
} }
// Generate all mipmap levels for a provided image
// NOTE 1: Supports POT and NPOT images
// NOTE 2: image.data is scaled to include mipmap levels
// NOTE 3: Mipmaps format is the same as base image
void ImageMipmaps(Image *image)
{
int mipCount = 1; // Required mipmap levels count (including base level)
int mipWidth = image->width; // Base image width
int mipHeight = image->height; // Base image height
int mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); // Image data size (in bytes)
// Count mipmap levels required
while ((mipWidth != 1) || (mipHeight != 1))
{
if (mipWidth != 1) mipWidth /= 2;
if (mipHeight != 1) mipHeight /= 2;
// Security check for NPOT textures
if (mipWidth < 1) mipWidth = 1;
if (mipHeight < 1) mipHeight = 1;
TraceLog(LOG_DEBUG, "Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize);
mipCount++;
mipSize += GetPixelDataSize(mipWidth, mipHeight, image->format); // Add mipmap size (in bytes)
}
TraceLog(LOG_DEBUG, "Mipmaps available: %i - Mipmaps required: %i", image->mipmaps, mipCount);
TraceLog(LOG_DEBUG, "Mipmaps total size required: %i", mipSize);
TraceLog(LOG_DEBUG, "Image data memory start address: 0x%x", image->data);
if (image->mipmaps < mipCount)
{
void *temp = realloc(image->data, mipSize);
if (temp != NULL)
{
image->data = temp; // Assign new pointer (new size) to store mipmaps data
TraceLog(LOG_DEBUG, "Image data memory point reallocated: 0x%x", temp);
}
else TraceLog(LOG_WARNING, "Mipmaps required memory could not be allocated");
// Pointer to allocated memory point where store next mipmap level data
unsigned char *nextmip = (unsigned char *)image->data + GetPixelDataSize(image->width, image->height, image->format);
mipWidth = image->width/2;
mipHeight = image->height/2;
mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);
Image imCopy = ImageCopy(*image);
for (int i = 1; i < mipCount; i++)
{
TraceLog(LOG_DEBUG, "Gen mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip);
ImageResize(&imCopy, mipWidth, mipHeight); // Uses internally Mitchell cubic downscale filter
memcpy(nextmip, imCopy.data, mipSize);
nextmip += mipSize;
image->mipmaps++;
mipWidth /= 2;
mipHeight /= 2;
// Security check for NPOT textures
if (mipWidth < 1) mipWidth = 1;
if (mipHeight < 1) mipHeight = 1;
mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);
}
UnloadImage(imCopy);
}
else TraceLog(LOG_WARNING, "Image mipmaps already available");
}
// Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
// NOTE: In case selected bpp do not represent an known 16bit format,
// dithered data is stored in the LSB part of the unsigned short
void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
{
if (image->format >= COMPRESSED_DXT1_RGB)
{
TraceLog(LOG_WARNING, "Compressed data formats can not be dithered");
return;
}
if ((rBpp+gBpp+bBpp+aBpp) > 16)
{
TraceLog(LOG_WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
}
else
{
Color *pixels = GetImageData(*image);
free(image->data); // free old image data
if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8))
{
TraceLog(LOG_WARNING, "Image format is already 16bpp or lower, dithering could have no effect");
}
// Define new image format, check if desired bpp match internal known format
if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5;
else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1;
else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4;
else
{
image->format = 0;
TraceLog(LOG_WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp);
}
// NOTE: We will store the dithered data as unsigned short (16bpp)
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
Color oldPixel = WHITE;
Color newPixel = WHITE;
int rError, gError, bError;
unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition
#define MIN(a,b) (((a)<(b))?(a):(b))
for (int y = 0; y < image->height; y++)
{
for (int x = 0; x < image->width; x++)
{
oldPixel = pixels[y*image->width + x];
// NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
newPixel.r = oldPixel.r >> (8 - rBpp); // R bits
newPixel.g = oldPixel.g >> (8 - gBpp); // G bits
newPixel.b = oldPixel.b >> (8 - bBpp); // B bits
newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering)
// NOTE: Error must be computed between new and old pixel but using same number of bits!
// We want to know how much color precision we have lost...
rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
pixels[y*image->width + x] = newPixel;
// NOTE: Some cases are out of the array and should be ignored
if (x < (image->width - 1))
{
pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
}
if ((x > 0) && (y < (image->height - 1)))
{
pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff);
pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff);
pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff);
}
if (y < (image->height - 1))
{
pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
}
if ((x < (image->width - 1)) && (y < (image->height - 1)))
{
pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff);
pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff);
pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff);
}
rPixel = (unsigned short)newPixel.r;
gPixel = (unsigned short)newPixel.g;
bPixel = (unsigned short)newPixel.b;
aPixel = (unsigned short)newPixel.a;
((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
}
}
free(pixels);
}
}
// Draw an image (source) within an image (destination) // Draw an image (source) within an image (destination)
// TODO: Feel this function could be simplified... // TODO: Feel this function could be simplified...
void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
@ -1069,29 +1374,59 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
{ {
int length = strlen(text); int length = strlen(text);
int posX = 0; int posX = 0;
int index; // Index position in sprite font
unsigned char character; // Current character
// TODO: ISSUE: Measured text size does not seem to be correct... issue on ImageDraw()
Vector2 imSize = MeasureTextEx(font, text, font.baseSize, spacing); Vector2 imSize = MeasureTextEx(font, text, font.baseSize, spacing);
TraceLog(LOG_WARNING, "Text Image size: %f, %f", imSize.x, imSize.y); TraceLog(LOG_DEBUG, "Text Image size: %f, %f", imSize.x, imSize.y);
// NOTE: glGetTexImage() not available in OpenGL ES // NOTE: glGetTexImage() not available in OpenGL ES
// TODO: This is horrible, retrieving font texture from GPU!!!
// Define ImageFont struct? or include Image spritefont in SpriteFont struct?
Image imFont = GetTextureData(font.texture); Image imFont = GetTextureData(font.texture);
ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Convert to 32 bit for color tint ImageColorTint(&imFont, tint); // Apply color tint to font
ImageColorTint(&imFont, tint); // Apply color tint to font
// Create image to store text // Create image to store text
Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK); Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
CharInfo letter = font.chars[(int)text[i] - 32]; if ((unsigned char)text[i] == '\n')
{
ImageDraw(&imText, imFont, letter.rec, (Rectangle){ posX + letter.offsetX, // TODO: Support line break
letter.offsetY, letter.rec.width, letter.rec.height }); }
else
{
if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK!
{
// Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿)
character = (unsigned char)text[i + 1];
index = GetGlyphIndex(font, (int)character);
i++;
}
else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK!
{
// Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ)
character = (unsigned char)text[i + 1];
index = GetGlyphIndex(font, (int)character + 64);
i++;
}
else index = GetGlyphIndex(font, (unsigned char)text[i]);
if (letter.advanceX == 0) posX += letter.rec.width + spacing; CharInfo letter = font.chars[index];
else posX += letter.advanceX + spacing;
if ((unsigned char)text[i] != ' ')
{
ImageDraw(&imText, imFont, letter.rec, (Rectangle){ posX + letter.offsetX,
letter.offsetY, letter.rec.width, letter.rec.height });
}
if (letter.advanceX == 0) posX += letter.rec.width + spacing;
else posX += letter.advanceX + spacing;
}
} }
UnloadImage(imFont); UnloadImage(imFont);
@ -1100,7 +1435,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
if (fontSize > imSize.y) if (fontSize > imSize.y)
{ {
float scaleFactor = fontSize/imSize.y; float scaleFactor = fontSize/imSize.y;
TraceLog(LOG_INFO, "Scalefactor: %f", scaleFactor); TraceLog(LOG_INFO, "Image text scaled by factor: %f", scaleFactor);
// Using nearest-neighbor scaling algorithm for default font // Using nearest-neighbor scaling algorithm for default font
if (font.texture.id == GetDefaultFont().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); if (font.texture.id == GetDefaultFont().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
@ -1178,115 +1513,6 @@ void ImageFlipHorizontal(Image *image)
image->data = processed.data; image->data = processed.data;
} }
// Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
// NOTE: In case selected bpp do not represent an known 16bit format,
// dithered data is stored in the LSB part of the unsigned short
void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
{
if (image->format >= COMPRESSED_DXT1_RGB)
{
TraceLog(LOG_WARNING, "Compressed data formats can not be dithered");
return;
}
if ((rBpp+gBpp+bBpp+aBpp) > 16)
{
TraceLog(LOG_WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
}
else
{
Color *pixels = GetImageData(*image);
free(image->data); // free old image data
if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8))
{
TraceLog(LOG_WARNING, "Image format is already 16bpp or lower, dithering could have no effect");
}
// Define new image format, check if desired bpp match internal known format
if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5;
else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1;
else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4;
else
{
image->format = 0;
TraceLog(LOG_WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp);
}
// NOTE: We will store the dithered data as unsigned short (16bpp)
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
Color oldPixel = WHITE;
Color newPixel = WHITE;
int rError, gError, bError;
unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition
#define MIN(a,b) (((a)<(b))?(a):(b))
for (int y = 0; y < image->height; y++)
{
for (int x = 0; x < image->width; x++)
{
oldPixel = pixels[y*image->width + x];
// NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
newPixel.r = oldPixel.r >> (8 - rBpp); // R bits
newPixel.g = oldPixel.g >> (8 - gBpp); // G bits
newPixel.b = oldPixel.b >> (8 - bBpp); // B bits
newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering)
// NOTE: Error must be computed between new and old pixel but using same number of bits!
// We want to know how much color precision we have lost...
rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
pixels[y*image->width + x] = newPixel;
// NOTE: Some cases are out of the array and should be ignored
if (x < (image->width - 1))
{
pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
}
if ((x > 0) && (y < (image->height - 1)))
{
pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff);
pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff);
pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff);
}
if (y < (image->height - 1))
{
pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
}
if ((x < (image->width - 1)) && (y < (image->height - 1)))
{
pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff);
pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff);
pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff);
}
rPixel = (unsigned short)newPixel.r;
gPixel = (unsigned short)newPixel.g;
bPixel = (unsigned short)newPixel.b;
aPixel = (unsigned short)newPixel.a;
((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
}
}
free(pixels);
}
}
// Modify image color: tint // Modify image color: tint
void ImageColorTint(Image *image, Color color) void ImageColorTint(Image *image, Color color)
{ {
@ -1576,7 +1802,7 @@ Image GenImageWhiteNoise(int width, int height, float factor)
} }
// Generate image: perlin noise // Generate image: perlin noise
Image GenImagePerlinNoise(int width, int height, float scale) Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale)
{ {
Color *pixels = (Color *)malloc(width*height*sizeof(Color)); Color *pixels = (Color *)malloc(width*height*sizeof(Color));
@ -1584,13 +1810,18 @@ Image GenImagePerlinNoise(int width, int height, float scale)
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
float nx = (float)x*scale/(float)width; float nx = (float)(x + offsetX)*scale/(float)width;
float ny = (float)y*scale/(float)height; float ny = (float)(y + offsetY)*scale/(float)height;
// we need to translate the data from [-1; 1] to [0; 1] // Typical values to start playing with:
float p = (stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6, 0, 0, 0) + 1.0f) / 2.0f; // lacunarity = ~2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
// gain = 0.5 -- relative weighting applied to each successive octave
// octaves = 6 -- number of "octaves" of noise3() to sum
// NOTE: We need to translate the data from [-1..1] to [0..1]
float p = (stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6, 0, 0, 0) + 1.0f)/2.0f;
int intensity = (int)(p * 255.0f); int intensity = (int)(p*255.0f);
pixels[y*width + x] = (Color){intensity, intensity, intensity, 255}; pixels[y*width + x] = (Color){intensity, intensity, intensity, 255};
} }
} }
@ -1665,7 +1896,7 @@ Image GenImageCellular(int width, int height, int tileSize)
// Generate GPU mipmaps for a texture // Generate GPU mipmaps for a texture
void GenTextureMipmaps(Texture2D *texture) void GenTextureMipmaps(Texture2D *texture)
{ {
#if PLATFORM_WEB #if defined(PLATFORM_WEB)
// Calculate next power-of-two values // Calculate next power-of-two values
int potWidth = (int)powf(2, ceilf(logf((float)texture->width)/logf(2))); int potWidth = (int)powf(2, ceilf(logf((float)texture->width)/logf(2)));
int potHeight = (int)powf(2, ceilf(logf((float)texture->height)/logf(2))); int potHeight = (int)powf(2, ceilf(logf((float)texture->height)/logf(2)));

View file

@ -47,7 +47,7 @@ func LoadImageEx(pixels []Color, width, height int32) *Image {
} }
// LoadImagePro - Load image from raw data with parameters // LoadImagePro - Load image from raw data with parameters
func LoadImagePro(data []byte, width, height int32, format TextureFormat) *Image { func LoadImagePro(data []byte, width, height int32, format PixelFormat) *Image {
cdata := unsafe.Pointer(&data[0]) cdata := unsafe.Pointer(&data[0])
cwidth := (C.int)(width) cwidth := (C.int)(width)
cheight := (C.int)(height) cheight := (C.int)(height)
@ -58,7 +58,7 @@ func LoadImagePro(data []byte, width, height int32, format TextureFormat) *Image
} }
// LoadImageRaw - Load image data from RAW file // LoadImageRaw - Load image data from RAW file
func LoadImageRaw(fileName string, width, height int32, format TextureFormat, headerSize int32) *Image { func LoadImageRaw(fileName string, width, height int32, format PixelFormat, headerSize int32) *Image {
cfileName := C.CString(fileName) cfileName := C.CString(fileName)
defer C.free(unsafe.Pointer(cfileName)) defer C.free(unsafe.Pointer(cfileName))
cwidth := (C.int)(width) cwidth := (C.int)(width)
@ -121,6 +121,15 @@ func GetImageData(image *Image) []byte {
return (*[1 << 30]uint8)(unsafe.Pointer(ret))[:] return (*[1 << 30]uint8)(unsafe.Pointer(ret))[:]
} }
// GetPixelDataSize - Get pixel data size in bytes (image or texture)
func GetPixelDataSize(width, height, format int32) int32 {
cwidth := (C.int)(width)
cheight := (C.int)(height)
cformat := (C.int)(format)
ret := C.GetPixelDataSize(cwidth, cheight, cformat)
return int32(ret)
}
// GetTextureData - Get pixel data from GPU texture and return an Image // GetTextureData - Get pixel data from GPU texture and return an Image
func GetTextureData(texture Texture2D) *Image { func GetTextureData(texture Texture2D) *Image {
ctexture := texture.cptr() ctexture := texture.cptr()
@ -166,6 +175,27 @@ func ImageAlphaMask(image, alphaMask *Image) {
C.ImageAlphaMask(cimage, *calphaMask) C.ImageAlphaMask(cimage, *calphaMask)
} }
// ImageAlphaClear - Apply alpha mask to image
func ImageAlphaClear(image *Image, color Color, threshold float32) {
cimage := image.cptr()
ccolor := color.cptr()
cthreshold := (C.float)(threshold)
C.ImageAlphaClear(cimage, *ccolor, cthreshold)
}
// ImageAlphaCrop - Crop image depending on alpha value
func ImageAlphaCrop(image *Image, threshold float32) {
cimage := image.cptr()
cthreshold := (C.float)(threshold)
C.ImageAlphaCrop(cimage, cthreshold)
}
// ImageAlphaPremultiply - Premultiply alpha channel
func ImageAlphaPremultiply(image *Image) {
cimage := image.cptr()
C.ImageAlphaPremultiply(cimage)
}
// ImageDither - Dither image data to 16bpp or lower (Floyd-Steinberg dithering) // ImageDither - Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
func ImageDither(image *Image, rBpp, gBpp, bBpp, aBpp int32) { func ImageDither(image *Image, rBpp, gBpp, bBpp, aBpp int32) {
cimage := image.cptr() cimage := image.cptr()
@ -207,6 +237,12 @@ func ImageResizeNN(image *Image, newWidth, newHeight int32) {
C.ImageResizeNN(cimage, cnewWidth, cnewHeight) C.ImageResizeNN(cimage, cnewWidth, cnewHeight)
} }
// ImageMipmaps - Generate all mipmap levels for a provided image
func ImageMipmaps(image *Image) {
cimage := image.cptr()
C.ImageMipmaps(cimage)
}
// ImageText - Create an image from text (default font) // ImageText - Create an image from text (default font)
func ImageText(text string, fontSize int32, color Color) *Image { func ImageText(text string, fontSize int32, color Color) *Image {
ctext := C.CString(text) ctext := C.CString(text)
@ -383,12 +419,14 @@ func GenImageWhiteNoise(width, height int, factor float32) *Image {
} }
// GenImagePerlinNoise - Generate image: perlin noise // GenImagePerlinNoise - Generate image: perlin noise
func GenImagePerlinNoise(width, height int, scale float32) *Image { func GenImagePerlinNoise(width, height, offsetX, offsetY int, scale float32) *Image {
cwidth := (C.int)(width) cwidth := (C.int)(width)
cheight := (C.int)(height) cheight := (C.int)(height)
coffsetX := (C.int)(offsetX)
coffsetY := (C.int)(offsetY)
cscale := (C.float)(scale) cscale := (C.float)(scale)
ret := C.GenImagePerlinNoise(cwidth, cheight, cscale) ret := C.GenImagePerlinNoise(cwidth, cheight, coffsetX, coffsetY, cscale)
v := newImageFromPointer(unsafe.Pointer(&ret)) v := newImageFromPointer(unsafe.Pointer(&ret))
return v return v
} }

View file

@ -1,5 +1,3 @@
// +build !js
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.utils - Some common utility functions * raylib.utils - Some common utility functions
@ -18,16 +16,13 @@
* Show TraceLog() output messages * Show TraceLog() output messages
* NOTE: By default LOG_DEBUG traces not shown * NOTE: By default LOG_DEBUG traces not shown
* *
* #define SUPPORT_TRACELOG_DEBUG
* Show TraceLog() LOG_DEBUG messages
*
* DEPENDENCIES: * DEPENDENCIES:
* stb_image_write - BMP/PNG writting functions * stb_image_write - BMP/PNG writting functions
* *
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -47,7 +42,6 @@
**********************************************************************************************/ **********************************************************************************************/
#define SUPPORT_TRACELOG // Output tracelog messages #define SUPPORT_TRACELOG // Output tracelog messages
//#define SUPPORT_TRACELOG_DEBUG // Avoid LOG_DEBUG messages tracing
#include "raylib.h" // WARNING: Required for: LogType enum #include "raylib.h" // WARNING: Required for: LogType enum
#include "utils.h" #include "utils.h"
@ -65,15 +59,16 @@
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png() #include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png()
#endif #endif
#define RRES_IMPLEMENTATION
#include "rres.h"
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Log types messages supported flags (bit based)
static unsigned char logTypeFlags = LOG_INFO | LOG_WARNING | LOG_ERROR;
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
AAssetManager *assetManager; AAssetManager *assetManager;
#endif #endif
@ -92,16 +87,17 @@ static int android_close(void *cookie);
// Module Functions Definition - Utilities // Module Functions Definition - Utilities
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Enable trace log message types (bit flags based)
void SetTraceLog(unsigned char types)
{
logTypeFlags = types;
}
// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
void TraceLog(int msgType, const char *text, ...) void TraceLog(int msgType, const char *text, ...)
{ {
#if defined(SUPPORT_TRACELOG) #if defined(SUPPORT_TRACELOG)
static char buffer[128]; static char buffer[128];
int traceDebugMsgs = 0;
#if defined(SUPPORT_TRACELOG_DEBUG)
traceDebugMsgs = 1;
#endif
switch(msgType) switch(msgType)
{ {
@ -121,14 +117,21 @@ void TraceLog(int msgType, const char *text, ...)
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
switch(msgType) switch(msgType)
{ {
case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break; case LOG_INFO: if (logTypeFlags & LOG_INFO) __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break;
case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break; case LOG_WARNING: if (logTypeFlags & LOG_WARNING) __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break;
case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break; case LOG_ERROR: if (logTypeFlags & LOG_ERROR) __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break;
case LOG_DEBUG: if (traceDebugMsgs) __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break; case LOG_DEBUG: if (logTypeFlags & LOG_DEBUG) __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break;
default: break; default: break;
} }
#else #else
if ((msgType != LOG_DEBUG) || ((msgType == LOG_DEBUG) && (traceDebugMsgs))) vprintf(buffer, args); switch(msgType)
{
case LOG_INFO: if (logTypeFlags & LOG_INFO) vprintf(buffer, args); break;
case LOG_WARNING: if (logTypeFlags & LOG_WARNING) vprintf(buffer, args); break;
case LOG_ERROR: if (logTypeFlags & LOG_ERROR) vprintf(buffer, args); break;
case LOG_DEBUG: if (logTypeFlags & LOG_DEBUG) vprintf(buffer, args); break;
default: break;
}
#endif #endif
va_end(args); va_end(args);

View file

@ -2,23 +2,41 @@
package raylib package raylib
/*
#include "raylib.h"
*/
import "C"
import ( import (
"fmt" "fmt"
"os" "os"
) )
// SetTraceLog - Enable trace log message types (bit flags based)
func SetTraceLog(typeFlags int) {
logTypeFlags = typeFlags
ctypeFlags := (C.uchar)(typeFlags)
C.SetTraceLog(ctypeFlags)
}
// TraceLog - Show trace log messages (INFO, WARNING, ERROR, DEBUG) // TraceLog - Show trace log messages (INFO, WARNING, ERROR, DEBUG)
func TraceLog(msgType int, text string, v ...interface{}) { func TraceLog(msgType int, text string, v ...interface{}) {
switch msgType { switch msgType {
case LogInfo: case LogInfo:
fmt.Printf("INFO: "+text+"\n", v...) if logTypeFlags&LogInfo == 0 {
fmt.Printf("INFO: "+text+"\n", v...)
}
case LogWarning: case LogWarning:
fmt.Printf("WARNING: "+text+"\n", v...) if logTypeFlags&LogWarning == 0 {
fmt.Printf("WARNING: "+text+"\n", v...)
}
case LogError: case LogError:
fmt.Printf("ERROR: "+text+"\n", v...) if logTypeFlags&LogError == 0 {
os.Exit(1) fmt.Printf("ERROR: "+text+"\n", v...)
}
case LogDebug: case LogDebug:
if traceDebugMsgs { if logTypeFlags&LogDebug == 0 {
fmt.Printf("DEBUG: "+text+"\n", v...) fmt.Printf("DEBUG: "+text+"\n", v...)
} }
} }

View file

@ -5,7 +5,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -32,8 +32,6 @@
#include <android/asset_manager.h> // Required for: AAssetManager #include <android/asset_manager.h> // Required for: AAssetManager
#endif #endif
#include "rres.h"
#define SUPPORT_SAVE_PNG #define SUPPORT_SAVE_PNG
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------

View file

@ -3,6 +3,7 @@
package raylib package raylib
/* /*
#include "raylib.h"
#include <stdlib.h> #include <stdlib.h>
void log_info(const char *msg); void log_info(const char *msg);
@ -16,28 +17,40 @@ import "C"
import ( import (
"fmt" "fmt"
"os"
"unsafe" "unsafe"
) )
// SetTraceLog - Enable trace log message types (bit flags based)
func SetTraceLog(typeFlags int) {
logTypeFlags = typeFlags
ctypeFlags := (C.uchar)(typeFlags)
C.SetTraceLog(ctypeFlags)
}
// TraceLog - Trace log messages showing (INFO, WARNING, ERROR, DEBUG) // TraceLog - Trace log messages showing (INFO, WARNING, ERROR, DEBUG)
func TraceLog(msgType int, text string, v ...interface{}) { func TraceLog(msgType int, text string, v ...interface{}) {
switch msgType { switch msgType {
case LogInfo: case LogInfo:
msg := C.CString(fmt.Sprintf("INFO: "+text, v...)) if logTypeFlags&LogInfo == 0 {
defer C.free(unsafe.Pointer(msg)) msg := C.CString(fmt.Sprintf("INFO: "+text, v...))
C.log_info(msg) defer C.free(unsafe.Pointer(msg))
case LogError: C.log_info(msg)
msg := C.CString(fmt.Sprintf("ERROR: "+text, v...)) }
defer C.free(unsafe.Pointer(msg))
C.log_error(msg)
os.Exit(1)
case LogWarning: case LogWarning:
msg := C.CString(fmt.Sprintf("WARNING: "+text, v...)) if logTypeFlags&LogWarning == 0 {
defer C.free(unsafe.Pointer(msg)) msg := C.CString(fmt.Sprintf("WARNING: "+text, v...))
C.log_warn(msg) defer C.free(unsafe.Pointer(msg))
C.log_warn(msg)
}
case LogError:
if logTypeFlags&LogError == 0 {
msg := C.CString(fmt.Sprintf("ERROR: "+text, v...))
defer C.free(unsafe.Pointer(msg))
C.log_error(msg)
}
case LogDebug: case LogDebug:
if traceDebugMsgs { if logTypeFlags&LogDebug == 0 {
msg := C.CString(fmt.Sprintf("DEBUG: "+text, v...)) msg := C.CString(fmt.Sprintf("DEBUG: "+text, v...))
defer C.free(unsafe.Pointer(msg)) defer C.free(unsafe.Pointer(msg))
C.log_debug(msg) C.log_debug(msg)

View file

@ -2,23 +2,41 @@
package raylib package raylib
/*
#include "raylib.h"
*/
import "C"
import ( import (
"fmt" "fmt"
"os" "os"
) )
// TraceLog - Trace log messages showing (INFO, WARNING, ERROR, DEBUG) // SetTraceLog - Enable trace log message types (bit flags based)
func SetTraceLog(typeFlags int) {
logTypeFlags = typeFlags
ctypeFlags := (C.uchar)(typeFlags)
C.SetTraceLog(ctypeFlags)
}
// TraceLog - Show trace log messages (INFO, WARNING, ERROR, DEBUG)
func TraceLog(msgType int, text string, v ...interface{}) { func TraceLog(msgType int, text string, v ...interface{}) {
switch msgType { switch msgType {
case LogInfo: case LogInfo:
fmt.Printf("INFO: "+text+"\n", v...) if logTypeFlags&LogInfo == 0 {
case LogError: fmt.Printf("INFO: "+text+"\n", v...)
fmt.Printf("ERROR: "+text+"\n", v...) }
os.Exit(1)
case LogWarning: case LogWarning:
fmt.Printf("WARNING: "+text+"\n", v...) if logTypeFlags&LogWarning == 0 {
fmt.Printf("WARNING: "+text+"\n", v...)
}
case LogError:
if logTypeFlags&LogError == 0 {
fmt.Printf("ERROR: "+text+"\n", v...)
}
case LogDebug: case LogDebug:
if traceDebugMsgs { if logTypeFlags&LogDebug == 0 {
fmt.Printf("DEBUG: "+text+"\n", v...) fmt.Printf("DEBUG: "+text+"\n", v...)
} }
} }