Merge branch 'master' of https://github.com/raysan5/raylib into raysan
This commit is contained in:
commit
2469f46950
|
|
@ -12,6 +12,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to
|
|||
- [cray](https://github.com/tapgg/cray) : raylib **Crystal** binding
|
||||
- [Graphics::Raylib](https://metacpan.org/pod/Graphics::Raylib) : raylib **Perl** wrapper
|
||||
- [raylib-pascal](https://github.com/drezgames/raylib-pascal) - raylib **Pascal** binding
|
||||
- [raylib-pas](https://github.com/tazdij/raylib-pas) - raylib **Pascal** binding (including rlgl & raymath)
|
||||
- [Raylib-cs](https://github.com/ChrisDill/Raylib-cs) : raylib **C#** binding
|
||||
- [RaylibSharp](https://github.com/TheLumaio/RaylibSharp) : raylib **C#** binding
|
||||
- [raylib-ruby-ffi](https://github.com/D3nX/raylib-ruby-ffi) : raylib **Ruby** binding
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ EXAMPLES = \
|
|||
shaders/shaders_eratosthenes \
|
||||
shaders/shaders_basic_lighting \
|
||||
shaders/shaders_fog \
|
||||
shaders/shaders_simple \
|
||||
shaders/shaders_simple_mask \
|
||||
audio/audio_module_playing \
|
||||
audio/audio_music_stream \
|
||||
audio/audio_raw_stream \
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ varying vec4 fragColor;
|
|||
|
||||
uniform vec3 viewEye;
|
||||
uniform vec3 viewCenter;
|
||||
uniform vec3 viewUp;
|
||||
uniform float deltaTime;
|
||||
uniform float runTime;
|
||||
uniform vec2 resolution;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ out vec4 finalColor;
|
|||
|
||||
uniform vec3 viewEye;
|
||||
uniform vec3 viewCenter;
|
||||
uniform vec3 viewUp;
|
||||
uniform float deltaTime;
|
||||
uniform float runTime;
|
||||
uniform vec2 resolution;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@ int main(void)
|
|||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
int screenWidth = 800;
|
||||
int screenHeight = 450;
|
||||
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - raymarching shapes");
|
||||
|
||||
Camera camera = { 0 };
|
||||
|
|
@ -48,12 +49,10 @@ int main(void)
|
|||
// Get shader locations for required uniforms
|
||||
int viewEyeLoc = GetShaderLocation(shader, "viewEye");
|
||||
int viewCenterLoc = GetShaderLocation(shader, "viewCenter");
|
||||
int viewUpLoc = GetShaderLocation(shader, "viewUp");
|
||||
int deltaTimeLoc = GetShaderLocation(shader, "deltaTime");
|
||||
int runTimeLoc = GetShaderLocation(shader, "runTime");
|
||||
int resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||
|
||||
float resolution[2] = { screenWidth, screenHeight };
|
||||
float resolution[2] = { (float)screenWidth, (float)screenHeight };
|
||||
SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2);
|
||||
|
||||
float runTime = 0.0f;
|
||||
|
|
@ -64,13 +63,22 @@ int main(void)
|
|||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Check if screen is resized
|
||||
//----------------------------------------------------------------------------------
|
||||
if(IsWindowResized())
|
||||
{
|
||||
screenWidth = GetScreenWidth();
|
||||
screenHeight = GetScreenHeight();
|
||||
float resolution[2] = { (float)screenWidth, (float)screenHeight };
|
||||
SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2);
|
||||
}
|
||||
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera); // Update camera
|
||||
|
||||
float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
|
||||
float cameraTarget[3] = { camera.target.x, camera.target.y, camera.target.z };
|
||||
float cameraUp[3] = { camera.up.x, camera.up.y, camera.up.z };
|
||||
|
||||
float deltaTime = GetFrameTime();
|
||||
runTime += deltaTime;
|
||||
|
|
@ -78,8 +86,6 @@ int main(void)
|
|||
// Set shader required uniform values
|
||||
SetShaderValue(shader, viewEyeLoc, cameraPos, UNIFORM_VEC3);
|
||||
SetShaderValue(shader, viewCenterLoc, cameraTarget, UNIFORM_VEC3);
|
||||
SetShaderValue(shader, viewUpLoc, cameraUp, UNIFORM_VEC3);
|
||||
SetShaderValue(shader, deltaTimeLoc, &deltaTime, UNIFORM_FLOAT);
|
||||
SetShaderValue(shader, runTimeLoc, &runTime, UNIFORM_FLOAT);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -95,7 +101,7 @@ int main(void)
|
|||
DrawRectangle(0, 0, screenWidth, screenHeight, WHITE);
|
||||
EndShaderMode();
|
||||
|
||||
DrawText("(c) Raymarching shader by Iñigo Quilez. MIT License.", screenWidth - 280, screenHeight - 20, 10, GRAY);
|
||||
DrawText("(c) Raymarching shader by Iñigo Quilez. MIT License.", screenWidth - 280, screenHeight - 20, 10, BLACK);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
|
|||
31
src/core.c
31
src/core.c
|
|
@ -1796,30 +1796,22 @@ bool FileExists(const char *fileName)
|
|||
bool IsFileExtension(const char *fileName, const char *ext)
|
||||
{
|
||||
bool result = false;
|
||||
const char *fileExt;
|
||||
const char *fileExt = GetExtension(fileName);
|
||||
|
||||
if ((fileExt = strrchr(fileName, '.')) != NULL)
|
||||
if (fileExt != NULL)
|
||||
{
|
||||
int extCount = 0;
|
||||
const char **checkExts = TextSplit(ext, ';', &extCount);
|
||||
|
||||
for (int i = 0; i < extCount; i++)
|
||||
{
|
||||
if (strcmp(fileExt, checkExts[i] + 1) == 0)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
result = true;
|
||||
int extLen = strlen(ext);
|
||||
|
||||
if (strlen(fileExt) == extLen)
|
||||
{
|
||||
for (int i = 0; i < extLen; i++)
|
||||
{
|
||||
if (tolower(fileExt[i]) != tolower(ext[i]))
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else result = false;
|
||||
#else
|
||||
if (strcmp(fileExt, ext) == 0) result = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1986,11 +1978,12 @@ void ClearDirectoryFiles(void)
|
|||
{
|
||||
if (dirFilesCount > 0)
|
||||
{
|
||||
for (int i = 0; i < dirFilesCount; i++) RL_FREE(dirFilesPath[i]);
|
||||
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesPath[i]);
|
||||
|
||||
RL_FREE(dirFilesPath);
|
||||
dirFilesCount = 0;
|
||||
}
|
||||
|
||||
dirFilesCount = 0;
|
||||
}
|
||||
|
||||
// Change working directory, returns true if success
|
||||
|
|
|
|||
18
src/external/stb_image.h
vendored
18
src/external/stb_image.h
vendored
|
|
@ -1,4 +1,4 @@
|
|||
/* stb_image - v2.22 - public domain image loader - http://nothings.org/stb
|
||||
/* stb_image - v2.23 - public domain image loader - http://nothings.org/stb
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Do this:
|
||||
|
|
@ -48,6 +48,7 @@ LICENSE
|
|||
|
||||
RECENT REVISION HISTORY:
|
||||
|
||||
2.23 (2019-08-11) fix clang static analysis warning
|
||||
2.22 (2019-03-04) gif fixes, fix warnings
|
||||
2.21 (2019-02-25) fix typo in comment
|
||||
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
|
||||
|
|
@ -5079,7 +5080,7 @@ static int stbi__high_bit(unsigned int z)
|
|||
if (z >= 0x00100) { n += 8; z >>= 8; }
|
||||
if (z >= 0x00010) { n += 4; z >>= 4; }
|
||||
if (z >= 0x00004) { n += 2; z >>= 2; }
|
||||
if (z >= 0x00002) { n += 1; z >>= 1; }
|
||||
if (z >= 0x00002) { n += 1;/* >>= 1;*/ }
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
@ -5237,6 +5238,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
|
|||
psize = (info.offset - 14 - info.hsz) >> 2;
|
||||
}
|
||||
|
||||
if (info.bpp == 24 && ma == 0xff000000)
|
||||
s->img_n = 3;
|
||||
else
|
||||
s->img_n = ma ? 4 : 3;
|
||||
if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
|
||||
target = req_comp;
|
||||
|
|
@ -5547,6 +5551,8 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
|
|||
int RLE_repeating = 0;
|
||||
int read_next_pixel = 1;
|
||||
STBI_NOTUSED(ri);
|
||||
STBI_NOTUSED(tga_x_origin); // @TODO
|
||||
STBI_NOTUSED(tga_y_origin); // @TODO
|
||||
|
||||
// do a tiny bit of precessing
|
||||
if ( tga_image_type >= 8 )
|
||||
|
|
@ -5710,6 +5716,7 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
|
|||
// Microsoft's C compilers happy... [8^(
|
||||
tga_palette_start = tga_palette_len = tga_palette_bits =
|
||||
tga_x_origin = tga_y_origin = 0;
|
||||
STBI_NOTUSED(tga_palette_start);
|
||||
// OK, done
|
||||
return tga_data;
|
||||
}
|
||||
|
|
@ -6936,7 +6943,12 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
|
|||
return 0;
|
||||
if (x) *x = s->img_x;
|
||||
if (y) *y = s->img_y;
|
||||
if (comp) *comp = info.ma ? 4 : 3;
|
||||
if (comp) {
|
||||
if (info.bpp == 24 && info.ma == 0xff000000)
|
||||
*comp = 3;
|
||||
else
|
||||
*comp = info.ma ? 4 : 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
6
src/external/stb_image_write.h
vendored
6
src/external/stb_image_write.h
vendored
|
|
@ -1,4 +1,4 @@
|
|||
/* stb_image_write - v1.13 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||
/* stb_image_write - v1.13 - public domain - http://nothings.org/stb
|
||||
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
|
|
@ -868,7 +868,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
|
|||
unsigned int bitbuf=0;
|
||||
int i,j, bitcount=0;
|
||||
unsigned char *out = NULL;
|
||||
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
|
||||
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));
|
||||
if (hash_table == NULL)
|
||||
return NULL;
|
||||
if (quality < 5) quality = 5;
|
||||
|
|
@ -1530,6 +1530,8 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
|
|||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
/* Revision history
|
||||
1.11 (2019-08-11)
|
||||
|
||||
1.10 (2019-02-07)
|
||||
support utf8 filenames in Windows; fix warnings and platform ifdefs
|
||||
1.09 (2018-02-11)
|
||||
|
|
|
|||
61
src/external/stb_perlin.h
vendored
61
src/external/stb_perlin.h
vendored
|
|
@ -81,6 +81,7 @@ extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap
|
|||
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
|
||||
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||
extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -321,6 +322,66 @@ float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity,
|
|||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
int px = stb__perlin_fastfloor(x);
|
||||
int py = stb__perlin_fastfloor(y);
|
||||
int pz = stb__perlin_fastfloor(z);
|
||||
int x_wrap2 = (x_wrap ? x_wrap : 256);
|
||||
int y_wrap2 = (y_wrap ? y_wrap : 256);
|
||||
int z_wrap2 = (z_wrap ? z_wrap : 256);
|
||||
int x0 = px % x_wrap2, x1;
|
||||
int y0 = py % y_wrap2, y1;
|
||||
int z0 = pz % z_wrap2, z1;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
if (x0 < 0) x0 += x_wrap2;
|
||||
if (y0 < 0) y0 += y_wrap2;
|
||||
if (z0 < 0) z0 += z_wrap2;
|
||||
x1 = (x0+1) % x_wrap2;
|
||||
y1 = (y0+1) % y_wrap2;
|
||||
z1 = (z0+1) % z_wrap2;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0];
|
||||
r0 = stb__perlin_randtab[r0+seed];
|
||||
r1 = stb__perlin_randtab[x1];
|
||||
r1 = stb__perlin_randtab[r1+seed];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
#endif // STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
|
|
|
|||
30
src/external/stb_truetype.h
vendored
30
src/external/stb_truetype.h
vendored
|
|
@ -1,5 +1,5 @@
|
|||
// stb_truetype.h - v1.21 - public domain
|
||||
// authored from 2009-2016 by Sean Barrett / RAD Game Tools
|
||||
// stb_truetype.h - v1.22 - public domain
|
||||
// authored from 2009-2019 by Sean Barrett / RAD Game Tools
|
||||
//
|
||||
// This library processes TrueType files:
|
||||
// parse files
|
||||
|
|
@ -46,9 +46,11 @@
|
|||
// Rob Loach Cort Stratton
|
||||
// Kenney Phillis Jr. github:oyvindjam
|
||||
// Brian Costabile github:vassvik
|
||||
// Ken Voskuil (kaesve) Ryan Griege
|
||||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||
// 1.21 (2019-02-25) fix warning
|
||||
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
||||
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
|
||||
|
|
@ -2540,8 +2542,7 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int
|
|||
|
||||
if (info->gpos)
|
||||
xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
|
||||
|
||||
if (info->kern)
|
||||
else if (info->kern)
|
||||
xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
|
||||
|
||||
return xAdvance;
|
||||
|
|
@ -3968,6 +3969,7 @@ static float stbtt__oversample_shift(int oversample)
|
|||
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||
{
|
||||
int i,j,k;
|
||||
int missing_glyph_added = 0;
|
||||
|
||||
k=0;
|
||||
for (i=0; i < num_ranges; ++i) {
|
||||
|
|
@ -3979,7 +3981,7 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
|
|||
int x0,y0,x1,y1;
|
||||
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
||||
int glyph = stbtt_FindGlyphIndex(info, codepoint);
|
||||
if (glyph == 0 && spc->skip_missing) {
|
||||
if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {
|
||||
rects[k].w = rects[k].h = 0;
|
||||
} else {
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
|
||||
|
|
@ -3989,6 +3991,8 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
|
|||
&x0,&y0,&x1,&y1);
|
||||
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
|
||||
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
|
||||
if (glyph == 0)
|
||||
missing_glyph_added = 1;
|
||||
}
|
||||
++k;
|
||||
}
|
||||
|
|
@ -4023,7 +4027,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info
|
|||
// rects array must be big enough to accommodate all characters in the given ranges
|
||||
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||
{
|
||||
int i,j,k, return_value = 1;
|
||||
int i,j,k, missing_glyph = -1, return_value = 1;
|
||||
|
||||
// save current values
|
||||
int old_h_over = spc->h_oversample;
|
||||
|
|
@ -4088,6 +4092,13 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const
|
|||
bc->yoff = (float) y0 * recip_v + sub_y;
|
||||
bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
|
||||
bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
|
||||
|
||||
if (glyph == 0)
|
||||
missing_glyph = j;
|
||||
} else if (spc->skip_missing) {
|
||||
return_value = 0;
|
||||
} else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {
|
||||
ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];
|
||||
} else {
|
||||
return_value = 0; // if any fail, report failure
|
||||
}
|
||||
|
|
@ -4389,12 +4400,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
|||
int w,h;
|
||||
unsigned char *data;
|
||||
|
||||
// if one scale is 0, use same scale for both
|
||||
if (scale_x == 0) scale_x = scale_y;
|
||||
if (scale_y == 0) {
|
||||
if (scale_x == 0) return NULL; // if both scales are 0, return NULL
|
||||
scale_y = scale_x;
|
||||
}
|
||||
if (scale == 0) return NULL;
|
||||
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
|
||||
|
||||
|
|
|
|||
213
src/models.c
213
src/models.c
|
|
@ -2385,8 +2385,18 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
|
|||
|
||||
for (int i = 0; i < model.meshCount; i++)
|
||||
{
|
||||
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = tint;
|
||||
// TODO: Review color + tint premultiplication mechanism
|
||||
Color color = model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color;
|
||||
|
||||
Color colorTint = WHITE;
|
||||
colorTint.r = (((float)color.r/255.0)*((float)tint.r/255.0))*255;
|
||||
colorTint.g = (((float)color.g/255.0)*((float)tint.g/255.0))*255;
|
||||
colorTint.b = (((float)color.b/255.0)*((float)tint.b/255.0))*255;
|
||||
colorTint.a = (((float)color.a/255.0)*((float)tint.a/255.0))*255;
|
||||
|
||||
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = colorTint;
|
||||
rlDrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
|
||||
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = color;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3344,6 +3354,88 @@ static unsigned char *DecodeBase64(char *input, int *size)
|
|||
return buf;
|
||||
}
|
||||
|
||||
// Load texture from cgltf_image
|
||||
static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
|
||||
{
|
||||
Texture texture = { 0 };
|
||||
|
||||
if (image->uri)
|
||||
{
|
||||
if ((strlen(image->uri) > 5) &&
|
||||
(image->uri[0] == 'd') &&
|
||||
(image->uri[1] == 'a') &&
|
||||
(image->uri[2] == 't') &&
|
||||
(image->uri[3] == 'a') &&
|
||||
(image->uri[4] == ':'))
|
||||
{
|
||||
// Data URI
|
||||
// Format: data:<mediatype>;base64,<data>
|
||||
|
||||
// Find the comma
|
||||
int i = 0;
|
||||
while ((image->uri[i] != ',') && (image->uri[i] != 0)) i++;
|
||||
|
||||
if (image->uri[i] == 0) TraceLog(LOG_WARNING, "CGLTF Image: Invalid data URI");
|
||||
else
|
||||
{
|
||||
int size;
|
||||
unsigned char *data = DecodeBase64(image->uri + i + 1, &size);
|
||||
|
||||
int w, h;
|
||||
unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
|
||||
|
||||
Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
|
||||
|
||||
// TODO: Tint shouldn't be applied here!
|
||||
ImageColorTint(&rimage, tint);
|
||||
texture = LoadTextureFromImage(rimage);
|
||||
UnloadImage(rimage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Image rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
|
||||
|
||||
// TODO: Tint shouldn't be applied here!
|
||||
ImageColorTint(&rimage, tint);
|
||||
texture = LoadTextureFromImage(rimage);
|
||||
UnloadImage(rimage);
|
||||
}
|
||||
}
|
||||
else if (image->buffer_view)
|
||||
{
|
||||
unsigned char *data = RL_MALLOC(image->buffer_view->size);
|
||||
int n = image->buffer_view->offset;
|
||||
int stride = image->buffer_view->stride ? image->buffer_view->stride : 1;
|
||||
|
||||
for (int i = 0; i < image->buffer_view->size; i++)
|
||||
{
|
||||
data[i] = ((unsigned char *)image->buffer_view->buffer->data)[n];
|
||||
n += stride;
|
||||
}
|
||||
|
||||
int w, h;
|
||||
unsigned char *raw = stbi_load_from_memory(data, image->buffer_view->size, &w, &h, NULL, 4);
|
||||
free(data);
|
||||
|
||||
Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
|
||||
free(raw);
|
||||
|
||||
// TODO: Tint shouldn't be applied here!
|
||||
ImageColorTint(&rimage, tint);
|
||||
texture = LoadTextureFromImage(rimage);
|
||||
UnloadImage(rimage);
|
||||
}
|
||||
else
|
||||
{
|
||||
Image rimage = LoadImageEx(&tint, 1, 1);
|
||||
texture = LoadTextureFromImage(rimage);
|
||||
UnloadImage(rimage);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Load glTF mesh data
|
||||
static Model LoadGLTF(const char *fileName)
|
||||
{
|
||||
|
|
@ -3409,9 +3501,7 @@ static Model LoadGLTF(const char *fileName)
|
|||
|
||||
// Read data buffers
|
||||
result = cgltf_load_buffers(&options, data, fileName);
|
||||
if (result != cgltf_result_success) {
|
||||
TraceLog(LOG_INFO, "[%s][%s] Error loading mesh/material buffers", fileName, (data->file_type == 2)? "glb" : "gltf");
|
||||
}
|
||||
if (result != cgltf_result_success) TraceLog(LOG_INFO, "[%s][%s] Error loading mesh/material buffers", fileName, (data->file_type == 2)? "glb" : "gltf");
|
||||
|
||||
int primitivesCount = 0;
|
||||
|
||||
|
|
@ -3426,106 +3516,55 @@ static Model LoadGLTF(const char *fileName)
|
|||
|
||||
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int));
|
||||
|
||||
//For each material
|
||||
for (int i = 0; i < model.materialCount - 1; i++)
|
||||
{
|
||||
Color tint = WHITE;
|
||||
Texture2D texture = { 0 };
|
||||
model.materials[i] = LoadMaterialDefault();
|
||||
Color tint = (Color){ 255, 255, 255, 255 };
|
||||
const char *texPath = GetDirectoryPath(fileName);
|
||||
|
||||
//Ensure material follows raylib support for PBR (metallic/roughness flow)
|
||||
if (data->materials[i].has_pbr_metallic_roughness)
|
||||
{
|
||||
tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255.99f);
|
||||
tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255.99f);
|
||||
tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255.99f);
|
||||
tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255.99f);
|
||||
}
|
||||
else
|
||||
float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
|
||||
float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
|
||||
|
||||
// NOTE: Material name not used for the moment
|
||||
//if (model.materials[i].name && data->materials[i].name) strcpy(model.materials[i].name, data->materials[i].name);
|
||||
|
||||
// TODO: REview: shouldn't these be *255 ???
|
||||
tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
|
||||
tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
|
||||
tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
|
||||
tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
|
||||
|
||||
model.materials[i].maps[MAP_ROUGHNESS].color = tint;
|
||||
|
||||
if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
|
||||
{
|
||||
tint.r = 1.0f;
|
||||
tint.g = 1.0f;
|
||||
tint.b = 1.0f;
|
||||
tint.a = 1.0f;
|
||||
model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
|
||||
}
|
||||
|
||||
if (data->materials[i].has_pbr_metallic_roughness)
|
||||
// NOTE: Tint isn't need for other textures.. pass null or clear?
|
||||
// Just set as white, multiplying by white has no effect
|
||||
tint = WHITE;
|
||||
|
||||
if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
|
||||
{
|
||||
cgltf_image *img = data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image;
|
||||
|
||||
if (img->uri)
|
||||
{
|
||||
if ((strlen(img->uri) > 5) &&
|
||||
(img->uri[0] == 'd') &&
|
||||
(img->uri[1] == 'a') &&
|
||||
(img->uri[2] == 't') &&
|
||||
(img->uri[3] == 'a') &&
|
||||
(img->uri[4] == ':'))
|
||||
{
|
||||
// Data URI
|
||||
// Format: data:<mediatype>;base64,<data>
|
||||
|
||||
// Find the comma
|
||||
int i = 0;
|
||||
while ((img->uri[i] != ',') && (img->uri[i] != 0)) i++;
|
||||
|
||||
if (img->uri[i] == 0) TraceLog(LOG_WARNING, "[%s] Invalid data URI", fileName);
|
||||
else
|
||||
{
|
||||
int size;
|
||||
unsigned char *data = DecodeBase64(img->uri + i + 1, &size);
|
||||
|
||||
int w, h;
|
||||
unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
|
||||
|
||||
Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
|
||||
ImageColorTint(&image, tint);
|
||||
texture = LoadTextureFromImage(image);
|
||||
UnloadImage(image);
|
||||
model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *textureName = img->uri;
|
||||
char *texturePath = RL_MALLOC(strlen(texPath) + strlen(textureName) + 2);
|
||||
strcpy(texturePath, texPath);
|
||||
strcat(texturePath, "/");
|
||||
strcat(texturePath, textureName);
|
||||
model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
|
||||
model.materials[i].maps[MAP_METALNESS].value = metallic;
|
||||
|
||||
Image image = LoadImage(texturePath);
|
||||
ImageColorTint(&image, tint);
|
||||
texture = LoadTextureFromImage(image);
|
||||
UnloadImage(image);
|
||||
RL_FREE(texturePath);
|
||||
}
|
||||
}
|
||||
else if (img->buffer_view)
|
||||
if (data->materials[i].normal_texture.texture)
|
||||
{
|
||||
unsigned char *data = RL_MALLOC(img->buffer_view->size);
|
||||
int n = img->buffer_view->offset;
|
||||
int stride = img->buffer_view->stride ? img->buffer_view->stride : 1;
|
||||
|
||||
for (int i = 0; i < img->buffer_view->size; i++)
|
||||
{
|
||||
data[i] = ((unsigned char *)img->buffer_view->buffer->data)[n];
|
||||
n += stride;
|
||||
model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
|
||||
}
|
||||
|
||||
int w, h;
|
||||
unsigned char *raw = stbi_load_from_memory(data, img->buffer_view->size, &w, &h, NULL, 4);
|
||||
|
||||
Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
|
||||
ImageColorTint(&image, tint);
|
||||
texture = LoadTextureFromImage(image);
|
||||
UnloadImage(image);
|
||||
}
|
||||
else
|
||||
if (data->materials[i].occlusion_texture.texture)
|
||||
{
|
||||
Image image = LoadImageEx(&tint, 1, 1);
|
||||
texture = LoadTextureFromImage(image);
|
||||
UnloadImage(image);
|
||||
model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
|
||||
}
|
||||
|
||||
model.materials[i] = LoadMaterialDefault();
|
||||
model.materials[i].maps[MAP_DIFFUSE].texture = texture;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -474,7 +474,11 @@ static void InitAudioBufferPool()
|
|||
// Close the audio buffers pool
|
||||
static void CloseAudioBufferPool()
|
||||
{
|
||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) RL_FREE(audioBufferPool[i]);
|
||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
||||
{
|
||||
RL_FREE(audioBufferPool[i]->buffer);
|
||||
RL_FREE(audioBufferPool[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
|
|||
12
src/raylib.h
12
src/raylib.h
|
|
@ -1188,14 +1188,11 @@ RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontS
|
|||
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
|
||||
RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font
|
||||
RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on font
|
||||
RLAPI int GetNextCodepoint(const char *text, int *bytesProcessed); // Returns next codepoint in a UTF8 encoded string
|
||||
// NOTE: 0x3f('?') is returned on failure
|
||||
|
||||
// Text strings management functions
|
||||
// Text strings management functions (no utf8 strings, only byte chars)
|
||||
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
|
||||
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
|
||||
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
|
||||
RLAPI unsigned int TextCountCodepoints(const char *text); // Get total number of characters (codepoints) in a UTF8 encoded string
|
||||
RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf style)
|
||||
RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string
|
||||
RLAPI char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (memory should be freed!)
|
||||
|
|
@ -1208,6 +1205,12 @@ RLAPI const char *TextToUpper(const char *text); // Get upp
|
|||
RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string
|
||||
RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
|
||||
RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported)
|
||||
RLAPI const char *TextToUtf8(int codepoint, int *byteLength); // Encode codepoint into utf8 text (char array length returned as parameter)
|
||||
|
||||
// UTF8 text strings management functions
|
||||
RLAPI int *GetCodepoints(const char *text, int *count); // Get all codepoints in a string, codepoints count returned by parameters
|
||||
RLAPI int GetCodepointsCount(const char *text); // Get total number of characters (codepoints) in a UTF8 encoded string
|
||||
RLAPI int GetNextCodepoint(const char *text, int *bytesProcessed); // Returns next codepoint in a UTF8 encoded string; 0x3f('?') is returned on failure
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Basic 3d Shapes Drawing Functions (Module: models)
|
||||
|
|
@ -1319,6 +1322,7 @@ RLAPI void SetShaderValueTexture(Shader shader, int uniformLoc, Texture2D textur
|
|||
RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
|
||||
RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
|
||||
RLAPI Matrix GetMatrixModelview(void); // Get internal modelview matrix
|
||||
RLAPI Matrix GetMatrixProjection(void); // Get internal projection matrix
|
||||
|
||||
// Texture maps generation (PBR)
|
||||
// NOTE: Required shaders should be provided
|
||||
|
|
|
|||
21
src/rlgl.h
21
src/rlgl.h
|
|
@ -3155,6 +3155,23 @@ void SetMatrixProjection(Matrix proj)
|
|||
#endif
|
||||
}
|
||||
|
||||
// Return internal projection matrix
|
||||
Matrix GetMatrixProjection(void) {
|
||||
#if defined(GRAPHICS_API_OPENGL_11)
|
||||
float mat[16];
|
||||
glGetFloatv(GL_PROJECTION_MATRIX,mat);
|
||||
Matrix m;
|
||||
m.m0 = mat[0]; m.m1 = mat[1]; m.m2 = mat[2]; m.m3 = mat[3];
|
||||
m.m4 = mat[4]; m.m5 = mat[5]; m.m6 = mat[6]; m.m7 = mat[7];
|
||||
m.m8 = mat[8]; m.m9 = mat[9]; m.m10 = mat[10]; m.m11 = mat[11];
|
||||
m.m12 = mat[12]; m.m13 = mat[13]; m.m14 = mat[14]; m.m15 = mat[15];
|
||||
return m;
|
||||
#else
|
||||
return projection;
|
||||
#endif
|
||||
#
|
||||
}
|
||||
|
||||
// Set a custom modelview matrix (replaces internal modelview matrix)
|
||||
void SetMatrixModelview(Matrix view)
|
||||
{
|
||||
|
|
@ -3170,6 +3187,10 @@ Matrix GetMatrixModelview(void)
|
|||
#if defined(GRAPHICS_API_OPENGL_11)
|
||||
float mat[16];
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, mat);
|
||||
matrix.m0 = mat[0]; matrix.m1 = mat[1]; matrix.m2 = mat[2]; matrix.m3 = mat[3];
|
||||
matrix.m4 = mat[4]; matrix.m5 = mat[5]; matrix.m6 = mat[6]; matrix.m7 = mat[7];
|
||||
matrix.m8 = mat[8]; matrix.m9 = mat[9]; matrix.m10 = mat[10]; matrix.m11 = mat[11];
|
||||
matrix.m12 = mat[12]; matrix.m13 = mat[13]; matrix.m14 = mat[14]; matrix.m15 = mat[15];
|
||||
#else
|
||||
matrix = modelview;
|
||||
#endif
|
||||
|
|
|
|||
383
src/text.c
383
src/text.c
|
|
@ -10,9 +10,19 @@
|
|||
* supported by default, to remove support, just comment unrequired #define in this module
|
||||
*
|
||||
* #define SUPPORT_DEFAULT_FONT
|
||||
* Load default raylib font on initialization to be used by DrawText() and MeasureText().
|
||||
* If no default font loaded, DrawTextEx() and MeasureTextEx() are required.
|
||||
*
|
||||
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
||||
* TextSplit() function static buffer max size
|
||||
*
|
||||
* #define TEXTSPLIT_MAX_SUBSTRINGS_COUNT
|
||||
* TextSplit() function static substrings pointers array (pointing to static buffer)
|
||||
*
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
* stb_truetype - Load TTF file and rasterize characters data
|
||||
* stb_rect_pack - Rectangles packing algorythms, required for font atlas generation
|
||||
*
|
||||
*
|
||||
* LICENSE: zlib/libpng
|
||||
|
|
@ -63,7 +73,18 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers of some Text*() functions
|
||||
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
||||
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal()
|
||||
|
||||
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints
|
||||
|
||||
#if !defined(TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH)
|
||||
#define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH 1024 // Size of static buffer: TextSplit()
|
||||
#endif
|
||||
|
||||
#if !defined(TEXTSPLIT_MAX_SUBSTRINGS_COUNT)
|
||||
#define TEXTSPLIT_MAX_SUBSTRINGS_COUNT 128 // Size of static pointers array: TextSplit()
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
|
|
@ -282,7 +303,7 @@ Font LoadFont(const char *fileName)
|
|||
Font font = { 0 };
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||
if (IsFileExtension(fileName, ".ttf") || IsFileExtension(fileName, ".otf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, NULL, DEFAULT_TTF_NUMCHARS);
|
||||
if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, NULL, DEFAULT_TTF_NUMCHARS);
|
||||
else
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_FNT)
|
||||
|
|
@ -756,120 +777,6 @@ void DrawFPS(int posX, int posY)
|
|||
DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, LIME);
|
||||
}
|
||||
|
||||
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
|
||||
// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
|
||||
// Total number of bytes processed are returned as a parameter
|
||||
// NOTE: the standard says U+FFFD should be returned in case of errors
|
||||
// but that character is not supported by the default font in raylib
|
||||
// TODO: optimize this code for speed!!
|
||||
int GetNextCodepoint(const char *text, int *bytesProcessed)
|
||||
{
|
||||
/*
|
||||
UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt
|
||||
|
||||
Char. number range | UTF-8 octet sequence
|
||||
(hexadecimal) | (binary)
|
||||
--------------------+---------------------------------------------
|
||||
0000 0000-0000 007F | 0xxxxxxx
|
||||
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
|
||||
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
||||
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
*/
|
||||
|
||||
// NOTE: on decode errors we return as soon as possible
|
||||
|
||||
int code = 0x3f; // Codepoint (defaults to '?')
|
||||
int octet = (unsigned char)(text[0]); // The first UTF8 octet
|
||||
*bytesProcessed = 1;
|
||||
|
||||
if (octet <= 0x7f)
|
||||
{
|
||||
// Only one octet (ASCII range x00-7F)
|
||||
code = text[0];
|
||||
}
|
||||
else if ((octet & 0xe0) == 0xc0)
|
||||
{
|
||||
// Two octets
|
||||
// [0]xC2-DF [1]UTF8-tail(x80-BF)
|
||||
unsigned char octet1 = text[1];
|
||||
|
||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||
|
||||
if ((octet >= 0xc2) && (octet <= 0xdf))
|
||||
{
|
||||
code = ((octet & 0x1f) << 6) | (octet1 & 0x3f);
|
||||
*bytesProcessed = 2;
|
||||
}
|
||||
}
|
||||
else if ((octet & 0xf0) == 0xe0)
|
||||
{
|
||||
// Three octets
|
||||
unsigned char octet1 = text[1];
|
||||
unsigned char octet2 = '\0';
|
||||
|
||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||
|
||||
octet2 = text[2];
|
||||
|
||||
if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
|
||||
|
||||
/*
|
||||
[0]xE0 [1]xA0-BF [2]UTF8-tail(x80-BF)
|
||||
[0]xE1-EC [1]UTF8-tail [2]UTF8-tail(x80-BF)
|
||||
[0]xED [1]x80-9F [2]UTF8-tail(x80-BF)
|
||||
[0]xEE-EF [1]UTF8-tail [2]UTF8-tail(x80-BF)
|
||||
*/
|
||||
|
||||
if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
|
||||
((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; }
|
||||
|
||||
if ((octet >= 0xe0) && (0 <= 0xef))
|
||||
{
|
||||
code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
|
||||
*bytesProcessed = 3;
|
||||
}
|
||||
}
|
||||
else if ((octet & 0xf8) == 0xf0)
|
||||
{
|
||||
// Four octets
|
||||
if (octet > 0xf4) return code;
|
||||
|
||||
unsigned char octet1 = text[1];
|
||||
unsigned char octet2 = '\0';
|
||||
unsigned char octet3 = '\0';
|
||||
|
||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||
|
||||
octet2 = text[2];
|
||||
|
||||
if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
|
||||
|
||||
octet3 = text[3];
|
||||
|
||||
if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *bytesProcessed = 4; return code; } // Unexpected sequence
|
||||
|
||||
/*
|
||||
[0]xF0 [1]x90-BF [2]UTF8-tail [3]UTF8-tail
|
||||
[0]xF1-F3 [1]UTF8-tail [2]UTF8-tail [3]UTF8-tail
|
||||
[0]xF4 [1]x80-8F [2]UTF8-tail [3]UTF8-tail
|
||||
*/
|
||||
|
||||
if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) ||
|
||||
((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||
|
||||
if (octet >= 0xf0)
|
||||
{
|
||||
code = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f);
|
||||
*bytesProcessed = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (code > 0x10ffff) code = 0x3f; // Codepoints after U+10ffff are invalid
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
// Draw text (using default font)
|
||||
// NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used
|
||||
// NOTE: chars spacing is proportional to fontSize
|
||||
|
|
@ -1194,27 +1101,6 @@ unsigned int TextLength(const char *text)
|
|||
return length;
|
||||
}
|
||||
|
||||
// Returns total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found
|
||||
// NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead
|
||||
unsigned int TextCountCodepoints(const char *text)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
char *ptr = (char *)&text[0];
|
||||
|
||||
while (*ptr != '\0')
|
||||
{
|
||||
int next = 0;
|
||||
int letter = GetNextCodepoint(ptr, &next);
|
||||
|
||||
if (letter == 0x3f) ptr += 1;
|
||||
else ptr += next;
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// Formatting of text with variables to 'embed'
|
||||
const char *TextFormat(const char *text, ...)
|
||||
{
|
||||
|
|
@ -1362,14 +1248,12 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
|||
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
|
||||
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
|
||||
// all used memory is static... it has some limitations:
|
||||
// 1. Maximum number of possible split strings is set by MAX_SUBSTRINGS_COUNT
|
||||
// 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
|
||||
// 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_SUBSTRINGS_COUNT
|
||||
// 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
||||
|
||||
#define MAX_SUBSTRINGS_COUNT 64
|
||||
|
||||
static const char *result[MAX_SUBSTRINGS_COUNT] = { NULL };
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
static const char *result[TEXTSPLIT_MAX_SUBSTRINGS_COUNT] = { NULL };
|
||||
static char buffer[TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
result[0] = buffer;
|
||||
int counter = 0;
|
||||
|
|
@ -1389,7 +1273,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
|||
result[counter] = buffer + i + 1;
|
||||
counter++;
|
||||
|
||||
if (counter == MAX_SUBSTRINGS_COUNT) break;
|
||||
if (counter == TEXTSPLIT_MAX_SUBSTRINGS_COUNT) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1492,6 +1376,200 @@ int TextToInteger(const char *text)
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Encode codepoint into utf8 text (char array length returned as parameter)
|
||||
RLAPI const char *TextToUtf8(int codepoint, int *byteLength)
|
||||
{
|
||||
static char utf8[6] = { 0 };
|
||||
int length = 0;
|
||||
|
||||
if (codepoint <= 0x7f)
|
||||
{
|
||||
utf8[0] = (char)codepoint;
|
||||
length = 1;
|
||||
}
|
||||
else if (codepoint <= 0x7ff)
|
||||
{
|
||||
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
|
||||
utf8[1] = (char)((codepoint & 0x3f) | 0x80);
|
||||
length = 2;
|
||||
}
|
||||
else if (codepoint <= 0xffff)
|
||||
{
|
||||
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
|
||||
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
|
||||
utf8[2] = (char)((codepoint & 0x3f) | 0x80);
|
||||
length = 3;
|
||||
}
|
||||
else if (codepoint <= 0x10ffff)
|
||||
{
|
||||
utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
|
||||
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
|
||||
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
|
||||
utf8[3] = (char)((codepoint & 0x3f) | 0x80);
|
||||
length = 4;
|
||||
}
|
||||
|
||||
*byteLength = length;
|
||||
|
||||
return utf8;
|
||||
}
|
||||
|
||||
|
||||
// Get all codepoints in a string, codepoints count returned by parameters
|
||||
int *GetCodepoints(const char *text, int *count)
|
||||
{
|
||||
static int codepoints[MAX_TEXT_UNICODE_CHARS] = { 0 };
|
||||
memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int));
|
||||
|
||||
int bytesProcessed = 0;
|
||||
int textLength = strlen(text);
|
||||
int codepointsCount = 0;
|
||||
|
||||
for (int i = 0; i < textLength; codepointsCount++)
|
||||
{
|
||||
codepoints[codepointsCount] = GetNextCodepoint(text + i, &bytesProcessed);
|
||||
i += bytesProcessed;
|
||||
}
|
||||
|
||||
*count = codepointsCount;
|
||||
|
||||
return codepoints;
|
||||
}
|
||||
|
||||
// Returns total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found
|
||||
// NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead
|
||||
int GetCodepointsCount(const char *text)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
char *ptr = (char *)&text[0];
|
||||
|
||||
while (*ptr != '\0')
|
||||
{
|
||||
int next = 0;
|
||||
int letter = GetNextCodepoint(ptr, &next);
|
||||
|
||||
if (letter == 0x3f) ptr += 1;
|
||||
else ptr += next;
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
|
||||
// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
|
||||
// Total number of bytes processed are returned as a parameter
|
||||
// NOTE: the standard says U+FFFD should be returned in case of errors
|
||||
// but that character is not supported by the default font in raylib
|
||||
// TODO: optimize this code for speed!!
|
||||
int GetNextCodepoint(const char *text, int *bytesProcessed)
|
||||
{
|
||||
/*
|
||||
UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt
|
||||
|
||||
Char. number range | UTF-8 octet sequence
|
||||
(hexadecimal) | (binary)
|
||||
--------------------+---------------------------------------------
|
||||
0000 0000-0000 007F | 0xxxxxxx
|
||||
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
|
||||
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
||||
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
*/
|
||||
// NOTE: on decode errors we return as soon as possible
|
||||
|
||||
int code = 0x3f; // Codepoint (defaults to '?')
|
||||
int octet = (unsigned char)(text[0]); // The first UTF8 octet
|
||||
*bytesProcessed = 1;
|
||||
|
||||
if (octet <= 0x7f)
|
||||
{
|
||||
// Only one octet (ASCII range x00-7F)
|
||||
code = text[0];
|
||||
}
|
||||
else if ((octet & 0xe0) == 0xc0)
|
||||
{
|
||||
// Two octets
|
||||
// [0]xC2-DF [1]UTF8-tail(x80-BF)
|
||||
unsigned char octet1 = text[1];
|
||||
|
||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||
|
||||
if ((octet >= 0xc2) && (octet <= 0xdf))
|
||||
{
|
||||
code = ((octet & 0x1f) << 6) | (octet1 & 0x3f);
|
||||
*bytesProcessed = 2;
|
||||
}
|
||||
}
|
||||
else if ((octet & 0xf0) == 0xe0)
|
||||
{
|
||||
// Three octets
|
||||
unsigned char octet1 = text[1];
|
||||
unsigned char octet2 = '\0';
|
||||
|
||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||
|
||||
octet2 = text[2];
|
||||
|
||||
if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
|
||||
|
||||
/*
|
||||
[0]xE0 [1]xA0-BF [2]UTF8-tail(x80-BF)
|
||||
[0]xE1-EC [1]UTF8-tail [2]UTF8-tail(x80-BF)
|
||||
[0]xED [1]x80-9F [2]UTF8-tail(x80-BF)
|
||||
[0]xEE-EF [1]UTF8-tail [2]UTF8-tail(x80-BF)
|
||||
*/
|
||||
|
||||
if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
|
||||
((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; }
|
||||
|
||||
if ((octet >= 0xe0) && (0 <= 0xef))
|
||||
{
|
||||
code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
|
||||
*bytesProcessed = 3;
|
||||
}
|
||||
}
|
||||
else if ((octet & 0xf8) == 0xf0)
|
||||
{
|
||||
// Four octets
|
||||
if (octet > 0xf4) return code;
|
||||
|
||||
unsigned char octet1 = text[1];
|
||||
unsigned char octet2 = '\0';
|
||||
unsigned char octet3 = '\0';
|
||||
|
||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||
|
||||
octet2 = text[2];
|
||||
|
||||
if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
|
||||
|
||||
octet3 = text[3];
|
||||
|
||||
if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *bytesProcessed = 4; return code; } // Unexpected sequence
|
||||
|
||||
/*
|
||||
[0]xF0 [1]x90-BF [2]UTF8-tail [3]UTF8-tail
|
||||
[0]xF1-F3 [1]UTF8-tail [2]UTF8-tail [3]UTF8-tail
|
||||
[0]xF4 [1]x80-8F [2]UTF8-tail [3]UTF8-tail
|
||||
*/
|
||||
|
||||
if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) ||
|
||||
((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||
|
||||
if (octet >= 0xf0)
|
||||
{
|
||||
code = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f);
|
||||
*bytesProcessed = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (code > 0x10ffff) code = 0x3f; // Codepoints after U+10ffff are invalid
|
||||
|
||||
return code;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -1572,18 +1650,15 @@ static Font LoadBMFont(const char *fileName)
|
|||
TraceLog(LOG_DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
|
||||
|
||||
Image imFont = LoadImage(texPath);
|
||||
Image imFontAlpha = ImageCopy(imFont);
|
||||
|
||||
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
|
||||
{
|
||||
for (int i = 0; i < imFontAlpha.width*imFontAlpha.height; i++) ((unsigned char *)imFontAlpha.data)[i] = 0xff;
|
||||
|
||||
ImageAlphaMask(&imFontAlpha, imFont);
|
||||
font.texture = LoadTextureFromImage(imFontAlpha);
|
||||
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
|
||||
ImageAlphaMask(&imFont, imFont);
|
||||
for (int p = 0; p < (imFont.width*imFont.height*2); p += 2) ((unsigned char *)(imFont.data))[p] = 0xff;
|
||||
}
|
||||
else font.texture = LoadTextureFromImage(imFont);
|
||||
|
||||
UnloadImage(imFont);
|
||||
font.texture = LoadTextureFromImage(imFont);
|
||||
|
||||
RL_FREE(texPath);
|
||||
|
||||
|
|
@ -1611,10 +1686,10 @@ static Font LoadBMFont(const char *fileName)
|
|||
font.chars[i].advanceX = charAdvanceX;
|
||||
|
||||
// Fill character image data from imFont data
|
||||
font.chars[i].image = ImageFromImage(imFontAlpha, font.recs[i]);
|
||||
font.chars[i].image = ImageFromImage(imFont, font.recs[i]);
|
||||
}
|
||||
|
||||
UnloadImage(imFontAlpha);
|
||||
UnloadImage(imFont);
|
||||
|
||||
fclose(fntFile);
|
||||
|
||||
|
|
|
|||
|
|
@ -1181,13 +1181,18 @@ void ImageAlphaMask(Image *image, Image alphaMask)
|
|||
// In case image is only grayscale, we just add alpha channel
|
||||
if (image->format == UNCOMPRESSED_GRAYSCALE)
|
||||
{
|
||||
ImageFormat(image, UNCOMPRESSED_GRAY_ALPHA);
|
||||
unsigned char *data = (unsigned char *)RL_MALLOC(image->width*image->height*2);
|
||||
|
||||
// Apply alpha mask to alpha channel
|
||||
for (int i = 0, k = 1; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
|
||||
for (int i = 0, k = 0; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
|
||||
{
|
||||
((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i];
|
||||
data[k] = ((unsigned char *)image->data)[i];
|
||||
data[k + 1] = ((unsigned char *)mask.data)[i];
|
||||
}
|
||||
|
||||
RL_FREE(image->data);
|
||||
image->data = data;
|
||||
image->format = UNCOMPRESSED_GRAY_ALPHA;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1997,7 +2002,7 @@ void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color)
|
|||
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y, rec.width, thick }, color);
|
||||
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y + thick, thick, rec.height - thick*2 }, color);
|
||||
ImageDrawRectangle(dst, (Rectangle){ rec.x + rec.width - thick, rec.y + thick, thick, rec.height - thick*2 }, color);
|
||||
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.height - thick, rec.width, thick }, color);
|
||||
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y + rec.height - thick, rec.width, thick }, color);
|
||||
}
|
||||
|
||||
// Draw text (default font) within an image (destination)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user