inline b32 AreEqual(render_handle A, render_handle B) { b32 Result = false; if((A.U64[0] == B.U64[0]) && (A.U64[1] == B.U64[1]) && (A.U64[2] == B.U64[2]) && (A.U64[3] == B.U64[3])) { Result = true; } return(Result); } inline v2_s32 GetTextureDim(render_handle Handle) { v2_s32 Result = V2S32(Handle.U32[2], Handle.U32[3]); return(Result); } inline render_handle EmptyRenderHandle(void) { render_handle Result = {}; return(Result); } #define PushCommand(Group, type) (type *)PushCommand_(Group, Render_Command_##type, sizeof(type)) static void *PushCommand_(render_group *Group, render_command_type Type, u64 Size) { void *Result = 0; vn_render_commands *Commands = Group->Commands; u64 TotalSize = Size + sizeof(render_command_header); u8 *PushBufferEnd = Commands->PushBufferBase + Commands->MaxPushBufferSize; if((Commands->PushBufferAt + TotalSize) <= PushBufferEnd) { render_command_header *Header = (render_command_header *)Commands->PushBufferAt; Header->Type = Type; Commands->PushBufferAt += sizeof(*Header); Group->CurrentCommand = Header; Result = Commands->PushBufferAt; Commands->PushBufferAt += Size; Fill(Result, 0, Size); } else { InvalidCodepath; } return(Result); } inline render_group BeginRenderGroup(vn_render_commands *Commands) { render_group Group = {}; Group.Commands = Commands; Group.ClipStack[0].Max = Commands->RenderDim; return(Group); } inline void PushClear(render_group *Group, v3 Color) { render_command_clear *Command = PushCommand(Group, render_command_clear); Command->Color = Color; } inline s32 GetTextureIndexForCommand(render_command_quads *Command, render_handle Handle) { s32 Result = -1; for(s32 TextureIndex = 0; TextureIndex < MAX_BOUND_TEXTURES; ++TextureIndex) { if(AreEqual(Command->Textures[TextureIndex], EmptyRenderHandle())) { Assert(Command->TexturesUsed == TextureIndex); Command->Textures[TextureIndex] = Handle; ++Command->TexturesUsed; } if(AreEqual(Command->Textures[TextureIndex], Handle)) { Result = TextureIndex; break; } } return(Result); } inline u32 PackV4ToU32(v4 V) { u32 Result = ((u8)(Clamp01(V.x)*255.0)<<24) | ((u8)(Clamp01(V.y)*255.0)<<16) | ((u8)(Clamp01(V.z)*255.0)<<8) | ((u8)(Clamp01(V.w)*255.0)<<0); return(Result); } inline void PushTexturedQuad(render_group *Group, v2 P, v2 Dim, v2 SourceP, v2 SourceDim, v4 Color00, v4 Color10, v4 Color01, v4 Color11, r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness, render_handle Texture) { 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, Texture)) != -1)) { Command = PushCommand(Group, render_command_quads); Command->QuadBufferIndex = Commands->QuadIndexCount; TextureIndex = GetTextureIndexForCommand(Command, Texture); } range2_r32 Clip = Group->ClipStack[Group->ClipStackUsed]; range2_r32 Dest = Range2R32(P, P + Dim); v2 DestMin = Max(Dest.Min, Clip.Min); v2 DestMax = Min(Dest.Max, Clip.Max); if(InRange(Clip, P) || InRange(Clip, P + Dim)) { v2 HalfSize = Dim*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 = P + HalfSize; u32 Width = Texture.U32[2]; u32 Height = Texture.U32[3]; SourceP.x /= Width; SourceP.y /= Height; SourceDim.x /= Width; SourceDim.y /= Height; v2 Source00 = SourceP; v2 Source01 = SourceP + V2(0, SourceDim.y); v2 Source10 = SourceP + V2(SourceDim.x, 0); v2 Source11 = SourceP + SourceDim; 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; } #if 0 else { int BreakMe = 0; } #endif } inline void PushQuad(render_group *Group, v2 P, v2 Dim, v4 Color00, v4 Color01, v4 Color10, v4 Color11, r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness) { PushTexturedQuad(Group, P, Dim, V2(0, 0), V2(0, 0), Color00, Color01, Color10, Color11, CornerRadius, EdgeSoftness, BorderThickness, Group->Commands->WhiteTexture); } inline void PushQuad(render_group *Group, v2 P, v2 Dim, v4 Color, r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness) { PushTexturedQuad(Group, P, Dim, V2(0, 0), V2(0, 0), Color, Color, Color, Color, CornerRadius, EdgeSoftness, BorderThickness, Group->Commands->WhiteTexture); } inline void PushClip(render_group *Group, range2_r32 Clip) { Assert(Group->ClipStackUsed + 1 < ArrayCount(Group->ClipStack)); Group->ClipStack[++Group->ClipStackUsed] = Clip; } inline void PopClip(render_group *Group) { Assert(Group->ClipStackUsed > 0); Group->ClipStack[--Group->ClipStackUsed]; }