commit
44c2df3c12
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
13
src/core.c
13
src/core.c
|
|
@ -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!
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
51
src/external/cgltf.h
vendored
51
src/external/cgltf.h
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
BIN
src/libraylib.a
BIN
src/libraylib.a
Binary file not shown.
24
src/models.c
24
src/models.c
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
// 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);
|
cgltf_free(&data);
|
||||||
|
}
|
||||||
|
else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName);
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
src/raudio.c
30
src/raudio.c
|
|
@ -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
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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:
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
20
src/text.c
20
src/text.c
|
|
@ -309,6 +309,7 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
|
||||||
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
|
||||||
|
|
@ -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,12 +544,16 @@ 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 };
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
266
src/textures.c
266
src/textures.c
|
|
@ -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)
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
@ -3173,12 +3193,14 @@ 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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user