Update C sources, add new functions

This commit is contained in:
Milan Nikolic 2017-02-10 11:28:19 +01:00
parent ac3cb63287
commit 2f90318d30
17 changed files with 332 additions and 242 deletions

View file

@ -19,8 +19,8 @@ func main() {
fontPosition := raylib.Vector2{} fontPosition := raylib.Vector2{}
fontPosition.X = float32(screenWidth)/2 - raylib.MeasureTextEx(fontBm, msgBm, float32(fontBm.Size), 0).X/2 fontPosition.X = float32(screenWidth)/2 - raylib.MeasureTextEx(fontBm, msgBm, float32(fontBm.BaseSize), 0).X/2
fontPosition.Y = float32(screenHeight)/2 - float32(fontBm.Size)/2 - 80 fontPosition.Y = float32(screenHeight)/2 - float32(fontBm.BaseSize)/2 - 80
raylib.SetTargetFPS(60) raylib.SetTargetFPS(60)
@ -29,8 +29,8 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.DrawTextEx(fontBm, msgBm, fontPosition, float32(fontBm.Size), 0, raylib.Maroon) raylib.DrawTextEx(fontBm, msgBm, fontPosition, float32(fontBm.BaseSize), 0, raylib.Maroon)
raylib.DrawTextEx(fontTtf, msgTtf, raylib.NewVector2(75.0, 240.0), float32(fontTtf.Size)*0.8, 2, raylib.Lime) raylib.DrawTextEx(fontTtf, msgTtf, raylib.NewVector2(75.0, 240.0), float32(fontTtf.BaseSize)*0.8, 2, raylib.Lime)
raylib.EndDrawing() raylib.EndDrawing()
} }

View file

@ -27,10 +27,10 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.DrawText("Font name: PixAntiqua", 40, 50, 20, raylib.Gray) 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 base size: %d", font.BaseSize), 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 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() raylib.EndDrawing()
} }

View file

@ -30,7 +30,7 @@ func main() {
text := "THIS is THE FONT you SELECTED!" // Main text 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{} mousePoint := raylib.Vector2{}
@ -112,7 +112,7 @@ func main() {
} }
// Text measurement for better positioning on screen // 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 // Draw
raylib.BeginDrawing() raylib.BeginDrawing()
@ -131,7 +131,7 @@ func main() {
raylib.DrawRectangle(675, positionY+2, 105, 40, btnNextInColor) raylib.DrawRectangle(675, positionY+2, 105, 40, btnNextInColor)
raylib.DrawText("NEXT", 700, positionY+13, 20, btnNextOutColor) 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() raylib.EndDrawing()
} }

View file

@ -36,8 +36,8 @@ func main() {
var i int32 var i int32
for i = 0; i < 8; i++ { 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) x := screenWidth/2 - int32(raylib.MeasureTextEx(fonts[i], messages[i], float32(fonts[i].BaseSize*2), spacings[i]).X/2)
y := 60 + fonts[i].Size + 45*i y := 60 + fonts[i].BaseSize + 45*i
positions[i] = raylib.NewVector2(float32(x), float32(y)) positions[i] = raylib.NewVector2(float32(x), float32(y))
} }
@ -53,7 +53,7 @@ func main() {
raylib.DrawLine(220, 50, 590, 50, raylib.DarkGray) raylib.DrawLine(220, 50, 590, 50, raylib.DarkGray)
for i = 0; i < 8; i++ { 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() raylib.EndDrawing()

View file

@ -21,14 +21,14 @@ func main() {
var fontPosition1, fontPosition2, fontPosition3 raylib.Vector2 var fontPosition1, fontPosition2, fontPosition3 raylib.Vector2
fontPosition1.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font1, msg1, float32(font1.Size), -3).X/2 fontPosition1.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font1, msg1, float32(font1.BaseSize), -3).X/2
fontPosition1.Y = float32(screenHeight)/2 - float32(font1.Size)/2 - 80 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.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font2, msg2, float32(font2.BaseSize), -2).X/2
fontPosition2.Y = float32(screenHeight)/2 - float32(font2.Size)/2 - 10 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.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font3, msg3, float32(font3.BaseSize), 2).X/2
fontPosition3.Y = float32(screenHeight)/2 - float32(font3.Size)/2 + 50 fontPosition3.Y = float32(screenHeight)/2 - float32(font3.BaseSize)/2 + 50
raylib.SetTargetFPS(60) raylib.SetTargetFPS(60)
@ -37,9 +37,9 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.DrawTextEx(font1, msg1, fontPosition1, float32(font1.Size), -3, raylib.White) raylib.DrawTextEx(font1, msg1, fontPosition1, float32(font1.BaseSize), -3, raylib.White)
raylib.DrawTextEx(font2, msg2, fontPosition2, float32(font2.Size), -2, raylib.White) raylib.DrawTextEx(font2, msg2, fontPosition2, float32(font2.BaseSize), -2, raylib.White)
raylib.DrawTextEx(font3, msg3, fontPosition3, float32(font3.Size), 2, raylib.White) raylib.DrawTextEx(font3, msg3, fontPosition3, float32(font3.BaseSize), 2, raylib.White)
raylib.EndDrawing() raylib.EndDrawing()
} }

