Started animating characters

main
sixtenhugosson 2023-10-04 19:21:15 +02:00
parent 10c5793a1d
commit 6e93783b03
27 changed files with 550 additions and 218 deletions

View File

@ -33,6 +33,7 @@ typedef void opengl_GetTexLevelParameterfv(GLenum target, GLint level, GLenum pn
typedef void opengl_GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params);
typedef void opengl_GetTexParameterfv(GLenum target, GLenum pname, GLfloat *params);
typedef void opengl_GetTexParameteriv(GLenum target, GLenum pname, GLint *params);
typedef void opengl_GenerateMipmap(GLenum target);
typedef void opengl_Hint(GLenum target, GLenum mode);
typedef GLboolean opengl_IsTexture(GLuint texture);
typedef void opengl_LineWidth(GLfloat width);
@ -121,6 +122,7 @@ global opengl_GetTexLevelParameterfv *glGetTexLevelParameterfv = 0;
global opengl_GetTexLevelParameteriv *glGetTexLevelParameteriv = 0;
global opengl_GetTexParameterfv *glGetTexParameterfv = 0;
global opengl_GetTexParameteriv *glGetTexParameteriv = 0;
global opengl_GenerateMipmap *glGenerateMipmap = 0;
global opengl_Hint *glHint = 0;
global opengl_IsTexture *glIsTexture = 0;
global opengl_LineWidth *glLineWidth = 0;
@ -212,6 +214,7 @@ glGetTexLevelParameterfv = (opengl_GetTexLevelParameterfv *)OpenGL_LoadFunction(
glGetTexLevelParameteriv = (opengl_GetTexLevelParameteriv *)OpenGL_LoadFunction("glGetTexLevelParameteriv");
glGetTexParameterfv = (opengl_GetTexParameterfv *)OpenGL_LoadFunction("glGetTexParameterfv");
glGetTexParameteriv = (opengl_GetTexParameteriv *)OpenGL_LoadFunction("glGetTexParameteriv");
glGenerateMipmap = (opengl_GenerateMipmap *)OpenGL_LoadFunction("glGenerateMipmap");
glHint = (opengl_Hint *)OpenGL_LoadFunction("glHint");
glIsTexture = (opengl_IsTexture *)OpenGL_LoadFunction("glIsTexture");
glLineWidth = (opengl_LineWidth *)OpenGL_LoadFunction("glLineWidth");

View File

@ -0,0 +1,10 @@
static character_state CR_CharacterStateFromString(string String)
{
character_state Result = CR_State_Invalid;
if(0) {}
else if(AreEqual(String, StrLit("none"))) { Result = CR_State_None; }
else if(AreEqual(String, StrLit("normal"))) { Result = CR_State_Normal; }
else if(AreEqual(String, StrLit("happy"))) { Result = CR_State_Happy; }
return(Result);
}

View File

@ -0,0 +1,8 @@
enum character_state
{
CR_State_Invalid = 0,
CR_State_None,
CR_State_Normal,
CR_State_Happy,
};

View File

@ -36,6 +36,7 @@ OpenGLFunctions:
{GetTexLevelParameteriv `void` `GLenum target, GLint level, GLenum pname, GLint *params`}
{GetTexParameterfv `void` `GLenum target, GLenum pname, GLfloat *params`}
{GetTexParameteriv `void` `GLenum target, GLenum pname, GLint *params`}
{GenerateMipmap `void` `GLenum target` }
{Hint `void` `GLenum target, GLenum mode`}
{IsTexture `GLboolean` `GLuint texture`}
{LineWidth `void` `GLfloat width`}

View File

@ -98,9 +98,22 @@ static RENDER_ALLOCATE_TEXTURE(OpenGL_AllocateTexture)
glBindTexture(GL_TEXTURE_2D, Texture.ID);
glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, Dim.x, Dim.y, 0, InternalFormat, GL_UNSIGNED_BYTE, Data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, SwizzleMask);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if(GenerateMipmap)
{
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
render_handle Handle = OpenGL_GetHandleFromTexture(Texture);
return(Handle);
@ -631,7 +644,7 @@ static opengl_context OpenGL_SetupContext(vn_render_commands *RenderCommands, um
#endif
u32 WhiteData = 0xFFFFFFFF;
RenderCommands->WhiteTexture = OpenGL_AllocateTexture(V2S32(1, 1), Render_TextureFormat_RGBA8, &WhiteData);
RenderCommands->WhiteTexture = OpenGL_AllocateTexture(V2S32(1, 1), Render_TextureFormat_RGBA8, false, &WhiteData);
RenderCommands->AllocateTexture = OpenGL_AllocateTexture;
RenderCommands->FillRegion = OpenGL_FillRegion;

View File

@ -22,12 +22,12 @@ global debug_settings *DEBUG_DebugSettings = 0;
#include "vn_text_op.h"
#include "vn_ui.h"
#include "vn_ui_utils.h"
#include "vn_character.h"
#include "vn_scene.h"
#include "vn_scene_view.h"
#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"
@ -53,6 +53,7 @@ struct vn_state
ui UI;
workspace Workspace;
animation_curve_state AnimationCurveState;
b32 EditorMode;
character_registry CharacterRegistry;
render_handle BackgroundTexture;
@ -88,7 +89,7 @@ static render_handle CreateTextureFromPath(vn_render_commands *Commands, string
case 4: { TextureFormat = Render_TextureFormat_RGBA8; } break;
}
Result = Commands->AllocateTexture(V2S32(Width, Height), TextureFormat, TextureData);
Result = Commands->AllocateTexture(V2S32(Width, Height), TextureFormat, true, TextureData);
stbi_image_free(TextureData);
@ -98,7 +99,6 @@ static render_handle CreateTextureFromPath(vn_render_commands *Commands, string
return(Result);
}
VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
{
SetThreadContext(ThreadContext);
@ -137,20 +137,23 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
//- sixten: load startup scene
scene_view *SceneView = &State->SceneView;
SV_Init(SceneView, State->Arena);
temporary_memory Scratch = GetScratch();
string SceneInput = Platform_ReadEntireFile(Scratch.Arena, StrLit("data/character.vns"));
compiled_scene Scene = S_ScriptFromText(Scratch.Arena, SceneInput);
SV_SetCurrentSource(&Scene);
ReleaseScratch(Scratch);
SceneView->TestHappy = CreateTextureFromPath(RenderCommands, StrLit("data/characters/test_happy.png"));
SceneView->TestNormal = CreateTextureFromPath(RenderCommands, StrLit("data/characters/test_normal.png"));
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);
return;
}
#if VN_INTERNAL
@ -161,13 +164,18 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
ArenaClear(State->FrameArena);
AC_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP, State->GlyphAtlas);
SV_SetState(&State->SceneView);
SV_NewFrame(&State->SceneView, Input->EventList, Input->dtForFrame);
//- sixten: check for toggle between modes
if(Platform_KeyPress(Input->EventList, Key_Return, PlatformModifier_Ctrl))
{
State->EditorMode = !State->EditorMode;
}
//- sixten: build the ui
UI_BeginBuild(RenderCommands->RenderDim);
{
b32 EditorMode = false;
if(EditorMode)
if(State->EditorMode)
{
W_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
}
@ -180,7 +188,7 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
//- sixten: update the scene
SV_Update(State->FrameArena, Input);
SV_Update(State->FrameArena);
//- sixten: consume all remaining evetns
for(platform_event *Event = Input->EventList->First;

View File

@ -1,3 +1,5 @@
#include "generated/vn_character.meta.c"
global character_registry *Global_CharacterRegistry = 0;
////////////////////////////////

View File

@ -3,6 +3,8 @@
#ifndef VN_CHARACTER_H
#define VN_CHARACTER_H
#include "generated/vn_character.meta.h"
////////////////////////////////
//~ sixten: Character String Chunk Types
#define CHARACTER_STRING_CHUNK_DATA_SIZE (64 - sizeof(character_string_chunk *))
@ -21,7 +23,6 @@ struct character_string_list
s64 StringCount;
};
////////////////////////////////
//~ sixten: Character Registry Types
struct character_entry
@ -62,4 +63,9 @@ static character_list CR_GetCharacters(void);
static void CR_Init(void);
static character_entry *CR_EntryFromName(string Name);
////////////////////////////////
//~ sixten: Misc. Character Functions
static character_state CR_CharacterStateFromString(string Input);
static string CR_StringFromCharacterState(character_state State);
#endif //VN_CHARACTER_H

View File

@ -0,0 +1,26 @@
@table(TypedName, EnumName) character_states:
{
{ "none", None },
{ "normal", Normal },
{ "happy", Happy },
}
@table_gen
{
`enum character_state`;
`{`;
`CR_State_Invalid = 0,`
@expand(character_states s) `CR_State_$(s.EnumName),`
`};`;
}
@table_gen @c
{
`static character_state CR_CharacterStateFromString(string String)`;
`{`;
`character_state Result = CR_State_Invalid;`;
`if(0) {}`;
@expand(character_states s) `else if(AreEqual(String, StrLit("$(s.TypedName)")))$(=>40) { Result = CR_State_$(s.EnumName); }`;
`return(Result);`;
`}`;
}

View File

@ -115,7 +115,7 @@ static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
Atlas->Glyphs = PushArray(Atlas->Arena, glyph, Atlas->MaxGlyphCount);
Atlas->RenderCommands = RenderCommands;
Atlas->Texture = RenderCommands->AllocateTexture(V2S32(BitmapSize, BitmapSize), Render_TextureFormat_R8, 0);
Atlas->Texture = RenderCommands->AllocateTexture(V2S32(BitmapSize, BitmapSize), Render_TextureFormat_R8, false, 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"));

View File

@ -134,7 +134,7 @@ static platform_api Platform;
#include "vn_render.h"
#define RENDER_ALLOCATE_TEXTURE(name) render_handle name(v2_s32 Dim, render_texture_format Format, void *Data)
#define RENDER_ALLOCATE_TEXTURE(name) render_handle name(v2_s32 Dim, render_texture_format Format, b32 GenerateMipmap, void *Data)
typedef RENDER_ALLOCATE_TEXTURE(render_allocate_texture);
#define RENDER_FILL_REGION(name) void name(render_handle Handle, v2_s32 DestP, v2_s32 DestDim, void *Data)

View File

@ -112,42 +112,45 @@ static void PushTexturedQuad(render_group *Group,
{
vn_render_commands *Commands = Group->Commands;
render_command_instanced_quads *Command = (render_command_instanced_quads *)(Group->CurrentCommand + 1);
s32 TextureIndex;
if(!(Group->CurrentCommand && Group->CurrentCommand->Type == Render_Command_render_command_instanced_quads &&
(TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture)) != -1))
if(!AreEqual(Texture, EmptyRenderHandle()))
{
Command = PushCommand(Group, render_command_instanced_quads);
TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture);
Command->QuadBufferIndex = Commands->InstancedQuadCount;
}
//if(InRange(Clip, Dest.Min) || InRange(Clip, Dest.Max))
{
v2_s32 TextureSize = DimFromTexture(Texture);
v2_r32 TextureSizeReal = ConvertV2ToR32(TextureSize);
Source.Min /= TextureSizeReal;
Source.Max /= TextureSizeReal;
render_command_instanced_quads *Command = (render_command_instanced_quads *)(Group->CurrentCommand + 1);
s32 TextureIndex;
if(!(Group->CurrentCommand && Group->CurrentCommand->Type == Render_Command_render_command_instanced_quads &&
(TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture)) != -1))
{
Command = PushCommand(Group, render_command_instanced_quads);
TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture);
Command->QuadBufferIndex = Commands->InstancedQuadCount;
}
//if(InRange(Clip, Dest.Min) || InRange(Clip, Dest.Max))
{
v2_s32 TextureSize = DimFromTexture(Texture);
v2_r32 TextureSizeReal = ConvertV2ToR32(TextureSize);
Source.Min /= TextureSizeReal;
Source.Max /= TextureSizeReal;
#if 0
Dest.Min.x = Round(Dest.Min.x);
Dest.Min.y = Round(Dest.Min.y);
Dest.Min.x = Round(Dest.Min.x);
Dest.Min.y = Round(Dest.Min.y);
#endif
instanced_quad *Quad = Commands->InstancedQuadBase + Commands->InstancedQuadCount++;
Quad->Dest = Dest;
Quad->Source = Source;
Quad->TextureIndex = TextureIndex;
Quad->Color[0] = PackV4ToU32(Color00);
Quad->Color[1] = PackV4ToU32(Color01);
Quad->Color[2] = PackV4ToU32(Color10);
Quad->Color[3] = PackV4ToU32(Color11);
Quad->CornerRadius = CornerRadius;
Quad->EdgeSoftness = EdgeSoftness;
Quad->BorderThickness = BorderThickness;
Command->QuadCount += 1;
instanced_quad *Quad = Commands->InstancedQuadBase + Commands->InstancedQuadCount++;
Quad->Dest = Dest;
Quad->Source = Source;
Quad->TextureIndex = TextureIndex;
Quad->Color[0] = PackV4ToU32(Color00);
Quad->Color[1] = PackV4ToU32(Color01);
Quad->Color[2] = PackV4ToU32(Color10);
Quad->Color[3] = PackV4ToU32(Color11);
Quad->CornerRadius = CornerRadius;
Quad->EdgeSoftness = EdgeSoftness;
Quad->BorderThickness = BorderThickness;
Command->QuadCount += 1;
}
}
}
#else
@ -160,96 +163,99 @@ static void PushTexturedQuad(render_group *Group,
{
vn_render_commands *Commands = Group->Commands;
render_command_quads *Command = (render_command_quads *)(Group->CurrentCommand + 1);
s32 TextureIndex;
if(!(Group->CurrentCommand && Group->CurrentCommand->Type == Render_Command_render_command_quads &&
(TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture)) != -1))
if(!AreEqual(Texture, EmptyRenderHandle()))
{
Command = PushCommand(Group, render_command_quads);
Command->QuadBufferIndex = Commands->QuadIndexCount;
TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture);
}
range2_r32 Clip = Group->ClipStack[Group->ClipStackUsed];
v2 DestMin = Max(Dest.Min, Clip.Min);
v2 DestMax = Min(Dest.Max, Clip.Max);
// sixten(TODO): Proper aabb overlap testing here!
if(InRange(Clip, Dest.Min) || InRange(Clip, Dest.Max))
{
v2 HalfSize = DimOfRange(Dest)*0.5;
render_command_quads *Command = (render_command_quads *)(Group->CurrentCommand + 1);
s32 TextureIndex;
if(!(Group->CurrentCommand && Group->CurrentCommand->Type == Render_Command_render_command_quads &&
(TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture)) != -1))
{
Command = PushCommand(Group, render_command_quads);
Command->QuadBufferIndex = Commands->QuadIndexCount;
TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture);
}
v2 P00 = V2(DestMin.x, DestMin.y);
v2 P01 = V2(DestMin.x, DestMax.y);
v2 P10 = V2(DestMax.x, DestMin.y);
v2 P11 = V2(DestMax.x, DestMax.y);
v2 Center = (DestMin + DestMax)*0.5;
range2_r32 Clip = Group->ClipStack[Group->ClipStackUsed];
v2 TextureSize = V2(Texture.U32[2], Texture.U32[3]);
v2 DestMin = Max(Dest.Min, Clip.Min);
v2 DestMax = Min(Dest.Max, Clip.Max);
Source.Min /= TextureSize;
Source.Max /= TextureSize;
v2 Source00 = Source.Min;
v2 Source01 = V2(Source.Min.x, Source.Max.y);
v2 Source10 = V2(Source.Max.x, Source.Min.y);
v2 Source11 = Source.Max;;
s32 BaseVertex = Commands->QuadVertexCount;
quad_vertex *Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
Vertex->P = P00;
Vertex->SourceP = Source00;
Vertex->TextureIndex = TextureIndex;
Vertex->Color = PackV4ToU32(Color00);
Vertex->ToCenter = Center - P00;
Vertex->HalfSize = HalfSize;
Vertex->CornerRadius = CornerRadius;
Vertex->EdgeSoftness = EdgeSoftness;
Vertex->BorderThickness = BorderThickness;
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
Vertex->P = P10;
Vertex->SourceP = Source10;
Vertex->TextureIndex = TextureIndex;
Vertex->Color = PackV4ToU32(Color10);
Vertex->ToCenter = Center - P10;
Vertex->HalfSize = HalfSize;
Vertex->CornerRadius = CornerRadius;
Vertex->EdgeSoftness = EdgeSoftness;
Vertex->BorderThickness = BorderThickness;
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
Vertex->P = P01;
Vertex->SourceP = Source01;
Vertex->TextureIndex = TextureIndex;
Vertex->Color = PackV4ToU32(Color01);
Vertex->ToCenter = Center - P01;
Vertex->HalfSize = HalfSize;
Vertex->CornerRadius = CornerRadius;
Vertex->EdgeSoftness = EdgeSoftness;
Vertex->BorderThickness = BorderThickness;
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
Vertex->P = P11;
Vertex->SourceP = Source11;
Vertex->TextureIndex = TextureIndex;
Vertex->Color = PackV4ToU32(Color11);
Vertex->ToCenter = Center - P11;
Vertex->HalfSize = HalfSize;
Vertex->CornerRadius = CornerRadius;
Vertex->EdgeSoftness = EdgeSoftness;
Vertex->BorderThickness = BorderThickness;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 0;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 3;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 1;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 0;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 2;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 3;
++Command->QuadCount;
// sixten(TODO): Proper aabb overlap testing here!
if(InRange(Clip, Dest.Min) || InRange(Clip, Dest.Max))
{
v2 HalfSize = DimOfRange(Dest)*0.5;
v2 P00 = V2(DestMin.x, DestMin.y);
v2 P01 = V2(DestMin.x, DestMax.y);
v2 P10 = V2(DestMax.x, DestMin.y);
v2 P11 = V2(DestMax.x, DestMax.y);
v2 Center = (DestMin + DestMax)*0.5;
v2 TextureSize = V2(Texture.U32[2], Texture.U32[3]);
Source.Min /= TextureSize;
Source.Max /= TextureSize;
v2 Source00 = Source.Min;
v2 Source01 = V2(Source.Min.x, Source.Max.y);
v2 Source10 = V2(Source.Max.x, Source.Min.y);
v2 Source11 = Source.Max;;
s32 BaseVertex = Commands->QuadVertexCount;
quad_vertex *Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
Vertex->P = P00;
Vertex->SourceP = Source00;
Vertex->TextureIndex = TextureIndex;
Vertex->Color = PackV4ToU32(Color00);
Vertex->ToCenter = Center - P00;
Vertex->HalfSize = HalfSize;
Vertex->CornerRadius = CornerRadius;
Vertex->EdgeSoftness = EdgeSoftness;
Vertex->BorderThickness = BorderThickness;
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
Vertex->P = P10;
Vertex->SourceP = Source10;
Vertex->TextureIndex = TextureIndex;
Vertex->Color = PackV4ToU32(Color10);
Vertex->ToCenter = Center - P10;
Vertex->HalfSize = HalfSize;
Vertex->CornerRadius = CornerRadius;
Vertex->EdgeSoftness = EdgeSoftness;
Vertex->BorderThickness = BorderThickness;
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
Vertex->P = P01;
Vertex->SourceP = Source01;
Vertex->TextureIndex = TextureIndex;
Vertex->Color = PackV4ToU32(Color01);
Vertex->ToCenter = Center - P01;
Vertex->HalfSize = HalfSize;
Vertex->CornerRadius = CornerRadius;
Vertex->EdgeSoftness = EdgeSoftness;
Vertex->BorderThickness = BorderThickness;
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
Vertex->P = P11;
Vertex->SourceP = Source11;
Vertex->TextureIndex = TextureIndex;
Vertex->Color = PackV4ToU32(Color11);
Vertex->ToCenter = Center - P11;
Vertex->HalfSize = HalfSize;
Vertex->CornerRadius = CornerRadius;
Vertex->EdgeSoftness = EdgeSoftness;
Vertex->BorderThickness = BorderThickness;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 0;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 3;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 1;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 0;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 2;
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 3;
++Command->QuadCount;
}
}
}
#endif

