Remove end-line spaces

This commit is contained in:
Ray 2018-11-06 15:10:50 +01:00
parent e340517a73
commit fc1c9505ba
8 changed files with 431 additions and 430 deletions

View File

@ -80,7 +80,7 @@
#endif
#include "external/mini_al.h" // mini_al audio library
// NOTE: Cannot be implement here because it conflicts with
// NOTE: Cannot be implement here because it conflicts with
// Win32 APIs: Rectangle, CloseWindow(), ShowCursor(), PlaySoundA()
#include <stdlib.h> // Required for: malloc(), free()
@ -132,12 +132,12 @@
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef enum {
MUSIC_AUDIO_OGG = 0,
MUSIC_AUDIO_FLAC,
MUSIC_AUDIO_MP3,
MUSIC_MODULE_XM,
MUSIC_MODULE_MOD
typedef enum {
MUSIC_AUDIO_OGG = 0,
MUSIC_AUDIO_FLAC,
MUSIC_AUDIO_MP3,
MUSIC_MODULE_XM,
MUSIC_MODULE_MOD
} MusicContextType;
// Music type (file streaming from memory)
@ -167,12 +167,12 @@ typedef struct MusicData {
} MusicData;
#if defined(AUDIO_STANDALONE)
typedef enum {
LOG_INFO = 0,
LOG_ERROR,
LOG_WARNING,
LOG_DEBUG,
LOG_OTHER
typedef enum {
LOG_INFO = 0,
LOG_ERROR,
LOG_WARNING,
LOG_DEBUG,
LOG_OTHER
} TraceLogType;
#endif
@ -214,7 +214,7 @@ typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioB
// Audio buffer structure
// NOTE: Slightly different logic is used when feeding data to the playback device depending on whether or not data is streamed
typedef struct AudioBuffer AudioBuffer;
typedef struct AudioBuffer AudioBuffer;
struct AudioBuffer {
mal_dsp dsp; // Required for format conversion
float volume;
@ -239,7 +239,7 @@ static bool isAudioInitialized = MAL_FALSE;
static float masterVolume = 1.0f;
// Audio buffers are tracked in a linked list
static AudioBuffer *firstAudioBuffer = NULL;
static AudioBuffer *firstAudioBuffer = NULL;
static AudioBuffer *lastAudioBuffer = NULL;
// mini_al functions declaration
@ -268,7 +268,7 @@ static void OnLog(mal_context *pContext, mal_device *pDevice, const char *messag
{
(void)pContext;
(void)pDevice;
TraceLog(LOG_ERROR, message); // All log messages from mini_al are errors
}
@ -291,30 +291,30 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
if (!audioBuffer->playing || audioBuffer->paused) continue;
mal_uint32 framesRead = 0;
for (;;)
for (;;)
{
if (framesRead > frameCount)
if (framesRead > frameCount)
{
TraceLog(LOG_DEBUG, "Mixed too many frames from audio buffer");
break;
}
if (framesRead == frameCount) break;
// Just read as much data as we can from the stream.
mal_uint32 framesToRead = (frameCount - framesRead);
while (framesToRead > 0)
while (framesToRead > 0)
{
float tempBuffer[1024]; // 512 frames for stereo.
mal_uint32 framesToReadRightNow = framesToRead;
if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS)
if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS)
{
framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS;
}
mal_uint32 framesJustRead = (mal_uint32)mal_dsp_read(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, audioBuffer->dsp.pUserData);
if (framesJustRead > 0)
if (framesJustRead > 0)
{
float *framesOut = (float *)pFramesOut + (framesRead*device.channels);
float *framesIn = tempBuffer;
@ -325,16 +325,16 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
}
// If we weren't able to read all the frames we requested, break.
if (framesJustRead < framesToReadRightNow)
if (framesJustRead < framesToReadRightNow)
{
if (!audioBuffer->looping)
if (!audioBuffer->looping)
{
StopAudioBuffer(audioBuffer);
break;
}
else
}
else
{
// Should never get here, but just for safety,
// Should never get here, but just for safety,
// move the cursor position back to the start and continue the loop.
audioBuffer->frameCursorPos = 0;
continue;
@ -342,13 +342,13 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
}
}
// If for some reason we weren't able to read every frame we'll need to break from the loop.
// If for some reason we weren't able to read every frame we'll need to break from the loop.
// Not doing this could theoretically put us into an infinite loop.
if (framesToRead > 0) break;
}
}
}
mal_mutex_unlock(&audioLock);
return frameCount; // We always output the same number of frames that were originally requested.
@ -361,8 +361,8 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2;
mal_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
if (currentSubBufferIndex > 1)
if (currentSubBufferIndex > 1)
{
TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream");
return 0;
@ -381,11 +381,11 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
{
// We break from this loop differently depending on the buffer's usage. For static buffers, we simply fill as much data as we can. For
// streaming buffers we only fill the halves of the buffer that are processed. Unprocessed halves must keep their audio data in-tact.
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
{
if (framesRead >= frameCount) break;
}
else
}
else
{
if (isSubBufferProcessed[currentSubBufferIndex]) break;
}
@ -394,11 +394,11 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
if (totalFramesRemaining == 0) break;
mal_uint32 framesRemainingInOutputBuffer;
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
{
framesRemainingInOutputBuffer = audioBuffer->bufferSizeInFrames - audioBuffer->frameCursorPos;
}
else
}
else
{
mal_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex;
framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer);
@ -412,7 +412,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
framesRead += framesToRead;
// If we've read to the end of the buffer, mark it as processed.
if (framesToRead == framesRemainingInOutputBuffer)
if (framesToRead == framesRemainingInOutputBuffer)
{
audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true;
isSubBufferProcessed[currentSubBufferIndex] = true;
@ -420,7 +420,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
currentSubBufferIndex = (currentSubBufferIndex + 1)%2;
// We need to break from this loop if we're not looping.
if (!audioBuffer->looping)
if (!audioBuffer->looping)
{
StopAudioBuffer(audioBuffer);
break;
@ -430,7 +430,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
// Zero-fill excess.
mal_uint32 totalFramesRemaining = (frameCount - framesRead);
if (totalFramesRemaining > 0)
if (totalFramesRemaining > 0)
{
memset((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes);
@ -447,9 +447,9 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
// NOTE: framesOut is both an input and an output. It will be initially filled with zeros outside of this function.
static void MixAudioFrames(float *framesOut, const float *framesIn, mal_uint32 frameCount, float localVolume)
{
for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame)
for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame)
{
for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel)
for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel)
{
float *frameOut = framesOut + (iFrame*device.channels);
const float *frameIn = framesIn + (iFrame*device.channels);
@ -519,7 +519,7 @@ void InitAudioDevice(void)
// Close the audio device for all contexts
void CloseAudioDevice(void)
{
if (!isAudioInitialized)
if (!isAudioInitialized)
{
TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized");
return;
@ -543,7 +543,7 @@ void SetMasterVolume(float volume)
{
if (volume < 0.0f) volume = 0.0f;
else if (volume > 1.0f) volume = 1.0f;
masterVolume = volume;
}
@ -574,7 +574,7 @@ AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint3
dspConfig.pUserData = audioBuffer;
dspConfig.allowDynamicSampleRate = MAL_TRUE; // <-- Required for pitch shifting.
mal_result resultMAL = mal_dsp_init(&dspConfig, &audioBuffer->dsp);
if (resultMAL != MAL_SUCCESS)
if (resultMAL != MAL_SUCCESS)
{
TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to create data conversion pipeline");
free(audioBuffer);
@ -716,10 +716,10 @@ void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
void TrackAudioBuffer(AudioBuffer *audioBuffer)
{
mal_mutex_lock(&audioLock);
{
if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer;
else
else
{
lastAudioBuffer->next = audioBuffer;
audioBuffer->prev = lastAudioBuffer;
@ -727,7 +727,7 @@ void TrackAudioBuffer(AudioBuffer *audioBuffer)
lastAudioBuffer = audioBuffer;
}
mal_mutex_unlock(&audioLock);
}
@ -735,7 +735,7 @@ void TrackAudioBuffer(AudioBuffer *audioBuffer)
void UntrackAudioBuffer(AudioBuffer *audioBuffer)
{
mal_mutex_lock(&audioLock);
{
if (audioBuffer->prev == NULL) firstAudioBuffer = audioBuffer->next;
else audioBuffer->prev->next = audioBuffer->next;
@ -746,7 +746,7 @@ void UntrackAudioBuffer(AudioBuffer *audioBuffer)
audioBuffer->prev = NULL;
audioBuffer->next = NULL;
}
mal_mutex_unlock(&audioLock);
}
@ -816,7 +816,7 @@ Sound LoadSoundFromWave(Wave wave)
{
// When using mini_al we need to do our own mixing. To simplify this we need convert the format of each sound to be consistent with
// the format used to open the playback device. We can do this two ways:
//
//
// 1) Convert the whole sound in one go at load time (here).
// 2) Convert the audio data in chunks at mixing time.
//
@ -861,7 +861,7 @@ void UnloadSound(Sound sound)
void UpdateSound(Sound sound, const void *data, int samplesCount)
{
AudioBuffer *audioBuffer = (AudioBuffer *)sound.audioBuffer;
if (audioBuffer == NULL)
{
TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer");
@ -878,9 +878,9 @@ void UpdateSound(Sound sound, const void *data, int samplesCount)
void ExportWave(Wave wave, const char *fileName)
{
bool success = false;
if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
else if (IsFileExtension(fileName, ".raw"))
else if (IsFileExtension(fileName, ".raw"))
{
// Export raw sample data (without header)
// NOTE: It's up to the user to track wave parameters
@ -888,7 +888,7 @@ void ExportWave(Wave wave, const char *fileName)
success = fwrite(wave.data, wave.sampleCount*wave.channels*wave.sampleSize/8, 1, rawFile);
fclose(rawFile);
}
if (success) TraceLog(LOG_INFO, "Wave exported successfully: %s", fileName);
else TraceLog(LOG_WARNING, "Wave could not be exported.");
}
@ -897,12 +897,12 @@ void ExportWave(Wave wave, const char *fileName)
void ExportWaveAsCode(Wave wave, const char *fileName)
{
#define BYTES_TEXT_PER_LINE 20
char varFileName[256] = { 0 };
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
FILE *txtFile = fopen(fileName, "wt");
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
@ -917,7 +917,7 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
// Get file name from path and convert variable name to uppercase
strcpy(varFileName, GetFileNameWithoutExt(fileName));
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
fprintf(txtFile, "// Wave data information\n");
fprintf(txtFile, "#define %s_SAMPLE_COUNT %i\n", varFileName, wave.sampleCount);
fprintf(txtFile, "#define %s_SAMPLE_RATE %i\n", varFileName, wave.sampleRate);
@ -983,7 +983,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so.
mal_uint32 frameCount = (mal_uint32)mal_convert_frames(NULL, formatOut, channels, sampleRate, NULL, formatIn, wave->channels, wave->sampleRate, frameCountIn);
if (frameCount == 0)
if (frameCount == 0)
{
TraceLog(LOG_ERROR, "WaveFormat() : Failed to get frame count for format conversion.");
return;
@ -992,7 +992,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
void *data = malloc(frameCount*channels*(sampleSize/8));
frameCount = (mal_uint32)mal_convert_frames(data, formatOut, channels, sampleRate, wave->data, formatIn, wave->channels, wave->sampleRate, frameCountIn);
if (frameCount == 0)
if (frameCount == 0)
{
TraceLog(LOG_ERROR, "WaveFormat() : Format conversion failed.");
return;
@ -1130,16 +1130,16 @@ Music LoadMusicStream(const char *fileName)
TraceLog(LOG_INFO, "[%s] MP3 sample rate: %i", fileName, music->ctxMp3.sampleRate);
TraceLog(LOG_INFO, "[%s] MP3 bits per sample: %i", fileName, 32);
TraceLog(LOG_INFO, "[%s] MP3 channels: %i", fileName, music->ctxMp3.channels);
music->stream = InitAudioStream(music->ctxMp3.sampleRate, 32, music->ctxMp3.channels);
// TODO: There is not an easy way to compute the total number of samples available
// in an MP3, frames size could be variable... we tried with a 60 seconds music... but crashes...
music->totalSamples = drmp3_get_pcm_frame_count(&music->ctxMp3)*music->ctxMp3.channels;
music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_AUDIO_MP3;
music->loopCount = -1; // Infinite loop by default
TraceLog(LOG_INFO, "[%s] MP3 total samples: %i", fileName, music->totalSamples);
}
}
@ -1186,7 +1186,7 @@ Music LoadMusicStream(const char *fileName)
}
#endif
else musicLoaded = false;
if (!musicLoaded)
{
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
@ -1238,7 +1238,7 @@ void UnloadMusicStream(Music music)
void PlayMusicStream(Music music)
{
AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.audioBuffer;
if (audioBuffer == NULL)
{
TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer");
@ -1250,7 +1250,7 @@ void PlayMusicStream(Music music)
// // just make sure to play again on window restore
// if (IsMusicPlaying(music)) PlayMusicStream(music);
mal_uint32 frameCursorPos = audioBuffer->frameCursorPos;
PlayAudioStream(music->stream); // <-- This resets the cursor position.
audioBuffer->frameCursorPos = frameCursorPos;
@ -1273,7 +1273,7 @@ void ResumeMusicStream(Music music)
void StopMusicStream(Music music)
{
StopAudioStream(music->stream);
// Restart music context
switch (music->ctxType)
{
@ -1332,18 +1332,18 @@ void UpdateMusicStream(Music music)
} break;
#endif
#if defined(SUPPORT_FILEFORMAT_MP3)
case MUSIC_AUDIO_MP3:
case MUSIC_AUDIO_MP3:
{
// NOTE: samplesCount, actually refers to framesCount and returns the number of frames processed
unsigned int numFramesMp3 = (unsigned int)drmp3_read_pcm_frames_f32(&music->ctxMp3, samplesCount/music->stream.channels, (float *)pcm);
drmp3_read_pcm_frames_f32(&music->ctxMp3, samplesCount/music->stream.channels, (float *)pcm);
} break;
#endif
#if defined(SUPPORT_FILEFORMAT_XM)
case MUSIC_MODULE_XM:
case MUSIC_MODULE_XM:
{
// NOTE: Internally this function considers 2 channels generation, so samplesCount/2 --> WEIRD
jar_xm_generate_samples_16bit(music->ctxXm, (short *)pcm, samplesCount/2);
jar_xm_generate_samples_16bit(music->ctxXm, (short *)pcm, samplesCount/2);
} break;
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
@ -1369,7 +1369,7 @@ void UpdateMusicStream(Music music)
if (streamEnding)
{
StopMusicStream(music); // Stop music (and reset)
// Decrease loopCount to stop when required
if (music->loopCount > 0)
{
@ -1475,7 +1475,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
void CloseAudioStream(AudioStream stream)
{
DeleteAudioBuffer((AudioBuffer *)stream.audioBuffer);
TraceLog(LOG_INFO, "[AUD ID %i] Unloaded audio stream data", stream.source);
}
@ -1494,7 +1494,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1])
{
mal_uint32 subBufferToUpdate;
if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1])
{
// Both buffers are available for updating. Update the first one and make sure the cursor is moved back to the front.
@ -1514,7 +1514,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
if (subBufferSizeInFrames >= (mal_uint32)samplesCount/stream.channels)
{
mal_uint32 framesToWrite = subBufferSizeInFrames;
if (framesToWrite > ((mal_uint32)samplesCount/stream.channels)) framesToWrite = (mal_uint32)samplesCount/stream.channels;
mal_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8);
@ -1522,8 +1522,8 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
// Any leftover frames should be filled with zeros.
mal_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite;
if (leftoverFrameCount > 0)
if (leftoverFrameCount > 0)
{
memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8));
}
@ -1723,7 +1723,7 @@ static int SaveWAV(Wave wave, const char *fileName)
{
int success = 0;
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
// Basic WAV headers structs
typedef struct {
char chunkID[4];
@ -1748,7 +1748,7 @@ static int SaveWAV(Wave wave, const char *fileName)
} WaveData;
FILE *wavFile = fopen(fileName, "wb");
if (wavFile == NULL) TraceLog(LOG_WARNING, "[%s] WAV audio file could not be created", fileName);
else
{
@ -1784,7 +1784,7 @@ static int SaveWAV(Wave wave, const char *fileName)
waveData.subChunkID[2] = 't';
waveData.subChunkID[3] = 'a';
waveData.subChunkSize = dataSize;
success = fwrite(&riffHeader, sizeof(RiffHeader), 1, wavFile);
success = fwrite(&waveFormat, sizeof(WaveFormat), 1, wavFile);
success = fwrite(&waveData, sizeof(WaveData), 1, wavFile);
@ -1793,7 +1793,7 @@ static int SaveWAV(Wave wave, const char *fileName)
fclose(wavFile);
}
// If all data has been written correctly to file, success = 1
return success;
}
@ -1812,7 +1812,7 @@ static Wave LoadOGG(const char *fileName)
else
{
stb_vorbis_info info = stb_vorbis_get_info(oggFile);
wave.sampleRate = info.sample_rate;
wave.sampleSize = 16; // 16 bit per sample (short)
wave.channels = info.channels;
@ -1872,7 +1872,7 @@ static Wave LoadMP3(const char *fileName)
uint64_t totalFrameCount = 0;
drmp3_config config = { 0 };
wave.data = drmp3_open_file_and_read_f32(fileName, &config, &totalFrameCount);
wave.channels = config.outputChannels;
wave.sampleRate = config.outputSampleRate;
wave.sampleCount = (int)totalFrameCount*wave.channels;
@ -1895,7 +1895,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
{
bool result = false;
const char *fileExt;
if ((fileExt = strrchr(fileName, '.')) != NULL)
{
if (strcmp(fileExt, ext) == 0) result = true;

View File

@ -45,7 +45,7 @@
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
#define SUPPORT_BUSY_WAIT_LOOP 1
// Wait for events passively (sleeping while no events) instead of polling them actively every frame
//SUPPORT_EVENTS_WAITING 1
//#define SUPPORT_EVENTS_WAITING 1
// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
#define SUPPORT_SCREEN_CAPTURE 1
// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()

View File

@ -2,12 +2,12 @@
*
* 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: Linux (X11 desktop mode)
* - PLATFORM_DESKTOP: FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop)
* - PLATFORM_DESKTOP: OSX/macOS
* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64)
* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64)
* - PLATFORM_RPI: Raspberry Pi 0,1,2,3 (Raspbian)
* - PLATFORM_WEB: HTML5 with asm.js (Chrome, Firefox)
* - PLATFORM_UWP: Windows 10 App, Windows Phone, Xbox One
@ -23,7 +23,7 @@
* NOTE: OpenGL ES 2.0 is required and graphic device is managed by EGL
*
* #define PLATFORM_RPI
* Windowing and input system configured for Raspberry Pi i native mode (no X.org required, tested on Raspbian),
* Windowing and input system configured for Raspberry Pi i native mode (no X.org required, tested on Raspbian),
* graphic device is managed by EGL and inputs are processed is raw mode, reading from /dev/input/
*
* #define PLATFORM_WEB
@ -155,7 +155,7 @@
#if defined(_WIN32)
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h> // WARNING: It requires customization to avoid windows.h inclusion!
#if !defined(SUPPORT_BUSY_WAIT_LOOP)
// NOTE: Those functions require linking with winmm library
unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
@ -164,7 +164,7 @@
#elif defined(__linux__)
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
//#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type
//#define GLFW_EXPOSE_NATIVE_WAYLAND
//#define GLFW_EXPOSE_NATIVE_MIR
@ -172,7 +172,7 @@
#elif defined(__APPLE__)
#include <unistd.h> // Required for: usleep()
#include <objc/message.h> // Required for: objc_msgsend(), sel_registerName()
//#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition
#define GLFW_EXPOSE_NATIVE_NSGL
#include <GLFW/glfw3native.h> // Required for: glfwGetCocoaWindow(), glfwGetNSGLContext()
@ -225,7 +225,7 @@
#define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL)
#include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
#include <emscripten/emscripten.h> // Emscripten library - LLVM to JavaScript compiler
#include <emscripten/html5.h> // Emscripten HTML5 library
#endif
@ -492,7 +492,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread
//----------------------------------------------------------------------------------
#if defined(PLATFORM_ANDROID)
// To allow easier porting to android, we allow the user to define a
// To allow easier porting to android, we allow the user to define a
// main function which we call from android_main, defined by ourselves
extern int main(int argc, char *argv[]);
@ -596,10 +596,10 @@ void InitWindow(int width, int height, const char *title)
#if defined(PLATFORM_WEB)
emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback);
// Support keyboard events
emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
// Support mouse events
emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback);
@ -638,7 +638,7 @@ void CloseWindow(void)
gifRecording = false;
}
#endif
#if defined(SUPPORT_DEFAULT_FONT)
UnloadDefaultFont();
#endif
@ -715,7 +715,7 @@ bool WindowShouldClose(void)
emscripten_sleep(16);
return false;
#endif
#if defined(PLATFORM_DESKTOP)
if (windowReady)
{
@ -766,7 +766,7 @@ void SetWindowIcon(Image image)
ImageFormat(&image, UNCOMPRESSED_R8G8B8A8);
GLFWimage icon[1];
icon[0].width = image.width;
icon[0].height = image.height;
icon[0].pixels = (unsigned char *)image.data;
@ -800,8 +800,8 @@ void SetWindowMonitor(int monitor)
#if defined(PLATFORM_DESKTOP)
int monitorCount;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if ((monitor >= 0) && (monitor < monitorCount))
if ((monitor >= 0) && (monitor < monitorCount))
{
//glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE);
TraceLog(LOG_INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
@ -873,12 +873,12 @@ int GetMonitorCount(void)
// Get primary monitor width
int GetMonitorWidth(int monitor)
{
{
#if defined(PLATFORM_DESKTOP)
int monitorCount;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if ((monitor >= 0) && (monitor < monitorCount))
if ((monitor >= 0) && (monitor < monitorCount))
{
const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
return mode->width;
@ -890,12 +890,12 @@ int GetMonitorWidth(int monitor)
// Get primary monitor width
int GetMonitorHeight(int monitor)
{
{
#if defined(PLATFORM_DESKTOP)
int monitorCount;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if ((monitor >= 0) && (monitor < monitorCount))
if ((monitor >= 0) && (monitor < monitorCount))
{
const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
return mode->height;
@ -911,8 +911,8 @@ int GetMonitorPhysicalWidth(int monitor)
#if defined(PLATFORM_DESKTOP)
int monitorCount;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if ((monitor >= 0) && (monitor < monitorCount))
if ((monitor >= 0) && (monitor < monitorCount))
{
int physicalWidth;
glfwGetMonitorPhysicalSize(monitors[monitor], &physicalWidth, NULL);
@ -929,8 +929,8 @@ int GetMonitorPhysicalHeight(int monitor)
#if defined(PLATFORM_DESKTOP)
int monitorCount;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if ((monitor >= 0) && (monitor < monitorCount))
if ((monitor >= 0) && (monitor < monitorCount))
{
int physicalHeight;
glfwGetMonitorPhysicalSize(monitors[monitor], NULL, &physicalHeight);
@ -944,11 +944,11 @@ int GetMonitorPhysicalHeight(int monitor)
// Get the human-readable, UTF-8 encoded name of the primary monitor
const char *GetMonitorName(int monitor)
{
#if defined(PLATFORM_DESKTOP)
#if defined(PLATFORM_DESKTOP)
int monitorCount;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if ((monitor >= 0) && (monitor < monitorCount))
if ((monitor >= 0) && (monitor < monitorCount))
{
return glfwGetMonitorName(monitors[monitor]);
}
@ -1038,7 +1038,7 @@ void EndDrawing(void)
if (gifRecording)
{
gifFramesCounter++;
// NOTE: We record one gif frame every 10 game frames
if ((gifFramesCounter%GIF_RECORD_FRAMERATE) == 0)
{
@ -1046,20 +1046,20 @@ void EndDrawing(void)
// NOTE: This process is very slow... :(
unsigned char *screenData = rlReadScreenPixels(screenWidth, screenHeight);
GifWriteFrame(screenData, screenWidth, screenHeight, 10, 8, false);
free(screenData); // Free image data
}
if (((gifFramesCounter/15)%2) == 1)
{
DrawCircle(30, screenHeight - 20, 10, RED);
DrawText("RECORDING", 50, screenHeight - 25, 10, MAROON);
}
rlglDraw(); // Draw RECORDING message
}
#endif
SwapBuffers(); // Copy back buffer to front buffer
PollInputEvents(); // Poll user events
@ -1067,7 +1067,7 @@ void EndDrawing(void)
currentTime = GetTime();
drawTime = currentTime - previousTime;
previousTime = currentTime;
frameTime = updateTime + drawTime;
// Wait for some milliseconds...
@ -1113,14 +1113,14 @@ void EndMode2D(void)
void BeginMode3D(Camera3D camera)
{
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection
rlLoadIdentity(); // Reset current matrix (PROJECTION)
float aspect = (float)screenWidth/(float)screenHeight;
if (camera.type == CAMERA_PERSPECTIVE)
if (camera.type == CAMERA_PERSPECTIVE)
{
// Setup perspective projection
double top = 0.01*tan(camera.fovy*0.5*DEG2RAD);
@ -1169,7 +1169,7 @@ void BeginTextureMode(RenderTexture2D target)
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
rlEnableRenderTexture(target.id); // Enable render target
rlClearScreenBuffers(); // Clear render texture buffers
// Set viewport to framebuffer size
@ -1230,7 +1230,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
Matrix matProj = MatrixIdentity();
if (camera.type == CAMERA_PERSPECTIVE)
if (camera.type == CAMERA_PERSPECTIVE)
{
// Calculate projection matrix from perspective
matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0);
@ -1240,7 +1240,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
float aspect = (float)screenWidth/(float)screenHeight;
double top = camera.fovy/2.0;
double right = top*aspect;
// Calculate projection matrix from orthographic
matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0);
}
@ -1250,7 +1250,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
Vector3 farPoint = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
// Unproject the mouse cursor in the near plane.
// We need this as the source position because orthographic projects, compared to perspect doesn't have a
// We need this as the source position because orthographic projects, compared to perspect doesn't have a
// convergence point, meaning that the "eye" of the camera is more like a plane than a point.
Vector3 cameraPlanePointerPos = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView);
@ -1282,7 +1282,7 @@ Vector2 GetWorldToScreen(Vector3 position, Camera camera)
float aspect = (float)screenWidth/(float)screenHeight;
double top = camera.fovy/2.0;
double right = top*aspect;
// Calculate projection matrix from orthographic
matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0);
}
@ -1369,7 +1369,7 @@ Vector4 ColorNormalize(Color color)
result.y = (float)color.g/255.0f;
result.z = (float)color.b/255.0f;
result.w = (float)color.a/255.0f;
return result;
}
@ -1389,27 +1389,27 @@ Vector3 ColorToHSV(Color color)
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)
if (max > 0.0f)
{
// NOTE: If max is 0, this divide would cause a crash
hsv.y = (delta/max); // Saturation
}
else
}
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
@ -1417,7 +1417,7 @@ Vector3 ColorToHSV(Color color)
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;
@ -1519,7 +1519,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
#if defined(_WIN32)
result = true;
int extLen = strlen(ext);
if (strlen(fileExt) == extLen)
{
for (int i = 0; i < extLen; i++)
@ -1544,9 +1544,9 @@ bool IsFileExtension(const char *fileName, const char *ext)
const char *GetExtension(const char *fileName)
{
const char *dot = strrchr(fileName, '.');
if (!dot || dot == fileName) return NULL;
return (dot + 1);
}
@ -1572,19 +1572,19 @@ const char *GetFileName(const char *filePath)
const char *GetFileNameWithoutExt(const char *filePath)
{
char *result, *lastDot, *lastSep;
char nameDot = '.'; // Default filename to extension separator character
char pathSep = '/'; // Default filepath separator character
// Error checks and allocate string
if (filePath == NULL) return NULL;
// Try to allocate new string, same size as original
// NOTE: By default strlen() does not count the '\0' character
if ((result = malloc(strlen(filePath) + 1)) == NULL) return NULL;
strcpy(result, filePath); // Make a copy of the string
// NOTE: strrchr() returns a pointer to the last occurrence of character
lastDot = strrchr(result, nameDot);
lastSep = (pathSep == 0) ? NULL : strrchr(result, pathSep);
@ -1593,11 +1593,11 @@ const char *GetFileNameWithoutExt(const char *filePath)
{
if (lastSep != NULL) // ...and it's before the extenstion separator...
{
if (lastSep < lastDot)
if (lastSep < lastDot)
{
*lastDot = '\0'; // ...then remove it
}
}
}
else *lastDot = '\0'; // Has extension separator with no path separator
}
@ -1626,9 +1626,9 @@ const char *GetWorkingDirectory(void)
{
static char currentDir[MAX_FILEPATH_LENGTH];
memset(currentDir, 0, MAX_FILEPATH_LENGTH);
GETCWD(currentDir, MAX_FILEPATH_LENGTH - 1);
return currentDir;
}
@ -1637,36 +1637,36 @@ const char *GetWorkingDirectory(void)
char **GetDirectoryFiles(const char *dirPath, int *fileCount)
{
#define MAX_DIRECTORY_FILES 512
ClearDirectoryFiles();
// Memory allocation for MAX_DIRECTORY_FILES
dirFilesPath = (char **)malloc(sizeof(char *)*MAX_DIRECTORY_FILES);
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)malloc(sizeof(char)*MAX_FILEPATH_LENGTH);
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)malloc(sizeof(char)*MAX_FILEPATH_LENGTH);
int counter = 0;
struct dirent *ent;
DIR *dir = opendir(dirPath);
if (dir != NULL) // It's a directory
{
// TODO: Reading could be done in two passes,
// TODO: Reading could be done in two passes,
// first one to count files and second one to read names
// That way we can allocate required memory, instead of a limited pool
while ((ent = readdir(dir)) != NULL)
{
strcpy(dirFilesPath[counter], ent->d_name);
counter++;
}
closedir(dir);
}
else TraceLog(LOG_WARNING, "Can not open directory...\n"); // Maybe it's a file...
dirFilesCount = counter;
*fileCount = dirFilesCount;
return dirFilesPath;
}
@ -1729,14 +1729,14 @@ void ClearDroppedFiles(void)
RLAPI long GetFileModTime(const char *fileName)
{
struct stat result = { 0 };
if (stat(fileName, &result) == 0)
{
time_t mod = result.st_mtime;
return (long)mod;
}
return 0;
}
@ -2011,7 +2011,7 @@ bool IsMouseButtonPressed(int button)
#else
if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true;
#endif
return pressed;
}
@ -2259,7 +2259,7 @@ static bool InitGraphicsDevice(int width, int height)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above!
// Other values: GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
// Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
#if defined(__APPLE__)
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // OSX Requires fordward compatibility
#else
@ -2357,10 +2357,10 @@ static bool InitGraphicsDevice(int width, int height)
#endif
glfwMakeContextCurrent(window);
// Try to disable GPU V-Sync by default, set framerate using SetTargetFPS()
// NOTE: V-Sync can be enabled by graphic driver configuration
glfwSwapInterval(0);
glfwSwapInterval(0);
#if defined(PLATFORM_DESKTOP)
// Load OpenGL 3.3 extensions
@ -2372,6 +2372,7 @@ static bool InitGraphicsDevice(int width, int height)
// NOTE: V-Sync can be enabled by graphic driver configuration
if (configFlags & FLAG_VSYNC_HINT)
{
// WARNING: It seems to hits a critical render path in Intel HD Graphics
glfwSwapInterval(1);
TraceLog(LOG_INFO, "Trying to enable VSYNC");
}
@ -2444,14 +2445,14 @@ static bool InitGraphicsDevice(int width, int height)
// 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.
// 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.
@ -2474,7 +2475,7 @@ static bool InitGraphicsDevice(int width, int height)
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.
@ -2486,15 +2487,15 @@ static bool InitGraphicsDevice(int width, int height)
}
//
// To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying
// 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
// 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
// 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)
@ -2502,7 +2503,7 @@ static bool InitGraphicsDevice(int width, int height)
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).
@ -2517,7 +2518,7 @@ static bool InitGraphicsDevice(int width, int height)
{
// 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)
if (display == EGL_NO_DISPLAY)
{
TraceLog(LOG_WARNING, "Failed to initialize EGL display");
return false;
@ -2545,7 +2546,7 @@ static bool InitGraphicsDevice(int width, int height)
//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
// 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.
@ -2557,20 +2558,20 @@ static bool InitGraphicsDevice(int width, int height)
// float customResolutionScale = 0.5f;
// surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(customResolutionScale));
// eglCreateWindowSurface() requires a EGLNativeWindowType parameter,
// 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)
@ -2586,16 +2587,16 @@ static bool InitGraphicsDevice(int width, int height)
return false;
}
// Get EGL display window size
// Get EGL display window size
eglQuerySurface(display, surface, EGL_WIDTH, &screenWidth);
eglQuerySurface(display, surface, EGL_HEIGHT, &screenHeight);
#else // PLATFORM_ANDROID, PLATFORM_RPI
EGLint numConfigs;
// Get an EGL display connection
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY)
if (display == EGL_NO_DISPLAY)
{
TraceLog(LOG_WARNING, "Failed to initialize EGL display");
return false;
@ -2828,7 +2829,7 @@ static void SetupFramebuffer(int width, int height)
static void InitTimer(void)
{
srand((unsigned int)time(NULL)); // Initialize random seed
#if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32)
timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
#endif
@ -2931,7 +2932,7 @@ static void PollInputEvents(void)
// Register previous mouse states
previousMouseWheelY = currentMouseWheelY;
currentMouseWheelY = 0;
for (int i = 0; i < 3; i++)
for (int i = 0; i < 3; i++)
{
previousMouseState[i] = currentMouseState[i];
currentMouseState[i] = currentMouseStateEvdev[i];
@ -3097,11 +3098,11 @@ static void SwapBuffers(void)
glfwSwapBuffers(window);
#if __APPLE__
// Workaround for missing/erroneous initial rendering on macOS
if (windowNeedsUpdating)
if (windowNeedsUpdating)
{
// Desugared version of Objective C: [glfwGetNSGLContext(window) update]
((id (*)(id, SEL))objc_msgSend)(glfwGetNSGLContext(window), sel_registerName("update"));
windowNeedsUpdating--;
}
#endif
@ -3144,19 +3145,19 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
{
GifEnd();
gifRecording = false;
TraceLog(LOG_INFO, "End animated GIF recording");
}
else
else
{
gifRecording = true;
gifFramesCounter = 0;
// NOTE: delay represents the time between frames in the gif, if we capture a gif frame every
// 10 game frames and each frame trakes 16.6ms (60fps), delay between gif frames should be ~16.6*10.
GifBegin(FormatText("screenrec%03i.gif", screenshotCounter), screenWidth, screenHeight, (int)(GetFrameTime()*10.0f), 8, false);
screenshotCounter++;
TraceLog(LOG_INFO, "Begin animated GIF recording: %s", FormatText("screenrec%03i.gif", screenshotCounter));
}
}
@ -3173,7 +3174,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
else
{
currentKeyState[key] = action;
// NOTE: lastKeyPressed already registered on CharCallback()
//if (action == GLFW_PRESS) lastKeyPressed = key;
}
@ -3243,12 +3244,12 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
// GLFW3 Char Key Callback, runs on key down (get unicode char value)
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;
}
@ -3349,7 +3350,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
{
// Init graphics device (display device and OpenGL context)
InitGraphicsDevice(screenWidth, screenHeight);
// Init hi-res timer
InitTimer();
@ -3457,15 +3458,15 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
// Get second touch position
touchPosition[1].x = AMotionEvent_getX(event, 1);
touchPosition[1].y = AMotionEvent_getY(event, 1);
// Useful functions for gamepad inputs:
//AMotionEvent_getAction()
//AMotionEvent_getAxisValue()
//AMotionEvent_getButtonState()
// Gamepad dpad button presses capturing
// TODO: That's weird, key input (or button)
// shouldn't come as a TYPE_MOTION event...
// shouldn't come as a TYPE_MOTION event...
int32_t keycode = AKeyEvent_getKeyCode(event);
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
{
@ -3541,7 +3542,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
// Normalize gestureEvent.position[x] for screenWidth and screenHeight
gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight();
gestureEvent.position[1].x /= (float)GetScreenWidth();
gestureEvent.position[1].y /= (float)GetScreenHeight();
@ -3549,14 +3550,14 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
ProcessGestureEvent(gestureEvent);
}
#else
// Support only simple touch position
if (flags == AMOTION_EVENT_ACTION_DOWN)
{
// Get first touch position
touchPosition[0].x = AMotionEvent_getX(event, 0);
touchPosition[0].y = AMotionEvent_getY(event, 0);
touchPosition[0].x /= (float)GetScreenWidth();
touchPosition[0].y /= (float)GetScreenHeight();
}
@ -3619,10 +3620,10 @@ static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent
emscripten_get_pointerlock_status(&plce);
//if (plce.isActive) TraceLog(LOG_WARNING, "Pointer lock exit did not work!");
}
toggleCursorLock = false;
}
return 0;
}
@ -3889,9 +3890,9 @@ static void InitMouse(void)
// Open the linux directory of "/dev/input"
directory = opendir(DEFAULT_EVDEV_PATH);
if (directory)
if (directory)
{
while ((entity = readdir(directory)) != NULL)
while ((entity = readdir(directory)) != NULL)
{
if (strncmp("event", entity->d_name, strlen("event")) == 0) // Search for devices named "event*"
{
@ -3899,7 +3900,7 @@ static void InitMouse(void)
EventThreadSpawn(Path); // Identify the device and spawn a thread for it
}
}
closedir(directory);
}
else
@ -3916,7 +3917,7 @@ static void EventThreadSpawn(char *device)
#define BIT(x) (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
struct input_absinfo absinfo;
unsigned long evBits[NBITS(EV_MAX)];
unsigned long absBits[NBITS(ABS_MAX)];
@ -3927,7 +3928,7 @@ static void EventThreadSpawn(char *device)
bool hasAbsMulti = false;
int freeWorkerId = -1;
int fd = -1;
InputEventWorker *worker;
/////////////////////////////////// Open the device and allocate worker /////////////////////////////////////////////
@ -3967,15 +3968,15 @@ static void EventThreadSpawn(char *device)
int devNum = 0;
char *ptrDevName = strrchr(device, 't');
worker->eventNum = -1;
if (ptrDevName != NULL)
{
if (sscanf(ptrDevName, "t%d", &devNum) == 1)
worker->eventNum = devNum;
}
// At this point we have a connection to the device,
// but we don't yet know what the device is (Could be
// At this point we have a connection to the device,
// but we don't yet know what the device is (Could be
// many things, even as simple as a power button)
/////////////////////////////////// Identify the device /////////////////////////////////////////////
@ -3983,15 +3984,15 @@ static void EventThreadSpawn(char *device)
ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits); // Read a bitfield of the avalable device properties
// Check for absolute input devices
if (TEST_BIT(evBits, EV_ABS))
if (TEST_BIT(evBits, EV_ABS))
{
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits);
// Check for absolute movement support (usualy touchscreens, but also joysticks)
if (TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y))
if (TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y))
{
hasAbs = true;
// Get the scaling values
ioctl(fd, EVIOCGABS(ABS_X), &absinfo);
worker->absRange.x = absinfo.minimum;
@ -4000,12 +4001,12 @@ static void EventThreadSpawn(char *device)
worker->absRange.y = absinfo.minimum;
worker->absRange.height = absinfo.maximum - absinfo.minimum;
}
// Check for multiple absolute movement support (usualy multitouch touchscreens)
if (TEST_BIT(absBits, ABS_MT_POSITION_X) && TEST_BIT(absBits, ABS_MT_POSITION_Y))
if (TEST_BIT(absBits, ABS_MT_POSITION_X) && TEST_BIT(absBits, ABS_MT_POSITION_Y))
{
hasAbsMulti = true;
// Get the scaling values
ioctl(fd, EVIOCGABS(ABS_X), &absinfo);
worker->absRange.x = absinfo.minimum;
@ -4017,15 +4018,15 @@ static void EventThreadSpawn(char *device)
}
// Check for relative movement support (usualy mouse)
if (TEST_BIT(evBits, EV_REL))
if (TEST_BIT(evBits, EV_REL))
{
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits);
if (TEST_BIT(relBits, REL_X) && TEST_BIT(relBits, REL_Y)) hasRel = true;
}
// Check for button support to determine the device type(usualy on all input devices)
if (TEST_BIT(evBits, EV_KEY))
if (TEST_BIT(evBits, EV_KEY))
{
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits);
@ -4077,12 +4078,12 @@ static void EventThreadSpawn(char *device)
#if defined(USE_LAST_TOUCH_DEVICE)
// Find touchscreen with the highest index
int maxTouchNumber = -1;
for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i)
{
if (eventWorkers[i].isTouch && (eventWorkers[i].eventNum > maxTouchNumber)) maxTouchNumber = eventWorkers[i].eventNum;
}
// Find toucnscreens with lower indexes
for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i)
{
@ -4134,7 +4135,7 @@ static void *EventThread(void *arg)
if (event.code == REL_WHEEL)
{
currentMouseWheelY += event.value;
}
}
}
/////////////////////////////// Absolute movement parsing ////////////////////////////////////
@ -4231,9 +4232,9 @@ static void *EventThread(void *arg)
usleep(5000); // Sleep for 5ms to avoid hogging CPU time
}
}
close(worker->fd);
return NULL;
}