View file

@ -25,7 +25,7 @@ func main() {
// NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR // NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR
raylib.GenTextureMipmaps(&font.Texture) raylib.GenTextureMipmaps(&font.Texture)
fontSize := font.Size fontSize := font.BaseSize
fontPosition := raylib.NewVector2(40, float32(screenHeight)/2+50) fontPosition := raylib.NewVector2(40, float32(screenHeight)/2+50)
textSize := raylib.Vector2{} textSize := raylib.Vector2{}

View file

@ -128,7 +128,7 @@ typedef struct MusicData {
AudioStream stream; // Audio stream (double buffering) 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 totalSamples; // Total number of samples
unsigned int samplesLeft; // Number of samples left to end unsigned int samplesLeft; // Number of samples left to end
} MusicData; } MusicData;
@ -182,9 +182,11 @@ void InitAudioDevice(void)
TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
// Listener definition (just for 2D) // Listener definition (just for 2D)
alListener3f(AL_POSITION, 0, 0, 0); alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f);
alListener3f(AL_VELOCITY, 0, 0, 0); alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alListener3f(AL_ORIENTATION, 0, 0, -1); 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) // Module Functions Definition - Sounds loading and playing (.WAV)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -318,10 +329,10 @@ Sound LoadSoundFromWave(Wave wave)
ALuint source; ALuint source;
alGenSources(1, &source); // Generate pointer to audio source alGenSources(1, &source); // Generate pointer to audio source
alSourcef(source, AL_PITCH, 1); alSourcef(source, AL_PITCH, 1.0f);
alSourcef(source, AL_GAIN, 1); alSourcef(source, AL_GAIN, 1.0f);
alSource3f(source, AL_POSITION, 0, 0, 0); alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_VELOCITY, 0, 0, 0); alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcei(source, AL_LOOPING, AL_FALSE); alSourcei(source, AL_LOOPING, AL_FALSE);
// Convert loaded data to OpenAL buffer // 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->totalSamples = (unsigned int)stb_vorbis_stream_length_in_samples(music->ctxOgg); // Independent by channel
music->samplesLeft = music->totalSamples; music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_AUDIO_OGG; 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] FLAC total samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate); 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->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount/music->ctxFlac->channels;
music->samplesLeft = music->totalSamples; music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_AUDIO_FLAC; 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 total samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate); TraceLog(DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate);
@ -666,7 +677,7 @@ Music LoadMusicStream(const char *fileName)
music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm); music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm);
music->samplesLeft = music->totalSamples; music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_MODULE_XM; 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 number of samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); 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->totalSamples = (unsigned int)jar_mod_max_samples(&music->ctxMod);
music->samplesLeft = music->totalSamples; music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_MODULE_MOD; 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 number of samples: %i", fileName, music->samplesLeft);
TraceLog(DEBUG, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); 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) if (!active)
{ {
StopMusicStream(music); // Stop music (and reset) 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 else
{ {
@ -845,6 +862,13 @@ void SetMusicPitch(Music music, float pitch)
alSourcef(music->stream.source, AL_PITCH, 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) // Get music time length (in seconds)
float GetMusicTimeLength(Music music) float GetMusicTimeLength(Music music)
{ {
@ -904,10 +928,10 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
// Create an audio source // Create an audio source
alGenSources(1, &stream.source); alGenSources(1, &stream.source);
alSourcef(stream.source, AL_PITCH, 1); alSourcef(stream.source, AL_PITCH, 1.0f);
alSourcef(stream.source, AL_GAIN, 1); alSourcef(stream.source, AL_GAIN, 1.0f);
alSource3f(stream.source, AL_POSITION, 0, 0, 0); alSource3f(stream.source, AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(stream.source, AL_VELOCITY, 0, 0, 0); alSource3f(stream.source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
// Create Buffers (double buffering) // Create Buffers (double buffering)
alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers); alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers);

View file

@ -112,6 +112,12 @@ func IsAudioDeviceReady() bool {
return v return v
} }
// Set master volume (listener)
func SetMasterVolume(volume float32) {
cvolume := (C.float)(volume)
C.SetMasterVolume(cvolume)
}
// Load wave data from file into RAM // Load wave data from file into RAM
func LoadWave(fileName string) Wave { func LoadWave(fileName string) Wave {
cfileName := C.CString(fileName) cfileName := C.CString(fileName)
@ -321,6 +327,14 @@ func SetMusicPitch(music Music, pitch float32) {
C.SetMusicPitch(cmusic, cpitch) 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) // Get music time length (in seconds)
func GetMusicTimeLength(music Music) float32 { func GetMusicTimeLength(music Music) float32 {
cmusic := *(*C.Music)(unsafe.Pointer(&music)) cmusic := *(*C.Music)(unsafe.Pointer(&music))

View file

@ -109,6 +109,7 @@ extern "C" { // Prevents name mangling of functions
void InitAudioDevice(void); // Initialize audio device and context void InitAudioDevice(void); // Initialize audio device and context
void CloseAudioDevice(void); // Close the audio device and context void CloseAudioDevice(void); // Close the audio device and context
bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully 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 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 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 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 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 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 GetMusicTimeLength(Music music); // Get music time length (in seconds)
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)

View file

@ -524,7 +524,7 @@ bool IsWindowMinimized(void)
#endif #endif
} }
// Fullscreen toggle // Fullscreen toggle (only PLATFORM_DESKTOP)
void ToggleFullscreen(void) void ToggleFullscreen(void)
{ {
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
@ -540,6 +540,25 @@ void ToggleFullscreen(void)
#endif #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 // Get current screen width
int GetScreenWidth(void) int GetScreenWidth(void)
{ {

View file

@ -484,6 +484,12 @@ func ToggleFullscreen() {
C.ToggleFullscreen() C.ToggleFullscreen()
} }
// Set icon for window (only PLATFORM_DESKTOP)
func SetWindowIcon(image Image) {
cimage := image.cptr()
C.SetWindowIcon(*cimage)
}
// Get current screen width // Get current screen width
func GetScreenWidth() int32 { func GetScreenWidth() int32 {
ret := C.GetScreenWidth() ret := C.GetScreenWidth()

View file

@ -366,15 +366,21 @@ typedef struct RenderTexture2D {
Texture2D depth; // Depth buffer attachment texture Texture2D depth; // Depth buffer attachment texture
} RenderTexture2D; } 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 // SpriteFont type, includes texture and charSet array data
typedef struct SpriteFont { typedef struct SpriteFont {
Texture2D texture; // Font texture Texture2D texture; // Font texture
int size; // Base size (default chars height) int baseSize; // Base size (default chars height)
int numChars; // Number of characters int charsCount; // Number of characters
int *charValues; // Characters values array CharInfo *chars; // Characters info data
Rectangle *charRecs; // Characters rectangles within the texture
Vector2 *charOffsets; // Characters offsets (on drawing)
int *charAdvanceX; // Characters x advance (on drawing)
} SpriteFont; } SpriteFont;
// Camera type, defines a camera position/orientation in 3d space // Camera type, defines a camera position/orientation in 3d space
@ -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 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 bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus)
RLAPI void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP) 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 GetScreenWidth(void); // Get current screen width
RLAPI int GetScreenHeight(void); // Get current screen height RLAPI int GetScreenHeight(void); // Get current screen height
@ -821,7 +828,7 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont
RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM) 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 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) RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
@ -936,6 +943,7 @@ RLAPI void ToggleVrMode(void); // Enable/Disable VR experienc
RLAPI void InitAudioDevice(void); // Initialize audio device and context RLAPI void InitAudioDevice(void); // Initialize audio device and context
RLAPI void CloseAudioDevice(void); // Close the 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 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 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 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 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 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 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 GetMusicTimeLength(Music music); // Get music time length (in seconds)
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)

View file

@ -251,25 +251,6 @@ typedef unsigned char byte;
float fovy; // Camera field-of-view apperture in Y (degrees) float fovy; // Camera field-of-view apperture in Y (degrees)
} Camera; } 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 // Texture parameters: filter mode
// NOTE 1: Filtering considers mipmaps if available in the texture // NOTE 1: Filtering considers mipmaps if available in the texture
// NOTE 2: Filter is accordingly set for minification and magnification // 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 BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
void EndBlendMode(void); // End blending mode (reset to default: alpha blending) 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, ...); void TraceLog(int msgType, const char *text, ...);
float *MatrixToFloat(Matrix mat); float *MatrixToFloat(Matrix mat);

View file

@ -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 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 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 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 LoadDefaultFont(void);
extern void UnloadDefaultFont(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 // 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 // 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) // Default font is directly defined here (data generated from a sprite font image)
// This way, we reconstruct SpriteFont without creating large global variables // This way, we reconstruct SpriteFont without creating large global variables
@ -189,29 +189,27 @@ extern void LoadDefaultFont(void)
defaultFont.texture = LoadTextureFromImage(image); defaultFont.texture = LoadTextureFromImage(image);
UnloadImage(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)); // Allocate space for our characters info data
defaultFont.charAdvanceX = (int *)malloc(defaultFont.numChars*sizeof(int)); // NOTE: This memory should be freed at end! --> CloseWindow()
defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo));
int currentLine = 0; int currentLine = 0;
int currentPosX = charsDivisor; int currentPosX = charsDivisor;
int testPosX = 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.chars[i].rec.x = currentPosX;
defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor);
defaultFont.charRecs[i].width = charsWidth[i]; defaultFont.chars[i].rec.width = charsWidth[i];
defaultFont.charRecs[i].height = charsHeight; defaultFont.chars[i].rec.height = charsHeight;
testPosX += (defaultFont.charRecs[i].width + charsDivisor); testPosX += (defaultFont.chars[i].rec.width + charsDivisor);
if (testPosX >= defaultFont.texture.width) if (testPosX >= defaultFont.texture.width)
{ {
@ -219,17 +217,18 @@ extern void LoadDefaultFont(void)
currentPosX = 2*charsDivisor + charsWidth[i]; currentPosX = 2*charsDivisor + charsWidth[i];
testPosX = currentPosX; testPosX = currentPosX;
defaultFont.charRecs[i].x = charsDivisor; defaultFont.chars[i].rec.x = charsDivisor;
defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor);
} }
else currentPosX = testPosX; else currentPosX = testPosX;
// NOTE: On default font character offsets and xAdvance are not required // NOTE: On default font character offsets and xAdvance are not required
defaultFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; defaultFont.chars[i].offsetX = 0;
defaultFont.charAdvanceX[i] = 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); TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
} }
@ -237,10 +236,7 @@ extern void LoadDefaultFont(void)
extern void UnloadDefaultFont(void) extern void UnloadDefaultFont(void)
{ {
UnloadTexture(defaultFont.texture); UnloadTexture(defaultFont.texture);
free(defaultFont.charValues); free(defaultFont.chars);
free(defaultFont.charRecs);
free(defaultFont.charOffsets);
free(defaultFont.charAdvanceX);
} }
// Get the default font, useful to be used with extended parameters // Get the default font, useful to be used with extended parameters
@ -260,9 +256,37 @@ SpriteFont LoadSpriteFont(const char *fileName)
SpriteFont spriteFont = { 0 }; SpriteFont spriteFont = { 0 };
// Check file extension // 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),"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),"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 else
{ {
Image image = LoadImage(fileName); Image image = LoadImage(fileName);
@ -283,13 +307,13 @@ SpriteFont LoadSpriteFont(const char *fileName)
// Load SpriteFont from TTF font file with generation parameters // 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 // 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 // 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 }; SpriteFont spriteFont = { 0 };
if (strcmp(GetExtension(fileName),"ttf") == 0) if (strcmp(GetExtension(fileName),"ttf") == 0)
{ {
if ((fontChars == NULL) || (numChars == 0)) if ((fontChars == NULL) || (charsCount == 0))
{ {
int totalChars = 95; // Default charset [32..126] 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); 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) if (spriteFont.texture.id == 0)
@ -318,10 +342,7 @@ void UnloadSpriteFont(SpriteFont spriteFont)
if (spriteFont.texture.id != defaultFont.texture.id) if (spriteFont.texture.id != defaultFont.texture.id)
{ {
UnloadTexture(spriteFont.texture); UnloadTexture(spriteFont.texture);
free(spriteFont.charValues); free(spriteFont.chars);
free(spriteFont.charRecs);
free(spriteFont.charOffsets);
free(spriteFont.charAdvanceX);
TraceLog(DEBUG, "Unloaded sprite font data"); 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 unsigned char letter; // Current character
int index; // Index position in sprite font 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 // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly
// written in C code files (codified by default as UTF-8) // 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') if ((unsigned char)text[i] == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 lines // 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; textOffsetX = 0;
} }
else else
@ -388,14 +409,14 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
} }
else index = GetCharIndex(spriteFont, (int)text[i]); else index = GetCharIndex(spriteFont, (int)text[i]);
DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index], DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec,
(Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor, (Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor,
position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor, position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor,
spriteFont.charRecs[index].width*scaleFactor, spriteFont.chars[index].rec.width*scaleFactor,
spriteFont.charRecs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); 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); if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing);
else textOffsetX += (int)(spriteFont.charAdvanceX[index]*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 textWidth = 0;
float tempTextWidth = 0; // Used to count longer text line width float tempTextWidth = 0; // Used to count longer text line width
float textHeight = (float)spriteFont.size; float textHeight = (float)spriteFont.baseSize;
float scaleFactor = fontSize/(float)spriteFont.size; float scaleFactor = fontSize/(float)spriteFont.baseSize;
for (int i = 0; i < len; i++) 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]); int index = GetCharIndex(spriteFont, (int)text[i]);
if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index]; if (spriteFont.chars[index].advanceX != 0) textWidth += spriteFont.chars[index].advanceX;
else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x); else textWidth += (spriteFont.chars[index].rec.width + spriteFont.chars[index].offsetX);
} }
else else
{ {
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
lenCounter = 0; lenCounter = 0;
textWidth = 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; if (tempLen < lenCounter) tempLen = lenCounter;
@ -518,9 +539,9 @@ static int GetCharIndex(SpriteFont font, int letter)
#if defined(UNORDERED_CHARSET) #if defined(UNORDERED_CHARSET)
int index = 0; 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; index = i;
break; break;
@ -621,28 +642,26 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
SpriteFont spriteFont = { 0 }; SpriteFont spriteFont = { 0 };
spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture 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 UnloadImage(fontClear); // Unload processed image once converted to texture
// We got tempCharValues and tempCharsRecs populated with chars data // We got tempCharValues and tempCharsRecs populated with chars data
// Now we move temp data to sized charValues and charRecs arrays // Now we move temp data to sized charValues and charRecs arrays
spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle)); spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo));
spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int));
spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2));
spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int));
for (int i = 0; i < spriteFont.numChars; i++) for (int i = 0; i < spriteFont.charsCount; i++)
{ {
spriteFont.charValues[i] = tempCharValues[i]; spriteFont.chars[i].value = tempCharValues[i];
spriteFont.charRecs[i] = tempCharRecs[i]; spriteFont.chars[i].rec = tempCharRecs[i];
// NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) // 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.chars[i].offsetX = 0;
spriteFont.charAdvanceX[i] = 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"); TraceLog(INFO, "Image file loaded correctly as SpriteFont");
@ -672,6 +691,8 @@ static SpriteFont LoadRBMF(const char *fileName)
SpriteFont spriteFont = { 0 }; SpriteFont spriteFont = { 0 };
// REMOVE SOON!!!
/*
rbmfInfoHeader rbmfHeader; rbmfInfoHeader rbmfHeader;
unsigned int *rbmfFileData = NULL; unsigned int *rbmfFileData = NULL;
unsigned char *rbmfCharWidthData = NULL; unsigned char *rbmfCharWidthData = NULL;
@ -737,29 +758,27 @@ static SpriteFont LoadRBMF(const char *fileName)
//TraceLog(INFO, "[%s] Starting chars set reconstruction", fileName); //TraceLog(INFO, "[%s] Starting chars set reconstruction", fileName);
// Get characters data using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars // Get characters data using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars
spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int)); spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo));
spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle));
spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2));
spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int));
int currentLine = 0; int currentLine = 0;
int currentPosX = charsDivisor; int currentPosX = charsDivisor;
int testPosX = 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.chars[i].rec.x = currentPosX;
spriteFont.charRecs[i].y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor); spriteFont.chars[i].rec.y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor);
spriteFont.charRecs[i].width = (int)rbmfCharWidthData[i]; spriteFont.chars[i].rec.width = (int)rbmfCharWidthData[i];
spriteFont.charRecs[i].height = (int)rbmfHeader.charHeight; 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) // 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.chars[i].offsetX = 0;
spriteFont.charAdvanceX[i] = 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) if (testPosX > spriteFont.texture.width)
{ {
@ -767,13 +786,13 @@ static SpriteFont LoadRBMF(const char *fileName)
currentPosX = 2*charsDivisor + (int)rbmfCharWidthData[i]; currentPosX = 2*charsDivisor + (int)rbmfCharWidthData[i];
testPosX = currentPosX; testPosX = currentPosX;
spriteFont.charRecs[i].x = charsDivisor; spriteFont.chars[i].rec.x = charsDivisor;
spriteFont.charRecs[i].y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor); spriteFont.chars[i].rec.y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor);
} }
else currentPosX = testPosX; 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); 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(rbmfFileData); // Now we can free loaded data from RAM memory
free(rbmfCharWidthData); free(rbmfCharWidthData);
*/
return spriteFont; return spriteFont;
} }
@ -800,7 +820,7 @@ static SpriteFont LoadBMFont(const char *fileName)
int fontSize = 0; int fontSize = 0;
int texWidth, texHeight; int texWidth, texHeight;
char texFileName[128]; char texFileName[128];
int numChars = 0; int charsCount = 0;
int base; // Useless data int base; // Useless data
@ -834,9 +854,9 @@ static SpriteFont LoadBMFont(const char *fileName)
fgets(buffer, MAX_BUFFER_SIZE, fntFile); fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "count"); 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 // Compose correct path using route of .fnt file (fileName) and texFileName
char *texPath = NULL; char *texPath = NULL;
@ -868,12 +888,9 @@ static SpriteFont LoadBMFont(const char *fileName)
} }
else font.texture = LoadTextureFromImage(imFont); else font.texture = LoadTextureFromImage(imFont);
font.size = fontSize; font.baseSize = fontSize;
font.numChars = numChars; font.charsCount = charsCount;
font.charValues = (int *)malloc(numChars*sizeof(int)); font.chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo));
font.charRecs = (Rectangle *)malloc(numChars*sizeof(Rectangle));
font.charOffsets = (Vector2 *)malloc(numChars*sizeof(Vector2));
font.charAdvanceX = (int *)malloc(numChars*sizeof(int));
UnloadImage(imFont); UnloadImage(imFont);
@ -881,17 +898,18 @@ static SpriteFont LoadBMFont(const char *fileName)
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; 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); 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", 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); &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
// Save data properly in sprite font // Save data properly in sprite font
font.charValues[i] = charId; font.chars[i].value = charId;
font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight }; font.chars[i].rec = (Rectangle){ charX, charY, charWidth, charHeight };
font.charOffsets[i] = (Vector2){ (float)charOffsetX, (float)charOffsetY }; font.chars[i].offsetX = charOffsetX;
font.charAdvanceX[i] = charAdvanceX; font.chars[i].offsetY = charOffsetY;
font.chars[i].advanceX = charAdvanceX;
} }
fclose(fntFile); fclose(fntFile);
@ -908,21 +926,21 @@ static SpriteFont LoadBMFont(const char *fileName)
// Generate a sprite font from TTF file data (font size required) // Generate a sprite font from TTF file data (font size required)
// TODO: Review texture packing method and generation (use oversampling) // 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) // 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) // 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... // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests...
// Calculate next power-of-two value // 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 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); TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize);
unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25); unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25);
unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! 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 }; 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... // 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, // 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 // 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(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"); 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 UnloadImage(image); // Unloads dataGrayAlpha
font.size = fontSize; font.baseSize = fontSize;
font.numChars = numChars; font.charsCount = charsCount;
font.charValues = (int *)malloc(font.numChars*sizeof(int)); font.chars = (CharInfo *)malloc(font.charsCount*sizeof(CharInfo));
font.charRecs = (Rectangle *)malloc(font.numChars*sizeof(Rectangle));
font.charOffsets = (Vector2 *)malloc(font.numChars*sizeof(Vector2));
font.charAdvanceX = (int *)malloc(font.numChars*sizeof(int));
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.chars[i].rec.x = (int)charData[i].x0;
font.charRecs[i].y = (int)charData[i].y0; font.chars[i].rec.y = (int)charData[i].y0;
font.charRecs[i].width = (int)charData[i].x1 - (int)charData[i].x0; font.chars[i].rec.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.height = (int)charData[i].y1 - (int)charData[i].y0;
font.charOffsets[i] = (Vector2){ charData[i].xoff, charData[i].yoff }; font.chars[i].offsetX = charData[i].xoff;
font.charAdvanceX[i] = (int)charData[i].xadvance; font.chars[i].offsetY = charData[i].yoff;
font.chars[i].advanceX = (int)charData[i].xadvance;
} }
free(charData); free(charData);

