Opengl render and font
This commit is contained in:
@@ -181,8 +181,8 @@ int CompileNewPlatform() {
|
|||||||
int main() {
|
int main() {
|
||||||
MA_InitScratch();
|
MA_InitScratch();
|
||||||
SRC_InitCache(Perm, "te.cache");
|
SRC_InitCache(Perm, "te.cache");
|
||||||
// int result = CompileTextEditor();
|
int result = CompileTextEditor();
|
||||||
int result = CompileNewPlatform();
|
// int result = CompileNewPlatform();
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
OS_DeleteFile("te.cache");
|
OS_DeleteFile("te.cache");
|
||||||
|
|||||||
@@ -3,6 +3,34 @@ struct Vec2 {
|
|||||||
float y;
|
float y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union Vec4 {
|
||||||
|
struct {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
float w;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
float r;
|
||||||
|
float g;
|
||||||
|
float b;
|
||||||
|
float a;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union Vec3 {
|
||||||
|
struct {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
float r;
|
||||||
|
float g;
|
||||||
|
float b;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct Rect2 {
|
struct Rect2 {
|
||||||
Vec2 min;
|
Vec2 min;
|
||||||
Vec2 max;
|
Vec2 max;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
struct Glyph {
|
struct Glyph {
|
||||||
Vec2I size;
|
Vec2 size;
|
||||||
Vec2I offset;
|
Vec2 offset;
|
||||||
int32_t xadvance;
|
float xadvance;
|
||||||
int32_t left_side_bearing;
|
float left_side_bearing;
|
||||||
Rect2 atlas_bounding_box;
|
Rect2 atlas_bounding_box;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Font {
|
struct Font {
|
||||||
@@ -11,10 +11,10 @@ struct Font {
|
|||||||
uint32_t first_char, last_char;
|
uint32_t first_char, last_char;
|
||||||
uint32_t texture_id;
|
uint32_t texture_id;
|
||||||
|
|
||||||
int32_t size;
|
float size;
|
||||||
int32_t descent;
|
float descent;
|
||||||
int32_t ascent;
|
float ascent;
|
||||||
int32_t line_gap;
|
float line_gap;
|
||||||
|
|
||||||
Rect2 white_texture_bounding_box;
|
Rect2 white_texture_bounding_box;
|
||||||
};
|
};
|
||||||
@@ -104,15 +104,15 @@ Font CreateFont(Atlas *atlas, int32_t size, String path) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
float scale = stbtt_ScaleForPixelHeight(&stb_font, (float)result.size);
|
float scale = stbtt_ScaleForPixelHeight(&stb_font, (float)size);
|
||||||
float em_scale = stbtt_ScaleForMappingEmToPixels(&stb_font, (float)result.size);
|
float em_scale = stbtt_ScaleForMappingEmToPixels(&stb_font, (float)size);
|
||||||
|
|
||||||
int ascent, descent, line_gap;
|
int ascent, descent, line_gap;
|
||||||
stbtt_GetFontVMetrics(&stb_font, &ascent, &descent, &line_gap);
|
stbtt_GetFontVMetrics(&stb_font, &ascent, &descent, &line_gap);
|
||||||
result.ascent = (int32_t)((float)ascent * scale);
|
result.ascent = (float)ascent * scale;
|
||||||
result.descent = (int32_t)((float)descent * scale);
|
result.descent = (float)descent * scale;
|
||||||
result.line_gap = (int32_t)((float)line_gap * scale);
|
result.line_gap = (float)line_gap * scale;
|
||||||
result.size = size;
|
result.size = (float)size;
|
||||||
result.first_char = ' ';
|
result.first_char = ' ';
|
||||||
result.last_char = '~';
|
result.last_char = '~';
|
||||||
result.white_texture_bounding_box = atlas->white_texture_bounding_box;
|
result.white_texture_bounding_box = atlas->white_texture_bounding_box;
|
||||||
@@ -127,10 +127,10 @@ Font CreateFont(Atlas *atlas, int32_t size, String path) {
|
|||||||
|
|
||||||
Glyph glyph = {};
|
Glyph glyph = {};
|
||||||
glyph.atlas_bounding_box = PackBitmap(atlas, bitmap, width, height);
|
glyph.atlas_bounding_box = PackBitmap(atlas, bitmap, width, height);
|
||||||
glyph.size = {width, height};
|
glyph.size = {(float)width, (float)height};
|
||||||
glyph.offset = {xoff, yoff};
|
glyph.offset = {(float)xoff, (float)yoff};
|
||||||
glyph.xadvance = (int32_t)((float)xadvance * scale);
|
glyph.xadvance = (float)xadvance * scale;
|
||||||
glyph.left_side_bearing = (int32_t)((float)left_side_bearing * scale);
|
glyph.left_side_bearing = (float)left_side_bearing * scale;
|
||||||
Add(&result.glyphs, glyph);
|
Add(&result.glyphs, glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "basic/math_int.cpp"
|
#include "basic/math_int.cpp"
|
||||||
#include "basic/math.cpp"
|
#include "basic/math.cpp"
|
||||||
#include "font.cpp"
|
#include "font.cpp"
|
||||||
|
#include "render_opengl.cpp"
|
||||||
|
|
||||||
bool AppIsRunning = true;
|
bool AppIsRunning = true;
|
||||||
|
|
||||||
@@ -69,11 +70,11 @@ int main()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *glsl_version = "#version 130";
|
const char *glsl_version = "#version 450";
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
@@ -95,30 +96,40 @@ int main()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_GL_SetSwapInterval(1); // vsync
|
||||||
glDebugMessageCallback(&GLDebugCallback, NULL);
|
glDebugMessageCallback(&GLDebugCallback, NULL);
|
||||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
|
|
||||||
Arena Perm = {};
|
|
||||||
InitArena(&Perm);
|
|
||||||
Atlas atlas = CreateAtlas(Perm, {1024, 1024});
|
|
||||||
Font font = CreateFont(&atlas, 16, "c:\\Windows\\Fonts\\consola.ttf");
|
|
||||||
{
|
{
|
||||||
glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id);
|
Scratch scratch;
|
||||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
Atlas atlas = CreateAtlas(scratch, {1024, 1024});
|
||||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
MainFont = CreateFont(&atlas, 16, "C:\\Windows\\Fonts\\consola.ttf");
|
||||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
{
|
||||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id);
|
||||||
glTextureStorage2D(atlas.texture_id, 1, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y);
|
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTextureSubImage2D(atlas.texture_id, 0, 0, 0, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap);
|
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTextureStorage2D(atlas.texture_id, 1, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y);
|
||||||
|
glTextureSubImage2D(atlas.texture_id, 0, 0, 0, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap);
|
||||||
|
}
|
||||||
|
MainFont.texture_id = atlas.texture_id;
|
||||||
}
|
}
|
||||||
font.texture_id = atlas.texture_id;
|
|
||||||
|
InitRender();
|
||||||
|
|
||||||
while (AppIsRunning) {
|
while (AppIsRunning) {
|
||||||
glClearColor(255, 255, 255, 255);
|
int window_x, window_y;
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
SDL_GetWindowSize(window, &window_x, &window_y);
|
||||||
|
Vec2 window_size = {(float)window_x, (float)window_y};
|
||||||
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
SDL_WaitEvent(&event);
|
SDL_WaitEvent(&event);
|
||||||
ProcessSDLEvent(&event);
|
ProcessSDLEvent(&event);
|
||||||
|
|
||||||
|
BeginFrameRender(window_size);
|
||||||
|
DrawString(&MainFont, L"Testing", {0, 0}, {255, 0, 0, 255});
|
||||||
|
EndFrameRender({0, 0, 0, 1});
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
285
src/new_platform/render_opengl.cpp
Normal file
285
src/new_platform/render_opengl.cpp
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
struct Shader {
|
||||||
|
uint32_t pipeline;
|
||||||
|
uint32_t fshader;
|
||||||
|
uint32_t vshader;
|
||||||
|
};
|
||||||
|
Shader CreateShader(char *glsl_vshader, char *glsl_fshader);
|
||||||
|
|
||||||
|
struct Color {
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t a;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex2D {
|
||||||
|
Vec2 pos;
|
||||||
|
Vec2 tex;
|
||||||
|
Color color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexNode2D {
|
||||||
|
VertexNode2D *next;
|
||||||
|
int count;
|
||||||
|
Vertex2D vertices[1024 * 64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexList2D {
|
||||||
|
VertexNode2D *first;
|
||||||
|
VertexNode2D *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
VertexList2D Vertices;
|
||||||
|
int64_t TotalVertexCount;
|
||||||
|
|
||||||
|
unsigned VBO, VAO;
|
||||||
|
Shader Shader2D;
|
||||||
|
Arena RenderArena;
|
||||||
|
Font MainFont;
|
||||||
|
Vec2 WindowSize;
|
||||||
|
|
||||||
|
void BeginFrameRender(Vec2 window_size) {
|
||||||
|
Clear(&RenderArena);
|
||||||
|
TotalVertexCount = 0;
|
||||||
|
Vertices.first = NULL;
|
||||||
|
Vertices.last = NULL;
|
||||||
|
WindowSize = window_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndFrameRender(Vec4 color) {
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
glViewport(0, 0, (GLsizei)WindowSize.x, (GLsizei)WindowSize.y);
|
||||||
|
glClearColor(color.r * 255.f, color.g * 255.f, color.b * 255.f, color.a * 255.f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
// Default draw using the font texture
|
||||||
|
glBindProgramPipeline(Shader2D.pipeline);
|
||||||
|
float xinverse = 1.f / (WindowSize.x / 2.f);
|
||||||
|
float yinverse = 1.f / (WindowSize.y / 2.f);
|
||||||
|
glProgramUniform2f(Shader2D.vshader, 0, xinverse, yinverse);
|
||||||
|
for (VertexNode2D *it = Vertices.first; it; it = it->next) {
|
||||||
|
glNamedBufferSubData(VBO, 0, it->count * sizeof(Vertex2D), it->vertices);
|
||||||
|
glBindVertexArray(VAO);
|
||||||
|
GLint s_texture = 0; // texture unit that sampler2D will use in GLSL code
|
||||||
|
glBindTextureUnit(s_texture, MainFont.texture_id);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, it->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitRender() {
|
||||||
|
InitArena(&RenderArena);
|
||||||
|
|
||||||
|
glCreateBuffers(1, &VBO);
|
||||||
|
glNamedBufferStorage(VBO, Lengthof(VertexNode2D::vertices) * sizeof(Vertex2D), 0, GL_DYNAMIC_STORAGE_BIT);
|
||||||
|
|
||||||
|
glCreateVertexArrays(1, &VAO);
|
||||||
|
|
||||||
|
GLint vbuf_index = 0;
|
||||||
|
glVertexArrayVertexBuffer(VAO, vbuf_index, VBO, 0, sizeof(struct Vertex2D));
|
||||||
|
|
||||||
|
GLint a_pos = 0;
|
||||||
|
glVertexArrayAttribFormat(VAO, a_pos, 2, GL_FLOAT, GL_FALSE, offsetof(struct Vertex2D, pos));
|
||||||
|
glVertexArrayAttribBinding(VAO, a_pos, vbuf_index);
|
||||||
|
glEnableVertexArrayAttrib(VAO, a_pos);
|
||||||
|
|
||||||
|
GLint a_tex = 1;
|
||||||
|
glVertexArrayAttribFormat(VAO, a_tex, 2, GL_FLOAT, GL_FALSE, offsetof(struct Vertex2D, tex));
|
||||||
|
glVertexArrayAttribBinding(VAO, a_tex, vbuf_index);
|
||||||
|
glEnableVertexArrayAttrib(VAO, a_tex);
|
||||||
|
|
||||||
|
GLint a_color = 2;
|
||||||
|
glVertexArrayAttribFormat(VAO, a_color, 4, GL_UNSIGNED_BYTE, GL_FALSE, offsetof(struct Vertex2D, color));
|
||||||
|
glVertexArrayAttribBinding(VAO, a_color, vbuf_index);
|
||||||
|
glEnableVertexArrayAttrib(VAO, a_color);
|
||||||
|
|
||||||
|
char *glsl_vshader = R"==(
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout(location=0) uniform vec2 U_InvHalfScreenSize;
|
||||||
|
layout(location=0) in vec2 VPos;
|
||||||
|
layout(location=1) in vec2 VTex;
|
||||||
|
layout(location=2) in vec4 VColor;
|
||||||
|
|
||||||
|
out gl_PerVertex { vec4 gl_Position; }; // required because of ARB_separate_shader_objects
|
||||||
|
out vec2 FUV;
|
||||||
|
out vec4 FColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 pos = VPos * U_InvHalfScreenSize;
|
||||||
|
pos.y = 2 - pos.y; // invert y axis
|
||||||
|
pos -= vec2(1, 1); // convert to 0,1 range
|
||||||
|
|
||||||
|
gl_Position = vec4(pos, 0, 1);
|
||||||
|
FUV = VTex;
|
||||||
|
|
||||||
|
FColor = VColor / 255.0;
|
||||||
|
}
|
||||||
|
)==";
|
||||||
|
|
||||||
|
char *glsl_fshader = R"==(
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
in vec2 FUV;
|
||||||
|
in vec4 FColor;
|
||||||
|
|
||||||
|
layout (binding=0) uniform sampler2D S_Texture;
|
||||||
|
layout (location=0) out vec4 OutColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 c = FColor;
|
||||||
|
c.a *= texture(S_Texture, FUV).r;
|
||||||
|
OutColor = c;
|
||||||
|
}
|
||||||
|
)==";
|
||||||
|
|
||||||
|
Shader2D = CreateShader(glsl_vshader, glsl_fshader);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader CreateShader(char *glsl_vshader, char *glsl_fshader) {
|
||||||
|
Shader result = {};
|
||||||
|
result.vshader = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vshader);
|
||||||
|
result.fshader = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fshader);
|
||||||
|
|
||||||
|
GLint linked;
|
||||||
|
glGetProgramiv(result.vshader, GL_LINK_STATUS, &linked);
|
||||||
|
if (!linked) {
|
||||||
|
char message[1024];
|
||||||
|
glGetProgramInfoLog(result.vshader, sizeof(message), NULL, message);
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Failed to create vertex shader!", message, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
glGetProgramiv(result.fshader, GL_LINK_STATUS, &linked);
|
||||||
|
if (!linked) {
|
||||||
|
char message[1024];
|
||||||
|
glGetProgramInfoLog(result.fshader, sizeof(message), NULL, message);
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Failed to create fragment shader!", message, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenProgramPipelines(1, &result.pipeline);
|
||||||
|
glUseProgramStages(result.pipeline, GL_VERTEX_SHADER_BIT, result.vshader);
|
||||||
|
glUseProgramStages(result.pipeline, GL_FRAGMENT_SHADER_BIT, result.fshader);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SLL_QUEUE_ADD_MOD(f, l, n, next) \
|
||||||
|
do { \
|
||||||
|
(n)->next = 0; \
|
||||||
|
if ((f) == 0) { \
|
||||||
|
(f) = (l) = (n); \
|
||||||
|
} else { \
|
||||||
|
(l) = (l)->next = (n); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define SLL_QUEUE_ADD(f, l, n) SLL_QUEUE_ADD_MOD(f, l, n, next)
|
||||||
|
|
||||||
|
Vertex2D *AllocVertex2D(Allocator allocator, VertexList2D *list, int count) {
|
||||||
|
VertexNode2D *node = list->last;
|
||||||
|
if (node == 0 || node->count + count > Lengthof(node->vertices)) {
|
||||||
|
node = AllocType(allocator, VertexNode2D);
|
||||||
|
SLL_QUEUE_ADD(list->first, list->last, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
TotalVertexCount += count;
|
||||||
|
Vertex2D *result = node->vertices + node->count;
|
||||||
|
node->count += count;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushVertex2D(Allocator allocator, VertexList2D *list, Vertex2D *vertices, int count) {
|
||||||
|
Vertex2D *result = AllocVertex2D(allocator, list, count);
|
||||||
|
for (int i = 0; i < count; i += 1) result[i] = vertices[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushQuad2D(Allocator arena, VertexList2D *list, Rect2 rect, Rect2 tex, Color color, float rotation = 0.f, Vec2 rotation_point = {}) {
|
||||||
|
Vertex2D *v = AllocVertex2D(arena, list, 6);
|
||||||
|
v[0] = {
|
||||||
|
{rect.min.x, rect.max.y},
|
||||||
|
{ tex.min.x, tex.max.y},
|
||||||
|
color
|
||||||
|
};
|
||||||
|
v[1] = {
|
||||||
|
{rect.max.x, rect.max.y},
|
||||||
|
{ tex.max.x, tex.max.y},
|
||||||
|
color
|
||||||
|
};
|
||||||
|
v[2] = {
|
||||||
|
{rect.min.x, rect.min.y},
|
||||||
|
{ tex.min.x, tex.min.y},
|
||||||
|
color
|
||||||
|
};
|
||||||
|
v[3] = {
|
||||||
|
{rect.min.x, rect.min.y},
|
||||||
|
{ tex.min.x, tex.min.y},
|
||||||
|
color
|
||||||
|
};
|
||||||
|
v[4] = {
|
||||||
|
{rect.max.x, rect.max.y},
|
||||||
|
{ tex.max.x, tex.max.y},
|
||||||
|
color
|
||||||
|
};
|
||||||
|
v[5] = {
|
||||||
|
{rect.max.x, rect.min.y},
|
||||||
|
{ tex.max.x, tex.min.y},
|
||||||
|
color
|
||||||
|
};
|
||||||
|
if (rotation != 0.f) {
|
||||||
|
float s = sinf(rotation);
|
||||||
|
float c = cosf(rotation);
|
||||||
|
for (int i = 0; i < 6; i += 1) {
|
||||||
|
v[i].pos -= rotation_point;
|
||||||
|
v[i].pos = {v[i].pos.x * c + v[i].pos.y * (-s), v[i].pos.x * s + v[i].pos.y * c};
|
||||||
|
v[i].pos += rotation_point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawRect(Rect2 rect, Color color) {
|
||||||
|
PushQuad2D(RenderArena, &Vertices, rect, MainFont.white_texture_bounding_box, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 DrawString(Font *font, String16 string, Vec2 pos, Color color, bool draw = true) {
|
||||||
|
pos.y += font->ascent;
|
||||||
|
Vec2 original_pos = pos;
|
||||||
|
For(string) {
|
||||||
|
Glyph *g = GetGlyph(font, it);
|
||||||
|
Rect2 rect = Rect2FromSize(pos + g->offset, g->size);
|
||||||
|
if (draw && it != '\n' && it != ' ' && it != '\t') {
|
||||||
|
PushQuad2D(RenderArena, &Vertices, rect, g->atlas_bounding_box, color);
|
||||||
|
}
|
||||||
|
pos.x += g->xadvance;
|
||||||
|
}
|
||||||
|
Vec2 result = {pos.x - original_pos.x, font->size};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 GetStringSize(Font *font, String16 string, Vec2 pos, Color color) {
|
||||||
|
return DrawString(font, string, pos, color, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int GetCharSpacing(Font *font) {
|
||||||
|
Glyph *g = GetGlyph(font, '_');
|
||||||
|
if (g->xadvance) return (Int)g->xadvance;
|
||||||
|
return (Int)g->size.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginScissor(Rect2 rect) {
|
||||||
|
glScissor((GLint)rect.min.x, (GLint)rect.min.y, (GLsizei)(rect.max.x - rect.min.x), (GLsizei)(rect.max.y - rect.min.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndScissor() {
|
||||||
|
glScissor(0, 0, (GLsizei)WindowSize.x, (GLsizei)WindowSize.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect2 GetScreenRectF() {
|
||||||
|
Rect2 result = {0, 0, WindowSize.x, WindowSize.y};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect2I GetScreenRectI() {
|
||||||
|
Rect2I result = {0, 0, (Int)WindowSize.x, (Int)WindowSize.y};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user