Started work on the character editor.

main
sixtenhugosson 2023-09-05 19:50:49 +02:00
parent e96b3a7850
commit 41c1f17158
20 changed files with 597 additions and 266 deletions

View File

@ -1,11 +1,11 @@
@echo off
set CommonCompilerOptions=/Zi /FC /nologo /DVN_INTERNAL=1 /DVN_SLOW=1 /DVN_USE_INSTANCING=1 /Oi /W4 /WX /wd4996 /wd4201 /wd4305 /wd4244 /wd4100 /wd4505 /std:c++17
set CommonCompilerOptions=/Zi /FC /nologo /DVN_INTERNAL=1 /DVN_SLOW=1 /DVN_USE_INSTANCING=1 /Oi /W4 /WX /we4062 /wd4996 /wd4201 /wd4305 /wd4244 /wd4100 /wd4505 /std:c++17
if not exist "../build" mkdir "../build"
pushd "../build/"
cl /Zi /nologo /FC ../code/third_party/codegen/codegen.c
rem cl /Zi /nologo /FC ../code/third_party/codegen/codegen.c
codegen ../code/
cl %CommonCompilerOptions% ../code/vn.cpp /LD /link /export:VN_UpdateAndRender /incremental:no

View File

@ -385,12 +385,11 @@ void main()
{
v2[] Vertices = V2[](V2(0, 0), V2(0, 1), V2(1, 0), V2(1, 1));
DestP = In_Dest.xy + (In_Dest.zw-In_Dest.xy)*Vertices[gl_VertexID];
DestP = LinearBlend(In_Dest.xy, In_Dest.zw, Vertices[gl_VertexID]);
DestHalfSize = (In_Dest.zw-In_Dest.xy)/2;
DestCenter = (In_Dest.xy+In_Dest.zw)/2;
v2 SourceDim = In_Source.zw-In_Source.xy;
SourceP = In_Source.xy + SourceDim*Vertices[gl_VertexID];
SourceP = LinearBlend(In_Source.xy, In_Source.zw, Vertices[gl_VertexID]);
v2 ScreenP = V2(DestP.x / Uniform_Resolution.x, DestP.y / Uniform_Resolution.y);
ScreenP = ScreenP*2 - 1;
@ -448,8 +447,9 @@ r32 BorderFactor = 1;
if(BorderThickness != 0)
{
v2 InteriorHalfSize = DestHalfSize - BorderThickness;
v2 InteriorRadiusReducePair = InteriorHalfSize / DestHalfSize;
r32 InteriorRadiusReduce = Min(InteriorHalfSize.x / DestHalfSize.x, InteriorHalfSize.y / DestHalfSize.y);
r32 InteriorRadiusReduce = Min(InteriorRadiusReducePair.x, InteriorRadiusReducePair.y);
r32 InteriorCornerRadius = CornerRadius*InteriorRadiusReduce*InteriorRadiusReduce;
r32 InsideDist = RoundedRect(DestP, DestCenter, InteriorHalfSize - SoftnessPadding, InteriorCornerRadius);

View File

@ -27,6 +27,7 @@ global debug_settings *DEBUG_DebugSettings = 0;
#include "vn_workspace.h"
#include "vn_animation_curve.h"
#include "vn_theme_dark.h"
#include "vn_character.h"
#include "vn_tokenizer.cpp"
#include "vn_config.cpp"
@ -38,6 +39,7 @@ global debug_settings *DEBUG_DebugSettings = 0;
#include "vn_scene.cpp"
#include "vn_scene_view.cpp"
#include "vn_workspace.cpp"
#include "vn_character.cpp"
struct vn_state
{
@ -52,6 +54,7 @@ struct vn_state
workspace Workspace;
animation_curve_state AnimationCurveState;
character_registry CharacterRegistry;
render_handle BackgroundTexture;
scene_view SceneView;
@ -136,6 +139,15 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
SV_Init(SceneView, State->Arena);
SceneView->BackgroundTexture = State->BackgroundTexture;
//- sixten: create mock characters
CR_Init(&State->CharacterRegistry);
character_entry *Arthur = CR_EntryFromName(StrLit("Arthur"));
UnusedVariable(Arthur);
CR_EntryFromName(StrLit("Catherine"));
CR_EntryFromName(StrLit("Quinn"));
CR_EntryFromName(StrLit("Margaret"));
UI_Init(&State->UI);
W_Init(&State->Workspace);
AC_Init(&State->AnimationCurveState);

View File

@ -0,0 +1,51 @@
global character_registry *Global_CharacterRegistry = 0;
////////////////////////////////
//~ sixten: Character Registry Functions
static void CR_SetState(character_registry *State)
{
Global_CharacterRegistry = State;
}
static character_registry *CR_GetState(void)
{
return(Global_CharacterRegistry);
}
static character_list CR_GetCharacters(void)
{
character_registry *Registry = CR_GetState();
character_list List = Registry->Characters;
return(List);
}
static void CR_Init(character_registry *State)
{
CR_SetState(State);
State->Arena = ArenaAllocate(Megabytes(32));
}
static character_entry *CR_EntryFromName(string Name)
{
character_entry *Entry = 0;
character_registry *Registry = CR_GetState();
for(character_entry *Iter = Registry->Characters.First; Iter != 0; Iter = Iter->Next)
{
if(AreEqual(Name, Iter->Name))
{
Entry = Iter;
break;
}
}
if(!Entry)
{
Entry = PushStruct(Registry->Arena, character_entry);
Entry->Name = PushString(Registry->Arena, Name);
DLLInsertLast(Registry->Characters.First, Registry->Characters.Last, Entry);
}
return(Entry);
}

View File

@ -0,0 +1,38 @@
/* date = August 30th 2023 6:28 pm */
#ifndef VN_CHARACTER_H
#define VN_CHARACTER_H
////////////////////////////////
//~ sixten: Character Registry Types
struct character_entry
{
character_entry *Next;
character_entry *Prev;
string Name;
};
struct character_list
{
character_entry *First;
character_entry *Last;
s64 Count;
};
struct character_registry
{
memory_arena *Arena;
character_list Characters;
};
////////////////////////////////
//~ sixten: Character Registry Functions
static void CR_SetState(character_registry *State);
static character_registry *CR_GetState(void);
static character_list CR_GetCharacters(void);
static void CR_Init(void);
static character_entry *CR_EntryFromName(string Name);
#endif //VN_CHARACTER_H

View File

@ -6,13 +6,16 @@
static void S_ParseError(scene_compiler *Compiler, char *Message, s64 TokenOffset)
{
Compiler->EncounteredError = true;
Compiler->InPanicMode = true;
scene_compile_error *Error = PushStruct(Compiler->Arena, scene_compile_error);
Error->Message = PushFormat(Compiler->Arena, Message);
Error->Token = Compiler->At[TokenOffset];
QueuePush(Compiler->Errors.First, Compiler->Errors.Last, Error);
Compiler->Errors.Count += 1;
if(!Compiler->InPanicMode)
{
Compiler->EncounteredError = true;
Compiler->InPanicMode = true;
scene_compile_error *Error = PushStruct(Compiler->Arena, scene_compile_error);
Error->Message = PushFormat(Compiler->Arena, Message);
Error->Token = Compiler->At[TokenOffset];
QueuePush(Compiler->Errors.First, Compiler->Errors.Last, Error);
Compiler->Errors.Count += 1;
}
}
static void S_EmitByte(scene_compiler *Compiler, u8 Byte)
@ -32,6 +35,14 @@ static void S_EmitByte(scene_compiler *Compiler, u8 Byte)
Chunk->Count += 1;
}
static void S_EmitU32(scene_compiler *Compiler, u32 Value)
{
S_EmitByte(Compiler, Value >> 0);
S_EmitByte(Compiler, Value >> 8);
S_EmitByte(Compiler, Value >> 16);
S_EmitByte(Compiler, Value >> 24);
}
static void S_EmitBucket(scene_compiler *Compiler, scene_annotated_bytecode_bucket *Bucket)
{
for(scene_annotated_bytecode_chunk *Chunk = Bucket->First; Chunk != 0; Chunk = Chunk->Next)
@ -51,44 +62,17 @@ static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value)
Chunk = PushStruct(Compiler->Arena, scene_value_chunk);
QueuePush(Compiler->FirstValueChunk, Compiler->LastValueChunk, Chunk);
}
Chunk->Values[Chunk->Count] = Value;
u64 Result = Compiler->ValueCount;
Compiler->ValueCount += 1;
Chunk->Values[Chunk->Count] = Value;
Chunk->Count += 1;
return(Result);
}
static s64 S_EmitVariableLength(scene_compiler *Compiler, u64 Value)
{
s64 Length = 1;
u64 Index = Value;
for(;Index > 0x7F; Index >>= 7)
{
S_EmitByte(Compiler, Index|0x80);
Length += 1;
InvalidCodepath;
}
S_EmitByte(Compiler, Index);
return(Length);
}
static scene_variable_read S_ReadVariableLength(u8 *Byte)
{
scene_variable_read Result = {};
u8 *StartByte = Byte;
for(;*Byte & 0x80; Byte += 1)
{
Result.Value = (Result.Value<<7)|(*Byte & 0x7F);
}
Result.Value = (Result.Value<<7)|(*Byte & 0x7F);
Result.Size = Byte-StartByte+1;
Compiler->ValueCount += 1;
return(Result);
}
static void S_EmitConstant(scene_compiler *Compiler, scene_value Value)
{
S_EmitByte(Compiler, S_Op_Constant);
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, Value));
S_EmitU32(Compiler, S_MakeConstant(Compiler, Value));
}
static void S_SetEmissionTarget(scene_compiler *Compiler, scene_emission_target Target)
@ -148,6 +132,7 @@ static scene_parse_rule S_ParseRuleFromToken(scene_compiler *Compiler, token Tok
case TokenKind_False: { Result = { S_ParseLiteral, 0, S_Precedence_None }; } break;
case TokenKind_True: { Result = { S_ParseLiteral, 0, S_Precedence_None }; } break;
case TokenKind_Numeric: { Result = { S_ParseNumber, 0, S_Precedence_None }; } break;
case TokenKind_StringLiteral: { Result = { S_ParseString, 0, S_Precedence_None }; } break;
case TokenKind_Identifier: { Result = { S_ParseVariable, 0, S_Precedence_None }; } break;
default:
{
@ -235,11 +220,6 @@ static void S_ParseDeclaration(scene_compiler *Compiler)
Compiler->At += 1;
S_ParseVariableDeclaration(Compiler);
} break;
case TokenKind_StringLiteral:
{
Compiler->At += 1;
S_ParseLineEntry(Compiler);
} break;
case TokenKind_Jump:
{
Compiler->At += 1;
@ -250,9 +230,46 @@ static void S_ParseDeclaration(scene_compiler *Compiler)
Compiler->At += 1;
S_ParseBranchStatement(Compiler);
} break;
case TokenKind_StringLiteral:
{
S_ParseExpression(Compiler);
S_EmitByte(Compiler, S_Op_LineEntry);
//- sixten: parse tags
{
b32 EmitAwait = true;
scene_line_entry_flag Flags = 0;
for(;Compiler->At[0].Kind == TokenKind_PoundSign;)
{
Compiler->At += 1;
token TagToken = S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected tag name after '#'.");
string TagString = T_StringFromToken(Compiler->Text, TagToken);
if(AreEqual(TagString, StrLit("noclear")))
{
Flags |= S_LineEntryFlag_NoClear;
}
else if(AreEqual(TagString, StrLit("noawait")))
{
EmitAwait = false;
}
else
{
S_ParseError(Compiler, "Unknown tag.");
}
}
if(EmitAwait)
{
S_EmitByte(Compiler, S_Op_AwaitInput);
}
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after statement.");
}
} break;
default:
{
S_ParseStatement(Compiler);
S_EmitByte(Compiler, S_Op_Pop);
} break;
}
@ -260,17 +277,18 @@ static void S_ParseDeclaration(scene_compiler *Compiler)
{
for(;Compiler->At < Compiler->TokensEnd;)
{
if(Compiler->At[0].Kind == TokenKind_Semicolon)
if(Compiler->At[-1].Kind == TokenKind_Semicolon)
{
goto End;
}
switch(Compiler->At[-1].Kind)
switch(Compiler->At[0].Kind)
{
case TokenKind_Var: goto End;
case TokenKind_StringLiteral: goto End;
case TokenKind_Jump: goto End;
case TokenKind_Branch: goto End;
default: break;
}
Compiler->At += 1;
@ -299,13 +317,9 @@ static void S_ParseVariableDeclaration(scene_compiler *Compiler)
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after variable declaration.");
S_EmitByte(Compiler, S_Op_DefineGlobal);
u64 Index = NameConstant;
for(;Index > 0x7F; Index >>= 7)
{
S_EmitByte(Compiler, Index|0x80);
InvalidCodepath;
}
S_EmitByte(Compiler, Index);
Assert(NameConstant < U32_Max);
S_EmitU32(Compiler, NameConstant);
}
static void S_ParseVariable(scene_compiler *Compiler, b32 CanAssign)
@ -326,44 +340,7 @@ static void S_ParseNamedVariable(scene_compiler *Compiler, token Token, b32 CanA
{
S_EmitByte(Compiler, S_Op_GetGlobal);
}
S_EmitVariableLength(Compiler, NameConstant);
}
static void S_ParseLineEntry(scene_compiler *Compiler)
{
token LineToken = Compiler->At[-1];
b32 EmitAwait = true;
// sixten: tags -> flags
scene_line_entry_flag Flags = 0;
for(;Compiler->At[0].Kind == TokenKind_PoundSign;)
{
Compiler->At += 1;
token TagToken = S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected tag name after '#'.");
string TagString = T_StringFromToken(Compiler->Text, TagToken);
if(AreEqual(TagString, StrLit("noclear")))
{
Flags |= S_LineEntryFlag_NoClear;
}
else if(AreEqual(TagString, StrLit("noawait")))
{
EmitAwait = false;
}
else
{
S_ParseError(Compiler, "Unknown tag.");
}
}
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after line entry.");
S_EmitByte(Compiler, S_Op_LineEntry|Flags);
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeSourceRef(LineToken)));
if(EmitAwait)
{
S_EmitByte(Compiler, S_Op_AwaitInput);
}
S_EmitU32(Compiler, NameConstant);
}
static void S_ParseJumpStatement(scene_compiler *Compiler)
@ -372,7 +349,7 @@ static void S_ParseJumpStatement(scene_compiler *Compiler)
token DestToken = Compiler->At[-1];
S_EmitByte(Compiler, S_Op_Jump);
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeSourceRef(DestToken)));
S_EmitU32(Compiler, S_MakeConstant(Compiler, S_MakeSourceRef(DestToken)));
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after jump statement.");
}
@ -415,8 +392,8 @@ static void S_ParseBranchStatement(scene_compiler *Compiler)
for(scene_branch_case *Branch = FirstBranch; Branch != 0; Branch = Branch->Next)
{
S_EmitByte(Compiler, S_Op_AddBranch);
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeSourceRef(Branch->Name)));
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeOffset(0)));
S_EmitU32(Compiler, S_MakeConstant(Compiler, S_MakeSourceRef(Branch->Name)));
S_EmitU32(Compiler, S_MakeConstant(Compiler, S_MakeOffset(0)));
scene_value_chunk *Chunk = Compiler->LastValueChunk;
Branch->OffsetValue = &Chunk->Values[Chunk->Count-1];
}
@ -441,8 +418,8 @@ static void S_ParseBranchStatement(scene_compiler *Compiler)
S_EmitByte(Compiler, S_Op_JumpClose);
BaseOffset += 1;
BaseOffset += S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeOffset(BaseOffset)));
S_EmitU32(Compiler, S_MakeConstant(Compiler, S_MakeOffset(BaseOffset)));
BaseOffset += 4;
scene_value_chunk *Chunk = Compiler->LastValueChunk;
Branch->EndOffsetValue = &Chunk->Values[Chunk->Count-1];
@ -451,7 +428,8 @@ static void S_ParseBranchStatement(scene_compiler *Compiler)
//- sixten: patch the last jump
for(scene_branch_case *Branch = FirstBranch; Branch != 0; Branch = Branch->Next)
{
Branch->EndOffsetValue->Offset = BaseOffset-Branch->EndOffsetValue->Offset;
// sixten(NOTE): This little line here feels rather sketchy, it may one day fail on us.
Branch->EndOffsetValue->Offset = BaseOffset-Branch->EndOffsetValue->Offset-4;
}
ReleaseScratch(Scratch);
@ -511,6 +489,11 @@ static void S_ParseNumber(scene_compiler *Compiler, b32 CanAssign)
S_EmitConstant(Compiler, S_MakeNumber(Value));
}
static void S_ParseString(scene_compiler *Compiler, b32 CanAssign)
{
S_EmitConstant(Compiler, S_MakeSourceRef(Compiler->At[-1]));
}
static void S_ParseGrouping(scene_compiler *Compiler, b32 CanAssign)
{
S_ParseExpression(Compiler);
@ -581,105 +564,6 @@ static void S_ParsePrecedence(scene_compiler *Compiler, scene_precedence Precede
}
}
static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_bytecode_chunk *Chunk, memory_arena *Arena)
{
string_list List = {};
temporary_memory Scratch = GetScratch(&Arena, 1);
u8 *ChunkBegin = Chunk->Data;
u8 *ChunkEnd = ChunkBegin + Chunk->Count;
for(u8 *Data = ChunkBegin; Data < ChunkEnd;)
{
switch(*Data)
{
case S_Op_Constant:
{
Data += 1;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
scene_value Value = Compiler->FirstValueChunk->Values[VariableRead.Value];
AppendString(&List, StrLit("Constant: "), Scratch.Arena);
switch(Value.Kind)
{
case S_ValueKind_Number: { AppendString(&List, PushFormat(Scratch.Arena, "%f (number)\n", Value.Number), Scratch.Arena); } break;
case S_ValueKind_Boolean: { AppendString(&List, PushFormat(Scratch.Arena, "%b (boolean)\n", Value.Boolean), Scratch.Arena); } break;
case S_ValueKind_Pointer: { AppendString(&List, PushFormat(Scratch.Arena, "%x (pointer)\n", Value.Pointer), Scratch.Arena); } break;
}
} break;
case S_Op_Nil: { AppendString(&List, StrLit("Nil\n"), Scratch.Arena); Data += 1; } break;
case S_Op_True: { AppendString(&List, StrLit("True\n"), Scratch.Arena); Data += 1; } break;
case S_Op_False: { AppendString(&List, StrLit("False\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Negate: { AppendString(&List, StrLit("Negate\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Not: { AppendString(&List, StrLit("Not\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Add: { AppendString(&List, StrLit("Add\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Subtract: { AppendString(&List, StrLit("Subtract\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Multiply: { AppendString(&List, StrLit("Multiply\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Divide: { AppendString(&List, StrLit("Divide\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Equal: { AppendString(&List, StrLit("Equal\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Greater: { AppendString(&List, StrLit("Greater\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Less: { AppendString(&List, StrLit("Less\n"), Scratch.Arena); Data += 1; } break;
case S_Op_DefineGlobal:
{
Data += 1;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
u64 Pointer = Compiler->FirstValueChunk->Values[VariableRead.Value].Pointer;
token *Token = (token *)Pointer;
string String = T_StringFromToken(Compiler->Text, *Token);
AppendString(&List, StrLit("Define Global: "), Scratch.Arena);
AppendString(&List, String, Scratch.Arena);
AppendString(&List, StrLit("\n"), Scratch.Arena);
} break;
case S_Op_GetGlobal:
{
Data += 1;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
u64 Pointer = Compiler->FirstValueChunk->Values[VariableRead.Value].Pointer;
token *Token = (token *)Pointer;
string String = T_StringFromToken(Compiler->Text, *Token);
AppendString(&List, PushFormat(Scratch.Arena, "Get Global: %S\n", String), Scratch.Arena);
} break;
case S_Op_SetGlobal:
{
Data += 1;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
u64 Pointer = Compiler->FirstValueChunk->Values[VariableRead.Value].Pointer;
token *Token = (token *)Pointer;
string String = T_StringFromToken(Compiler->Text, *Token);
AppendString(&List, PushFormat(Scratch.Arena, "Set Global: %S\n", String), Scratch.Arena);
} break;
case S_Op_AwaitInput: { AppendString(&List, StrLit("Await Input\n"), Scratch.Arena); } break;
default:
{
if(*Data & S_Op_LineEntry)
{
Data += 1;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
u64 Pointer = Compiler->FirstValueChunk->Values[VariableRead.Value].Pointer;
token *Token = (token *)Pointer;
string String = Substring(Compiler->Text, Pad(Token->Range, -1));
AppendString(&List, PushFormat(Scratch.Arena, "Line Entry: %S\n", String), Scratch.Arena);
}
else
{
AppendString(&List, StrLit("Unknown Op\n"), Scratch.Arena);
Data += 1;
}
} break;
}
}
string Result = JoinStringList(&List, Arena);
ReleaseScratch(Scratch);
return(Result);
}
struct proc_from_chunks_result
{
scene_proc *Proc;
@ -696,11 +580,11 @@ static proc_from_chunks_result S_ProcFromChunks(memory_arena *Arena, scene_annot
scene_annotated_bytecode_chunk *NextChunk = 0;
{
scene_annotated_bytecode_chunk *Chunk = First;
for(; Chunk != 0 && AreEqual(Chunk->Name, ChunkName); Chunk = Chunk->Next)
for(;Chunk != 0 && AreEqual(Chunk->Name, ChunkName); Chunk = Chunk->Next)
{
RequiredBytes += Chunk->Count;
}
NextChunk= Chunk;
NextChunk = Chunk;
}
scene_proc *Proc = PushStruct(Arena, scene_proc);
@ -838,7 +722,7 @@ static compiled_scene S_CopyCompiledScene(memory_arena *Arena, compiled_scene *C
//- sixten: copy the source
Result.Source = PushString(Arena, Compiled->Source);
Result.IsValid = true;//Compiled->IsValid;
Result.IsValid = true;//Compiled->IsValid; sixten(TODO): I don't know why this is commented out.
return(Result);
}
@ -880,6 +764,36 @@ static scene_proc *S_FindProcByName(compiled_scene *Compiled, string Name)
return(Result);
}
static void S_PushStack(scene_runtime *Runtime, scene_value Value)
{
scene_runtime_stack *Stack = &Runtime->Stack;
if(Stack->Count < ArrayCount(Stack->Stack))
{
Stack->Stack[Stack->Count] = Value;
Stack->Count += 1;
}
else
{
S_RuntimeError(Runtime, StrLit("Stack overflow"));
}
}
static scene_value S_PopStack(scene_runtime *Runtime)
{
scene_value Result = {};
scene_runtime_stack *Stack = &Runtime->Stack;
if(Stack->Count > 0)
{
Stack->Count -= 1;
Result = Stack->Stack[Stack->Count];
}
else
{
S_RuntimeError(Runtime, StrLit("Stack underflow"));
}
return(Result);
}
static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameArena, b32 AdvanceOnAwait)
{
scene_runtime_result Result = {};
@ -893,6 +807,10 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
Runtime->CurrentProc = S_FindProcByName(Compiled, StrLit("main"));
}
// sixten(NOTE): This will only work on little endian architectures.
#define S_ReadU32() (Runtime->IP += 4, *(u32 *)(Data+Runtime->IP-4))
#define S_ReadValue() Compiled->Values[S_ReadU32()]
if(Runtime->CurrentProc)
{
if(Runtime->IP < Runtime->CurrentProc->Count)
@ -901,12 +819,80 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
switch(Data[Runtime->IP])
{
case S_Op_Constant:
{
Runtime->IP += 1;
S_PushStack(Runtime, S_ReadValue());
} break;
case S_Op_Pop:
{
Runtime->IP += 1;
S_PopStack(Runtime);
} break;
case S_Op_Nil:
{
Runtime->IP += 1;
S_PushStack(Runtime, S_MakeNil());
} break;
case S_Op_True:
{
Runtime->IP += 1;
S_PushStack(Runtime, S_MakeBoolean(true));
} break;
case S_Op_False:
{
Runtime->IP += 1;
S_PushStack(Runtime, S_MakeBoolean(false));
} break;
case S_Op_Add:
{
Runtime->IP += 1;
scene_value Value1 = S_PopStack(Runtime);
scene_value Value2 = S_PopStack(Runtime);
if(Value1.Kind == S_ValueKind_Number && Value2.Kind == S_ValueKind_Number)
{
S_PushStack(Runtime, S_MakeNumber(Value1.Number + Value2.Number));
}
else if(Value1.Kind == S_ValueKind_String && Value2.Kind == S_ValueKind_String)
{
S_RuntimeError(Runtime, StrLit("String concatination is not yet supported."));
}
else
{
S_RuntimeError(Runtime, StrLit("This operation is not supported."));
}
} break;
case S_Op_Subtract:
{
Runtime->IP += 1;
scene_value Value1 = S_PopStack(Runtime);
scene_value Value2 = S_PopStack(Runtime);
if(Value1.Kind == S_ValueKind_Number && Value2.Kind == S_ValueKind_Number)
{
S_PushStack(Runtime, S_MakeNumber(Value1.Number - Value2.Number));
}
else
{
S_RuntimeError(Runtime, StrLit("This operation is not supported."));
}
} break;
case S_Op_Multiply:
case S_Op_Divide:
{
S_RuntimeError(Runtime, StrLit("This operation is not supported."));
} break;
case S_Op_Jump:
{
Runtime->IP += 1;
scene_variable_read VariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
Runtime->IP += VariableRead.Size;
scene_value Value = Compiled->Values[VariableRead.Value];
scene_value Value = S_ReadValue();
if(Value.Kind == S_ValueKind_SourceRef)
{
string JumpDest = Substring(Compiled->Source, Value.SourceRef);
@ -930,8 +916,7 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
case S_Op_JumpClose:
{
Runtime->IP += 1;
scene_variable_read OffsetVariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
scene_value OffsetValue = Compiled->Values[OffsetVariableRead.Value];
scene_value OffsetValue = S_ReadValue();
if(OffsetValue.Kind == S_ValueKind_Offset)
{
Runtime->IP += OffsetValue.Offset;
@ -945,14 +930,10 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
case S_Op_AddBranch:
{
Runtime->IP += 1;
scene_variable_read BranchVariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
scene_value BranchName = Compiled->Values[BranchVariableRead.Value];
Runtime->IP += BranchVariableRead.Size;
scene_value BranchName = S_ReadValue();
if(BranchName.Kind == S_ValueKind_SourceRef)
{
scene_variable_read OffsetVariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
scene_value Offset = Compiled->Values[OffsetVariableRead.Value];
Runtime->IP += OffsetVariableRead.Size;
scene_value Offset = S_ReadValue();
if(Offset.Kind == S_ValueKind_Offset)
{
branch_case *Branch = &Runtime->Branches[Runtime->BranchCount];
@ -997,9 +978,8 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
}
Runtime->IP += 1;
scene_variable_read VariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
Runtime->IP += VariableRead.Size;
scene_value Value = Compiled->Values[VariableRead.Value];
scene_value Value = S_PopStack(Runtime);
if(Value.Kind == S_ValueKind_SourceRef)
{
Action->String = Substring(Compiled->Source, Pad(Value.SourceRef, -1));

View File

@ -37,6 +37,7 @@ enum scene_opcode
S_Op_Invalid = 0,
S_Op_Constant,
S_Op_Pop,
S_Op_Nil,
S_Op_True,
@ -92,10 +93,12 @@ struct scene_annotated_bytecode_bucket
enum scene_value_kind
{
S_ValueKind_Nil = 0,
S_ValueKind_Number,
S_ValueKind_Boolean,
S_ValueKind_Pointer,
S_ValueKind_SourceRef,
S_ValueKind_String,
S_ValueKind_Offset,
};
@ -119,12 +122,6 @@ struct scene_value_chunk
scene_value Values[512];
};
struct scene_variable_read
{
u64 Value;
s64 Size;
};
enum scene_precedence
{
S_Precedence_None,
@ -172,6 +169,20 @@ struct scene_branch_case
scene_value *EndOffsetValue;
};
struct scene_character
{
string Name;
scene_character *Next;
scene_character *Prev;
};
struct scene_character_bucket
{
scene_character *First;
scene_character *Last;
s64 Count;
};
struct scene_compiler
{
memory_arena *Arena;
@ -259,6 +270,12 @@ struct branch_case
s64 Offset;
};
struct scene_runtime_stack
{
scene_value Stack[128];
s32 Count;
};
struct scene_runtime
{
compiled_scene Compiled;
@ -266,6 +283,8 @@ struct scene_runtime
// sixten: runtime state
scene_proc *CurrentProc;
s64 IP;
memory_arena *Arena;
scene_runtime_stack Stack;
// sixten: errors
memory_arena *ErrorArena;
@ -287,6 +306,13 @@ struct scene_runtime
//~ sixten: Scene Compiler Functions
//- sixten: value helpers
inline scene_value S_MakeNil(void)
{
scene_value Result;
Result.Kind = S_ValueKind_Nil;
return(Result);
}
inline scene_value S_MakeNumber(r64 Value)
{
scene_value Result;
@ -332,10 +358,9 @@ static void S_ParseError(scene_compiler *Compiler, char *Message, s64 TokenOffse
//- sixten: bytecode helpers
static void S_EmitByte(scene_compiler *Compiler, u8 Byte);
static void S_EmitU32(scene_compiler *Compiler, u32 Value);
static void S_EmitBucket(scene_compiler *Compiler, scene_annotated_bytecode_bucket *Bucket);
static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value);
static s64 S_EmitVariableLength(scene_compiler *Compiler, u64 Value);
static scene_variable_read S_ReadVariableLength(u8 *Byte);
static void S_EmitConstant(scene_compiler *Compiler, scene_value Value);
static void S_SetEmissionTarget(scene_compiler *Compiler, scene_emission_target Target);
static void S_PushEmissionTarget(scene_compiler *Compiler, scene_emission_target Target);
@ -382,6 +407,7 @@ static void S_ParseStatement(scene_compiler *Compiler);
static void S_ParseExpression(scene_compiler *Compiler);
static void S_ParseLiteral(scene_compiler *Compiler, b32 CanAssign);
static void S_ParseNumber(scene_compiler *Compiler, b32 CanAssign);
static void S_ParseString(scene_compiler *Compiler, b32 CanAssign);
static void S_ParseGrouping(scene_compiler *Compiler, b32 CanAssign);
static void S_ParseUnary(scene_compiler *Compiler, b32 CanAssign);
static void S_ParseBinary(scene_compiler *Compiler, b32 CanAssign);

View File

@ -19,6 +19,8 @@ static void SV_SetCurrentSource(compiled_scene *Compiled)
ArenaClear(SceneView->SceneArena);
SceneView->Runtime.Compiled = S_CopyCompiledScene(SceneView->SceneArena, Compiled);
SceneView->Runtime.IP = 0;
SceneView->Runtime.Stack.Count = 0;
SceneView->Runtime.BranchCount = 0;
}
static void SV_Init(scene_view *SceneView, memory_arena *TextboxArena)
@ -132,7 +134,7 @@ UI_CUSTOM_DRAW_CALLBACK(BuildSceneTextboxDrawCallback)
r32 CharsRevealed = Textbox->CharsRevealed;
r32 GlobalScale = CalculateGlobalScaleFromRootBox(TextboxData->SceneViewBox);
text_properties Properties = {};
Properties.Font = Font_Japanese;
Properties.Font = Font_Fancy;
Properties.FontSize = GlobalScale;
Properties.LineHeight = GlobalScale*1.5f;
r32 Padding = 1.5f*GlobalScale;
@ -287,7 +289,7 @@ static void SV_Update(memory_arena *FrameArena, vn_input *Input)
}
}
}
r32 CharsPerSecond = 15.0f;//35.0f;
r32 CharsPerSecond = 10.0f;//35.0f;
Textbox->CharsRevealed += Input->dtForFrame*CharsPerSecond;
Textbox->CharsRevealed = Min(Textbox->CharsRevealed, (r32)Textbox->String.Count);

View File

@ -175,6 +175,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Text, toke
else if(AreEqual(String, StrLit("true"))) { TokenKind = TokenKind_True; }
else if(AreEqual(String, StrLit("var"))) { TokenKind = TokenKind_Var; }
else if(AreEqual(String, StrLit("while"))) { TokenKind = TokenKind_While; }
else if(AreEqual(String, StrLit("define"))) { TokenKind = TokenKind_Define; }
}
//- sixten: numerics

View File

@ -55,6 +55,7 @@ enum token_kind
TokenKind_True,
TokenKind_Var,
TokenKind_While,
TokenKind_Define,
TokenKind_KeywordsEnd,
// sixten: whitespace

View File

@ -202,6 +202,7 @@ static ui_signal UI_Scrollbar(axis2 Axis, string Name, r32 Size, r32 Offset)
UI_Spacer(UI_Pixels(Offset, 1));
UI_SetNextCornerRadius(4.0f);
UI_SetNextAxisSize(Axis, UI_Pixels(Size, 1));
UI_SetNextAxisSize(Opposite(Axis), UI_Percent(1, 1));
@ -224,7 +225,6 @@ static ui_signal UI_Scrollbar(axis2 Axis, string Name, r32 Size, r32 Offset)
static void UI_ScrollBegin(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
{
b32 AllowOnX = (X != 0);
b32 AllowOnY = (Y != 0);
@ -308,7 +308,7 @@ static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
UI_Column()
{
r32 TotalHeight = UI_CalculateBoxSize(ScrollableBox, Axis2_Y);
r32 ViewHeight = UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_Y);
r32 ViewHeight = DimOfRange(ScrollableBox->Parent->Parent->Rect).y;//UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_Y);
if(ViewHeight / TotalHeight < 1)
{

View File

@ -1,6 +1,7 @@
#include "vn_workspace_view.cpp"
#include "vn_workspace_editor.cpp"
#include "vn_workspace_text_editor.cpp"
#include "vn_workspace_character_editor.cpp"
#include "vn_workspace_commands.cpp"
//- sixten: State management
@ -254,6 +255,11 @@ static void W_BuildToolbar()
W_CreateNewView(W_View_SceneView, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(W_BuildMenuItem(FontIcon_User, "Character Editor", "").Clicked)
{
W_CreateNewView(W_View_CharacterEditor, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(W_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked)
{
W_CreateNewView(W_View_Settings, CurrentPanel);
@ -767,9 +773,15 @@ static void W_Init(workspace *Workspace)
W_CreateNewView(W_View_Startup, Workspace->RootPanel);
}
W_CreateNewView(W_View_TextEditor, Workspace->RootPanel);
W_SplitPanel(Workspace->RootPanel, Axis2_X);
W_CreateNewView(W_View_SceneView, Workspace->RootPanel->Last);
// sixten: build text editor / scene view layout
if(0)
{
W_CreateNewView(W_View_TextEditor, Workspace->RootPanel);
W_SplitPanel(Workspace->RootPanel, Axis2_X);
W_CreateNewView(W_View_SceneView, Workspace->RootPanel->Last);
}
W_CreateNewView(W_View_CharacterEditor, Workspace->RootPanel);
}
static void W_Update(workspace *Workspace, vn_render_commands *RenderCommands,

View File

@ -100,6 +100,7 @@ struct workspace
#include "vn_workspace_editor.h"
#include "vn_workspace_text_editor.h"
#include "vn_workspace_character_editor.h"
#include "vn_workspace_view.h"
////////////////////////////////

View File

@ -0,0 +1,100 @@
////////////////////////////////
//~ sixten: Workspace Character Editor Functions
static character_editor_entry_data *W_AllocateCharacterEntryData(workspace_view_character_editor *Editor, memory_arena *Arena)
{
character_editor_entry_data *Result = Editor->FreeList.First;
if(!Result)
{
Result = PushStructNoClear(Arena, character_editor_entry_data);
}
*Result = {};
return(Result);
}
static void W_BuildCharacterEditorView(workspace_view *View)
{
workspace_view_character_editor *Editor = (workspace_view_character_editor *)View->Data;
//- sixten: check that the entry list is filled out
if(DLLIsEmpty(Editor->List.First))
{
character_list Characters = CR_GetCharacters();
for(character_entry *Character = Characters.First; Character != 0; Character = Character->Next)
{
character_editor_entry_data *Data = W_AllocateCharacterEntryData(Editor, View->Arena);
Data->Entry = Character;
DLLInsertLast(Editor->List.First, Editor->List.Last, Data);
}
}
UI_WidthFill UI_HeightFill UI_Row() UI_Padding(UI_Em(5, 1)) UI_Column()
{
UI_Spacer(UI_Em(2, 1));
// sixten: build character lister
{
UI_SetNextWidth(UI_Percent(1, 1));
UI_SetNextHeight(UI_Percent(1, 0));
UI_Scroll(0, &Editor->ScrollT)
{
UI_Height(UI_Em(2.0f, 1)) UI_CornerRadius(4.0f)
for(character_editor_entry_data *Data = Editor->List.First; Data != 0; Data = Data->Next)
{
character_entry *Entry = Data->Entry;
if(UI_ButtonF("%S", Entry->Name).Clicked)
{
Data->IsOpen = !Data->IsOpen;
}
AC_AnimateValueDirect(Data->IsOpen, 0.3f, &Data->OpenTransition);
if(Data->OpenTransition > 0.1f)
{
UI_SetNextHeight(UI_ChildrenSum(Data->OpenTransition, 1));
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder |
UI_BoxFlag_DrawDropShadow |
UI_BoxFlag_Clip,
StrLit("")))
{
UI_LabelF("hello");
UI_LabelF("line");
UI_LabelF("paint");
UI_LabelF("color");
UI_LabelF("design");
UI_LabelF("address");
UI_LabelF("brightness");
}
}
}
}
}
// sixten: build bottom controls
UI_Spacer(UI_Em(1.5, 1));
UI_Height(UI_Em(2, 1)) UI_Row()
{
UI_Width(UI_TextContent(15, 1)) UI_CornerRadius(4)
{
UI_SetNextFont(Font_Icons);
ui_signal AddSignal = UI_ButtonF("%U", FontIcon_UserPlus);
if(AddSignal.Hovering)
{
UI_TooltipLabel(StrLit("Add new character"), UI_MouseP());
}
UI_Spacer(UI_Em(0.5, 1));
UI_SetNextFont(Font_Icons);
ui_signal RemoveSignal = UI_ButtonF("%U", FontIcon_UserTimes);
if(RemoveSignal.Hovering)
{
UI_TooltipLabel(StrLit("Delete selected character"), UI_MouseP());
}
}
}
UI_Spacer(UI_Em(1.5, 1));
}
}

View File

@ -0,0 +1,40 @@
/* date = August 27th 2023 3:38 pm */
#ifndef VN_WORKSPACE_CHARACTER_EDITOR_H
#define VN_WORKSPACE_CHARACTER_EDITOR_H
////////////////////////////////
//~ sixten: Workspace Character Editor Types
struct character_editor_entry_data
{
//- sixten: node links
character_editor_entry_data *Next;
character_editor_entry_data *Prev;
//- sixten: contents
struct character_entry *Entry;
b32 IsOpen;
r32 OpenTransition;
};
struct character_editor_processed_entry_list
{
character_editor_entry_data *First;
character_editor_entry_data *Last;
};
struct workspace_view_character_editor
{
character_editor_processed_entry_list List;
character_editor_processed_entry_list FreeList;
r32 ScrollT;
};
////////////////////////////////
//~ sixten: Workspace Character Editor Functions
static void W_BuildCharacterEditorView(workspace_view *View);
#endif //VN_WORKSPACE_CHARACTER_EDITOR_H

View File

@ -41,6 +41,13 @@ inline workspace_view *W_CreateNewView(workspace_view_type Type, workspace_panel
Editor->Tokens = TextData.Tokens;
Editor->Lines = TextData.Lines;
} break;
case W_View_CharacterEditor:
{
View->Data = PushStruct(View->Arena, workspace_view_character_editor);
} break;
default: break;
}
DLLInsertLast(Parent->FirstView, Parent->LastView, View);
@ -64,6 +71,8 @@ inline void W_DestroyView(workspace_view *View)
MutableStringRelease(&Editor->Text);
ArenaRelease(Editor->HistoryArena);
} break;
default: break;
}
// sixten(NOTE): This function does not ensure that the view is not being used anywhere else.
@ -107,6 +116,8 @@ inline string W_GetViewName(workspace_view *View)
}
} break;
case W_View_SceneView: { Result = StrLit("Scene View"); } break;
case W_View_CommandPalette: { Result = StrLit("Command Palette"); } break;
case W_View_CharacterEditor: { Result = StrLit("Character Editor"); } break;
}
return(Result);
@ -458,8 +469,8 @@ static void W_BuildSettings(workspace_view *View)
{
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("General");
char *Alternatives[] = {"60 Hz", "120 Hz", "144 Hz", "Uncapped", "V-Sync"};
s64 AlternativeMapping[] = {60, 120, 144, -1, 0};
char *Alternatives[] = {"15 Hz", "30 Hz", "60 Hz", "120 Hz", "144 Hz", "Uncapped", "V-Sync"};
s64 AlternativeMapping[] = {15, 30, 60, 120, 144, -1, 0};
s32 DropdownSelected;
FindIndexOfElement(DropdownSelected, AlternativeMapping, 0, Workspace->Input->RefreshRate);
@ -537,42 +548,55 @@ static void W_BuildView(workspace_view *View)
UI_Parent(ViewBox)
UI_Size(UI_Percent(1, 0), UI_Percent(1, 0))
{
if(View->Type == W_View_Startup)
switch(View->Type)
{
UI_Row() UI_Padding(UI_Pixels(50, 0))
UI_Width(UI_ChildrenSum(1, 1)) UI_Column() UI_Padding(UI_Pixels(50, 0))
case W_View_Startup:
{
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
UI_Row() UI_Padding(UI_Pixels(50, 0))
UI_Width(UI_ChildrenSum(1, 1)) UI_Column() UI_Padding(UI_Pixels(50, 0))
{
UI_Font(Font_Bold) UI_FontSize(36)
UI_LabelF("Welcome to VN");
UI_TextColor(Theme_BorderColor) UI_LabelF("An impractical way to make a game");
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
{
UI_Font(Font_Bold) UI_FontSize(36)
UI_LabelF("Welcome to VN");
UI_TextColor(Theme_BorderColor) UI_LabelF("An impractical way to make a game");
UI_Spacer(UI_Percent(1, 0));
UI_Spacer(UI_Percent(1, 0));
UI_Checkbox(&DEBUG_DebugSettings->ShowWelcomeMessage, StrLit("Show this message on startup"));
UI_Checkbox(&DEBUG_DebugSettings->ShowWelcomeMessage, StrLit("Show this message on startup"));
}
}
}
}
else if(View->Type == W_View_CommandPalette)
{
W_BuildViewTypeLister(View);
}
else if(View->Type == W_View_Editor)
{
Workspace_BuildEditor(View);
}
else if(View->Type == W_View_Settings)
{
W_BuildSettings(View);
}
else if(View->Type == W_View_TextEditor)
{
W_BuildTextEditor(View);
}
else if(View->Type == W_View_SceneView)
{
W_BuildSceneView(View);
} break;
case W_View_CommandPalette:
{
W_BuildViewTypeLister(View);
} break;
case W_View_Editor:
{
Workspace_BuildEditor(View);
} break;
case W_View_Settings:
{
W_BuildSettings(View);
} break;
case W_View_TextEditor:
{
W_BuildTextEditor(View);
} break;
case W_View_SceneView:
{
W_BuildSceneView(View);
} break;
case W_View_CharacterEditor:
{
W_BuildCharacterEditorView(View);
} break;
}
}

View File

@ -26,6 +26,7 @@ enum workspace_view_type
W_View_Settings,
W_View_TextEditor,
W_View_SceneView,
W_View_CharacterEditor,
};
struct workspace_view_editor

Binary file not shown.

11
data/demo.vns 100644
View File

@ -0,0 +1,11 @@
proc main
{
"This is the editor";
"You can write text in here";
"If you want to add a branch, you use the branch keyword";
jump main; // to not hit the "end of proc" error
}

31
test 100644
View File

@ -0,0 +1,31 @@
proc main
{
"Hello!";
"This is a little text editor with syntax highlighting";
"Is it cool?" #noawait;
branch
{
"Yes"
{
"I know right?";
}
"No"
{
"Wow, no need to be a hater dude.";
"Seriously";
"...";
"Grow up";
}
}
"Oh, forgot to mention that it also supports unicode.";
"Which makes it able to use all langages that use left to right writing.";
"Assuming that the character system isn't too complex.";
"Мой домашний питомец";
"悠輝さんに渡すつもりです";
jump main;
}