View file

@ -7,22 +7,44 @@ package raylib
import "C" import "C"
import "unsafe" 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 // SpriteFont type, includes texture and charSet array data
type SpriteFont struct { type SpriteFont struct {
// Font texture // Font texture
Texture Texture2D Texture Texture2D
// Base size (default chars height) // Base size (default chars height)
Size int32 BaseSize int32
// Number of characters // Number of characters
NumChars int32 CharsCount int32
// Characters values array // Characters info data
CharValues []int32 Chars *CharInfo
// Characters rectangles within the texture
CharRecs []Rectangle
// Characters offsets (on drawing)
CharOffsets []Vector2
// Characters x advance (on drawing)
CharAdvanceX []int32
} }
func (s *SpriteFont) cptr() *C.SpriteFont { func (s *SpriteFont) cptr() *C.SpriteFont {
@ -30,8 +52,8 @@ func (s *SpriteFont) cptr() *C.SpriteFont {
} }
// Returns new SpriteFont // Returns new SpriteFont
func NewSpriteFont(texture Texture2D, size, numChars int32, charValues []int32, charRecs []Rectangle, charOffsets []Vector2, charAdvanceX []int32) SpriteFont { func NewSpriteFont(texture Texture2D, baseSize, charsCount int32, chars *CharInfo) SpriteFont {
return SpriteFont{texture, size, numChars, charValues, charRecs, charOffsets, charAdvanceX} return SpriteFont{texture, baseSize, charsCount, chars}
} }
// Returns new SpriteFont from pointer // Returns new SpriteFont from pointer
@ -56,13 +78,13 @@ func LoadSpriteFont(fileName string) SpriteFont {
} }
// Load a SpriteFont from TTF font with parameters // 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) cfileName := C.CString(fileName)
defer C.free(unsafe.Pointer(cfileName)) defer C.free(unsafe.Pointer(cfileName))
cfontSize := (C.int)(fontSize) cfontSize := (C.int)(fontSize)
cnumChars := (C.int)(numChars) ccharsCount := (C.int)(charsCount)
cfontChars := (*C.int)(unsafe.Pointer(fontChars)) 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)) v := NewSpriteFontFromPointer(unsafe.Pointer(&ret))
return v return v
} }

View file

@ -1064,7 +1064,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
int length = strlen(text); int length = strlen(text);
int posX = 0; 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 // NOTE: GetTextureData() not available in OpenGL ES
Image imFont = GetTextureData(font.texture); 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++) 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++) for (int y = letterRec.y; y < (letterRec.y + letterRec.height); y++)
{ {