diff --git a/code/vn.cpp b/code/vn.cpp index 571e113..0445e71 100644 --- a/code/vn.cpp +++ b/code/vn.cpp @@ -19,50 +19,50 @@ struct vn_state { - memory_arena Arena; - glyph_atlas *GlyphAtlas; - - config *Config; - - ui UI; - workspace Workspace; - animation_curve_state AnimationCurveState; + memory_arena Arena; + glyph_atlas *GlyphAtlas; + + config *Config; + + ui UI; + workspace Workspace; + animation_curve_state AnimationCurveState; }; VN_UPDATE_AND_RENDER(VN_UpdateAndRender) { - SetThreadContext(ThreadContext); - Platform = Memory->PlatformAPI; + SetThreadContext(ThreadContext); + 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) - { - 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); - } + Config_BindEntry(State->Config, StrLit("Platform/RefreshRate"), Config_Entry_S32, &Input->RefreshRate); - AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame); - UI_NewFrame(&State->UI, Input->EventList, Input->MouseP); - - Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas); - UI_SignalFromBox(UI_GetState()->ContainerNode); // sixten(TODO): Move elsewhere. - - for(platform_event *Event = Input->EventList->First; - Event != 0; - Event = Event->Next) - { - Platform_ConsumeEvent(Input->EventList, Event); - } - - render_group Group = BeginRenderGroup(RenderCommands); - PushClear(&Group, V3(0.1, 0.1, 0.1)); - - UI_RenderFrame(&Group, State->GlyphAtlas); + Workspace_Init(&State->Workspace); + } + + AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame); + UI_NewFrame(&State->UI, Input->EventList, Input->MouseP); + + Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas); + UI_SignalFromBox(UI_GetState()->ContainerNode); // sixten(TODO): Move elsewhere. + + for(platform_event *Event = Input->EventList->First; + Event != 0; + Event = Event->Next) + { + Platform_ConsumeEvent(Input->EventList, Event); + } + + render_group Group = BeginRenderGroup(RenderCommands); + PushClear(&Group, V3(0.1, 0.1, 0.1)); + + UI_RenderFrame(&Group, State->GlyphAtlas); } \ No newline at end of file diff --git a/code/vn_font.cpp b/code/vn_font.cpp index c4be53b..37ffac1 100644 --- a/code/vn_font.cpp +++ b/code/vn_font.cpp @@ -2,223 +2,223 @@ inline s32 GetSubpixelSegmentAtP(r32 Value) { - s32 Result = (s32)(Value - Floor(Value))*GLYPH_SUBPIXEL_SEGMENTS; - return(Result); + s32 Result = (s32)(Value - Floor(Value))*GLYPH_SUBPIXEL_SEGMENTS; + return(Result); } static void RasterizeGlyph(glyph_atlas *Atlas, font_id Font, glyph *Glyph, u32 Codepoint, r32 Size, s32 Subpixel) { - Glyph->Font = Font; - Glyph->Codepoint = Codepoint; - Glyph->Size = Size; - Glyph->Subpixel = Subpixel; - - Assert(Subpixel < GLYPH_SUBPIXEL_SEGMENTS); - - loaded_font *LoadedFont = Atlas->Fonts + Font; - stbtt_fontinfo *Info = &LoadedFont->Info; - - r32 Scale = stbtt_ScaleForMappingEmToPixels(Info, Size); - - s32 InternalIndex = (s32)(Glyph - Atlas->Glyphs); - s32 GlyphsPerRow = Atlas->BitmapSize / Atlas->GlyphSize; - - v2s BaseTextureOffset = V2S((InternalIndex % GlyphsPerRow)*Atlas->GlyphSize, - (InternalIndex / GlyphsPerRow)*Atlas->GlyphSize); - - int GlyphIndex = stbtt_FindGlyphIndex(Info, Codepoint); - - 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, + Glyph->Font = Font; + Glyph->Codepoint = Codepoint; + Glyph->Size = Size; + Glyph->Subpixel = Subpixel; + + Assert(Subpixel < GLYPH_SUBPIXEL_SEGMENTS); + + loaded_font *LoadedFont = Atlas->Fonts + Font; + stbtt_fontinfo *Info = &LoadedFont->Info; + + r32 Scale = stbtt_ScaleForMappingEmToPixels(Info, Size); + + s32 InternalIndex = (s32)(Glyph - Atlas->Glyphs); + s32 GlyphsPerRow = Atlas->BitmapSize / Atlas->GlyphSize; + + v2s BaseTextureOffset = V2S((InternalIndex % GlyphsPerRow)*Atlas->GlyphSize, + (InternalIndex / GlyphsPerRow)*Atlas->GlyphSize); + + int GlyphIndex = stbtt_FindGlyphIndex(Info, Codepoint); + + stbtt_GetGlyphBitmapBoxSubpixel(Info, GlyphIndex, Scale, Scale, (r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0, - GlyphIndex); - - s32 Advance, LeftSideBearing; - stbtt_GetGlyphHMetrics(Info, GlyphIndex, &Advance, &LeftSideBearing); - Glyph->Advance = Advance*Scale; - Glyph->Offset.x = LeftSideBearing*Scale; - - Glyph->Offset.y = Glyph->P0.y + (LoadedFont->Ascent + LoadedFont->LineGap)*Scale; - - 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); + &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, + GlyphIndex); + + s32 Advance, LeftSideBearing; + stbtt_GetGlyphHMetrics(Info, GlyphIndex, &Advance, &LeftSideBearing); + Glyph->Advance = Advance*Scale; + Glyph->Offset.x = LeftSideBearing*Scale; + + Glyph->Offset.y = Glyph->P0.y + (LoadedFont->Ascent + LoadedFont->LineGap)*Scale; + + 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) { - glyph *Glyph = 0; - - for(s32 GlyphIndex = 0; - GlyphIndex < Atlas->GlyphsUsed; - ++GlyphIndex) + glyph *Glyph = 0; + + for(s32 GlyphIndex = 0; + GlyphIndex < Atlas->GlyphsUsed; + ++GlyphIndex) + { + glyph *At = Atlas->Glyphs + GlyphIndex; + if((At->Font == Font) && (At->Codepoint == Codepoint) && (At->Size == Size) && (At->Subpixel == Subpixel)) { - glyph *At = Atlas->Glyphs + GlyphIndex; - if((At->Font == Font) && (At->Codepoint == Codepoint) && (At->Size == Size) && (At->Subpixel == Subpixel)) - { - Glyph = At; - 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 { - if(Atlas->GlyphsUsed < Atlas->MaxGlyphCount) - { - Glyph = Atlas->Glyphs + Atlas->GlyphsUsed++; - } - else - { - Glyph = Atlas->LRUFirst; - Assert(Glyph); - - DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev); - } - - RasterizeGlyph(Atlas, Font, Glyph, Codepoint, Size, Subpixel); + Glyph = Atlas->LRUFirst; + Assert(Glyph); + + DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev); } - DLLInsertLast_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev); - - return(Glyph); + RasterizeGlyph(Atlas, Font, Glyph, Codepoint, Size, Subpixel); + } + + DLLInsertLast_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev); + + return(Glyph); } static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands, s32 BitmapSize = DEFAULT_GLYPH_ATLAS_DIM, 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; - 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)); - - stbtt_GetFontVMetrics(&Font->Info, &Font->Ascent, &Font->Descent, &Font->LineGap); - } - - Atlas->BitmapBuffer = PushArray(&Atlas->Arena, u8, GlyphSize*GlyphSize); - - return(Atlas); + 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, v2 P, r32 Size, v4 Color, 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); - Iter.Codepoint != 0; - Advance(&Iter)) - { - u32 Codepoint = Iter.Codepoint; - - glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(P.x*Oversample)); - Assert(Glyph); - - v2 GlyphP = P; - GlyphP.x += Glyph->Offset.x/Oversample; - GlyphP.y += Glyph->Offset.y/Oversample; - - v2 RenderDim = V2(Glyph->P1 - Glyph->P0); - v2 Dim = RenderDim; - 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; - } + glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(P.x*Oversample)); + Assert(Glyph); + + v2 GlyphP = P; + GlyphP.x += Glyph->Offset.x/Oversample; + GlyphP.y += Glyph->Offset.y/Oversample; + + v2 RenderDim = V2(Glyph->P1 - Glyph->P0); + v2 Dim = RenderDim; + 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, v2 P, r32 Size, v4 Color, char *Format, ...) { - temporary_memory Scratch = GetScratch(0, 0); - - va_list Arguments; - va_start(Arguments, Format); - string String = PushFormatVariadic(Scratch.Arena, Format, Arguments); - va_end(Arguments); - - PushText(Group, Atlas, Font, P, Size, Color, String); - - ReleaseScratch(Scratch); + temporary_memory Scratch = GetScratch(0, 0); + + va_list Arguments; + va_start(Arguments, Format); + string String = PushFormatVariadic(Scratch.Arena, Format, Arguments); + va_end(Arguments); + + PushText(Group, Atlas, Font, P, Size, Color, String); + + ReleaseScratch(Scratch); } 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); - Iter.Codepoint != 0; - Advance(&Iter)) - { - u32 Codepoint = Iter.Codepoint; - - glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(X*Oversample)); - Assert(Glyph); - - X += Glyph->Advance/Oversample; - } - - return(X); + X += Glyph->Advance/Oversample; + } + + return(X); } inline r32 CalculateRasterizedTextHeight(glyph_atlas *Atlas, font_id Font, r32 Size, string Text) { - r32 Scale = stbtt_ScaleForMappingEmToPixels(&Atlas->Fonts[Font].Info, Size)/ - stbtt_ScaleForPixelHeight(&Atlas->Fonts[Font].Info, Size); + r32 Scale = stbtt_ScaleForMappingEmToPixels(&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; - - for(utf8_iterator Iter = IterateUTF8String(Text); - Iter.Codepoint != 0; - Advance(&Iter)) + if(Codepoint == '\n') { - u32 Codepoint = Iter.Codepoint; - - if(Codepoint == '\n') - { - Y += Size*Scale; - } + Y += Size*Scale; } - return(Y); + } + return(Y); } \ No newline at end of file diff --git a/code/vn_string.h b/code/vn_string.h index 6ba7fc2..1e326ab 100644 --- a/code/vn_string.h +++ b/code/vn_string.h @@ -5,161 +5,181 @@ inline b32 IsWhitespace(char C) { - b32 Result = ((C == ' ') || - (C == '\n') || - (C == '\t') || - (C == '\r')); - return(Result); + b32 Result = ((C == ' ') || + (C == '\n') || + (C == '\t') || + (C == '\r')); + return(Result); } inline s64 StringLength(char *String) { - s64 Result = 0; - while(*String++) - { - ++Result; - } - return(Result); + s64 Result = 0; + while(*String++) + { + ++Result; + } + return(Result); } inline u64 HashString(string String) { - u64 Result = 5731; - for(s64 Index = 0; - Index < String.Count; - ++Index) - { - Result += String.Data[Index]; - Result ^= Result << 13; - Result ^= Result >> 7; - Result ^= Result << 17; - } - - return(Result); + u64 Result = 5731; + for(s64 Index = 0; + Index < String.Count; + ++Index) + { + Result += String.Data[Index]; + Result ^= Result << 13; + Result ^= Result >> 7; + Result ^= Result << 17; + } + + return(Result); } inline string MakeStringFromCString(char *Data) { - string Result = {StringLength(Data), (u8 *)Data}; - 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); + string Result = {StringLength(Data), (u8 *)Data}; + return(Result); } inline b32 AreEqual(string A, string B) { - b32 Result = false; - if(A.Count == B.Count) - { - Result = true; - - for(s64 Index = 0; - Index < A.Count; - ++Index) - { - if(A.Data[Index] != B.Data[Index]) - { - Result = false; - break; - } - } - } + b32 Result = false; + if(A.Count == B.Count) + { + Result = true; - 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) { - s64 Length = 0; - if(Codepoint <= 0x7F) - { - Out[0] = (u8)Codepoint; - Length = 1; - } - else if(Codepoint <= 0x7FF) - { - Out[0] = (0x3 << 6) | ((Codepoint >> 6) & 0x1F); - Out[1] = 0x80 | ( Codepoint & 0x3F); - Length = 2; - } - else if(Codepoint <= 0xFFFF) - { - Out[0] = (0x7 << 5) | ((Codepoint >> 12) & 0x0F); - Out[1] = 0x80 | ((Codepoint >> 6) & 0x3F); - Out[2] = 0x80 | ( Codepoint & 0x3F); - Length = 3; - } - else if(Codepoint <= 0x10FFFF) - { - Out[0] = (0xF << 4) | ((Codepoint >> 12) & 0x07); - Out[1] = 0x80 | ((Codepoint >> 12) & 0x3F); - Out[2] = 0x80 | ((Codepoint >> 6) & 0x3F); - Out[3] = 0x80 | ( Codepoint & 0x3F); - Length = 4; - } - else - { - Out[0] = '?'; - Length = 1; - } - - return(Length); + s64 Length = 0; + if(Codepoint <= 0x7F) + { + Out[0] = (u8)Codepoint; + Length = 1; + } + else if(Codepoint <= 0x7FF) + { + Out[0] = (0x3 << 6) | ((Codepoint >> 6) & 0x1F); + Out[1] = 0x80 | ( Codepoint & 0x3F); + Length = 2; + } + else if(Codepoint <= 0xFFFF) + { + Out[0] = (0x7 << 5) | ((Codepoint >> 12) & 0x0F); + Out[1] = 0x80 | ((Codepoint >> 6) & 0x3F); + Out[2] = 0x80 | ( Codepoint & 0x3F); + Length = 3; + } + else if(Codepoint <= 0x10FFFF) + { + Out[0] = (0xF << 4) | ((Codepoint >> 12) & 0x07); + Out[1] = 0x80 | ((Codepoint >> 12) & 0x3F); + Out[2] = 0x80 | ((Codepoint >> 6) & 0x3F); + Out[3] = 0x80 | ( Codepoint & 0x3F); + Length = 4; + } + else + { + Out[0] = '?'; + Length = 1; + } + + return(Length); } inline s64 GetCodepointSize(u32 Codepoint) { - s64 Result = 0; - if(Codepoint <= 0x7F) - { - Result = 1; - } - else if(Codepoint <= 0x7FF) - { - Result = 2; - } - else if(Codepoint <= 0xFFFF) - { - Result = 3; - } - else if(Codepoint <= 0x10FFFF) - { - Result = 4; - } - else - { - Result = 1; - } - return(Result); + s64 Result = 0; + if(Codepoint <= 0x7F) + { + Result = 1; + } + else if(Codepoint <= 0x7FF) + { + Result = 2; + } + else if(Codepoint <= 0xFFFF) + { + Result = 3; + } + else if(Codepoint <= 0x10FFFF) + { + Result = 4; + } + else + { + Result = 1; + } + return(Result); } // 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) { - char Buffer[5] = {}; - UTF8FromCodepoint((u8 *)Buffer, Codepoint); - - string Result = PushCString(Arena, Buffer); - return(Result); + char Buffer[5] = {}; + UTF8FromCodepoint((u8 *)Buffer, Codepoint); + + string Result = PushCString(Arena, Buffer); + return(Result); } struct utf8_iterator { - string Data; - s64 Index; - - u32 Codepoint; + string Data; + s64 Index; + + u32 Codepoint; }; inline void Advance(utf8_iterator *Iter) { - u8 *At = Iter->Data.Data + Iter->Index; - - if(Iter->Index < Iter->Data.Count) + u8 *At = Iter->Data.Data + Iter->Index; + + if(Iter->Index < Iter->Data.Count) + { + if((At[0] & 0x80) == 0x00) { - if((At[0] & 0x80) == 0x00) - { - 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; - } + Iter->Codepoint = (At[0] & 0x7F); + Iter->Index += 1; } - 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) { - utf8_iterator Iter = {}; - Iter.Data = String; - Advance(&Iter); - - return(Iter); + utf8_iterator Iter = {}; + Iter.Data = String; + Advance(&Iter); + + return(Iter); } #endif //VN_STRING_H diff --git a/code/win32_main.cpp b/code/win32_main.cpp index aefbc63..1926e93 100644 --- a/code/win32_main.cpp +++ b/code/win32_main.cpp @@ -14,673 +14,688 @@ global WINDOWPLACEMENT Global_WindowPosition = {sizeof(Global_WindowPosition)};; static void Win32_PlatformError(char *Message, bool IsFatal) { - MessageBoxA(0, Message, "nv - Platform Error", MB_OK|(IsFatal?MB_ICONSTOP:MB_ICONEXCLAMATION)); - - if(IsFatal) - { - ExitProcess((UINT)-1); - } + MessageBoxA(0, Message, "nv - Platform Error", MB_OK|(IsFatal?MB_ICONSTOP:MB_ICONEXCLAMATION)); + + if(IsFatal) + { + ExitProcess((UINT)-1); + } } static PLATFORM_ALLOCATE_MEMORY(Win32_AllocateMemory) { - win32_state *State = &Global_Win32State; - - umm TotalSize = Size + sizeof(win32_memory_block); - - win32_memory_block *Block = - (win32_memory_block *)VirtualAlloc(0, TotalSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - - Assert(Block); - Block->Block.Base = (u8 *)Block + sizeof(win32_memory_block); - Block->Block.Size = Size; - - win32_memory_block *Sentinel = &State->MemorySentinel; - Block->Next = Sentinel; - - BeginTicketMutex(&State->MemoryMutex); - Block->Prev = Sentinel->Prev; - Block->Prev->Next = Block; - Block->Next->Prev = Block; - EndTicketMutex(&State->MemoryMutex); - - platform_memory_block *Result = &Block->Block; - return(Result); + win32_state *State = &Global_Win32State; + + umm TotalSize = Size + sizeof(win32_memory_block); + + win32_memory_block *Block = + (win32_memory_block *)VirtualAlloc(0, TotalSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + + Assert(Block); + Block->Block.Base = (u8 *)Block + sizeof(win32_memory_block); + Block->Block.Size = Size; + + win32_memory_block *Sentinel = &State->MemorySentinel; + Block->Next = Sentinel; + + BeginTicketMutex(&State->MemoryMutex); + Block->Prev = Sentinel->Prev; + Block->Prev->Next = Block; + Block->Next->Prev = Block; + EndTicketMutex(&State->MemoryMutex); + + platform_memory_block *Result = &Block->Block; + return(Result); } static PLATFORM_DEALLOCATE_MEMORY(Win32_DeallocateMemory) { - win32_state *State = &Global_Win32State; - - win32_memory_block *Win32Block = (win32_memory_block *)Block; - - if(Block) - { - BeginTicketMutex(&State->MemoryMutex); - Win32Block->Prev->Next = Win32Block->Next; - Win32Block->Next->Prev = Win32Block->Prev; - EndTicketMutex(&State->MemoryMutex); - } - - BOOL Result = VirtualFree(Block, 0, MEM_RELEASE); - return(Result); + win32_state *State = &Global_Win32State; + + win32_memory_block *Win32Block = (win32_memory_block *)Block; + + if(Block) + { + BeginTicketMutex(&State->MemoryMutex); + Win32Block->Prev->Next = Win32Block->Next; + Win32Block->Next->Prev = Win32Block->Prev; + EndTicketMutex(&State->MemoryMutex); + } + + BOOL Result = VirtualFree(Block, 0, MEM_RELEASE); + return(Result); } static PLATFORM_OPEN_FILE(Win32_OpenFile) { - DWORD DesiredAccess = 0; - if(FileAccess & PlatformAccess_Read) - { - DesiredAccess |= GENERIC_READ; - } - if(FileAccess & PlatformAccess_Write) - { - DesiredAccess |= GENERIC_WRITE; - } - - DWORD CreationAttributes = 0; - if(FileAccess & PlatformAccess_Read) - { - CreationAttributes = OPEN_EXISTING; - } - - string FullPath = Path; - - HANDLE File = CreateFileA((char *)Path.Data, DesiredAccess, 0, 0, CreationAttributes, 0, 0); - - platform_file_handle Result = {}; - Result.Platform = (u64)File; - Result.IsValid = (File != INVALID_HANDLE_VALUE); - - return(Result); + DWORD DesiredAccess = 0; + if(FileAccess & PlatformAccess_Read) + { + DesiredAccess |= GENERIC_READ; + } + if(FileAccess & PlatformAccess_Write) + { + DesiredAccess |= GENERIC_WRITE; + } + + DWORD CreationAttributes = 0; + if(FileAccess & PlatformAccess_Read) + { + CreationAttributes = OPEN_EXISTING; + } + + temporary_memory Scratch = GetScratch(0, 0); + + string FullPath = PushFormat(Scratch.Arena, "%S\\%S", Global_Win32State.ContentsPath, Path); + HANDLE File = CreateFileA((char *)FullPath.Data, DesiredAccess, 0, 0, CreationAttributes, 0, 0); + + ReleaseScratch(Scratch); + + platform_file_handle Result = {}; + Result.Platform = (u64)File; + Result.IsValid = (File != INVALID_HANDLE_VALUE); + + return(Result); } static PLATFORM_CLOSE_FILE(Win32_CloseFile) { - HANDLE File = (HANDLE)Handle.Platform; - if(File != INVALID_HANDLE_VALUE) - { - CloseHandle(File); - } + HANDLE File = (HANDLE)Handle.Platform; + if(File != INVALID_HANDLE_VALUE) + { + CloseHandle(File); + } } static PLATFORM_READ_FILE(Win32_ReadFile) { - HANDLE File = (HANDLE)Handle.Platform; - if(File != INVALID_HANDLE_VALUE) - { - DWORD BytesRead; - ReadFile(File, Dest, Size, &BytesRead, 0); - - Assert(BytesRead == Size); - } + HANDLE File = (HANDLE)Handle.Platform; + if(File != INVALID_HANDLE_VALUE) + { + DWORD BytesRead; + ReadFile(File, Dest, Size, &BytesRead, 0); + + Assert(BytesRead == Size); + } } static PLATFORM_GET_FILE_SIZE(Win32_GetFileSize) { - u64 Result = 0; + u64 Result = 0; + + HANDLE File = (HANDLE)Handle.Platform; + if(File != INVALID_HANDLE_VALUE) + { + LARGE_INTEGER FileSize; + GetFileSizeEx(File, &FileSize); - HANDLE File = (HANDLE)Handle.Platform; - if(File != INVALID_HANDLE_VALUE) - { - LARGE_INTEGER FileSize; - GetFileSizeEx(File, &FileSize); - - Result = FileSize.QuadPart; - } - - return(Result); + Result = FileSize.QuadPart; + } + + return(Result); } static PLATFORM_SET_CURSOR(Win32_SetCursor) { - Global_Win32State.Cursor = Cursor; + Global_Win32State.Cursor = Cursor; } inline u64 Win32_GetWallClock(void) { - LARGE_INTEGER Query; - QueryPerformanceCounter(&Query); - - u64 Result = Query.QuadPart; - return(Result); + LARGE_INTEGER Query; + QueryPerformanceCounter(&Query); + + u64 Result = Query.QuadPart; + return(Result); } inline r64 Win32_GetSecondsElapsed(u64 Start, u64 End) { - u64 Elapsed = End - Start; - - r64 Result = (r64)Elapsed/(r64)Global_Win32State.PerformanceFrequency; - return(Result); + u64 Elapsed = End - Start; + + r64 Result = (r64)Elapsed/(r64)Global_Win32State.PerformanceFrequency; + return(Result); } inline FILETIME Win32_GetLastWriteTime(char *Path) { - FILETIME Result = {}; + FILETIME Result = {}; + + HANDLE File = CreateFileA(Path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if(File) + { + FILETIME Creation, LastAccess, LastWrite; + GetFileTime(File, &Creation, &LastAccess, &LastWrite); - HANDLE File = CreateFileA(Path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - if(File) - { - FILETIME Creation, LastAccess, LastWrite; - GetFileTime(File, &Creation, &LastAccess, &LastWrite); - - Result = LastWrite; - - CloseHandle(File); - } + Result = LastWrite; - return(Result); + CloseHandle(File); + } + + return(Result); } static win32_loaded_code Win32_LoadCode(void) { - win32_loaded_code Code = {}; + win32_loaded_code Code = {}; + + win32_state *State = &Global_Win32State; + + if(CopyFile(State->DLLPath, State->TempDLLPath, FALSE)) + { + Code.LastWriteTime = Win32_GetLastWriteTime(State->DLLPath); - win32_state *State = &Global_Win32State; - - if(CopyFile(State->DLLPath, State->TempDLLPath, FALSE)) + Code.DLL = LoadLibraryA(State->TempDLLPath); + if(Code.DLL) { - Code.LastWriteTime = Win32_GetLastWriteTime(State->DLLPath); - - Code.DLL = LoadLibraryA(State->TempDLLPath); - if(Code.DLL) - { - Code.UpdateAndRender = (vn_update_and_render *)GetProcAddress(Code.DLL, "VN_UpdateAndRender"); - if(Code.UpdateAndRender) - { - Code.IsValid = true; - } - } + Code.UpdateAndRender = (vn_update_and_render *)GetProcAddress(Code.DLL, "VN_UpdateAndRender"); + if(Code.UpdateAndRender) + { + Code.IsValid = true; + } } - - return(Code); + } + + return(Code); } static void Win32_UnloadCode(win32_loaded_code *Code) { - if(Code->DLL) - { - FreeLibrary(Code->DLL); - } - - *Code = {}; + if(Code->DLL) + { + FreeLibrary(Code->DLL); + } + + *Code = {}; } static void Win32_UpdateCode(win32_loaded_code *Code) { - win32_state *State = &Global_Win32State; - - FILETIME LastWriteTime = Win32_GetLastWriteTime(State->DLLPath); - if(CompareFileTime(&Code->LastWriteTime, &LastWriteTime) != 0) - { - Win32_UnloadCode(Code); - *Code = Win32_LoadCode(); - } + win32_state *State = &Global_Win32State; + + FILETIME LastWriteTime = Win32_GetLastWriteTime(State->DLLPath); + if(CompareFileTime(&Code->LastWriteTime, &LastWriteTime) != 0) + { + Win32_UnloadCode(Code); + *Code = Win32_LoadCode(); + } } static PLATFORM_TOGGLE_FULLSCREEN(Win32_ToggleFullscreen) { - HWND Window = Global_Win32State.Window; - - DWORD Style = GetWindowLong(Window, GWL_STYLE); - if(Style & WS_OVERLAPPEDWINDOW) + HWND Window = Global_Win32State.Window; + + DWORD Style = GetWindowLong(Window, GWL_STYLE); + if(Style & WS_OVERLAPPEDWINDOW) + { + MONITORINFO MonitorInfo = {sizeof(MonitorInfo)}; + if(GetWindowPlacement(Window, &Global_WindowPosition) && + GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), &MonitorInfo)) { - MONITORINFO MonitorInfo = {sizeof(MonitorInfo)}; - if(GetWindowPlacement(Window, &Global_WindowPosition) && - GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), &MonitorInfo)) - { - SetWindowPos(Window, HWND_TOP, - MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top, - MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left, - MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top, - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - } - } - else - { - SetWindowPlacement(Window, &Global_WindowPosition); - SetWindowPos(Window, 0, 0, 0, 0, 0, - SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_FRAMECHANGED); + SetWindowPos(Window, HWND_TOP, + MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top, + MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left, + MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top, + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } + } + else + { + SetWindowPlacement(Window, &Global_WindowPosition); + SetWindowPos(Window, 0, 0, 0, 0, 0, + SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_FRAMECHANGED); + } } inline v2 Win32_GetMouseP(HWND Window) { - POINT Point; - GetCursorPos(&Point); - ScreenToClient(Window, &Point); - - v2 Result = V2(Point.x, Point.y); - return(Result); + POINT Point; + GetCursorPos(&Point); + ScreenToClient(Window, &Point); + + v2 Result = V2(Point.x, Point.y); + return(Result); } inline v2 Win32_GetWindowDim(HWND Window) { - RECT ClientRect; - GetClientRect(Window, &ClientRect); - - v2 Result = V2(ClientRect.right - ClientRect.left, ClientRect.bottom - ClientRect.top); - return(Result); + RECT ClientRect; + GetClientRect(Window, &ClientRect); + + v2 Result = V2(ClientRect.right - ClientRect.left, ClientRect.bottom - ClientRect.top); + return(Result); } inline platform_modifiers Win32_GetModifiers(void) { - platform_modifiers Modifiers = 0; - - if(GetKeyState(VK_CONTROL) & 0x8000) - { - Modifiers |= PlatformModifier_Ctrl; - } - if(GetKeyState(VK_SHIFT) & 0x8000) - { - Modifiers |= PlatformModifier_Shift; - } - if(GetKeyState(VK_MENU) & 0x8000) - { - Modifiers |= PlatformModifier_Alt; - } - - return(Modifiers); + platform_modifiers Modifiers = 0; + + if(GetKeyState(VK_CONTROL) & 0x8000) + { + Modifiers |= PlatformModifier_Ctrl; + } + if(GetKeyState(VK_SHIFT) & 0x8000) + { + Modifiers |= PlatformModifier_Shift; + } + if(GetKeyState(VK_MENU) & 0x8000) + { + Modifiers |= PlatformModifier_Alt; + } + + return(Modifiers); } static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) { - LRESULT Result = 0; - - win32_state *State = &Global_Win32State; - - temporary_memory Scratch = GetScratch(0, 0); - - platform_event *Event = 0; - - b32 ButtonIsUp = false; - axis2 ScrollAxis = Axis2_Y; - - switch(Message) + LRESULT Result = 0; + + win32_state *State = &Global_Win32State; + + temporary_memory Scratch = GetScratch(0, 0); + + platform_event *Event = 0; + + b32 ButtonIsUp = false; + axis2 ScrollAxis = Axis2_Y; + + switch(Message) + { + case WM_CLOSE: { - case WM_CLOSE: - { - Global_Running = false; - } break; - - case WM_WINDOWPOSCHANGED: - { - // TODO(casey): For now, we are setting the window styles in here - // because sometimes Windows can reposition our window out of fullscreen - // without going through our ToggleFullscreen(), and we want to put our - // title bar and border back when it does! - - WINDOWPOS *NewPos = (WINDOWPOS *)LParam; - - b32 BecomingFullscreen = false; - MONITORINFO MonitorInfo = {sizeof(MonitorInfo)}; - if(GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), - &MonitorInfo)) - { - s32 MonWidth = (MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left); - s32 MonHeight = (MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top); - BecomingFullscreen = ((MonitorInfo.rcMonitor.left == NewPos->x) && - (MonitorInfo.rcMonitor.top == NewPos->y) && - (MonWidth == NewPos->cx) && - (MonHeight == NewPos->cy)); - } - - DWORD OldStyle = GetWindowLong(Window, GWL_STYLE); - DWORD FullscreenStyle = OldStyle & ~WS_OVERLAPPEDWINDOW; - DWORD WindowedStyle = OldStyle | WS_OVERLAPPEDWINDOW; - DWORD NewStyle = (BecomingFullscreen) ? FullscreenStyle : WindowedStyle; - - if(NewStyle != OldStyle) - { - SetWindowLong(Window, GWL_STYLE, NewStyle); - } - - Result = DefWindowProcA(Window, Message, WParam, LParam); - } break; - - case WM_MOUSEHWHEEL: - { - ScrollAxis = Axis2_X; - } fallthrough; - case WM_MOUSEWHEEL: - { - Event = PushStruct(&State->EventArena, platform_event); - Event->Type = PlatformEvent_MouseScroll; - Event->Scroll.E[ScrollAxis] = GET_WHEEL_DELTA_WPARAM(WParam) / 120.0; - } break; - - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - { - ButtonIsUp = true; - } fallthrough; - - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - { - platform_event_type Type = ButtonIsUp ? PlatformEvent_Release : PlatformEvent_Press; - - platform_key Key = Key_Invalid; - switch(Message) - { - case WM_LBUTTONUP: case WM_LBUTTONDOWN: { Key = Key_MouseLeft; } break; - case WM_MBUTTONUP: case WM_MBUTTONDOWN: { Key = Key_MouseMiddle; } break; - case WM_RBUTTONUP: case WM_RBUTTONDOWN: { Key = Key_MouseRight; } break; - } - - Event = PushStruct(&State->EventArena, platform_event); - Event->Type = Type; - Event->Key = Key; - Event->P = Win32_GetMouseP(Window); - } break; - - case WM_SYSKEYUP: - case WM_KEYUP: - { - ButtonIsUp = true; - } fallthrough; - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - { - platform_event_type Type = ButtonIsUp ? PlatformEvent_Release : PlatformEvent_Press; - - u32 VKCode = (u32)WParam; - platform_key Key = Key_Invalid; - - if(VKCode >= 'A' && VKCode <= 'Z') - { - Key = (platform_key)(Key_A + (VKCode - 'A')); - } - else if(VKCode >= VK_F1 && VKCode <= VK_F12) - { - Key = (platform_key)(Key_F1 + (VKCode - VK_F1)); - } - else if(VKCode == VK_LEFT) { Key = Key_Left; } - else if(VKCode == VK_RIGHT) { Key = Key_Right; } - else if(VKCode == VK_UP) { Key = Key_Up; } - else if(VKCode == VK_DOWN) { Key = Key_Down; } - else if(VKCode == VK_SPACE) { Key = Key_Space; } - else if(VKCode == VK_PRIOR) { Key = Key_PageUp; } - else if(VKCode == VK_NEXT) { Key = Key_PageDown; } - else if(VKCode == VK_HOME) { Key = Key_Home; } - else if(VKCode == VK_END) { Key = Key_End; } - else if(VKCode == VK_BACK) { Key = Key_Backspace; } - else if(VKCode == VK_DELETE) { Key = Key_Delete; } - - if(Key != Key_Invalid) - { - Event = PushStruct(&State->EventArena, platform_event); - Event->Type = Type; - Event->Key = Key; - } - - if(!ButtonIsUp && (VKCode == VK_RETURN) && (LParam & (1 << 29))) - { - Win32_ToggleFullscreen(); - } - else - { - Result = DefWindowProc(Window, Message, WParam, LParam); - } - - } break; - - case WM_CHAR: - { - u32 Codepoint = (u32)WParam; - if(Codepoint == '\r') - { - Codepoint = '\n'; - } - - if((Codepoint >= 32 && Codepoint != 127) || Codepoint == '\t' || Codepoint == '\n') - { - Event = PushStruct(&State->EventArena, platform_event); - Event->Type = PlatformEvent_Text; - Event->Codepoint = Codepoint; - } - } break; - - case WM_SETCURSOR: - { - range2_r32 WindowRect = {}; - WindowRect.Max = Win32_GetWindowDim(Window); - if(InRange(WindowRect, Win32_GetMouseP(Window))) - { - persist HCURSOR CursorTable[PlatformCursor_Count]; - persist b32 CursorTableLoaded = false; - if(!CursorTableLoaded) - { - CursorTable[PlatformCursor_Arrow] = LoadCursor(0, IDC_ARROW); - CursorTable[PlatformCursor_Cross] = LoadCursor(0, IDC_CROSS); - CursorTable[PlatformCursor_Hand] = LoadCursor(0, IDC_HAND); - CursorTable[PlatformCursor_Help] = LoadCursor(0, IDC_HELP); - CursorTable[PlatformCursor_IBeam] = LoadCursor(0, IDC_IBEAM); - CursorTable[PlatformCursor_SlashedCircle] = LoadCursor(0, IDC_NO); - CursorTable[PlatformCursor_ArrowAll] = LoadCursor(0, IDC_SIZEALL); - CursorTable[PlatformCursor_ArrowNESW] = LoadCursor(0, IDC_SIZENESW); - CursorTable[PlatformCursor_ArrowVertical] = LoadCursor(0, IDC_SIZENS); - CursorTable[PlatformCursor_ArrowNWSE] = LoadCursor(0, IDC_SIZENWSE); - CursorTable[PlatformCursor_ArrowHorizontal] = LoadCursor(0, IDC_SIZEWE); - CursorTable[PlatformCursor_Wait] = LoadCursor(0, IDC_WAIT); - - CursorTableLoaded = true; - } - - SetCursor(CursorTable[Global_Win32State.Cursor]); - } - else - { - DefWindowProc(Window, Message, WParam, LParam); - } - } break; - - default: - { - Result = DefWindowProc(Window, Message, WParam, LParam); - } break; - } + Global_Running = false; + } break; - if(Event) + case WM_WINDOWPOSCHANGED: { - Event->Modifiers = Win32_GetModifiers(); - DLLInsertLast(State->EventList.First, State->EventList.Last, Event); - } + // TODO(casey): For now, we are setting the window styles in here + // because sometimes Windows can reposition our window out of fullscreen + // without going through our ToggleFullscreen(), and we want to put our + // title bar and border back when it does! + + WINDOWPOS *NewPos = (WINDOWPOS *)LParam; + + b32 BecomingFullscreen = false; + MONITORINFO MonitorInfo = {sizeof(MonitorInfo)}; + if(GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), + &MonitorInfo)) + { + s32 MonWidth = (MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left); + s32 MonHeight = (MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top); + BecomingFullscreen = ((MonitorInfo.rcMonitor.left == NewPos->x) && + (MonitorInfo.rcMonitor.top == NewPos->y) && + (MonWidth == NewPos->cx) && + (MonHeight == NewPos->cy)); + } + + DWORD OldStyle = GetWindowLong(Window, GWL_STYLE); + DWORD FullscreenStyle = OldStyle & ~WS_OVERLAPPEDWINDOW; + DWORD WindowedStyle = OldStyle | WS_OVERLAPPEDWINDOW; + DWORD NewStyle = (BecomingFullscreen) ? FullscreenStyle : WindowedStyle; + + if(NewStyle != OldStyle) + { + SetWindowLong(Window, GWL_STYLE, NewStyle); + } + + Result = DefWindowProcA(Window, Message, WParam, LParam); + } break; - ReleaseScratch(Scratch); + case WM_MOUSEHWHEEL: + { + ScrollAxis = Axis2_X; + } fallthrough; + case WM_MOUSEWHEEL: + { + Event = PushStruct(&State->EventArena, platform_event); + Event->Type = PlatformEvent_MouseScroll; + Event->Scroll.E[ScrollAxis] = GET_WHEEL_DELTA_WPARAM(WParam) / 120.0; + } break; - return(Result); + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + ButtonIsUp = true; + } fallthrough; + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + platform_event_type Type = ButtonIsUp ? PlatformEvent_Release : PlatformEvent_Press; + + platform_key Key = Key_Invalid; + switch(Message) + { + case WM_LBUTTONUP: case WM_LBUTTONDOWN: { Key = Key_MouseLeft; } break; + case WM_MBUTTONUP: case WM_MBUTTONDOWN: { Key = Key_MouseMiddle; } break; + case WM_RBUTTONUP: case WM_RBUTTONDOWN: { Key = Key_MouseRight; } break; + } + + Event = PushStruct(&State->EventArena, platform_event); + Event->Type = Type; + Event->Key = Key; + Event->P = Win32_GetMouseP(Window); + } break; + + case WM_SYSKEYUP: + case WM_KEYUP: + { + ButtonIsUp = true; + } fallthrough; + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + platform_event_type Type = ButtonIsUp ? PlatformEvent_Release : PlatformEvent_Press; + + u32 VKCode = (u32)WParam; + platform_key Key = Key_Invalid; + + if(VKCode >= 'A' && VKCode <= 'Z') + { + Key = (platform_key)(Key_A + (VKCode - 'A')); + } + else if(VKCode >= VK_F1 && VKCode <= VK_F12) + { + Key = (platform_key)(Key_F1 + (VKCode - VK_F1)); + } + else if(VKCode == VK_LEFT) { Key = Key_Left; } + else if(VKCode == VK_RIGHT) { Key = Key_Right; } + else if(VKCode == VK_UP) { Key = Key_Up; } + else if(VKCode == VK_DOWN) { Key = Key_Down; } + else if(VKCode == VK_SPACE) { Key = Key_Space; } + else if(VKCode == VK_PRIOR) { Key = Key_PageUp; } + else if(VKCode == VK_NEXT) { Key = Key_PageDown; } + else if(VKCode == VK_HOME) { Key = Key_Home; } + else if(VKCode == VK_END) { Key = Key_End; } + else if(VKCode == VK_BACK) { Key = Key_Backspace; } + else if(VKCode == VK_DELETE) { Key = Key_Delete; } + + if(Key != Key_Invalid) + { + Event = PushStruct(&State->EventArena, platform_event); + Event->Type = Type; + Event->Key = Key; + } + + if(!ButtonIsUp && (VKCode == VK_RETURN) && (LParam & (1 << 29))) + { + Win32_ToggleFullscreen(); + } + else + { + Result = DefWindowProc(Window, Message, WParam, LParam); + } + + } break; + + case WM_CHAR: + { + u32 Codepoint = (u32)WParam; + if(Codepoint == '\r') + { + Codepoint = '\n'; + } + + if((Codepoint >= 32 && Codepoint != 127) || Codepoint == '\t' || Codepoint == '\n') + { + Event = PushStruct(&State->EventArena, platform_event); + Event->Type = PlatformEvent_Text; + Event->Codepoint = Codepoint; + } + } break; + + case WM_SETCURSOR: + { + range2_r32 WindowRect = {}; + WindowRect.Max = Win32_GetWindowDim(Window); + if(InRange(WindowRect, Win32_GetMouseP(Window))) + { + persist HCURSOR CursorTable[PlatformCursor_Count]; + persist b32 CursorTableLoaded = false; + if(!CursorTableLoaded) + { + CursorTable[PlatformCursor_Arrow] = LoadCursor(0, IDC_ARROW); + CursorTable[PlatformCursor_Cross] = LoadCursor(0, IDC_CROSS); + CursorTable[PlatformCursor_Hand] = LoadCursor(0, IDC_HAND); + CursorTable[PlatformCursor_Help] = LoadCursor(0, IDC_HELP); + CursorTable[PlatformCursor_IBeam] = LoadCursor(0, IDC_IBEAM); + CursorTable[PlatformCursor_SlashedCircle] = LoadCursor(0, IDC_NO); + CursorTable[PlatformCursor_ArrowAll] = LoadCursor(0, IDC_SIZEALL); + CursorTable[PlatformCursor_ArrowNESW] = LoadCursor(0, IDC_SIZENESW); + CursorTable[PlatformCursor_ArrowVertical] = LoadCursor(0, IDC_SIZENS); + CursorTable[PlatformCursor_ArrowNWSE] = LoadCursor(0, IDC_SIZENWSE); + CursorTable[PlatformCursor_ArrowHorizontal] = LoadCursor(0, IDC_SIZEWE); + CursorTable[PlatformCursor_Wait] = LoadCursor(0, IDC_WAIT); + + CursorTableLoaded = true; + } + + SetCursor(CursorTable[Global_Win32State.Cursor]); + } + else + { + DefWindowProc(Window, Message, WParam, LParam); + } + } break; + + default: + { + Result = DefWindowProc(Window, Message, WParam, LParam); + } break; + } + + if(Event) + { + Event->Modifiers = Win32_GetModifiers(); + DLLInsertLast(State->EventList.First, State->EventList.Last, Event); + } + + ReleaseScratch(Scratch); + + return(Result); } static void Win32_ProcessInput(vn_input *Input, HWND Window, r32 dtForFrame) { - win32_state *State = &Global_Win32State; - + win32_state *State = &Global_Win32State; + + { + if(State->EventArenaTemp.Arena) { - if(State->EventArenaTemp.Arena) - { - EndTemporaryMemory(State->EventArenaTemp); - } - - State->EventArenaTemp = BeginTemporaryMemory(&State->EventArena); + EndTemporaryMemory(State->EventArenaTemp); } - MSG Message; - while(PeekMessage(&Message, Window, 0, 0, PM_REMOVE)) - { - TranslateMessage(&Message); - DispatchMessageA(&Message); - } - - Input->EventList = &State->EventList; - - v2 NewMouseP = Win32_GetMouseP(Window); - v2 OldMouseP = Input->MouseP; - - Input->dMouseP = NewMouseP - OldMouseP; - Input->MouseP = NewMouseP; - - Input->dtForFrame = dtForFrame; + State->EventArenaTemp = BeginTemporaryMemory(&State->EventArena); + } + + MSG Message; + while(PeekMessage(&Message, Window, 0, 0, PM_REMOVE)) + { + TranslateMessage(&Message); + DispatchMessageA(&Message); + } + + Input->EventList = &State->EventList; + + v2 NewMouseP = Win32_GetMouseP(Window); + v2 OldMouseP = Input->MouseP; + + Input->dMouseP = NewMouseP - OldMouseP; + Input->MouseP = NewMouseP; + + Input->dtForFrame = dtForFrame; } static void Win32_EnforceFrameRate(u64 FrameBegin, r32 TargetFrameRate) { - win32_state *State = &Global_Win32State; - - r64 TimeElapsed = Win32_GetSecondsElapsed(FrameBegin, Win32_GetWallClock()); - r64 Target = 1.0 / TargetFrameRate; - - r64 ToSleep = Target - TimeElapsed; - if(ToSleep > 0) + win32_state *State = &Global_Win32State; + + r64 TimeElapsed = Win32_GetSecondsElapsed(FrameBegin, Win32_GetWallClock()); + r64 Target = 1.0 / TargetFrameRate; + + r64 ToSleep = Target - TimeElapsed; + if(ToSleep > 0) + { + u64 MSToSleep = (u64)Floor(ToSleep*1000); + if(State->SleepIsGranular) { - u64 MSToSleep = (u64)Floor(ToSleep*1000); - if(State->SleepIsGranular) - { - Sleep(MSToSleep); - } - - while(ToSleep > 0) - { - TimeElapsed = Win32_GetSecondsElapsed(FrameBegin, Win32_GetWallClock()); - ToSleep = Target - TimeElapsed; - } + Sleep(MSToSleep); } + + while(ToSleep > 0) + { + TimeElapsed = Win32_GetSecondsElapsed(FrameBegin, Win32_GetWallClock()); + ToSleep = Target - TimeElapsed; + } + } } inline void Win32_GetRelevantPaths(win32_state *State) { - GetModuleFileName(0, State->EXEPath, ArrayCount(State->EXEPath)); - if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - Win32_PlatformError("Path to executable is too long. Try running the game from another directory", true); - } - - s64 OnePastLastSlash = LastIndexOf(MakeStringFromCString(State->EXEPath), '\\') + 1; - - string DLLName = StrLit("vn.dll"); - Copy(State->DLLPath, State->EXEPath, OnePastLastSlash); - Copy(State->DLLPath+OnePastLastSlash, DLLName.Data, DLLName.Count); - - string TempDLLName = StrLit("temp_vn.dll"); - Copy(State->TempDLLPath, State->EXEPath, OnePastLastSlash); - Copy(State->TempDLLPath+OnePastLastSlash, TempDLLName.Data, TempDLLName.Count); + GetModuleFileName(0, State->EXEPath, ArrayCount(State->EXEPath)); + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + Win32_PlatformError("Path to executable is too long. Try running the game from another directory", true); + } + + string EXEPathString = MakeStringFromCString(State->EXEPath); + + s64 OnePastLastSlash = LastIndexOf(EXEPathString, '\\') + 1; + s64 BuildIndex = LastIndexOf(EXEPathString, StrLit("build")); + + if(BuildIndex == -1) + { + State->ContentsPath = MakeString((char *)EXEPathString.Data, OnePastLastSlash); + } + else + { + State->ContentsPath = MakeString((char *)EXEPathString.Data, BuildIndex); + } + + string DLLName = StrLit("vn.dll"); + Copy(State->DLLPath, State->EXEPath, OnePastLastSlash); + Copy(State->DLLPath+OnePastLastSlash, DLLName.Data, DLLName.Count); + + string TempDLLName = StrLit("temp_vn.dll"); + Copy(State->TempDLLPath, State->EXEPath, OnePastLastSlash); + Copy(State->TempDLLPath+OnePastLastSlash, TempDLLName.Data, TempDLLName.Count); } int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, int ShowCommand) { - thread_context ThreadContext = {}; - SetThreadContext(&ThreadContext); + thread_context ThreadContext = {}; + SetThreadContext(&ThreadContext); + + // sixten: Setup Win32 platform state. + { + win32_state *State = &Global_Win32State; + Win32_GetRelevantPaths(State); - // sixten: Setup Win32 platform state. + LARGE_INTEGER FrequencyQuery; + QueryPerformanceFrequency(&FrequencyQuery); + State->PerformanceFrequency = FrequencyQuery.QuadPart; + + State->MemorySentinel.Next = &State->MemorySentinel; + State->MemorySentinel.Prev = &State->MemorySentinel; + + State->SleepIsGranular = (timeBeginPeriod(1) != TIMERR_NOERROR); + } + + // sixten: Setup platform layer + { + Platform.AllocateMemory = Win32_AllocateMemory; + Platform.DeallocateMemory = Win32_DeallocateMemory; + Platform.OpenFile = Win32_OpenFile; + Platform.CloseFile = Win32_CloseFile; + Platform.ReadFile = Win32_ReadFile; + Platform.GetFileSize = Win32_GetFileSize; + Platform.SetCursor = Win32_SetCursor; + Platform.ToggleFullscreen = Win32_ToggleFullscreen; + } + + WNDCLASS WindowClass = {}; + WindowClass.lpszClassName = "vn-window-class"; + WindowClass.lpfnWndProc = Win32_WindowCallback; + WindowClass.hCursor = LoadCursorA(0, IDC_ARROW); + WindowClass.style = CS_OWNDC; + + if(RegisterClassA(&WindowClass)) + { + HWND Window = CreateWindowEx(0, + WindowClass.lpszClassName, + "vn - June 2023 Build", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + 0, 0, Instance, 0); + if(Window) { - win32_state *State = &Global_Win32State; - Win32_GetRelevantPaths(State); + Global_Win32State.Window = Window; + + vn_input Input = {}; + + // sixten: Setup OpenGL + vn_render_commands RenderCommands = {}; + HDC DeviceContext = GetDC(Window); + Win32_CreateOpenGLContext(DeviceContext); + opengl_context OpenGLContext = OpenGL_SetupContext(&RenderCommands, 16*1024); + + vn_memory Memory = {}; + Memory.PlatformAPI = Platform; + + win32_loaded_code LoadedCode = Win32_LoadCode(); + + ShowWindow(Window, SW_SHOWNORMAL); + + u64 CurrentTime = Win32_GetWallClock(); + + Global_Running = true; + while(Global_Running) + { + u64 NewTime = Win32_GetWallClock(); + r64 dtForFrame = Win32_GetSecondsElapsed(CurrentTime, NewTime); + CurrentTime = NewTime; - LARGE_INTEGER FrequencyQuery; - QueryPerformanceFrequency(&FrequencyQuery); - State->PerformanceFrequency = FrequencyQuery.QuadPart; + Win32_ProcessInput(&Input, Window, dtForFrame); - State->MemorySentinel.Next = &State->MemorySentinel; - State->MemorySentinel.Prev = &State->MemorySentinel; + Win32_SetCursor(PlatformCursor_Arrow); - State->SleepIsGranular = (timeBeginPeriod(1) != TIMERR_NOERROR); - } - - // sixten: Setup platform layer - { - Platform.AllocateMemory = Win32_AllocateMemory; - Platform.DeallocateMemory = Win32_DeallocateMemory; - Platform.OpenFile = Win32_OpenFile; - Platform.CloseFile = Win32_CloseFile; - Platform.ReadFile = Win32_ReadFile; - Platform.GetFileSize = Win32_GetFileSize; - Platform.SetCursor = Win32_SetCursor; - Platform.ToggleFullscreen = Win32_ToggleFullscreen; - } - - WNDCLASS WindowClass = {}; - WindowClass.lpszClassName = "vn-window-class"; - WindowClass.lpfnWndProc = Win32_WindowCallback; - WindowClass.hCursor = LoadCursorA(0, IDC_ARROW); - WindowClass.style = CS_OWNDC; - - if(RegisterClassA(&WindowClass)) - { - HWND Window = CreateWindowEx(0, - WindowClass.lpszClassName, - "vn - June 2023 Build", - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - 0, 0, Instance, 0); - if(Window) + // sixten: Update and render frame. { - Global_Win32State.Window = Window; - - vn_input Input = {}; - - // sixten: Setup OpenGL - vn_render_commands RenderCommands = {}; - HDC DeviceContext = GetDC(Window); - Win32_CreateOpenGLContext(DeviceContext); - opengl_context OpenGLContext = OpenGL_SetupContext(&RenderCommands, 16*1024); - - vn_memory Memory = {}; - Memory.PlatformAPI = Platform; - - win32_loaded_code LoadedCode = Win32_LoadCode(); - - ShowWindow(Window, SW_SHOWNORMAL); - - u64 CurrentTime = Win32_GetWallClock(); - - Global_Running = true; - while(Global_Running) - { - u64 NewTime = Win32_GetWallClock(); - r64 dtForFrame = Win32_GetSecondsElapsed(CurrentTime, NewTime); - CurrentTime = NewTime; - - Win32_ProcessInput(&Input, Window, dtForFrame); - - Win32_SetCursor(PlatformCursor_Arrow); - - // sixten: Update and render frame. - { - Win32_UpdateCode(&LoadedCode); - - OpenGL_BeginFrame(&RenderCommands, Win32_GetWindowDim(Window)); - - if(LoadedCode.IsValid) - { - LoadedCode.UpdateAndRender(&ThreadContext, &Memory, &Input, &RenderCommands); - } - - b32 UseVSync = (Input.RefreshRate == 0); - wglSwapIntervalEXT(UseVSync); - - OpenGL_EndFrame(&OpenGLContext, &RenderCommands); - wglSwapLayerBuffers(DeviceContext, WGL_SWAP_MAIN_PLANE); - } - - b32 ShouldLimitFrameRate = (Input.RefreshRate > 0); - if(ShouldLimitFrameRate) - { - Win32_EnforceFrameRate(CurrentTime, Input.RefreshRate); - } - } + Win32_UpdateCode(&LoadedCode); + + OpenGL_BeginFrame(&RenderCommands, Win32_GetWindowDim(Window)); + + if(LoadedCode.IsValid) + { + LoadedCode.UpdateAndRender(&ThreadContext, &Memory, &Input, &RenderCommands); + } + + b32 UseVSync = (Input.RefreshRate == 0); + wglSwapIntervalEXT(UseVSync); + + OpenGL_EndFrame(&OpenGLContext, &RenderCommands); + wglSwapLayerBuffers(DeviceContext, WGL_SWAP_MAIN_PLANE); } - else + + b32 ShouldLimitFrameRate = (Input.RefreshRate > 0); + if(ShouldLimitFrameRate) { - Win32_PlatformError("Unable to create window.", true); + Win32_EnforceFrameRate(CurrentTime, Input.RefreshRate); } + } } else { - Win32_PlatformError("Unable to register window class.", true); + Win32_PlatformError("Unable to create window.", true); } - - return(0); + } + else + { + Win32_PlatformError("Unable to register window class.", true); + } + + return(0); } \ No newline at end of file diff --git a/code/win32_main.h b/code/win32_main.h index 1ca0be0..7e8397b 100644 --- a/code/win32_main.h +++ b/code/win32_main.h @@ -5,43 +5,44 @@ struct win32_memory_block { - platform_memory_block Block; - win32_memory_block *Next; - win32_memory_block *Prev; - u64 Padding[2]; + platform_memory_block Block; + win32_memory_block *Next; + win32_memory_block *Prev; + u64 Padding[2]; }; CTAssert(sizeof(win32_memory_block) == 64); struct win32_state { - win32_memory_block MemorySentinel; - ticket_mutex MemoryMutex; - - u64 PerformanceFrequency; - b32 SleepIsGranular; - - HWND Window; - - memory_arena EventArena; - temporary_memory EventArenaTemp; - platform_event_list EventList; - - char EXEPath[512]; - char DLLPath[512]; - char TempDLLPath[512]; - - platform_cursor Cursor; + win32_memory_block MemorySentinel; + ticket_mutex MemoryMutex; + + u64 PerformanceFrequency; + b32 SleepIsGranular; + + HWND Window; + + memory_arena EventArena; + temporary_memory EventArenaTemp; + platform_event_list EventList; + + char EXEPath[512]; + char DLLPath[512]; + char TempDLLPath[512]; + string ContentsPath; + + platform_cursor Cursor; }; struct win32_loaded_code { - HMODULE DLL; - FILETIME LastWriteTime; - - vn_update_and_render *UpdateAndRender; - - b32 IsValid; + HMODULE DLL; + FILETIME LastWriteTime; + + vn_update_and_render *UpdateAndRender; + + b32 IsValid; }; #endif //WIN32_MAIN_H