// sixten: Functions implemented by the platform layer static void *OpenGL_AllocateMemory(umm Size); inline void *OpenGL_LoadFunction(char *Name); static void OpenGL_DeallocateMemory(void *Memory); //- sixten: OpenGL Render Layer static void OpenGL_DebugMessageCallback(GLenum Source, GLenum Type, GLuint ID, GLenum Severity, GLsizei Length, const GLchar *Message, const void *UserParam) { if(Severity == GL_DEBUG_SEVERITY_HIGH) { __debugbreak(); } } inline render_handle OpenGL_GetHandleFromTexture(opengl_texture Texture) { render_handle Result = {}; Result.U32[0] = Texture.ID; Result.U32[1] = Texture.Format; Result.U32[2] = Texture.Dim.x; Result.U32[3] = Texture.Dim.y; return(Result); } inline opengl_texture OpenGL_GetTextureFromHandle(render_handle Handle) { opengl_texture Result = {}; Result.ID = Handle.U32[0]; Result.Format = (render_texture_format)Handle.U32[1]; Result.Dim.x = Handle.U32[2]; Result.Dim.y = Handle.U32[3]; return(Result); } inline u32 OpenGL_GetInternalFormatFromTextureFormat(render_texture_format Format) { u32 InternalFormat = GL_INVALID_ENUM; if(Format == Render_TextureFormat_R8) { InternalFormat = GL_RED; } else if(Format == Render_TextureFormat_RGB8) { InternalFormat = GL_RGB; } else if(Format == Render_TextureFormat_RGBA8) { InternalFormat = GL_RGBA; } else { InvalidCodepath; } return(InternalFormat); } global GLint Global_OpenGL_SwizzleMaskR8[4] = {GL_ONE, GL_ONE, GL_ONE, GL_RED}; global GLint Global_OpenGL_SwizzleMaskRGB8[4] = {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}; global GLint Global_OpenGL_SwizzleMaskRGBA8[4] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; inline GLint *OpenGL_GetSwizzleFromTextureFormat(render_texture_format Format) { GLint *Swizzle = 0; if(Format == Render_TextureFormat_R8) { Swizzle = Global_OpenGL_SwizzleMaskR8; } else if(Format == Render_TextureFormat_RGB8) { Swizzle = Global_OpenGL_SwizzleMaskRGB8; } else if(Format == Render_TextureFormat_RGBA8) { Swizzle = Global_OpenGL_SwizzleMaskRGBA8; } else { InvalidCodepath; } return(Swizzle); } static RENDER_ALLOCATE_TEXTURE(OpenGL_AllocateTexture) { opengl_texture Texture = {}; Texture.Dim = Dim; Texture.Format = Format; glGenTextures(1, &Texture.ID); Assert(Texture.ID); u32 InternalFormat = OpenGL_GetInternalFormatFromTextureFormat(Format); GLint *SwizzleMask = OpenGL_GetSwizzleFromTextureFormat(Format); glBindTexture(GL_TEXTURE_2D, Texture.ID); glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, Dim.x, Dim.y, 0, InternalFormat, GL_UNSIGNED_BYTE, Data); 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_LINEAR); 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); } static RENDER_FILL_REGION(OpenGL_FillRegion) { opengl_texture Texture = OpenGL_GetTextureFromHandle(Handle); glBindTexture(GL_TEXTURE_2D, Texture.ID); glTexSubImage2D(GL_TEXTURE_2D, 0, DestP.x, DestP.y, DestDim.x, DestDim.y, OpenGL_GetInternalFormatFromTextureFormat(Texture.Format), GL_UNSIGNED_BYTE, Data); glBindTexture(GL_TEXTURE_2D, 0); } global char *OpenGL_ShaderHeader = R"GLSL( #version 330 core #define s32 int #define u32 uint #define v2s ivec2 #define v2u uvec2 #define r32 float #define v2 vec2 #define v3 vec3 #define v4 vec4 #define m4x4 mat4x4 #define V2 vec2 #define V3 vec3 #define V4 vec4 #define Min(a, b) min(a, b) #define Max(a, b) max(a, b) #define Clamp(x, min, max), clamp(x, min, max) #define Clamp01(x), Clamp(x, 0, 1) #define LinearBlend(A, B, C) mix(A, B, C) #define AbsoluteValue(x) abs(x) #define Length(x) length(x) #define Pow(x, y) pow(x, y) )GLSL"; static u32 OpenGL_CompileShaderProgram(char *VertexSource, char *FragmentSource) { u32 Result = 0; u32 VertexShader = glCreateShader(GL_VERTEX_SHADER); char *VertexSources[] = { OpenGL_ShaderHeader, VertexSource }; glShaderSource(VertexShader, ArrayCount(VertexSources), VertexSources, 0); glCompileShader(VertexShader); s32 VertexCompilationStatus; glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &VertexCompilationStatus); if(VertexCompilationStatus) { u32 FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); char *FragmentSources[] = { OpenGL_ShaderHeader, FragmentSource }; glShaderSource(FragmentShader, ArrayCount(FragmentSources), FragmentSources, 0); glCompileShader(FragmentShader); s32 FragmentCompilationStatus; glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &FragmentCompilationStatus); if(FragmentCompilationStatus) { u32 Program = glCreateProgram(); glAttachShader(Program, VertexShader); glAttachShader(Program, FragmentShader); glLinkProgram(Program); glDeleteShader(VertexShader); glDeleteShader(FragmentShader); s32 ProgramLinkStatus; glGetProgramiv(Program, GL_LINK_STATUS, &ProgramLinkStatus); if(ProgramLinkStatus) { Result = Program; } else { char InfoLog[1024]; glGetProgramInfoLog(Program, ArrayCount(InfoLog), 0, InfoLog); InvalidCodepath; } } else { char InfoLog[1024]; glGetShaderInfoLog(FragmentShader, ArrayCount(InfoLog), 0, InfoLog); InvalidCodepath; } } else { char InfoLog[1024]; glGetShaderInfoLog(VertexShader, ArrayCount(InfoLog), 0, InfoLog); InvalidCodepath; } return(Result); } static quad_program OpenGL_CompileQuadProgram(void) { char *VertexSource = R"GLSL( in v2 In_P; in v2 In_SourceP; in s32 In_TextureIndex; in u32 In_Color; in v2 In_ToCenter; in v2 In_HalfSize; in r32 In_CornerRadius; in r32 In_EdgeSoftness; in r32 In_BorderThickness; )GLSL" "uniform sampler2D TextureSamplers[" Stringify(MAX_BOUND_TEXTURES) "];" R"GLSL( uniform v2 Uniform_Resolution; flat out s32 TextureIndex; out v2 DestP; out v2 DestHalfSize; out v2 DestCenter; out v2 SourceP; out v4 Color; out r32 CornerRadius; out r32 EdgeSoftness; out r32 BorderThickness; void main() { DestP = In_P; DestCenter = In_P + In_ToCenter; DestHalfSize = In_HalfSize; SourceP = In_SourceP; v2 ScreenP = DestP / Uniform_Resolution;; ScreenP = ScreenP*2 - 1; ScreenP.y = -ScreenP.y; gl_Position = V4(ScreenP, 0, 1); Color.r = r32((In_Color >> 24) & 255u)/255.0; Color.g = r32((In_Color >> 16) & 255u)/255.0; Color.b = r32((In_Color >> 8) & 255u)/255.0; Color.a = r32((In_Color >> 0) & 255u)/255.0; TextureIndex = In_TextureIndex; CornerRadius = In_CornerRadius; EdgeSoftness = In_EdgeSoftness; BorderThickness = In_BorderThickness; })GLSL"; char *FragmentSource = R"GLSL( flat in s32 TextureIndex; in v2 DestP; in v2 DestHalfSize; in v2 DestCenter; in v2 SourceP; in v4 Color; in r32 CornerRadius; in r32 EdgeSoftness; in r32 BorderThickness; )GLSL" "uniform sampler2D TextureSamplers[" Stringify(MAX_BOUND_TEXTURES) "];" R"GLSL( out v4 Out_Color; r32 RoundedRect(v2 P, v2 Center, v2 HalfSize, r32 r) { v2 d2 = AbsoluteValue(Center - P) - HalfSize + r; r32 Result = Min(Max(d2.x, d2.y), 0) + Length(Max(d2, 0)) - r; return(Result); } void main() { r32 SoftnessPadding = Max(0, EdgeSoftness*2-1); r32 Dist = RoundedRect(DestP, DestCenter, DestHalfSize - SoftnessPadding, CornerRadius); r32 SDFFactor = 1 - smoothstep(0, 2*EdgeSoftness, Dist); r32 BorderFactor = 1; if(BorderThickness != 0) { v2 InteriorHalfSize = DestHalfSize - BorderThickness; r32 InteriorRadiusReduce = Min(InteriorHalfSize.x / DestHalfSize.x, InteriorHalfSize.y / DestHalfSize.y); r32 InteriorCornerRadius = CornerRadius*InteriorRadiusReduce*InteriorRadiusReduce; r32 InsideDist = RoundedRect(DestP, DestCenter, InteriorHalfSize - SoftnessPadding, InteriorCornerRadius); BorderFactor = smoothstep(0, 2*EdgeSoftness, InsideDist); } v4 TextureFactor = texture(TextureSamplers[TextureIndex], SourceP); Out_Color = Color*TextureFactor*BorderFactor*SDFFactor; })GLSL"; quad_program Program = {}; Program.ID = OpenGL_CompileShaderProgram(VertexSource, FragmentSource); Program.PID = glGetAttribLocation(Program.ID, "In_P"); Program.SourcePID = glGetAttribLocation(Program.ID, "In_SourceP"); Program.TextureIndexID = glGetAttribLocation(Program.ID, "In_TextureIndex"); Program.ColorID = glGetAttribLocation(Program.ID, "In_Color"); Program.ToCenterID = glGetAttribLocation(Program.ID, "In_ToCenter"); Program.HalfSizeID = glGetAttribLocation(Program.ID, "In_HalfSize"); Program.CornerRadiusID = glGetAttribLocation(Program.ID, "In_CornerRadius"); Program.EdgeSoftnessID = glGetAttribLocation(Program.ID, "In_EdgeSoftness"); Program.BorderThicknessID = glGetAttribLocation(Program.ID, "In_BorderThickness"); glUseProgram(Program.ID); Program.UniformResolutionLocation = glGetUniformLocation(Program.ID, "Uniform_Resolution"); temporary_memory Scratch = GetScratch(0, 0); for(s32 TextureIndex = 0; TextureIndex < MAX_BOUND_TEXTURES; ++TextureIndex) { string Name = PushFormat(Scratch.Arena, "TextureSamplers[%i]", TextureIndex); s32 Location = glGetUniformLocation(Program.ID, (char *)Name.Data); glUniform1i(Location, TextureIndex); } ReleaseScratch(Scratch); glUseProgram(0); return(Program); } static instanced_quad_program OpenGL_CompileInstacedQuadProgram(void) { char *VertexSource = R"GLSL( in v4 In_Dest; in v4 In_Source; in s32 In_TextureIndex; in u32 In_Color[4]; in r32 In_CornerRadius; in r32 In_EdgeSoftness; in r32 In_BorderThickness; )GLSL" "uniform sampler2D TextureSamplers[" Stringify(MAX_BOUND_TEXTURES) "];" R"GLSL( uniform v2 Uniform_Resolution; out v2 DestP; out v2 DestHalfSize; out v2 DestCenter; out v2 SourceP; out v4 Color; out r32 CornerRadius; out r32 EdgeSoftness; out r32 BorderThickness; flat out s32 TextureIndex; void main() { v2[] Vertices = V2[](V2(0, 0), V2(0, 1), V2(1, 0), V2(1, 1)); 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; 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; ScreenP.y = -ScreenP.y; gl_Position = V4(ScreenP, 0, 1); u32 ColorData = In_Color[gl_VertexID]; Color.r = r32((ColorData >> 24) & 255u)/255.0; Color.g = r32((ColorData >> 16) & 255u)/255.0; Color.b = r32((ColorData >> 8) & 255u)/255.0; Color.a = r32((ColorData >> 0) & 255u)/255.0; CornerRadius = In_CornerRadius; EdgeSoftness = In_EdgeSoftness; BorderThickness = In_BorderThickness; TextureIndex = In_TextureIndex; } )GLSL"; char *FragmentSource = R"GLSL( in v2 DestP; in v2 DestHalfSize; in v2 DestCenter; in v2 SourceP; in v4 Color; in r32 CornerRadius; in r32 EdgeSoftness; in r32 BorderThickness; flat in s32 TextureIndex; )GLSL" "uniform sampler2D TextureSamplers[" Stringify(MAX_BOUND_TEXTURES) "];" R"GLSL( out v4 Out_Color; r32 RoundedRect(v2 P, v2 Center, v2 HalfSize, r32 r) { v2 d2 = AbsoluteValue(Center - P) - HalfSize + r; r32 Result = Min(Max(d2.x, d2.y), 0) + Length(Max(d2, 0)) - r; return(Result); } void main() { r32 SoftnessPadding = Max(0, EdgeSoftness*2-1); r32 Dist = RoundedRect(DestP, DestCenter, DestHalfSize - SoftnessPadding, CornerRadius); r32 SDFFactor = 1 - smoothstep(0, 2*EdgeSoftness, Dist); r32 BorderFactor = 1; if(BorderThickness != 0) { v2 InteriorHalfSize = DestHalfSize - BorderThickness; v2 InteriorRadiusReducePair = InteriorHalfSize / DestHalfSize; r32 InteriorRadiusReduce = Min(InteriorRadiusReducePair.x, InteriorRadiusReducePair.y); r32 InteriorCornerRadius = CornerRadius*InteriorRadiusReduce*InteriorRadiusReduce; r32 InsideDist = RoundedRect(DestP, DestCenter, InteriorHalfSize - SoftnessPadding, InteriorCornerRadius); BorderFactor = smoothstep(0, 2*EdgeSoftness, InsideDist); } v4 TextureFactor = texture(TextureSamplers[TextureIndex], SourceP); Out_Color = Color*SDFFactor*BorderFactor*TextureFactor; } )GLSL"; instanced_quad_program Program = {}; Program.ID = OpenGL_CompileShaderProgram(VertexSource, FragmentSource); Program.DestID = glGetAttribLocation(Program.ID, "In_Dest"); Program.SourceID = glGetAttribLocation(Program.ID, "In_Source"); Program.TextureIndexID = glGetAttribLocation(Program.ID, "In_TextureIndex"); Program.ColorID[0] = glGetAttribLocation(Program.ID, "In_Color[0]"); Program.ColorID[1] = glGetAttribLocation(Program.ID, "In_Color[1]"); Program.ColorID[2] = glGetAttribLocation(Program.ID, "In_Color[2]"); Program.ColorID[3] = glGetAttribLocation(Program.ID, "In_Color[3]"); Program.CornerRadiusID = glGetAttribLocation(Program.ID, "In_CornerRadius"); Program.EdgeSoftnessID = glGetAttribLocation(Program.ID, "In_EdgeSoftness"); Program.BorderThicknessID = glGetAttribLocation(Program.ID, "In_BorderThickness"); glUseProgram(Program.ID); Program.UniformResolutionLocation = glGetUniformLocation(Program.ID, "Uniform_Resolution"); temporary_memory Scratch = GetScratch(0, 0); for(s32 TextureIndex = 0; TextureIndex < MAX_BOUND_TEXTURES; ++TextureIndex) { string Name = PushFormat(Scratch.Arena, "TextureSamplers[%i]", TextureIndex); s32 Location = glGetUniformLocation(Program.ID, (char *)Name.Data); glUniform1i(Location, TextureIndex); } ReleaseScratch(Scratch); glUseProgram(0); return(Program); } #define OpenGL_EnableFloatVertexAttribute(Index, Size, Type, type, Member)\ if(Index != -1)\ {\ glEnableVertexAttribArray(Index);\ glVertexAttribPointer(Index, Size, Type, GL_FALSE, sizeof(type), (void *)OffsetOf(type, Member));\ if(VN_USE_INSTANCING)\ {\ glVertexAttribDivisor(Index, 1);\ }\ } #define OpenGL_EnableIntegerVertexAttribute(Index, Size, Type, type, Member)\ if(Index != -1)\ {\ glEnableVertexAttribArray(Index);\ glVertexAttribIPointer(Index, Size, Type, sizeof(type), (void *)OffsetOf(type, Member));\ if(VN_USE_INSTANCING)\ {\ glVertexAttribDivisor(Index, 1);\ }\ } #define OpenGL_DisableVertexAttribute(Index)\ if(Index != -1)\ {\ glDisableVertexAttribArray(Index);\ } static void OpenGL_BeginProgram(quad_program *Program) { glUseProgram(Program->ID); OpenGL_EnableFloatVertexAttribute(Program->PID, 2, GL_FLOAT, quad_vertex, P); OpenGL_EnableFloatVertexAttribute(Program->SourcePID, 2, GL_FLOAT, quad_vertex, SourceP); OpenGL_EnableIntegerVertexAttribute(Program->TextureIndexID, 1, GL_UNSIGNED_INT, quad_vertex, TextureIndex); OpenGL_EnableIntegerVertexAttribute(Program->ColorID, 1, GL_UNSIGNED_INT, quad_vertex, Color); OpenGL_EnableFloatVertexAttribute(Program->ToCenterID, 2, GL_FLOAT, quad_vertex, ToCenter); OpenGL_EnableFloatVertexAttribute(Program->HalfSizeID, 2, GL_FLOAT, quad_vertex, HalfSize); OpenGL_EnableFloatVertexAttribute(Program->CornerRadiusID, 1, GL_FLOAT, quad_vertex, CornerRadius); OpenGL_EnableFloatVertexAttribute(Program->EdgeSoftnessID, 1, GL_FLOAT, quad_vertex, EdgeSoftness); OpenGL_EnableFloatVertexAttribute(Program->BorderThicknessID, 1, GL_FLOAT, quad_vertex, BorderThickness); } static void OpenGL_EndProgram(quad_program *Program) { OpenGL_DisableVertexAttribute(Program->PID); OpenGL_DisableVertexAttribute(Program->SourcePID); OpenGL_DisableVertexAttribute(Program->TextureIndexID); OpenGL_DisableVertexAttribute(Program->ColorID); OpenGL_DisableVertexAttribute(Program->ToCenterID); OpenGL_DisableVertexAttribute(Program->HalfSizeID); OpenGL_DisableVertexAttribute(Program->CornerRadiusID); OpenGL_DisableVertexAttribute(Program->EdgeSoftnessID); OpenGL_DisableVertexAttribute(Program->BorderThicknessID); glUseProgram(0); } static void OpenGL_BeginProgram(instanced_quad_program *Program) { glUseProgram(Program->ID); OpenGL_EnableFloatVertexAttribute(Program->DestID, 4, GL_FLOAT, instanced_quad, Dest); OpenGL_EnableFloatVertexAttribute(Program->SourceID, 4, GL_FLOAT, instanced_quad, Source); OpenGL_EnableIntegerVertexAttribute(Program->TextureIndexID, 1, GL_UNSIGNED_INT, instanced_quad, TextureIndex); OpenGL_EnableIntegerVertexAttribute(Program->ColorID[0], 1, GL_UNSIGNED_INT, instanced_quad, Color[0]); OpenGL_EnableIntegerVertexAttribute(Program->ColorID[1], 1, GL_UNSIGNED_INT, instanced_quad, Color[1]); OpenGL_EnableIntegerVertexAttribute(Program->ColorID[2], 1, GL_UNSIGNED_INT, instanced_quad, Color[2]); OpenGL_EnableIntegerVertexAttribute(Program->ColorID[3], 1, GL_UNSIGNED_INT, instanced_quad, Color[3]); OpenGL_EnableFloatVertexAttribute(Program->CornerRadiusID, 1, GL_FLOAT, instanced_quad, CornerRadius); OpenGL_EnableFloatVertexAttribute(Program->EdgeSoftnessID, 1, GL_FLOAT, instanced_quad, EdgeSoftness); OpenGL_EnableFloatVertexAttribute(Program->BorderThicknessID, 1, GL_FLOAT, instanced_quad, BorderThickness); } static void OpenGL_EndProgram(instanced_quad_program *Program) { OpenGL_DisableVertexAttribute(Program->DestID); OpenGL_DisableVertexAttribute(Program->SourceID); OpenGL_DisableVertexAttribute(Program->TextureIndexID); OpenGL_DisableVertexAttribute(Program->ColorID[0]); OpenGL_DisableVertexAttribute(Program->ColorID[1]); OpenGL_DisableVertexAttribute(Program->ColorID[2]); OpenGL_DisableVertexAttribute(Program->ColorID[3]); OpenGL_DisableVertexAttribute(Program->CornerRadiusID); OpenGL_DisableVertexAttribute(Program->EdgeSoftnessID); OpenGL_DisableVertexAttribute(Program->BorderThicknessID); glUseProgram(0); } static opengl_context OpenGL_SetupContext(vn_render_commands *RenderCommands, umm MaxPushBufferSize) { opengl_context Context = {}; RenderCommands->MaxPushBufferSize = MaxPushBufferSize; RenderCommands->PushBufferBase = (u8 *)OpenGL_AllocateMemory(RenderCommands->MaxPushBufferSize); #if VN_USE_INSTANCING RenderCommands->MaxInstancedQuadCount = MAX_QUAD_COUNT; RenderCommands->InstancedQuadBase = (instanced_quad *)OpenGL_AllocateMemory(RenderCommands->MaxInstancedQuadCount*sizeof(instanced_quad)); #else RenderCommands->MaxQuadVertexCount = MAX_QUAD_COUNT*4; RenderCommands->QuadVertexBase = (quad_vertex *)OpenGL_AllocateMemory(RenderCommands->MaxQuadVertexCount*sizeof(quad_vertex)); RenderCommands->MaxQuadIndexCount = MAX_QUAD_COUNT*6; RenderCommands->QuadIndexBase = (s32 *)OpenGL_AllocateMemory(RenderCommands->MaxQuadIndexCount*sizeof(s32)); #endif #if VN_USE_INSTANCING Context.InstancedQuadProgram = OpenGL_CompileInstacedQuadProgram(); #else Context.QuadProgram = OpenGL_CompileQuadProgram(); #endif #if VN_USE_INSTANCING glGenBuffers(1, &Context.InstancedQuadBuffer); #else glGenBuffers(1, &Context.VertexBuffer); glGenBuffers(1, &Context.IndexBuffer); #endif #if VN_USE_INSTANCING glBindBuffer(GL_ARRAY_BUFFER, Context.InstancedQuadBuffer); glBufferData(GL_ARRAY_BUFFER, RenderCommands->MaxInstancedQuadCount*sizeof(instanced_quad), 0, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); #else glBindBuffer(GL_ARRAY_BUFFER, Context.VertexBuffer); glBufferData(GL_ARRAY_BUFFER, RenderCommands->MaxQuadVertexCount*sizeof(quad_vertex), 0, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Context.IndexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, RenderCommands->MaxQuadIndexCount*sizeof(s32), 0, GL_STREAM_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #endif u32 WhiteData = 0xFFFFFFFF; RenderCommands->WhiteTexture = OpenGL_AllocateTexture(V2S32(1, 1), Render_TextureFormat_RGBA8, false, &WhiteData); RenderCommands->AllocateTexture = OpenGL_AllocateTexture; RenderCommands->FillRegion = OpenGL_FillRegion; #if VN_SLOW&&0 glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(OpenGL_DebugMessageCallback, 0); #endif u32 DummyVertexArray; glGenVertexArrays(1, &DummyVertexArray); glBindVertexArray(DummyVertexArray); return(Context); } static void OpenGL_BeginFrame(vn_render_commands *RenderCommands, v2 RenderDim) { RenderCommands->PushBufferAt = RenderCommands->PushBufferBase; #if VN_USE_INSTANCING RenderCommands->InstancedQuadCount = 0; #else RenderCommands->QuadVertexCount = 0; RenderCommands->QuadIndexCount = 0; #endif RenderCommands->RenderDim = RenderDim; } static void OpenGL_EndFrame(opengl_context *Context, vn_render_commands *RenderCommands) { glViewport(0, 0, RenderCommands->RenderDim.x, RenderCommands->RenderDim.y); glScissor(0, 0, RenderCommands->RenderDim.x, RenderCommands->RenderDim.y); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_SCISSOR_TEST); #if !VN_USE_INSTANCING glBindBuffer(GL_ARRAY_BUFFER, Context->VertexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Context->IndexBuffer); void *VertexData = RenderCommands->QuadVertexBase; umm VertexSize = RenderCommands->QuadVertexCount*sizeof(quad_vertex); glBufferSubData(GL_ARRAY_BUFFER, 0, VertexSize, VertexData); void *IndexData = RenderCommands->QuadIndexBase; umm IndexSize = RenderCommands->QuadIndexCount*sizeof(s32); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, IndexSize, IndexData); #endif for(u8 *PushBufferAt = RenderCommands->PushBufferBase; PushBufferAt < RenderCommands->PushBufferAt;) { render_command_header *Header = (render_command_header *)PushBufferAt; PushBufferAt += sizeof(*Header); switch(Header->Type) { case Render_Command_render_command_clear: { render_command_clear *Command = (render_command_clear *)PushBufferAt; PushBufferAt += sizeof(*Command); glClearColor(Command->Color.r, Command->Color.g, Command->Color.b, 1.0); glClear(GL_COLOR_BUFFER_BIT); } break; #if VN_USE_INSTANCING case Render_Command_render_command_instanced_quads: { render_command_instanced_quads *Command = (render_command_instanced_quads *)PushBufferAt; PushBufferAt += sizeof(*Command); render_texture_mapping *Mapping = &Command->Mapping; for(s32 TextureIndex = 0; TextureIndex < Mapping->TexturesUsed; ++TextureIndex) { opengl_texture Texture = OpenGL_GetTextureFromHandle(Mapping->Textures[TextureIndex]); glActiveTexture(GL_TEXTURE0 + TextureIndex); glBindTexture(GL_TEXTURE_2D, Texture.ID); } glBindBuffer(GL_ARRAY_BUFFER, Context->InstancedQuadBuffer); void *VertexData = RenderCommands->InstancedQuadBase+Command->QuadBufferIndex; umm VertexSize = Command->QuadCount*sizeof(instanced_quad); glBufferSubData(GL_ARRAY_BUFFER, 0, VertexSize, VertexData); OpenGL_BeginProgram(&Context->InstancedQuadProgram); glUniform2f(Context->InstancedQuadProgram.UniformResolutionLocation, RenderCommands->RenderDim.x, RenderCommands->RenderDim.y); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, Command->QuadCount); OpenGL_EndProgram(&Context->InstancedQuadProgram); glBindTexture(GL_TEXTURE_2D, 0); } break; case Render_Command_render_command_clip: { render_command_clip *Command = (render_command_clip *)PushBufferAt; PushBufferAt += sizeof(*Command); v2_r32 P = Command->ClipRect.Min; P.x = Max(Round(P.x), 0.0f); P.y = Max(Round(P.y), 0.0f); v2_r32 Dim = DimOfRange(Command->ClipRect); Dim.x = Max(Round(Dim.x), 0.0f); Dim.y = Max(Round(Dim.y), 0.0f); v2_r32 FlippedP = V2R32(P.x, RenderCommands->RenderDim.y-Dim.y-P.y); glScissor(FlippedP.x, FlippedP.y, Dim.x, Dim.y); } break; #else case Render_Command_render_command_quads: { render_command_quads *Command = (render_command_quads *)PushBufferAt; PushBufferAt += sizeof(*Command); OpenGL_BeginProgram(&Context->QuadProgram); glUniform2f(Context->QuadProgram.UniformResolutionLocation, RenderCommands->RenderDim.x, RenderCommands->RenderDim.y); render_texture_mapping *Mapping = &Command->Mapping; for(s32 TextureIndex = 0; TextureIndex < Mapping->TexturesUsed; ++TextureIndex) { opengl_texture Texture = OpenGL_GetTextureFromHandle(Mapping->Textures[TextureIndex]); glActiveTexture(GL_TEXTURE0 + TextureIndex); glBindTexture(GL_TEXTURE_2D, Texture.ID); } glDrawElements(GL_TRIANGLES, Command->QuadCount*6, GL_UNSIGNED_INT, 0); OpenGL_EndProgram(&Context->QuadProgram); glBindTexture(GL_TEXTURE_2D, 0); } break; #endif InvalidDefaultCase; } } glBindBuffer(GL_ARRAY_BUFFER, 0); }