Merge pull request #134 from kichikuou/raster

DrawDungeon14: Implement raster effect
This commit is contained in:
Nunuhara Cabbage
2023-09-01 13:42:49 -07:00
committed by GitHub
10 changed files with 178 additions and 25 deletions
+2 -1
View File
@@ -20,7 +20,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "gfx/gl.h"
#include "gfx/gfx.h"
#include "plugin.h"
struct page;
@@ -63,6 +63,7 @@ struct dungeon_context {
struct dtx *dtx;
struct tes *tes;
struct dungeon_renderer *renderer;
struct texture texture;
GLuint depth_buffer;
};
+4
View File
@@ -20,6 +20,7 @@
#include <cglm/cglm.h>
#include "gfx/gl.h"
struct texture;
struct dgn_cell;
struct dtx;
struct polyobj;
@@ -31,5 +32,8 @@ void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells
void dungeon_renderer_enable_event_markers(struct dungeon_renderer *r, bool enable);
bool dungeon_renderer_event_markers_enabled(struct dungeon_renderer *r);
bool dungeon_renderer_is_floor_opaque(struct dungeon_renderer *r, struct dgn_cell *cell);
void dungeon_renderer_run_post_processing(struct dungeon_renderer *r, struct texture *src, struct texture *dst);
void dungeon_renderer_set_raster_scroll(struct dungeon_renderer *r, int type);
void dungeon_renderer_set_raster_amp(struct dungeon_renderer *r, float amp);
#endif /* SYSTEM4_DUNGEON_RENDERER_H */
+1
View File
@@ -154,6 +154,7 @@ void gfx_copy_rot_zoom_amap(Texture *dst, Texture *src, int sx, int sy, int w, i
void gfx_copy_rot_zoom_use_amap(Texture *dst, Texture *src, int sx, int sy, int w, int h, float rotate, float mag);
void gfx_copy_root_zoom2(Texture *dst, float cx, float cy, Texture *src, float scx, float scy, float rot, float mag);
void gfx_copy_reverse_LR(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_copy_reverse_UD(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_copy_reverse_amap_LR(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_copy_rotate_y(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag);
void gfx_copy_rotate_y_use_amap(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag);
+39
View File
@@ -0,0 +1,39 @@
/* Copyright (C) 2023 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex;
uniform float amp;
uniform float t;
const float PI = 3.14159265;
in vec2 tex_coord;
out vec4 frag_color;
vec4 sample(float offset_x) {
return texture(tex, vec2(tex_coord.x + offset_x, tex_coord.y));
}
void main() {
float a = amp * cos((tex_coord.y + fract(t / 8.0)) * 16.0 * PI);
float p1 = 6.0 * tex_coord.y + 1.5;
float p2 = 4.0 * tex_coord.y + 2.0;
float offset1 = cos(p1 * 2.0 * PI) * a;
float offset2 = cos(p2 * 2.0 * PI) * a;
frag_color = mix(sample(offset1), sample(offset2), 0.5);
}
+17
View File
@@ -891,6 +891,23 @@ void gfx_copy_reverse_LR(Texture *dst, int dx, int dy, Texture *src, int sx, int
restore_blend_mode();
}
void gfx_copy_reverse_UD(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
mat4 mw_transform = MAT4(
src->w, 0, 0, -sx,
0, -src->h, 0, sy + h,
0, 0, 1, 0,
0, 0, 0, 1);
mat4 wv_transform = WV_TRANSFORM(w, h);
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
run_draw_shader(&copy_shader.s, dst, src, mw_transform, wv_transform, &data);
restore_blend_mode();
}
void gfx_copy_reverse_amap_LR(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
mat4 mw_transform = MAT4(
+8 -15
View File
@@ -62,13 +62,12 @@ struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version
if (!sp)
VM_ERROR("DrawDungeon.Init: invalid surface %d", surface);
// Dungeon scene will be rendered to this texture.
struct texture *texture = sprite_get_texture(sp);
sprite_bind_plugin(sp, &ctx->plugin);
gfx_init_texture_blank(&ctx->texture, sp->rect.w, sp->rect.h);
glGenRenderbuffers(1, &ctx->depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, ctx->depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, texture->w, texture->h);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, sp->rect.w, sp->rect.h);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
ctx->map = dungeon_map_create(version);
@@ -91,6 +90,7 @@ void dungeon_context_free(struct dungeon_context *ctx)
if (ctx->renderer)
dungeon_renderer_free(ctx->renderer);
gfx_delete_texture(&ctx->texture);
glDeleteRenderbuffers(1, &ctx->depth_buffer);
if (ctx->map)
dungeon_map_free(ctx->map);
@@ -265,10 +265,8 @@ static void dungeon_render(struct sact_sprite *sp)
struct dungeon_context *ctx = (struct dungeon_context *)sp->plugin;
if (!ctx->loaded || !ctx->draw_enabled)
return;
sprite_dirty(sp);
struct texture *texture = sprite_get_texture(sp);
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, texture, 0, 0, texture->w, texture->h);
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, &ctx->texture, 0, 0, ctx->texture.w, ctx->texture.h);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ctx->depth_buffer);
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
ERROR("Incomplete framebuffer");
@@ -281,14 +279,7 @@ static void dungeon_render(struct sact_sprite *sp)
mat4 local_transform, view_transform, proj_transform;
glm_mat4_identity(local_transform);
model_view_matrix(&ctx->camera, eye, view_transform);
glm_perspective(M_PI / 3.0, (float)texture->w / texture->h, 0.5, 100.0, proj_transform);
// Tweak the projection transform so that the rendering result is vertically
// flipped. If we render the scene normally, the resulting image will be
// bottom-up (the first pixel is at the bottom-left), but we want a top-down
// image (the first pixel is at the top-left).
proj_transform[1][1] *= -1;
glFrontFace(GL_CW);
glm_perspective(M_PI / 3.0, (float)ctx->texture.w / ctx->texture.h, 0.5, 100.0, proj_transform);
int dgn_x = round(eye[0] / 2.0);
int dgn_y = round(eye[1] / 2.0);
@@ -297,11 +288,13 @@ static void dungeon_render(struct sact_sprite *sp)
struct dgn_cell **cells = dgn_get_visible_cells(ctx->dgn, dgn_x, dgn_y, dgn_z, &nr_cells);
dungeon_renderer_render(ctx->renderer, cells, nr_cells, view_transform, proj_transform);
glFrontFace(GL_CCW);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
dungeon_renderer_run_post_processing(ctx->renderer, &ctx->texture, sprite_get_texture(sp));
sprite_dirty(sp);
}
static void neighbor_reveal(struct dungeon_context *ctx, int x, int y, int z)
+72
View File
@@ -77,6 +77,12 @@ struct geometry;
struct material;
struct object3d;
struct raster_shader {
struct shader s;
GLint amp;
GLint t;
};
struct dungeon_renderer {
struct shader shader;
// Uniform variable locations
@@ -108,6 +114,10 @@ struct dungeon_renderer {
struct material *polyobj_materials;
struct skybox *skybox;
struct raster_shader raster_shader;
bool raster_scroll;
float raster_amp;
};
static const struct marker_info *get_marker_info(struct dungeon_renderer *r, int event_type)
@@ -402,6 +412,8 @@ void dungeon_renderer_free(struct dungeon_renderer *r)
free(r->polyobj_materials);
skybox_free(r->skybox);
if (r->raster_shader.s.program)
glDeleteProgram(r->raster_shader.s.program);
free(r);
}
@@ -719,3 +731,63 @@ bool dungeon_renderer_is_floor_opaque(struct dungeon_renderer *r, struct dgn_cel
struct material *material = get_material(r, DTX_FLOOR, cell->floor);
return material && material->opaque;
}
static void prepare_raster_shader(struct gfx_render_job *job, void *data)
{
struct dungeon_renderer *r = data;
float width = job->world_transform[0];
glUniform1f(r->raster_shader.amp, r->raster_amp / width);
glUniform1f(r->raster_shader.t, SDL_GetTicks() / 1000.f);
}
static void load_raster_shader(struct raster_shader *s)
{
gfx_load_shader(&s->s, "shaders/render.v.glsl", "shaders/dungeon_raster.f.glsl");
s->amp = glGetUniformLocation(s->s.program, "amp");
s->t = glGetUniformLocation(s->s.program, "t");
s->s.prepare = prepare_raster_shader;
}
void dungeon_renderer_run_post_processing(struct dungeon_renderer *r, struct texture *src, struct texture *dst)
{
// This function flips the image upside down, because the image in `src`
// (rendered by dungeon_renderer_render) is bottom-up (the first pixel is at
// the bottom-left), but sprite textures are top-down (the first pixel is at
// the top-left).
if (r->raster_scroll) {
mat4 mw_transform = MAT4(
src->w, 0, 0, 0,
0, -src->h, 0, src->h, // flip vertically
0, 0, 1, 0,
0, 0, 0, 1);
mat4 wv_transform = WV_TRANSFORM(src->w, src->h);
struct gfx_render_job job = {
.shader = &r->raster_shader.s,
.shape = GFX_RECTANGLE,
.texture = src->handle,
.world_transform = mw_transform[0],
.view_transform = wv_transform[0],
.data = r
};
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, dst, 0, 0, dst->w, dst->h);
gfx_render(&job);
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
} else {
gfx_copy_reverse_UD(dst, 0, 0, src, 0, 0, src->w, src->h);
}
}
void dungeon_renderer_set_raster_scroll(struct dungeon_renderer *r, int type)
{
r->raster_scroll = !!type;
if (r->raster_scroll && !r->raster_shader.s.program) {
load_raster_shader(&r->raster_shader);
}
}
void dungeon_renderer_set_raster_amp(struct dungeon_renderer *r, float amp)
{
r->raster_amp = amp;
}
+21 -5
View File
@@ -267,7 +267,8 @@ HLL_QUIET_UNIMPLEMENTED(1, bool, DrawDungeon, IsDrawSettingFile, void);
HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, DeleteDrawSettingFile, void);
HLL_QUIET_UNIMPLEMENTED(1, bool, DrawDungeon, IsSSEFlag, void);
HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, SetSSEFlag, bool flag);
bool DrawDungeon_IsPVSData(int surface)
static bool DrawDungeon_IsPVSData(int surface)
{
return false;
}
@@ -408,11 +409,26 @@ HLL_LIBRARY(DrawDungeon,
DRAW_DUNGEON_EXPORTS
);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetRasterScroll, int surface, int type);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetRasterAmp, int nSurface, float fAmp);
static void DrawDungeon14_SetRasterScroll(int surface, int type)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->renderer)
return true;
return dungeon_renderer_set_raster_scroll(ctx->renderer, type);
}
static void DrawDungeon14_SetRasterAmp(int surface, float amp)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->renderer)
return true;
return dungeon_renderer_set_raster_amp(ctx->renderer, amp);
}
// unused
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetLapFilter, int surface, int type, int r, int g, int b);
bool DrawDungeon14_GetDrawMapObjectFlag(int surface)
static bool DrawDungeon14_GetDrawMapObjectFlag(int surface)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->renderer)
@@ -420,7 +436,7 @@ bool DrawDungeon14_GetDrawMapObjectFlag(int surface)
return dungeon_renderer_event_markers_enabled(ctx->renderer);
}
void DrawDungeon14_SetDrawMapObjectFlag(int surface, bool flag)
static void DrawDungeon14_SetDrawMapObjectFlag(int surface, bool flag)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->renderer)
+5 -2
View File
@@ -338,7 +338,10 @@ static void DrawGraph_CopyReverseLR(int dst, int dx, int dy, int src, int sx, in
gfx_copy_reverse_LR(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
//void DrawGraph_CopyReverseUD(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
static void DrawGraph_CopyReverseUD(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_copy_reverse_UD(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_CopyReverseAMapLR(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
@@ -495,7 +498,7 @@ HLL_LIBRARY(DrawGraph,
//HLL_EXPORT(CopyRotateXFixUUseAMap, DrawGraph_CopyRotateXFixUUseAMap),
//HLL_EXPORT(CopyRotateXFixDUseAMap, DrawGraph_CopyRotateXFixDUseAMap),
HLL_EXPORT(CopyReverseLR, DrawGraph_CopyReverseLR),
//HLL_EXPORT(CopyReverseUD, DrawGraph_CopyReverseUD),
HLL_EXPORT(CopyReverseUD, DrawGraph_CopyReverseUD),
HLL_EXPORT(CopyReverseAMapLR, DrawGraph_CopyReverseAMapLR),
//HLL_EXPORT(CopyReverseAMapUD, DrawGraph_CopyReverseAMapUD),
HLL_EXPORT(CopyWidthBlur, DrawGraph_CopyWidthBlur),
+9 -2
View File
@@ -372,7 +372,14 @@ static void Gpx2Plus_CopyReverseLR(int destSurface, int dx, int dy, int srcSurfa
gfx_copy_reverse_LR(dst, dx, dy, src, sx, sy, width, height);
}
// void CopyReverseUD(int nDestSurface, int nDx, int nDy, int nSrcSurface, int nSx, int nSy, int nWidth, int nHeight);
static void Gpx2Plus_CopyReverseUD(int destSurface, int dx, int dy, int srcSurface, int sx, int sy, int width, int height)
{
struct texture *dst = get_texture(destSurface);
struct texture *src = get_texture(srcSurface);
if (!dst || !src)
return;
gfx_copy_reverse_UD(dst, dx, dy, src, sx, sy, width, height);
}
static void Gpx2Plus_CopyReverseAMapLR(int destSurface, int dx, int dy, int srcSurface, int sx, int sy, int width, int height)
{
@@ -745,7 +752,7 @@ HLL_LIBRARY(Gpx2Plus,
HLL_EXPORT(CopyStretchReduce, Gpx2Plus_CopyStretchReduce),
HLL_EXPORT(CopyStretchReduceAMap, Gpx2Plus_CopyStretchReduceAMap),
HLL_EXPORT(CopyReverseLR, Gpx2Plus_CopyReverseLR),
// HLL_EXPORT(CopyReverseUD, Gpx2Plus_CopyReverseUD),
HLL_EXPORT(CopyReverseUD, Gpx2Plus_CopyReverseUD),
HLL_EXPORT(CopyReverseAMapLR, Gpx2Plus_CopyReverseAMapLR),
// HLL_EXPORT(CopyReverseAMapUD, Gpx2Plus_CopyReverseAMapUD),
// HLL_EXPORT(BlendScreenWDS, Gpx2Plus_BlendScreenWDS),