824 lines
25 KiB
C++
824 lines
25 KiB
C++
// 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_HandleFromTexture(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_TextureFromHandle(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_InternalFormatFromTextureFormat(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_SwizzleFromTextureFormat(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_InternalFormatFromTextureFormat(Format);
|
|
GLint *SwizzleMask = OpenGL_SwizzleFromTextureFormat(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_HandleFromTexture(Texture);
|
|
return(Handle);
|
|
}
|
|
|
|
RENDER_DEALLOCATE_TEXTURE(OpenGL_DeallocateTexture)
|
|
{
|
|
opengl_texture Texture = OpenGL_TextureFromHandle(Handle);
|
|
glDeleteTextures(1, &Texture.ID);
|
|
}
|
|
|
|
static RENDER_FILL_REGION(OpenGL_FillRegion)
|
|
{
|
|
opengl_texture Texture = OpenGL_TextureFromHandle(Handle);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, Texture.ID);
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
|
DestP.x, DestP.y, DestDim.x, DestDim.y,
|
|
OpenGL_InternalFormatFromTextureFormat(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");
|
|
|
|
temp 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[4];
|
|
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[gl_VertexID];
|
|
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 SDFFactor = 1;
|
|
r32 SoftnessPadding = Max(0, EdgeSoftness*2-1);
|
|
|
|
if(EdgeSoftness != 0 || CornerRadius != 0)
|
|
{
|
|
r32 Dist = RoundedRect(DestP, DestCenter, DestHalfSize - SoftnessPadding, CornerRadius);
|
|
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*TextureFactor*SDFFactor*BorderFactor;
|
|
}
|
|
|
|
)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[0] = glGetAttribLocation(Program.ID, "In_CornerRadius[0]");
|
|
Program.CornerRadiusID[1] = glGetAttribLocation(Program.ID, "In_CornerRadius[1]");
|
|
Program.CornerRadiusID[2] = glGetAttribLocation(Program.ID, "In_CornerRadius[2]");
|
|
Program.CornerRadiusID[3] = glGetAttribLocation(Program.ID, "In_CornerRadius[3]");
|
|
Program.EdgeSoftnessID = glGetAttribLocation(Program.ID, "In_EdgeSoftness");
|
|
Program.BorderThicknessID = glGetAttribLocation(Program.ID, "In_BorderThickness");
|
|
|
|
glUseProgram(Program.ID);
|
|
Program.UniformResolutionLocation = glGetUniformLocation(Program.ID, "Uniform_Resolution");
|
|
|
|
temp 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[0], 1, GL_FLOAT, instanced_quad, CornerRadius[0]);
|
|
OpenGL_EnableFloatVertexAttribute(Program->CornerRadiusID[1], 1, GL_FLOAT, instanced_quad, CornerRadius[1]);
|
|
OpenGL_EnableFloatVertexAttribute(Program->CornerRadiusID[2], 1, GL_FLOAT, instanced_quad, CornerRadius[2]);
|
|
OpenGL_EnableFloatVertexAttribute(Program->CornerRadiusID[3], 1, GL_FLOAT, instanced_quad, CornerRadius[3]);
|
|
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[0]);
|
|
OpenGL_DisableVertexAttribute(Program->CornerRadiusID[1]);
|
|
OpenGL_DisableVertexAttribute(Program->CornerRadiusID[2]);
|
|
OpenGL_DisableVertexAttribute(Program->CornerRadiusID[3]);
|
|
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->DeallocateTexture = OpenGL_DeallocateTexture;
|
|
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_r32 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
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, Context->InstancedQuadBuffer);
|
|
OpenGL_BeginProgram(&Context->InstancedQuadProgram);
|
|
glUniform2f(Context->InstancedQuadProgram.UniformResolutionLocation,
|
|
RenderCommands->RenderDim.x, RenderCommands->RenderDim.y);
|
|
|
|
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_TextureFromHandle(Mapping->Textures[TextureIndex]);
|
|
glActiveTexture(GL_TEXTURE0 + TextureIndex);
|
|
glBindTexture(GL_TEXTURE_2D, Texture.ID);
|
|
}
|
|
|
|
void *VertexData = RenderCommands->InstancedQuadBase+Command->QuadBufferIndex;
|
|
umm VertexSize = Command->QuadCount*sizeof(instanced_quad);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, VertexSize, VertexData);
|
|
|
|
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, Command->QuadCount);
|
|
|
|
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_TextureFromHandle(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;
|
|
}
|
|
}
|
|
|
|
OpenGL_EndProgram(&Context->InstancedQuadProgram);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
} |