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..f63d491 100644 --- a/include/dungeon/dungeon.h +++ b/include/dungeon/dungeon.h @@ -22,12 +22,19 @@ #include #include +struct page; struct dgn; struct dtx; 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; @@ -44,6 +51,7 @@ struct camera { */ struct dungeon_context { + enum draw_dungeon_version version; int surface; bool loaded; bool draw_enabled; @@ -56,11 +64,16 @@ 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); 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..e8559f3 100644 --- a/include/dungeon/map.h +++ b/include/dungeon/map.h @@ -17,11 +17,10 @@ #ifndef SYSTEM4_DUNGEON_MAP_H #define SYSTEM4_DUNGEON_MAP_H -struct page; 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); @@ -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/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 014f5d8..c2ab08b 100644 --- a/include/dungeon/renderer.h +++ b/include/dungeon/renderer.h @@ -22,10 +22,13 @@ struct dgn_cell; struct dtx; +struct polyobj; 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, 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); +bool dungeon_renderer_event_markers_enabled(struct dungeon_renderer *r); #endif /* SYSTEM4_DUNGEON_RENDERER_H */ diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h index 97fc1d9..e6feb85 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; @@ -88,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); @@ -102,6 +101,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/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/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 new file mode 100644 index 0000000..03c3a12 --- /dev/null +++ b/shaders/copy_alpha_key.f.glsl @@ -0,0 +1,28 @@ +/* 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 . + */ + +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/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/effects/crossfade.f.glsl b/shaders/effects/crossfade.f.glsl index c92de0f..24f2cdd 100644 --- a/shaders/effects/crossfade.f.glsl +++ b/shaders/effects/crossfade.f.glsl @@ -14,9 +14,6 @@ * along with this program; if not, see . */ -#version 140 - - uniform sampler2D tex; // the new scene uniform sampler2D old; // the old scene uniform float progress; // effect progress (0..1) diff --git a/shaders/effects/mosaic.f.glsl b/shaders/effects/mosaic.f.glsl index d99af13..2da3b8e 100644 --- a/shaders/effects/mosaic.f.glsl +++ b/shaders/effects/mosaic.f.glsl @@ -14,8 +14,6 @@ * along with this program; if not, see . */ -#version 140 - uniform sampler2D tex; // the new scene uniform sampler2D old; // the old scene uniform vec2 resolution; // the screen resolution 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/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/dungeon/dgn.c b/src/dungeon/dgn.c index bf432ad..bba9407 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++) { @@ -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); @@ -146,7 +150,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 +179,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 3cb1003..3dcf193 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -25,43 +25,44 @@ #include "system4/archive.h" #include "system4/cg.h" #include "system4/dlf.h" +#include "system4/file.h" #include "dungeon/dgn.h" #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" #include "sact.h" #include "sprite.h" #include "vm.h" +#include "vm/page.h" #include "xsystem4.h" #ifndef M_PI #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) 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); 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; } @@ -78,11 +79,8 @@ void dungeon_context_free(struct dungeon_context *ctx) dungeon_renderer_free(ctx->renderer); 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; + if (ctx->map) + dungeon_map_free(ctx->map); free(ctx); } @@ -130,37 +128,78 @@ 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"); - 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); + + 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); } - 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; @@ -171,7 +210,10 @@ 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, polyobj); + + if (polyobj) + polyobj_free(polyobj); dungeon_map_init(ctx); @@ -226,6 +268,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,8 +282,158 @@ 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); 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 (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) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return 0; + return dgn_calc_conquer(ctx->dgn); +} + +/* + * WalkData serialization format: + * + * 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..6f52d1e 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; }; @@ -72,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; @@ -85,7 +86,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); } @@ -93,10 +93,11 @@ 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; - 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 +131,12 @@ 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); + 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); } @@ -159,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); @@ -243,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) @@ -275,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) @@ -302,21 +306,17 @@ 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); } } 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); @@ -325,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); @@ -334,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); @@ -344,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; } @@ -352,151 +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; } - -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/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 9f27f15..d3a2113 100644 --- a/src/dungeon/renderer.c +++ b/src/dungeon/renderer.c @@ -20,10 +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" @@ -35,34 +38,44 @@ 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, 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}, +}; + +static const struct marker_info *marker_tables[] = { + [DRAW_DUNGEON_1] = rance6_marker_info, + [DRAW_DUNGEON_14] = galzoo_marker_info +}; struct geometry; struct material; +struct object3d; struct dungeon_renderer { struct shader shader; @@ -76,7 +89,9 @@ 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; struct material *materials; int nr_materials; @@ -84,10 +99,26 @@ struct dungeon_renderer { GLuint *event_textures; int nr_event_textures; + 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; }; +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; }; @@ -113,6 +144,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}, @@ -142,16 +180,31 @@ 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; 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); @@ -181,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); @@ -196,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) @@ -213,7 +262,77 @@ 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 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)); @@ -223,16 +342,22 @@ struct dungeon_renderer *dungeon_renderer_create(struct dtx *dtx, GLuint *event_ 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->stairs_geometry = geometry_create(r, stairs_vertices, sizeof(stairs_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; @@ -240,6 +365,11 @@ 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->draw_event_markers = true; + + if (po) + init_polyobjs(r, po); r->skybox = skybox_create(dtx); @@ -253,7 +383,9 @@ 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); for (int i = 0; i < r->nr_materials; i++) delete_material(&r->materials[i]); @@ -262,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); @@ -277,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); } @@ -323,20 +462,59 @@ 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); } +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}; + 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; @@ -456,33 +634,39 @@ 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->floor_event && !render_opaque) { - const struct marker_info *info = get_marker_info(cell->floor_event); + 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 (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) { uint32_t t = SDL_GetTicks(); draw_floor_marker(r, info, x, y, z, t); @@ -515,3 +699,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/ffi.c b/src/ffi.c index 6a72327..cefdeea 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -291,9 +291,11 @@ 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; +extern struct static_library lib_DrawSimpleText; extern struct static_library lib_File; extern struct static_library lib_FileOperation; extern struct static_library lib_GoatGUIEngine; @@ -338,9 +340,11 @@ static struct static_library *static_libraries[] = { &lib_CrayfishLogViewer, &lib_DataFile, &lib_DrawDungeon, + &lib_DrawDungeon14, &lib_DrawGraph, &lib_DrawMovie2, &lib_DrawPluginManager, + &lib_DrawSimpleText, &lib_File, &lib_FileOperation, &lib_GoatGUIEngine, 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/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index 81e82b1..01bbeb9 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -23,11 +23,22 @@ #include "dungeon/dgn.h" #include "dungeon/dungeon.h" #include "dungeon/map.h" +#include "dungeon/renderer.h" #include "dungeon/tes.h" #include "hll.h" 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 +60,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 +280,157 @@ 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_map_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(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_map_load_walk_data), - HLL_EXPORT(SaveWalkData, dungeon_map_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); + +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), + 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) + ); 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), 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/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)); 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/meson.build b/src/meson.build index 01b2a3d..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', @@ -47,6 +48,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', 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; 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 e023df3..5bcaed5 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", @@ -234,7 +254,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 +390,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 +400,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,21 +423,20 @@ 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; } -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; } @@ -439,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); } @@ -459,13 +469,13 @@ 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) { 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)