View File

@ -511,7 +511,7 @@ typedef struct Mesh {
float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// Vertex indices (in case vertex data comes indexed)
// Animation vertex data
float *baseVertices; // Vertex base position (required to apply bones transformations)
float *baseNormals; // Vertex base normals (required to apply bones transformations)

View File

@ -199,7 +199,7 @@ typedef unsigned char byte;
float *tangents; // vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// vertex indices (in case vertex data comes indexed)
// Animation vertex data
float *baseVertices; // Vertex base position (required to apply bones transformations)
float *baseNormals; // Vertex base normals (required to apply bones transformations)
@ -729,7 +729,7 @@ typedef struct VrStereoConfig {
//----------------------------------------------------------------------------------
#if !defined(GRAPHICS_API_OPENGL_11) && defined(SUPPORT_DISTORTION_SHADER)
// Distortion shader embedded
static char distortionFShaderStr[] =
static char distortionFShaderStr[] =
#if defined(GRAPHICS_API_OPENGL_21)
"#version 120 \n"
#elif defined(GRAPHICS_API_OPENGL_ES2)
@ -1217,9 +1217,9 @@ void rlEnd(void)
// WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlglDraw(),
// we need to call rlPopMatrix() before to recover *currentMatrix (modelview) for the next forced draw call!
// Also noted that if we had multiple matrix pushed, it will require "stackCounter" pops before launching the draw
// TODO: Undoubtely, current rlPushMatrix/rlPopMatrix should be redesigned... or removed... it's not working properly
rlPopMatrix();
rlglDraw();
}
@ -1507,7 +1507,7 @@ void rlDeleteRenderTextures(RenderTexture2D target)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id);
if (target.depth.id > 0)
if (target.depth.id > 0)
{
#if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
glDeleteRenderbuffers(1, &target.depth.id);
@ -1640,7 +1640,7 @@ void rlglInit(int width, int height)
char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big const string
// NOTE: We have to duplicate string because glGetString() returns a const string
int len = strlen(extensions) + 1;
int len = strlen(extensions) + 1;
char *extensionsDup = (char *)malloc(len);
strcpy(extensionsDup, extensions);
@ -2260,7 +2260,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height)
}
if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id);
if (target.depth.id > 0)
if (target.depth.id > 0)
{
#if defined(USE_DEPTH_RENDERBUFFER)
glDeleteRenderbuffers(1, &target.depth.id);
@ -2268,7 +2268,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height)
glDeleteTextures(1, &target.depth.id);
#endif
}
glDeleteFramebuffers(1, &target.id);
}
else TraceLog(LOG_INFO, "[FBO ID %i] Framebuffer object created successfully", target.id);
@ -2736,7 +2736,7 @@ void rlUnloadMesh(Mesh *mesh)
if (mesh->tangents != NULL) free(mesh->tangents);
if (mesh->texcoords2 != NULL) free(mesh->texcoords2);
if (mesh->indices != NULL) free(mesh->indices);
if (mesh->baseVertices != NULL) free(mesh->baseVertices);
if (mesh->baseNormals != NULL) free(mesh->baseNormals);
if (mesh->weightBias != NULL) free(mesh->weightBias);

