Fixed relative file paths
parent
1fa199512d
commit
376349b922
78
code/vn.cpp
78
code/vn.cpp
|
@ -19,50 +19,50 @@
|
||||||
|
|
||||||
struct vn_state
|
struct vn_state
|
||||||
{
|
{
|
||||||
memory_arena Arena;
|
memory_arena Arena;
|
||||||
glyph_atlas *GlyphAtlas;
|
glyph_atlas *GlyphAtlas;
|
||||||
|
|
||||||
config *Config;
|
config *Config;
|
||||||
|
|
||||||
ui UI;
|
ui UI;
|
||||||
workspace Workspace;
|
workspace Workspace;
|
||||||
animation_curve_state AnimationCurveState;
|
animation_curve_state AnimationCurveState;
|
||||||
};
|
};
|
||||||
|
|
||||||
VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
|
VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
|
||||||
{
|
{
|
||||||
SetThreadContext(ThreadContext);
|
SetThreadContext(ThreadContext);
|
||||||
Platform = Memory->PlatformAPI;
|
Platform = Memory->PlatformAPI;
|
||||||
|
|
||||||
|
vn_state *State = Memory->State;
|
||||||
|
|
||||||
|
if(!Memory->State)
|
||||||
|
{
|
||||||
|
State = Memory->State = BootstrapPushStruct(vn_state, Arena);
|
||||||
|
|
||||||
vn_state *State = Memory->State;
|
State->GlyphAtlas = CreateGlyphAtlas(RenderCommands);
|
||||||
|
State->Config = BootstrapPushStruct(config, Arena);
|
||||||
|
|
||||||
if(!Memory->State)
|
Config_BindEntry(State->Config, StrLit("Platform/RefreshRate"), Config_Entry_S32, &Input->RefreshRate);
|
||||||
{
|
|
||||||
State = Memory->State = BootstrapPushStruct(vn_state, Arena);
|
|
||||||
|
|
||||||
State->GlyphAtlas = CreateGlyphAtlas(RenderCommands);
|
|
||||||
State->Config = BootstrapPushStruct(config, Arena);
|
|
||||||
|
|
||||||
Config_BindEntry(State->Config, StrLit("Platform/RefreshRate"), Config_Entry_S32, &Input->RefreshRate);
|
|
||||||
|
|
||||||
Workspace_Init(&State->Workspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
|
Workspace_Init(&State->Workspace);
|
||||||
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP);
|
}
|
||||||
|
|
||||||
Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
|
AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
|
||||||
UI_SignalFromBox(UI_GetState()->ContainerNode); // sixten(TODO): Move elsewhere.
|
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP);
|
||||||
|
|
||||||
for(platform_event *Event = Input->EventList->First;
|
Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
|
||||||
Event != 0;
|
UI_SignalFromBox(UI_GetState()->ContainerNode); // sixten(TODO): Move elsewhere.
|
||||||
Event = Event->Next)
|
|
||||||
{
|
for(platform_event *Event = Input->EventList->First;
|
||||||
Platform_ConsumeEvent(Input->EventList, Event);
|
Event != 0;
|
||||||
}
|
Event = Event->Next)
|
||||||
|
{
|
||||||
render_group Group = BeginRenderGroup(RenderCommands);
|
Platform_ConsumeEvent(Input->EventList, Event);
|
||||||
PushClear(&Group, V3(0.1, 0.1, 0.1));
|
}
|
||||||
|
|
||||||
UI_RenderFrame(&Group, State->GlyphAtlas);
|
render_group Group = BeginRenderGroup(RenderCommands);
|
||||||
|
PushClear(&Group, V3(0.1, 0.1, 0.1));
|
||||||
|
|
||||||
|
UI_RenderFrame(&Group, State->GlyphAtlas);
|
||||||
}
|
}
|
338
code/vn_font.cpp
338
code/vn_font.cpp
|
@ -2,223 +2,223 @@
|
||||||
|
|
||||||
inline s32 GetSubpixelSegmentAtP(r32 Value)
|
inline s32 GetSubpixelSegmentAtP(r32 Value)
|
||||||
{
|
{
|
||||||
s32 Result = (s32)(Value - Floor(Value))*GLYPH_SUBPIXEL_SEGMENTS;
|
s32 Result = (s32)(Value - Floor(Value))*GLYPH_SUBPIXEL_SEGMENTS;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RasterizeGlyph(glyph_atlas *Atlas, font_id Font, glyph *Glyph, u32 Codepoint, r32 Size, s32 Subpixel)
|
static void RasterizeGlyph(glyph_atlas *Atlas, font_id Font, glyph *Glyph, u32 Codepoint, r32 Size, s32 Subpixel)
|
||||||
{
|
{
|
||||||
Glyph->Font = Font;
|
Glyph->Font = Font;
|
||||||
Glyph->Codepoint = Codepoint;
|
Glyph->Codepoint = Codepoint;
|
||||||
Glyph->Size = Size;
|
Glyph->Size = Size;
|
||||||
Glyph->Subpixel = Subpixel;
|
Glyph->Subpixel = Subpixel;
|
||||||
|
|
||||||
Assert(Subpixel < GLYPH_SUBPIXEL_SEGMENTS);
|
Assert(Subpixel < GLYPH_SUBPIXEL_SEGMENTS);
|
||||||
|
|
||||||
loaded_font *LoadedFont = Atlas->Fonts + Font;
|
loaded_font *LoadedFont = Atlas->Fonts + Font;
|
||||||
stbtt_fontinfo *Info = &LoadedFont->Info;
|
stbtt_fontinfo *Info = &LoadedFont->Info;
|
||||||
|
|
||||||
r32 Scale = stbtt_ScaleForMappingEmToPixels(Info, Size);
|
r32 Scale = stbtt_ScaleForMappingEmToPixels(Info, Size);
|
||||||
|
|
||||||
s32 InternalIndex = (s32)(Glyph - Atlas->Glyphs);
|
s32 InternalIndex = (s32)(Glyph - Atlas->Glyphs);
|
||||||
s32 GlyphsPerRow = Atlas->BitmapSize / Atlas->GlyphSize;
|
s32 GlyphsPerRow = Atlas->BitmapSize / Atlas->GlyphSize;
|
||||||
|
|
||||||
v2s BaseTextureOffset = V2S((InternalIndex % GlyphsPerRow)*Atlas->GlyphSize,
|
v2s BaseTextureOffset = V2S((InternalIndex % GlyphsPerRow)*Atlas->GlyphSize,
|
||||||
(InternalIndex / GlyphsPerRow)*Atlas->GlyphSize);
|
(InternalIndex / GlyphsPerRow)*Atlas->GlyphSize);
|
||||||
|
|
||||||
int GlyphIndex = stbtt_FindGlyphIndex(Info, Codepoint);
|
int GlyphIndex = stbtt_FindGlyphIndex(Info, Codepoint);
|
||||||
|
|
||||||
stbtt_GetGlyphBitmapBoxSubpixel(Info, GlyphIndex, Scale, Scale,
|
stbtt_GetGlyphBitmapBoxSubpixel(Info, GlyphIndex, Scale, Scale,
|
||||||
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
|
||||||
&Glyph->P0.x, &Glyph->P0.y, &Glyph->P1.x, &Glyph->P1.y);
|
|
||||||
|
|
||||||
ZeroSize(Atlas->BitmapBuffer, Atlas->GlyphSize*Atlas->GlyphSize);
|
|
||||||
stbtt_MakeGlyphBitmapSubpixel(Info, Atlas->BitmapBuffer,
|
|
||||||
Atlas->GlyphSize, Atlas->GlyphSize, Atlas->GlyphSize,
|
|
||||||
Scale, Scale,
|
|
||||||
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
||||||
GlyphIndex);
|
&Glyph->P0.x, &Glyph->P0.y, &Glyph->P1.x, &Glyph->P1.y);
|
||||||
|
|
||||||
s32 Advance, LeftSideBearing;
|
ZeroSize(Atlas->BitmapBuffer, Atlas->GlyphSize*Atlas->GlyphSize);
|
||||||
stbtt_GetGlyphHMetrics(Info, GlyphIndex, &Advance, &LeftSideBearing);
|
stbtt_MakeGlyphBitmapSubpixel(Info, Atlas->BitmapBuffer,
|
||||||
Glyph->Advance = Advance*Scale;
|
Atlas->GlyphSize, Atlas->GlyphSize, Atlas->GlyphSize,
|
||||||
Glyph->Offset.x = LeftSideBearing*Scale;
|
Scale, Scale,
|
||||||
|
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
||||||
Glyph->Offset.y = Glyph->P0.y + (LoadedFont->Ascent + LoadedFont->LineGap)*Scale;
|
GlyphIndex);
|
||||||
|
|
||||||
v2s Dim = Glyph->P1 - Glyph->P0;
|
s32 Advance, LeftSideBearing;
|
||||||
|
stbtt_GetGlyphHMetrics(Info, GlyphIndex, &Advance, &LeftSideBearing);
|
||||||
Glyph->P0 = BaseTextureOffset;
|
Glyph->Advance = Advance*Scale;
|
||||||
Glyph->P1 = BaseTextureOffset + Dim + V2S(2, 2);
|
Glyph->Offset.x = LeftSideBearing*Scale;
|
||||||
|
|
||||||
Atlas->RenderCommands->FillRegion(Atlas->Texture,
|
Glyph->Offset.y = Glyph->P0.y + (LoadedFont->Ascent + LoadedFont->LineGap)*Scale;
|
||||||
BaseTextureOffset, V2S(Atlas->GlyphSize, Atlas->GlyphSize),
|
|
||||||
Atlas->BitmapBuffer);
|
v2s Dim = Glyph->P1 - Glyph->P0;
|
||||||
|
|
||||||
|
Glyph->P0 = BaseTextureOffset;
|
||||||
|
Glyph->P1 = BaseTextureOffset + Dim + V2S(2, 2);
|
||||||
|
|
||||||
|
Atlas->RenderCommands->FillRegion(Atlas->Texture,
|
||||||
|
BaseTextureOffset, V2S(Atlas->GlyphSize, Atlas->GlyphSize),
|
||||||
|
Atlas->BitmapBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static glyph *GetGlyph(glyph_atlas *Atlas, font_id Font, u32 Codepoint, r32 Size, s32 Subpixel)
|
static glyph *GetGlyph(glyph_atlas *Atlas, font_id Font, u32 Codepoint, r32 Size, s32 Subpixel)
|
||||||
{
|
{
|
||||||
glyph *Glyph = 0;
|
glyph *Glyph = 0;
|
||||||
|
|
||||||
for(s32 GlyphIndex = 0;
|
for(s32 GlyphIndex = 0;
|
||||||
GlyphIndex < Atlas->GlyphsUsed;
|
GlyphIndex < Atlas->GlyphsUsed;
|
||||||
++GlyphIndex)
|
++GlyphIndex)
|
||||||
|
{
|
||||||
|
glyph *At = Atlas->Glyphs + GlyphIndex;
|
||||||
|
if((At->Font == Font) && (At->Codepoint == Codepoint) && (At->Size == Size) && (At->Subpixel == Subpixel))
|
||||||
{
|
{
|
||||||
glyph *At = Atlas->Glyphs + GlyphIndex;
|
Glyph = At;
|
||||||
if((At->Font == Font) && (At->Codepoint == Codepoint) && (At->Size == Size) && (At->Subpixel == Subpixel))
|
break;
|
||||||
{
|
|
||||||
Glyph = At;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if(Glyph)
|
|
||||||
|
if(Glyph)
|
||||||
|
{
|
||||||
|
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(Atlas->GlyphsUsed < Atlas->MaxGlyphCount)
|
||||||
{
|
{
|
||||||
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
Glyph = Atlas->Glyphs + Atlas->GlyphsUsed++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(Atlas->GlyphsUsed < Atlas->MaxGlyphCount)
|
Glyph = Atlas->LRUFirst;
|
||||||
{
|
Assert(Glyph);
|
||||||
Glyph = Atlas->Glyphs + Atlas->GlyphsUsed++;
|
|
||||||
}
|
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||||
else
|
|
||||||
{
|
|
||||||
Glyph = Atlas->LRUFirst;
|
|
||||||
Assert(Glyph);
|
|
||||||
|
|
||||||
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
|
||||||
}
|
|
||||||
|
|
||||||
RasterizeGlyph(Atlas, Font, Glyph, Codepoint, Size, Subpixel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLInsertLast_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
RasterizeGlyph(Atlas, Font, Glyph, Codepoint, Size, Subpixel);
|
||||||
|
}
|
||||||
return(Glyph);
|
|
||||||
|
DLLInsertLast_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||||
|
|
||||||
|
return(Glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
|
static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
|
||||||
s32 BitmapSize = DEFAULT_GLYPH_ATLAS_DIM,
|
s32 BitmapSize = DEFAULT_GLYPH_ATLAS_DIM,
|
||||||
s32 GlyphSize = MAX_GLYPH_SIZE)
|
s32 GlyphSize = MAX_GLYPH_SIZE)
|
||||||
{
|
{
|
||||||
glyph_atlas *Atlas = BootstrapPushStruct(glyph_atlas, Arena);
|
glyph_atlas *Atlas = BootstrapPushStruct(glyph_atlas, Arena);
|
||||||
|
|
||||||
|
Atlas->BitmapSize = BitmapSize;
|
||||||
|
Atlas->GlyphSize = GlyphSize;
|
||||||
|
|
||||||
|
Atlas->MaxGlyphCount = (DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE)*(DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE);
|
||||||
|
Atlas->Glyphs = PushArray(&Atlas->Arena, glyph, Atlas->MaxGlyphCount);
|
||||||
|
|
||||||
|
Atlas->RenderCommands = RenderCommands;
|
||||||
|
Atlas->Texture = RenderCommands->AllocateTexture(V2S(BitmapSize, BitmapSize), Render_TextureFormat_R8, 0);
|
||||||
|
|
||||||
|
Atlas->Fonts[Font_Regular].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/Roboto-Regular.ttf"));
|
||||||
|
Atlas->Fonts[Font_Bold].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/Roboto-Bold.ttf"));
|
||||||
|
Atlas->Fonts[Font_Monospace].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/Liberation-Mono.ttf"));
|
||||||
|
Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/icons.ttf"));
|
||||||
|
|
||||||
|
for(s32 FontIndex = 0;
|
||||||
|
FontIndex < Font_Count;
|
||||||
|
++FontIndex)
|
||||||
|
{
|
||||||
|
loaded_font *Font = Atlas->Fonts + FontIndex;
|
||||||
|
stbtt_InitFont(&Font->Info,
|
||||||
|
Font->Data.Data,
|
||||||
|
stbtt_GetFontOffsetForIndex(Font->Data.Data, 0));
|
||||||
|
|
||||||
Atlas->BitmapSize = BitmapSize;
|
stbtt_GetFontVMetrics(&Font->Info, &Font->Ascent, &Font->Descent, &Font->LineGap);
|
||||||
Atlas->GlyphSize = GlyphSize;
|
}
|
||||||
|
|
||||||
Atlas->MaxGlyphCount = (DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE)*(DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE);
|
Atlas->BitmapBuffer = PushArray(&Atlas->Arena, u8, GlyphSize*GlyphSize);
|
||||||
Atlas->Glyphs = PushArray(&Atlas->Arena, glyph, Atlas->MaxGlyphCount);
|
|
||||||
|
return(Atlas);
|
||||||
Atlas->RenderCommands = RenderCommands;
|
|
||||||
Atlas->Texture = RenderCommands->AllocateTexture(V2S(BitmapSize, BitmapSize), Render_TextureFormat_R8, 0);
|
|
||||||
|
|
||||||
Atlas->Fonts[Font_Regular].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("../fonts/Roboto-Regular.ttf"));
|
|
||||||
Atlas->Fonts[Font_Bold].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("../fonts/Roboto-Bold.ttf"));
|
|
||||||
Atlas->Fonts[Font_Monospace].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("../fonts/Liberation-Mono.ttf"));
|
|
||||||
Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("../fonts/icons.ttf"));
|
|
||||||
|
|
||||||
for(s32 FontIndex = 0;
|
|
||||||
FontIndex < Font_Count;
|
|
||||||
++FontIndex)
|
|
||||||
{
|
|
||||||
loaded_font *Font = Atlas->Fonts + FontIndex;
|
|
||||||
stbtt_InitFont(&Font->Info,
|
|
||||||
Font->Data.Data,
|
|
||||||
stbtt_GetFontOffsetForIndex(Font->Data.Data, 0));
|
|
||||||
|
|
||||||
stbtt_GetFontVMetrics(&Font->Info, &Font->Ascent, &Font->Descent, &Font->LineGap);
|
|
||||||
}
|
|
||||||
|
|
||||||
Atlas->BitmapBuffer = PushArray(&Atlas->Arena, u8, GlyphSize*GlyphSize);
|
|
||||||
|
|
||||||
return(Atlas);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PushText(render_group *Group, glyph_atlas *Atlas, font_id Font,
|
static void PushText(render_group *Group, glyph_atlas *Atlas, font_id Font,
|
||||||
v2 P, r32 Size, v4 Color,
|
v2 P, r32 Size, v4 Color,
|
||||||
string Text)
|
string Text)
|
||||||
{
|
{
|
||||||
r32 Oversample = 2;
|
r32 Oversample = 2;
|
||||||
|
|
||||||
|
for(utf8_iterator Iter = IterateUTF8String(Text);
|
||||||
|
Iter.Codepoint != 0;
|
||||||
|
Advance(&Iter))
|
||||||
|
{
|
||||||
|
u32 Codepoint = Iter.Codepoint;
|
||||||
|
|
||||||
for(utf8_iterator Iter = IterateUTF8String(Text);
|
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(P.x*Oversample));
|
||||||
Iter.Codepoint != 0;
|
Assert(Glyph);
|
||||||
Advance(&Iter))
|
|
||||||
{
|
v2 GlyphP = P;
|
||||||
u32 Codepoint = Iter.Codepoint;
|
GlyphP.x += Glyph->Offset.x/Oversample;
|
||||||
|
GlyphP.y += Glyph->Offset.y/Oversample;
|
||||||
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(P.x*Oversample));
|
|
||||||
Assert(Glyph);
|
v2 RenderDim = V2(Glyph->P1 - Glyph->P0);
|
||||||
|
v2 Dim = RenderDim;
|
||||||
v2 GlyphP = P;
|
Dim.x /= Oversample;
|
||||||
GlyphP.x += Glyph->Offset.x/Oversample;
|
Dim.y /= Oversample;
|
||||||
GlyphP.y += Glyph->Offset.y/Oversample;
|
|
||||||
|
PushTexturedQuad(Group, GlyphP, Dim, V2(Glyph->P0), RenderDim, Color, Color, Color, Color, 0, 0, 0, Atlas->Texture);
|
||||||
v2 RenderDim = V2(Glyph->P1 - Glyph->P0);
|
|
||||||
v2 Dim = RenderDim;
|
P.x += Glyph->Advance/Oversample;
|
||||||
Dim.x /= Oversample;
|
}
|
||||||
Dim.y /= Oversample;
|
|
||||||
|
|
||||||
PushTexturedQuad(Group, GlyphP, Dim, V2(Glyph->P0), RenderDim, Color, Color, Color, Color, 0, 0, 0, Atlas->Texture);
|
|
||||||
|
|
||||||
P.x += Glyph->Advance/Oversample;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PushTextF(render_group *Group, glyph_atlas *Atlas, font_id Font,
|
static void PushTextF(render_group *Group, glyph_atlas *Atlas, font_id Font,
|
||||||
v2 P, r32 Size, v4 Color,
|
v2 P, r32 Size, v4 Color,
|
||||||
char *Format, ...)
|
char *Format, ...)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch(0, 0);
|
temporary_memory Scratch = GetScratch(0, 0);
|
||||||
|
|
||||||
va_list Arguments;
|
va_list Arguments;
|
||||||
va_start(Arguments, Format);
|
va_start(Arguments, Format);
|
||||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||||
va_end(Arguments);
|
va_end(Arguments);
|
||||||
|
|
||||||
PushText(Group, Atlas, Font, P, Size, Color, String);
|
PushText(Group, Atlas, Font, P, Size, Color, String);
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline r32 CalculateRasterizedTextWidth(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
inline r32 CalculateRasterizedTextWidth(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
||||||
{
|
{
|
||||||
r32 Oversample = 2;
|
r32 Oversample = 2;
|
||||||
|
|
||||||
|
r32 X = 0;
|
||||||
|
|
||||||
|
for(utf8_iterator Iter = IterateUTF8String(Text);
|
||||||
|
Iter.Codepoint != 0;
|
||||||
|
Advance(&Iter))
|
||||||
|
{
|
||||||
|
u32 Codepoint = Iter.Codepoint;
|
||||||
|
|
||||||
r32 X = 0;
|
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(X*Oversample));
|
||||||
|
Assert(Glyph);
|
||||||
|
|
||||||
for(utf8_iterator Iter = IterateUTF8String(Text);
|
X += Glyph->Advance/Oversample;
|
||||||
Iter.Codepoint != 0;
|
}
|
||||||
Advance(&Iter))
|
|
||||||
{
|
return(X);
|
||||||
u32 Codepoint = Iter.Codepoint;
|
|
||||||
|
|
||||||
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(X*Oversample));
|
|
||||||
Assert(Glyph);
|
|
||||||
|
|
||||||
X += Glyph->Advance/Oversample;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(X);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline r32 CalculateRasterizedTextHeight(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
inline r32 CalculateRasterizedTextHeight(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
||||||
{
|
{
|
||||||
r32 Scale = stbtt_ScaleForMappingEmToPixels(&Atlas->Fonts[Font].Info, Size)/
|
r32 Scale = stbtt_ScaleForMappingEmToPixels(&Atlas->Fonts[Font].Info, Size)/
|
||||||
stbtt_ScaleForPixelHeight(&Atlas->Fonts[Font].Info, Size);
|
stbtt_ScaleForPixelHeight(&Atlas->Fonts[Font].Info, Size);
|
||||||
|
|
||||||
|
r32 Y = Size*Scale;
|
||||||
|
|
||||||
|
for(utf8_iterator Iter = IterateUTF8String(Text);
|
||||||
|
Iter.Codepoint != 0;
|
||||||
|
Advance(&Iter))
|
||||||
|
{
|
||||||
|
u32 Codepoint = Iter.Codepoint;
|
||||||
|
|
||||||
r32 Y = Size*Scale;
|
if(Codepoint == '\n')
|
||||||
|
|
||||||
for(utf8_iterator Iter = IterateUTF8String(Text);
|
|
||||||
Iter.Codepoint != 0;
|
|
||||||
Advance(&Iter))
|
|
||||||
{
|
{
|
||||||
u32 Codepoint = Iter.Codepoint;
|
Y += Size*Scale;
|
||||||
|
|
||||||
if(Codepoint == '\n')
|
|
||||||
{
|
|
||||||
Y += Size*Scale;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return(Y);
|
}
|
||||||
|
return(Y);
|
||||||
}
|
}
|
358
code/vn_string.h
358
code/vn_string.h
|
@ -5,161 +5,181 @@
|
||||||
|
|
||||||
inline b32 IsWhitespace(char C)
|
inline b32 IsWhitespace(char C)
|
||||||
{
|
{
|
||||||
b32 Result = ((C == ' ') ||
|
b32 Result = ((C == ' ') ||
|
||||||
(C == '\n') ||
|
(C == '\n') ||
|
||||||
(C == '\t') ||
|
(C == '\t') ||
|
||||||
(C == '\r'));
|
(C == '\r'));
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 StringLength(char *String)
|
inline s64 StringLength(char *String)
|
||||||
{
|
{
|
||||||
s64 Result = 0;
|
s64 Result = 0;
|
||||||
while(*String++)
|
while(*String++)
|
||||||
{
|
{
|
||||||
++Result;
|
++Result;
|
||||||
}
|
}
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u64 HashString(string String)
|
inline u64 HashString(string String)
|
||||||
{
|
{
|
||||||
u64 Result = 5731;
|
u64 Result = 5731;
|
||||||
for(s64 Index = 0;
|
for(s64 Index = 0;
|
||||||
Index < String.Count;
|
Index < String.Count;
|
||||||
++Index)
|
++Index)
|
||||||
{
|
{
|
||||||
Result += String.Data[Index];
|
Result += String.Data[Index];
|
||||||
Result ^= Result << 13;
|
Result ^= Result << 13;
|
||||||
Result ^= Result >> 7;
|
Result ^= Result >> 7;
|
||||||
Result ^= Result << 17;
|
Result ^= Result << 17;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline string MakeStringFromCString(char *Data)
|
inline string MakeStringFromCString(char *Data)
|
||||||
{
|
{
|
||||||
string Result = {StringLength(Data), (u8 *)Data};
|
string Result = {StringLength(Data), (u8 *)Data};
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
|
||||||
|
|
||||||
inline s64 FirstIndexOf(string String, char Char)
|
|
||||||
{
|
|
||||||
s64 Result = -1;
|
|
||||||
for(s64 Index = 0;
|
|
||||||
Index < String.Count;
|
|
||||||
++Index)
|
|
||||||
{
|
|
||||||
if(String.Data[Index] == Char)
|
|
||||||
{
|
|
||||||
Result = Index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline s64 LastIndexOf(string String, char Char)
|
|
||||||
{
|
|
||||||
s64 Result = -1;
|
|
||||||
for(s64 Index = String.Count-1;
|
|
||||||
Index >= 0;
|
|
||||||
--Index)
|
|
||||||
{
|
|
||||||
if(String.Data[Index] == Char)
|
|
||||||
{
|
|
||||||
Result = Index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(Result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline b32 AreEqual(string A, string B)
|
inline b32 AreEqual(string A, string B)
|
||||||
{
|
{
|
||||||
b32 Result = false;
|
b32 Result = false;
|
||||||
if(A.Count == B.Count)
|
if(A.Count == B.Count)
|
||||||
{
|
{
|
||||||
Result = true;
|
Result = true;
|
||||||
|
|
||||||
for(s64 Index = 0;
|
|
||||||
Index < A.Count;
|
|
||||||
++Index)
|
|
||||||
{
|
|
||||||
if(A.Data[Index] != B.Data[Index])
|
|
||||||
{
|
|
||||||
Result = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(Result);
|
for(s64 Index = 0;
|
||||||
|
Index < A.Count;
|
||||||
|
++Index)
|
||||||
|
{
|
||||||
|
if(A.Data[Index] != B.Data[Index])
|
||||||
|
{
|
||||||
|
Result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s64 FirstIndexOf(string String, char Char)
|
||||||
|
{
|
||||||
|
s64 Result = -1;
|
||||||
|
for(s64 Index = 0;
|
||||||
|
Index < String.Count;
|
||||||
|
++Index)
|
||||||
|
{
|
||||||
|
if(String.Data[Index] == Char)
|
||||||
|
{
|
||||||
|
Result = Index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s64 LastIndexOf(string String, char Char)
|
||||||
|
{
|
||||||
|
s64 Result = -1;
|
||||||
|
for(s64 Index = String.Count-1;
|
||||||
|
Index >= 0;
|
||||||
|
--Index)
|
||||||
|
{
|
||||||
|
if(String.Data[Index] == Char)
|
||||||
|
{
|
||||||
|
Result = Index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s64 LastIndexOf(string String, string Substring)
|
||||||
|
{
|
||||||
|
s64 Result = -1;
|
||||||
|
if(String.Count >= Substring.Count)
|
||||||
|
{
|
||||||
|
for(s64 Index = String.Count-Substring.Count;
|
||||||
|
Index >= 0;
|
||||||
|
--Index)
|
||||||
|
{
|
||||||
|
string ToCheck = MakeString((char *)String.Data + Index, Substring.Count);
|
||||||
|
if(AreEqual(ToCheck, Substring))
|
||||||
|
{
|
||||||
|
Result = Index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint)
|
static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint)
|
||||||
{
|
{
|
||||||
s64 Length = 0;
|
s64 Length = 0;
|
||||||
if(Codepoint <= 0x7F)
|
if(Codepoint <= 0x7F)
|
||||||
{
|
{
|
||||||
Out[0] = (u8)Codepoint;
|
Out[0] = (u8)Codepoint;
|
||||||
Length = 1;
|
Length = 1;
|
||||||
}
|
}
|
||||||
else if(Codepoint <= 0x7FF)
|
else if(Codepoint <= 0x7FF)
|
||||||
{
|
{
|
||||||
Out[0] = (0x3 << 6) | ((Codepoint >> 6) & 0x1F);
|
Out[0] = (0x3 << 6) | ((Codepoint >> 6) & 0x1F);
|
||||||
Out[1] = 0x80 | ( Codepoint & 0x3F);
|
Out[1] = 0x80 | ( Codepoint & 0x3F);
|
||||||
Length = 2;
|
Length = 2;
|
||||||
}
|
}
|
||||||
else if(Codepoint <= 0xFFFF)
|
else if(Codepoint <= 0xFFFF)
|
||||||
{
|
{
|
||||||
Out[0] = (0x7 << 5) | ((Codepoint >> 12) & 0x0F);
|
Out[0] = (0x7 << 5) | ((Codepoint >> 12) & 0x0F);
|
||||||
Out[1] = 0x80 | ((Codepoint >> 6) & 0x3F);
|
Out[1] = 0x80 | ((Codepoint >> 6) & 0x3F);
|
||||||
Out[2] = 0x80 | ( Codepoint & 0x3F);
|
Out[2] = 0x80 | ( Codepoint & 0x3F);
|
||||||
Length = 3;
|
Length = 3;
|
||||||
}
|
}
|
||||||
else if(Codepoint <= 0x10FFFF)
|
else if(Codepoint <= 0x10FFFF)
|
||||||
{
|
{
|
||||||
Out[0] = (0xF << 4) | ((Codepoint >> 12) & 0x07);
|
Out[0] = (0xF << 4) | ((Codepoint >> 12) & 0x07);
|
||||||
Out[1] = 0x80 | ((Codepoint >> 12) & 0x3F);
|
Out[1] = 0x80 | ((Codepoint >> 12) & 0x3F);
|
||||||
Out[2] = 0x80 | ((Codepoint >> 6) & 0x3F);
|
Out[2] = 0x80 | ((Codepoint >> 6) & 0x3F);
|
||||||
Out[3] = 0x80 | ( Codepoint & 0x3F);
|
Out[3] = 0x80 | ( Codepoint & 0x3F);
|
||||||
Length = 4;
|
Length = 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Out[0] = '?';
|
Out[0] = '?';
|
||||||
Length = 1;
|
Length = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(Length);
|
return(Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 GetCodepointSize(u32 Codepoint)
|
inline s64 GetCodepointSize(u32 Codepoint)
|
||||||
{
|
{
|
||||||
s64 Result = 0;
|
s64 Result = 0;
|
||||||
if(Codepoint <= 0x7F)
|
if(Codepoint <= 0x7F)
|
||||||
{
|
{
|
||||||
Result = 1;
|
Result = 1;
|
||||||
}
|
}
|
||||||
else if(Codepoint <= 0x7FF)
|
else if(Codepoint <= 0x7FF)
|
||||||
{
|
{
|
||||||
Result = 2;
|
Result = 2;
|
||||||
}
|
}
|
||||||
else if(Codepoint <= 0xFFFF)
|
else if(Codepoint <= 0xFFFF)
|
||||||
{
|
{
|
||||||
Result = 3;
|
Result = 3;
|
||||||
}
|
}
|
||||||
else if(Codepoint <= 0x10FFFF)
|
else if(Codepoint <= 0x10FFFF)
|
||||||
{
|
{
|
||||||
Result = 4;
|
Result = 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Result = 1;
|
Result = 1;
|
||||||
}
|
}
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sixten(TODO): Remove this forward decl.
|
// sixten(TODO): Remove this forward decl.
|
||||||
|
@ -167,61 +187,61 @@ inline string PushCString(struct memory_arena *Arena, char *CString);
|
||||||
|
|
||||||
inline string StringFromCodepoint(struct memory_arena *Arena, u32 Codepoint)
|
inline string StringFromCodepoint(struct memory_arena *Arena, u32 Codepoint)
|
||||||
{
|
{
|
||||||
char Buffer[5] = {};
|
char Buffer[5] = {};
|
||||||
UTF8FromCodepoint((u8 *)Buffer, Codepoint);
|
UTF8FromCodepoint((u8 *)Buffer, Codepoint);
|
||||||
|
|
||||||
string Result = PushCString(Arena, Buffer);
|
string Result = PushCString(Arena, Buffer);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct utf8_iterator
|
struct utf8_iterator
|
||||||
{
|
{
|
||||||
string Data;
|
string Data;
|
||||||
s64 Index;
|
s64 Index;
|
||||||
|
|
||||||
u32 Codepoint;
|
u32 Codepoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void Advance(utf8_iterator *Iter)
|
inline void Advance(utf8_iterator *Iter)
|
||||||
{
|
{
|
||||||
u8 *At = Iter->Data.Data + Iter->Index;
|
u8 *At = Iter->Data.Data + Iter->Index;
|
||||||
|
|
||||||
if(Iter->Index < Iter->Data.Count)
|
if(Iter->Index < Iter->Data.Count)
|
||||||
|
{
|
||||||
|
if((At[0] & 0x80) == 0x00)
|
||||||
{
|
{
|
||||||
if((At[0] & 0x80) == 0x00)
|
Iter->Codepoint = (At[0] & 0x7F);
|
||||||
{
|
Iter->Index += 1;
|
||||||
Iter->Codepoint = (At[0] & 0x7F);
|
|
||||||
Iter->Index += 1;
|
|
||||||
}
|
|
||||||
else if((At[0] & 0xE0) == 0xC0)
|
|
||||||
{
|
|
||||||
Iter->Codepoint = ((At[0] & 0x1F) << 6)|(At[1] & 0x3F);
|
|
||||||
Iter->Index += 2;
|
|
||||||
}
|
|
||||||
else if((At[0] & 0xF0) == 0xE0)
|
|
||||||
{
|
|
||||||
Iter->Codepoint = ((At[0] & 0x0F) << 12)|((At[1] & 0x3F) << 6)|(At[2] & 0x3F);
|
|
||||||
Iter->Index += 3;
|
|
||||||
}
|
|
||||||
else if((Iter->Data.Data[Iter->Index] & 0xF8) == 0xF0)
|
|
||||||
{
|
|
||||||
Iter->Codepoint = ((At[0] & 0x0F) << 18)|((At[1] & 0x3F) << 12)|((At[2] & 0x3F) << 6)|(At[3] & 0x3F);
|
|
||||||
Iter->Index += 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else if((At[0] & 0xE0) == 0xC0)
|
||||||
{
|
{
|
||||||
Iter->Codepoint = 0;
|
Iter->Codepoint = ((At[0] & 0x1F) << 6)|(At[1] & 0x3F);
|
||||||
|
Iter->Index += 2;
|
||||||
}
|
}
|
||||||
|
else if((At[0] & 0xF0) == 0xE0)
|
||||||
|
{
|
||||||
|
Iter->Codepoint = ((At[0] & 0x0F) << 12)|((At[1] & 0x3F) << 6)|(At[2] & 0x3F);
|
||||||
|
Iter->Index += 3;
|
||||||
|
}
|
||||||
|
else if((Iter->Data.Data[Iter->Index] & 0xF8) == 0xF0)
|
||||||
|
{
|
||||||
|
Iter->Codepoint = ((At[0] & 0x0F) << 18)|((At[1] & 0x3F) << 12)|((At[2] & 0x3F) << 6)|(At[3] & 0x3F);
|
||||||
|
Iter->Index += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Iter->Codepoint = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline utf8_iterator IterateUTF8String(string String)
|
inline utf8_iterator IterateUTF8String(string String)
|
||||||
{
|
{
|
||||||
utf8_iterator Iter = {};
|
utf8_iterator Iter = {};
|
||||||
Iter.Data = String;
|
Iter.Data = String;
|
||||||
Advance(&Iter);
|
Advance(&Iter);
|
||||||
|
|
||||||
return(Iter);
|
return(Iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //VN_STRING_H
|
#endif //VN_STRING_H
|
||||||
|
|
1115
code/win32_main.cpp
1115
code/win32_main.cpp
File diff suppressed because it is too large
Load Diff
|
@ -5,43 +5,44 @@
|
||||||
|
|
||||||
struct win32_memory_block
|
struct win32_memory_block
|
||||||
{
|
{
|
||||||
platform_memory_block Block;
|
platform_memory_block Block;
|
||||||
win32_memory_block *Next;
|
win32_memory_block *Next;
|
||||||
win32_memory_block *Prev;
|
win32_memory_block *Prev;
|
||||||
u64 Padding[2];
|
u64 Padding[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
CTAssert(sizeof(win32_memory_block) == 64);
|
CTAssert(sizeof(win32_memory_block) == 64);
|
||||||
|
|
||||||
struct win32_state
|
struct win32_state
|
||||||
{
|
{
|
||||||
win32_memory_block MemorySentinel;
|
win32_memory_block MemorySentinel;
|
||||||
ticket_mutex MemoryMutex;
|
ticket_mutex MemoryMutex;
|
||||||
|
|
||||||
u64 PerformanceFrequency;
|
u64 PerformanceFrequency;
|
||||||
b32 SleepIsGranular;
|
b32 SleepIsGranular;
|
||||||
|
|
||||||
HWND Window;
|
HWND Window;
|
||||||
|
|
||||||
memory_arena EventArena;
|
memory_arena EventArena;
|
||||||
temporary_memory EventArenaTemp;
|
temporary_memory EventArenaTemp;
|
||||||
platform_event_list EventList;
|
platform_event_list EventList;
|
||||||
|
|
||||||
char EXEPath[512];
|
char EXEPath[512];
|
||||||
char DLLPath[512];
|
char DLLPath[512];
|
||||||
char TempDLLPath[512];
|
char TempDLLPath[512];
|
||||||
|
string ContentsPath;
|
||||||
platform_cursor Cursor;
|
|
||||||
|
platform_cursor Cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct win32_loaded_code
|
struct win32_loaded_code
|
||||||
{
|
{
|
||||||
HMODULE DLL;
|
HMODULE DLL;
|
||||||
FILETIME LastWriteTime;
|
FILETIME LastWriteTime;
|
||||||
|
|
||||||
vn_update_and_render *UpdateAndRender;
|
vn_update_and_render *UpdateAndRender;
|
||||||
|
|
||||||
b32 IsValid;
|
b32 IsValid;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //WIN32_MAIN_H
|
#endif //WIN32_MAIN_H
|
||||||
|
|
Loading…
Reference in New Issue