From b5f226ff7907167423235134c2b3f5dfc5c63033 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 12 Jun 2021 10:35:53 +0900 Subject: [PATCH 01/13] Fix SACT2.SP_GetMaxZ It should return the maximum Z value among all sprites, not among visible sprites. This fixes a bug in Rance VI where some UI elements are incorrectly Z-ordered. --- include/sact.h | 2 +- include/scene.h | 1 - src/hll/SACT2.c | 10 ++++++++++ src/scene.c | 7 ------- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/sact.h b/include/sact.h index 9592f2a..1bda29f 100644 --- a/include/sact.h +++ b/include/sact.h @@ -35,7 +35,7 @@ int sact_Effect(int type, int time, int key); int sact_SP_GetUnuseNum(int min); int sact_SP_Count(void); int sact_SP_Enum(struct page **array); -#define sact_SP_GetMaxZ scene_get_max_z +int sact_SP_GetMaxZ(void); int sact_SP_SetCG(int sp, int cg); int sact_SP_SetCGFromFile(int sp, struct string *filename); int sact_SP_SaveCG(int sp, struct string *filename); diff --git a/include/scene.h b/include/scene.h index 4e912f5..d141f09 100644 --- a/include/scene.h +++ b/include/scene.h @@ -47,7 +47,6 @@ void scene_render(void); void scene_flip(void); int scene_set_wp(int cg_no); int scene_set_wp_color(int r, int g, int b); -int scene_get_max_z(void); void scene_set_sprite_z(struct sprite *sp, int z); void scene_set_sprite_z2(struct sprite *sp, int z, int z2); diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index 867e3b6..24bb86c 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -183,6 +183,16 @@ int sact_SP_Enum(struct page **array) return count; } +int sact_SP_GetMaxZ(void) +{ + int max_z = 0; + for (int i = 0; i < nr_sprites; i++) { + if (sprites[i] && max_z < sprites[i]->sp.z) + max_z = sprites[i]->sp.z; + } + return max_z; +} + int sact_SP_SetCG(int sp_no, int cg_no) { struct sact_sprite *sp = sact_get_sprite(sp_no); diff --git a/src/scene.c b/src/scene.c index 50c3817..3feecbe 100644 --- a/src/scene.c +++ b/src/scene.c @@ -112,13 +112,6 @@ int scene_set_wp_color(int r, int g, int b) return 1; } -int scene_get_max_z(void) -{ - if (TAILQ_EMPTY(&sprite_list)) - return 0; - return TAILQ_LAST(&sprite_list, listhead)->z; -} - void scene_set_sprite_z(struct sprite *sp, int z) { sp->z = z; From 4d139a0dddc290291934c5f4f59e71bc82418e12 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 13 Jun 2021 11:36:45 +0900 Subject: [PATCH 02/13] Implement DrawGraph.SpriteCopyAMap Used in GALZOO Island. --- include/gfx/gfx.h | 1 + shaders/copy_alpha_key.f.glsl | 30 ++++++++++++++++++++++++++++++ src/draw.c | 15 +++++++++++++++ src/hll/DrawGraph.c | 9 +++++++-- 4 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 shaders/copy_alpha_key.f.glsl diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h index 97fc1d9..5222c45 100644 --- a/include/gfx/gfx.h +++ b/include/gfx/gfx.h @@ -102,6 +102,7 @@ void gfx_copy(struct texture *dst, int dx, int dy, struct texture *src, int sx, void gfx_copy_bright(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h, int rate); void gfx_copy_amap(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h); void gfx_copy_sprite(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h, SDL_Color color); +void gfx_sprite_copy_amap(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h, int alpha_key); void gfx_copy_color_reverse(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h); void gfx_copy_use_amap_under(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h, int threshold); void gfx_copy_use_amap_border(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h, int threshold); diff --git a/shaders/copy_alpha_key.f.glsl b/shaders/copy_alpha_key.f.glsl new file mode 100644 index 0000000..2aaeaeb --- /dev/null +++ b/shaders/copy_alpha_key.f.glsl @@ -0,0 +1,30 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * 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 . + */ + +#version 140 + +uniform sampler2D tex; +uniform vec4 color; + +in vec2 tex_coord; +out vec4 frag_color; + +void main() { + vec4 texel = texture(tex, tex_coord); + if (texel.a == color.a) + discard; + frag_color = texel; +} diff --git a/src/draw.c b/src/draw.c index cfc80b0..3485cdb 100644 --- a/src/draw.c +++ b/src/draw.c @@ -59,6 +59,7 @@ struct copy_data { static struct copy_shader copy_shader; static struct copy_shader copy_color_reverse_shader; static struct copy_shader copy_key_shader; +static struct copy_shader copy_alpha_key_shader; static struct copy_shader copy_use_amap_under_shader; static struct copy_shader copy_use_amap_border_shader; static struct copy_shader blend_amap_color_shader; @@ -102,6 +103,9 @@ void gfx_draw_init(void) // copy shader which also discards fragments matching a color key load_copy_shader(©_key_shader, "shaders/render.v.glsl", "shaders/copy_key.f.glsl"); + // copy shader which also discards fragments matching an alpha key + load_copy_shader(©_alpha_key_shader, "shaders/render.v.glsl", "shaders/copy_alpha_key.f.glsl"); + // copy shader that only keeps fragments below a certain alpha threshold load_copy_shader(©_use_amap_under_shader, "shaders/render.v.glsl", "shaders/copy_use_amap_under.f.glsl"); @@ -226,6 +230,17 @@ void gfx_copy_sprite(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, restore_blend_mode(); } +void gfx_sprite_copy_amap(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int alpha_key) +{ + glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ZERO); + + struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h); + data.a = alpha_key / 255.0; + run_copy_shader(©_alpha_key_shader.s, dst, src, &data); + + restore_blend_mode(); +} + void gfx_copy_color_reverse(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h) { glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ONE); diff --git a/src/hll/DrawGraph.c b/src/hll/DrawGraph.c index f83d3c8..5880648 100644 --- a/src/hll/DrawGraph.c +++ b/src/hll/DrawGraph.c @@ -232,7 +232,12 @@ static void DrawGraph_FillAMapUnderBorder(int dst, int x, int y, int w, int h, i //void DrawGraph_FillMultiply(int dst, int x, int y, int w, int h, int r, int g, int b); //void DrawGraph_SaturDP_DPxSA(int dst, int dx, int dy, int src, int sx, int sy, int w, int h); //void DrawGraph_ScreenDA_DAxSA(int dst, int dx, int dy, int src, int sx, int sy, int w, int h); -//void DrawGraph_SpriteCopyAMap(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int key); + +static void DrawGraph_SpriteCopyAMap(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int key) +{ + gfx_sprite_copy_amap(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, key); +} + //void DrawGraph_BrightDestOnly(int dst, int x, int y, int w, int h, int rate); //void DrawGraph_CopyTextureWrap(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh, int u, int v); //void DrawGraph_CopyTextureWrapAlpha(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh, int u, int v, int alpha); @@ -351,7 +356,7 @@ HLL_LIBRARY(DrawGraph, //HLL_EXPORT(SaturDP_DPxSA, DrawGraph_SaturDP_DPxSA), //HLL_EXPORT(ScreenDA_DAxSA, DrawGraph_ScreenDA_DAxSA), HLL_EXPORT(AddDA_DAxSA, DrawGraph_AddDA_DAxSA), - //HLL_EXPORT(SpriteCopyAMap, DrawGraph_SpriteCopyAMap), + HLL_EXPORT(SpriteCopyAMap, DrawGraph_SpriteCopyAMap), HLL_EXPORT(BlendDA_DAxSA, DrawGraph_BlendDA_DAxSA), HLL_EXPORT(SubDA_DAxSA, DrawGraph_SubDA_DAxSA), //HLL_EXPORT(BrightDestOnly, DrawGraph_BrightDestOnly), From 66d6fc38da775d359163e15c0f486e48ea2cd0cb Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 13 Jun 2021 13:14:57 +0900 Subject: [PATCH 03/13] Implement DrawSimpleText HLL Used in GALZOO Island. --- src/ffi.c | 2 + src/hll/DrawSimpleText.c | 87 ++++++++++++++++++++++++++++++++++++++++ src/meson.build | 1 + 3 files changed, 90 insertions(+) create mode 100644 src/hll/DrawSimpleText.c diff --git a/src/ffi.c b/src/ffi.c index 6a72327..42fd856 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -294,6 +294,7 @@ extern struct static_library lib_DrawDungeon; extern struct static_library lib_DrawGraph; extern struct static_library lib_DrawMovie2; extern struct static_library lib_DrawPluginManager; +extern struct static_library lib_DrawSimpleText; extern struct static_library lib_File; extern struct static_library lib_FileOperation; extern struct static_library lib_GoatGUIEngine; @@ -341,6 +342,7 @@ static struct static_library *static_libraries[] = { &lib_DrawGraph, &lib_DrawMovie2, &lib_DrawPluginManager, + &lib_DrawSimpleText, &lib_File, &lib_FileOperation, &lib_GoatGUIEngine, diff --git a/src/hll/DrawSimpleText.c b/src/hll/DrawSimpleText.c new file mode 100644 index 0000000..3e740eb --- /dev/null +++ b/src/hll/DrawSimpleText.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2021 kichikuou + * + * 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 . + */ + +#include "system4/string.h" + +#include "hll.h" +#include "gfx/gfx.h" +#include "sact.h" + +static int size = 20; +static int weight = 1; // in pixels +static int pitch = 0; + +static bool DrawSimpleText_DrawToAlphaMap(int sp_no, int x, int y, struct string *s) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) + return NULL; + sprite_dirty(sp); + + int orig_weight = gfx_get_font_weight(); + int orig_size = gfx_get_font_size(); + int orig_space = gfx_get_font_space(); + gfx_set_font_weight(weight <= 1 ? FW_NORMAL : FW_BOLD); + gfx_set_font_size(size); + gfx_set_font_space(pitch); + + gfx_draw_text_to_amap(sprite_get_texture(sp), x, y, s->text); + + gfx_set_font_weight(orig_weight); + gfx_set_font_size(orig_size); + gfx_set_font_space(orig_space); + return true; +} + +static void DrawSimpleText_SetSize(int n) +{ + size = n; +} + +static int DrawSimpleText_GetSize(void) +{ + return size; +} + +static void DrawSimpleText_SetWeight(int n) +{ + weight = n; +} + +static int DrawSimpleText_GetWeight(void) +{ + return weight; +} + +static void DrawSimpleText_SetPitch(int n) +{ + pitch = n; +} + +static int DrawSimpleText_GetPitch(void) +{ + return pitch; +} + +HLL_LIBRARY(DrawSimpleText, + HLL_EXPORT(DrawToAlphaMap, DrawSimpleText_DrawToAlphaMap), + HLL_EXPORT(SetSize, DrawSimpleText_SetSize), + HLL_EXPORT(GetSize, DrawSimpleText_GetSize), + HLL_EXPORT(SetWeight, DrawSimpleText_SetWeight), + HLL_EXPORT(GetWeight, DrawSimpleText_GetWeight), + HLL_EXPORT(SetPitch, DrawSimpleText_SetPitch), + HLL_EXPORT(GetPitch, DrawSimpleText_GetPitch) + ); diff --git a/src/meson.build b/src/meson.build index 01b2a3d..ad68edc 100644 --- a/src/meson.build +++ b/src/meson.build @@ -47,6 +47,7 @@ xsystem4 = ['audio.c', 'hll/DrawGraph.c', 'hll/DrawMovie2.c', 'hll/DrawPluginManager.c', + 'hll/DrawSimpleText.c', 'hll/File.c', 'hll/FileOperation.c', 'hll/GoatGUIEngine.c', From 09adefe4783e5500b5c7d3fbdd6f1be05fc48370 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 13 Jun 2021 14:15:49 +0900 Subject: [PATCH 04/13] Implement Math.BezierCurve Used in GALZOO Island. --- src/hll/Math.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/hll/Math.c b/src/hll/Math.c index cddcf2b..04f90f7 100644 --- a/src/hll/Math.c +++ b/src/hll/Math.c @@ -17,12 +17,14 @@ #include #include #include +#include #ifndef M_PI #define M_PI (3.14159265358979323846) #endif #include "hll.h" +#include "vm/page.h" struct shuffle_table { int id; @@ -150,11 +152,31 @@ static int Math_RandTable(int num) //void Math_RandTable2Init(int num, struct page *array); //int Math_RandTable2(int num); -int Math_Ceil(float f) +static int Math_Ceil(float f) { return (int)ceilf(f); } +static bool Math_BezierCurve(struct page **x_array, struct page **y_array, int num, float t, int *result_x, int *result_y) +{ + vec2 *coeffs = xmalloc(num * sizeof(vec2)); + for (int i = 0; i < num; i++) { + coeffs[i][0] = (*x_array)->values[i].i; + coeffs[i][1] = (*y_array)->values[i].i; + } + + // De Casteljau's algorithm. + for (; num > 1; num--) { + for (int i = 0; i < num - 1; i++) + glm_vec2_lerp(coeffs[i], coeffs[i + 1], t, coeffs[i]); + } + *result_x = coeffs[0][0]; + *result_y = coeffs[0][1]; + + free(coeffs); + return true; +} + HLL_LIBRARY(Math, HLL_EXPORT(Cos, Math_Cos), HLL_EXPORT(Sin, Math_Sin), @@ -181,5 +203,6 @@ HLL_LIBRARY(Math, HLL_EXPORT(SwapF, Math_SwapF), HLL_EXPORT(Log, logf), HLL_EXPORT(Log10, log10f), - HLL_EXPORT(Ceil, Math_Ceil)); + HLL_EXPORT(Ceil, Math_Ceil), + HLL_EXPORT(BezierCurve, Math_BezierCurve)); From fb94881f9f888e1b5bad425bf19ca71bdc8d14b1 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 12 Jun 2021 22:20:46 +0900 Subject: [PATCH 05/13] Remove flip_y field from texture It was introduced to flip texture image rendered by DrawDungeon when presenting on the screen. In GALZOO this approach does not work because dungeon texture is also used as the source image of gfx functions. After this, DrawDungeon directly generates vertically flipped image, by tweaking the projection matrix. --- include/gfx/gfx.h | 1 - src/dungeon/dungeon.c | 17 +++++++++-------- src/video.c | 10 ---------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h index 5222c45..e93d2d1 100644 --- a/include/gfx/gfx.h +++ b/include/gfx/gfx.h @@ -38,7 +38,6 @@ typedef struct texture { mat4 world_transform; int w, h; bool has_alpha; - bool flip_y; int alpha_mod; enum draw_method draw_method; } Texture; diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index 3cb1003..976947e 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -50,11 +50,8 @@ struct dungeon_context *dungeon_context_create(int surface) if (!sp) VM_ERROR("DrawDungeon.Init: invalid surface %d", surface); - // Dungeon scene will be rendered to this texture. Unlike other textures, - // its (0,0) is at the bottom-left, so it needs to be flipped vertically - // when displayed on the screen. + // Dungeon scene will be rendered to this texture. struct texture *texture = sprite_get_texture(sp); - texture->flip_y = true; glGenRenderbuffers(1, &ctx->depth_buffer); glBindRenderbuffer(GL_RENDERBUFFER, ctx->depth_buffer); @@ -80,10 +77,6 @@ void dungeon_context_free(struct dungeon_context *ctx) glDeleteRenderbuffers(1, &ctx->depth_buffer); dungeon_map_free(ctx->map); - struct sact_sprite *sp = sact_get_sprite(ctx->surface); - if (sp) - sprite_get_texture(sp)->flip_y = false; - free(ctx); } @@ -226,6 +219,13 @@ void dungeon_render(struct dungeon_context *ctx) model_view_matrix(&ctx->camera, 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); + int dgn_x = round(ctx->camera.pos[0] / 2.0); int dgn_y = round(ctx->camera.pos[1] / 2.0); int dgn_z = round(ctx->camera.pos[2] / -2.0); @@ -233,6 +233,7 @@ void dungeon_render(struct dungeon_context *ctx) 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); diff --git a/src/video.c b/src/video.c index e023df3..0cd6644 100644 --- a/src/video.c +++ b/src/video.c @@ -234,7 +234,6 @@ static void main_surface_init(int w, int h) main_surface.w = w; main_surface.h = h; main_surface.has_alpha = true; - main_surface.flip_y = false; main_surface.alpha_mod = 255; main_surface.draw_method = DRAW_METHOD_NORMAL; @@ -371,10 +370,6 @@ void gfx_render_texture(struct texture *t, Rectangle *r) t->world_transform[3][0] = r ? r->x : 0; t->world_transform[3][1] = r ? r->y : 0; - if (t->flip_y) { - t->world_transform[3][1] += t->world_transform[1][1]; - t->world_transform[1][1] *= -1; - } struct gfx_render_job job = { .shader = &default_shader.s, @@ -385,10 +380,6 @@ void gfx_render_texture(struct texture *t, Rectangle *r) }; gfx_render(&job); - if (t->flip_y) { - t->world_transform[1][1] *= -1; - t->world_transform[3][1] -= t->world_transform[1][1]; - } if (t->draw_method != DRAW_METHOD_NORMAL || t->alpha_mod != 255) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); } @@ -412,7 +403,6 @@ static void init_texture(struct texture *t, int w, int h) t->h = h; t->has_alpha = true; - t->flip_y = false; t->alpha_mod = 255; t->draw_method = DRAW_METHOD_NORMAL; From 9c6bf5c110b53f9f7dcfbc54146ee4be4561de32 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 12 Jun 2021 23:52:52 +0900 Subject: [PATCH 06/13] DrawDungeon: Move walk-flag management code out of map.c So that ctx->map can just be null in DrawDungeon14 (GALZOO), where 2D maps are not drawn by the HLL. --- include/dungeon/dgn.h | 7 ++ include/dungeon/dungeon.h | 5 ++ include/dungeon/map.h | 6 +- src/dungeon/dgn.c | 19 ++++- src/dungeon/dungeon.c | 140 ++++++++++++++++++++++++++++++++ src/dungeon/map.c | 167 ++------------------------------------ src/hll/DrawDungeon.c | 8 +- 7 files changed, 181 insertions(+), 171 deletions(-) diff --git a/include/dungeon/dgn.h b/include/dungeon/dgn.h index df69673..c194294 100644 --- a/include/dungeon/dgn.h +++ b/include/dungeon/dgn.h @@ -80,6 +80,7 @@ struct dgn_cell { // Runtime data (not stored in .dgn) int x, y, z; + int walked; int event_blend_rate; float north_door_angle; float south_door_angle; @@ -119,6 +120,12 @@ void dgn_free(struct dgn *dgn); int dgn_cell_index(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z); struct dgn_cell *dgn_cell_at(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z); +int dgn_calc_conquer(struct dgn *dgn); + +static inline int dgn_nr_cells(struct dgn *dgn) +{ + return dgn->size_x * dgn->size_y * dgn->size_z; +} static inline bool dgn_is_in_map(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z) { diff --git a/include/dungeon/dungeon.h b/include/dungeon/dungeon.h index 79bc0f0..2674262 100644 --- a/include/dungeon/dungeon.h +++ b/include/dungeon/dungeon.h @@ -22,6 +22,7 @@ #include #include +struct page; struct dgn; struct dtx; struct tes; @@ -61,6 +62,10 @@ void dungeon_context_free(struct dungeon_context *ctx); bool dungeon_load(struct dungeon_context *ctx, int num); void dungeon_set_camera(int surface, float x, float y, float z, float angle, float angle_p); void dungeon_render(struct dungeon_context *ctx); +void dungeon_set_walked(int surface, int x, int y, int z, int flag); +int dungeon_calc_conquer(int surface); +bool dungeon_load_walk_data(int surface, int map, struct page **page); +bool dungeon_save_walk_data(int surface, int map, struct page **page); struct dungeon_context *dungeon_get_context(int surface); void dungeon_update(void); diff --git a/include/dungeon/map.h b/include/dungeon/map.h index 6f8db86..614a306 100644 --- a/include/dungeon/map.h +++ b/include/dungeon/map.h @@ -17,7 +17,6 @@ #ifndef SYSTEM4_DUNGEON_MAP_H #define SYSTEM4_DUNGEON_MAP_H -struct page; struct dungeon_context; struct dungeon_map; @@ -33,9 +32,6 @@ void dungeon_map_set_all_view(int surface, int flag); void dungeon_map_set_cg(int surface, int index, int sprite); void dungeon_map_set_small_map_floor(int surface, int floor); void dungeon_map_set_large_map_floor(int surface, int floor); -void dungeon_map_set_walked(int surface, int x, int y, int z, int flag); -int dungeon_map_calc_conquer(int surface); -bool dungeon_map_load_walk_data(int surface, int map, struct page **page); -bool dungeon_map_save_walk_data(int surface, int map, struct page **page); +void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z); #endif /* SYSTEM4_DUNGEON_MAP_H */ diff --git a/src/dungeon/dgn.c b/src/dungeon/dgn.c index bf432ad..ff7873b 100644 --- a/src/dungeon/dgn.c +++ b/src/dungeon/dgn.c @@ -42,7 +42,7 @@ struct dgn *dgn_parse(uint8_t *data, size_t size) dgn->size_z = buffer_read_int32(&r); buffer_skip(&r, 40); - int nr_cells = dgn->size_x * dgn->size_y * dgn->size_z; + int nr_cells = dgn_nr_cells(dgn); dgn->cells = xcalloc(nr_cells, sizeof(struct dgn_cell)); uint32_t x = 0, y = 0, z = 0; for (int i = 0; i < nr_cells; i++) { @@ -146,7 +146,7 @@ struct dgn *dgn_parse(uint8_t *data, size_t size) void dgn_free(struct dgn *dgn) { - int nr_cells = dgn->size_x * dgn->size_y * dgn->size_z; + int nr_cells = dgn_nr_cells(dgn); for (int i = 0; i < nr_cells; i++) { if (dgn->cells[i].visible_cells) @@ -175,6 +175,21 @@ struct dgn_cell *dgn_cell_at(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z return &dgn->cells[dgn_cell_index(dgn, x, y, z)]; } +int dgn_calc_conquer(struct dgn *dgn) +{ + int nr_cells = dgn_nr_cells(dgn); + int enterable = 0; + int walked = 0; + for (int i = 0; i < nr_cells; i++) { + if (!dgn->cells[i].enterable) + continue; + enterable++; + if (dgn->cells[i].walked) + walked++; + } + return walked * 100 / enterable; +} + struct pvs_cell { struct dgn_cell *cell; int distance; diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index 976947e..4bcbdc1 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -36,6 +36,7 @@ #include "sact.h" #include "sprite.h" #include "vm.h" +#include "vm/page.h" #include "xsystem4.h" #ifndef M_PI @@ -239,3 +240,142 @@ void dungeon_render(struct dungeon_context *ctx) glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo); } + +static void neighbor_reveal(struct dungeon_context *ctx, int x, int y, int z) +{ + struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z); + if (cell->floor < 0) { + cell->walked = 1; + dungeon_map_reveal(ctx, x, y, z); + } +} + +void dungeon_set_walked(int surface, int x, int y, int z, int flag) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx) + return; + dgn_cell_at(ctx->dgn, x, y, z)->walked = 1; + dungeon_map_reveal(ctx, x, y, z); + if (x > 0) + neighbor_reveal(ctx, x - 1, y, z); + if (x + 1u < ctx->dgn->size_x) + neighbor_reveal(ctx, x + 1, y, z); + if (z > 0) + neighbor_reveal(ctx, x, y, z - 1); + if (z + 1u < ctx->dgn->size_z) + neighbor_reveal(ctx, x, y, z + 1); +} + +int dungeon_calc_conquer(int surface) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return 0; + return dgn_calc_conquer(ctx->dgn); +} + +/* + * WalkData serialization format (in Rance VI): + * + * struct WalkData { + * int version; // zero + * int nr_maps; + * struct { + * int map_no; + * int size_x, size_y, size_z; + * int cells[size_x * size_y * size_z]; + * } maps[nr_maps]; + * }; + */ + +enum { + WALK_DATA_NOT_FOUND = -1, + WALK_DATA_BROKEN = -2, +}; + +static int find_walk_data(struct page *array, int map_no, struct dgn *dgn) +{ + if (!array) + return WALK_DATA_BROKEN; + if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->rank != 1) + VM_ERROR("Not a flat integer array"); + + int ptr = 0; + if (array->nr_vars < 2 || array->values[ptr++].i != 0) + return WALK_DATA_BROKEN; + int nr_maps = array->values[ptr++].i; + + for (int i = 0; i < nr_maps; i++) { + if (array->nr_vars < ptr + 4) + return WALK_DATA_BROKEN; + int no = array->values[ptr].i; + uint32_t size_x = array->values[ptr + 1].i; + uint32_t size_y = array->values[ptr + 2].i; + uint32_t size_z = array->values[ptr + 3].i; + int nr_cells = size_x * size_y * size_z; + if (no == map_no) { + if (size_x != dgn->size_x || size_y != dgn->size_y || size_z != dgn->size_z) + return WALK_DATA_BROKEN; + if (ptr + 4 + nr_cells > array->nr_vars) + return WALK_DATA_BROKEN; + return ptr; + } + ptr += 4 + nr_cells; + } + return WALK_DATA_NOT_FOUND; +} + +bool dungeon_load_walk_data(int surface, int map, struct page **page) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return false; + struct page *array = *page; + + int offset = find_walk_data(array, map, ctx->dgn); + if (offset < 0) + return false; + + offset += 4; + int nr_cells = dgn_nr_cells(ctx->dgn); + for (struct dgn_cell *c = ctx->dgn->cells; c < ctx->dgn->cells + nr_cells; c++) { + if (array->values[offset].i) + dungeon_map_reveal(ctx, c->x, c->y, c->z); + c->walked = array->values[offset++].i; + } + + return true; +} + +bool dungeon_save_walk_data(int surface, int map, struct page **page) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return false; + struct page *array = *page; + int nr_cells = dgn_nr_cells(ctx->dgn); + + int offset = find_walk_data(array, map, ctx->dgn); + if (offset == WALK_DATA_NOT_FOUND) { + offset = array->nr_vars; + array->values[1].i += 1; + union vm_value dim = { .i = array->nr_vars + 4 + nr_cells }; + *page = array = realloc_array(array, 1, &dim, AIN_ARRAY_INT, 0, false); + } else if (offset == WALK_DATA_BROKEN) { + if (array) + WARNING("Discarding broken walk data"); + union vm_value dim = { .i = 2 + 4 + nr_cells }; + *page = array = realloc_array(array, 1, &dim, AIN_ARRAY_INT, 0, false); + array->values[0].i = 0; + array->values[1].i = 1; + offset = 2; + } + array->values[offset++].i = map; + array->values[offset++].i = ctx->dgn->size_x; + array->values[offset++].i = ctx->dgn->size_y; + array->values[offset++].i = ctx->dgn->size_z; + for (int i = 0; i < nr_cells; i++) + array->values[offset++].i = ctx->dgn->cells[i].walked; + return true; +} diff --git a/src/dungeon/map.c b/src/dungeon/map.c index 73f6546..de3c627 100644 --- a/src/dungeon/map.c +++ b/src/dungeon/map.c @@ -24,7 +24,6 @@ #include "gfx/gfx.h" #include "sact.h" #include "vm.h" -#include "vm/page.h" #ifndef M_PI #define M_PI (3.14159265358979323846) @@ -60,7 +59,6 @@ struct dungeon_map { int large_map_floor; bool radar; bool all_visible; - int *walk_data; int offset_x, offset_y; }; @@ -85,7 +83,6 @@ void dungeon_map_free(struct dungeon_map *map) for (int i = 0; i < map->nr_textures; i++) gfx_delete_texture(&map->textures[i]); free(map->textures); - free(map->walk_data); free(map); } @@ -96,7 +93,6 @@ void dungeon_map_init(struct dungeon_context *ctx) map->textures = xcalloc(dgn->size_y, sizeof(struct texture)); map->nr_textures = dgn->size_y; - map->walk_data = xcalloc(dgn->size_x * dgn->size_y * dgn->size_z, sizeof(int)); // Calculate the bounding box on the XZ plane so that map is drawn in the // center of the texture. uint32_t min_x = dgn->size_x; @@ -130,11 +126,10 @@ void dungeon_map_init(struct dungeon_context *ctx) } } -static void reveal_cell(struct dungeon_context *ctx, int dgn_x, int dgn_y, int dgn_z) +void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z) { - ctx->map->walk_data[dgn_cell_index(ctx->dgn, dgn_x, dgn_y, dgn_z)] = 1; - struct texture *dst = &ctx->map->textures[dgn_y]; - Point pos = texture_pos(ctx, dgn_x, dgn_z); + struct texture *dst = &ctx->map->textures[y]; + Point pos = texture_pos(ctx, x, z); gfx_fill_amap(dst, pos.x, pos.y, CS, CS, 255); } @@ -302,14 +297,10 @@ void dungeon_map_draw_lmap(int surface, int sprite) static void redraw_event_symbols(struct dungeon_context *ctx) { - struct dgn *dgn = ctx->dgn; - for (uint32_t y = 0; y < dgn->size_y; y++) { - for (uint32_t z = 0; z < dgn->size_z; z++) { - for (uint32_t x = 0; x < dgn->size_x; x++) { - if (dgn_cell_at(dgn, x, y, z)->floor_event) - dungeon_map_update_cell(ctx, x, y, z); - } - } + int nr_cells = dgn_nr_cells(ctx->dgn); + for (struct dgn_cell *c = ctx->dgn->cells; c < ctx->dgn->cells + nr_cells; c++) { + if (c->floor_event) + dungeon_map_update_cell(ctx, c->x, c->y, c->z); } } @@ -356,147 +347,3 @@ void dungeon_map_set_large_map_floor(int surface, int floor) return; ctx->map->large_map_floor = floor; } - -void dungeon_map_set_walked(int surface, int x, int y, int z, int flag) -{ - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx) - return; - reveal_cell(ctx, x, y, z); - if (x > 0 && dgn_cell_at(ctx->dgn, x - 1, y, z)->floor < 0) - reveal_cell(ctx, x - 1, y, z); - if (x + 1u < ctx->dgn->size_x && dgn_cell_at(ctx->dgn, x + 1, y, z)->floor < 0) - reveal_cell(ctx, x + 1, y, z); - if (z > 0 && dgn_cell_at(ctx->dgn, x, y, z - 1)->floor < 0) - reveal_cell(ctx, x, y, z - 1); - if (z + 1u < ctx->dgn->size_z && dgn_cell_at(ctx->dgn, x, y, z + 1)->floor < 0) - reveal_cell(ctx, x, y, z + 1); -} - -int dungeon_map_calc_conquer(int surface) -{ - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx || !ctx->dgn) - return 0; - - int nr_cells = ctx->dgn->size_x * ctx->dgn->size_y * ctx->dgn->size_z; - int enterable = 0; - int walked = 0; - for (int i = 0; i < nr_cells; i++) { - if (!ctx->dgn->cells[i].enterable) - continue; - enterable++; - if (ctx->map->walk_data[i]) - walked++; - } - return walked * 100 / enterable; -} - -/* - * WalkData serialization format (in Rance VI): - * - * struct WalkData { - * int version; // zero - * int nr_maps; - * struct { - * int map_no; - * int size_x, size_y, size_z; - * int cells[size_x * size_y * size_z]; - * } maps[nr_maps]; - * }; - */ - -enum { - WALK_DATA_NOT_FOUND = -1, - WALK_DATA_BROKEN = -2, -}; - -static int find_walk_data(struct page *array, int map_no, struct dgn *dgn) -{ - if (!array) - return WALK_DATA_BROKEN; - if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->rank != 1) - VM_ERROR("Not a flat integer array"); - - int ptr = 0; - if (array->nr_vars < 2 || array->values[ptr++].i != 0) - return WALK_DATA_BROKEN; - int nr_maps = array->values[ptr++].i; - - for (int i = 0; i < nr_maps; i++) { - if (array->nr_vars < ptr + 4) - return WALK_DATA_BROKEN; - int no = array->values[ptr].i; - uint32_t size_x = array->values[ptr + 1].i; - uint32_t size_y = array->values[ptr + 2].i; - uint32_t size_z = array->values[ptr + 3].i; - int nr_cells = size_x * size_y * size_z; - if (no == map_no) { - if (size_x != dgn->size_x || size_y != dgn->size_y || size_z != dgn->size_z) - return WALK_DATA_BROKEN; - if (ptr + 4 + nr_cells > array->nr_vars) - return WALK_DATA_BROKEN; - return ptr; - } - ptr += 4 + nr_cells; - } - return WALK_DATA_NOT_FOUND; -} - -bool dungeon_map_load_walk_data(int surface, int map, struct page **page) -{ - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx || !ctx->dgn) - return false; - struct page *array = *page; - - int offset = find_walk_data(array, map, ctx->dgn); - if (offset < 0) - return false; - - offset += 4; - int i = 0; - for (uint32_t z = 0; z < ctx->dgn->size_z; z++) { - for (uint32_t y = 0; y < ctx->dgn->size_y; y++) { - for (uint32_t x = 0; x < ctx->dgn->size_x; x++) { - if (array->values[offset].i) - reveal_cell(ctx, x, y, z); - ctx->map->walk_data[i++] = array->values[offset++].i; - } - } - } - - return true; -} - -bool dungeon_map_save_walk_data(int surface, int map, struct page **page) -{ - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx || !ctx->dgn) - return false; - struct page *array = *page; - int nr_cells = ctx->dgn->size_x * ctx->dgn->size_y * ctx->dgn->size_z; - - int offset = find_walk_data(array, map, ctx->dgn); - if (offset == WALK_DATA_NOT_FOUND) { - offset = array->nr_vars; - array->values[1].i += 1; - union vm_value dim = { .i = array->nr_vars + 4 + nr_cells }; - *page = array = realloc_array(array, 1, &dim, AIN_ARRAY_INT, 0, false); - } else if (offset == WALK_DATA_BROKEN) { - if (array) - WARNING("Discarding broken walk data"); - union vm_value dim = { .i = 2 + 4 + nr_cells }; - *page = array = realloc_array(array, 1, &dim, AIN_ARRAY_INT, 0, false); - array->values[0].i = 0; - array->values[1].i = 1; - offset = 2; - } - array->values[offset++].i = map; - array->values[offset++].i = ctx->dgn->size_x; - array->values[offset++].i = ctx->dgn->size_y; - array->values[offset++].i = ctx->dgn->size_z; - for (int i = 0; i < nr_cells; i++) - array->values[offset++].i = ctx->map->walk_data[i]; - return true; -} diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index 81e82b1..37cd395 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -360,12 +360,12 @@ HLL_LIBRARY(DrawDungeon, HLL_EXPORT(SetDrawMapRadar, dungeon_map_set_radar), HLL_EXPORT(SetDrawHalfFlag, DrawDungeon_SetDrawHalfFlag), HLL_EXPORT(GetDrawHalfFlag, DrawDungeon_GetDrawHalfFlag), - HLL_EXPORT(SetWalked, dungeon_map_set_walked), + HLL_EXPORT(SetWalked, dungeon_set_walked), HLL_TODO_EXPORT(SetWalkedAll, DrawDungeon_SetWalkedAll), HLL_TODO_EXPORT(CalcNumofFloor, DrawDungeon_CalcNumofFloor), HLL_TODO_EXPORT(CalcNumofWalk, DrawDungeon_CalcNumofWalk), HLL_TODO_EXPORT(CalcNumofWalk2, DrawDungeon_CalcNumofWalk2), - HLL_EXPORT(CalcConquer, dungeon_map_calc_conquer), + HLL_EXPORT(CalcConquer, dungeon_calc_conquer), HLL_EXPORT(SetInterlaceMode, DrawDungeon_SetInterlaceMode), HLL_EXPORT(SetDirect3DMode, DrawDungeon_SetDirect3DMode), HLL_EXPORT(SaveDrawSettingFlag, DrawDungeon_SaveDrawSettingFlag), @@ -378,6 +378,6 @@ HLL_LIBRARY(DrawDungeon, HLL_EXPORT(GetTexSound, DrawDungeon_GetTexSound), HLL_EXPORT(StopTimer, DrawDungeon_StopTimer), HLL_EXPORT(RestartTimer, DrawDungeon_RestartTimer), - HLL_EXPORT(LoadWalkData, dungeon_map_load_walk_data), - HLL_EXPORT(SaveWalkData, dungeon_map_save_walk_data) + HLL_EXPORT(LoadWalkData, dungeon_load_walk_data), + HLL_EXPORT(SaveWalkData, dungeon_save_walk_data) ); From 1d8615d14f7a2b7644bbefbda29d9ea17161078c Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 12 Jun 2021 22:50:37 +0900 Subject: [PATCH 07/13] Initial implementation of DrawDungeon14.hll (GALZOO Island) Major differences from DrawDungeon.hll are: - DGN, DTX, TES are loaded from individual files, not from a DLF archive - 2D map functions are not used - (unimplemented) Spinning motion of event markers - (unimplemented) Additional 3D object types (polygon models and roofs) --- include/dungeon/dungeon.h | 10 +- include/dungeon/map.h | 2 +- include/dungeon/renderer.h | 2 +- src/dungeon/dungeon.c | 122 +++++++++++----- src/dungeon/map.c | 25 ++-- src/dungeon/renderer.c | 63 +++++--- src/ffi.c | 2 + src/hll/DrawDungeon.c | 288 +++++++++++++++++++++---------------- 8 files changed, 318 insertions(+), 196 deletions(-) diff --git a/include/dungeon/dungeon.h b/include/dungeon/dungeon.h index 2674262..f63d491 100644 --- a/include/dungeon/dungeon.h +++ b/include/dungeon/dungeon.h @@ -29,6 +29,12 @@ struct tes; struct dungeon_renderer; struct dungeon_map; +enum draw_dungeon_version { + DRAW_DUNGEON_1, // Rance VI + // DRAW_DUNGEON_2, // Dungeons & Dolls + DRAW_DUNGEON_14 // GALZOO Island +}; + struct camera { float pos[3]; float angle; @@ -45,6 +51,7 @@ struct camera { */ struct dungeon_context { + enum draw_dungeon_version version; int surface; bool loaded; bool draw_enabled; @@ -57,12 +64,13 @@ struct dungeon_context { GLuint depth_buffer; }; -struct dungeon_context *dungeon_context_create(int surface); +struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int surface); void dungeon_context_free(struct dungeon_context *ctx); bool dungeon_load(struct dungeon_context *ctx, int num); void dungeon_set_camera(int surface, float x, float y, float z, float angle, float angle_p); void dungeon_render(struct dungeon_context *ctx); void dungeon_set_walked(int surface, int x, int y, int z, int flag); +int dungeon_get_walked(int surface, int x, int y, int z); int dungeon_calc_conquer(int surface); bool dungeon_load_walk_data(int surface, int map, struct page **page); bool dungeon_save_walk_data(int surface, int map, struct page **page); diff --git a/include/dungeon/map.h b/include/dungeon/map.h index 614a306..e8559f3 100644 --- a/include/dungeon/map.h +++ b/include/dungeon/map.h @@ -20,7 +20,7 @@ struct dungeon_context; struct dungeon_map; -struct dungeon_map *dungeon_map_create(void); +struct dungeon_map *dungeon_map_create(enum draw_dungeon_version version); void dungeon_map_free(struct dungeon_map *map); void dungeon_map_init(struct dungeon_context *ctx); void dungeon_map_update_cell(struct dungeon_context *ctx, int x, int y, int z); diff --git a/include/dungeon/renderer.h b/include/dungeon/renderer.h index 014f5d8..4919365 100644 --- a/include/dungeon/renderer.h +++ b/include/dungeon/renderer.h @@ -24,7 +24,7 @@ struct dgn_cell; struct dtx; struct dungeon_renderer; -struct dungeon_renderer *dungeon_renderer_create(struct dtx *dtx, GLuint *event_textures, int nr_event_textures); +struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, struct dtx *dtx, GLuint *event_textures, int nr_event_textures); void dungeon_renderer_free(struct dungeon_renderer *r); void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells, int nr_cells, mat4 view_transform, mat4 proj_transform); diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index 4bcbdc1..e8263b8 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -25,6 +25,7 @@ #include "system4/archive.h" #include "system4/cg.h" #include "system4/dlf.h" +#include "system4/file.h" #include "dungeon/dgn.h" #include "dungeon/dtx.h" @@ -43,9 +44,10 @@ #define M_PI (3.14159265358979323846) #endif -struct dungeon_context *dungeon_context_create(int surface) +struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int surface) { struct dungeon_context *ctx = xcalloc(1, sizeof(struct dungeon_context)); + ctx->version = version; ctx->surface = surface; struct sact_sprite *sp = sact_get_sprite(ctx->surface); if (!sp) @@ -59,7 +61,7 @@ struct dungeon_context *dungeon_context_create(int surface) glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, texture->w, texture->h); glBindRenderbuffer(GL_RENDERBUFFER, 0); - ctx->map = dungeon_map_create(); + ctx->map = dungeon_map_create(version); return ctx; } @@ -76,7 +78,8 @@ void dungeon_context_free(struct dungeon_context *ctx) dungeon_renderer_free(ctx->renderer); glDeleteRenderbuffers(1, &ctx->depth_buffer); - dungeon_map_free(ctx->map); + if (ctx->map) + dungeon_map_free(ctx->map); free(ctx); } @@ -127,34 +130,65 @@ bool dungeon_load(struct dungeon_context *ctx, int num) if (ctx->loaded) VM_ERROR("Dungeon is already loaded"); - char *path = gamedir_path("Data/DungeonData.dlf"); - int error = ARCHIVE_SUCCESS; - struct archive *dlf = (struct archive *)dlf_open(path, ARCHIVE_MMAP, &error); - if (error == ARCHIVE_FILE_ERROR) { - WARNING("dlf_open(\"%s\"): %s", path, strerror(errno)); - } else if (error == ARCHIVE_BAD_ARCHIVE_ERROR) { - WARNING("dlf_open(\"%s\"): invalid .dlf file", path); - } - free(path); - if (!dlf) - return false; + if (ctx->version == DRAW_DUNGEON_1) { + char *path = gamedir_path("Data/DungeonData.dlf"); + int error = ARCHIVE_SUCCESS; + struct archive *dlf = (struct archive *)dlf_open(path, ARCHIVE_MMAP, &error); + if (error == ARCHIVE_FILE_ERROR) { + WARNING("dlf_open(\"%s\"): %s", path, strerror(errno)); + } else if (error == ARCHIVE_BAD_ARCHIVE_ERROR) { + WARNING("dlf_open(\"%s\"): invalid .dlf file", path); + } + free(path); + if (!dlf) + return false; - struct archive_data *dgn = archive_get(dlf, num * 3); - if (dgn) { - ctx->dgn = dgn_parse(dgn->data, dgn->size); - archive_free_data(dgn); + struct archive_data *dgn = archive_get(dlf, num * 3); + if (dgn) { + ctx->dgn = dgn_parse(dgn->data, dgn->size); + archive_free_data(dgn); + } + struct archive_data *dtx = archive_get(dlf, num * 3 + 1); + if (dtx) { + ctx->dtx = dtx_parse(dtx->data, dtx->size); + archive_free_data(dtx); + } + struct archive_data *tes = archive_get(dlf, num * 3 + 2); + if (tes) { + ctx->tes = tes_parse(tes->data, tes->size); + archive_free_data(tes); + } + archive_free(dlf); + } else if (ctx->version == DRAW_DUNGEON_14) { + char buf[100]; + sprintf(buf, "Data/map%02d.dgn", num); + char *path = gamedir_path(buf); + + size_t len; + uint8_t *dgn = file_read(path, &len); + if (dgn) { + ctx->dgn = dgn_parse(dgn, len); + free(dgn); + } + + strcpy(path + strlen(path) - 3, "dtx"); + uint8_t *dtx = file_read(path, &len); + if (dtx) { + ctx->dtx = dtx_parse(dtx, len); + free(dtx); + } + + strcpy(path + strlen(path) - 3, "tes"); + uint8_t *tes = file_read(path, &len); + if (tes) { + ctx->tes = tes_parse(tes, len); + free(tes); + } + free(path); + } else { + ERROR("Invalid DrawDungeon version %d", ctx->version); } - struct archive_data *dtx = archive_get(dlf, num * 3 + 1); - if (dtx) { - ctx->dtx = dtx_parse(dtx->data, dtx->size); - archive_free_data(dtx); - } - struct archive_data *tes = archive_get(dlf, num * 3 + 2); - if (tes) { - ctx->tes = tes_parse(tes->data, tes->size); - archive_free_data(tes); - } - archive_free(dlf); + if (!ctx->dgn || !ctx->dtx) { WARNING("Cannot load dungeon %d", num); return false; @@ -165,7 +199,7 @@ bool dungeon_load(struct dungeon_context *ctx, int num) if (!event_textures) return false; - ctx->renderer = dungeon_renderer_create(ctx->dtx, event_textures, nr_event_textures); + ctx->renderer = dungeon_renderer_create(ctx->version, ctx->dtx, event_textures, nr_event_textures); dungeon_map_init(ctx); @@ -257,14 +291,24 @@ void dungeon_set_walked(int surface, int x, int y, int z, int flag) return; dgn_cell_at(ctx->dgn, x, y, z)->walked = 1; dungeon_map_reveal(ctx, x, y, z); - if (x > 0) - neighbor_reveal(ctx, x - 1, y, z); - if (x + 1u < ctx->dgn->size_x) - neighbor_reveal(ctx, x + 1, y, z); - if (z > 0) - neighbor_reveal(ctx, x, y, z - 1); - if (z + 1u < ctx->dgn->size_z) - neighbor_reveal(ctx, x, y, z + 1); + if (ctx->version == DRAW_DUNGEON_1) { + if (x > 0) + neighbor_reveal(ctx, x - 1, y, z); + if (x + 1u < ctx->dgn->size_x) + neighbor_reveal(ctx, x + 1, y, z); + if (z > 0) + neighbor_reveal(ctx, x, y, z - 1); + if (z + 1u < ctx->dgn->size_z) + neighbor_reveal(ctx, x, y, z + 1); + } +} + +int dungeon_get_walked(int surface, int x, int y, int z) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return 0; + return dgn_cell_at(ctx->dgn, x, y, z)->walked; } int dungeon_calc_conquer(int surface) @@ -276,7 +320,7 @@ int dungeon_calc_conquer(int surface) } /* - * WalkData serialization format (in Rance VI): + * WalkData serialization format: * * struct WalkData { * int version; // zero diff --git a/src/dungeon/map.c b/src/dungeon/map.c index de3c627..6f52d1e 100644 --- a/src/dungeon/map.c +++ b/src/dungeon/map.c @@ -70,8 +70,11 @@ static Point texture_pos(struct dungeon_context *ctx, int x, int z) }; } -struct dungeon_map *dungeon_map_create(void) +struct dungeon_map *dungeon_map_create(enum draw_dungeon_version version) { + if (version == DRAW_DUNGEON_14) + return NULL; // GALZOO does not use DrawDungeon's 2D map functions. + struct dungeon_map *map = xcalloc(1, sizeof(struct dungeon_map)); map->small_map_floor = -1; map->large_map_floor = -1; @@ -90,6 +93,8 @@ void dungeon_map_init(struct dungeon_context *ctx) { struct dungeon_map *map = ctx->map; struct dgn *dgn = ctx->dgn; + if (!map) + return; map->textures = xcalloc(dgn->size_y, sizeof(struct texture)); map->nr_textures = dgn->size_y; @@ -128,6 +133,8 @@ void dungeon_map_init(struct dungeon_context *ctx) void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z) { + if (!ctx->map) + return; struct texture *dst = &ctx->map->textures[y]; Point pos = texture_pos(ctx, x, z); gfx_fill_amap(dst, pos.x, pos.y, CS, CS, 255); @@ -154,6 +161,8 @@ static void draw_symbol(struct dungeon_context *ctx, struct texture *dst, int x, void dungeon_map_update_cell(struct dungeon_context *ctx, int dgn_x, int dgn_y, int dgn_z) { + if (!ctx->map) + return; struct dgn_cell *cell = dgn_cell_at(ctx->dgn, dgn_x, dgn_y, dgn_z); struct texture *dst = &ctx->map->textures[dgn_y]; Point pos = texture_pos(ctx, dgn_x, dgn_z); @@ -238,7 +247,7 @@ static int player_symbol(struct dungeon_context *ctx) void dungeon_map_draw(int surface, int sprite) { struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx) + if (!ctx || !ctx->map) return; struct sact_sprite *sp = sact_get_sprite(sprite); if (!sp) @@ -270,7 +279,7 @@ void dungeon_map_draw(int surface, int sprite) void dungeon_map_draw_lmap(int surface, int sprite) { struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx) + if (!ctx || !ctx->map) return; struct sact_sprite *sp = sact_get_sprite(sprite); if (!sp) @@ -307,7 +316,7 @@ static void redraw_event_symbols(struct dungeon_context *ctx) void dungeon_map_set_radar(int surface, int flag) { struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx || ctx->map->radar == flag) + if (!ctx || !ctx->map || ctx->map->radar == flag) return; ctx->map->radar = flag; redraw_event_symbols(ctx); @@ -316,7 +325,7 @@ void dungeon_map_set_radar(int surface, int flag) void dungeon_map_set_all_view(int surface, int flag) { struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx || ctx->map->all_visible == flag) + if (!ctx || !ctx->map || ctx->map->all_visible == flag) return; ctx->map->all_visible = flag; redraw_event_symbols(ctx); @@ -325,7 +334,7 @@ void dungeon_map_set_all_view(int surface, int flag) void dungeon_map_set_cg(int surface, int index, int sprite) { struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx) + if (!ctx || !ctx->map) return; if (index < 0 || index >= NR_SYMBOLS) VM_ERROR("DrawDungeon.SetMapCG: index %d is out of bounds", index); @@ -335,7 +344,7 @@ void dungeon_map_set_cg(int surface, int index, int sprite) void dungeon_map_set_small_map_floor(int surface, int floor) { struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx) + if (!ctx || !ctx->map) return; ctx->map->small_map_floor = floor; } @@ -343,7 +352,7 @@ void dungeon_map_set_small_map_floor(int surface, int floor) void dungeon_map_set_large_map_floor(int surface, int floor) { struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx) + if (!ctx || !ctx->map) return; ctx->map->large_map_floor = floor; } diff --git a/src/dungeon/renderer.c b/src/dungeon/renderer.c index 9f27f15..f1f5338 100644 --- a/src/dungeon/renderer.c +++ b/src/dungeon/renderer.c @@ -22,6 +22,7 @@ #include "system4.h" #include "system4/cg.h" +#include "dungeon/dungeon.h" #include "dungeon/dgn.h" #include "dungeon/dtx.h" #include "dungeon/renderer.h" @@ -35,31 +36,40 @@ struct marker_info { int floor_marker; }; -enum rance6_floor_marker { - MAGIC_CIRCLE = 1, - RED_OCTAGRAM = 63, +enum floor_marker { + // Rance VI + R6_MAGIC_CIRCLE = 1, + R6_RED_OCTAGRAM = 63, + // GALZOO Island + GZ_MAGIC_CIRCLE = 0, }; static const struct marker_info rance6_marker_info[] = { - { 11, 41, 3, MAGIC_CIRCLE}, // treasure chest - { 12, 51, 7, RED_OCTAGRAM}, // enemy - { 14, 8, 5, MAGIC_CIRCLE}, // green star - { 15, 21, 10, MAGIC_CIRCLE}, // heart - { 16, 45, 5, MAGIC_CIRCLE}, // BP cross - { 17, 58, 5, MAGIC_CIRCLE}, // exit - { 18, 31, 10, MAGIC_CIRCLE}, // teleporter - {140, 13, 5, RED_OCTAGRAM}, // red star + { 11, 41, 3, R6_MAGIC_CIRCLE}, // treasure chest + { 12, 51, 7, R6_RED_OCTAGRAM}, // enemy + { 14, 8, 5, R6_MAGIC_CIRCLE}, // green star + { 15, 21, 10, R6_MAGIC_CIRCLE}, // heart + { 16, 45, 5, R6_MAGIC_CIRCLE}, // BP cross + { 17, 58, 5, R6_MAGIC_CIRCLE}, // exit + { 18, 31, 10, R6_MAGIC_CIRCLE}, // teleporter + {140, 13, 5, R6_RED_OCTAGRAM}, // red star {0}, }; -static const struct marker_info *get_marker_info(int event_type) -{ - for (const struct marker_info *info = rance6_marker_info; info->event_type; info++) { - if (info->event_type == event_type) - return info; - } - return NULL; -} +static const struct marker_info galzoo_marker_info[] = { + {11, 1, 1, GZ_MAGIC_CIRCLE}, // item + {12, 2, 1, GZ_MAGIC_CIRCLE}, // enemy + {14, 3, 1, GZ_MAGIC_CIRCLE}, // star + {15, 4, 1, GZ_MAGIC_CIRCLE}, // heart + {17, 5, 1, GZ_MAGIC_CIRCLE}, // exit + {18, 6, 1, GZ_MAGIC_CIRCLE}, // teleporter + {0}, +}; + +static const struct marker_info *marker_tables[] = { + [DRAW_DUNGEON_1] = rance6_marker_info, + [DRAW_DUNGEON_14] = galzoo_marker_info +}; struct geometry; struct material; @@ -84,10 +94,20 @@ struct dungeon_renderer { GLuint *event_textures; int nr_event_textures; + const struct marker_info *marker_table; struct skybox *skybox; }; +static const struct marker_info *get_marker_info(struct dungeon_renderer *r, int event_type) +{ + for (const struct marker_info *info = r->marker_table; info->event_type; info++) { + if (info->event_type == event_type) + return info; + } + return NULL; +} + struct vertex { GLfloat x, y, z, u, v; }; @@ -213,7 +233,7 @@ static struct material *get_material(struct dungeon_renderer *r, int type, int i return m; } -struct dungeon_renderer *dungeon_renderer_create(struct dtx *dtx, GLuint *event_textures, int nr_event_textures) +struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, struct dtx *dtx, GLuint *event_textures, int nr_event_textures) { struct dungeon_renderer *r = xcalloc(1, sizeof(struct dungeon_renderer)); @@ -240,6 +260,7 @@ struct dungeon_renderer *dungeon_renderer_create(struct dtx *dtx, GLuint *event_ r->event_textures = event_textures; r->nr_event_textures = nr_event_textures; + r->marker_table = marker_tables[version]; r->skybox = skybox_create(dtx); @@ -482,7 +503,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re } } if (cell->floor_event && !render_opaque) { - const struct marker_info *info = get_marker_info(cell->floor_event); + const struct marker_info *info = get_marker_info(r, cell->floor_event); if (info) { uint32_t t = SDL_GetTicks(); draw_floor_marker(r, info, x, y, z, t); diff --git a/src/ffi.c b/src/ffi.c index 42fd856..cefdeea 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -291,6 +291,7 @@ extern struct static_library lib_Confirm2; extern struct static_library lib_CrayfishLogViewer; extern struct static_library lib_DataFile; extern struct static_library lib_DrawDungeon; +extern struct static_library lib_DrawDungeon14; extern struct static_library lib_DrawGraph; extern struct static_library lib_DrawMovie2; extern struct static_library lib_DrawPluginManager; @@ -339,6 +340,7 @@ static struct static_library *static_libraries[] = { &lib_CrayfishLogViewer, &lib_DataFile, &lib_DrawDungeon, + &lib_DrawDungeon14, &lib_DrawGraph, &lib_DrawMovie2, &lib_DrawPluginManager, diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index 37cd395..c968481 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -28,6 +28,16 @@ static struct dungeon_context *current_context = NULL; +static int dungeon_init(enum draw_dungeon_version version, int surface) +{ + if (current_context) + VM_ERROR("Dungeon is already associated with surface %d", current_context->surface); + if (surface < 0) + return 0; + current_context = dungeon_context_create(version, surface); + return 1; +} + struct dungeon_context *dungeon_get_context(int surface) { if (!current_context || surface != current_context->surface) @@ -49,14 +59,22 @@ static struct dgn_cell *dungeon_get_cell(int surface, int x, int y, int z) return dgn_cell_at(ctx->dgn, x, y, z); } +static void DrawDungeon_ModuleFini(void) +{ + if (current_context) { + dungeon_context_free(current_context); + current_context = NULL; + } +} + static int DrawDungeon_Init(int surface) { - if (current_context) - VM_ERROR("Dungeon is already associated with surface %d", current_context->surface); - if (surface < 0) - return 0; - current_context = dungeon_context_create(surface); - return 1; + return dungeon_init(DRAW_DUNGEON_1, surface); +} + +static int DrawDungeon14_Init(int surface) +{ + return dungeon_init(DRAW_DUNGEON_14, surface); } static void DrawDungeon_Release(int surface) @@ -261,123 +279,143 @@ static int DrawDungeon_GetTexSound(int surface, int type, int num) HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, StopTimer, void); HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, RestartTimer, void); +#define DRAW_DUNGEON_EXPORTS \ + HLL_EXPORT(_ModuleFini, DrawDungeon_ModuleFini), \ + HLL_EXPORT(Release, DrawDungeon_Release), \ + HLL_EXPORT(SetDrawFlag, DrawDungeon_SetDrawFlag), \ + HLL_EXPORT(BeginLoad, DrawDungeon_BeginLoad), \ + HLL_EXPORT(IsLoading, DrawDungeon_IsLoading), \ + HLL_EXPORT(IsSucceededLoading, DrawDungeon_IsSucceededLoading), \ + HLL_TODO_EXPORT(GetLoadingPercent, DrawDungeon_GetLoadingPercent), \ + HLL_TODO_EXPORT(LoadFromFile, DrawDungeon_LoadFromFile), \ + HLL_TODO_EXPORT(LoadTexture, DrawDungeon_LoadTexture), \ + HLL_TODO_EXPORT(LoadEventTexture, DrawDungeon_LoadEventTexture), \ + HLL_EXPORT(GetMapX, DrawDungeon_GetMapX), \ + HLL_EXPORT(GetMapY, DrawDungeon_GetMapY), \ + HLL_EXPORT(GetMapZ, DrawDungeon_GetMapZ), \ + HLL_EXPORT(SetCamera, dungeon_set_camera), \ + HLL_EXPORT(IsInMap, DrawDungeon_IsInMap), \ + HLL_EXPORT(IsFloor, DrawDungeon_IsFloor), \ + HLL_TODO_EXPORT(IsFloorFillTexture, DrawDungeon_IsFloorFillTexture), \ + HLL_EXPORT(IsStair, DrawDungeon_IsStair), \ + HLL_EXPORT(IsStairN, DrawDungeon_IsStairN), \ + HLL_EXPORT(IsStairW, DrawDungeon_IsStairW), \ + HLL_EXPORT(IsStairS, DrawDungeon_IsStairS), \ + HLL_EXPORT(IsStairE, DrawDungeon_IsStairE), \ + HLL_EXPORT(IsWallN, DrawDungeon_IsWallN), \ + HLL_EXPORT(IsWallW, DrawDungeon_IsWallW), \ + HLL_EXPORT(IsWallS, DrawDungeon_IsWallS), \ + HLL_EXPORT(IsWallE, DrawDungeon_IsWallE), \ + HLL_EXPORT(IsDoorN, DrawDungeon_IsDoorN), \ + HLL_EXPORT(IsDoorW, DrawDungeon_IsDoorW), \ + HLL_EXPORT(IsDoorS, DrawDungeon_IsDoorS), \ + HLL_EXPORT(IsDoorE, DrawDungeon_IsDoorE), \ + HLL_EXPORT(IsEnter, DrawDungeon_IsEnter), \ + HLL_EXPORT(IsEnterN, DrawDungeon_IsEnterN), \ + HLL_EXPORT(IsEnterW, DrawDungeon_IsEnterW), \ + HLL_EXPORT(IsEnterS, DrawDungeon_IsEnterS), \ + HLL_EXPORT(IsEnterE, DrawDungeon_IsEnterE), \ + HLL_EXPORT(GetEvFloor, DrawDungeon_GetEvFloor), \ + HLL_EXPORT(GetEvWallN, DrawDungeon_GetEvWallN), \ + HLL_EXPORT(GetEvWallW, DrawDungeon_GetEvWallW), \ + HLL_EXPORT(GetEvWallS, DrawDungeon_GetEvWallS), \ + HLL_EXPORT(GetEvWallE, DrawDungeon_GetEvWallE), \ + HLL_EXPORT(GetEvFloor2, DrawDungeon_GetEvFloor2), \ + HLL_EXPORT(GetEvWallN2, DrawDungeon_GetEvWallN2), \ + HLL_EXPORT(GetEvWallW2, DrawDungeon_GetEvWallW2), \ + HLL_EXPORT(GetEvWallS2, DrawDungeon_GetEvWallS2), \ + HLL_EXPORT(GetEvWallE2, DrawDungeon_GetEvWallE2), \ + HLL_EXPORT(GetTexFloor, DrawDungeon_GetTexFloor), \ + HLL_EXPORT(GetTexCeiling, DrawDungeon_GetTexCeiling), \ + HLL_EXPORT(GetTexWallN, DrawDungeon_GetTexWallN), \ + HLL_EXPORT(GetTexWallW, DrawDungeon_GetTexWallW), \ + HLL_EXPORT(GetTexWallS, DrawDungeon_GetTexWallS), \ + HLL_EXPORT(GetTexWallE, DrawDungeon_GetTexWallE), \ + HLL_EXPORT(GetTexDoorN, DrawDungeon_GetTexDoorN), \ + HLL_EXPORT(GetTexDoorW, DrawDungeon_GetTexDoorW), \ + HLL_EXPORT(GetTexDoorS, DrawDungeon_GetTexDoorS), \ + HLL_EXPORT(GetTexDoorE, DrawDungeon_GetTexDoorE), \ + HLL_EXPORT(GetTexStair, DrawDungeon_GetTexStair), \ + HLL_EXPORT(GetBattleBack, DrawDungeon_GetBattleBack), \ + HLL_EXPORT(SetDoorNAngle, DrawDungeon_SetDoorNAngle), \ + HLL_EXPORT(SetDoorWAngle, DrawDungeon_SetDoorWAngle), \ + HLL_EXPORT(SetDoorSAngle, DrawDungeon_SetDoorSAngle), \ + HLL_EXPORT(SetDoorEAngle, DrawDungeon_SetDoorEAngle), \ + HLL_EXPORT(SetEvFloor, DrawDungeon_SetEvFloor), \ + HLL_EXPORT(SetEvWallN, DrawDungeon_SetEvWallN), \ + HLL_EXPORT(SetEvWallW, DrawDungeon_SetEvWallW), \ + HLL_EXPORT(SetEvWallS, DrawDungeon_SetEvWallS), \ + HLL_EXPORT(SetEvWallE, DrawDungeon_SetEvWallE), \ + HLL_EXPORT(SetEvFloor2, DrawDungeon_SetEvFloor2), \ + HLL_EXPORT(SetEvWallN2, DrawDungeon_SetEvWallN2), \ + HLL_EXPORT(SetEvWallW2, DrawDungeon_SetEvWallW2), \ + HLL_EXPORT(SetEvWallS2, DrawDungeon_SetEvWallS2), \ + HLL_EXPORT(SetEvWallE2, DrawDungeon_SetEvWallE2), \ + HLL_TODO_EXPORT(SetEvMag, DrawDungeon_SetEvMag), \ + HLL_EXPORT(SetEvRate, DrawDungeon_SetEvRate), \ + HLL_EXPORT(SetEnter, DrawDungeon_SetEnter), \ + HLL_EXPORT(SetEnterN, DrawDungeon_SetEnterN), \ + HLL_EXPORT(SetEnterW, DrawDungeon_SetEnterW), \ + HLL_EXPORT(SetEnterS, DrawDungeon_SetEnterS), \ + HLL_EXPORT(SetEnterE, DrawDungeon_SetEnterE), \ + HLL_EXPORT(SetTexFloor, DrawDungeon_SetTexFloor), \ + HLL_EXPORT(SetTexCeiling, DrawDungeon_SetTexCeiling), \ + HLL_EXPORT(SetTexWallN, DrawDungeon_SetTexWallN), \ + HLL_EXPORT(SetTexWallW, DrawDungeon_SetTexWallW), \ + HLL_EXPORT(SetTexWallS, DrawDungeon_SetTexWallS), \ + HLL_EXPORT(SetTexWallE, DrawDungeon_SetTexWallE), \ + HLL_EXPORT(SetTexDoorN, DrawDungeon_SetTexDoorN), \ + HLL_EXPORT(SetTexDoorW, DrawDungeon_SetTexDoorW), \ + HLL_EXPORT(SetTexDoorS, DrawDungeon_SetTexDoorS), \ + HLL_EXPORT(SetTexDoorE, DrawDungeon_SetTexDoorE), \ + HLL_TODO_EXPORT(SetSkyTextureSet, DrawDungeon_SetSkyTextureSet), \ + HLL_EXPORT(DrawMap, dungeon_map_draw), \ + HLL_EXPORT(SetMapAllViewFlag, dungeon_map_set_all_view), \ + HLL_EXPORT(SetDrawMapFloor, dungeon_map_set_small_map_floor), \ + HLL_EXPORT(DrawLMap, dungeon_map_draw_lmap), \ + HLL_EXPORT(SetMapCG, dungeon_map_set_cg), \ + HLL_EXPORT(SetDrawLMapFloor, dungeon_map_set_large_map_floor), \ + HLL_EXPORT(SetDrawMapRadar, dungeon_map_set_radar), \ + HLL_EXPORT(SetDrawHalfFlag, DrawDungeon_SetDrawHalfFlag), \ + HLL_EXPORT(GetDrawHalfFlag, DrawDungeon_GetDrawHalfFlag), \ + HLL_EXPORT(SetWalked, dungeon_set_walked), \ + HLL_TODO_EXPORT(SetWalkedAll, DrawDungeon_SetWalkedAll), \ + HLL_TODO_EXPORT(CalcNumofFloor, DrawDungeon_CalcNumofFloor), \ + HLL_TODO_EXPORT(CalcNumofWalk, DrawDungeon_CalcNumofWalk), \ + HLL_TODO_EXPORT(CalcNumofWalk2, DrawDungeon_CalcNumofWalk2), \ + HLL_EXPORT(CalcConquer, dungeon_calc_conquer), \ + HLL_EXPORT(SetInterlaceMode, DrawDungeon_SetInterlaceMode), \ + HLL_EXPORT(SetDirect3DMode, DrawDungeon_SetDirect3DMode), \ + HLL_EXPORT(SaveDrawSettingFlag, DrawDungeon_SaveDrawSettingFlag), \ + HLL_EXPORT(GetDrawSettingFlag, DrawDungeon_GetDrawSettingFlag), \ + HLL_EXPORT(IsDrawSettingFile, DrawDungeon_IsDrawSettingFile), \ + HLL_EXPORT(DeleteDrawSettingFile, DrawDungeon_DeleteDrawSettingFile), \ + HLL_EXPORT(IsSSEFlag, DrawDungeon_IsSSEFlag), \ + HLL_EXPORT(SetSSEFlag, DrawDungeon_SetSSEFlag), \ + HLL_EXPORT(IsPVSData, DrawDungeon_IsPVSData), \ + HLL_EXPORT(GetTexSound, DrawDungeon_GetTexSound), \ + HLL_EXPORT(StopTimer, DrawDungeon_StopTimer), \ + HLL_EXPORT(RestartTimer, DrawDungeon_RestartTimer), \ + HLL_EXPORT(LoadWalkData, dungeon_load_walk_data), \ + HLL_EXPORT(SaveWalkData, dungeon_save_walk_data) + HLL_LIBRARY(DrawDungeon, - HLL_EXPORT(Init, DrawDungeon_Init), - HLL_EXPORT(Release, DrawDungeon_Release), - HLL_EXPORT(SetDrawFlag, DrawDungeon_SetDrawFlag), - HLL_EXPORT(BeginLoad, DrawDungeon_BeginLoad), - HLL_EXPORT(IsLoading, DrawDungeon_IsLoading), - HLL_EXPORT(IsSucceededLoading, DrawDungeon_IsSucceededLoading), - HLL_TODO_EXPORT(GetLoadingPercent, DrawDungeon_GetLoadingPercent), - HLL_TODO_EXPORT(LoadFromFile, DrawDungeon_LoadFromFile), - HLL_TODO_EXPORT(LoadTexture, DrawDungeon_LoadTexture), - HLL_TODO_EXPORT(LoadEventTexture, DrawDungeon_LoadEventTexture), - HLL_EXPORT(GetMapX, DrawDungeon_GetMapX), - HLL_EXPORT(GetMapY, DrawDungeon_GetMapY), - HLL_EXPORT(GetMapZ, DrawDungeon_GetMapZ), - HLL_EXPORT(SetCamera, dungeon_set_camera), - HLL_EXPORT(IsInMap, DrawDungeon_IsInMap), - HLL_EXPORT(IsFloor, DrawDungeon_IsFloor), - HLL_TODO_EXPORT(IsFloorFillTexture, DrawDungeon_IsFloorFillTexture), - HLL_EXPORT(IsStair, DrawDungeon_IsStair), - HLL_EXPORT(IsStairN, DrawDungeon_IsStairN), - HLL_EXPORT(IsStairW, DrawDungeon_IsStairW), - HLL_EXPORT(IsStairS, DrawDungeon_IsStairS), - HLL_EXPORT(IsStairE, DrawDungeon_IsStairE), - HLL_EXPORT(IsWallN, DrawDungeon_IsWallN), - HLL_EXPORT(IsWallW, DrawDungeon_IsWallW), - HLL_EXPORT(IsWallS, DrawDungeon_IsWallS), - HLL_EXPORT(IsWallE, DrawDungeon_IsWallE), - HLL_EXPORT(IsDoorN, DrawDungeon_IsDoorN), - HLL_EXPORT(IsDoorW, DrawDungeon_IsDoorW), - HLL_EXPORT(IsDoorS, DrawDungeon_IsDoorS), - HLL_EXPORT(IsDoorE, DrawDungeon_IsDoorE), - HLL_EXPORT(IsEnter, DrawDungeon_IsEnter), - HLL_EXPORT(IsEnterN, DrawDungeon_IsEnterN), - HLL_EXPORT(IsEnterW, DrawDungeon_IsEnterW), - HLL_EXPORT(IsEnterS, DrawDungeon_IsEnterS), - HLL_EXPORT(IsEnterE, DrawDungeon_IsEnterE), - HLL_EXPORT(GetEvFloor, DrawDungeon_GetEvFloor), - HLL_EXPORT(GetEvWallN, DrawDungeon_GetEvWallN), - HLL_EXPORT(GetEvWallW, DrawDungeon_GetEvWallW), - HLL_EXPORT(GetEvWallS, DrawDungeon_GetEvWallS), - HLL_EXPORT(GetEvWallE, DrawDungeon_GetEvWallE), - HLL_EXPORT(GetEvFloor2, DrawDungeon_GetEvFloor2), - HLL_EXPORT(GetEvWallN2, DrawDungeon_GetEvWallN2), - HLL_EXPORT(GetEvWallW2, DrawDungeon_GetEvWallW2), - HLL_EXPORT(GetEvWallS2, DrawDungeon_GetEvWallS2), - HLL_EXPORT(GetEvWallE2, DrawDungeon_GetEvWallE2), - HLL_EXPORT(GetTexFloor, DrawDungeon_GetTexFloor), - HLL_EXPORT(GetTexCeiling, DrawDungeon_GetTexCeiling), - HLL_EXPORT(GetTexWallN, DrawDungeon_GetTexWallN), - HLL_EXPORT(GetTexWallW, DrawDungeon_GetTexWallW), - HLL_EXPORT(GetTexWallS, DrawDungeon_GetTexWallS), - HLL_EXPORT(GetTexWallE, DrawDungeon_GetTexWallE), - HLL_EXPORT(GetTexDoorN, DrawDungeon_GetTexDoorN), - HLL_EXPORT(GetTexDoorW, DrawDungeon_GetTexDoorW), - HLL_EXPORT(GetTexDoorS, DrawDungeon_GetTexDoorS), - HLL_EXPORT(GetTexDoorE, DrawDungeon_GetTexDoorE), - HLL_EXPORT(GetTexStair, DrawDungeon_GetTexStair), - HLL_EXPORT(GetBattleBack, DrawDungeon_GetBattleBack), - HLL_EXPORT(SetDoorNAngle, DrawDungeon_SetDoorNAngle), - HLL_EXPORT(SetDoorWAngle, DrawDungeon_SetDoorWAngle), - HLL_EXPORT(SetDoorSAngle, DrawDungeon_SetDoorSAngle), - HLL_EXPORT(SetDoorEAngle, DrawDungeon_SetDoorEAngle), - HLL_EXPORT(SetEvFloor, DrawDungeon_SetEvFloor), - HLL_EXPORT(SetEvWallN, DrawDungeon_SetEvWallN), - HLL_EXPORT(SetEvWallW, DrawDungeon_SetEvWallW), - HLL_EXPORT(SetEvWallS, DrawDungeon_SetEvWallS), - HLL_EXPORT(SetEvWallE, DrawDungeon_SetEvWallE), - HLL_EXPORT(SetEvFloor2, DrawDungeon_SetEvFloor2), - HLL_EXPORT(SetEvWallN2, DrawDungeon_SetEvWallN2), - HLL_EXPORT(SetEvWallW2, DrawDungeon_SetEvWallW2), - HLL_EXPORT(SetEvWallS2, DrawDungeon_SetEvWallS2), - HLL_EXPORT(SetEvWallE2, DrawDungeon_SetEvWallE2), - HLL_TODO_EXPORT(SetEvMag, DrawDungeon_SetEvMag), - HLL_EXPORT(SetEvRate, DrawDungeon_SetEvRate), - HLL_EXPORT(SetEnter, DrawDungeon_SetEnter), - HLL_EXPORT(SetEnterN, DrawDungeon_SetEnterN), - HLL_EXPORT(SetEnterW, DrawDungeon_SetEnterW), - HLL_EXPORT(SetEnterS, DrawDungeon_SetEnterS), - HLL_EXPORT(SetEnterE, DrawDungeon_SetEnterE), - HLL_EXPORT(SetTexFloor, DrawDungeon_SetTexFloor), - HLL_EXPORT(SetTexCeiling, DrawDungeon_SetTexCeiling), - HLL_EXPORT(SetTexWallN, DrawDungeon_SetTexWallN), - HLL_EXPORT(SetTexWallW, DrawDungeon_SetTexWallW), - HLL_EXPORT(SetTexWallS, DrawDungeon_SetTexWallS), - HLL_EXPORT(SetTexWallE, DrawDungeon_SetTexWallE), - HLL_EXPORT(SetTexDoorN, DrawDungeon_SetTexDoorN), - HLL_EXPORT(SetTexDoorW, DrawDungeon_SetTexDoorW), - HLL_EXPORT(SetTexDoorS, DrawDungeon_SetTexDoorS), - HLL_EXPORT(SetTexDoorE, DrawDungeon_SetTexDoorE), - HLL_TODO_EXPORT(SetSkyTextureSet, DrawDungeon_SetSkyTextureSet), - HLL_EXPORT(DrawMap, dungeon_map_draw), - HLL_EXPORT(SetMapAllViewFlag, dungeon_map_set_all_view), - HLL_EXPORT(SetDrawMapFloor, dungeon_map_set_small_map_floor), - HLL_EXPORT(DrawLMap, dungeon_map_draw_lmap), - HLL_EXPORT(SetMapCG, dungeon_map_set_cg), - HLL_EXPORT(SetDrawLMapFloor, dungeon_map_set_large_map_floor), - HLL_EXPORT(SetDrawMapRadar, dungeon_map_set_radar), - HLL_EXPORT(SetDrawHalfFlag, DrawDungeon_SetDrawHalfFlag), - HLL_EXPORT(GetDrawHalfFlag, DrawDungeon_GetDrawHalfFlag), - HLL_EXPORT(SetWalked, dungeon_set_walked), - HLL_TODO_EXPORT(SetWalkedAll, DrawDungeon_SetWalkedAll), - HLL_TODO_EXPORT(CalcNumofFloor, DrawDungeon_CalcNumofFloor), - HLL_TODO_EXPORT(CalcNumofWalk, DrawDungeon_CalcNumofWalk), - HLL_TODO_EXPORT(CalcNumofWalk2, DrawDungeon_CalcNumofWalk2), - HLL_EXPORT(CalcConquer, dungeon_calc_conquer), - HLL_EXPORT(SetInterlaceMode, DrawDungeon_SetInterlaceMode), - HLL_EXPORT(SetDirect3DMode, DrawDungeon_SetDirect3DMode), - HLL_EXPORT(SaveDrawSettingFlag, DrawDungeon_SaveDrawSettingFlag), - HLL_EXPORT(GetDrawSettingFlag, DrawDungeon_GetDrawSettingFlag), - HLL_EXPORT(IsDrawSettingFile, DrawDungeon_IsDrawSettingFile), - HLL_EXPORT(DeleteDrawSettingFile, DrawDungeon_DeleteDrawSettingFile), - HLL_EXPORT(IsSSEFlag, DrawDungeon_IsSSEFlag), - HLL_EXPORT(SetSSEFlag, DrawDungeon_SetSSEFlag), - HLL_EXPORT(IsPVSData, DrawDungeon_IsPVSData), - HLL_EXPORT(GetTexSound, DrawDungeon_GetTexSound), - HLL_EXPORT(StopTimer, DrawDungeon_StopTimer), - HLL_EXPORT(RestartTimer, DrawDungeon_RestartTimer), - HLL_EXPORT(LoadWalkData, dungeon_load_walk_data), - HLL_EXPORT(SaveWalkData, dungeon_save_walk_data) - ); + HLL_EXPORT(Init, DrawDungeon_Init), + DRAW_DUNGEON_EXPORTS + ); + +HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetRasterAmp, int nSurface, float fAmp); +HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetLapFilter, int surface, int type, int r, int g, int b); +HLL_WARN_UNIMPLEMENTED(1, bool, DrawDungeon14, GetDrawMapObjectFlag, int nSurface); +HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetDrawMapObjectFlag, int nSurface, bool bFlag); + +HLL_LIBRARY(DrawDungeon14, + HLL_EXPORT(Init, DrawDungeon14_Init), + DRAW_DUNGEON_EXPORTS, + HLL_EXPORT(GetWalked, dungeon_get_walked), + HLL_TODO_EXPORT(SetRasterScroll, DrawDungeon14_SetRasterScroll), + HLL_EXPORT(SetRasterAmp, DrawDungeon14_SetRasterAmp), + HLL_EXPORT(SetLapFilter, DrawDungeon14_SetLapFilter), + HLL_EXPORT(GetDrawMapObjectFlag, DrawDungeon14_GetDrawMapObjectFlag), + HLL_EXPORT(SetDrawMapObjectFlag, DrawDungeon14_SetDrawMapObjectFlag) + ); From 1fdd88ff4d5fdd87610879a2b0fd0a920a04980c Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 13 Jun 2021 15:48:49 +0900 Subject: [PATCH 08/13] DrawDungeon14: Implement spinning motion of event markers --- src/dungeon/renderer.c | 57 +++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/src/dungeon/renderer.c b/src/dungeon/renderer.c index f1f5338..ffcc769 100644 --- a/src/dungeon/renderer.c +++ b/src/dungeon/renderer.c @@ -57,12 +57,12 @@ static const struct marker_info rance6_marker_info[] = { }; static const struct marker_info galzoo_marker_info[] = { - {11, 1, 1, GZ_MAGIC_CIRCLE}, // item - {12, 2, 1, GZ_MAGIC_CIRCLE}, // enemy - {14, 3, 1, GZ_MAGIC_CIRCLE}, // star - {15, 4, 1, GZ_MAGIC_CIRCLE}, // heart - {17, 5, 1, GZ_MAGIC_CIRCLE}, // exit - {18, 6, 1, GZ_MAGIC_CIRCLE}, // teleporter + {11, 1, 0, GZ_MAGIC_CIRCLE}, // item + {12, 2, 0, GZ_MAGIC_CIRCLE}, // enemy + {14, 3, 0, GZ_MAGIC_CIRCLE}, // star + {15, 4, 0, GZ_MAGIC_CIRCLE}, // heart + {17, 5, 0, GZ_MAGIC_CIRCLE}, // exit + {18, 6, 0, GZ_MAGIC_CIRCLE}, // teleporter {0}, }; @@ -87,6 +87,7 @@ struct dungeon_renderer { struct geometry *door_left_geometry; struct geometry *door_right_geometry; struct geometry *stairs_geometry; + struct geometry *floating_marker_geometry; struct material *materials; int nr_materials; @@ -162,6 +163,19 @@ static const struct vertex stairs_vertices[] = { {-1, -3/3.f, 3/3.f, 0, 12/12.f}, }; +static const struct vertex floating_marker_vertices[] = { + {-0.9, 0.9, 0.0, 0.0, 0.0}, + {-0.9, -0.9, 0.0, 0.0, 1.0}, + { 0.9, 0.9, 0.0, 1.0, 0.0}, + { 0.9, -0.9, 0.0, 1.0, 1.0}, + { 0.9, -0.9, 0.0, 1.0, 1.0}, // degenerate triangle + { 0.9, 0.9, 0.0, 0.0, 0.0}, // degenerate triangle + { 0.9, 0.9, 0.0, 0.0, 0.0}, + { 0.9, -0.9, 0.0, 0.0, 1.0}, + {-0.9, 0.9, 0.0, 1.0, 0.0}, + {-0.9, -0.9, 0.0, 1.0, 1.0}, +}; + struct geometry { GLuint vao; GLuint attr_buffer; @@ -247,6 +261,7 @@ struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version versi r->door_left_geometry = geometry_create(r, door_left_vertices, sizeof(door_left_vertices)); r->door_right_geometry = geometry_create(r, door_right_vertices, sizeof(door_right_vertices)); r->stairs_geometry = geometry_create(r, stairs_vertices, sizeof(stairs_vertices)); + r->floating_marker_geometry = geometry_create(r, floating_marker_vertices, sizeof(floating_marker_vertices)); const int nr_types = DTX_DOOR + 1; r->materials = xcalloc(nr_types * dtx->nr_columns, sizeof(struct material)); @@ -275,6 +290,7 @@ void dungeon_renderer_free(struct dungeon_renderer *r) geometry_free(r->door_left_geometry); geometry_free(r->door_right_geometry); geometry_free(r->stairs_geometry); + geometry_free(r->floating_marker_geometry); for (int i = 0; i < r->nr_materials; i++) delete_material(&r->materials[i]); @@ -344,17 +360,28 @@ static void draw_floor_marker(struct dungeon_renderer *r, const struct marker_in glDepthFunc(GL_LESS); } -static void draw_floating_marker(struct dungeon_renderer *r, const struct marker_info *info, float x, float y, float z, int blend_rate, uint32_t t, mat4 v) +static void draw_floating_marker(struct dungeon_renderer *r, const struct marker_info *info, float x, float y, float z, int blend_rate, uint32_t t, mat4 view_mat) { - int frame = t / 100; // 100ms per frame - int texture = info->texture_index + frame % info->texture_count; - mat4 billboard = MAT4( - v[0][0], v[0][1], v[0][2], x, - v[1][0], v[1][1], v[1][2], y, - v[2][0], v[2][1], v[2][2], z, - 0, 0, 0, 1); + int texture = info->texture_index; + mat4 m = MAT4( + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1); + if (info->texture_count) { + int frame = t / 100; // 100ms per frame + texture += frame % info->texture_count; + // Make a billboard matrix + mat3 r; + glm_mat4_pick3t(view_mat, r); + glm_mat4_ins3(r, m); + } else { + float angle = t / -(M_PI * 100.0); + glm_rotate_y(m, angle, m); + } + glUniform1f(r->alpha_mod, blend_rate / 255.0); - draw(r, r->wall_geometry, r->event_textures[texture], billboard); + draw(r, r->floating_marker_geometry, r->event_textures[texture], m); glUniform1f(r->alpha_mod, 1.0); } From 946e3bdab6c9ce07cad42e195249cc97ce127519 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 13 Jun 2021 16:55:20 +0900 Subject: [PATCH 09/13] DrawDungeon14: Implement {Get,Set}DrawMapObjectFlag --- include/dungeon/renderer.h | 2 ++ src/dungeon/renderer.c | 14 +++++++++++++- src/hll/DrawDungeon.c | 19 +++++++++++++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/include/dungeon/renderer.h b/include/dungeon/renderer.h index 4919365..2e4c993 100644 --- a/include/dungeon/renderer.h +++ b/include/dungeon/renderer.h @@ -27,5 +27,7 @@ struct dungeon_renderer; struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, struct dtx *dtx, GLuint *event_textures, int nr_event_textures); void dungeon_renderer_free(struct dungeon_renderer *r); void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells, int nr_cells, mat4 view_transform, mat4 proj_transform); +void dungeon_renderer_enable_event_markers(struct dungeon_renderer *r, bool enable); +bool dungeon_renderer_event_markers_enabled(struct dungeon_renderer *r); #endif /* SYSTEM4_DUNGEON_RENDERER_H */ diff --git a/src/dungeon/renderer.c b/src/dungeon/renderer.c index ffcc769..c055d15 100644 --- a/src/dungeon/renderer.c +++ b/src/dungeon/renderer.c @@ -96,6 +96,7 @@ struct dungeon_renderer { GLuint *event_textures; int nr_event_textures; const struct marker_info *marker_table; + bool draw_event_markers; struct skybox *skybox; }; @@ -276,6 +277,7 @@ struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version versi r->event_textures = event_textures; r->nr_event_textures = nr_event_textures; r->marker_table = marker_tables[version]; + r->draw_event_markers = true; r->skybox = skybox_create(dtx); @@ -529,7 +531,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re draw(r, r->stairs_geometry, material->texture, matrices[cell->stairs_orientation]); } } - if (cell->floor_event && !render_opaque) { + if (r->draw_event_markers && cell->floor_event && !render_opaque) { const struct marker_info *info = get_marker_info(r, cell->floor_event); if (info) { uint32_t t = SDL_GetTicks(); @@ -563,3 +565,13 @@ void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells glUseProgram(0); } + +void dungeon_renderer_enable_event_markers(struct dungeon_renderer *r, bool enable) +{ + r->draw_event_markers = enable; +} + +bool dungeon_renderer_event_markers_enabled(struct dungeon_renderer *r) +{ + return r->draw_event_markers; +} diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index c968481..01bbeb9 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -23,6 +23,7 @@ #include "dungeon/dgn.h" #include "dungeon/dungeon.h" #include "dungeon/map.h" +#include "dungeon/renderer.h" #include "dungeon/tes.h" #include "hll.h" @@ -406,8 +407,22 @@ HLL_LIBRARY(DrawDungeon, HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetRasterAmp, int nSurface, float fAmp); HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetLapFilter, int surface, int type, int r, int g, int b); -HLL_WARN_UNIMPLEMENTED(1, bool, DrawDungeon14, GetDrawMapObjectFlag, int nSurface); -HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon14, SetDrawMapObjectFlag, int nSurface, bool bFlag); + +bool DrawDungeon14_GetDrawMapObjectFlag(int surface) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->renderer) + return true; + return dungeon_renderer_event_markers_enabled(ctx->renderer); +} + +void DrawDungeon14_SetDrawMapObjectFlag(int surface, bool flag) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->renderer) + return; + dungeon_renderer_enable_event_markers(ctx->renderer, flag); +} HLL_LIBRARY(DrawDungeon14, HLL_EXPORT(Init, DrawDungeon14_Init), From 5adf8f090efb34caca568444cad7ddae33c2663e Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 19 Jun 2021 14:27:56 +0900 Subject: [PATCH 10/13] DrawDungeon14: Draw roofs This is used only in the first map of GALZOO. --- src/dungeon/dgn.c | 8 +++-- src/dungeon/renderer.c | 66 +++++++++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/dungeon/dgn.c b/src/dungeon/dgn.c index ff7873b..bba9407 100644 --- a/src/dungeon/dgn.c +++ b/src/dungeon/dgn.c @@ -89,9 +89,13 @@ struct dgn *dgn_parse(uint8_t *data, size_t size) } buffer_skip(&r, 4); cell->battle_background = buffer_read_int32(&r); - if (dgn->version != DGN_VER_GALZOO) + if (dgn->version != DGN_VER_GALZOO) { + cell->polyobj_index = -1; + cell->roof_orientation = -1; + cell->roof_texture = -1; + cell->roof_underside_texture = -1; continue; - + } cell->polyobj_index = buffer_read_int32(&r); cell->polyobj_scale = buffer_read_float(&r); cell->polyobj_rotation_y = buffer_read_float(&r); diff --git a/src/dungeon/renderer.c b/src/dungeon/renderer.c index c055d15..4f90a16 100644 --- a/src/dungeon/renderer.c +++ b/src/dungeon/renderer.c @@ -86,6 +86,7 @@ struct dungeon_renderer { struct geometry *wall_geometry; struct geometry *door_left_geometry; struct geometry *door_right_geometry; + struct geometry *roof_geometry; struct geometry *stairs_geometry; struct geometry *floating_marker_geometry; @@ -135,6 +136,13 @@ static const struct vertex door_right_vertices[] = { { 0.0, -1.0, 0.0, 1.0, 1.0}, }; +static const struct vertex roof_vertices[] = { + {-1.0, 1.0, -1.0, 0.0, 0.0}, + {-1.0, -1.0, 1.0, 0.0, 1.0}, + { 1.0, 1.0, -1.0, 1.0, 0.0}, + { 1.0, -1.0, 1.0, 1.0, 1.0}, +}; + static const struct vertex stairs_vertices[] = { { 1, 3/3.f, -3/3.f, 1, 0/12.f}, {-1, 3/3.f, -3/3.f, 0, 0/12.f}, @@ -261,6 +269,7 @@ struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version versi r->wall_geometry = geometry_create(r, wall_vertices, sizeof(wall_vertices)); r->door_left_geometry = geometry_create(r, door_left_vertices, sizeof(door_left_vertices)); r->door_right_geometry = geometry_create(r, door_right_vertices, sizeof(door_right_vertices)); + r->roof_geometry = geometry_create(r, roof_vertices, sizeof(roof_vertices)); r->stairs_geometry = geometry_create(r, stairs_vertices, sizeof(stairs_vertices)); r->floating_marker_geometry = geometry_create(r, floating_marker_vertices, sizeof(floating_marker_vertices)); @@ -291,6 +300,7 @@ void dungeon_renderer_free(struct dungeon_renderer *r) geometry_free(r->wall_geometry); geometry_free(r->door_left_geometry); geometry_free(r->door_right_geometry); + geometry_free(r->roof_geometry); geometry_free(r->stairs_geometry); geometry_free(r->floating_marker_geometry); @@ -387,6 +397,18 @@ static void draw_floating_marker(struct dungeon_renderer *r, const struct marker glUniform1f(r->alpha_mod, 1.0); } +static void stairs_matrix(mat4 dst, float x, float y, float z, int orientation) +{ + vec3 pos = {x, y, z}; + glm_translate_make(dst, pos); + const float cos[4] = {1, 0, -1, 0}; + const float sin[4] = {0, 1, 0, -1}; + dst[0][0] = cos[orientation % 4]; + dst[0][2] = -sin[orientation % 4]; + dst[2][0] = sin[orientation % 4]; + dst[2][2] = cos[orientation % 4]; +} + static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool render_opaque, mat4 view_transform) { float x = 2.0 * cell->x; @@ -506,29 +528,27 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re if (cell->stairs_texture >= 0) { struct material *material = get_material(r, DTX_STAIRS, cell->stairs_texture); if (material && material->opaque == render_opaque) { - mat4 matrices[4] = { - MAT4( - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1), - MAT4( - 0, 0, 1, x, - 0, 1, 0, y, - -1, 0, 0, z, - 0, 0, 0, 1), - MAT4( - -1, 0, 0, x, - 0, 1, 0, y, - 0, 0, -1, z, - 0, 0, 0, 1), - MAT4( - 0, 0, -1, x, - 0, 1, 0, y, - 1, 0, 0, z, - 0, 0, 0, 1) - }; - draw(r, r->stairs_geometry, material->texture, matrices[cell->stairs_orientation]); + mat4 m; + stairs_matrix(m, x, y, z, cell->stairs_orientation); + draw(r, r->stairs_geometry, material->texture, m); + } + } + if (cell->roof_texture >= 0) { + struct material *material = get_material(r, DTX_STAIRS, cell->roof_texture); + if (material && material->opaque == render_opaque) { + mat4 m; + stairs_matrix(m, x, y, z, cell->roof_orientation); + draw(r, r->roof_geometry, material->texture, m); + } + } + if (cell->roof_underside_texture >= 0) { + struct material *material = get_material(r, DTX_STAIRS, cell->roof_underside_texture); + if (material && material->opaque == render_opaque) { + mat4 m; + stairs_matrix(m, x, y, z, cell->roof_orientation); + glCullFace(GL_FRONT); + draw(r, r->roof_geometry, material->texture, m); + glCullFace(GL_BACK); } } if (r->draw_event_markers && cell->floor_event && !render_opaque) { From 057862b533d1363085ee5202cc76c319b2d09e85 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 19 Jun 2021 22:56:06 +0900 Subject: [PATCH 11/13] DrawDungeon14: Draw 3D objects in PolyObj.lin --- include/dungeon/polyobj.h | 65 +++++++++++++++++ include/dungeon/renderer.h | 3 +- src/dungeon/dungeon.c | 16 ++++- src/dungeon/polyobj.c | 133 ++++++++++++++++++++++++++++++++++ src/dungeon/renderer.c | 144 +++++++++++++++++++++++++++++++++---- src/meson.build | 1 + 6 files changed, 345 insertions(+), 17 deletions(-) create mode 100644 include/dungeon/polyobj.h create mode 100644 src/dungeon/polyobj.c diff --git a/include/dungeon/polyobj.h b/include/dungeon/polyobj.h new file mode 100644 index 0000000..015ec5e --- /dev/null +++ b/include/dungeon/polyobj.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2021 kichikuou + * + * 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 . + */ + +#ifndef SYSTEM4_POLYOBJ_H +#define SYSTEM4_POLYOBJ_H + +#include +#include +#include + +struct polyobj_location { + uint32_t offset; + uint32_t length; +}; + +struct polyobj { + uint8_t *data; + size_t size; + int nr_textures; + struct polyobj_location *textures; + int nr_objects; + struct polyobj_location *objects; +}; + +struct polyobj_triangle { + int material; + int index[3]; + vec2 uv[3]; +}; + +struct polyobj_part { + int nr_vertices; + vec3 *vertices; + int nr_triangles; + struct polyobj_triangle *triangles; +}; + +struct polyobj_object { + char *name; + int nr_materials; + int *materials; + int nr_parts; + struct polyobj_part *parts; +}; + +struct polyobj *polyobj_load(const char *path); +void polyobj_free(struct polyobj *po); +struct cg *polyobj_get_texture(struct polyobj *po, int index); +struct polyobj_object *polyobj_get_object(struct polyobj *po, int index); +void polyobj_object_free(struct polyobj_object *obj); + +#endif /* SYSTEM4_POLYOBJ_H */ diff --git a/include/dungeon/renderer.h b/include/dungeon/renderer.h index 2e4c993..c2ab08b 100644 --- a/include/dungeon/renderer.h +++ b/include/dungeon/renderer.h @@ -22,9 +22,10 @@ struct dgn_cell; struct dtx; +struct polyobj; struct dungeon_renderer; -struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, struct dtx *dtx, GLuint *event_textures, int nr_event_textures); +struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, struct dtx *dtx, GLuint *event_textures, int nr_event_textures, struct polyobj *po); void dungeon_renderer_free(struct dungeon_renderer *r); void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells, int nr_cells, mat4 view_transform, mat4 proj_transform); void dungeon_renderer_enable_event_markers(struct dungeon_renderer *r, bool enable); diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index e8263b8..3dcf193 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -31,6 +31,7 @@ #include "dungeon/dtx.h" #include "dungeon/dungeon.h" #include "dungeon/map.h" +#include "dungeon/polyobj.h" #include "dungeon/renderer.h" #include "dungeon/tes.h" #include "gfx/gfx.h" @@ -127,6 +128,8 @@ static GLuint *load_event_textures(int *nr_textures_out) bool dungeon_load(struct dungeon_context *ctx, int num) { + struct polyobj *polyobj = NULL; + if (ctx->loaded) VM_ERROR("Dungeon is already loaded"); @@ -185,6 +188,14 @@ bool dungeon_load(struct dungeon_context *ctx, int num) free(tes); } free(path); + + char *polyobj_path = gamedir_path("Data/PolyObj.lin"); + polyobj = polyobj_load(polyobj_path); + free(polyobj_path); + if (!polyobj) { + WARNING("Cannot load Data/PolyObj.lin"); + return false; + } } else { ERROR("Invalid DrawDungeon version %d", ctx->version); } @@ -199,7 +210,10 @@ bool dungeon_load(struct dungeon_context *ctx, int num) if (!event_textures) return false; - ctx->renderer = dungeon_renderer_create(ctx->version, ctx->dtx, event_textures, nr_event_textures); + ctx->renderer = dungeon_renderer_create(ctx->version, ctx->dtx, event_textures, nr_event_textures, polyobj); + + if (polyobj) + polyobj_free(polyobj); dungeon_map_init(ctx); diff --git a/src/dungeon/polyobj.c b/src/dungeon/polyobj.c new file mode 100644 index 0000000..be978ac --- /dev/null +++ b/src/dungeon/polyobj.c @@ -0,0 +1,133 @@ +/* Copyright (C) 2021 kichikuou + * + * 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 . + */ +#include +#include +#include "system4.h" +#include "system4/buffer.h" +#include "system4/cg.h" +#include "system4/file.h" + +#include "dungeon/polyobj.h" + +struct polyobj *polyobj_load(const char *path) +{ + size_t size; + uint8_t *data = file_read(path, &size); + if (!data) + return NULL; + struct buffer r; + buffer_init(&r, data, size); + if (memcmp(buffer_strdata(&r), "POL\0\0\0\0\0", 8)) + return NULL; + buffer_skip(&r, 8); + + struct polyobj *po = xcalloc(1, sizeof(struct polyobj)); + po->data = data; + po->size = size; + po->nr_textures = buffer_read_int32(&r); + po->textures = xcalloc(po->nr_textures, sizeof(struct polyobj_location)); + for (int i = 0; i < po->nr_textures; i++) { + po->textures[i].offset = buffer_read_int32(&r); + po->textures[i].length = buffer_read_int32(&r); + } + po->nr_objects = buffer_read_int32(&r); + po->objects = xcalloc(po->nr_objects, sizeof(struct polyobj_location)); + for (int i = 0; i < po->nr_objects; i++) { + po->objects[i].offset = buffer_read_int32(&r); + po->objects[i].length = buffer_read_int32(&r); + } + return po; +} + +void polyobj_free(struct polyobj *po) +{ + free(po->textures); + free(po->objects); + free(po->data); + free(po); +} + +struct cg *polyobj_get_texture(struct polyobj *po, int index) +{ + if (index < 0 || index >= po->nr_textures) + return NULL; + struct polyobj_location *loc = &po->textures[index]; + return cg_load_buffer(po->data + loc->offset, loc->length); +} + +struct polyobj_object *polyobj_get_object(struct polyobj *po, int index) +{ + if (index < 0 || index >= po->nr_objects) + return NULL; + struct polyobj_location *loc = &po->objects[index]; + struct buffer r; + buffer_init(&r, po->data + loc->offset, loc->length); + + struct polyobj_object *obj = xcalloc(1, sizeof(struct polyobj_object)); + obj->name = strdup(buffer_strdata(&r)); + buffer_skip(&r, strlen(obj->name) + 1); + if (memcmp(buffer_strdata(&r), "POO\0\0\0\0\0", 8)) { + polyobj_object_free(obj); + return NULL; + } + buffer_skip(&r, 8); + obj->nr_materials = buffer_read_int32(&r); + obj->materials = xcalloc(obj->nr_materials, sizeof(int)); + for (int i = 0; i < obj->nr_materials; i++) + obj->materials[i] = buffer_read_int32(&r); + obj->nr_parts = buffer_read_int32(&r); + obj->parts = xcalloc(obj->nr_parts, sizeof(struct polyobj_part)); + for (int i = 0; i < obj->nr_parts; i++) { + struct polyobj_part *part = &obj->parts[i]; + part->nr_vertices = buffer_read_int32(&r); + part->vertices = xcalloc(part->nr_vertices, sizeof(vec3)); + for (int j = 0; j < part->nr_vertices; j++) { + part->vertices[j][0] = buffer_read_float(&r); + part->vertices[j][1] = buffer_read_float(&r); + part->vertices[j][2] = buffer_read_float(&r); + } + + part->nr_triangles = buffer_read_int32(&r); + part->triangles = xcalloc(part->nr_triangles, sizeof(struct polyobj_triangle)); + for (int j = 0; j < part->nr_triangles; j++) { + struct polyobj_triangle *triangle = &part->triangles[j]; + triangle->material = buffer_read_int32(&r); + triangle->index[0] = buffer_read_int32(&r); + triangle->index[1] = buffer_read_int32(&r); + triangle->index[2] = buffer_read_int32(&r); + triangle->uv[0][0] = buffer_read_float(&r); + triangle->uv[0][1] = buffer_read_float(&r); + triangle->uv[1][0] = buffer_read_float(&r); + triangle->uv[1][1] = buffer_read_float(&r); + triangle->uv[2][0] = buffer_read_float(&r); + triangle->uv[2][1] = buffer_read_float(&r); + } + } + return obj; +} + +void polyobj_object_free(struct polyobj_object *obj) +{ + for (int i = 0; i < obj->nr_parts; i++) { + struct polyobj_part *part = &obj->parts[i]; + free(part->vertices); + free(part->triangles); + } + free(obj->parts); + free(obj->materials); + free(obj->name); + free(obj); +} diff --git a/src/dungeon/renderer.c b/src/dungeon/renderer.c index 4f90a16..d3a2113 100644 --- a/src/dungeon/renderer.c +++ b/src/dungeon/renderer.c @@ -20,11 +20,13 @@ #include #include #include "system4.h" +#include "system4/buffer.h" #include "system4/cg.h" #include "dungeon/dungeon.h" #include "dungeon/dgn.h" #include "dungeon/dtx.h" +#include "dungeon/polyobj.h" #include "dungeon/renderer.h" #include "dungeon/skybox.h" #include "gfx/gfx.h" @@ -73,6 +75,7 @@ static const struct marker_info *marker_tables[] = { struct geometry; struct material; +struct object3d; struct dungeon_renderer { struct shader shader; @@ -99,6 +102,11 @@ struct dungeon_renderer { const struct marker_info *marker_table; bool draw_event_markers; + int nr_polyobjs; + struct object3d *polyobjs; + int nr_polyobj_materials; + struct material *polyobj_materials; + struct skybox *skybox; }; @@ -189,12 +197,14 @@ struct geometry { GLuint vao; GLuint attr_buffer; int nr_vertices; + GLenum mode; }; -static struct geometry *geometry_create(struct dungeon_renderer *r, const struct vertex *vertices, size_t size) +static struct geometry *geometry_create(struct dungeon_renderer *r, const struct vertex *vertices, size_t size, GLenum mode) { struct geometry *g = xcalloc(1, sizeof(struct geometry)); g->nr_vertices = size / sizeof(struct vertex); + g->mode = mode; glGenVertexArrays(1, &g->vao); glBindVertexArray(g->vao); @@ -224,11 +234,8 @@ struct material { bool opaque; }; -static void init_material(struct material *m, struct dtx *dtx, int type, int index) +static void init_material(struct material *m, struct cg *cg) { - struct cg *cg = dtx_create_cg(dtx, type, index); - if (!cg) - return; glGenTextures(1, &m->texture); glBindTexture(GL_TEXTURE_2D, m->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels); @@ -239,7 +246,6 @@ static void init_material(struct material *m, struct dtx *dtx, int type, int ind glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); m->opaque = !cg->metrics.has_alpha; - cg_free(cg); } static void delete_material(struct material *m) @@ -256,7 +262,77 @@ static struct material *get_material(struct dungeon_renderer *r, int type, int i return m; } -struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, struct dtx *dtx, GLuint *event_textures, int nr_event_textures) +struct mesh { + struct geometry *geometry; + int material; +}; + +struct object3d { + int nr_meshes; + struct mesh *meshes; +}; + +static void init_object3d(struct object3d *o3d, struct dungeon_renderer *r, const struct polyobj_object *obj) +{ + o3d->nr_meshes = obj->nr_materials; + o3d->meshes = xcalloc(obj->nr_materials, sizeof(struct mesh)); + for (int i = 0; i < obj->nr_materials; i++) + o3d->meshes[i].material = obj->materials[i]; + + struct buffer *bufs = xcalloc(obj->nr_materials, sizeof(struct buffer)); + for (int i = 0; i < obj->nr_parts; i++) { + const struct polyobj_part *part = &obj->parts[i]; + for (int j = 0; j < part->nr_triangles; j++) { + const struct polyobj_triangle *triangle = &part->triangles[j]; + for (int k = 0; k < 3; k++) { + const int ltor[] = {0, 2, 1}; // left->right handed system + const vec3 *pos = &part->vertices[triangle->index[ltor[k]]]; + const vec2 *uv = &triangle->uv[ltor[k]]; + buffer_write_float(&bufs[triangle->material], (*pos)[0]); // x + buffer_write_float(&bufs[triangle->material], (*pos)[1]); // y + buffer_write_float(&bufs[triangle->material], -(*pos)[2]); // z + buffer_write_float(&bufs[triangle->material], (*uv)[0]); // u + buffer_write_float(&bufs[triangle->material], (*uv)[1]); // v + } + } + } + + for (int i = 0; i < obj->nr_materials; i++) { + o3d->meshes[i].geometry = geometry_create(r, (const struct vertex *)bufs[i].buf, bufs[i].index, GL_TRIANGLES); + free(bufs[i].buf); + } + free(bufs); +} + +static void delete_object3d(struct object3d *o3d) +{ + for (int i = 0; i < o3d->nr_meshes; i++) + geometry_free(o3d->meshes[i].geometry); + free(o3d->meshes); +} + +static void init_polyobjs(struct dungeon_renderer *r, struct polyobj *po) +{ + r->nr_polyobj_materials = po->nr_textures; + r->polyobj_materials = xcalloc(po->nr_textures, sizeof(struct material)); + for (int i = 0; i < po->nr_textures; i++) { + struct cg *cg = polyobj_get_texture(po, i); + init_material(&r->polyobj_materials[i], cg); + cg_free(cg); + } + + r->nr_polyobjs = po->nr_objects; + r->polyobjs = xcalloc(po->nr_objects, sizeof(struct object3d)); + for (int i = 0; i < po->nr_objects; i++) { + struct polyobj_object *obj = polyobj_get_object(po, i); + if (!obj) + continue; + init_object3d(&r->polyobjs[i], r, obj); + polyobj_object_free(obj); + } +} + +struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, struct dtx *dtx, GLuint *event_textures, int nr_event_textures, struct polyobj *po) { struct dungeon_renderer *r = xcalloc(1, sizeof(struct dungeon_renderer)); @@ -266,18 +342,22 @@ struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version versi 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)); - r->door_left_geometry = geometry_create(r, door_left_vertices, sizeof(door_left_vertices)); - r->door_right_geometry = geometry_create(r, door_right_vertices, sizeof(door_right_vertices)); - r->roof_geometry = geometry_create(r, roof_vertices, sizeof(roof_vertices)); - r->stairs_geometry = geometry_create(r, stairs_vertices, sizeof(stairs_vertices)); - r->floating_marker_geometry = geometry_create(r, floating_marker_vertices, sizeof(floating_marker_vertices)); + 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); + r->door_right_geometry = geometry_create(r, door_right_vertices, sizeof(door_right_vertices), GL_TRIANGLE_STRIP); + r->roof_geometry = geometry_create(r, roof_vertices, sizeof(roof_vertices), GL_TRIANGLE_STRIP); + r->stairs_geometry = geometry_create(r, stairs_vertices, sizeof(stairs_vertices), GL_TRIANGLE_STRIP); + r->floating_marker_geometry = geometry_create(r, floating_marker_vertices, sizeof(floating_marker_vertices), GL_TRIANGLE_STRIP); const int nr_types = DTX_DOOR + 1; r->materials = xcalloc(nr_types * dtx->nr_columns, sizeof(struct material)); for (int type = 0; type < nr_types; type++) { for (int i = 0; i < dtx->nr_columns; i++) { - init_material(&r->materials[type * dtx->nr_columns + i], dtx, type, i); + struct cg *cg = dtx_create_cg(dtx, type, i); + if (!cg) + continue; + init_material(&r->materials[type * dtx->nr_columns + i], cg); + cg_free(cg); } } r->nr_dtx_columns = dtx->nr_columns; @@ -288,6 +368,9 @@ struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version versi r->marker_table = marker_tables[version]; r->draw_event_markers = true; + if (po) + init_polyobjs(r, po); + r->skybox = skybox_create(dtx); return r; @@ -311,6 +394,13 @@ void dungeon_renderer_free(struct dungeon_renderer *r) glDeleteTextures(r->nr_event_textures, r->event_textures); free(r->event_textures); + for (int i = 0; i < r->nr_polyobjs; i++) + delete_object3d(&r->polyobjs[i]); + free(r->polyobjs); + for (int i = 0; i < r->nr_polyobj_materials; i++) + delete_material(&r->polyobj_materials[i]); + free(r->polyobj_materials); + skybox_free(r->skybox); free(r); @@ -326,7 +416,7 @@ static void draw(struct dungeon_renderer *r, struct geometry *geometry, GLuint t glUniform1i(r->shader.texture, 0); glBindVertexArray(geometry->vao); - glDrawArrays(GL_TRIANGLE_STRIP, 0, geometry->nr_vertices); + glDrawArrays(geometry->mode, 0, geometry->nr_vertices); glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); } @@ -397,6 +487,22 @@ static void draw_floating_marker(struct dungeon_renderer *r, const struct marker glUniform1f(r->alpha_mod, 1.0); } +static void draw_object3d(struct dungeon_renderer *r, struct object3d *o3d, bool render_opaque, vec3 pos, float scale, float rotation_y) +{ + mat4 m; + glm_translate_make(m, pos); + glm_rotate_y(m, glm_rad(rotation_y), m); + glm_scale_uni(m, scale); + + for (int i = 0; i < o3d->nr_meshes; i++) { + struct mesh *mesh = &o3d->meshes[i]; + struct material *material = &r->polyobj_materials[mesh->material]; + if (material->opaque != render_opaque) + continue; + draw(r, mesh->geometry, material->texture, m); + } +} + static void stairs_matrix(mat4 dst, float x, float y, float z, int orientation) { vec3 pos = {x, y, z}; @@ -551,6 +657,14 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re glCullFace(GL_BACK); } } + if (cell->polyobj_index >= 0) { + vec3 pos = { + x + cell->polyobj_position_x, + y + cell->polyobj_position_y - 1, + z - cell->polyobj_position_z + }; + draw_object3d(r, &r->polyobjs[cell->polyobj_index], render_opaque, pos, cell->polyobj_scale, cell->polyobj_rotation_y); + } if (r->draw_event_markers && cell->floor_event && !render_opaque) { const struct marker_info *info = get_marker_info(r, cell->floor_event); if (info) { diff --git a/src/meson.build b/src/meson.build index ad68edc..199cb77 100644 --- a/src/meson.build +++ b/src/meson.build @@ -23,6 +23,7 @@ xsystem4 = ['audio.c', 'dungeon/dtx.c', 'dungeon/dungeon.c', 'dungeon/map.c', + 'dungeon/polyobj.c', 'dungeon/renderer.c', 'dungeon/skybox.c', 'dungeon/tes.c', From da5ac4a26c9f8fc6efe1cd55120e3d85e678a2f0 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 20 Jun 2021 10:35:07 +0900 Subject: [PATCH 12/13] Support OpenGL ES 3.0 This adds `USE_GLES` compile-time flag. If it's defined, gfx_init() requests an OpenGL ES >=3.0 context. This also makes the following changes to make it work with OpenGL ES: - The USE_GLES flag also switches shader's #version directive, which is now provided separately from the .glsl file. - Implicit conversion between int and float is not supported in GLSL ES. - Use GL_RGB in gfx_copy_main_surface. Because main_surface is in GL_RGB format, using GL_RGBA generates GL_INVALID_OPERATION in OpenGL ES. --- shaders/blend_amap_alpha.f.glsl | 2 -- shaders/blend_amap_color.f.glsl | 2 -- shaders/copy.f.glsl | 2 -- shaders/copy_alpha_key.f.glsl | 2 -- shaders/copy_color_reverse.f.glsl | 2 -- shaders/copy_key.f.glsl | 2 -- shaders/copy_use_amap_border.f.glsl | 2 -- shaders/copy_use_amap_under.f.glsl | 2 -- shaders/dungeon.f.glsl | 2 -- shaders/dungeon.v.glsl | 2 -- shaders/dungeon_skybox.f.glsl | 2 -- shaders/dungeon_skybox.v.glsl | 2 -- shaders/fill.f.glsl | 2 -- shaders/fill_amap_over_border.f.glsl | 2 -- shaders/fill_amap_under_border.f.glsl | 2 -- shaders/hitbox.f.glsl | 6 ++--- shaders/hitbox_noblend.f.glsl | 8 +++---- shaders/render.f.glsl | 2 -- shaders/render.v.glsl | 2 -- src/video.c | 32 ++++++++++++++++++++++----- 20 files changed, 31 insertions(+), 49 deletions(-) diff --git a/shaders/blend_amap_alpha.f.glsl b/shaders/blend_amap_alpha.f.glsl index 6adb70b..1f46f9d 100644 --- a/shaders/blend_amap_alpha.f.glsl +++ b/shaders/blend_amap_alpha.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform float threshold; diff --git a/shaders/blend_amap_color.f.glsl b/shaders/blend_amap_color.f.glsl index c1c4353..5250bf6 100644 --- a/shaders/blend_amap_color.f.glsl +++ b/shaders/blend_amap_color.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform vec4 color; diff --git a/shaders/copy.f.glsl b/shaders/copy.f.glsl index 6363711..46c53c3 100644 --- a/shaders/copy.f.glsl +++ b/shaders/copy.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; in vec2 tex_coord; diff --git a/shaders/copy_alpha_key.f.glsl b/shaders/copy_alpha_key.f.glsl index 2aaeaeb..03c3a12 100644 --- a/shaders/copy_alpha_key.f.glsl +++ b/shaders/copy_alpha_key.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform vec4 color; diff --git a/shaders/copy_color_reverse.f.glsl b/shaders/copy_color_reverse.f.glsl index 4160336..7a491af 100644 --- a/shaders/copy_color_reverse.f.glsl +++ b/shaders/copy_color_reverse.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; in vec2 tex_coord; diff --git a/shaders/copy_key.f.glsl b/shaders/copy_key.f.glsl index 4ab69e4..3c33ff0 100644 --- a/shaders/copy_key.f.glsl +++ b/shaders/copy_key.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform vec4 color; diff --git a/shaders/copy_use_amap_border.f.glsl b/shaders/copy_use_amap_border.f.glsl index ef1f4da..f11ba31 100644 --- a/shaders/copy_use_amap_border.f.glsl +++ b/shaders/copy_use_amap_border.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform float threshold; diff --git a/shaders/copy_use_amap_under.f.glsl b/shaders/copy_use_amap_under.f.glsl index 342713c..3a57319 100644 --- a/shaders/copy_use_amap_under.f.glsl +++ b/shaders/copy_use_amap_under.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform float threshold; diff --git a/shaders/dungeon.f.glsl b/shaders/dungeon.f.glsl index 0e7c456..cb60d00 100644 --- a/shaders/dungeon.f.glsl +++ b/shaders/dungeon.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform float alpha_mod; diff --git a/shaders/dungeon.v.glsl b/shaders/dungeon.v.glsl index 4cfe35f..4828602 100644 --- a/shaders/dungeon.v.glsl +++ b/shaders/dungeon.v.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform mat4 local_transform; uniform mat4 view_transform; uniform mat4 proj_transform; diff --git a/shaders/dungeon_skybox.f.glsl b/shaders/dungeon_skybox.f.glsl index 2ef08a0..fdb1aab 100644 --- a/shaders/dungeon_skybox.f.glsl +++ b/shaders/dungeon_skybox.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform samplerCube tex; in vec3 tex_coord; diff --git a/shaders/dungeon_skybox.v.glsl b/shaders/dungeon_skybox.v.glsl index 6f36502..18f7ea3 100644 --- a/shaders/dungeon_skybox.v.glsl +++ b/shaders/dungeon_skybox.v.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform mat4 view_transform; uniform mat4 proj_transform; diff --git a/shaders/fill.f.glsl b/shaders/fill.f.glsl index 1dce654..27d5c84 100644 --- a/shaders/fill.f.glsl +++ b/shaders/fill.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform vec4 color; in vec2 tex_coord; diff --git a/shaders/fill_amap_over_border.f.glsl b/shaders/fill_amap_over_border.f.glsl index 88b5310..a5f4835 100644 --- a/shaders/fill_amap_over_border.f.glsl +++ b/shaders/fill_amap_over_border.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform float threshold; uniform vec4 color; diff --git a/shaders/fill_amap_under_border.f.glsl b/shaders/fill_amap_under_border.f.glsl index 02406e8..df6839d 100644 --- a/shaders/fill_amap_under_border.f.glsl +++ b/shaders/fill_amap_under_border.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform float threshold; uniform vec4 color; diff --git a/shaders/hitbox.f.glsl b/shaders/hitbox.f.glsl index d0602b6..e1e3e4a 100644 --- a/shaders/hitbox.f.glsl +++ b/shaders/hitbox.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform vec2 bot_left; uniform vec2 top_right; @@ -29,11 +27,11 @@ float point_in_rect(vec2 p, vec2 bot_left, vec2 top_right) { } void main() { - ivec2 size = textureSize(tex, 0); + vec2 size = vec2(textureSize(tex, 0)); vec2 tex_bot_left = bot_left / size; vec2 tex_top_right = top_right / size; vec4 texel = texture(tex, tex_coord); float t = point_in_rect(tex_coord, tex_bot_left, tex_top_right); - frag_color = t * texel + (1 - t) * vec4(0, 0, 0, 0); + frag_color = t * texel + (1.0 - t) * vec4(0, 0, 0, 0); } diff --git a/shaders/hitbox_noblend.f.glsl b/shaders/hitbox_noblend.f.glsl index 9c13e00..f935441 100644 --- a/shaders/hitbox_noblend.f.glsl +++ b/shaders/hitbox_noblend.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform vec2 bot_left; uniform vec2 top_right; @@ -29,12 +27,12 @@ float point_in_rect(vec2 p, vec2 bot_left, vec2 top_right) { } void main() { - ivec2 size = textureSize(tex, 0); + vec2 size = vec2(textureSize(tex, 0)); vec2 tex_bot_left = bot_left / size; vec2 tex_top_right = top_right / size; vec4 texel = texture(tex, tex_coord); - texel.a = 1; + texel.a = 1.0; float t = point_in_rect(tex_coord, tex_bot_left, tex_top_right); - frag_color = t * texel + (1 - t) * vec4(0, 0, 0, 0); + frag_color = t * texel + (1.0 - t) * vec4(0, 0, 0, 0); } diff --git a/shaders/render.f.glsl b/shaders/render.f.glsl index d3f73ae..d7131e7 100644 --- a/shaders/render.f.glsl +++ b/shaders/render.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; uniform float alpha_mod; diff --git a/shaders/render.v.glsl b/shaders/render.v.glsl index e76cec5..711a935 100644 --- a/shaders/render.v.glsl +++ b/shaders/render.v.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform mat4 world_transform; uniform mat4 view_transform; diff --git a/src/video.c b/src/video.c index 0cd6644..da0e22c 100644 --- a/src/video.c +++ b/src/video.c @@ -32,6 +32,19 @@ struct sdl_private sdl; +/* + * Define this to target OpenGL ES 3.0. + */ +//#define USE_GLES + +static const GLchar glsl_preamble[] = +#ifdef USE_GLES + "#version 300 es\n" + "precision highp float;\n"; +#else + "#version 140\n"; +#endif + /* * Transform from the window coordinate system -> clip-space. * @@ -84,16 +97,17 @@ static GLuint load_shader_file(const char *path, GLenum type) { GLint shader_compiled; GLuint shader; - const GLchar *source; - - source = read_shader_file(path); + const GLchar *source[2] = { + glsl_preamble, + read_shader_file(path) + }; shader = glCreateShader(type); - glShaderSource(shader, 1, &source, NULL); + glShaderSource(shader, 2, source, NULL); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_compiled); if (!shader_compiled) ERROR("Failed to compile shader: %s", path); - free((char*)source); + free((char*)source[1]); return shader; } @@ -164,9 +178,15 @@ int gfx_init(void) if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) ERROR("SDL_Init failed: %s", SDL_GetError()); +#ifdef USE_GLES + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); +#else SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#endif sdl.format = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA32); sdl.window = SDL_CreateWindow("XSystem4", @@ -455,7 +475,7 @@ void gfx_init_texture_blank(struct texture *t, int w, int h) void gfx_copy_main_surface(struct texture *dst) { init_texture(dst, main_surface.w, main_surface.h); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, main_surface.w, main_surface.h, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, main_surface.w, main_surface.h, 0); } void gfx_delete_texture(struct texture *t) From 86a5c62fc753f1ab08a99db6d32449bc9f1d3e28 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 20 Jun 2021 17:14:40 +0900 Subject: [PATCH 13/13] Fix text rendering in OpenGL ES 3 In OpenGL ES 3, glTexImage2D cannot handle GL_BGRA format. SDL_ttf returns pixels in BGRA format (because it's the format used in FreeType2), so it needs to be converted to RGBA before passing to gfx_init_texture_with_pixels. --- include/gfx/gfx.h | 2 +- src/fnl_render.c | 2 +- src/text.c | 8 +++++--- src/video.c | 10 +++++----- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h index e93d2d1..e6feb85 100644 --- a/include/gfx/gfx.h +++ b/include/gfx/gfx.h @@ -87,7 +87,7 @@ void gfx_init_texture_blank(struct texture *t, int w, int h); void gfx_init_texture_with_cg(struct texture *t, struct cg *cg); void gfx_init_texture_rgba(struct texture *t, int w, int h, SDL_Color color); void gfx_init_texture_rgb(struct texture *t, int w, int h, SDL_Color color); -void gfx_init_texture_with_pixels(struct texture *t, int w, int h, void *pixels, GLenum format); +void gfx_init_texture_with_pixels(struct texture *t, int w, int h, void *pixels); void gfx_copy_main_surface(struct texture *dst); void gfx_delete_texture(struct texture *t); GLuint gfx_set_framebuffer(GLenum target, Texture *t, int x, int y, int w, int h); diff --git a/src/fnl_render.c b/src/fnl_render.c index 898c1a6..5e69fb9 100644 --- a/src/fnl_render.c +++ b/src/fnl_render.c @@ -111,7 +111,7 @@ static void render_text(struct fnl_font_face *font, struct text_style *ts, Textu } // create texture from surface - gfx_init_texture_with_pixels(dst, width, height, surf, GL_RGBA); + gfx_init_texture_with_pixels(dst, width, height, surf); free(surf); free(glyphs); } diff --git a/src/text.c b/src/text.c index 716bd26..26ffe0d 100644 --- a/src/text.c +++ b/src/text.c @@ -252,10 +252,12 @@ static void get_glyph(TTF_Font *f, Texture *dst, char *msg, SDL_Color color) WARNING("Text rendering failed: %s", msg); return; } - if (s->format->format != SDL_PIXELFORMAT_BGRA32) { - WARNING("Wrong pixel format from SDL_ttf"); + if (s->format->format != SDL_PIXELFORMAT_RGBA32) { + SDL_Surface *tmp = SDL_ConvertSurfaceFormat(s, SDL_PIXELFORMAT_RGBA32, 0); + SDL_FreeSurface(s); + s = tmp; } - gfx_init_texture_with_pixels(dst, s->w, s->h, s->pixels, GL_BGRA); + gfx_init_texture_with_pixels(dst, s->w, s->h, s->pixels); SDL_FreeSurface(s); } diff --git a/src/video.c b/src/video.c index da0e22c..5bcaed5 100644 --- a/src/video.c +++ b/src/video.c @@ -428,15 +428,15 @@ static void init_texture(struct texture *t, int w, int h) } -void gfx_init_texture_with_pixels(struct texture *t, int w, int h, void *pixels, GLenum format) +void gfx_init_texture_with_pixels(struct texture *t, int w, int h, void *pixels) { init_texture(t, w, h); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, format, GL_UNSIGNED_BYTE, pixels); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } void gfx_init_texture_with_cg(struct texture *t, struct cg *cg) { - gfx_init_texture_with_pixels(t, cg->metrics.w, cg->metrics.h, cg->pixels, GL_RGBA); + gfx_init_texture_with_pixels(t, cg->metrics.w, cg->metrics.h, cg->pixels); t->has_alpha = cg->metrics.has_alpha; } @@ -449,7 +449,7 @@ void gfx_init_texture_rgba(struct texture *t, int w, int h, SDL_Color color) pixels[i] = c; } - gfx_init_texture_with_pixels(t, w, h, pixels, GL_RGBA); + gfx_init_texture_with_pixels(t, w, h, pixels); free(pixels); } @@ -469,7 +469,7 @@ void gfx_init_texture_rgb(struct texture *t, int w, int h, SDL_Color color) void gfx_init_texture_blank(struct texture *t, int w, int h) { - gfx_init_texture_with_pixels(t, w, h, NULL, GL_RGBA); + gfx_init_texture_with_pixels(t, w, h, NULL); } void gfx_copy_main_surface(struct texture *dst)