View File

@ -9,7 +9,7 @@
* Allows drawing rectangles and text with a single draw call, very useful for GUI systems!
*
* #define SUPPORT_QUADS_DRAW_MODE
* Use QUADS instead of TRIANGLES for drawing when possible.
* Use QUADS instead of TRIANGLES for drawing when possible.
* Some lines-based shapes could still use lines
*
* LICENSE: zlib/libpng
@ -116,13 +116,13 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
startPos = endPos;
endPos = tempPos;
}
float dx = endPos.x - startPos.x;
float dy = endPos.y - startPos.y;
float d = sqrtf(dx*dx + dy*dy);
float angle = asinf(dy/d);
rlEnableTexture(GetShapesTexture().id);
rlPushMatrix();
@ -155,12 +155,12 @@ void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
for (int i = 1; i <= LINE_DIVISIONS; i++)
{
// Cubic easing in-out
// NOTE: Easing is calculated only for y position value
// NOTE: Easing is calculated only for y position value
current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)LINE_DIVISIONS);
current.x = previous.x + (endPos.x - startPos.x)/ (float)LINE_DIVISIONS;
DrawLineEx(previous, current, thick, color);
previous = current;
}
}
@ -176,7 +176,7 @@ void DrawCircle(int centerX, int centerY, float radius, Color color)
void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)
{
if (rlCheckBufferLimit(RL_TRIANGLES, 3*36)) rlglDraw();
rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 10)
{
@ -193,31 +193,31 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co
// Draw a color-filled circle (Vector version)
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawCircleV(Vector2 center, float radius, Color color)
{
{
#if defined(SUPPORT_QUADS_DRAW_MODE)
if (rlCheckBufferLimit(RL_QUADS, 4*(36/2))) rlglDraw();
rlEnableTexture(GetShapesTexture().id);
rlBegin(RL_QUADS);
for (int i = 0; i < 360; i += 20)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(center.x, center.y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(i + 20))*radius, center.y + cosf(DEG2RAD*(i + 20))*radius);
}
rlEnd();
rlDisableTexture();
#else
if (rlCheckBufferLimit(RL_TRIANGLES, 3*(36/2))) rlglDraw();
@ -226,7 +226,7 @@ void DrawCircleV(Vector2 center, float radius, Color color)
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius);
@ -239,7 +239,7 @@ void DrawCircleV(Vector2 center, float radius, Color color)
void DrawCircleLines(int centerX, int centerY, float radius, Color color)
{
if (rlCheckBufferLimit(RL_LINES, 2*36)) rlglDraw();
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
@ -263,7 +263,7 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color)
void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{
Color colors[4] = { color, color, color, color };
DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, colors);
}
@ -271,7 +271,7 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
void DrawRectangleRec(Rectangle rec, Color color)
{
Color colors[4] = { color, color, color, color };
DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, colors);
}
@ -292,15 +292,15 @@ void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color
rlColor4ub(colors[0].r, colors[0].g, colors[0].b, colors[0].a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(rec.x, rec.y);
rlColor4ub(colors[1].r, colors[1].g, colors[1].b, colors[1].a);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(rec.x, rec.y + rec.height);
rlColor4ub(colors[2].r, colors[2].g, colors[2].b, colors[2].a);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
rlColor4ub(colors[3].r, colors[3].g, colors[3].b, colors[3].a);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(rec.x + rec.width, rec.y);
@ -329,14 +329,14 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color col
void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)
{
Color colors[4] = { col1, col2, col3, col4 };
DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, colors);
}
// Draw rectangle outline
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
{
{
#if defined(SUPPORT_QUADS_DRAW_MODE)
DrawRectangle(posX, posY, width, 1, color);
DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
@ -362,13 +362,13 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
// Draw rectangle outline with extended parameters
void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color)
{
{
if (lineThick > rec.width || lineThick > rec.height)
{
if(rec.width > rec.height) lineThick = (int)rec.height/2;
else if (rec.width < rec.height) lineThick = (int)rec.width/2;
}
}
DrawRectangle( (int)rec.x, (int)rec.y, (int)rec.width, lineThick, color);
DrawRectangle( (int)(rec.x - lineThick + rec.width), (int)(rec.y + lineThick), lineThick, (int)(rec.height - lineThick*2.0f), color);
DrawRectangle( (int)rec.x, (int)(rec.y + rec.height - lineThick), (int)rec.width, lineThick, color);
@ -383,20 +383,20 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(v1.x, v1.y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(v2.x, v2.y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(v2.x, v2.y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(v3.x, v3.y);
rlEnd();
rlDisableTexture();
#else
rlBegin(RL_TRIANGLES);
@ -428,13 +428,13 @@ void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
{
if (sides < 3) sides = 3;
if (rlCheckBufferLimit(RL_QUADS, 4*(360/sides))) rlglDraw();
rlPushMatrix();
rlTranslatef(center.x, center.y, 0.0);
rlRotatef(rotation, 0, 0, 1);
#if defined(SUPPORT_QUADS_DRAW_MODE)
rlEnableTexture(GetShapesTexture().id);
@ -445,13 +445,13 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(0, 0);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius);
}
@ -478,7 +478,7 @@ void DrawPolyEx(Vector2 *points, int pointsCount, Color color)
if (pointsCount >= 3)
{
if (rlCheckBufferLimit(RL_QUADS, pointsCount)) rlglDraw();
#if defined(SUPPORT_QUADS_DRAW_MODE)
rlEnableTexture(GetShapesTexture().id);
@ -577,7 +577,7 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2
bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
{
bool collision = false;
if ((rec1.x <= (rec2.x + rec2.width) && (rec1.x + rec1.width) >= rec2.x) &&
(rec1.y <= (rec2.y + rec2.height) && (rec1.y + rec1.height) >= rec2.y)) collision = true;
@ -605,7 +605,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
{
int recCenterX = (int)(rec.x + rec.width/2.0f);
int recCenterY = (int)(rec.y + rec.height/2.0f);
float dx = (float)fabs(center.x - recCenterX);
float dy = (float)fabs(center.y - recCenterY);
@ -615,7 +615,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
if (dx <= (rec.width/2.0f)) { return true; }
if (dy <= (rec.height/2.0f)) { return true; }
float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
(dy - rec.height/2.0f)*(dy - rec.height/2.0f);
return (cornerDistanceSq <= (radius*radius));
@ -674,7 +674,7 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
{
if (retRec.width >= rec1.width) retRec.width = rec1.width;
}
if (rec1.height > rec2.height)
{
if (retRec.height >= rec2.height) retRec.height = rec2.height;
@ -692,10 +692,10 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
// Module specific Functions Definition
//----------------------------------------------------------------------------------
// Cubic easing in-out
// Cubic easing in-out
// NOTE: Required for DrawLineBezier()
static float EaseCubicInOut(float t, float b, float c, float d)
{
static float EaseCubicInOut(float t, float b, float c, float d)
{
if ((t /= 0.5f*d) < 1)
return 0.5f*c*t*t*t + b;
t -= 2;
@ -715,6 +715,6 @@ static Texture2D GetShapesTexture(void)
recTexShapes = { 0.0f, 0.0f, 1.0f, 1.0f };
#endif
}
return texShapes;
}

View File

@ -200,10 +200,10 @@ extern void LoadDefaultFont(void)
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
//------------------------------------------------------------------------------
// Allocate space for our characters info data
// NOTE: This memory should be freed at end! --> CloseWindow()
defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo));
defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo));
int currentLine = 0;
int currentPosX = charsDivisor;
@ -238,7 +238,7 @@ extern void LoadDefaultFont(void)
}
defaultFont.baseSize = (int)defaultFont.chars[0].rec.height;
TraceLog(LOG_INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
}
@ -258,7 +258,7 @@ Font GetFontDefault()
#else
Font font = { 0 };
return font;
#endif
#endif
}
// Load Font from file into GPU memory (VRAM)
@ -301,11 +301,11 @@ Font LoadFont(const char *fileName)
Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars)
{
Font font = { 0 };
font.baseSize = fontSize;
font.charsCount = (charsCount > 0) ? charsCount : 95;
font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT);
if (font.chars != NULL)
{
Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 2, 0);
@ -313,7 +313,7 @@ Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontCha
UnloadImage(atlas);
}
else font = GetFontDefault();
return font;
}
@ -326,7 +326,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
#define SDF_CHAR_PADDING 4
#define SDF_ON_EDGE_VALUE 128
#define SDF_PIXEL_DIST_SCALE 64.0f
#define BITMAP_ALPHA_THRESHOLD 80
CharInfo *chars = NULL;
@ -335,15 +335,15 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
// NOTE: Loaded information should be enough to generate font image atlas,
// using any packaging method
FILE *fontFile = fopen(fileName, "rb"); // Load font file
if (fontFile != NULL)
{
fseek(fontFile, 0, SEEK_END);
long size = ftell(fontFile); // Get file size
fseek(fontFile, 0, SEEK_SET); // Reset file pointer
unsigned char *fontBuffer = (unsigned char *)malloc(size);
fread(fontBuffer, size, 1, fontFile);
fclose(fontFile);
@ -358,10 +358,10 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
// NOTE: ascent is equivalent to font baseline
int ascent, descent, lineGap;
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
// In case no chars count provided, default to 95
charsCount = (charsCount > 0) ? charsCount : 95;
// Fill fontChars in case not provided externally
// NOTE: By default we fill charsCount consecutevely, starting at 32 (Space)
int genFontChars = false;
@ -373,22 +373,22 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
}
chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo));
// NOTE: Using simple packaging, one char after another
for (int i = 0; i < charsCount; i++)
for (int i = 0; i < charsCount; i++)
{
int chw = 0, chh = 0; // Character width and height (on generation)
int ch = fontChars[i]; // Character value to get info for
chars[i].value = ch;
// Render a unicode codepoint to a bitmap
// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
if (type != FONT_SDF) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else if (ch != 32) chars[i].data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
if (type == FONT_BITMAP)
{
// Aliased bitmap (black & white) font generation, avoiding anti-aliasing
@ -399,15 +399,15 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
else chars[i].data[p] = 255;
}
}
chars[i].rec.width = (float)chw;
chars[i].rec.height = (float)chh;
chars[i].offsetY += (int)((float)ascent*scaleFactor);
// Get bounding box for character (may be offset to account for chars that dip above or below the line)
int chX1, chY1, chX2, chY2;
stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);
TraceLog(LOG_DEBUG, "Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1);
TraceLog(LOG_DEBUG, "Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1);
@ -419,7 +419,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
if (genFontChars) free(fontChars);
}
else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName);
return chars;
}
@ -428,25 +428,25 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod)
{
Image atlas = { 0 };
// In case no chars count provided we suppose default of 95
charsCount = (charsCount > 0) ? charsCount : 95;
// Calculate image size based on required pixel area
// NOTE 1: Image is forced to be squared and POT... very conservative!
// NOTE 2: SDF font characters already contain an internal padding,
// NOTE 2: SDF font characters already contain an internal padding,
// so image size would result bigger than default font type
float requiredArea = 0;
for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].rec.width + 2*padding)*(chars[i].rec.height + 2*padding));
float guessSize = sqrtf(requiredArea)*1.25f;
int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT
atlas.width = imageSize; // Atlas bitmap width
atlas.height = imageSize; // Atlas bitmap height
atlas.data = (unsigned char *)calloc(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp)
atlas.format = UNCOMPRESSED_GRAYSCALE;
atlas.mipmaps = 1;
// DEBUG: We can see padding in the generated image setting a gray background...
//for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100;
@ -454,9 +454,9 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi
{
int offsetX = padding;
int offsetY = padding;
// NOTE: Using simple packaging, one char after another
for (int i = 0; i < charsCount; i++)
for (int i = 0; i < charsCount; i++)
{
// Copy pixel data from fc.data to atlas
for (int y = 0; y < (int)chars[i].rec.height; y++)
@ -466,22 +466,22 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi
((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = chars[i].data[y*(int)chars[i].rec.width + x];
}
}
chars[i].rec.x = (float)offsetX;
chars[i].rec.y = (float)offsetY;
// Move atlas position X for next character drawing
offsetX += ((int)chars[i].rec.width + 2*padding);
if (offsetX >= (atlas.width - (int)chars[i].rec.width - padding))
{
offsetX = padding;
// NOTE: Be careful on offsetY for SDF fonts, by default SDF
// NOTE: Be careful on offsetY for SDF fonts, by default SDF
// use an internal padding of 4 pixels, it means char rectangle
// height is bigger than fontSize, it could be up to (fontSize + 8)
offsetY += (fontSize + 2*padding);
if (offsetY > (atlas.height - fontSize - padding)) break;
}
}
@ -489,13 +489,13 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi
else if (packMethod == 1) // Use Skyline rect packing algorythm (stb_pack_rect)
{
TraceLog(LOG_DEBUG, "Using Skyline packing algorythm!");
stbrp_context *context = (stbrp_context *)malloc(sizeof(*context));
stbrp_node *nodes = (stbrp_node *)malloc(charsCount*sizeof(*nodes));
stbrp_init_target(context, atlas.width, atlas.height, nodes, charsCount);
stbrp_rect *rects = (stbrp_rect *)malloc(charsCount*sizeof(stbrp_rect));
// Fill rectangles for packaging
for (int i = 0; i < charsCount; i++)
{
@ -506,12 +506,12 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi
// Package rectangles into atlas
stbrp_pack_rects(context, rects, charsCount);
for (int i = 0; i < charsCount; i++)
{
chars[i].rec.x = rects[i].x + (float)padding;
chars[i].rec.y = rects[i].y + (float)padding;
if (rects[i].was_packed)
{
// Copy pixel data from fc.data to atlas
@ -530,9 +530,9 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi
free(nodes);
free(context);
}
// TODO: Crop image if required for smaller size
// Convert image data from GRAYSCALE to GRAY_ALPHA
// WARNING: ImageAlphaMask(&atlas, atlas) does not work in this case, requires manual operation
unsigned char *dataGrayAlpha = (unsigned char *)malloc(imageSize*imageSize*sizeof(unsigned char)*2); // Two channels
@ -546,7 +546,7 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi
free(atlas.data);
atlas.data = dataGrayAlpha;
atlas.format = UNCOMPRESSED_GRAY_ALPHA;
return atlas;
}
@ -580,7 +580,7 @@ void DrawFPS(int posX, int posY)
refreshRate = fps;
counter = 0;
}
// NOTE: We have rounding errors every frame, so it oscillates a lot
DrawText(FormatText("%2i FPS", fps), posX, posY, 20, LIME);
}
@ -645,7 +645,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
i++;
}
else index = GetGlyphIndex(font, (unsigned char)text[i]);
if ((unsigned char)text[i] != ' ')
{
DrawTexturePro(font.texture, font.chars[index].rec,
@ -795,27 +795,27 @@ char **SplitText(char *text, char delimiter, int *strCount)
char *strDup = (char *)malloc(len + 1);
strcpy(strDup, text);
int counter = 1;
// Count how many substrings we have on string
for (int i = 0; i < len; i++) if (text[i] == delimiter) counter++;
// Memory allocation for substrings
strings = (char **)malloc(sizeof(char *)*counter);
for (int i = 0; i < counter; i++) strings[i] = (char *)malloc(sizeof(char)*MAX_SUBSTRING_LENGTH);
char *substrPtr = NULL;
char delimiters[1] = { delimiter }; // Only caring for one delimiter
substrPtr = strtok(strDup, delimiters);
for (int i = 0; (i < counter) && (substrPtr != NULL); i++)
{
strcpy(strings[i], substrPtr);
substrPtr = strtok(NULL, delimiters);
}
*strCount = counter;
free(strDup);
return strings;
}
@ -823,9 +823,9 @@ char **SplitText(char *text, char delimiter, int *strCount)
bool IsEqualText(const char *text1, const char *text2)
{
bool result = false;
if (strcmp(text1, text2) == 0) result = true;
return result;
}
@ -861,7 +861,7 @@ static Font LoadImageFont(Image image, Color key, int firstChar)
{
if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
}
if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
}
@ -1031,10 +1031,10 @@ static Font LoadBMFont(const char *fileName)
UnloadImage(imCopy);
}
else font.texture = LoadTextureFromImage(imFont);
UnloadImage(imFont);
free(texPath);
// Fill font characters info data
font.baseSize = fontSize;

