Refactor text rendering to use less input data
This commit is contained in:
parent
c1b6a2add3
commit
678414f014
2 changed files with 57 additions and 40 deletions
89
main.cpp
89
main.cpp
|
|
@ -61,7 +61,7 @@ struct debug_clock_t
|
||||||
struct timespec spec;
|
struct timespec spec;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &spec);
|
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||||
start = spec.tv_sec * 1000 * 1000 + spec.tv_nsec / 1000;
|
start = spec.tv_sec * 1000 * 1000 + spec.tv_nsec / 1000;
|
||||||
|
|
||||||
}
|
}
|
||||||
~debug_clock_t()
|
~debug_clock_t()
|
||||||
{
|
{
|
||||||
|
|
@ -207,7 +207,7 @@ uint32_t make_gl_program(const char *pathname_vertex, const char *pathname_fragm
|
||||||
|
|
||||||
char *vertex_source = load_file(pathname_vertex);
|
char *vertex_source = load_file(pathname_vertex);
|
||||||
char *fragment_source = load_file(pathname_fragment);
|
char *fragment_source = load_file(pathname_fragment);
|
||||||
|
|
||||||
unsigned int vertex_shader = build_shader_from_source(vertex_source, GL_VERTEX_SHADER);
|
unsigned int vertex_shader = build_shader_from_source(vertex_source, GL_VERTEX_SHADER);
|
||||||
unsigned int fragment_shader = build_shader_from_source(fragment_source, GL_FRAGMENT_SHADER);
|
unsigned int fragment_shader = build_shader_from_source(fragment_source, GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
|
@ -237,9 +237,9 @@ uint32_t make_gl_program(const char *pathname_vertex, const char *pathname_fragm
|
||||||
void render_text(const char *text, float x, float y, float scale, glm::vec3 color)
|
void render_text(const char *text, float x, float y, float scale, glm::vec3 color)
|
||||||
{
|
{
|
||||||
// TODO: Group draw calls together instead of doing 1 draw call/character. Use an atlas with GL_TEXTURE_ARRAY
|
// TODO: Group draw calls together instead of doing 1 draw call/character. Use an atlas with GL_TEXTURE_ARRAY
|
||||||
// TODO: Do not make draw calls for invisible characters!
|
// Take tips from https://www.youtube.com/watch?v=S0PyZKX4lyI
|
||||||
|
|
||||||
// activate corresponding render state
|
// activate corresponding render state
|
||||||
glUseProgram(text_program);
|
glUseProgram(text_program);
|
||||||
glUniform3f(glGetUniformLocation(text_program, "text_color"), color.x, color.y, color.z);
|
glUniform3f(glGetUniformLocation(text_program, "text_color"), color.x, color.y, color.z);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
@ -251,31 +251,39 @@ void render_text(const char *text, float x, float y, float scale, glm::vec3 colo
|
||||||
char c = *p;
|
char c = *p;
|
||||||
charglyph_t charglyph = glyphmap[(size_t)c];
|
charglyph_t charglyph = glyphmap[(size_t)c];
|
||||||
|
|
||||||
|
if (c == ' ') // Just advance by normal horizontal distance and prepare for next char
|
||||||
|
{
|
||||||
|
x += (charglyph.advance >> 6) * scale;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
float xpos = x + charglyph.bearing.x * scale;
|
float xpos = x + charglyph.bearing.x * scale;
|
||||||
float ypos = y - (charglyph.size.y - charglyph.bearing.y) * scale;
|
float ypos = y - (charglyph.size.y - charglyph.bearing.y) * scale;
|
||||||
|
|
||||||
float w = charglyph.size.x * scale;
|
glm::mat4 transform = glm::translate(glm::mat4(1.0f), glm::vec3(xpos, ypos, 0)) * glm::scale(glm::mat4(1.0f), glm::vec3(charglyph.size.x * scale, charglyph.size.y * scale, 0));
|
||||||
float h = charglyph.size.y * scale;
|
glUniformMatrix4fv(glGetUniformLocation(text_program, "transform"), 1, GL_FALSE, &transform[0][0]);
|
||||||
|
|
||||||
// update VBO for each character
|
// update VBO for each character
|
||||||
float vertices[4][4] = {
|
// float vertices[4][4] = {
|
||||||
{ xpos, ypos + h, 0.0f, 0.0f },
|
// { xpos, ypos + h, 0.0f, 0.0f },
|
||||||
{ xpos, ypos, 0.0f, 1.0f },
|
// { xpos, ypos, 0.0f, 1.0f },
|
||||||
{ xpos + w, ypos, 1.0f, 1.0f },
|
// { xpos + w, ypos, 1.0f, 1.0f },
|
||||||
{ xpos + w, ypos + h, 1.0f, 0.0f }
|
// { xpos + w, ypos + h, 1.0f, 0.0f }
|
||||||
};
|
// };
|
||||||
// render glyph texture over quad
|
// render glyph texture over quad
|
||||||
glBindTexture(GL_TEXTURE_2D, charglyph.tex);
|
glBindTexture(GL_TEXTURE_2D, charglyph.tex);
|
||||||
// update content of VBO memory
|
// update content of VBO memory
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, textvbo);
|
glBindBuffer(GL_ARRAY_BUFFER, textvbo);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
//glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
// render quad
|
// render quad
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, 1);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
|
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
|
||||||
x += (charglyph.advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64)
|
x += (charglyph.advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64)
|
||||||
}
|
}
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -297,7 +305,7 @@ void create_grid(grid_t *grid, int rows, int columns)
|
||||||
{
|
{
|
||||||
grid->rows = rows;
|
grid->rows = rows;
|
||||||
grid->columns = columns;
|
grid->columns = columns;
|
||||||
if (!grid->hexes)
|
if (!grid->hexes)
|
||||||
grid->hexes = (hex_t*)calloc(grid->rows * grid->columns, sizeof(hex_t));
|
grid->hexes = (hex_t*)calloc(grid->rows * grid->columns, sizeof(hex_t));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -329,13 +337,13 @@ void create_grid(grid_t *grid, int rows, int columns)
|
||||||
the_hexagon->vertices[4] = the_hexagon->position + glm::vec3(radius, 0, 0);
|
the_hexagon->vertices[4] = the_hexagon->position + glm::vec3(radius, 0, 0);
|
||||||
the_hexagon->vertices[5] = the_hexagon->position + glm::vec3(radius * glm::cos(glm::radians(60.0)), -radius * glm::sin(glm::radians(60.0)), 0);
|
the_hexagon->vertices[5] = the_hexagon->position + glm::vec3(radius * glm::cos(glm::radians(60.0)), -radius * glm::sin(glm::radians(60.0)), 0);
|
||||||
the_hexagon->vertices[6] = the_hexagon->position + glm::vec3(-radius * glm::cos(glm::radians(60.0)), -radius * glm::sin(glm::radians(60.0)), 0);
|
the_hexagon->vertices[6] = the_hexagon->position + glm::vec3(-radius * glm::cos(glm::radians(60.0)), -radius * glm::sin(glm::radians(60.0)), 0);
|
||||||
|
|
||||||
glGenVertexArrays(1, &the_hexagon->vao);
|
glGenVertexArrays(1, &the_hexagon->vao);
|
||||||
glGenBuffers(1, &the_hexagon->vbo);
|
glGenBuffers(1, &the_hexagon->vbo);
|
||||||
glBindVertexArray(the_hexagon->vao);
|
glBindVertexArray(the_hexagon->vao);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, the_hexagon->vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, the_hexagon->vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 7 * 3, the_hexagon->vertices, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 7 * 3, the_hexagon->vertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
// EBO setup
|
// EBO setup
|
||||||
unsigned int indices[18];
|
unsigned int indices[18];
|
||||||
indices[0] = 0; indices[1] = 2; indices[2] = 1;
|
indices[0] = 0; indices[1] = 2; indices[2] = 1;
|
||||||
|
|
@ -348,7 +356,7 @@ void create_grid(grid_t *grid, int rows, int columns)
|
||||||
glGenBuffers(1, &the_hexagon->ebo);
|
glGenBuffers(1, &the_hexagon->ebo);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, the_hexagon->ebo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, the_hexagon->ebo);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*3 * sizeof(unsigned int), indices, GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*3 * sizeof(unsigned int), indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
@ -408,10 +416,10 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
FT_Set_Pixel_Sizes(face, 0, 48);
|
FT_Set_Pixel_Sizes(face, 0, 48);
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
|
||||||
|
|
||||||
for (unsigned char c = 0; c < 128; c++)
|
for (unsigned char c = 0; c < 128; c++)
|
||||||
{
|
{
|
||||||
// load character glyph
|
// load character glyph
|
||||||
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
|
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
|
||||||
{
|
{
|
||||||
MAIN_ERROR(ERR_CHAR_LOAD);
|
MAIN_ERROR(ERR_CHAR_LOAD);
|
||||||
|
|
@ -438,7 +446,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
// now store character for later use
|
// now store character for later use
|
||||||
charglyph_t charglyph = {
|
charglyph_t charglyph = {
|
||||||
texture,
|
texture,
|
||||||
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
|
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
|
||||||
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
|
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
|
||||||
(uint32_t)face->glyph->advance.x
|
(uint32_t)face->glyph->advance.x
|
||||||
|
|
@ -452,14 +460,21 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
// text initialization
|
// text initialization
|
||||||
text_program = make_gl_program("shaders/text.vert", "shaders/text.frag");
|
text_program = make_gl_program("shaders/text.vert", "shaders/text.frag");
|
||||||
|
|
||||||
|
static GLfloat vertex_data[] = {
|
||||||
|
0.0f, 1.0f,
|
||||||
|
0.0f, 0.0f,
|
||||||
|
1.0f, 0.0f,
|
||||||
|
1.0f, 1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
glGenVertexArrays(1, &textvao);
|
glGenVertexArrays(1, &textvao);
|
||||||
glGenBuffers(1, &textvbo);
|
glGenBuffers(1, &textvbo);
|
||||||
glBindVertexArray(textvao);
|
glBindVertexArray(textvao);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, textvbo);
|
glBindBuffer(GL_ARRAY_BUFFER, textvbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
|
@ -477,7 +492,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||||
ImGui_ImplOpenGL3_Init("#version 330 core"); // same as shader version
|
ImGui_ImplOpenGL3_Init("#version 330 core"); // same as shader version
|
||||||
|
|
||||||
double cursor_x;
|
double cursor_x;
|
||||||
double cursor_y;
|
double cursor_y;
|
||||||
camera_t the_camera;
|
camera_t the_camera;
|
||||||
|
|
@ -487,7 +502,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
static selection_t selection;
|
static selection_t selection;
|
||||||
selection.indices = (int32_t*)calloc(1, sizeof(int32_t) * grid.rows * grid.columns);
|
selection.indices = (int32_t*)calloc(1, sizeof(int32_t) * grid.rows * grid.columns);
|
||||||
selection.nselected = 0;
|
selection.nselected = 0;
|
||||||
|
|
||||||
the_camera.position = glm::vec3(0.0f, 0.0f, 1.0f);
|
the_camera.position = glm::vec3(0.0f, 0.0f, 1.0f);
|
||||||
the_camera.size = glm::vec2(1.0f, 1.0f);
|
the_camera.size = glm::vec2(1.0f, 1.0f);
|
||||||
// main loop
|
// main loop
|
||||||
|
|
@ -538,7 +553,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
cursor_dy = cursor_y;
|
cursor_dy = cursor_y;
|
||||||
|
|
||||||
glfwGetCursorPos(window, &cursor_x, &cursor_y);
|
glfwGetCursorPos(window, &cursor_x, &cursor_y);
|
||||||
|
|
||||||
cursor_dx -= cursor_x;
|
cursor_dx -= cursor_x;
|
||||||
cursor_dy -= cursor_y;
|
cursor_dy -= cursor_y;
|
||||||
|
|
||||||
|
|
@ -574,7 +589,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
proj_matrix = glm::ortho((the_camera.position.x - the_camera.size.x/2) * aspect_ratio, (the_camera.position.x + the_camera.size.x/2) * aspect_ratio, the_camera.position.y - the_camera.size.y/2, the_camera.position.y + the_camera.size.y/2);
|
proj_matrix = glm::ortho((the_camera.position.x - the_camera.size.x/2) * aspect_ratio, (the_camera.position.x + the_camera.size.x/2) * aspect_ratio, the_camera.position.y - the_camera.size.y/2, the_camera.position.y + the_camera.size.y/2);
|
||||||
|
|
||||||
glm::vec4 aux((float)cursor_x, (float)cursor_y, 0.0f, 1.0f);
|
glm::vec4 aux((float)cursor_x, (float)cursor_y, 0.0f, 1.0f);
|
||||||
|
|
||||||
// move screen coordinates to NDC
|
// move screen coordinates to NDC
|
||||||
aux.x -= window_width/2.0f;
|
aux.x -= window_width/2.0f;
|
||||||
aux.x /= window_width/2.0f;
|
aux.x /= window_width/2.0f;
|
||||||
|
|
@ -582,7 +597,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
aux.y /= -window_height/2.0f;
|
aux.y /= -window_height/2.0f;
|
||||||
aux = glm::inverse(proj_matrix) * aux;
|
aux = glm::inverse(proj_matrix) * aux;
|
||||||
cursor_world = glm::vec2(aux.x, aux.y);
|
cursor_world = glm::vec2(aux.x, aux.y);
|
||||||
|
|
||||||
glUseProgram(hex_program);
|
glUseProgram(hex_program);
|
||||||
glUniformMatrix4fv(glGetUniformLocation(hex_program, "model"), 1, GL_FALSE, &model_matrix[0][0]);
|
glUniformMatrix4fv(glGetUniformLocation(hex_program, "model"), 1, GL_FALSE, &model_matrix[0][0]);
|
||||||
glUniformMatrix4fv(glGetUniformLocation(hex_program, "view"), 1, GL_FALSE, &view_matrix[0][0]);
|
glUniformMatrix4fv(glGetUniformLocation(hex_program, "view"), 1, GL_FALSE, &view_matrix[0][0]);
|
||||||
|
|
@ -612,7 +627,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
else
|
else
|
||||||
glUniform4f(glGetUniformLocation(hex_program, "hex_color"), grid.hexes[idx].color.x, grid.hexes[idx].color.y, grid.hexes[idx].color.z, grid.hexes[idx].color.w);
|
glUniform4f(glGetUniformLocation(hex_program, "hex_color"), grid.hexes[idx].color.x, grid.hexes[idx].color.y, grid.hexes[idx].color.z, grid.hexes[idx].color.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindVertexArray(grid.hexes[idx].vao);
|
glBindVertexArray(grid.hexes[idx].vao);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, grid.hexes[idx].vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, grid.hexes[idx].vbo);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, grid.hexes[idx].ebo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, grid.hexes[idx].ebo);
|
||||||
|
|
@ -660,18 +675,18 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
render_text(buf, 25.0f, window_height - 25.0f, .5f, glm::vec3(1.0f, 1.0f, 1.0f));
|
render_text(buf, 25.0f, window_height - 25.0f, .5f, glm::vec3(1.0f, 1.0f, 1.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
static int grid_rows = grid.rows;
|
static int grid_rows = grid.rows;
|
||||||
static int grid_columns = grid.columns;
|
static int grid_columns = grid.columns;
|
||||||
|
|
||||||
if (grid_rows != grid.rows || grid_columns != grid.columns)
|
if (grid_rows != grid.rows || grid_columns != grid.columns)
|
||||||
{
|
{
|
||||||
create_grid(&grid, grid_rows, grid_columns);
|
create_grid(&grid, grid_rows, grid_columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
// Start the Dear ImGui frame
|
||||||
{
|
{
|
||||||
TIME_BLOCK(gui_render);
|
TIME_BLOCK(gui_render);
|
||||||
|
|
@ -693,7 +708,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -701,7 +716,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv)
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
ImGui_ImplGlfw_Shutdown();
|
ImGui_ImplGlfw_Shutdown();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
exit_main_with_error:
|
exit_main_with_error:
|
||||||
if (window)
|
if (window)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
#version 330 core
|
#version 330 core
|
||||||
layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
|
layout (location = 0) in vec2 vertex; // <vec2 pos>
|
||||||
out vec2 texuv;
|
out vec2 texuv;
|
||||||
|
|
||||||
|
uniform mat4 transform;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
|
gl_Position = projection * transform * vec4(vertex.xy, 0.0, 1.0);
|
||||||
texuv = vertex.zw;
|
texuv = vertex.xy;
|
||||||
|
texuv.y=1.0f-texuv.y;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue