mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
gfx: Add gfx_render_quadrilateral()
It draws a quadrilateral with arbitrary vertex and texture coordinates. This is used to properly implement DrawGraph.DrawDeformedSpriteBilinear, and will be used to implement ChipmunkSpriteEngine. SP_SetSpriteTransformPos in a subsequent patch.
This commit is contained in:
+10
-1
@@ -48,13 +48,15 @@ typedef struct shader {
|
||||
GLuint world_transform;
|
||||
GLuint view_transform;
|
||||
GLuint texture;
|
||||
GLuint vertex;
|
||||
GLuint vertex_pos;
|
||||
GLuint vertex_uv;
|
||||
void (*prepare)(struct gfx_render_job *, void *);
|
||||
} Shader;
|
||||
|
||||
enum gfx_shape {
|
||||
GFX_RECTANGLE,
|
||||
GFX_LINE,
|
||||
GFX_QUADRILATERAL,
|
||||
};
|
||||
|
||||
struct gfx_render_job {
|
||||
@@ -66,6 +68,11 @@ struct gfx_render_job {
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct gfx_vertex {
|
||||
GLfloat x, y, z, w;
|
||||
GLfloat u, v;
|
||||
};
|
||||
|
||||
int gfx_init(void);
|
||||
void gfx_fini(void);
|
||||
|
||||
@@ -90,6 +97,7 @@ void gfx_run_job(struct gfx_render_job *job);
|
||||
void gfx_render(struct gfx_render_job *job);
|
||||
void _gfx_render_texture(struct shader *s, struct texture *t, Rectangle *r, void *data);
|
||||
void gfx_render_texture(struct texture *t, Rectangle *r);
|
||||
void gfx_render_quadrilateral(struct texture *t, struct gfx_vertex vertices[4]);
|
||||
|
||||
// texture management
|
||||
void gfx_init_texture_blank(struct texture *t, int w, int h);
|
||||
@@ -179,5 +187,6 @@ void gfx_draw_line_to_amap(Texture *dst, int x0, int y0, int x1, int y1, int a);
|
||||
void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width, bool blend);
|
||||
void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, SDL_Color color, float scale_x);
|
||||
void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, float scale_x);
|
||||
void gfx_draw_quadrilateral(Texture *dst, Texture *src, struct gfx_vertex vertices[4]);
|
||||
|
||||
#endif /* SYSTEM4_SDL_CORE_H */
|
||||
|
||||
@@ -31,6 +31,7 @@ struct sdl_private {
|
||||
SDL_GLContext context;
|
||||
GLuint vao;
|
||||
GLuint vbo;
|
||||
GLuint quad_vbo;
|
||||
GLuint rect_ibo;
|
||||
GLuint line_ibo;
|
||||
} gl;
|
||||
|
||||
@@ -18,9 +18,10 @@ uniform mat4 world_transform;
|
||||
uniform mat4 view_transform;
|
||||
|
||||
in vec4 vertex_pos;
|
||||
in vec2 vertex_uv;
|
||||
out vec2 tex_coord;
|
||||
|
||||
void main() {
|
||||
gl_Position = view_transform * world_transform * vertex_pos;
|
||||
tex_coord = vertex_pos.xy;
|
||||
tex_coord = vertex_uv;
|
||||
}
|
||||
|
||||
@@ -1146,6 +1146,15 @@ void gfx_draw_line_to_amap(Texture *dst, int x0, int y0, int x1, int y1, int a)
|
||||
restore_blend_mode();
|
||||
}
|
||||
|
||||
void gfx_draw_quadrilateral(Texture *dst, Texture *src, struct gfx_vertex vertices[4])
|
||||
{
|
||||
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ONE);
|
||||
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, dst, 0, 0, dst->w, dst->h);
|
||||
gfx_render_quadrilateral(src, vertices);
|
||||
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||
restore_blend_mode();
|
||||
}
|
||||
|
||||
// XXX: Not an actual DrawGraph function; used for rendering text
|
||||
void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width, bool blend)
|
||||
{
|
||||
|
||||
@@ -89,8 +89,6 @@ struct dungeon_renderer {
|
||||
GLint local_transform;
|
||||
GLint proj_transform;
|
||||
GLuint alpha_mod;
|
||||
// Attribute variable locations
|
||||
GLint vertex_uv;
|
||||
|
||||
struct geometry *wall_geometry;
|
||||
struct geometry *door_left_geometry;
|
||||
@@ -221,10 +219,10 @@ static struct geometry *geometry_create(struct dungeon_renderer *r, const struct
|
||||
glGenBuffers(1, &g->attr_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g->attr_buffer);
|
||||
|
||||
glEnableVertexAttribArray(r->shader.vertex);
|
||||
glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)0);
|
||||
glEnableVertexAttribArray(r->vertex_uv);
|
||||
glVertexAttribPointer(r->vertex_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)(3 * sizeof(GLfloat)));
|
||||
glEnableVertexAttribArray(r->shader.vertex_pos);
|
||||
glVertexAttribPointer(r->shader.vertex_pos, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)0);
|
||||
glEnableVertexAttribArray(r->shader.vertex_uv);
|
||||
glVertexAttribPointer(r->shader.vertex_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)(3 * sizeof(GLfloat)));
|
||||
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
|
||||
|
||||
glBindVertexArray(0);
|
||||
@@ -350,7 +348,6 @@ struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version versi
|
||||
r->local_transform = glGetUniformLocation(r->shader.program, "local_transform");
|
||||
r->proj_transform = glGetUniformLocation(r->shader.program, "proj_transform");
|
||||
r->alpha_mod = glGetUniformLocation(r->shader.program, "alpha_mod");
|
||||
r->vertex_uv = glGetAttribLocation(r->shader.program, "vertex_uv");
|
||||
|
||||
r->wall_geometry = geometry_create(r, wall_vertices, sizeof(wall_vertices), GL_TRIANGLE_STRIP);
|
||||
r->door_left_geometry = geometry_create(r, door_left_vertices, sizeof(door_left_vertices), GL_TRIANGLE_STRIP);
|
||||
|
||||
@@ -63,8 +63,8 @@ struct skybox *skybox_create(struct dtx *dtx)
|
||||
glGenBuffers(1, &s->attr_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s->attr_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(s->shader.vertex);
|
||||
glVertexAttribPointer(s->shader.vertex, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glEnableVertexAttribArray(s->shader.vertex_pos);
|
||||
glVertexAttribPointer(s->shader.vertex_pos, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glGenBuffers(1, &s->index_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
|
||||
|
||||
+7
-9
@@ -437,15 +437,13 @@ static void DrawGraph_DrawDeformedSpriteBilinear(int dst, int tex,
|
||||
float x2, float y2, float z2, float u2, float v2,
|
||||
float x3, float y3, float z3, float u3, float v3)
|
||||
{
|
||||
if (x0 == x2 && x1 == x3 && x0 <= x1 &&
|
||||
y0 == y1 && y2 == y3 && y0 <= y2 &&
|
||||
z0 == 0.f && z1 == 0.f && z2 == 0.f && z3 == 0.f &&
|
||||
u0 == u2 && u1 == u3 && u0 <= u1 &&
|
||||
v0 == v1 && v2 == v3 && v0 <= v2) {
|
||||
gfx_copy_stretch(DTEX(dst), x0, y0, x3 - x0, y3 - y0, STEX(tex), u0, v0, u3 - u0, v3 - v0);
|
||||
} else {
|
||||
WARNING("DrawGraph.DrawDeformedSpriteBilinear: Non-rectangular deformation is not implemented");
|
||||
}
|
||||
struct gfx_vertex vertices[4] = {
|
||||
{x0, y0, z0, 1.f, u0, v0},
|
||||
{x1, y1, z1, 1.f, u1, v1},
|
||||
{x2, y2, z2, 1.f, u2, v2},
|
||||
{x3, y3, z3, 1.f, u3, v3}
|
||||
};
|
||||
gfx_draw_quadrilateral(DTEX(dst), STEX(tex), vertices);
|
||||
}
|
||||
|
||||
//void DrawGraph_BlendAMapDeformedSpriteBilinear(int dst, int tex, float x0, float y0, float z0, float u0, float v0, float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3);
|
||||
|
||||
+50
-13
@@ -127,7 +127,8 @@ void gfx_load_shader(struct shader *dst, const char *vertex_shader_path, const c
|
||||
dst->world_transform = glGetUniformLocation(program, "world_transform");
|
||||
dst->view_transform = glGetUniformLocation(program, "view_transform");
|
||||
dst->texture = glGetUniformLocation(program, "tex");
|
||||
dst->vertex = glGetAttribLocation(program, "vertex_pos");
|
||||
dst->vertex_pos = glGetAttribLocation(program, "vertex_pos");
|
||||
dst->vertex_uv = glGetAttribLocation(program, "vertex_uv");
|
||||
dst->prepare = NULL;
|
||||
}
|
||||
|
||||
@@ -135,22 +136,24 @@ static int gl_initialize(void)
|
||||
{
|
||||
gfx_load_shader(&default_shader, "shaders/render.v.glsl", "shaders/render.f.glsl");
|
||||
|
||||
GLfloat vertex_data[] = {
|
||||
0.f, 0.f, 0.f, 1.f,
|
||||
1.f, 0.f, 0.f, 1.f,
|
||||
1.f, 1.f, 0.f, 1.f,
|
||||
0.f, 1.f, 0.f, 1.f
|
||||
const struct gfx_vertex vertex_data[] = {
|
||||
// x, y, z, w, u, v
|
||||
{ 0.f, 0.f, 0.f, 1.f, 0.f, 0.f },
|
||||
{ 1.f, 0.f, 0.f, 1.f, 1.f, 0.f },
|
||||
{ 0.f, 1.f, 0.f, 1.f, 0.f, 1.f },
|
||||
{ 1.f, 1.f, 0.f, 1.f, 1.f, 1.f }
|
||||
};
|
||||
|
||||
GLuint rect_index_data[] = { 0, 1, 2, 3 };
|
||||
GLuint line_index_data[] = { 0, 2 };
|
||||
const GLuint rect_index_data[] = { 0, 1, 3, 2 };
|
||||
const GLuint line_index_data[] = { 0, 3 };
|
||||
|
||||
glGenVertexArrays(1, &sdl.gl.vao);
|
||||
glBindVertexArray(sdl.gl.vao);
|
||||
|
||||
glGenBuffers(1, &sdl.gl.vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, sdl.gl.vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(GLfloat), vertex_data, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
|
||||
glGenBuffers(1, &sdl.gl.quad_vbo);
|
||||
|
||||
glGenBuffers(1, &sdl.gl.rect_ibo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sdl.gl.rect_ibo);
|
||||
@@ -465,13 +468,16 @@ void gfx_prepare_job(struct gfx_render_job *job)
|
||||
void gfx_run_job(struct gfx_render_job *job)
|
||||
{
|
||||
glBindVertexArray(sdl.gl.vao);
|
||||
glEnableVertexAttribArray(job->shader->vertex);
|
||||
glEnableVertexAttribArray(job->shader->vertex_pos);
|
||||
glEnableVertexAttribArray(job->shader->vertex_uv);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, sdl.gl.vbo);
|
||||
glVertexAttribPointer(job->shader->vertex, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), NULL);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, job->shape == GFX_QUADRILATERAL ? sdl.gl.quad_vbo : sdl.gl.vbo);
|
||||
glVertexAttribPointer(job->shader->vertex_pos, 4, GL_FLOAT, GL_FALSE, sizeof(struct gfx_vertex), NULL);
|
||||
glVertexAttribPointer(job->shader->vertex_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct gfx_vertex), (void*)offsetof(struct gfx_vertex, u));
|
||||
|
||||
switch (job->shape) {
|
||||
case GFX_RECTANGLE:
|
||||
case GFX_QUADRILATERAL:
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sdl.gl.rect_ibo);
|
||||
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, NULL);
|
||||
break;
|
||||
@@ -481,7 +487,8 @@ void gfx_run_job(struct gfx_render_job *job)
|
||||
break;
|
||||
}
|
||||
|
||||
glDisableVertexAttribArray(job->shader->vertex);
|
||||
glDisableVertexAttribArray(job->shader->vertex_pos);
|
||||
glDisableVertexAttribArray(job->shader->vertex_uv);
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
@@ -525,6 +532,36 @@ void gfx_render_texture(struct texture *t, Rectangle *r)
|
||||
_gfx_render_texture(&default_shader, t, r, t);
|
||||
}
|
||||
|
||||
void gfx_render_quadrilateral(struct texture *t, struct gfx_vertex vertices[4])
|
||||
{
|
||||
if (!t->handle) {
|
||||
WARNING("Attempted to render uninitialized texture");
|
||||
return;
|
||||
}
|
||||
|
||||
// Normalize the texture coordinates to [0, 1]
|
||||
struct gfx_vertex buf[4];
|
||||
memcpy(buf, vertices, sizeof(struct gfx_vertex) * 4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
buf[i].u /= t->w;
|
||||
buf[i].v /= t->h;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, sdl.gl.quad_vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_DYNAMIC_DRAW);
|
||||
|
||||
mat4 world_transform = GLM_MAT4_IDENTITY_INIT;
|
||||
struct gfx_render_job job = {
|
||||
.shader = &default_shader,
|
||||
.shape = GFX_QUADRILATERAL,
|
||||
.texture = t->handle,
|
||||
.world_transform = world_transform[0],
|
||||
.view_transform = world_view_transform[0],
|
||||
.data = t
|
||||
};
|
||||
gfx_render(&job);
|
||||
}
|
||||
|
||||
static void init_texture(struct texture *t, int w, int h)
|
||||
{
|
||||
glGenTextures(1, &t->handle);
|
||||
|
||||
Reference in New Issue
Block a user