View File

@ -424,7 +424,7 @@ Color *GetImageData(Image image)
if ((image.format == UNCOMPRESSED_R32) ||
(image.format == UNCOMPRESSED_R32G32B32) ||
(image.format == UNCOMPRESSED_R32G32B32A32)) TraceLog(LOG_WARNING, "32bit pixel format converted to 8bit per channel");
for (int i = 0, k = 0; i < image.width*image.height; i++)
{
switch (image.format)
@ -500,7 +500,7 @@ Color *GetImageData(Image image)
pixels[i].g = 0;
pixels[i].b = 0;
pixels[i].a = 255;
} break;
case UNCOMPRESSED_R32G32B32:
{
@ -508,7 +508,7 @@ Color *GetImageData(Image image)
pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f);
pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f);
pixels[i].a = 255;
k += 3;
}
case UNCOMPRESSED_R32G32B32A32:
@ -517,7 +517,7 @@ Color *GetImageData(Image image)
pixels[i].g = (unsigned char)(((float *)image.data)[k]*255.0f);
pixels[i].b = (unsigned char)(((float *)image.data)[k]*255.0f);
pixels[i].a = (unsigned char)(((float *)image.data)[k]*255.0f);
k += 4;
}
default: break;
@ -532,7 +532,7 @@ Color *GetImageData(Image image)
Vector4 *GetImageDataNormalized(Image image)
{
Vector4 *pixels = (Vector4 *)malloc(image.width*image.height*sizeof(Vector4));
if (image.format >= COMPRESSED_DXT1_RGB) TraceLog(LOG_WARNING, "Pixel data retrieval not supported for compressed image formats");
else
{
@ -611,7 +611,7 @@ Vector4 *GetImageDataNormalized(Image image)
pixels[i].y = 0.0f;
pixels[i].z = 0.0f;
pixels[i].w = 1.0f;
} break;
case UNCOMPRESSED_R32G32B32:
{
@ -619,7 +619,7 @@ Vector4 *GetImageDataNormalized(Image image)
pixels[i].y = ((float *)image.data)[k + 1];
pixels[i].z = ((float *)image.data)[k + 2];
pixels[i].w = 1.0f;
k += 3;
}
case UNCOMPRESSED_R32G32B32A32:
@ -628,14 +628,14 @@ Vector4 *GetImageDataNormalized(Image image)
pixels[i].y = ((float *)image.data)[k + 1];
pixels[i].z = ((float *)image.data)[k + 2];
pixels[i].w = ((float *)image.data)[k + 3];
k += 4;
}
default: break;
}
}
}
return pixels;
}
@ -720,16 +720,16 @@ void UpdateTexture(Texture2D texture, const void *pixels)
void ExportImage(Image image, const char *fileName)
{
int success = 0;
// NOTE: Getting Color array as RGBA unsigned char values
unsigned char *imgData = (unsigned char *)GetImageData(image);
if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, 4, imgData, image.width*4);
else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, 4, imgData);
else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, 4, imgData);
else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, 4, imgData, 80); // JPG quality: between 1 and 100
else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName);
else if (IsFileExtension(fileName, ".raw"))
else if (IsFileExtension(fileName, ".raw"))
{
// Export raw pixel data (without header)
// NOTE: It's up to the user to track image parameters
@ -740,7 +740,7 @@ void ExportImage(Image image, const char *fileName)
if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName);
else TraceLog(LOG_WARNING, "Image could not be exported.");
free(imgData);
}
@ -748,10 +748,10 @@ void ExportImage(Image image, const char *fileName)
void ExportImageAsCode(Image image, const char *fileName)
{
#define BYTES_TEXT_PER_LINE 20
char varFileName[256] = { 0 };
int dataSize = GetPixelDataSize(image.width, image.height, image.format);
FILE *txtFile = fopen(fileName, "wt");
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////////\n");
@ -764,11 +764,11 @@ void ExportImageAsCode(Image image, const char *fileName)
fprintf(txtFile, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
// Get file name from path and convert variable name to uppercase
strcpy(varFileName, GetFileNameWithoutExt(fileName));
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
// Add image information
fprintf(txtFile, "// Image data information\n");
fprintf(txtFile, "#define %s_WIDTH %i\n", varFileName, image.width);
@ -987,7 +987,7 @@ void ImageFormat(Image *image, int newFormat)
case UNCOMPRESSED_R32:
{
// WARNING: Image is converted to GRAYSCALE eqeuivalent 32bit
image->data = (float *)malloc(image->width*image->height*sizeof(float));
for (int i = 0; i < image->width*image->height; i++)
@ -1023,7 +1023,7 @@ void ImageFormat(Image *image, int newFormat)
free(pixels);
pixels = NULL;
// 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)
@ -1087,14 +1087,14 @@ void ImageAlphaMask(Image *image, Image alphaMask)
void ImageAlphaClear(Image *image, Color color, float threshold)
{
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;
UnloadImage(*image);
int prevFormat = image->format;
*image = LoadImageEx(pixels, image->width, image->height);
ImageFormat(image, prevFormat);
}
@ -1102,13 +1102,13 @@ void ImageAlphaClear(Image *image, Color color, float threshold)
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++)
for (int i = 0; i < image->width*image->height; i++)
{
if (pixels[i].a > (unsigned char)(threshold*255.0f))
{
@ -1127,18 +1127,18 @@ void ImageAlphaCrop(Image *image, float threshold)
else if (crop.height < (float)miny) crop.height = (float)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) &&
if ((crop.x != 1) &&
(crop.y != 1) &&
(crop.width != image->width - 1) &&
(crop.height != image->height - 1)) ImageCrop(image, crop);
}
@ -1148,8 +1148,8 @@ void ImageAlphaPremultiply(Image *image)
{
float alpha = 0.0f;
Color *pixels = GetImageData(*image);
for (int i = 0; i < image->width*image->height; i++)
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);
@ -1158,10 +1158,10 @@ void ImageAlphaPremultiply(Image *image)
}
UnloadImage(*image);
int prevFormat = image->format;
*image = LoadImageEx(pixels, image->width, image->height);
ImageFormat(image, prevFormat);
}
@ -1282,9 +1282,9 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in
Image imTemp = GenImageColor(newWidth, newHeight, color);
Rectangle srcRec = { 0.0f, 0.0f, (float)image->width, (float)image->height };
Rectangle dstRec = { (float)offsetX, (float)offsetY, (float)srcRec.width, (float)srcRec.height };
// TODO: Review different scaling situations
if ((newWidth > image->width) && (newHeight > image->height))
{
ImageDraw(&imTemp, *image, srcRec, dstRec);
@ -1314,7 +1314,7 @@ void ImageMipmaps(Image *image)
{
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;
@ -1332,8 +1332,8 @@ void ImageMipmaps(Image *image)
if (image->mipmaps < mipCount)
{
void *temp = realloc(image->data, mipSize);
if (temp != NULL)
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);
@ -1342,29 +1342,29 @@ void ImageMipmaps(Image *image)
// 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);
}
@ -1487,10 +1487,10 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount)
{
#define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
Color *pixels = GetImageData(image);
Color *palette = (Color *)malloc(maxPaletteSize*sizeof(Color));
int palCount = 0;
for (int i = 0; i < maxPaletteSize; i++) palette[i] = BLANK; // Set all colors to BLANK
@ -1499,23 +1499,23 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount)
if (pixels[i].a > 0)
{
bool colorInPalette = false;
// Check if the color is already on palette
for (int j = 0; j < maxPaletteSize; j++)
{
if (COLOR_EQUAL(pixels[i], palette[j]))
if (COLOR_EQUAL(pixels[i], palette[j]))
{
colorInPalette = true;
break;
}
}
// Store color if not on the palette
if (!colorInPalette)
{
palette[palCount] = pixels[i]; // Add pixels[i] to palette
palCount++;
// We reached the limit of colors supported by palette
if (palCount >= maxPaletteSize)
{
@ -1527,9 +1527,9 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount)
}
free(pixels);
*extractCount = palCount;
return palette;
}
@ -1595,7 +1595,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
UnloadImage(srcCopy); // Source copy not required any more...
Vector4 fsrc, fdst, fout; // float based versions of pixel data
// Blit pixels, copy source image into destination
// TODO: Probably out-of-bounds blitting could be considered here instead of so much cropping...
for (int j = (int)dstRec.y; j < (int)(dstRec.y + dstRec.height); j++)
@ -1603,12 +1603,12 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
for (int i = (int)dstRec.x; i < (int)(dstRec.x + dstRec.width); i++)
{
// Alpha blending (https://en.wikipedia.org/wiki/Alpha_compositing)
fdst = ColorNormalize(dstPixels[j*(int)dst->width + i]);
fsrc = ColorNormalize(srcPixels[(j - (int)dstRec.y)*(int)dstRec.width + (i - (int)dstRec.x)]);
fout.w = fsrc.w + fdst.w*(1.0f - fsrc.w);
if (fout.w <= 0.0f)
{
fout.x = 0.0f;
@ -1622,9 +1622,9 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w;
}
dstPixels[j*(int)dst->width + i] = (Color){ (unsigned char)(fout.x*255.0f),
(unsigned char)(fout.y*255.0f),
(unsigned char)(fout.z*255.0f),
dstPixels[j*(int)dst->width + i] = (Color){ (unsigned char)(fout.x*255.0f),
(unsigned char)(fout.y*255.0f),
(unsigned char)(fout.z*255.0f),
(unsigned char)(fout.w*255.0f) };
// TODO: Support other blending options
@ -1662,16 +1662,16 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
// TODO: ISSUE: Measured text size does not seem to be correct... issue on ImageDraw()
Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing);
TraceLog(LOG_DEBUG, "Text Image size: %f, %f", imSize.x, imSize.y);
// NOTE: glGetTexImage() not available in OpenGL ES
// TODO: This is horrible, retrieving font texture from GPU!!!
// TODO: This is horrible, retrieving font texture from GPU!!!
// Define ImageFont struct? or include Image spritefont in Font struct?
Image imFont = GetTextureData(font.texture);
ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Make sure image format could be properly colored!
ImageColorTint(&imFont, tint); // Apply color tint to font
// Create image to store text
@ -1702,10 +1702,10 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
else index = GetGlyphIndex(font, (unsigned char)text[i]);
CharInfo letter = font.chars[index];
if ((unsigned char)text[i] != ' ')
{
ImageDraw(&imText, imFont, letter.rec, (Rectangle){ (float)(posX + letter.offsetX),
ImageDraw(&imText, imFont, letter.rec, (Rectangle){ (float)(posX + letter.offsetX),
(float)letter.offsetY, (float)letter.rec.width, (float)letter.rec.height });
}
@ -1734,11 +1734,11 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
void ImageDrawRectangle(Image *dst, Vector2 position, Rectangle rec, Color color)
{
Image imRec = GenImageColor((int)rec.width, (int)rec.height, color);
Rectangle dstRec = { position.x, position.y, (float)imRec.width, (float)imRec.height };
ImageDraw(dst, imRec, rec, dstRec);
UnloadImage(imRec);
}
@ -2056,13 +2056,13 @@ void ImageColorReplace(Image *image, Color color, Color replace)
Image GenImageColor(int width, int height, Color color)
{
Color *pixels = (Color *)calloc(width*height, sizeof(Color));
for (int i = 0; i < width*height; i++) pixels[i] = color;
Image image = LoadImageEx(pixels, width, height);
free(pixels);
return image;
}
@ -2120,17 +2120,17 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner,
float centerX = (float)width/2.0f;
float centerY = (float)height/2.0f;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
float dist = hypotf((float)x - centerX, (float)y - centerY);
float factor = (dist - radius*density)/(radius*(1.0f - density));
factor = (float)fmax(factor, 0.f);
factor = (float)fmin(factor, 1.f); // dist can be bigger than radius so we have to check
pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor));
pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor));
pixels[y*width + x].b = (int)((float)outer.b*factor + (float)inner.b*(1.0f - factor));
@ -2192,7 +2192,7 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float
{
float nx = (float)(x + offsetX)*scale/(float)width;
float ny = (float)(y + offsetY)*scale/(float)height;
// Typical values to start playing with:
// lacunarity = ~2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
// gain = 0.5 -- relative weighting applied to each successive octave
@ -2200,7 +2200,7 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float
// 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);
pixels[y*width + x] = (Color){intensity, intensity, intensity, 255};
}
@ -2233,7 +2233,7 @@ Image GenImageCellular(int width, int height, int tileSize)
for (int y = 0; y < height; y++)
{
int tileY = y/tileSize;
for (int x = 0; x < width; x++)
{
int tileX = x/tileSize;
@ -2263,7 +2263,7 @@ Image GenImageCellular(int width, int height, int tileSize)
pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 };
}
}
free(seeds);
Image image = LoadImageEx(pixels, width, height);
@ -2411,7 +2411,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
{
float width = (float)texture.width;
float height = (float)texture.height;
if (sourceRec.width < 0) sourceRec.x -= sourceRec.width;
if (sourceRec.height < 0) sourceRec.y -= sourceRec.height;
@ -2729,7 +2729,7 @@ static Image LoadDDS(const char *fileName)
image.width = ddsHeader.width;
image.height = ddsHeader.height;
if (ddsHeader.mipmapCount == 0) image.mipmaps = 1; // Parameter not used
else image.mipmaps = ddsHeader.mipmapCount;
@ -2946,9 +2946,9 @@ static Image LoadKTX(const char *fileName)
// KTX file Header (64 bytes)
// v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
// v2.0 - http://github.khronos.org/KTX-Specification/
// TODO: Support KTX 2.2 specs!
typedef struct {
char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n"
unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04
@ -3028,11 +3028,11 @@ static Image LoadKTX(const char *fileName)
static int SaveKTX(Image image, const char *fileName)
{
int success = 0;
// KTX file Header (64 bytes)
// v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
// v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation
typedef struct {
char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n"
unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04
@ -3060,11 +3060,11 @@ static int SaveKTX(Image image, const char *fileName)
else
{
KTXHeader ktxHeader;
// KTX identifier (v2.2)
//unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
//unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
// Get the image header
strcpy(ktxHeader.id, "«KTX 11»\r\n\x1A\n"); // KTX 1.1 signature
ktxHeader.endianness = 0;
@ -3080,28 +3080,28 @@ static int SaveKTX(Image image, const char *fileName)
ktxHeader.faces = 1;
ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats)
ktxHeader.keyValueDataSize = 0; // No extra data after the header
rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function
ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only
// NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
if (ktxHeader.glFormat == -1) TraceLog(LOG_WARNING, "Image format not supported for KTX export.");
else
{
success = fwrite(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
int width = image.width;
int height = image.height;
int dataOffset = 0;
// Save all mipmaps data
for (int i = 0; i < image.mipmaps; i++)
{
unsigned int dataSize = GetPixelDataSize(width, height, image.format);
success = fwrite(&dataSize, sizeof(unsigned int), 1, ktxFile);
success = fwrite((unsigned char *)image.data + dataOffset, dataSize, 1, ktxFile);
width /= 2;
height /= 2;
dataOffset += dataSize;
@ -3110,7 +3110,7 @@ static int SaveKTX(Image image, const char *fileName)
fclose(ktxFile); // Close file pointer
}
// If all data has been written correctly to file, success = 1
return success;
}
@ -3321,7 +3321,7 @@ static Image LoadASTC(const char *fileName)
TraceLog(LOG_DEBUG, "ASTC image width: %i", image.width);
TraceLog(LOG_DEBUG, "ASTC image height: %i", image.height);
TraceLog(LOG_DEBUG, "ASTC image blocks: %ix%i", astcHeader.blockX, astcHeader.blockY);
image.mipmaps = 1; // NOTE: ASTC format only contains one mipmap level
// NOTE: Each block is always stored in 128bit so we can calculate the bpp