Merge pull request #2 from raysan5/master

merged raylib-master
This commit is contained in:
Jak 2019-02-24 21:57:31 +00:00 committed by GitHub
commit 44c2df3c12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 545 additions and 422 deletions

1
.gitignore vendored
View File

@ -49,6 +49,7 @@ ipch/
# Ignore compiled binaries # Ignore compiled binaries
*.o *.o
*.exe *.exe
*.a
!raylib.rc.o !raylib.rc.o
# Ignore all examples files # Ignore all examples files

View File

@ -707,7 +707,7 @@ bool WindowShouldClose(void)
{ {
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
// Emterpreter-Async required to run sync code // Emterpreter-Async required to run sync code
// https://github.com/kripken/emscripten/wiki/Emterpreter#emterpreter-async-run-synchronous-code // https://github.com/emscripten-core/emscripten/wiki/Emterpreter#emterpreter-async-run-synchronous-code
// By default, this function is never called on a web-ready raylib example because we encapsulate // By default, this function is never called on a web-ready raylib example because we encapsulate
// frame code in a UpdateDrawFrame() function, to allow browser manage execution asynchronously // frame code in a UpdateDrawFrame() function, to allow browser manage execution asynchronously
// but now emscripten allows sync code to be executed in an interpreted way, using emterpreter! // but now emscripten allows sync code to be executed in an interpreted way, using emterpreter!
@ -871,7 +871,7 @@ void *GetWindowHandle(void)
{ {
#if defined(_WIN32) #if defined(_WIN32)
// NOTE: Returned handle is: void *HWND (windows.h) // NOTE: Returned handle is: void *HWND (windows.h)
return glfwGetWin32Window(window); return glfwGetWin32Window(window);
#elif defined(__linux__) #elif defined(__linux__)
// NOTE: Returned handle is: unsigned long Window (X.h) // NOTE: Returned handle is: unsigned long Window (X.h)
// typedef unsigned long XID; // typedef unsigned long XID;
@ -1254,6 +1254,10 @@ void EndTextureMode(void)
rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
// Reset current screen size
currentWidth = GetScreenWidth();
currentHeight = GetScreenHeight();
} }
// Returns a ray trace from mouse position // Returns a ray trace from mouse position
@ -1426,11 +1430,11 @@ Vector3 ColorToHSV(Color color)
Vector3 hsv = { 0.0f, 0.0f, 0.0f }; Vector3 hsv = { 0.0f, 0.0f, 0.0f };
float min, max, delta; float min, max, delta;
min = rgb.x < rgb.y ? rgb.x : rgb.y; min = rgb.x < rgb.y? rgb.x : rgb.y;
min = min < rgb.z ? min : rgb.z; min = min < rgb.z? min : rgb.z;
max = rgb.x > rgb.y ? rgb.x : rgb.y; max = rgb.x > rgb.y? rgb.x : rgb.y;
max = max > rgb.z ? max : rgb.z; max = max > rgb.z? max : rgb.z;
hsv.z = max; // Value hsv.z = max; // Value
delta = max - min; delta = max - min;
@ -1481,25 +1485,25 @@ Color ColorFromHSV(Vector3 hsv)
// Red channel // Red channel
float k = fmod((5.0f + h/60.0f), 6); float k = fmod((5.0f + h/60.0f), 6);
float t = 4.0f - k; float t = 4.0f - k;
k = (t < k) ? t : k; k = (t < k)? t : k;
k = (k < 1) ? k : 1; k = (k < 1)? k : 1;
k = (k > 0) ? k : 0; k = (k > 0)? k : 0;
color.r = (v - v*s*k)*255; color.r = (v - v*s*k)*255;
// Green channel // Green channel
k = fmod((3.0f + h/60.0f), 6); k = fmod((3.0f + h/60.0f), 6);
t = 4.0f - k; t = 4.0f - k;
k = (t < k) ? t : k; k = (t < k)? t : k;
k = (k < 1) ? k : 1; k = (k < 1)? k : 1;
k = (k > 0) ? k : 0; k = (k > 0)? k : 0;
color.g = (v - v*s*k)*255; color.g = (v - v*s*k)*255;
// Blue channel // Blue channel
k = fmod((1.0f + h/60.0f), 6); k = fmod((1.0f + h/60.0f), 6);
t = 4.0f - k; t = 4.0f - k;
k = (t < k) ? t : k; k = (t < k)? t : k;
k = (k < 1) ? k : 1; k = (k < 1)? k : 1;
k = (k > 0) ? k : 0; k = (k > 0)? k : 0;
color.b = (v - v*s*k)*255; color.b = (v - v*s*k)*255;
return color; return color;
@ -1673,7 +1677,7 @@ const char *GetFileNameWithoutExt(const char *filePath)
// NOTE: strrchr() returns a pointer to the last occurrence of character // NOTE: strrchr() returns a pointer to the last occurrence of character
lastDot = strrchr(result, nameDot); lastDot = strrchr(result, nameDot);
lastSep = (pathSep == 0) ? NULL : strrchr(result, pathSep); lastSep = (pathSep == 0)? NULL : strrchr(result, pathSep);
if (lastDot != NULL) // Check if it has an extension separator... if (lastDot != NULL) // Check if it has an extension separator...
{ {
@ -1913,14 +1917,13 @@ void OpenURL(const char *url)
char *cmd = (char *)calloc(strlen(url) + 10, sizeof(char)); char *cmd = (char *)calloc(strlen(url) + 10, sizeof(char));
#if defined(_WIN32) #if defined(_WIN32)
sprintf(cmd, "explorer '%s'", url); sprintf(cmd, "explorer %s", url);
#elif defined(__linux__) #elif defined(__linux__)
sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
#elif defined(__APPLE__) #elif defined(__APPLE__)
sprintf(cmd, "open '%s'", url); sprintf(cmd, "open '%s'", url);
#endif #endif
system(cmd); system(cmd);
free(cmd); free(cmd);
} }
} }
@ -2210,7 +2213,7 @@ void SetMouseOffset(int offsetX, int offsetY)
// NOTE: Useful when rendering to different size targets // NOTE: Useful when rendering to different size targets
void SetMouseScale(float scaleX, float scaleY) void SetMouseScale(float scaleX, float scaleY)
{ {
mouseScale = (Vector2){ scaleX, scaleY }; mouseScale = (Vector2){ scaleX, scaleY };
} }
// Returns mouse wheel movement Y // Returns mouse wheel movement Y
@ -3188,7 +3191,7 @@ static void PollInputEvents(void)
// Poll Events (registered events) // Poll Events (registered events)
// NOTE: Activity is paused if not enabled (appEnabled) // NOTE: Activity is paused if not enabled (appEnabled)
while ((ident = ALooper_pollAll(appEnabled ? 0 : -1, NULL, &events,(void**)&source)) >= 0) while ((ident = ALooper_pollAll(appEnabled? 0 : -1, NULL, &events,(void**)&source)) >= 0)
{ {
// Process this event // Process this event
if (source != NULL) source->process(androidApp, source); if (source != NULL) source->process(androidApp, source);
@ -3274,9 +3277,9 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
char path[512] = { 0 }; char path[512] = { 0 };
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
strcpy(path, internalDataPath); strcpy(path, internalDataPath);
strcat(path, TextFormat("/screenrec%03i.gif", screenshotCounter)); strcat(path, TextFormat("./screenrec%03i.gif", screenshotCounter));
#else #else
strcpy(path, TextFormat("/screenrec%03i.gif", screenshotCounter)); strcpy(path, TextFormat("./screenrec%03i.gif", screenshotCounter));
#endif #endif
// NOTE: delay represents the time between frames in the gif, if we capture a gif frame every // NOTE: delay represents the time between frames in the gif, if we capture a gif frame every
@ -3768,7 +3771,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
} }
printf("%s, numTouches: %d %s%s%s%s\n", emscripten_event_type_to_string(eventType), event->numTouches, printf("%s, numTouches: %d %s%s%s%s\n", emscripten_event_type_to_string(eventType), event->numTouches,
event->ctrlKey ? " CTRL" : "", event->shiftKey ? " SHIFT" : "", event->altKey ? " ALT" : "", event->metaKey ? " META" : ""); event->ctrlKey? " CTRL" : "", event->shiftKey? " SHIFT" : "", event->altKey? " ALT" : "", event->metaKey? " META" : "");
for (int i = 0; i < event->numTouches; ++i) for (int i = 0; i < event->numTouches; ++i)
{ {
@ -3822,7 +3825,7 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
{ {
/* /*
printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n", printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n",
eventType != 0 ? emscripten_event_type_to_string(eventType) : "Gamepad state", eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping); gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
for(int i = 0; i < gamepadEvent->numAxes; ++i) printf("Axis %d: %g\n", i, gamepadEvent->axis[i]); for(int i = 0; i < gamepadEvent->numAxes; ++i) printf("Axis %d: %g\n", i, gamepadEvent->axis[i]);
@ -4186,11 +4189,11 @@ static void EventThreadSpawn(char *device)
{ {
// Looks like a interesting device // Looks like a interesting device
TraceLog(LOG_INFO, "Opening input device [%s] (%s%s%s%s%s)", device, TraceLog(LOG_INFO, "Opening input device [%s] (%s%s%s%s%s)", device,
worker->isMouse ? "mouse " : "", worker->isMouse? "mouse " : "",
worker->isMultitouch ? "multitouch " : "", worker->isMultitouch? "multitouch " : "",
worker->isTouch ? "touchscreen " : "", worker->isTouch? "touchscreen " : "",
worker->isGamepad ? "gamepad " : "", worker->isGamepad? "gamepad " : "",
worker->isKeyboard ? "keyboard " : ""); worker->isKeyboard? "keyboard " : "");
// Create a thread for this device // Create a thread for this device
int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker); int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker);

51
src/external/cgltf.h vendored
View File

@ -1,6 +1,49 @@
/** /**
* cgltf - a single-file glTF 2.0 parser written in C99. * cgltf - a single-file glTF 2.0 parser written in C99.
*
* Version: 1.0
*
* Website: https://github.com/jkuhlmann/cgltf
*
* Distributed under the MIT License, see notice at the end of this file. * Distributed under the MIT License, see notice at the end of this file.
*
* Building:
* Include this file where you need the struct and function
* declarations. Have exactly one source file where you define
* `CGLTF_IMPLEMENTATION` before including this file to get the
* function definitions.
*
* Reference:
* `cgltf_result cgltf_parse(const cgltf_options*, const void*,
* cgltf_size, cgltf_data**)` parses both glTF and GLB data. If
* this function returns `cgltf_result_success`, you have to call
* `cgltf_free()` on the created `cgltf_data*` variable.
* Note that contents of external files for buffers and images are not
* automatically loaded. You'll need to read these files yourself using
* URIs in the `cgltf_data` structure.
*
* `cgltf_options` is the struct passed to `cgltf_parse()` to control
* parts of the parsing process. You can use it to force the file type
* and provide memory allocation callbacks. Should be zero-initialized
* to trigger default behavior.
*
* `cgltf_data` is the struct allocated and filled by `cgltf_parse()`.
* It generally mirrors the glTF format as described by the spec (see
* https://github.com/KhronosGroup/glTF/tree/master/specification/2.0).
*
* `void cgltf_free(cgltf_data*)` frees the allocated `cgltf_data`
* variable.
*
* `cgltf_result cgltf_load_buffers(const cgltf_options*, cgltf_data*,
* const char*)` can be optionally called to open and read buffer
* files using the `FILE*` APIs.
*
* `cgltf_result cgltf_parse_file(const cgltf_options* options, const
* char* path, cgltf_data** out_data)` can be used to open the given
* file using `FILE*` APIs and parse the data using `cgltf_parse()`.
*
* `cgltf_result cgltf_validate(cgltf_data*)` can be used to do additional
* checks to make sure the parsed glTF data is valid.
*/ */
#ifndef CGLTF_H_INCLUDED__ #ifndef CGLTF_H_INCLUDED__
#define CGLTF_H_INCLUDED__ #define CGLTF_H_INCLUDED__
@ -462,6 +505,10 @@ void cgltf_free(cgltf_data* data);
void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix);
void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef CGLTF_H_INCLUDED__ */ #endif /* #ifndef CGLTF_H_INCLUDED__ */
/* /*
@ -4266,10 +4313,6 @@ static void jsmn_init(jsmn_parser *parser) {
#endif /* #ifdef CGLTF_IMPLEMENTATION */ #endif /* #ifdef CGLTF_IMPLEMENTATION */
#ifdef __cplusplus
}
#endif
/* cgltf is distributed under MIT license: /* cgltf is distributed under MIT license:
* *
* Copyright (c) 2018 Johannes Kuhlmann * Copyright (c) 2018 Johannes Kuhlmann

Binary file not shown.

View File

@ -655,12 +655,16 @@ Mesh LoadMesh(const char *fileName)
TraceLog(LOG_WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName); TraceLog(LOG_WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName);
#endif #endif
#if defined(SUPPORT_MESH_GENERATION)
if (mesh.vertexCount == 0) if (mesh.vertexCount == 0)
{ {
TraceLog(LOG_WARNING, "Mesh could not be loaded! Let's load a cube to replace it!"); TraceLog(LOG_WARNING, "Mesh could not be loaded! Let's load a cube to replace it!");
mesh = GenMeshCube(1.0f, 1.0f, 1.0f); mesh = GenMeshCube(1.0f, 1.0f, 1.0f);
} }
else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
#else
rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
#endif
return mesh; return mesh;
} }
@ -2256,7 +2260,7 @@ void MeshTangents(Mesh *mesh)
float t2 = uv3.y - uv1.y; float t2 = uv3.y - uv1.y;
float div = s1*t2 - s2*t1; float div = s1*t2 - s2*t1;
float r = (div == 0.0f) ? 0.0f : 1.0f/div; float r = (div == 0.0f)? 0.0f : 1.0f/div;
Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r }; Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r }; Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
@ -2289,7 +2293,7 @@ void MeshTangents(Mesh *mesh)
mesh->tangents[i*4 + 0] = tangent.x; mesh->tangents[i*4 + 0] = tangent.x;
mesh->tangents[i*4 + 1] = tangent.y; mesh->tangents[i*4 + 1] = tangent.y;
mesh->tangents[i*4 + 2] = tangent.z; mesh->tangents[i*4 + 2] = tangent.z;
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f) ? -1.0f : 1.0f; mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
#endif #endif
} }
@ -2308,7 +2312,7 @@ void MeshBinormals(Mesh *mesh)
Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] }; Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
float tangentW = mesh->tangents[i*4 + 3]; float tangentW = mesh->tangents[i*4 + 3];
// TODO: Register computed binormal in mesh->binormal ? // TODO: Register computed binormal in mesh->binormal?
// Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW); // Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW);
} }
} }
@ -2635,7 +2639,7 @@ static Material LoadMTL(const char *fileName)
} break; } break;
case 'e': // Ke float float float Emmisive color (RGB) case 'e': // Ke float float float Emmisive color (RGB)
{ {
// TODO: Support Ke ? // TODO: Support Ke?
} break; } break;
default: break; default: break;
} }
@ -2744,17 +2748,17 @@ static Mesh LoadIQM(const char *fileName)
#endif #endif
#if defined(SUPPORT_FILEFORMAT_GLTF) #if defined(SUPPORT_FILEFORMAT_GLTF)
// Load GLTF mesh data // Load glTF mesh data
static Mesh LoadGLTF(const char *fileName) static Mesh LoadGLTF(const char *fileName)
{ {
Mesh mesh = { 0 }; Mesh mesh = { 0 };
// GLTF file loading // glTF file loading
FILE *gltfFile = fopen(fileName, "rb"); FILE *gltfFile = fopen(fileName, "rb");
if (gltfFile == NULL) if (gltfFile == NULL)
{ {
TraceLog(LOG_WARNING, "[%s] GLTF file could not be opened", fileName); TraceLog(LOG_WARNING, "[%s] glTF file could not be opened", fileName);
return mesh; return mesh;
} }
@ -2767,21 +2771,27 @@ static Mesh LoadGLTF(const char *fileName)
fclose(gltfFile); fclose(gltfFile);
// GLTF data loading // glTF data loading
cgltf_options options = {0}; cgltf_options options = {0};
cgltf_data data; cgltf_data data;
cgltf_result result = cgltf_parse(&options, buffer, size, &data); cgltf_result result = cgltf_parse(&options, buffer, size, &data);
free(buffer);
if (result == cgltf_result_success) if (result == cgltf_result_success)
{ {
printf("Type: %u\n", data.file_type); printf("Type: %u\n", data.file_type);
printf("Version: %d\n", data.version); printf("Version: %d\n", data.version);
printf("Meshes: %lu\n", data.meshes_count); printf("Meshes: %lu\n", data.meshes_count);
}
else TraceLog(LOG_WARNING, "[%s] GLTF data could not be loaded", fileName);
free(buffer); // TODO: Process glTF data and map to mesh
cgltf_free(&data);
// NOTE: data.buffers[] and data.images[] should be loaded
// using buffers[n].uri and images[n].uri... or use cgltf_load_buffers(&options, data, fileName);
cgltf_free(&data);
}
else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName);
return mesh; return mesh;
} }

View File

@ -712,11 +712,13 @@ void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
return; return;
} }
audioBuffer->pitch = pitch; float pitchMul = pitch / audioBuffer->pitch;
// Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches
// will make the sound faster; lower pitches make it slower. // will make the sound faster; lower pitches make it slower.
mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.src.config.sampleRateOut / (float)audioBuffer->dsp.src.config.sampleRateIn) / pitch) * audioBuffer->dsp.src.config.sampleRateIn); mal_uint32 newOutputSampleRate = (mal_uint32)((float)audioBuffer->dsp.src.config.sampleRateOut / pitchMul);
audioBuffer->pitch *= (float)audioBuffer->dsp.src.config.sampleRateOut / newOutputSampleRate;
mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate); mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate);
} }
@ -767,7 +769,11 @@ Wave LoadWave(const char *fileName)
{ {
Wave wave = { 0 }; Wave wave = { 0 };
#if defined(SUPPORT_FILEFORMAT_WAV)
if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName); if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName); else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName);
#endif #endif
@ -830,7 +836,7 @@ Sound LoadSoundFromWave(Wave wave)
// //
// I have decided on the first option because it offloads work required for the format conversion to the to the loading stage. // I have decided on the first option because it offloads work required for the format conversion to the to the loading stage.
// The downside to this is that it uses more memory if the original sound is u8 or s16. // The downside to this is that it uses more memory if the original sound is u8 or s16.
mal_format formatIn = ((wave.sampleSize == 8) ? mal_format_u8 : ((wave.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatIn = ((wave.sampleSize == 8)? mal_format_u8 : ((wave.sampleSize == 16)? mal_format_s16 : mal_format_f32));
mal_uint32 frameCountIn = wave.sampleCount/wave.channels; mal_uint32 frameCountIn = wave.sampleCount/wave.channels;
mal_uint32 frameCount = (mal_uint32)mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn); mal_uint32 frameCount = (mal_uint32)mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn);
@ -887,7 +893,11 @@ void ExportWave(Wave wave, const char *fileName)
{ {
bool success = false; bool success = false;
#if defined(SUPPORT_FILEFORMAT_WAV)
if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName); if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
#else
if (false) {}
#endif
else if (IsFileExtension(fileName, ".raw")) else if (IsFileExtension(fileName, ".raw"))
{ {
// Export raw sample data (without header) // Export raw sample data (without header)
@ -938,7 +948,7 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
// Write byte data as hexadecimal text // Write byte data as hexadecimal text
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0) ? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]); for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]); fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
fclose(txtFile); fclose(txtFile);
@ -989,8 +999,8 @@ void SetSoundPitch(Sound sound, float pitch)
// Convert wave data to desired format // Convert wave data to desired format
void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
{ {
mal_format formatIn = ((wave->sampleSize == 8) ? mal_format_u8 : ((wave->sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatIn = ((wave->sampleSize == 8)? mal_format_u8 : ((wave->sampleSize == 16)? mal_format_s16 : mal_format_f32));
mal_format formatOut = (( sampleSize == 8) ? mal_format_u8 : (( sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatOut = (( sampleSize == 8)? mal_format_u8 : (( sampleSize == 16)? mal_format_s16 : mal_format_f32));
mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so.
@ -1087,6 +1097,7 @@ Music LoadMusicStream(const char *fileName)
Music music = (MusicData *)malloc(sizeof(MusicData)); Music music = (MusicData *)malloc(sizeof(MusicData));
bool musicLoaded = true; bool musicLoaded = true;
#if defined(SUPPORT_FILEFORMAT_OGG)
if (IsFileExtension(fileName, ".ogg")) if (IsFileExtension(fileName, ".ogg"))
{ {
// Open ogg audio stream // Open ogg audio stream
@ -1110,6 +1121,9 @@ Music LoadMusicStream(const char *fileName)
TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required); TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
} }
} }
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac")) else if (IsFileExtension(fileName, ".flac"))
{ {
@ -1202,7 +1216,11 @@ Music LoadMusicStream(const char *fileName)
if (!musicLoaded) if (!musicLoaded)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG)
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac); else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac);
#endif #endif
@ -1232,7 +1250,11 @@ void UnloadMusicStream(Music music)
CloseAudioStream(music->stream); CloseAudioStream(music->stream);
#if defined(SUPPORT_FILEFORMAT_OGG)
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac); else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac);
#endif #endif
@ -1297,7 +1319,9 @@ void StopMusicStream(Music music)
// Restart music context // Restart music context
switch (music->ctxType) switch (music->ctxType)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break; case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break;
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break; case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break;
#endif #endif
@ -1339,12 +1363,14 @@ void UpdateMusicStream(Music music)
// TODO: Really don't like ctxType thingy... // TODO: Really don't like ctxType thingy...
switch (music->ctxType) switch (music->ctxType)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: case MUSIC_AUDIO_OGG:
{ {
// NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount); stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount);
} break; } break;
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: case MUSIC_AUDIO_FLAC:
{ {
@ -1382,8 +1408,8 @@ void UpdateMusicStream(Music music)
UpdateAudioStream(music->stream, pcm, samplesCount); UpdateAudioStream(music->stream, pcm, samplesCount);
if ((music->ctxType == MUSIC_MODULE_XM) || (music->ctxType == MUSIC_MODULE_MOD)) if ((music->ctxType == MUSIC_MODULE_XM) || (music->ctxType == MUSIC_MODULE_MOD))
{ {
if (samplesCount > 1) music->samplesLeft -= samplesCount/2; if (samplesCount > 1) music->samplesLeft -= samplesCount/2;
else music->samplesLeft -= samplesCount; else music->samplesLeft -= samplesCount;
} }
else music->samplesLeft -= samplesCount; else music->samplesLeft -= samplesCount;
@ -1487,7 +1513,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
stream.channels = 1; // Fallback to mono channel stream.channels = 1; // Fallback to mono channel
} }
mal_format formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatIn = ((stream.sampleSize == 8)? mal_format_u8 : ((stream.sampleSize == 16)? mal_format_s16 : mal_format_f32));
// The size of a streaming buffer must be at least double the size of a period. // The size of a streaming buffer must be at least double the size of a period.
unsigned int periodSize = device.bufferSizeInFrames/device.periods; unsigned int periodSize = device.bufferSizeInFrames/device.periods;
@ -1504,7 +1530,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
audioBuffer->looping = true; // Always loop for streaming buffers. audioBuffer->looping = true; // Always loop for streaming buffers.
stream.audioBuffer = audioBuffer; stream.audioBuffer = audioBuffer;
TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1) ? "Mono" : "Stereo"); TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo");
return stream; return stream;
} }
@ -1542,7 +1568,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
else else
{ {
// Just update whichever sub-buffer is processed. // Just update whichever sub-buffer is processed.
subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0]) ? 0 : 1; subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0])? 0 : 1;
} }
mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2;
@ -1745,7 +1771,7 @@ static Wave LoadWAV(const char *fileName)
// NOTE: subChunkSize comes in bytes, we need to translate it to number of samples // NOTE: subChunkSize comes in bytes, we need to translate it to number of samples
wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels; wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels;
TraceLog(LOG_INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); TraceLog(LOG_INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
} }
} }
} }
@ -1866,7 +1892,7 @@ static Wave LoadOGG(const char *fileName)
TraceLog(LOG_DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg); TraceLog(LOG_DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg);
TraceLog(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); TraceLog(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
stb_vorbis_close(oggFile); stb_vorbis_close(oggFile);
} }
@ -1893,7 +1919,7 @@ static Wave LoadFLAC(const char *fileName)
if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels); if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels);
if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] FLAC data could not be loaded", fileName); if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] FLAC data could not be loaded", fileName);
else TraceLog(LOG_INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); else TraceLog(LOG_INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
return wave; return wave;
} }
@ -1920,7 +1946,7 @@ static Wave LoadMP3(const char *fileName)
if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] MP3 channels number (%i) not supported", fileName, wave.channels); if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] MP3 channels number (%i) not supported", fileName, wave.channels);
if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] MP3 data could not be loaded", fileName); if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] MP3 data could not be loaded", fileName);
else TraceLog(LOG_INFO, "[%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); else TraceLog(LOG_INFO, "[%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
return wave; return wave;
} }

View File

@ -775,8 +775,8 @@ typedef struct DrawCall {
#endif #endif
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" vec2 lensCenter = fragTexCoord.x < 0.5 ? leftLensCenter : rightLensCenter; \n" " vec2 lensCenter = fragTexCoord.x < 0.5? leftLensCenter : rightLensCenter; \n"
" vec2 screenCenter = fragTexCoord.x < 0.5 ? leftScreenCenter : rightScreenCenter; \n" " vec2 screenCenter = fragTexCoord.x < 0.5? leftScreenCenter : rightScreenCenter; \n"
" vec2 theta = (fragTexCoord - lensCenter)*scaleIn; \n" " vec2 theta = (fragTexCoord - lensCenter)*scaleIn; \n"
" float rSq = theta.x*theta.x + theta.y*theta.y; \n" " float rSq = theta.x*theta.x + theta.y*theta.y; \n"
" vec2 theta1 = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq); \n" " vec2 theta1 = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq); \n"
@ -1136,7 +1136,7 @@ void rlEnd(void)
// TODO: System could be improved (a bit) just storing every draw alignment value // TODO: System could be improved (a bit) just storing every draw alignment value
// and adding it to vertexOffset on drawing... maybe in a future... // and adding it to vertexOffset on drawing... maybe in a future...
int vertexCount = draws[drawsCounter - 1].vertexCount; int vertexCount = draws[drawsCounter - 1].vertexCount;
int vertexToAlign = (vertexCount >= 4) ? vertexCount%4 : (4 - vertexCount%4); int vertexToAlign = (vertexCount >= 4)? vertexCount%4 : (4 - vertexCount%4);
for (int i = 0; i < vertexToAlign; i++) rlVertex3f(-1, -1, -1); for (int i = 0; i < vertexToAlign; i++) rlVertex3f(-1, -1, -1);
// Make sure vertexCount is the same for vertices, texcoords, colors and normals // Make sure vertexCount is the same for vertices, texcoords, colors and normals
@ -1233,7 +1233,7 @@ void rlTexCoord2f(float x, float y)
} }
// Define one vertex (normal) // Define one vertex (normal)
// NOTE: Normals limited to TRIANGLES only ? // NOTE: Normals limited to TRIANGLES only?
void rlNormal3f(float x, float y, float z) void rlNormal3f(float x, float y, float z)
{ {
// TODO: Normals usage... // TODO: Normals usage...
@ -2206,7 +2206,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depth
target.depth.id = rlLoadTextureDepth(width, height, depthBits, !useDepthTexture); target.depth.id = rlLoadTextureDepth(width, height, depthBits, !useDepthTexture);
target.depth.width = width; target.depth.width = width;
target.depth.height = height; target.depth.height = height;
target.depth.format = 19; //DEPTH_COMPONENT_24BIT ? target.depth.format = 19; //DEPTH_COMPONENT_24BIT?
target.depth.mipmaps = 1; target.depth.mipmaps = 1;
} }
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------

View File

@ -132,7 +132,7 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
rlPushMatrix(); rlPushMatrix();
rlTranslatef((float)startPos.x, (float)startPos.y, 0.0f); rlTranslatef((float)startPos.x, (float)startPos.y, 0.0f);
rlRotatef(RAD2DEG*angle, 0.0f, 0.0f, 1.0f); rlRotatef(RAD2DEG*angle, 0.0f, 0.0f, 1.0f);
rlTranslatef(0, (thick > 1.0f) ? -thick/2.0f : -1.0f, 0.0f); rlTranslatef(0, (thick > 1.0f)? -thick/2.0f : -1.0f, 0.0f);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
@ -644,7 +644,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
if (dy <= (rec.height/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); (dy - rec.height/2.0f)*(dy - rec.height/2.0f);
return (cornerDistanceSq <= (radius*radius)); return (cornerDistanceSq <= (radius*radius));
} }
@ -742,7 +742,7 @@ static Texture2D GetShapesTexture(void)
recTexShapes = (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }; recTexShapes = (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 };
#else #else
texShapes = GetTextureDefault(); // Use default white texture texShapes = GetTextureDefault(); // Use default white texture
recTexShapes = { 0.0f, 0.0f, 1.0f, 1.0f }; recTexShapes = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
#endif #endif
} }

View File

@ -306,9 +306,10 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
Font font = { 0 }; Font font = { 0 };
font.baseSize = fontSize; font.baseSize = fontSize;
font.charsCount = (charsCount > 0) ? charsCount : 95; font.charsCount = (charsCount > 0)? charsCount : 95;
font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT); font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT);
#if defined(SUPPORT_FILEFORMAT_TTF)
if (font.chars != NULL) if (font.chars != NULL)
{ {
Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 2, 0); Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 2, 0);
@ -316,6 +317,9 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
UnloadImage(atlas); UnloadImage(atlas);
} }
else font = GetFontDefault(); else font = GetFontDefault();
#else
font = GetFontDefault();
#endif
return font; return font;
} }
@ -426,6 +430,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
spriteFont.chars[i].offsetX = 0; spriteFont.chars[i].offsetX = 0;
spriteFont.chars[i].offsetY = 0; spriteFont.chars[i].offsetY = 0;
spriteFont.chars[i].advanceX = 0; spriteFont.chars[i].advanceX = 0;
spriteFont.chars[i].data = NULL;
} }
spriteFont.baseSize = (int)spriteFont.chars[0].rec.height; spriteFont.baseSize = (int)spriteFont.chars[0].rec.height;
@ -449,6 +454,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
CharInfo *chars = NULL; CharInfo *chars = NULL;
#if defined(SUPPORT_FILEFORMAT_TTF)
// Load font data (including pixel data) from TTF file // Load font data (including pixel data) from TTF file
// NOTE: Loaded information should be enough to generate font image atlas, // NOTE: Loaded information should be enough to generate font image atlas,
// using any packaging method // using any packaging method
@ -478,7 +484,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
// In case no chars count provided, default to 95 // In case no chars count provided, default to 95
charsCount = (charsCount > 0) ? charsCount : 95; charsCount = (charsCount > 0)? charsCount : 95;
// Fill fontChars in case not provided externally // Fill fontChars in case not provided externally
// NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space)
@ -506,6 +512,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
if (type != FONT_SDF) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); 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); 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);
else chars[i].data = NULL;
if (type == FONT_BITMAP) if (type == FONT_BITMAP)
{ {
@ -537,18 +544,22 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
if (genFontChars) free(fontChars); if (genFontChars) free(fontChars);
} }
else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName); else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName);
#else
TraceLog(LOG_WARNING, "[%s] TTF support is disabled", fileName);
#endif
return chars; return chars;
} }
// Generate image font atlas using chars info // Generate image font atlas using chars info
// NOTE: Packing method: 0-Default, 1-Skyline // NOTE: Packing method: 0-Default, 1-Skyline
#if defined(SUPPORT_FILEFORMAT_TTF)
Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod) Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod)
{ {
Image atlas = { 0 }; Image atlas = { 0 };
// In case no chars count provided we suppose default of 95 // In case no chars count provided we suppose default of 95
charsCount = (charsCount > 0) ? charsCount : 95; charsCount = (charsCount > 0)? charsCount : 95;
// Calculate image size based on required pixel area // Calculate image size based on required pixel area
// NOTE 1: Image is forced to be squared and POT... very conservative! // NOTE 1: Image is forced to be squared and POT... very conservative!
@ -667,6 +678,7 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi
return atlas; return atlas;
} }
#endif
// Unload Font from GPU memory (VRAM) // Unload Font from GPU memory (VRAM)
void UnloadFont(Font font) void UnloadFont(Font font)
@ -674,6 +686,11 @@ void UnloadFont(Font font)
// NOTE: Make sure spriteFont is not default font (fallback) // NOTE: Make sure spriteFont is not default font (fallback)
if (font.texture.id != GetFontDefault().texture.id) if (font.texture.id != GetFontDefault().texture.id)
{ {
for (int i = 0; i < font.charsCount; i++)
{
if(font.chars[i].data != NULL)
free(font.chars[i].data);
}
UnloadTexture(font.texture); UnloadTexture(font.texture);
free(font.chars); free(font.chars);
@ -846,7 +863,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
if ((textOffsetX + glyphWidth + 1) >= rec.width) if ((textOffsetX + glyphWidth + 1) >= rec.width)
{ {
endLine = (endLine < 1) ? i : endLine; endLine = (endLine < 1)? i : endLine;
if (i == endLine) endLine -= 1; if (i == endLine) endLine -= 1;
if ((startLine + 1) == endLine) endLine = i - 1; if ((startLine + 1) == endLine) endLine = i - 1;
state = !state; state = !state;
@ -887,7 +904,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
textOffsetX = 0; textOffsetX = 0;
} }
if ((textOffsetY + (int)((font.baseSize + font.baseSize/2)*scaleFactor)) > rec.height) break; if ((textOffsetY + (int)(font.baseSize*scaleFactor)) > rec.height) break;
//draw selected //draw selected
bool isGlyphSelected = false; bool isGlyphSelected = false;
@ -906,7 +923,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor, rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.chars[index].rec.width*scaleFactor, font.chars[index].rec.width*scaleFactor,
font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f,
(!isGlyphSelected) ? tint : selectText); (!isGlyphSelected)? tint : selectText);
} }
} }
@ -1376,10 +1393,10 @@ static Font LoadBMFont(const char *fileName)
char *lastSlash = NULL; char *lastSlash = NULL;
lastSlash = strrchr(fileName, '/'); lastSlash = strrchr(fileName, '/');
if (lastSlash == NULL) if (lastSlash == NULL)
{ {
lastSlash = strrchr(fileName, '\\'); lastSlash = strrchr(fileName, '\\');
} }
// NOTE: We need some extra space to avoid memory corruption on next allocations! // NOTE: We need some extra space to avoid memory corruption on next allocations!
texPath = malloc(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4); texPath = malloc(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4);
@ -1428,6 +1445,7 @@ static Font LoadBMFont(const char *fileName)
font.chars[i].offsetX = charOffsetX; font.chars[i].offsetX = charOffsetX;
font.chars[i].offsetY = charOffsetY; font.chars[i].offsetY = charOffsetY;
font.chars[i].advanceX = charAdvanceX; font.chars[i].advanceX = charAdvanceX;
font.chars[i].data = NULL;
} }
fclose(fntFile); fclose(fntFile);

View File

@ -182,7 +182,11 @@ Image LoadImage(const char *fileName)
{ {
Image image = { 0 }; Image image = { 0 };
#if defined(SUPPORT_FILEFORMAT_PNG)
if ((IsFileExtension(fileName, ".png")) if ((IsFileExtension(fileName, ".png"))
#else
if ((false)
#endif
#if defined(SUPPORT_FILEFORMAT_BMP) #if defined(SUPPORT_FILEFORMAT_BMP)
|| (IsFileExtension(fileName, ".bmp")) || (IsFileExtension(fileName, ".bmp"))
#endif #endif
@ -398,90 +402,6 @@ Texture2D LoadTextureFromImage(Image image)
return texture; return texture;
} }
// Load cubemap from image, multiple image cubemap layouts supported
TextureCubemap LoadTextureCubemap(Image image, int layoutType)
{
TextureCubemap cubemap = { 0 };
if (layoutType == CUBEMAP_AUTO_DETECT) // Try to automatically guess layout type
{
// Check image width/height to determine the type of cubemap provided
if (image.width > image.height)
{
if ((image.width/6) == image.height) { layoutType = CUBEMAP_LINE_HORIZONTAL; cubemap.width = image.width/6; }
else if ((image.width/4) == (image.height/3)) { layoutType = CUBEMAP_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; }
else if (image.width >= (int)((float)image.height*1.85f)) { layoutType = CUBEMAP_PANORAMA; cubemap.width = image.width/4; }
}
else if (image.height > image.width)
{
if ((image.height/6) == image.width) { layoutType = CUBEMAP_LINE_VERTICAL; cubemap.width = image.height/6; }
else if ((image.width/3) == (image.height/4)) { layoutType = CUBEMAP_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
}
cubemap.height = cubemap.width;
}
int size = cubemap.width;
if (layoutType != CUBEMAP_AUTO_DETECT)
{
//unsigned int dataSize = GetPixelDataSize(size, size, format);
//void *facesData = malloc(size*size*dataSize*6); // Get memory for 6 faces in a column
Image faces = { 0 }; // Vertical column image
Rectangle faceRecs[6] = { 0 }; // Face source rectangles
for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, size, size };
if (layoutType == CUBEMAP_LINE_VERTICAL)
{
faces = image;
for (int i = 0; i < 6; i++) faceRecs[i].y = size*i;
}
else if (layoutType == CUBEMAP_PANORAMA)
{
// TODO: Convert panorama image to square faces...
}
else
{
if (layoutType == CUBEMAP_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = size*i;
else if (layoutType == CUBEMAP_CROSS_THREE_BY_FOUR)
{
faceRecs[0].x = size; faceRecs[0].y = size;
faceRecs[1].x = size; faceRecs[1].y = 3*size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = 0; faceRecs[4].y = size;
faceRecs[5].x = 2*size; faceRecs[5].y = size;
}
else if (layoutType == CUBEMAP_CROSS_FOUR_BY_THREE)
{
faceRecs[0].x = 2*size; faceRecs[0].y = size;
faceRecs[1].x = 0; faceRecs[1].y = size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = size; faceRecs[4].y = size;
faceRecs[5].x = 3*size; faceRecs[5].y = size;
}
// Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
faces = GenImageColor(size, size*6, MAGENTA);
ImageFormat(&faces, image.format);
// TODO: Image formating does not work with compressed textures!
}
for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, size*i, size, size });
cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
if (cubemap.id == 0) TraceLog(LOG_WARNING, "Cubemap image could not be loaded.");
UnloadImage(faces);
}
else TraceLog(LOG_WARNING, "Cubemap image layout can not be detected.");
return cubemap;
}
// Load texture for rendering (framebuffer) // Load texture for rendering (framebuffer)
// NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer // NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer
RenderTexture2D LoadRenderTexture(int width, int height) RenderTexture2D LoadRenderTexture(int width, int height)
@ -668,7 +588,7 @@ Vector4 *GetImageDataNormalized(Image image)
pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31);
pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31);
pixels[i].w = ((pixel & 0b0000000000000001) == 0) ? 0.0f : 1.0f; pixels[i].w = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f;
} break; } break;
case UNCOMPRESSED_R5G6B5: case UNCOMPRESSED_R5G6B5:
@ -825,14 +745,27 @@ void ExportImage(Image image, const char *fileName)
{ {
int success = 0; int success = 0;
#if defined(SUPPORT_IMAGE_EXPORT)
// NOTE: Getting Color array as RGBA unsigned char values // NOTE: Getting Color array as RGBA unsigned char values
unsigned char *imgData = (unsigned char *)GetImageData(image); unsigned char *imgData = (unsigned char *)GetImageData(image);
#if defined(SUPPORT_FILEFORMAT_PNG)
if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, 4, imgData, image.width*4); if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, 4, imgData, image.width*4);
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_BMP)
else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, 4, imgData); else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, 4, imgData);
#endif
#if defined(SUPPORT_FILEFORMAT_TGA)
else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, 4, imgData); else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, 4, imgData);
#endif
#if defined(SUPPORT_FILEFORMAT_JPG)
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, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, 4, imgData, 80); // JPG quality: between 1 and 100
#endif
#if defined(SUPPORT_FILEFORMAT_KTX)
else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName); else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName);
#endif
else if (IsFileExtension(fileName, ".raw")) else if (IsFileExtension(fileName, ".raw"))
{ {
// Export raw pixel data (without header) // Export raw pixel data (without header)
@ -842,10 +775,11 @@ void ExportImage(Image image, const char *fileName)
fclose(rawFile); fclose(rawFile);
} }
free(imgData);
#endif
if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName); if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName);
else TraceLog(LOG_WARNING, "Image could not be exported."); else TraceLog(LOG_WARNING, "Image could not be exported.");
free(imgData);
} }
// Export image as code file (.h) defining an array of bytes // Export image as code file (.h) defining an array of bytes
@ -880,7 +814,7 @@ void ExportImageAsCode(Image image, const char *fileName)
fprintf(txtFile, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format); fprintf(txtFile, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format);
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0) ? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]); for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]);
fprintf(txtFile, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]); fprintf(txtFile, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]);
fclose(txtFile); fclose(txtFile);
@ -1050,7 +984,7 @@ void ImageFormat(Image *image, int newFormat)
r = (unsigned char)(round(pixels[i].x*31.0f)); r = (unsigned char)(round(pixels[i].x*31.0f));
g = (unsigned char)(round(pixels[i].y*31.0f)); g = (unsigned char)(round(pixels[i].y*31.0f));
b = (unsigned char)(round(pixels[i].z*31.0f)); b = (unsigned char)(round(pixels[i].z*31.0f));
a = (pixels[i].w > ((float)ALPHA_THRESHOLD/255.0f)) ? 1 : 0; a = (pixels[i].w > ((float)ALPHA_THRESHOLD/255.0f))? 1 : 0;
((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
} }
@ -1133,7 +1067,9 @@ void ImageFormat(Image *image, int newFormat)
if (image->mipmaps > 1) if (image->mipmaps > 1)
{ {
image->mipmaps = 1; image->mipmaps = 1;
#if defined(SUPPORT_IMAGE_MANIPULATION)
if (image->data != NULL) ImageMipmaps(image); if (image->data != NULL) ImageMipmaps(image);
#endif
} }
} }
else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted"); else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted");
@ -1202,38 +1138,6 @@ void ImageAlphaClear(Image *image, Color color, float threshold)
ImageFormat(image, prevFormat); ImageFormat(image, prevFormat);
} }
// Crop image depending on alpha value
void ImageAlphaCrop(Image *image, float threshold)
{
Color *pixels = GetImageData(*image);
int xMin = 65536; // Define a big enough number
int xMax = 0;
int yMin = 65536;
int yMax = 0;
for (int y = 0; y < image->height; y++)
{
for (int x = 0; x < image->width; x++)
{
if (pixels[y*image->width + x].a > (unsigned char)(threshold*255.0f))
{
if (x < xMin) xMin = x;
if (x > xMax) xMax = x;
if (y < yMin) yMin = y;
if (y > yMax) yMax = y;
}
}
}
Rectangle crop = { xMin, yMin, (xMax + 1) - xMin, (yMax + 1) - yMin };
free(pixels);
// Check for not empty image brefore cropping
if (!((xMax < xMin) || (yMax < yMin))) ImageCrop(image, crop);
}
// Premultiply alpha channel // Premultiply alpha channel
void ImageAlphaPremultiply(Image *image) void ImageAlphaPremultiply(Image *image)
{ {
@ -1259,6 +1163,90 @@ void ImageAlphaPremultiply(Image *image)
#if defined(SUPPORT_IMAGE_MANIPULATION) #if defined(SUPPORT_IMAGE_MANIPULATION)
// Load cubemap from image, multiple image cubemap layouts supported
TextureCubemap LoadTextureCubemap(Image image, int layoutType)
{
TextureCubemap cubemap = { 0 };
if (layoutType == CUBEMAP_AUTO_DETECT) // Try to automatically guess layout type
{
// Check image width/height to determine the type of cubemap provided
if (image.width > image.height)
{
if ((image.width/6) == image.height) { layoutType = CUBEMAP_LINE_HORIZONTAL; cubemap.width = image.width/6; }
else if ((image.width/4) == (image.height/3)) { layoutType = CUBEMAP_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; }
else if (image.width >= (int)((float)image.height*1.85f)) { layoutType = CUBEMAP_PANORAMA; cubemap.width = image.width/4; }
}
else if (image.height > image.width)
{
if ((image.height/6) == image.width) { layoutType = CUBEMAP_LINE_VERTICAL; cubemap.width = image.height/6; }
else if ((image.width/3) == (image.height/4)) { layoutType = CUBEMAP_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
}
cubemap.height = cubemap.width;
}
int size = cubemap.width;
if (layoutType != CUBEMAP_AUTO_DETECT)
{
//unsigned int dataSize = GetPixelDataSize(size, size, format);
//void *facesData = malloc(size*size*dataSize*6); // Get memory for 6 faces in a column
Image faces = { 0 }; // Vertical column image
Rectangle faceRecs[6] = { 0 }; // Face source rectangles
for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, size, size };
if (layoutType == CUBEMAP_LINE_VERTICAL)
{
faces = image;
for (int i = 0; i < 6; i++) faceRecs[i].y = size*i;
}
else if (layoutType == CUBEMAP_PANORAMA)
{
// TODO: Convert panorama image to square faces...
}
else
{
if (layoutType == CUBEMAP_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = size*i;
else if (layoutType == CUBEMAP_CROSS_THREE_BY_FOUR)
{
faceRecs[0].x = size; faceRecs[0].y = size;
faceRecs[1].x = size; faceRecs[1].y = 3*size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = 0; faceRecs[4].y = size;
faceRecs[5].x = 2*size; faceRecs[5].y = size;
}
else if (layoutType == CUBEMAP_CROSS_FOUR_BY_THREE)
{
faceRecs[0].x = 2*size; faceRecs[0].y = size;
faceRecs[1].x = 0; faceRecs[1].y = size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = size; faceRecs[4].y = size;
faceRecs[5].x = 3*size; faceRecs[5].y = size;
}
// Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
faces = GenImageColor(size, size*6, MAGENTA);
ImageFormat(&faces, image.format);
// TODO: Image formating does not work with compressed textures!
}
for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, size*i, size, size });
cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
if (cubemap.id == 0) TraceLog(LOG_WARNING, "Cubemap image could not be loaded.");
UnloadImage(faces);
}
else TraceLog(LOG_WARNING, "Cubemap image layout can not be detected.");
return cubemap;
}
// Crop an image to area defined by a rectangle // Crop an image to area defined by a rectangle
// NOTE: Security checks are performed in case rectangle goes out of bounds // NOTE: Security checks are performed in case rectangle goes out of bounds
void ImageCrop(Image *image, Rectangle crop) void ImageCrop(Image *image, Rectangle crop)
@ -1309,6 +1297,38 @@ void ImageCrop(Image *image, Rectangle crop)
} }
} }
// Crop image depending on alpha value
void ImageAlphaCrop(Image *image, float threshold)
{
Color *pixels = GetImageData(*image);
int xMin = 65536; // Define a big enough number
int xMax = 0;
int yMin = 65536;
int yMax = 0;
for (int y = 0; y < image->height; y++)
{
for (int x = 0; x < image->width; x++)
{
if (pixels[y*image->width + x].a > (unsigned char)(threshold*255.0f))
{
if (x < xMin) xMin = x;
if (x > xMax) xMax = x;
if (y < yMin) yMin = y;
if (y > yMax) yMax = y;
}
}
}
Rectangle crop = { xMin, yMin, (xMax + 1) - xMin, (yMax + 1) - yMin };
free(pixels);
// Check for not empty image brefore cropping
if (!((xMax < xMin) || (yMax < yMin))) ImageCrop(image, crop);
}
// Resize and image to new size // Resize and image to new size
// NOTE: Uses stb default scaling filters (both bicubic): // NOTE: Uses stb default scaling filters (both bicubic):
// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM // STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
@ -1611,7 +1631,7 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount)
if (palCount >= maxPaletteSize) if (palCount >= maxPaletteSize)
{ {
i = image.width*image.height; // Finish palette get i = image.width*image.height; // Finish palette get
printf("WARNING: Image palette is greater than %i colors!\n", maxPaletteSize); TraceLog(LOG_WARNING, "Image palette is greater than %i colors!", maxPaletteSize);
} }
} }
} }
@ -2146,7 +2166,6 @@ void ImageColorReplace(Image *image, Color color, Color replace)
} }
#endif // SUPPORT_IMAGE_MANIPULATION #endif // SUPPORT_IMAGE_MANIPULATION
#if defined(SUPPORT_IMAGE_GENERATION)
// Generate image: plain color // Generate image: plain color
Image GenImageColor(int width, int height, Color color) Image GenImageColor(int width, int height, Color color)
{ {
@ -2161,6 +2180,7 @@ Image GenImageColor(int width, int height, Color color)
return image; return image;
} }
#if defined(SUPPORT_IMAGE_GENERATION)
// Generate image: vertical gradient // Generate image: vertical gradient
Image GenImageGradientV(int width, int height, Color top, Color bottom) Image GenImageGradientV(int width, int height, Color top, Color bottom)
{ {
@ -2211,7 +2231,7 @@ Image GenImageGradientH(int width, int height, Color left, Color right)
Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer) Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer)
{ {
Color *pixels = (Color *)malloc(width*height*sizeof(Color)); Color *pixels = (Color *)malloc(width*height*sizeof(Color));
float radius = (width < height) ? (float)width/2.0f : (float)height/2.0f; float radius = (width < height)? (float)width/2.0f : (float)height/2.0f;
float centerX = (float)width/2.0f; float centerX = (float)width/2.0f;
float centerY = (float)height/2.0f; float centerY = (float)height/2.0f;
@ -3173,25 +3193,27 @@ static int SaveKTX(Image image, const char *fileName)
{ {
KTXHeader ktxHeader; KTXHeader ktxHeader;
// KTX identifier (v2.2) // KTX identifier (v1.1)
//unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' }; //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 }; //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
// Get the image header // Get the image header
strcpy(ktxHeader.id, "«KTX 11»\r\n\x1A\n"); // KTX 1.1 signature strncpy(ktxHeader.id, ktxIdentifier, 12); // KTX 1.1 signature
ktxHeader.endianness = 0; ktxHeader.endianness = 0;
ktxHeader.glType = 0; // Obtained from image.format ktxHeader.glType = 0; // Obtained from image.format
ktxHeader.glTypeSize = 1; ktxHeader.glTypeSize = 1;
ktxHeader.glFormat = 0; // Obtained from image.format ktxHeader.glFormat = 0; // Obtained from image.format
ktxHeader.glInternalFormat = 0; // Obtained from image.format ktxHeader.glInternalFormat = 0; // Obtained from image.format
ktxHeader.glBaseInternalFormat = 0; ktxHeader.glBaseInternalFormat = 0;
ktxHeader.width = image.width; ktxHeader.width = image.width;
ktxHeader.height = image.height; ktxHeader.height = image.height;
ktxHeader.depth = 0; ktxHeader.depth = 0;
ktxHeader.elements = 0; ktxHeader.elements = 0;
ktxHeader.faces = 1; ktxHeader.faces = 1;
ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats) 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 ktxHeader.keyValueDataSize = 0; // No extra data after the header
rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function
ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only