mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
Merge pull request #134 from kichikuou/raster
DrawDungeon14: Implement raster effect
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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(©_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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user