From 2f90318d3053e905120e23d8a2f4f37d7a1b0aa5 Mon Sep 17 00:00:00 2001 From: Milan Nikolic Date: Fri, 10 Feb 2017 11:28:19 +0100 Subject: [PATCH] Update C sources, add new functions --- examples/text/bmfont_ttf/main.go | 8 +- examples/text/bmfont_unordered/main.go | 6 +- examples/text/font_select/main.go | 6 +- examples/text/rbmf_fonts/main.go | 6 +- examples/text/sprite_fonts/main.go | 18 +- examples/text/ttf_loading/main.go | 2 +- raylib/audio.c | 60 +++++-- raylib/audio.go | 14 ++ raylib/audio.h | 2 + raylib/core.c | 21 ++- raylib/core.go | 6 + raylib/models.c | 66 +++---- raylib/raylib.h | 49 +++--- raylib/rlgl.h | 22 --- raylib/text.c | 232 +++++++++++++------------ raylib/text.go | 52 ++++-- raylib/textures.c | 4 +- 17 files changed, 332 insertions(+), 242 deletions(-) diff --git a/examples/text/bmfont_ttf/main.go b/examples/text/bmfont_ttf/main.go index 9f58e1e..3f3a710 100644 --- a/examples/text/bmfont_ttf/main.go +++ b/examples/text/bmfont_ttf/main.go @@ -19,8 +19,8 @@ func main() { fontPosition := raylib.Vector2{} - fontPosition.X = float32(screenWidth)/2 - raylib.MeasureTextEx(fontBm, msgBm, float32(fontBm.Size), 0).X/2 - fontPosition.Y = float32(screenHeight)/2 - float32(fontBm.Size)/2 - 80 + fontPosition.X = float32(screenWidth)/2 - raylib.MeasureTextEx(fontBm, msgBm, float32(fontBm.BaseSize), 0).X/2 + fontPosition.Y = float32(screenHeight)/2 - float32(fontBm.BaseSize)/2 - 80 raylib.SetTargetFPS(60) @@ -29,8 +29,8 @@ func main() { raylib.ClearBackground(raylib.RayWhite) - raylib.DrawTextEx(fontBm, msgBm, fontPosition, float32(fontBm.Size), 0, raylib.Maroon) - raylib.DrawTextEx(fontTtf, msgTtf, raylib.NewVector2(75.0, 240.0), float32(fontTtf.Size)*0.8, 2, raylib.Lime) + raylib.DrawTextEx(fontBm, msgBm, fontPosition, float32(fontBm.BaseSize), 0, raylib.Maroon) + raylib.DrawTextEx(fontTtf, msgTtf, raylib.NewVector2(75.0, 240.0), float32(fontTtf.BaseSize)*0.8, 2, raylib.Lime) raylib.EndDrawing() } diff --git a/examples/text/bmfont_unordered/main.go b/examples/text/bmfont_unordered/main.go index b419296..77cede5 100644 --- a/examples/text/bmfont_unordered/main.go +++ b/examples/text/bmfont_unordered/main.go @@ -27,10 +27,10 @@ func main() { raylib.ClearBackground(raylib.RayWhite) raylib.DrawText("Font name: PixAntiqua", 40, 50, 20, raylib.Gray) - raylib.DrawText(fmt.Sprintf("Font base size: %d", font.Size), 40, 80, 20, raylib.Gray) - raylib.DrawText(fmt.Sprintf("Font chars number: %d", font.NumChars), 40, 110, 20, raylib.Gray) + raylib.DrawText(fmt.Sprintf("Font base size: %d", font.BaseSize), 40, 80, 20, raylib.Gray) + raylib.DrawText(fmt.Sprintf("Font chars number: %d", font.CharsCount), 40, 110, 20, raylib.Gray) - raylib.DrawTextEx(font, msg, raylib.NewVector2(40, 180), float32(font.Size), 0, raylib.Maroon) + raylib.DrawTextEx(font, msg, raylib.NewVector2(40, 180), float32(font.BaseSize), 0, raylib.Maroon) raylib.EndDrawing() } diff --git a/examples/text/font_select/main.go b/examples/text/font_select/main.go index ffe1d3d..a6fc138 100644 --- a/examples/text/font_select/main.go +++ b/examples/text/font_select/main.go @@ -30,7 +30,7 @@ func main() { text := "THIS is THE FONT you SELECTED!" // Main text - textSize := raylib.MeasureTextEx(fonts[currentFont], text, float32(fonts[currentFont].Size)*3, 1) + textSize := raylib.MeasureTextEx(fonts[currentFont], text, float32(fonts[currentFont].BaseSize)*3, 1) mousePoint := raylib.Vector2{} @@ -112,7 +112,7 @@ func main() { } // Text measurement for better positioning on screen - textSize = raylib.MeasureTextEx(fonts[currentFont], text, float32(fonts[currentFont].Size)*3, 1) + textSize = raylib.MeasureTextEx(fonts[currentFont], text, float32(fonts[currentFont].BaseSize)*3, 1) // Draw raylib.BeginDrawing() @@ -131,7 +131,7 @@ func main() { raylib.DrawRectangle(675, positionY+2, 105, 40, btnNextInColor) raylib.DrawText("NEXT", 700, positionY+13, 20, btnNextOutColor) - raylib.DrawTextEx(fonts[currentFont], text, raylib.NewVector2(float32(screenWidth)/2-textSize.X/2, 260+(70-textSize.Y)/2), float32(fonts[currentFont].Size*3), 1, colors[currentFont]) + raylib.DrawTextEx(fonts[currentFont], text, raylib.NewVector2(float32(screenWidth)/2-textSize.X/2, 260+(70-textSize.Y)/2), float32(fonts[currentFont].BaseSize*3), 1, colors[currentFont]) raylib.EndDrawing() } diff --git a/examples/text/rbmf_fonts/main.go b/examples/text/rbmf_fonts/main.go index e2db346..fdd7a70 100644 --- a/examples/text/rbmf_fonts/main.go +++ b/examples/text/rbmf_fonts/main.go @@ -36,8 +36,8 @@ func main() { var i int32 for i = 0; i < 8; i++ { - x := screenWidth/2 - int32(raylib.MeasureTextEx(fonts[i], messages[i], float32(fonts[i].Size*2), spacings[i]).X/2) - y := 60 + fonts[i].Size + 45*i + x := screenWidth/2 - int32(raylib.MeasureTextEx(fonts[i], messages[i], float32(fonts[i].BaseSize*2), spacings[i]).X/2) + y := 60 + fonts[i].BaseSize + 45*i positions[i] = raylib.NewVector2(float32(x), float32(y)) } @@ -53,7 +53,7 @@ func main() { raylib.DrawLine(220, 50, 590, 50, raylib.DarkGray) for i = 0; i < 8; i++ { - raylib.DrawTextEx(fonts[i], messages[i], positions[i], float32(fonts[i].Size*2), spacings[i], colors[i]) + raylib.DrawTextEx(fonts[i], messages[i], positions[i], float32(fonts[i].BaseSize*2), spacings[i], colors[i]) } raylib.EndDrawing() diff --git a/examples/text/sprite_fonts/main.go b/examples/text/sprite_fonts/main.go index cbcb88b..4f9b323 100644 --- a/examples/text/sprite_fonts/main.go +++ b/examples/text/sprite_fonts/main.go @@ -21,14 +21,14 @@ func main() { var fontPosition1, fontPosition2, fontPosition3 raylib.Vector2 - fontPosition1.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font1, msg1, float32(font1.Size), -3).X/2 - fontPosition1.Y = float32(screenHeight)/2 - float32(font1.Size)/2 - 80 + fontPosition1.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font1, msg1, float32(font1.BaseSize), -3).X/2 + fontPosition1.Y = float32(screenHeight)/2 - float32(font1.BaseSize)/2 - 80 - fontPosition2.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font2, msg2, float32(font2.Size), -2).X/2 - fontPosition2.Y = float32(screenHeight)/2 - float32(font2.Size)/2 - 10 + fontPosition2.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font2, msg2, float32(font2.BaseSize), -2).X/2 + fontPosition2.Y = float32(screenHeight)/2 - float32(font2.BaseSize)/2 - 10 - fontPosition3.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font3, msg3, float32(font3.Size), 2).X/2 - fontPosition3.Y = float32(screenHeight)/2 - float32(font3.Size)/2 + 50 + fontPosition3.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font3, msg3, float32(font3.BaseSize), 2).X/2 + fontPosition3.Y = float32(screenHeight)/2 - float32(font3.BaseSize)/2 + 50 raylib.SetTargetFPS(60) @@ -37,9 +37,9 @@ func main() { raylib.ClearBackground(raylib.RayWhite) - raylib.DrawTextEx(font1, msg1, fontPosition1, float32(font1.Size), -3, raylib.White) - raylib.DrawTextEx(font2, msg2, fontPosition2, float32(font2.Size), -2, raylib.White) - raylib.DrawTextEx(font3, msg3, fontPosition3, float32(font3.Size), 2, raylib.White) + raylib.DrawTextEx(font1, msg1, fontPosition1, float32(font1.BaseSize), -3, raylib.White) + raylib.DrawTextEx(font2, msg2, fontPosition2, float32(font2.BaseSize), -2, raylib.White) + raylib.DrawTextEx(font3, msg3, fontPosition3, float32(font3.BaseSize), 2, raylib.White) raylib.EndDrawing() } diff --git a/examples/text/ttf_loading/main.go b/examples/text/ttf_loading/main.go index cd13043..709f0b5 100644 --- a/examples/text/ttf_loading/main.go +++ b/examples/text/ttf_loading/main.go @@ -25,7 +25,7 @@ func main() { // NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR raylib.GenTextureMipmaps(&font.Texture) - fontSize := font.Size + fontSize := font.BaseSize fontPosition := raylib.NewVector2(40, float32(screenHeight)/2+50) textSize := raylib.Vector2{} diff --git a/raylib/audio.c b/raylib/audio.c index 708d2ac..741c87c 100644 --- a/raylib/audio.c +++ b/raylib/audio.c @@ -128,7 +128,7 @@ typedef struct MusicData { AudioStream stream; // Audio stream (double buffering) - bool loop; // Repeat music after finish (loop) + int loopCount; // Loops count (times music repeats), -1 means infinite loop unsigned int totalSamples; // Total number of samples unsigned int samplesLeft; // Number of samples left to end } MusicData; @@ -182,9 +182,11 @@ void InitAudioDevice(void) TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); // Listener definition (just for 2D) - alListener3f(AL_POSITION, 0, 0, 0); - alListener3f(AL_VELOCITY, 0, 0, 0); - alListener3f(AL_ORIENTATION, 0, 0, -1); + alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f); + alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f); + alListener3f(AL_ORIENTATION, 0.0f, 0.0f, -1.0f); + + alListenerf(AL_GAIN, 1.0f); } } } @@ -221,6 +223,15 @@ bool IsAudioDeviceReady(void) } } +// Set master volume (listener) +void SetMasterVolume(float volume) +{ + if (volume < 0.0f) volume = 0.0f; + else if (volume > 1.0f) volume = 1.0f; + + alListenerf(AL_GAIN, volume); +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- @@ -318,10 +329,10 @@ Sound LoadSoundFromWave(Wave wave) ALuint source; alGenSources(1, &source); // Generate pointer to audio source - alSourcef(source, AL_PITCH, 1); - alSourcef(source, AL_GAIN, 1); - alSource3f(source, AL_POSITION, 0, 0, 0); - alSource3f(source, AL_VELOCITY, 0, 0, 0); + alSourcef(source, AL_PITCH, 1.0f); + alSourcef(source, AL_GAIN, 1.0f); + alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcei(source, AL_LOOPING, AL_FALSE); // Convert loaded data to OpenAL buffer @@ -626,7 +637,7 @@ Music LoadMusicStream(const char *fileName) music->totalSamples = (unsigned int)stb_vorbis_stream_length_in_samples(music->ctxOgg); // Independent by channel music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_OGG; - music->loop = true; // We loop by default + music->loopCount = -1; // Infinite loop by default TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples); TraceLog(DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate); @@ -645,7 +656,7 @@ Music LoadMusicStream(const char *fileName) music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount/music->ctxFlac->channels; music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_FLAC; - music->loop = true; // We loop by default + music->loopCount = -1; // Infinite loop by default TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples); TraceLog(DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate); @@ -659,14 +670,14 @@ Music LoadMusicStream(const char *fileName) if (!result) // XM context created successfully { - jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops + jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops // NOTE: Only stereo is supported for XM music->stream = InitAudioStream(48000, 16, 2); music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm); music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_MODULE_XM; - music->loop = true; + music->loopCount = -1; // Infinite loop by default TraceLog(DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples); TraceLog(DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); @@ -683,7 +694,7 @@ Music LoadMusicStream(const char *fileName) music->totalSamples = (unsigned int)jar_mod_max_samples(&music->ctxMod); music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_MODULE_MOD; - music->loop = true; + music->loopCount = -1; // Infinite loop by default TraceLog(DEBUG, "[%s] MOD number of samples: %i", fileName, music->samplesLeft); TraceLog(DEBUG, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); @@ -807,7 +818,13 @@ void UpdateMusicStream(Music music) if (!active) { StopMusicStream(music); // Stop music (and reset) - if (music->loop) PlayMusicStream(music); // Play again + + // Decrease loopCount to stop when required + if (music->loopCount > 0) + { + music->loopCount--; // Decrease loop count + PlayMusicStream(music); // Play again + } } else { @@ -845,6 +862,13 @@ void SetMusicPitch(Music music, float pitch) alSourcef(music->stream.source, AL_PITCH, pitch); } +// Set music loop count (loop repeats) +// NOTE: If set to -1, means infinite loop +void SetMusicLoopCount(Music music, float count) +{ + music->loopCount = count; +} + // Get music time length (in seconds) float GetMusicTimeLength(Music music) { @@ -904,10 +928,10 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un // Create an audio source alGenSources(1, &stream.source); - alSourcef(stream.source, AL_PITCH, 1); - alSourcef(stream.source, AL_GAIN, 1); - alSource3f(stream.source, AL_POSITION, 0, 0, 0); - alSource3f(stream.source, AL_VELOCITY, 0, 0, 0); + alSourcef(stream.source, AL_PITCH, 1.0f); + alSourcef(stream.source, AL_GAIN, 1.0f); + alSource3f(stream.source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(stream.source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); // Create Buffers (double buffering) alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers); diff --git a/raylib/audio.go b/raylib/audio.go index ad5a564..f9380be 100644 --- a/raylib/audio.go +++ b/raylib/audio.go @@ -112,6 +112,12 @@ func IsAudioDeviceReady() bool { return v } +// Set master volume (listener) +func SetMasterVolume(volume float32) { + cvolume := (C.float)(volume) + C.SetMasterVolume(cvolume) +} + // Load wave data from file into RAM func LoadWave(fileName string) Wave { cfileName := C.CString(fileName) @@ -321,6 +327,14 @@ func SetMusicPitch(music Music, pitch float32) { C.SetMusicPitch(cmusic, cpitch) } +// Set music loop count (loop repeats) +// NOTE: If set to -1, means infinite loop +func SetMusicLoopCount(music Music, count float32) { + cmusic := *(*C.Music)(unsafe.Pointer(&music)) + ccount := (C.float)(count) + C.SetMusicLoopCount(cmusic, ccount) +} + // Get music time length (in seconds) func GetMusicTimeLength(music Music) float32 { cmusic := *(*C.Music)(unsafe.Pointer(&music)) diff --git a/raylib/audio.h b/raylib/audio.h index 6f0c235..05ba1a1 100644 --- a/raylib/audio.h +++ b/raylib/audio.h @@ -109,6 +109,7 @@ extern "C" { // Prevents name mangling of functions void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully +void SetMasterVolume(float volume); // Set master volume (listener) Wave LoadWave(const char *fileName); // Load wave data from file Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data @@ -138,6 +139,7 @@ void ResumeMusicStream(Music music); // Resume playin bool IsMusicPlaying(Music music); // Check if music is playing void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats) float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) diff --git a/raylib/core.c b/raylib/core.c index 4ce32a0..04dd054 100644 --- a/raylib/core.c +++ b/raylib/core.c @@ -524,7 +524,7 @@ bool IsWindowMinimized(void) #endif } -// Fullscreen toggle +// Fullscreen toggle (only PLATFORM_DESKTOP) void ToggleFullscreen(void) { #if defined(PLATFORM_DESKTOP) @@ -540,6 +540,25 @@ void ToggleFullscreen(void) #endif } +// Set icon for window (only PLATFORM_DESKTOP) +void SetWindowIcon(Image image) +{ +#if defined(PLATFORM_DESKTOP) + ImageFormat(&image, UNCOMPRESSED_R8G8B8A8); + + GLFWimage icon[1]; + + icon[0].width = image.width; + icon[0].height = image.height; + icon[0].pixels = (unsigned char *)image.data; + + // NOTE: We only support one image icon + glfwSetWindowIcon(window, 1, icon); + + // TODO: Support multi-image icons --> image.mipmaps +#endif +} + // Get current screen width int GetScreenWidth(void) { diff --git a/raylib/core.go b/raylib/core.go index 1bd002e..463d5e4 100644 --- a/raylib/core.go +++ b/raylib/core.go @@ -484,6 +484,12 @@ func ToggleFullscreen() { C.ToggleFullscreen() } +// Set icon for window (only PLATFORM_DESKTOP) +func SetWindowIcon(image Image) { + cimage := image.cptr() + C.SetWindowIcon(*cimage) +} + // Get current screen width func GetScreenWidth() int32 { ret := C.GetScreenWidth() diff --git a/raylib/models.c b/raylib/models.c index 23c2e6f..4382169 100644 --- a/raylib/models.c +++ b/raylib/models.c @@ -584,7 +584,7 @@ Mesh LoadMesh(const char *fileName) if (mesh.vertexCount == 0) TraceLog(WARNING, "Mesh could not be loaded"); else rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) - + // TODO: Initialize default mesh data in case loading fails, maybe a cube? return mesh; @@ -607,7 +607,7 @@ Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color mesh.indices = NULL; rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) - + return mesh; } @@ -668,7 +668,7 @@ Model LoadCubicmap(Image cubicmap) return model; } - + // Unload mesh from memory (RAM and/or VRAM) void UnloadMesh(Mesh *mesh) { @@ -1438,34 +1438,34 @@ RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh) int triangleCount = mesh->vertexCount/3; // Test against all triangles in mesh - for (int i = 0; i < triangleCount; i++) + for (int i = 0; i < triangleCount; i++) { Vector3 a, b, c; Vector3 *vertdata = (Vector3 *)mesh->vertices; - - if (mesh->indices) + + if (mesh->indices) { a = vertdata[mesh->indices[i*3 + 0]]; b = vertdata[mesh->indices[i*3 + 1]]; - c = vertdata[mesh->indices[i*3 + 2]]; - } - else - { + c = vertdata[mesh->indices[i*3 + 2]]; + } + else + { a = vertdata[i*3 + 0]; b = vertdata[i*3 + 1]; c = vertdata[i*3 + 2]; } RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c); - - if (triHitInfo.hit) + + if (triHitInfo.hit) { // Save the closest hit triangle if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo; } } - return result; + return result; } // Get collision info between ray and triangle @@ -1478,44 +1478,44 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3) Vector3 p, q, tv; float det, invDet, u, v, t; RayHitInfo result = {0}; - + // Find vectors for two edges sharing V1 edge1 = VectorSubtract(p2, p1); edge2 = VectorSubtract(p3, p1); - + // Begin calculating determinant - also used to calculate u parameter p = VectorCrossProduct(ray.direction, edge2); - + // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle det = VectorDotProduct(edge1, p); - + // Avoid culling! if ((det > -EPSILON) && (det < EPSILON)) return result; - + invDet = 1.0f/det; - + // Calculate distance from V1 to ray origin tv = VectorSubtract(ray.position, p1); - + // Calculate u parameter and test bound u = VectorDotProduct(tv, p)*invDet; - + // The intersection lies outside of the triangle if ((u < 0.0f) || (u > 1.0f)) return result; - + // Prepare to test v parameter q = VectorCrossProduct(tv, edge1); - + // Calculate V parameter and test bound v = VectorDotProduct(ray.direction, q)*invDet; - + // The intersection lies outside of the triangle if ((v < 0.0f) || ((u + v) > 1.0f)) return result; - + t = VectorDotProduct(edge2, q)*invDet; - - if (t > EPSILON) - { + + if (t > EPSILON) + { // Ray hit, get hit point and normal result.hit = true; result.distance = t; @@ -1523,10 +1523,10 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3) result.hitNormal = VectorCrossProduct(edge1, edge2); VectorNormalize(&result.hitNormal); Vector3 rayDir = ray.direction; - VectorScale(&rayDir, t); + VectorScale(&rayDir, t); result.hitPosition = VectorAdd(ray.position, rayDir); } - + return result; } @@ -1540,8 +1540,8 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) if (fabsf(ray.direction.y) > EPSILON) { float t = (ray.position.y - groundHeight)/-ray.direction.y; - - if (t >= 0.0) + + if (t >= 0.0) { Vector3 rayDir = ray.direction; VectorScale(&rayDir, t); @@ -1551,7 +1551,7 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) result.hitPosition = VectorAdd(ray.position, rayDir); } } - + return result; } diff --git a/raylib/raylib.h b/raylib/raylib.h index 5489b7b..5ecbfa6 100644 --- a/raylib/raylib.h +++ b/raylib/raylib.h @@ -366,15 +366,21 @@ typedef struct RenderTexture2D { Texture2D depth; // Depth buffer attachment texture } RenderTexture2D; +// SpriteFont character info +typedef struct CharInfo { + int value; // Character value (Unicode) + Rectangle rec; // Character rectangle in sprite font + int offsetX; // Character offset X when drawing + int offsetY; // Character offset Y when drawing + int advanceX; // Character advance position X +} CharInfo; + // SpriteFont type, includes texture and charSet array data typedef struct SpriteFont { Texture2D texture; // Font texture - int size; // Base size (default chars height) - int numChars; // Number of characters - int *charValues; // Characters values array - Rectangle *charRecs; // Characters rectangles within the texture - Vector2 *charOffsets; // Characters offsets (on drawing) - int *charAdvanceX; // Characters x advance (on drawing) + int baseSize; // Base size (default chars height) + int charsCount; // Number of characters + CharInfo *chars; // Characters info data } SpriteFont; // Camera type, defines a camera position/orientation in 3d space @@ -589,21 +595,21 @@ typedef enum { // rRES data returned when reading a resource, it contains all required data for user (24 byte) typedef struct { unsigned int type; // Resource type (4 byte) - + unsigned int param1; // Resouce parameter 1 (4 byte) unsigned int param2; // Resouce parameter 2 (4 byte) unsigned int param3; // Resouce parameter 3 (4 byte) unsigned int param4; // Resouce parameter 4 (4 byte) - + void *data; // Resource data pointer (4 byte) } RRESData; -typedef enum { - RRES_RAW = 0, - RRES_IMAGE, - RRES_WAVE, - RRES_VERTEX, - RRES_TEXT +typedef enum { + RRES_RAW = 0, + RRES_IMAGE, + RRES_WAVE, + RRES_VERTEX, + RRES_TEXT } RRESDataType; #ifdef __cplusplus @@ -628,6 +634,7 @@ RLAPI void CloseWindow(void); // Close Windo RLAPI bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed RLAPI bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) RLAPI void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP) +RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP) RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height @@ -796,7 +803,7 @@ RLAPI Image ImageText(const char *text, int fontSize, Color color); RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) -RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, +RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) RLAPI void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally @@ -821,7 +828,7 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest //------------------------------------------------------------------------------------ RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM) -RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load SpriteFont from TTF font file with generation parameters +RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load SpriteFont from TTF font file with generation parameters RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory (VRAM) RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) @@ -872,15 +879,15 @@ RLAPI Material LoadDefaultMaterial(void); RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) -RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, +RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) -RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, +RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture -RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, +RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec RLAPI BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits @@ -888,7 +895,7 @@ RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere -RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, +RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box RLAPI RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh); // Get collision info between ray and mesh @@ -936,6 +943,7 @@ RLAPI void ToggleVrMode(void); // Enable/Disable VR experienc RLAPI void InitAudioDevice(void); // Initialize audio device and context RLAPI void CloseAudioDevice(void); // Close the audio device and context RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully +RLAPI void SetMasterVolume(float volume); // Set master volume (listener) RLAPI Wave LoadWave(const char *fileName); // Load wave data from file RLAPI Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data @@ -965,6 +973,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume RLAPI bool IsMusicPlaying(Music music); // Check if music is playing RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +RLAPI void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) diff --git a/raylib/rlgl.h b/raylib/rlgl.h index 9cee39c..41f671e 100644 --- a/raylib/rlgl.h +++ b/raylib/rlgl.h @@ -251,25 +251,6 @@ typedef unsigned char byte; float fovy; // Camera field-of-view apperture in Y (degrees) } Camera; - // Light type - typedef struct LightData { - unsigned int id; // Light unique id - bool enabled; // Light enabled - int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT - - Vector3 position; // Light position - Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) - float radius; // Light attenuation radius light intensity reduced with distance (world distance) - - Color diffuse; // Light diffuse color - float intensity; // Light intensity level - - float coneAngle; // Light cone max angle: LIGHT_SPOT - } LightData, *Light; - - // Light types - typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; - // Texture parameters: filter mode // NOTE 1: Filtering considers mipmaps if available in the texture // NOTE 2: Filter is accordingly set for minification and magnification @@ -415,9 +396,6 @@ void EndShaderMode(void); // End custo void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) void EndBlendMode(void); // End blending mode (reset to default: alpha blending) -Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool -void DestroyLight(Light light); // Destroy a light and take it out of the list - void TraceLog(int msgType, const char *text, ...); float *MatrixToFloat(Matrix mat); diff --git a/raylib/text.c b/raylib/text.c index e3d22fb..206d06f 100644 --- a/raylib/text.c +++ b/raylib/text.c @@ -79,7 +79,7 @@ static int GetCharIndex(SpriteFont font, int letter); static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) -static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load spritefont from TTF data +static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data extern void LoadDefaultFont(void); extern void UnloadDefaultFont(void); @@ -92,7 +92,7 @@ extern void LoadDefaultFont(void) // NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement // http://www.utf8-chartable.de/unicode-utf8-table.pl - defaultFont.numChars = 224; // Number of chars included in our default font + defaultFont.charsCount = 224; // Number of chars included in our default font // Default font is directly defined here (data generated from a sprite font image) // This way, we reconstruct SpriteFont without creating large global variables @@ -189,29 +189,27 @@ extern void LoadDefaultFont(void) defaultFont.texture = LoadTextureFromImage(image); UnloadImage(image); - // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars + // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount //------------------------------------------------------------------------------ - defaultFont.charValues = (int *)malloc(defaultFont.numChars*sizeof(int)); - defaultFont.charRecs = (Rectangle *)malloc(defaultFont.numChars*sizeof(Rectangle)); // Allocate space for our character rectangle data - // This memory should be freed at end! --> Done on CloseWindow() - - defaultFont.charOffsets = (Vector2 *)malloc(defaultFont.numChars*sizeof(Vector2)); - defaultFont.charAdvanceX = (int *)malloc(defaultFont.numChars*sizeof(int)); + + // Allocate space for our characters info data + // NOTE: This memory should be freed at end! --> CloseWindow() + defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo)); int currentLine = 0; int currentPosX = charsDivisor; int testPosX = charsDivisor; - for (int i = 0; i < defaultFont.numChars; i++) + for (int i = 0; i < defaultFont.charsCount; i++) { - defaultFont.charValues[i] = 32 + i; // First char is 32 + defaultFont.chars[i].value = 32 + i; // First char is 32 - defaultFont.charRecs[i].x = currentPosX; - defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); - defaultFont.charRecs[i].width = charsWidth[i]; - defaultFont.charRecs[i].height = charsHeight; + defaultFont.chars[i].rec.x = currentPosX; + defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor); + defaultFont.chars[i].rec.width = charsWidth[i]; + defaultFont.chars[i].rec.height = charsHeight; - testPosX += (defaultFont.charRecs[i].width + charsDivisor); + testPosX += (defaultFont.chars[i].rec.width + charsDivisor); if (testPosX >= defaultFont.texture.width) { @@ -219,17 +217,18 @@ extern void LoadDefaultFont(void) currentPosX = 2*charsDivisor + charsWidth[i]; testPosX = currentPosX; - defaultFont.charRecs[i].x = charsDivisor; - defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); + defaultFont.chars[i].rec.x = charsDivisor; + defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor); } else currentPosX = testPosX; // NOTE: On default font character offsets and xAdvance are not required - defaultFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; - defaultFont.charAdvanceX[i] = 0; + defaultFont.chars[i].offsetX = 0; + defaultFont.chars[i].offsetY = 0; + defaultFont.chars[i].advanceX = 0; } - defaultFont.size = defaultFont.charRecs[0].height; + defaultFont.baseSize = defaultFont.chars[0].rec.height; TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id); } @@ -237,10 +236,7 @@ extern void LoadDefaultFont(void) extern void UnloadDefaultFont(void) { UnloadTexture(defaultFont.texture); - free(defaultFont.charValues); - free(defaultFont.charRecs); - free(defaultFont.charOffsets); - free(defaultFont.charAdvanceX); + free(defaultFont.chars); } // Get the default font, useful to be used with extended parameters @@ -260,9 +256,37 @@ SpriteFont LoadSpriteFont(const char *fileName) SpriteFont spriteFont = { 0 }; // Check file extension - if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); + if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); // TODO: DELETE... SOON... else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadSpriteFontTTF(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); else if (strcmp(GetExtension(fileName),"fnt") == 0) spriteFont = LoadBMFont(fileName); + else if (strcmp(GetExtension(fileName),"rres") == 0) + { + // TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA) + RRESData rres = LoadResource(fileName); + + // Load sprite font texture + /* + if (rres.type == RRES_FONT_IMAGE) + { + // NOTE: Parameters for RRES_FONT_IMAGE type are: width, height, format, mipmaps + Image image = LoadImagePro(rres.data, rres.param1, rres.param2, rres.param3); + spriteFont.texture = LoadTextureFromImage(image); + UnloadImage(image); + } + + // Load sprite characters data + if (rres.type == RRES_FONT_CHARDATA) + { + // NOTE: Parameters for RRES_FONT_CHARDATA type are: fontSize, charsCount + spriteFont.baseSize = rres.param1; + spriteFont.charsCount = rres.param2; + spriteFont.chars = rres.data; + } + */ + + // TODO: Do not free rres.data memory (chars info data!) + UnloadResource(rres); + } else { Image image = LoadImage(fileName); @@ -283,13 +307,13 @@ SpriteFont LoadSpriteFont(const char *fileName) // Load SpriteFont from TTF font file with generation parameters // NOTE: You can pass an array with desired characters, those characters should be available in the font // if array is NULL, default char set is selected 32..126 -SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars) +SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) { SpriteFont spriteFont = { 0 }; if (strcmp(GetExtension(fileName),"ttf") == 0) { - if ((fontChars == NULL) || (numChars == 0)) + if ((fontChars == NULL) || (charsCount == 0)) { int totalChars = 95; // Default charset [32..126] @@ -299,7 +323,7 @@ SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, i spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars); } - else spriteFont = LoadTTF(fileName, fontSize, numChars, fontChars); + else spriteFont = LoadTTF(fileName, fontSize, charsCount, fontChars); } if (spriteFont.texture.id == 0) @@ -318,10 +342,7 @@ void UnloadSpriteFont(SpriteFont spriteFont) if (spriteFont.texture.id != defaultFont.texture.id) { UnloadTexture(spriteFont.texture); - free(spriteFont.charValues); - free(spriteFont.charRecs); - free(spriteFont.charOffsets); - free(spriteFont.charAdvanceX); + free(spriteFont.chars); TraceLog(DEBUG, "Unloaded sprite font data"); } @@ -357,7 +378,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float unsigned char letter; // Current character int index; // Index position in sprite font - scaleFactor = fontSize/spriteFont.size; + scaleFactor = fontSize/spriteFont.baseSize; // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly // written in C code files (codified by default as UTF-8) @@ -367,7 +388,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float if ((unsigned char)text[i] == '\n') { // NOTE: Fixed line spacing of 1.5 lines - textOffsetY += (int)((spriteFont.size + spriteFont.size/2)*scaleFactor); + textOffsetY += (int)((spriteFont.baseSize + spriteFont.baseSize/2)*scaleFactor); textOffsetX = 0; } else @@ -388,14 +409,14 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float } else index = GetCharIndex(spriteFont, (int)text[i]); - DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index], - (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor, - position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor, - spriteFont.charRecs[index].width*scaleFactor, - spriteFont.charRecs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); + DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec, + (Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor, + position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor, + spriteFont.chars[index].rec.width*scaleFactor, + spriteFont.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); - if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (int)(spriteFont.charRecs[index].width*scaleFactor + spacing); - else textOffsetX += (int)(spriteFont.charAdvanceX[index]*scaleFactor + spacing); + if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing); + else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing); } } } @@ -466,8 +487,8 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i float textWidth = 0; float tempTextWidth = 0; // Used to count longer text line width - float textHeight = (float)spriteFont.size; - float scaleFactor = fontSize/(float)spriteFont.size; + float textHeight = (float)spriteFont.baseSize; + float scaleFactor = fontSize/(float)spriteFont.baseSize; for (int i = 0; i < len; i++) { @@ -477,15 +498,15 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i { int index = GetCharIndex(spriteFont, (int)text[i]); - if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index]; - else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x); + if (spriteFont.chars[index].advanceX != 0) textWidth += spriteFont.chars[index].advanceX; + else textWidth += (spriteFont.chars[index].rec.width + spriteFont.chars[index].offsetX); } else { if (tempTextWidth < textWidth) tempTextWidth = textWidth; lenCounter = 0; textWidth = 0; - textHeight += ((float)spriteFont.size*1.5f); // NOTE: Fixed line spacing of 1.5 lines + textHeight += ((float)spriteFont.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines } if (tempLen < lenCounter) tempLen = lenCounter; @@ -518,9 +539,9 @@ static int GetCharIndex(SpriteFont font, int letter) #if defined(UNORDERED_CHARSET) int index = 0; - for (int i = 0; i < font.numChars; i++) + for (int i = 0; i < font.charsCount; i++) { - if (font.charValues[i] == letter) + if (font.chars[i].value == letter) { index = i; break; @@ -621,28 +642,26 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) SpriteFont spriteFont = { 0 }; spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture - spriteFont.numChars = index; + spriteFont.charsCount = index; UnloadImage(fontClear); // Unload processed image once converted to texture // We got tempCharValues and tempCharsRecs populated with chars data // Now we move temp data to sized charValues and charRecs arrays - spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle)); - spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int)); - spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2)); - spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int)); + spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo)); - for (int i = 0; i < spriteFont.numChars; i++) + for (int i = 0; i < spriteFont.charsCount; i++) { - spriteFont.charValues[i] = tempCharValues[i]; - spriteFont.charRecs[i] = tempCharRecs[i]; + spriteFont.chars[i].value = tempCharValues[i]; + spriteFont.chars[i].rec = tempCharRecs[i]; // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) - spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; - spriteFont.charAdvanceX[i] = 0; + spriteFont.chars[i].offsetX = 0; + spriteFont.chars[i].offsetY = 0; + spriteFont.chars[i].advanceX = 0; } - spriteFont.size = spriteFont.charRecs[0].height; + spriteFont.baseSize = spriteFont.chars[0].rec.height; TraceLog(INFO, "Image file loaded correctly as SpriteFont"); @@ -672,6 +691,8 @@ static SpriteFont LoadRBMF(const char *fileName) SpriteFont spriteFont = { 0 }; + // REMOVE SOON!!! +/* rbmfInfoHeader rbmfHeader; unsigned int *rbmfFileData = NULL; unsigned char *rbmfCharWidthData = NULL; @@ -737,29 +758,27 @@ static SpriteFont LoadRBMF(const char *fileName) //TraceLog(INFO, "[%s] Starting chars set reconstruction", fileName); // Get characters data using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars - spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int)); - spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle)); - spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2)); - spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int)); + spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo)); int currentLine = 0; int currentPosX = charsDivisor; int testPosX = charsDivisor; - for (int i = 0; i < spriteFont.numChars; i++) + for (int i = 0; i < spriteFont.charsCount; i++) { - spriteFont.charValues[i] = (int)rbmfHeader.firstChar + i; + spriteFont.chars[i].value = (int)rbmfHeader.firstChar + i; - spriteFont.charRecs[i].x = currentPosX; - spriteFont.charRecs[i].y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor); - spriteFont.charRecs[i].width = (int)rbmfCharWidthData[i]; - spriteFont.charRecs[i].height = (int)rbmfHeader.charHeight; + spriteFont.chars[i].rec.x = currentPosX; + spriteFont.chars[i].rec.y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor); + spriteFont.chars[i].rec.width = (int)rbmfCharWidthData[i]; + spriteFont.chars[i].rec.height = (int)rbmfHeader.charHeight; // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) - spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; - spriteFont.charAdvanceX[i] = 0; + spriteFont.chars[i].offsetX = 0; + spriteFont.chars[i].offsetY = 0; + spriteFont.chars[i].advanceX = 0; - testPosX += (spriteFont.charRecs[i].width + charsDivisor); + testPosX += (spriteFont.chars[i].rec.width + charsDivisor); if (testPosX > spriteFont.texture.width) { @@ -767,13 +786,13 @@ static SpriteFont LoadRBMF(const char *fileName) currentPosX = 2*charsDivisor + (int)rbmfCharWidthData[i]; testPosX = currentPosX; - spriteFont.charRecs[i].x = charsDivisor; - spriteFont.charRecs[i].y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor); + spriteFont.chars[i].rec.x = charsDivisor; + spriteFont.chars[i].rec.y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor); } else currentPosX = testPosX; } - spriteFont.size = spriteFont.charRecs[0].height; + spriteFont.baseSize = spriteFont.charRecs[0].height; TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName); } @@ -782,6 +801,7 @@ static SpriteFont LoadRBMF(const char *fileName) free(rbmfFileData); // Now we can free loaded data from RAM memory free(rbmfCharWidthData); +*/ return spriteFont; } @@ -800,7 +820,7 @@ static SpriteFont LoadBMFont(const char *fileName) int fontSize = 0; int texWidth, texHeight; char texFileName[128]; - int numChars = 0; + int charsCount = 0; int base; // Useless data @@ -834,9 +854,9 @@ static SpriteFont LoadBMFont(const char *fileName) fgets(buffer, MAX_BUFFER_SIZE, fntFile); searchPoint = strstr(buffer, "count"); - sscanf(searchPoint, "count=%i", &numChars); + sscanf(searchPoint, "count=%i", &charsCount); - TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, numChars); + TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, charsCount); // Compose correct path using route of .fnt file (fileName) and texFileName char *texPath = NULL; @@ -868,12 +888,9 @@ static SpriteFont LoadBMFont(const char *fileName) } else font.texture = LoadTextureFromImage(imFont); - font.size = fontSize; - font.numChars = numChars; - font.charValues = (int *)malloc(numChars*sizeof(int)); - font.charRecs = (Rectangle *)malloc(numChars*sizeof(Rectangle)); - font.charOffsets = (Vector2 *)malloc(numChars*sizeof(Vector2)); - font.charAdvanceX = (int *)malloc(numChars*sizeof(int)); + font.baseSize = fontSize; + font.charsCount = charsCount; + font.chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); UnloadImage(imFont); @@ -881,17 +898,18 @@ static SpriteFont LoadBMFont(const char *fileName) int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; - for (int i = 0; i < numChars; i++) + for (int i = 0; i < charsCount; i++) { fgets(buffer, MAX_BUFFER_SIZE, fntFile); sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); // Save data properly in sprite font - font.charValues[i] = charId; - font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight }; - font.charOffsets[i] = (Vector2){ (float)charOffsetX, (float)charOffsetY }; - font.charAdvanceX[i] = charAdvanceX; + font.chars[i].value = charId; + font.chars[i].rec = (Rectangle){ charX, charY, charWidth, charHeight }; + font.chars[i].offsetX = charOffsetX; + font.chars[i].offsetY = charOffsetY; + font.chars[i].advanceX = charAdvanceX; } fclose(fntFile); @@ -908,21 +926,21 @@ static SpriteFont LoadBMFont(const char *fileName) // Generate a sprite font from TTF file data (font size required) // TODO: Review texture packing method and generation (use oversampling) -static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars) +static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) { // NOTE: Font texture size is predicted (being as much conservative as possible) // Predictive method consist of supposing same number of chars by line-column (sqrtf) // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... // Calculate next power-of-two value - float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)numChars)); + float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount)); int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25); unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! - stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*numChars); + stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount); SpriteFont font = { 0 }; @@ -941,7 +959,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... // TODO: Replace this function by a proper packing method and support random chars order, // we already receive a list (fontChars) with the ordered expected characters - int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], numChars, charData); + int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], charsCount, charData); //if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font"); @@ -973,24 +991,22 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int UnloadImage(image); // Unloads dataGrayAlpha - font.size = fontSize; - font.numChars = numChars; - font.charValues = (int *)malloc(font.numChars*sizeof(int)); - font.charRecs = (Rectangle *)malloc(font.numChars*sizeof(Rectangle)); - font.charOffsets = (Vector2 *)malloc(font.numChars*sizeof(Vector2)); - font.charAdvanceX = (int *)malloc(font.numChars*sizeof(int)); + font.baseSize = fontSize; + font.charsCount = charsCount; + font.chars = (CharInfo *)malloc(font.charsCount*sizeof(CharInfo)); - for (int i = 0; i < font.numChars; i++) + for (int i = 0; i < font.charsCount; i++) { - font.charValues[i] = fontChars[i]; + font.chars[i].value = fontChars[i]; - font.charRecs[i].x = (int)charData[i].x0; - font.charRecs[i].y = (int)charData[i].y0; - font.charRecs[i].width = (int)charData[i].x1 - (int)charData[i].x0; - font.charRecs[i].height = (int)charData[i].y1 - (int)charData[i].y0; + font.chars[i].rec.x = (int)charData[i].x0; + font.chars[i].rec.y = (int)charData[i].y0; + font.chars[i].rec.width = (int)charData[i].x1 - (int)charData[i].x0; + font.chars[i].rec.height = (int)charData[i].y1 - (int)charData[i].y0; - font.charOffsets[i] = (Vector2){ charData[i].xoff, charData[i].yoff }; - font.charAdvanceX[i] = (int)charData[i].xadvance; + font.chars[i].offsetX = charData[i].xoff; + font.chars[i].offsetY = charData[i].yoff; + font.chars[i].advanceX = (int)charData[i].xadvance; } free(charData); diff --git a/raylib/text.go b/raylib/text.go index 138ff34..bdb7598 100644 --- a/raylib/text.go +++ b/raylib/text.go @@ -7,22 +7,44 @@ package raylib import "C" import "unsafe" +// SpriteFont character info +type CharInfo struct { + // Character value (Unicode) + Value int32 + // Character rectangle in sprite font + Rec Rectangle + // Character offset X when drawing + OffsetX int32 + // Character offset Y when drawing + OffsetY int32 + // Character advance position X + AdvanceX int32 +} + +func (c *CharInfo) cptr() *C.CharInfo { + return (*C.CharInfo)(unsafe.Pointer(c)) +} + +// Returns new SpriteFont +func NewCharInfo(value int32, rec Rectangle, offsetX, offsetY, advanceX int32) CharInfo { + return CharInfo{value, rec, offsetX, offsetY, advanceX} +} + +// Returns new SpriteFont from pointer +func NewCharInfoFromPointer(ptr unsafe.Pointer) CharInfo { + return *(*CharInfo)(ptr) +} + // SpriteFont type, includes texture and charSet array data type SpriteFont struct { // Font texture Texture Texture2D // Base size (default chars height) - Size int32 + BaseSize int32 // Number of characters - NumChars int32 - // Characters values array - CharValues []int32 - // Characters rectangles within the texture - CharRecs []Rectangle - // Characters offsets (on drawing) - CharOffsets []Vector2 - // Characters x advance (on drawing) - CharAdvanceX []int32 + CharsCount int32 + // Characters info data + Chars *CharInfo } func (s *SpriteFont) cptr() *C.SpriteFont { @@ -30,8 +52,8 @@ func (s *SpriteFont) cptr() *C.SpriteFont { } // Returns new SpriteFont -func NewSpriteFont(texture Texture2D, size, numChars int32, charValues []int32, charRecs []Rectangle, charOffsets []Vector2, charAdvanceX []int32) SpriteFont { - return SpriteFont{texture, size, numChars, charValues, charRecs, charOffsets, charAdvanceX} +func NewSpriteFont(texture Texture2D, baseSize, charsCount int32, chars *CharInfo) SpriteFont { + return SpriteFont{texture, baseSize, charsCount, chars} } // Returns new SpriteFont from pointer @@ -56,13 +78,13 @@ func LoadSpriteFont(fileName string) SpriteFont { } // Load a SpriteFont from TTF font with parameters -func LoadSpriteFontTTF(fileName string, fontSize int32, numChars int32, fontChars *int32) SpriteFont { +func LoadSpriteFontTTF(fileName string, fontSize int32, charsCount int32, fontChars *int32) SpriteFont { cfileName := C.CString(fileName) defer C.free(unsafe.Pointer(cfileName)) cfontSize := (C.int)(fontSize) - cnumChars := (C.int)(numChars) + ccharsCount := (C.int)(charsCount) cfontChars := (*C.int)(unsafe.Pointer(fontChars)) - ret := C.LoadSpriteFontTTF(cfileName, cfontSize, cnumChars, cfontChars) + ret := C.LoadSpriteFontTTF(cfileName, cfontSize, ccharsCount, cfontChars) v := NewSpriteFontFromPointer(unsafe.Pointer(&ret)) return v } diff --git a/raylib/textures.c b/raylib/textures.c index 9d865aa..ce978b6 100644 --- a/raylib/textures.c +++ b/raylib/textures.c @@ -1064,7 +1064,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing int length = strlen(text); int posX = 0; - Vector2 imSize = MeasureTextEx(font, text, font.size, spacing); + Vector2 imSize = MeasureTextEx(font, text, font.baseSize, spacing); // NOTE: GetTextureData() not available in OpenGL ES Image imFont = GetTextureData(font.texture); @@ -1080,7 +1080,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing for (int i = 0; i < length; i++) { - Rectangle letterRec = font.charRecs[(int)text[i] - 32]; + Rectangle letterRec = font.chars[(int)text[i] - 32].rec; for (int y = letterRec.y; y < (letterRec.y + letterRec.height); y++) {