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 DimFromTexture(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_texture_mapping *Mapping, render_handle Handle) { s32 Result = -1; for(s32 TextureIndex = 0; TextureIndex < MAX_BOUND_TEXTURES; ++TextureIndex) { if(AreEqual(Mapping->Textures[TextureIndex], EmptyRenderHandle())) { Assert(Mapping->TexturesUsed == TextureIndex); Mapping->Textures[TextureIndex] = Handle; ++Mapping->TexturesUsed; } if(AreEqual(Mapping->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); } #if VN_USE_INSTANCING static void PushTexturedQuad(render_group *Group, range2_r32 Dest, range2_r32 Source, v4 Color00, v4 Color10, v4 Color01, v4 Color11, r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness, render_handle Texture) { vn_render_commands *Commands = Group->Commands; if(!AreEqual(Texture, EmptyRenderHandle())) { 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); #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; } } } #else static void PushTexturedQuad(render_group *Group, range2_r32 Dest, range2_r32 Source, v4 Color00, v4 Color10, v4 Color01, v4 Color11, r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness, render_handle Texture) { vn_render_commands *Commands = Group->Commands; if(!AreEqual(Texture, EmptyRenderHandle())) { 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); } 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; 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 inline void PushQuad(render_group *Group, range2_r32 Dest, v4 Color00, v4 Color01, v4 Color10, v4 Color11, r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness) { PushTexturedQuad(Group, Dest, Range2R32(V2(0, 0), V2(0, 0)), Color00, Color01, Color10, Color11, CornerRadius, EdgeSoftness, BorderThickness, Group->Commands->WhiteTexture); } inline void PushQuad(render_group *Group, range2_r32 Dest, v4 Color, r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness) { PushTexturedQuad(Group, Dest, Range2R32(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)); #if VN_USE_INSTANCING render_command_clip *Command = PushCommand(Group, render_command_clip); Command->ClipRect = Group->ClipStack[++Group->ClipStackUsed] = Clip; #else Group->ClipStack[++Group->ClipStackUsed] = Clip; #endif } inline void PopClip(render_group *Group) { Assert(Group->ClipStackUsed > 0); #if VN_USE_INSTANCING render_command_clip *Command = PushCommand(Group, render_command_clip); Command->ClipRect = Group->ClipStack[--Group->ClipStackUsed]; #else --Group->ClipStackUsed; #endif }