View File

@ -233,28 +233,38 @@ static void S_ParseDeclaration(scene_compiler *Compiler)
case TokenKind_At:
{
Compiler->At += 1;
token IdentifierToken = S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected identifier after '@'");
S_EmitConstant(Compiler, S_MakeSourceRef(IdentifierToken));
if(Compiler->At->Kind == TokenKind_ParenthesisOpen)
{
Compiler->At += 1;
token StateToken = S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected character state.");
S_ConsumeToken(Compiler, TokenKind_ParenthesisClose, "Expected ')' after character state.");
S_EmitConstant(Compiler, S_MakeSourceRef(StateToken));
}
else
{
S_EmitConstant(Compiler, S_MakeNil());
}
S_EmitByte(Compiler, S_Op_ShowCharacter);
if(Compiler->At->Kind == TokenKind_Semicolon)
{
Compiler->At += 1;
}
} 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;
b32 EmitClear = true;
for(;Compiler->At[0].Kind == TokenKind_PoundSign;)
{
Compiler->At += 1;
@ -262,7 +272,7 @@ static void S_ParseDeclaration(scene_compiler *Compiler)
string TagString = T_StringFromToken(Compiler->Text, TagToken);
if(AreEqual(TagString, StrLit("noclear")))
{
Flags |= S_LineEntryFlag_NoClear;
EmitClear = false;
}
else if(AreEqual(TagString, StrLit("noawait")))
{
@ -274,6 +284,13 @@ static void S_ParseDeclaration(scene_compiler *Compiler)
}
}
if(EmitClear)
{
S_EmitByte(Compiler, S_Op_ClearDialog);
}
S_EmitByte(Compiler, S_Op_LineEntry);
if(EmitAwait)
{
S_EmitByte(Compiler, S_Op_AwaitInput);
@ -810,6 +827,33 @@ static scene_value S_PopStack(scene_runtime *Runtime)
return(Result);
}
static scene_value S_PopStackAndImplicitConvert(scene_runtime *Runtime)
{
scene_value Result = S_PopStack(Runtime);
if(Result.Kind == S_ValueKind_SourceRef)
{
Result.Kind = S_ValueKind_String;
Result.String = Substring(Runtime->Compiled.Source, Result.SourceRef);
}
return(Result);
}
static void S_ResetRuntime(scene_runtime *Runtime)
{
Runtime->IP = 0;
Runtime->CurrentProc = 0;
Runtime->BranchCount = 0;
if(Runtime->RuntimeArena)
{
ArenaClear(Runtime->RuntimeArena);
}
else
{
Runtime->RuntimeArena = ArenaAllocate(Megabytes(32));
}
}
static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameArena, b32 AdvanceOnAwait)
{
scene_runtime_result Result = {};
@ -818,6 +862,7 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
Assert(Runtime != 0);
Assert(Compiled->IsValid);
//- sixten: default to the main proc
if(Runtime->CurrentProc == 0)
{
Runtime->CurrentProc = S_FindProcByName(Compiled, StrLit("main"));
@ -827,6 +872,7 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
#define S_ReadU32() (Runtime->IP += 4, *(u32 *)(Data+Runtime->IP-4))
#define S_ReadValue() Compiled->Values[S_ReadU32()]
//- sixten: run the bytecode interpreter
if(Runtime->CurrentProc)
{
if(Runtime->IP < Runtime->CurrentProc->Count)
@ -868,8 +914,8 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
case S_Op_Add:
{
Runtime->IP += 1;
scene_value Value1 = S_PopStack(Runtime);
scene_value Value2 = S_PopStack(Runtime);
scene_value Value1 = S_PopStackAndImplicitConvert(Runtime);
scene_value Value2 = S_PopStackAndImplicitConvert(Runtime);
if(Value1.Kind == S_ValueKind_Number && Value2.Kind == S_ValueKind_Number)
{
S_PushStack(Runtime, S_MakeNumber(Value1.Number + Value2.Number));
@ -979,37 +1025,71 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameAre
Result.ReachedAwait = true;
} break;
default:
case S_Op_ClearDialog:
{
if(Data[Runtime->IP] & S_Op_LineEntry)
textbox_action *Action = PushStructNoClear(FrameArena, textbox_action);
Action->Kind = TextboxActionKind_Set;
Action->String = StrLit("");
QueuePush(Runtime->FirstTextboxAction, Runtime->LastTextboxAction, Action);
Runtime->IP += 1;
} break;
case S_Op_ShowCharacter:
{
Runtime->IP += 1;
scene_value State = S_PopStackAndImplicitConvert(Runtime);
scene_value CharacterValue = S_PopStackAndImplicitConvert(Runtime);
string Character = StrLit("");
if(CharacterValue.Kind == S_ValueKind_String)
{
textbox_action *Action = PushStructNoClear(FrameArena, textbox_action);
if(Data[Runtime->IP] & S_LineEntryFlag_NoClear)
{
Action->Kind = TextboxActionKind_Append;
}
else
{
Action->Kind = TextboxActionKind_Set;
}
Runtime->IP += 1;
scene_value Value = S_PopStack(Runtime);
if(Value.Kind == S_ValueKind_SourceRef)
{
Action->String = Substring(Compiled->Source, Pad(Value.SourceRef, -1));
QueuePush(Runtime->FirstTextboxAction, Runtime->LastTextboxAction, Action);
}
else
{
S_RuntimeErrorF(Runtime, "Incorrect value kind when retrieving line entry.");
}
Character = CharacterValue.String;
}
else
{
S_RuntimeErrorF(Runtime, "Unknown bytecode op: 0x%02x", Data[Runtime->IP]);
S_RuntimeErrorF(Runtime, "Incorrect value kind when retrieving character name.");
}
// sixten: create & apply character action
scene_character_action *Action = PushStruct(FrameArena, scene_character_action);
Action->Target = Character;
if(State.Kind == S_ValueKind_Nil)
{
Action->State = CR_State_None;
}
else
{
Action->State = CR_CharacterStateFromString(State.String);
}
DLLInsertLast(Runtime->FirstCharacterAction, Runtime->LastCharacterAction, Action);
} break;
case S_Op_LineEntry:
{
textbox_action *Action = PushStructNoClear(FrameArena, textbox_action);
Action->Kind = TextboxActionKind_Append;
Runtime->IP += 1;
scene_value Value = S_PopStack(Runtime);
if(Value.Kind == S_ValueKind_SourceRef)
{
Action->String = Substring(Compiled->Source, Pad(Value.SourceRef, -1));
QueuePush(Runtime->FirstTextboxAction, Runtime->LastTextboxAction, Action);
}
else
{
S_RuntimeErrorF(Runtime, "Incorrect value kind when retrieving line entry.");
}
} break;
default:
{
S_RuntimeErrorF(Runtime, "Unknown bytecode op: 0x%02x", Data[Runtime->IP]);
} break;
}
}

View File

@ -26,12 +26,6 @@ struct scene_compile_error_list
s64 Count;
};
typedef u64 scene_line_entry_flag;
enum
{
S_LineEntryFlag_NoClear = (1<<0),
};
enum scene_opcode
{
S_Op_Invalid = 0,
@ -65,10 +59,9 @@ enum scene_opcode
S_Op_Halt,
S_Op_AwaitInput,
S_Op_ClearDialog,
S_Op_LineEntry,
S_Op_ShowCharacter,
S_Op_LineEntry = 0x80, // sixten(NOTE): All opcoodes above are reserved.
};
struct scene_bytecode_chunk
@ -113,6 +106,7 @@ struct scene_value
b32 Boolean;
u64 Pointer;
range1_s64 SourceRef;
string String;
s64 Offset;
};
};
@ -171,18 +165,13 @@ struct scene_branch_case
scene_value *EndOffsetValue;
};
struct scene_character
struct scene_character_action
{
string Name;
scene_character *Next;
scene_character *Prev;
};
struct scene_character_bucket
{
scene_character *First;
scene_character *Last;
s64 Count;
scene_character_action *Next;
scene_character_action *Prev;
string Target;
character_state State;
};
struct scene_compiler
@ -283,9 +272,9 @@ struct scene_runtime
compiled_scene Compiled;
// sixten: runtime state
memory_arena *RuntimeArena;
scene_proc *CurrentProc;
s64 IP;
memory_arena *Arena;
scene_runtime_stack Stack;
// sixten: errors
@ -300,6 +289,8 @@ struct scene_runtime
// sixten: result
textbox_action *FirstTextboxAction;
textbox_action *LastTextboxAction;
scene_character_action *FirstCharacterAction;
scene_character_action *LastCharacterAction;
branch_case *FirstBranchCase;
scene_runtime_result LastResult;
};
@ -425,6 +416,7 @@ static compiled_scene S_CopyCompiledScene(memory_arena *Arena, compiled_scene *C
////////////////////////////////
//~ sixten: Scene Runtime Functions
static scene_proc *S_FindProcByName(compiled_scene *Compiled, string Name);
static void S_ResetRuntime(scene_runtime *Runtime);
static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameArena, b32 AdvanceOnAwait);
#endif //VN_SCENE_H

View File

@ -10,6 +10,13 @@ static scene_view *SV_GetState()
return(ThreadLocal_SceneView);
}
static void SV_NewFrame(scene_view *View, platform_event_list *EventList, r32 dtForFrame)
{
SV_SetState(View);
View->EventList = EventList;
View->dtForFrame = dtForFrame;
}
static void SV_SetCurrentSource(compiled_scene *Compiled)
{
scene_view *SceneView = SV_GetState();
@ -18,9 +25,7 @@ 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;
S_ResetRuntime(&SceneView->Runtime);
}
static void SV_Init(scene_view *SceneView, memory_arena *TextboxArena)
@ -30,6 +35,8 @@ static void SV_Init(scene_view *SceneView, memory_arena *TextboxArena)
SceneView->SceneArena = ArenaAllocate(Gigabytes(1));
SceneView->Runtime.ErrorArena = ArenaAllocate(Megabytes(1));
S_ResetRuntime(&SceneView->Runtime);
SceneView->Textbox.Capacity = 4096;
SceneView->Textbox.String.Data = PushArray(TextboxArena, u8, SceneView->Textbox.Capacity);
SceneView->Textbox.String.Count = 0;
@ -89,7 +96,7 @@ static void RenderAnimatedText(render_group *Group, glyph_atlas *Atlas, text_pro
WordBegin = TrueWordEnd;
if(Byte==TextEnd || CharsToRender < 1)
if(Byte == TextEnd || CharsToRender < 1)
{
break;
}
@ -105,6 +112,12 @@ static void RenderAnimatedText(render_group *Group, glyph_atlas *Atlas, text_pro
}
}
static r32 CalculateGlobalScaleFromDim(v2_r32 Dim)
{
r32 GlobalScale = SquareRoot(Dim.x*Dim.y)/45;
return(GlobalScale);
}
static r32 CalculateGlobalScaleFromRootBox(ui_box *Box)
{
v2 RenderDim = DimOfRange(Box->Rect);
@ -142,36 +155,47 @@ UI_CUSTOM_DRAW_CALLBACK(BuildSceneTextboxDrawCallback)
RenderAnimatedText(Group, Atlas, Properties, Text, CharsRevealed, Box->Rect.Min+Offset, DimOfRange(Box->Rect).x-2*Padding);
}
// sixten(NOTE): This is most likely temporarary and just contains all the data required to render the scene.
struct scene_render_data
{
render_handle BackgroundTexture;
scene_runtime *Runtime;
};
UI_CUSTOM_DRAW_CALLBACK(BuildSceneDrawCallback)
{
scene_render_data *RenderData = (scene_render_data *)Data;
scene_view *SceneView = (scene_view *)Data;
v2 RenderDim = DimOfRange(Box->Rect);
r32 GlobalScale = CalculateGlobalScaleFromDim(RenderDim);
//- sixten: render background
// sixten(TODO, but soon): Currently we add Box->Rect.Min to everything, but that should really be a transform
// on the render group.
v2 RenderDim = DimOfRange(Box->Rect);
range2_r32 Dest = Range2R32(Box->Rect.Min, RenderDim+Box->Rect.Min);
range2_r32 Source = Range2R32(V2R32(0, 0), ConvertV2ToR32(DimFromTexture(RenderData->BackgroundTexture)));
PushTexturedQuad(Group, Dest, Source, Color_White, Color_White, Color_White, Color_White, 0, 0, 0, RenderData->BackgroundTexture);
range2_r32 BackgroundDest = Range2R32(Box->Rect.Min, RenderDim+Box->Rect.Min);
range2_r32 BackgroundSource = Range2R32(V2R32(0, 0), ConvertV2ToR32(DimFromTexture(SceneView->BackgroundTexture)));
PushTexturedQuad(Group, BackgroundDest, BackgroundSource, Color_White, Color_White, Color_White, Color_White, 0, 0, 0, SceneView->BackgroundTexture);
//- sixten: render characters
for(s32 CharacterIndex = 0; CharacterIndex < SceneView->CharacterCount; CharacterIndex += 1)
{
scene_view_character_data *Character = SceneView->OnscreenCharacters + CharacterIndex;
v4_r32 BlendColor = LinearBlend(Color_White, Color_Black, 0.5-Character->TalkingT*0.5);
BlendColor.a = Character->ActiveT;
r32 Scale = (Character->TextureScale + Character->TalkingT*0.001)*(0.95+Character->ActiveT*0.05)*GlobalScale;
render_handle CharacterHandle = Character->Texture;
v2_r32 CharacterDim = ConvertV2ToR32(DimFromTexture(CharacterHandle));
v2_r32 CharacterOriginP = V2R32(RenderDim.x*Character->PctP, RenderDim.y);
v2_r32 CharacterMidP = V2R32(CharacterOriginP.x, CharacterOriginP.y - CharacterDim.y*Scale/2);
range2_r32 CharacterDest = Range2R32(CharacterMidP-CharacterDim*0.5f*Scale, CharacterMidP+CharacterDim*0.5f*Scale);
range2_r32 CharacterSource = Range2R32(V2R32(0, 0), CharacterDim);
PushTexturedQuad(Group, CharacterDest, CharacterSource, BlendColor, BlendColor, BlendColor, BlendColor, 0, 0, 0, CharacterHandle);
}
}
static void BuildScene(scene_runtime *Runtime, render_handle BackgroundTexture, textbox *Textbox)
static void BuildScene(scene_view *View)
{
scene_runtime *Runtime = &View->Runtime;
textbox *Textbox = &View->Textbox;
UI_SetNextWidth(UI_Percent(1, 0));
UI_SetNextHeight(UI_Percent(1, 0));
UI_SetNextLayoutAxis(Axis2_Y);
ui_box *Box = UI_MakeBox(0, StrLit("Scene View"));
scene_render_data *Data = PushStruct(UI_FrameArena(), scene_render_data);
Data->BackgroundTexture = BackgroundTexture;
Data->Runtime = Runtime;
UI_EquipBoxCustomDrawCallback(Box, BuildSceneDrawCallback, Data);
UI_EquipBoxCustomDrawCallback(Box, BuildSceneDrawCallback, View);
UI_Parent(Box)
{
@ -264,14 +288,90 @@ static void BuildErrorScreen(scene_runtime *Runtime, vn_input *Input)
}
}
static void SV_Update(memory_arena *FrameArena, vn_input *Input)
static scene_view_character_data *SV_CharacterDataFromName(string Name)
{
scene_view_character_data *Result = 0;
scene_view *View = SV_GetState();
for(s32 CharacterIndex = 0; CharacterIndex < View->CharacterCount; CharacterIndex += 1)
{
scene_view_character_data *Character = View->OnscreenCharacters + CharacterIndex;
if(AreEqual(Character->Name, Name))
{
Result = Character;
break;
}
}
//- sixten: create character if not initialized
if(!Result && View->CharacterCount < ArrayCount(View->OnscreenCharacters))
{
s32 CharacterIndex = View->CharacterCount;
View->CharacterCount += 1;
Result = View->OnscreenCharacters + CharacterIndex;
*Result = {};
Result->Name = Name;
Result->Active = true;
Result->PctP = (r32)(CharacterIndex + 1) / (View->CharacterCount + 1);
}
return(Result);
}
static render_handle SV_CharacterTextureFromAction(scene_character_action *Action)
{
render_handle Result = EmptyRenderHandle();
scene_view *View = SV_GetState();
if(AreEqual(StrLit("arthur"), Action->Target))
{
switch(Action->State)
{
case CR_State_Normal: { Result = View->TestNormal; } break;
case CR_State_Happy: { Result = View->TestHappy; } break;
default: break;
}
}
return(Result);
}
static void SV_Update(memory_arena *FrameArena)
{
scene_view *SceneView = SV_GetState();
textbox *Textbox = &SceneView->Textbox;
scene_runtime *Runtime = &SceneView->Runtime;
platform_event_list *EventList = Input->EventList;
platform_event_list *EventList = SceneView->EventList;
r32 dtForFrame = SceneView->dtForFrame;
compiled_scene *Compiled = &Runtime->Compiled;
//- sixten: update the characters
for(s32 CharacterIndex = 0; CharacterIndex < SceneView->CharacterCount; CharacterIndex += 1)
{
scene_view_character_data *Data = SceneView->OnscreenCharacters + CharacterIndex;
AC_AnimateValueDirect(Data->Active, 0.3f, &Data->ActiveT);
AC_AnimateValueDirect(Data->Talking, 0.3f, &Data->TalkingT);
r32 TargetPctP = (r32)(CharacterIndex+1)/(SceneView->CharacterCount+1);
AC_AnimateValueDirect(TargetPctP, 0.3f, &Data->PctP);
}
//- sixten: prune any unactive characters
for(s32 CharacterIndex = 0; CharacterIndex < SceneView->CharacterCount; CharacterIndex += 1)
{
scene_view_character_data *Data = SceneView->OnscreenCharacters + CharacterIndex;
if(!Data->Active && Data->ActiveT < 0.01)
{
Move(Data, Data+1, SceneView->CharacterCount-CharacterIndex-1);
SceneView->CharacterCount -= 1;
CharacterIndex -= 1;
}
}
if(Compiled && Compiled->IsValid)
{
b32 PlayerAction = (Platform_KeyPress(EventList, Key_Space)||Platform_KeyPress(EventList, Key_MouseLeft));
@ -289,8 +389,8 @@ static void SV_Update(memory_arena *FrameArena, vn_input *Input)
}
}
}
r32 CharsPerSecond = 10.0f;//35.0f;
Textbox->CharsRevealed += Input->dtForFrame*CharsPerSecond;
r32 CharsPerSecond = 35.0f;//10.0f;
Textbox->CharsRevealed += dtForFrame*CharsPerSecond;
Textbox->CharsRevealed = Min(Textbox->CharsRevealed, (r32)Textbox->String.Count);
if(Textbox->CharsRevealed < Textbox->String.Count && PlayerAction)
@ -322,6 +422,26 @@ static void SV_Update(memory_arena *FrameArena, vn_input *Input)
}
}
Runtime->FirstTextboxAction = Runtime->LastTextboxAction = 0;
//- sixten: apply character actions
for(scene_character_action *Action = Runtime->FirstCharacterAction; Action != 0; Action = Action->Next)
{
// sixten: find character
scene_view_character_data *Data = SV_CharacterDataFromName(Action->Target);
if(Action->State == CR_State_None)
{
Data->Active = false;
}
else
{
Data->Texture = SV_CharacterTextureFromAction(Action);
Data->TextureScale = 0.017f;
Data->Talking = true;
}
}
Runtime->FirstCharacterAction = Runtime->LastCharacterAction = 0;
}
}
@ -335,7 +455,24 @@ static void SV_BuildSceneView(vn_input *Input)
}
else if(SceneView->Runtime.Compiled.IsValid)
{
BuildScene(&SceneView->Runtime, SceneView->BackgroundTexture, &SceneView->Textbox);
BuildScene(SceneView);
#if 0
UI_Tooltip
{
UI_SetNextFixedP(V2R32(0, 0));
UI_SetNextSize(UI_ChildrenSum(1, 1), UI_ChildrenSum(1, 1));
UI_Column() UI_Size(UI_TextContent(15, 1), UI_TextContent(15, 1))
{
UI_Row()
{
UI_LabelF("Character Count: %i", SceneView->CharacterCount);
if(UI_ButtonF("+").Clicked) ++SceneView->CharacterCount;
if(UI_ButtonF("-").Clicked) --SceneView->CharacterCount;
}
}
}
#endif
}
else
{

View File

@ -10,19 +10,47 @@ struct textbox
r32 CharsRevealed;
};
struct scene_view_character_data
{
string Name;
b32 Active;
b32 Talking;
render_handle Texture;
r32 TextureScale;
r32 ActiveT;
r32 TalkingT;
r32 PctP;
};
struct scene_view
{
memory_arena *SceneArena;
// sixten: input
platform_event_list *EventList;
r32 dtForFrame;
scene_runtime Runtime;
textbox Textbox;
render_handle BackgroundTexture;
s32 TargetCharacter;
render_handle TestHappy;
render_handle TestNormal;
s32 CharacterCount;
scene_view_character_data OnscreenCharacters[16];
};
static void SV_SetState(scene_view *View);
static scene_view *SV_GetState();
static void SV_NewFrame(scene_view *View, platform_event_list *EventList, r32 dtForFrame);
static void SV_SetCurrentSource(compiled_scene *Compiled);
static void SV_Init(scene_view *View, memory_arena *TextboxArena);
static void SV_BuildSceneView(vn_input *Input);
static void SV_Update(memory_arena *FrameArena);
#endif //VN_SCENE_VIEW_H

View File

@ -1,6 +1,12 @@
proc main
{
@arthur(greeting) "Welcome to this fine estate!";
"One line test";
@arthur(normal) "Welcome to this fine estate!";
@arthur(happy) "I am pleased to see you.";
"An inbetweener if you were";
@arthur(none);
jump main; // return to start
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

6
weeks.txt 100644
View File

@ -0,0 +1,6 @@
[0] - Characters
[1] - Environments & Time
[2] - Map & Notebook
[3] - UI
[4] - Minigames
[5] - Rendering