From 554f742a000c8594a5171bdaa5ab51306626b1b9 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Thu, 24 Jul 2025 11:27:38 +0900 Subject: [PATCH] Pastel Chime Continue: Add DrawField HLL DrawField is a variant of DrawDungeon. Unlike the first-person perspective of DrawDungeon, DrawField uses a third-person, bird's-eye view camera. Key features include: - Character Rendering: A new system to render up to 256 billboarded sprites (characters, enemies, etc.) in the 3D world. The renderer supports controlling position, sprite animation, and visibility for each character. - DrawField HLL API: Functions for loading assets, managing characters, and manipulating dungeon properties like door locks. - Renderer: The core renderer is updated to support the DrawField mode. This includes disabling fog, handling sprite sheets via UV manipulation, and rendering ceilings as billboards. - Map: The 2D map has been updated to reflect the DrawField style, including colored door lock indicators. --- include/dungeon/dgn.h | 22 +- include/dungeon/dungeon.h | 19 +- include/dungeon/map.h | 3 +- include/dungeon/renderer.h | 14 +- shaders/dungeon.f.glsl | 14 +- shaders/dungeon.v.glsl | 4 +- src/dungeon/dgn.c | 149 ++++++++----- src/dungeon/dungeon.c | 251 +++++++++++++++++---- src/dungeon/map.c | 163 ++++++++++---- src/dungeon/renderer.c | 198 +++++++++++++--- src/dungeon/skybox.c | 4 +- src/ffi.c | 2 + src/hll/DrawDungeon.c | 446 ++++++++++++++++++++++++++++++++++++- 13 files changed, 1104 insertions(+), 185 deletions(-) diff --git a/include/dungeon/dgn.h b/include/dungeon/dgn.h index 0279b7e..7c9a0f2 100644 --- a/include/dungeon/dgn.h +++ b/include/dungeon/dgn.h @@ -20,6 +20,7 @@ #include #include #include +#include /* * Dungeon data is a collection of cells indexed by three integers (x, y, z). @@ -92,6 +93,10 @@ struct dgn_cell { float south_door_angle; float east_door_angle; float west_door_angle; + int north_door_lock; + int south_door_lock; + int east_door_lock; + int west_door_lock; int32_t floor_event2; int32_t north_event2; int32_t south_event2; @@ -113,19 +118,28 @@ struct packed_pvs { }; struct dgn { - uint32_t version; // 10: Rance VI, 13: GALZOO Island + uint32_t version; uint32_t size_x; uint32_t size_y; uint32_t size_z; // uint32_t unknown[10]; struct dgn_cell *cells; struct packed_pvs *pvs; + vec3 sphere_theta; + float sphere_color_top; + float sphere_color_bottom; - int start_x, start_y; // DrawDungeon2 - int exit_x, exit_y; // DrawDungeon2 + // DrawDungeon2 + int start_x, start_y; + int exit_x, exit_y; + + // DrawField + int32_t back_color_r; + int32_t back_color_g; + int32_t back_color_b; }; -struct dgn *dgn_parse(uint8_t *data, size_t size); +struct dgn *dgn_parse(uint8_t *data, size_t size, bool for_draw_field); void dgn_free(struct dgn *dgn); int dgn_cell_index(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 939b1be..3a7a3b8 100644 --- a/include/dungeon/dungeon.h +++ b/include/dungeon/dungeon.h @@ -20,20 +20,25 @@ #include #include #include +#include #include "gfx/gfx.h" #include "plugin.h" +#define DRAWFIELD_NR_CHARACTERS 256 + struct page; struct dgn; struct dtx; struct tes; struct dungeon_renderer; struct dungeon_map; +struct drawfield_character; enum draw_dungeon_version { DRAW_DUNGEON_1, // Rance VI DRAW_DUNGEON_2, // Dungeons & Dolls - DRAW_DUNGEON_14 // GALZOO Island + DRAW_DUNGEON_14, // GALZOO Island + DRAW_FIELD // Pastel Chime Continue }; struct camera { @@ -62,6 +67,9 @@ struct dungeon_context { struct dgn *dgn; struct dtx *dtx; struct tes *tes; + ivec3 player_pos; + struct drawfield_character *characters; + mat4 proj_transform; struct dungeon_renderer *renderer; struct texture texture; GLuint depth_buffer; @@ -69,7 +77,11 @@ struct dungeon_context { struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int width, int height); bool dungeon_load(struct dungeon_context *ctx, int num); +bool dungeon_load_dungeon(struct dungeon_context *ctx, const char *filename, int num); +bool dungeon_load_texture(struct dungeon_context *ctx, const char *filename); void dungeon_set_camera(int surface, float x, float y, float z, float angle, float angle_p); +void dungeon_set_perspective(int surface, int width, int height, float near, float far, float deg); +void dungeon_set_player_pos(int surface, int x, int y, int z); 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); void dungeon_set_walked_all(int surface); @@ -77,6 +89,11 @@ 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); void dungeon_paint_step(int surface, int x, int y, int z); +void dungeon_set_chara_sprite(int surface, int num, int sprite); +void dungeon_set_chara_pos(int surface, int num, float x, float y, float z); +void dungeon_set_chara_cg(int surface, int num, int cg); +void dungeon_set_chara_cg_info(int surface, int num, int num_chara_x, int num_chara_y); +void dungeon_set_chara_show(int surface, int num, bool show); struct dungeon_context *dungeon_get_context(int surface); diff --git a/include/dungeon/map.h b/include/dungeon/map.h index e54ac95..88e8a68 100644 --- a/include/dungeon/map.h +++ b/include/dungeon/map.h @@ -32,6 +32,7 @@ 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_reveal(struct dungeon_context *ctx, int x, int y, int z, bool transparent); +void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z, bool from_walk_data); +void dungeon_map_hide(struct dungeon_context *ctx, int x, int y, int z); #endif /* SYSTEM4_DUNGEON_MAP_H */ diff --git a/include/dungeon/renderer.h b/include/dungeon/renderer.h index 3a9fc19..ec6e8c8 100644 --- a/include/dungeon/renderer.h +++ b/include/dungeon/renderer.h @@ -26,14 +26,26 @@ struct dtx; struct polyobj; struct dungeon_renderer; +struct drawfield_character { + vec3 pos; + int sprite; + int rows; + int cols; + int cg_index; + bool show; +}; + struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, int num, 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_render(struct dungeon_renderer *r, struct dgn_cell **cells, int nr_cells, struct drawfield_character *characters, 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); bool dungeon_renderer_is_floor_opaque(struct dungeon_renderer *r, struct dgn_cell *cell); void dungeon_renderer_run_post_processing(struct dungeon_renderer *r, struct texture *src, struct texture *dst); void dungeon_renderer_set_raster_scroll(struct dungeon_renderer *r, int type); void dungeon_renderer_set_raster_amp(struct dungeon_renderer *r, float amp); +void dungeon_renderer_enable_lightmap(struct dungeon_renderer *r, bool enable); +bool dungeon_renderer_get_draw_obj_flag(struct dungeon_renderer *r, int type); +void dungeon_renderer_set_draw_obj_flag(struct dungeon_renderer *r, int type, bool flag); #endif /* SYSTEM4_DUNGEON_RENDERER_H */ diff --git a/shaders/dungeon.f.glsl b/shaders/dungeon.f.glsl index 3232ebb..99a4816 100644 --- a/shaders/dungeon.f.glsl +++ b/shaders/dungeon.f.glsl @@ -18,6 +18,7 @@ uniform sampler2D tex; uniform sampler2D light_texture; uniform bool use_lightmap; uniform float alpha_mod; +uniform bool use_fog; in float dist; in vec2 tex_coord; @@ -32,7 +33,14 @@ void main() { if (use_lightmap) { light_factor = texture(light_texture, tex_coord).a; } - float fog_factor = (FOG_MAX_DIST - dist) / FOG_MAX_DIST; - fog_factor = clamp(fog_factor, 0.3, 1.0); - frag_color = vec4(mix(FOG_COLOR, texel.rgb * light_factor, fog_factor), texel.a * alpha_mod); + if (use_fog) { + float fog_factor = (FOG_MAX_DIST - dist) / FOG_MAX_DIST; + fog_factor = clamp(fog_factor, 0.3, 1.0); + frag_color = vec4(mix(FOG_COLOR, texel.rgb * light_factor, fog_factor), texel.a * alpha_mod); + } else { + if (texel.a < 0.01) { + discard; + } + frag_color = vec4(texel.rgb * light_factor, texel.a * alpha_mod); + } } diff --git a/shaders/dungeon.v.glsl b/shaders/dungeon.v.glsl index 4828602..d6b6f78 100644 --- a/shaders/dungeon.v.glsl +++ b/shaders/dungeon.v.glsl @@ -17,6 +17,8 @@ uniform mat4 local_transform; uniform mat4 view_transform; uniform mat4 proj_transform; +uniform vec2 uv_offset; +uniform vec2 uv_scale; in vec3 vertex_pos; in vec2 vertex_uv; @@ -27,5 +29,5 @@ void main() { vec4 pos = view_transform * local_transform * vec4(vertex_pos, 1.0); dist = abs(pos.z); gl_Position = proj_transform * pos; - tex_coord = vertex_uv; + tex_coord = vertex_uv * uv_scale + uv_offset; } diff --git a/src/dungeon/dgn.c b/src/dungeon/dgn.c index 5a7d2f7..ebfecbb 100644 --- a/src/dungeon/dgn.c +++ b/src/dungeon/dgn.c @@ -24,7 +24,7 @@ #include "dungeon/mtrand43.h" #include "vm.h" -struct dgn *dgn_parse(uint8_t *data, size_t size) +struct dgn *dgn_parse(uint8_t *data, size_t size, bool for_draw_field) { struct buffer r; buffer_init(&r, data, size); @@ -34,11 +34,6 @@ struct dgn *dgn_parse(uint8_t *data, size_t size) struct dgn *dgn = xcalloc(1, sizeof(struct dgn)); dgn->version = buffer_read_int32(&r); - if (dgn->version != DGN_VER_RANCE6 && dgn->version != DGN_VER_GALZOO) { - WARNING("unknown DGN version: %d", dgn->version); - free(dgn); - return NULL; - } dgn->size_x = buffer_read_int32(&r); dgn->size_y = buffer_read_int32(&r); dgn->size_z = buffer_read_int32(&r); @@ -79,7 +74,7 @@ struct dgn *dgn_parse(uint8_t *data, size_t size) cell->lightmap_south = buffer_read_int32(&r); cell->lightmap_east = buffer_read_int32(&r); cell->lightmap_west = buffer_read_int32(&r); - buffer_skip(&r, 7 * 4); + buffer_skip(&r, 7 * 4); // lightmap parameters for doors / stairs, 2 unknowns cell->enterable = buffer_read_int32(&r); cell->enterable_north = buffer_read_int32(&r); cell->enterable_south = buffer_read_int32(&r); @@ -95,64 +90,102 @@ struct dgn *dgn_parse(uint8_t *data, size_t size) buffer_skip(&r, 4); buffer_skip(&r, strlen(buffer_strdata(&r)) + 1); } - buffer_skip(&r, 4); - cell->battle_background = buffer_read_int32(&r); - 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 = -1; + cell->roof_orientation = -1; + cell->roof_texture = -1; + cell->roof_underside_texture = -1; + if (for_draw_field) { + if (dgn->version >= 9) { + cell->north_door_lock = buffer_read_int32(&r); + cell->west_door_lock = buffer_read_int32(&r); + cell->south_door_lock = buffer_read_int32(&r); + cell->east_door_lock = buffer_read_int32(&r); + cell->north_door_angle = buffer_read_float(&r); + cell->west_door_angle = buffer_read_float(&r); + cell->south_door_angle = buffer_read_float(&r); + cell->east_door_angle = buffer_read_float(&r); + cell->walked = buffer_read_int32(&r); + } + if (dgn->version >= 11) { + cell->polyobj_index = buffer_read_int32(&r); + cell->polyobj_scale = buffer_read_float(&r); + cell->polyobj_rotation_y = buffer_read_float(&r); + cell->polyobj_rotation_z = buffer_read_float(&r); + cell->polyobj_rotation_x = buffer_read_float(&r); + cell->polyobj_position_x = buffer_read_float(&r); + cell->polyobj_position_y = buffer_read_float(&r); + cell->polyobj_position_z = buffer_read_float(&r); + } + } else { + buffer_skip(&r, 4); // unknown + cell->battle_background = buffer_read_int32(&r); + if (dgn->version != DGN_VER_GALZOO) { + continue; + } + cell->polyobj_index = buffer_read_int32(&r); + cell->polyobj_scale = buffer_read_float(&r); + cell->polyobj_rotation_y = buffer_read_float(&r); + cell->polyobj_rotation_z = buffer_read_float(&r); + cell->polyobj_rotation_x = buffer_read_float(&r); + cell->polyobj_position_x = buffer_read_float(&r); + cell->polyobj_position_y = buffer_read_float(&r); + cell->polyobj_position_z = buffer_read_float(&r); + cell->roof_orientation = buffer_read_int32(&r); + cell->roof_texture = buffer_read_int32(&r); + buffer_skip(&r, 4); // unknown + cell->roof_underside_texture = buffer_read_int32(&r); + buffer_skip(&r, 4); // unknown } - cell->polyobj_index = buffer_read_int32(&r); - cell->polyobj_scale = buffer_read_float(&r); - cell->polyobj_rotation_y = buffer_read_float(&r); - cell->polyobj_rotation_z = buffer_read_float(&r); - cell->polyobj_rotation_x = buffer_read_float(&r); - cell->polyobj_position_x = buffer_read_float(&r); - cell->polyobj_position_y = buffer_read_float(&r); - cell->polyobj_position_z = buffer_read_float(&r); - cell->roof_orientation = buffer_read_int32(&r); - cell->roof_texture = buffer_read_int32(&r); - buffer_skip(&r, 4); - cell->roof_underside_texture = buffer_read_int32(&r); - buffer_skip(&r, 4); } - if (buffer_read_u8(&r) != 0 || buffer_read_int32(&r) != 1) { + if (buffer_read_u8(&r) != 0) { dgn_free(dgn); return NULL; } - dgn->pvs = xcalloc(nr_cells, sizeof(struct packed_pvs)); - for (int i = 0; i < nr_cells; i++) { - struct packed_pvs *pvs = &dgn->pvs[i]; - int32_t len = buffer_read_int32(&r); - if (len % 8 != 4) { - WARNING("dgn_parse: unexpected PVS length"); - dgn_free(dgn); - return NULL; - } - if (buffer_read_int32(&r) != nr_cells) { - WARNING("dgn_parse: bad PVS"); - dgn_free(dgn); - return NULL; - } - pvs->nr_run_lengths = (len - 4) / 8; - pvs->run_lengths = xmalloc(pvs->nr_run_lengths * sizeof(struct pvs_run_lengths)); - int32_t total = 0; - for (int j = 0; j < pvs->nr_run_lengths; j++) { - int32_t invisible = buffer_read_int32(&r); - int32_t visible = buffer_read_int32(&r); - pvs->run_lengths[j].invisible_cells = invisible; - pvs->run_lengths[j].visible_cells = visible; - pvs->nr_visible_cells += visible; - total += invisible + visible; - } - if (total != nr_cells) { - WARNING("dgn_parse: bad PVS"); - dgn_free(dgn); - return NULL; + int has_pvs = buffer_read_int32(&r); + if (has_pvs) { + dgn->pvs = xcalloc(nr_cells, sizeof(struct packed_pvs)); + for (int i = 0; i < nr_cells; i++) { + struct packed_pvs *pvs = &dgn->pvs[i]; + int32_t len = buffer_read_int32(&r); + if (len % 8 != 4) { + WARNING("dgn_parse: unexpected PVS length"); + dgn_free(dgn); + return NULL; + } + if (buffer_read_int32(&r) != nr_cells) { + WARNING("dgn_parse: bad PVS"); + dgn_free(dgn); + return NULL; + } + pvs->nr_run_lengths = (len - 4) / 8; + pvs->run_lengths = xmalloc(pvs->nr_run_lengths * sizeof(struct pvs_run_lengths)); + int32_t total = 0; + for (int j = 0; j < pvs->nr_run_lengths; j++) { + int32_t invisible = buffer_read_int32(&r); + int32_t visible = buffer_read_int32(&r); + pvs->run_lengths[j].invisible_cells = invisible; + pvs->run_lengths[j].visible_cells = visible; + pvs->nr_visible_cells += visible; + total += invisible + visible; + } + if (total != nr_cells) { + WARNING("dgn_parse: bad PVS"); + dgn_free(dgn); + return NULL; + } } } + dgn->sphere_theta[0] = buffer_read_float(&r); + dgn->sphere_theta[1] = buffer_read_float(&r); + dgn->sphere_theta[2] = buffer_read_float(&r); + dgn->sphere_color_top = buffer_read_float(&r); + dgn->sphere_color_bottom = buffer_read_float(&r); + buffer_skip(&r, 4); // unknown + if (for_draw_field && dgn->version >= 10) { + dgn->back_color_r = buffer_read_int32(&r); + dgn->back_color_g = buffer_read_int32(&r); + dgn->back_color_b = buffer_read_int32(&r); + } return dgn; } diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index aada10f..6601851 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -43,10 +43,6 @@ #include "vm/page.h" #include "xsystem4.h" -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif - static const char plugin_name[] = "DrawDungeon"; static void dungeon_render(struct sact_sprite *sp); @@ -75,8 +71,13 @@ struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version glBindRenderbuffer(GL_RENDERBUFFER, ctx->depth_buffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); + glm_perspective(GLM_PIf / 3.f, (float)width / height, 0.5f, 100.f, ctx->proj_transform); ctx->map = dungeon_map_create(version); + + if (version == DRAW_FIELD) { + ctx->characters = xcalloc(DRAWFIELD_NR_CHARACTERS, sizeof(struct drawfield_character)); + } return ctx; } @@ -89,6 +90,8 @@ static void dungeon_context_free(struct draw_plugin *plugin) dtx_free(ctx->dtx); if (ctx->tes) tes_free(ctx->tes); + if (ctx->characters) + free(ctx->characters); if (ctx->renderer) dungeon_renderer_free(ctx->renderer); @@ -164,7 +167,7 @@ bool dungeon_load(struct dungeon_context *ctx, int num) struct archive_data *dgn = archive_get(dlf, num * 3); if (dgn) { - ctx->dgn = dgn_parse(dgn->data, dgn->size); + ctx->dgn = dgn_parse(dgn->data, dgn->size, false); archive_free_data(dgn); } struct archive_data *dtx = archive_get(dlf, num * 3 + 1); @@ -191,7 +194,7 @@ bool dungeon_load(struct dungeon_context *ctx, int num) size_t len; uint8_t *dgn = file_read(path, &len); if (dgn) { - ctx->dgn = dgn_parse(dgn, len); + ctx->dgn = dgn_parse(dgn, len, false); free(dgn); } @@ -242,6 +245,79 @@ bool dungeon_load(struct dungeon_context *ctx, int num) return true; } +static void dungeon_finalize_loading(struct dungeon_context *ctx) +{ + ctx->renderer = dungeon_renderer_create(ctx->version, 0, ctx->dtx, NULL, 0, NULL); + dungeon_map_init(ctx); + ctx->loaded = true; +} + +bool dungeon_load_dungeon(struct dungeon_context *ctx, const char *filename, int num) +{ + char *path = gamedir_path(filename); + size_t len; + uint8_t *dgn = file_read(path, &len); + if (!dgn) { + WARNING("Cannot load %s", path); + free(path); + return false; + } + free(path); + if (ctx->dgn) + dgn_free(ctx->dgn); + ctx->dgn = dgn_parse(dgn, len, ctx->version == DRAW_FIELD); + free(dgn); + if (!ctx->dgn) + return false; + + if (ctx->dgn && ctx->dtx) { + dungeon_finalize_loading(ctx); + } + return true; +} + +bool dungeon_load_texture(struct dungeon_context *ctx, const char *filename) +{ + // load .dtx + char *path = gamedir_path(filename); + size_t dtx_len; + uint8_t *dtx = file_read(path, &dtx_len); + if (!dtx) { + WARNING("Cannot load %s", path); + free(path); + return false; + } + if (ctx->dtx) + dtx_free(ctx->dtx); + ctx->dtx = dtx_parse(dtx, dtx_len); + free(dtx); + if (!ctx->dtx) { + free(path); + return false; + } + + // load .tes + if (ctx->tes) + tes_free(ctx->tes); + ctx->tes = NULL; + size_t path_len = strlen(path); + if (path_len > 4 && path[path_len - 4] == '.') { + strcpy(path + path_len - 4, ".tes"); // .dtx -> .tes + size_t tes_len; + uint8_t *tes = file_read(path, &tes_len); + if (tes) { + ctx->tes = tes_parse(tes, tes_len); + free(tes); + } + } + + if (ctx->dgn && ctx->dtx) { + dungeon_finalize_loading(ctx); + } + free(path); + return true; +} + void dungeon_set_camera(int surface, float x, float y, float z, float angle, float angle_p) { struct dungeon_context *ctx = dungeon_get_context(surface); @@ -250,22 +326,59 @@ void dungeon_set_camera(int surface, float x, float y, float z, float angle, flo ctx->camera.pos[0] = x; ctx->camera.pos[1] = y; ctx->camera.pos[2] = -z; - ctx->camera.angle = -angle * M_PI / 180; - ctx->camera.angle_p = angle_p * M_PI / 180; + ctx->camera.angle = -glm_rad(angle); + ctx->camera.angle_p = glm_rad(angle_p); + + if (ctx->version != DRAW_FIELD) { + ctx->player_pos[0] = roundf(x / 2.f); + ctx->player_pos[1] = roundf(y / 2.f); + ctx->player_pos[2] = roundf(z / 2.f); + } } -static void model_view_matrix(struct camera *camera, vec3 eye_out, mat4 mv_out) +void dungeon_set_perspective(int surface, int width, int height, float near, float far, float deg) { - // The actual camera position is slightly behind camera->pos. - float dist = 0.9; - vec3 d = { - dist * sin(camera->angle) * cos(camera->angle_p), - dist * sin(camera->angle_p), - dist * -cos(camera->angle) * cos(camera->angle_p), + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx) + return; + + float aspect = (float)width / height; + // XXX: Pastel Chime Continue sets unnecessarily small near (0.1) and large + // far (10000), which degrades depth buffer precision. + near = max(near, 0.4f); + far = min(far, 500.f); + glm_perspective(glm_rad(deg), aspect, near, far, ctx->proj_transform); +} + +void dungeon_set_player_pos(int surface, int x, int y, int z) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx) + return; + ctx->player_pos[0] = x; + ctx->player_pos[1] = y; + ctx->player_pos[2] = z; +} + +static void model_view_matrix(struct dungeon_context *ctx, mat4 mv_out) +{ + struct camera *camera = &ctx->camera; + float dist = 0.9f; + vec3 front = { + dist * sinf(camera->angle) * cosf(camera->angle_p), + dist * sinf(camera->angle_p), + dist * -cosf(camera->angle) * cosf(camera->angle_p), }; - glm_vec3_sub(camera->pos, d, eye_out); - vec3 up = {0.0, 1.0, 0.0}; - glm_lookat(eye_out, camera->pos, up, mv_out); + if (ctx->version != DRAW_FIELD) { + // The actual camera position is slightly behind camera->pos. + vec3 eye; + glm_vec3_sub(camera->pos, front, eye); + glm_lookat(eye, camera->pos, GLM_YUP, mv_out); + } else { + vec3 target; + glm_vec3_add(camera->pos, front, target); + glm_lookat(camera->pos, target, GLM_YUP, mv_out); + } } static void dungeon_render(struct sact_sprite *sp) @@ -279,23 +392,28 @@ static void dungeon_render(struct sact_sprite *sp) if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) ERROR("Incomplete framebuffer"); - glClearColor(0.f, 0.f, 0.f, 1.f); + glClearColor(ctx->dgn->back_color_r / 255.f, ctx->dgn->back_color_g / 255.f, ctx->dgn->back_color_b / 255.f, 1.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClearColor(0.f, 0.f, 0.f, 1.f); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); - vec3 eye; - mat4 local_transform, view_transform, proj_transform; - glm_mat4_identity(local_transform); - model_view_matrix(&ctx->camera, eye, view_transform); - glm_perspective(M_PI / 3.0, (float)ctx->texture.w / ctx->texture.h, 0.5, 100.0, proj_transform); + mat4 view_transform; + model_view_matrix(ctx, view_transform); - int dgn_x = round(eye[0] / 2.0); - int dgn_y = round(eye[1] / 2.0); - int dgn_z = round(eye[2] / -2.0); + int dgn_x, dgn_y, dgn_z; + if (ctx->version == DRAW_FIELD) { + dgn_x = 0; + dgn_y = ctx->dgn->size_y - 1; + dgn_z = 0; + } else { + dgn_x = ctx->player_pos[0]; + dgn_y = ctx->player_pos[1]; + dgn_z = ctx->player_pos[2]; + } int nr_cells; 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); + dungeon_renderer_render(ctx->renderer, cells, nr_cells, ctx->characters, view_transform, ctx->proj_transform); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); @@ -323,6 +441,7 @@ static void neighbor_reveal(struct dungeon_context *ctx, int x, int y, int z) } break; case DRAW_DUNGEON_14: + case DRAW_FIELD: // do nothing break; } @@ -333,16 +452,23 @@ 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 = ctx->version == DRAW_DUNGEON_2 ? 3 : 1; - dungeon_map_reveal(ctx, x, y, z, false); - 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 (x < 0 || y < 0 || z < 0) + return; // avoid VM_ERROR in Pastel Chime Continue + if (flag) { + dgn_cell_at(ctx->dgn, x, y, z)->walked = ctx->version == DRAW_DUNGEON_2 ? 3 : 1; + dungeon_map_reveal(ctx, x, y, z, false); + 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); + } else { + dgn_cell_at(ctx->dgn, x, y, z)->walked = 0; + dungeon_map_hide(ctx, x, y, z); + } } void dungeon_set_walked_all(int surface) @@ -482,7 +608,7 @@ static bool dd2_load_walk_data(struct dungeon_context *ctx, struct page **page) for (struct dgn_cell *c = ctx->dgn->cells; c < ctx->dgn->cells + nr_cells; c++) { c->walked = array->values[ptr++].i; if (c->walked) - dungeon_map_reveal(ctx, c->x, c->y, c->z, false); + dungeon_map_reveal(ctx, c->x, c->y, c->z, true); } return true; } @@ -498,6 +624,8 @@ bool dungeon_load_walk_data(int surface, int map, struct page **page) return dd1_load_walk_data(ctx, map, page); case DRAW_DUNGEON_2: return dd2_load_walk_data(ctx, page); + case DRAW_FIELD: + break; // DrawField does not export LoadWalkData } return false; } @@ -563,6 +691,8 @@ bool dungeon_save_walk_data(int surface, int map, struct page **page) return dd1_save_walk_data(ctx, map, page); case DRAW_DUNGEON_2: return dd2_save_walk_data(ctx, page); + case DRAW_FIELD: + break; // DrawField does not export SaveWalkData } return false; } @@ -575,6 +705,49 @@ void dungeon_paint_step(int surface, int x, int y, int z) dgn_paint_step(ctx->dgn, x, z); } +void dungeon_set_chara_sprite(int surface, int num, int sprite) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->characters || num < 0 || num >= DRAWFIELD_NR_CHARACTERS) + return; + ctx->characters[num].sprite = sprite; +} + +void dungeon_set_chara_pos(int surface, int num, float x, float y, float z) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->characters || num < 0 || num >= DRAWFIELD_NR_CHARACTERS) + return; + ctx->characters[num].pos[0] = x; + ctx->characters[num].pos[1] = y; + ctx->characters[num].pos[2] = -z; +} + +void dungeon_set_chara_cg(int surface, int num, int cg) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->characters || num < 0 || num >= DRAWFIELD_NR_CHARACTERS) + return; + ctx->characters[num].cg_index = cg; +} + +void dungeon_set_chara_cg_info(int surface, int num, int num_chara_x, int num_chara_y) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->characters || num < 0 || num >= DRAWFIELD_NR_CHARACTERS) + return; + ctx->characters[num].rows = num_chara_y; + ctx->characters[num].cols = num_chara_x; +} + +void dungeon_set_chara_show(int surface, int num, bool show) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->characters || num < 0 || num >= DRAWFIELD_NR_CHARACTERS) + return; + ctx->characters[num].show = show; +} + static cJSON *dungeon_to_json(struct sact_sprite *sp, bool verbose) { cJSON *obj, *cam; diff --git a/src/dungeon/map.c b/src/dungeon/map.c index c792260..db2bd52 100644 --- a/src/dungeon/map.c +++ b/src/dungeon/map.c @@ -25,10 +25,6 @@ #include "sact.h" #include "vm.h" -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif - static const SDL_Color unenterable_cell_color = {182, 72, 0, 0}; enum dd1_symbol_type { @@ -86,6 +82,7 @@ struct dungeon_map *dungeon_map_create(enum draw_dungeon_version version) struct dungeon_map *map = xcalloc(1, sizeof(struct dungeon_map)); switch (version) { case DRAW_DUNGEON_1: + case DRAW_FIELD: map->grid_size = 12; break; case DRAW_DUNGEON_2: @@ -120,35 +117,48 @@ void dungeon_map_init(struct dungeon_context *ctx) int map_width; int map_height; - if (ctx->version == DRAW_DUNGEON_1) { - // 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; - uint32_t min_y = dgn->size_z; - uint32_t max_x = 0; - uint32_t max_y = 0; - for (uint32_t y = 0; y < dgn->size_y; y++) { - for (uint32_t z = 0; z < dgn->size_z; z++) { - uint32_t map_y = ctx->dgn->size_z - z - 1; - for (uint32_t x = 0; x < dgn->size_x; x++) { - if (dgn_cell_at(ctx->dgn, x, y, z)->floor < 0) - continue; - min_x = min(min_x, x); - min_y = min(min_y, map_y); - max_x = max(max_x, x); - max_y = max(max_y, map_y); + switch (ctx->version) { + case DRAW_DUNGEON_1: { + // 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; + uint32_t min_y = dgn->size_z; + uint32_t max_x = 0; + uint32_t max_y = 0; + for (uint32_t y = 0; y < dgn->size_y; y++) { + for (uint32_t z = 0; z < dgn->size_z; z++) { + uint32_t map_y = ctx->dgn->size_z - z - 1; + for (uint32_t x = 0; x < dgn->size_x; x++) { + if (dgn_cell_at(ctx->dgn, x, y, z)->floor < 0) + continue; + min_x = min(min_x, x); + min_y = min(min_y, map_y); + max_x = max(max_x, x); + max_y = max(max_y, map_y); + } } } + map_width = 32; + map_height = 32; + map->offset_x = (map_width - (max_x - min_x + 1)) / 2 - min_x; + map->offset_y = (map_height - (max_y - min_y)) / 2 - min_y; } - map_width = 32; - map_height = 32; - map->offset_x = (map_width - (max_x - min_x + 1)) / 2 - min_x; - map->offset_y = (map_height - (max_y - min_y)) / 2 - min_y; - } else { + break; + case DRAW_DUNGEON_2: map_width = 19; map_height = 19; map->offset_x = 0; map->offset_y = 1; + break; + case DRAW_DUNGEON_14: + ERROR("cannot happen"); + break; + case DRAW_FIELD: + map_width = dgn->size_x; + map_height = dgn->size_z; + map->offset_x = 0; + map->offset_y = 0; + break; } // Initial draw for (uint32_t y = 0; y < dgn->size_y; y++) { @@ -164,16 +174,18 @@ void dungeon_map_init(struct dungeon_context *ctx) } } -void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z, bool transparent) +void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z, bool from_walk_data) { if (!ctx->map) return; struct texture *dst = &ctx->map->textures[y]; struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z); Point pos = texture_pos(ctx, x, z); + int alpha; switch (ctx->version) { case DRAW_DUNGEON_1: - gfx_fill_amap(dst, pos.x, pos.y, ctx->map->grid_size, ctx->map->grid_size, transparent ? 128 : 255); + alpha = from_walk_data ? 128 : 255; + gfx_fill_amap(dst, pos.x, pos.y, ctx->map->grid_size, ctx->map->grid_size, alpha); break; case DRAW_DUNGEON_2: if ((x == ctx->dgn->start_x && z == ctx->dgn->start_y) || cell->floor_event == 17) { @@ -184,11 +196,23 @@ void dungeon_map_reveal(struct dungeon_context *ctx, int x, int y, int z, bool t gfx_fill_with_alpha(dst, pos.x, pos.y, ctx->map->grid_size, ctx->map->grid_size, rg, rg, 0, 255); } break; + case DRAW_FIELD: + alpha = cell->floor == -1 ? 160 : 255; + gfx_fill_amap(dst, pos.x, pos.y, ctx->map->grid_size, ctx->map->grid_size, alpha); default: break; } } +void dungeon_map_hide(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, ctx->map->grid_size, ctx->map->grid_size, 0); +} + static void draw_hline(struct texture *dst, int x, int y, int w, SDL_Color col) { gfx_fill(dst, x, y, w, 1, col.r, col.g, col.b); @@ -298,6 +322,60 @@ static void dd2_update_cell(struct dungeon_context *ctx, int dgn_x, int dgn_y, i } } +static void df_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); + int x = pos.x; + int y = pos.y; + const int CS = ctx->map->grid_size; + + if (cell->floor >= 0) + gfx_fill(dst, x, y, CS, CS, 128, 64, 32); + else + gfx_fill(dst, x, y, CS, CS, 0, 0, 0); + + const SDL_Color wall_color = {255, 255, 255, 255}; + if (cell->north_wall >= 0) + draw_hline(dst, x, y, CS, wall_color); + if (cell->south_wall >= 0) + draw_hline(dst, x, y + CS - 1, CS, wall_color); + if (cell->west_wall >= 0) + draw_vline(dst, x, y, CS, wall_color); + if (cell->east_wall >= 0) + draw_vline(dst, x + CS - 1, y, CS, wall_color); + + const SDL_Color door_colors[2] = {{0, 255, 0, 255}, {255, 0, 0, 255}}; + if (cell->north_door >= 0) { + draw_hline(dst, x, y, CS / 2 - 1, door_colors[cell->north_door_lock]); + draw_hline(dst, x + CS / 2 - 1, y, 2, COLOR(0, 0, 0, 0)); + draw_hline(dst, x + CS / 2 + 1, y, CS / 2 - 1, door_colors[cell->north_door_lock]); + } + if (cell->south_door >= 0) { + draw_hline(dst, x, y + CS - 1, CS / 2 - 1, door_colors[cell->south_door_lock]); + draw_hline(dst, x + CS / 2 - 1, y + CS - 1, 2, COLOR(0, 0, 0, 0)); + draw_hline(dst, x + CS / 2 + 1, y + CS - 1, CS / 2 - 1, door_colors[cell->south_door_lock]); + } + if (cell->west_door >= 0) { + draw_vline(dst, x, y, CS / 2 - 1, door_colors[cell->west_door_lock]); + draw_vline(dst, x, y + CS / 2 - 1, 2, COLOR(0, 0, 0, 0)); + draw_vline(dst, x, y + CS / 2 + 1, CS / 2 - 1, door_colors[cell->west_door_lock]); + } + if (cell->east_door >= 0) { + draw_vline(dst, x + CS - 1, y, CS / 2 - 1, door_colors[cell->east_door_lock]); + draw_vline(dst, x + CS - 1, y + CS / 2 - 1, 2, COLOR(0, 0, 0, 0)); + draw_vline(dst, x + CS - 1, y + CS / 2 + 1, CS / 2 - 1, door_colors[cell->east_door_lock]); + } + + if (cell->stairs_texture >= 0) + gfx_fill(dst, x + 2, y + 2, CS - 4, CS - 4, 0, 255, 255); + else if (dgn_y && dgn_cell_at(ctx->dgn, dgn_x, dgn_y - 1, dgn_z)->stairs_texture >= 0) + gfx_fill(dst, x + 2, y + 2, CS - 4, CS - 4, 0, 0, 255); +} + void dungeon_map_update_cell(struct dungeon_context *ctx, int dgn_x, int dgn_y, int dgn_z) { switch (ctx->version) { @@ -310,6 +388,8 @@ void dungeon_map_update_cell(struct dungeon_context *ctx, int dgn_x, int dgn_y, case DRAW_DUNGEON_14: // unused break; + case DRAW_FIELD: + df_update_cell(ctx, dgn_x, dgn_y, dgn_z); } } @@ -328,7 +408,7 @@ static int player_symbol(struct dungeon_context *ctx) DD2_SYMBOL_PLAYER_WEST, }; const int *symbols = ctx->version == DRAW_DUNGEON_1 ? dd1_symbols : dd2_symbols; - return symbols[(int)(round(ctx->camera.angle * 2 / M_PI)) & 3]; + return symbols[(int)(roundf(ctx->camera.angle * 2 / GLM_PIf)) & 3]; } void dungeon_map_draw(int surface, int sprite) @@ -349,17 +429,14 @@ void dungeon_map_draw(int surface, int sprite) sprite_dirty(sp); struct texture *dst = sprite_get_texture(sp); - int player_x = round(ctx->camera.pos[0] / 2.0); - int player_y = round(ctx->camera.pos[1] / 2.0); - int player_z = round(ctx->camera.pos[2] / -2.0); int level = ctx->map->small_map_floor; if (level < 0) - level = player_y; + level = ctx->player_pos[1]; struct texture *src = &ctx->map->textures[level]; const int CS = ctx->map->grid_size; - Point pos = texture_pos(ctx, player_x, player_z); + Point pos = texture_pos(ctx, ctx->player_pos[0], ctx->player_pos[2]); int x = pos.x - (dst->w - CS) / 2; int y = pos.y - (dst->h - CS) / 2; @@ -385,12 +462,9 @@ void dungeon_map_draw_lmap(int surface, int sprite) sprite_dirty(sp); struct texture *dst = sprite_get_texture(sp); - int player_x = round(ctx->camera.pos[0] / 2.0); - int player_y = round(ctx->camera.pos[1] / 2.0); - int player_z = round(ctx->camera.pos[2] / -2.0); int level = ctx->map->large_map_floor; if (level < 0) - level = player_y; + level = ctx->player_pos[1]; struct texture *src = &ctx->map->textures[level]; gfx_copy_with_alpha_map(dst, 0, 0, src, 0, 0, src->w, src->h); @@ -399,10 +473,15 @@ void dungeon_map_draw_lmap(int surface, int sprite) gfx_fill_amap(dst, 0, 0, dst->w, dst->h, 255); // Draw the player symbol. - Point pos = texture_pos(ctx, player_x, player_z); - draw_symbol(ctx->map, dst, pos.x + 1, pos.y + 1, player_symbol(ctx)); - int size = ctx->map->grid_size - 2; - gfx_fill_amap(dst, pos.x + 1, pos.y + 1, size, size, level == player_y ? 255 : 128); + Point pos = texture_pos(ctx, ctx->player_pos[0], ctx->player_pos[2]); + if (ctx->version == DRAW_FIELD) { + int ofs = (ctx->map->grid_size - 4) / 2; + gfx_fill(dst, pos.x + ofs, pos.y + ofs, 4, 4, 255, 192, 255); + } else { + draw_symbol(ctx->map, dst, pos.x + 1, pos.y + 1, player_symbol(ctx)); + int size = ctx->map->grid_size - 2; + gfx_fill_amap(dst, pos.x + 1, pos.y + 1, size, size, level == ctx->player_pos[1] ? 255 : 128); + } } static void redraw_event_symbols(struct dungeon_context *ctx) diff --git a/src/dungeon/renderer.c b/src/dungeon/renderer.c index 09e000e..a819661 100644 --- a/src/dungeon/renderer.c +++ b/src/dungeon/renderer.c @@ -30,6 +30,7 @@ #include "dungeon/renderer.h" #include "dungeon/skybox.h" #include "gfx/gfx.h" +#include "sact.h" enum { COLOR_TEXTURE_UNIT, @@ -55,6 +56,10 @@ enum floor_marker { GZ_MAGIC_CIRCLE = 0, }; +static const struct marker_info empty_marker_info[] = { + {0}, +}; + static const struct marker_info rance6_marker_info[] = { { 11, 41, 3, R6_MAGIC_CIRCLE}, // treasure chest { 12, 51, 7, R6_RED_OCTAGRAM}, // enemy @@ -92,7 +97,8 @@ static const struct marker_info galzoo_marker_info[] = { static const struct marker_info *marker_tables[] = { [DRAW_DUNGEON_1] = rance6_marker_info, [DRAW_DUNGEON_2] = dolls_marker_info, - [DRAW_DUNGEON_14] = galzoo_marker_info + [DRAW_DUNGEON_14] = galzoo_marker_info, + [DRAW_FIELD] = empty_marker_info }; struct geometry; @@ -106,6 +112,7 @@ struct raster_shader { }; struct dungeon_renderer { + enum draw_dungeon_version version; struct shader shader; // Uniform variable locations GLint local_transform; @@ -113,6 +120,9 @@ struct dungeon_renderer { GLint alpha_mod; GLint use_lightmap; GLint light_texture; + GLint use_fog; + GLint uv_offset; + GLint uv_scale; struct geometry *wall_geometry; struct geometry *door_left_geometry; @@ -140,6 +150,19 @@ struct dungeon_renderer { struct raster_shader raster_shader; bool raster_scroll; float raster_amp; + + bool enable_lightmap; + uint32_t draw_obj_flags; +}; + +enum draw_obj_flag_index { + DRAW_POLYOBJ = 0, + DRAW_FLOOR = 1, + DRAW_WALL = 2, + DRAW_DOOR = 3, + DRAW_CEILING = 4, + DRAW_STAIRS = 5, + NR_DRAW_OBJ_FLAGS }; static const struct marker_info *get_marker_info(struct dungeon_renderer *r, int event_type) @@ -389,13 +412,21 @@ static bool is_dolls_boss_floor(int num) struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version version, int num, struct dtx *dtx, GLuint *event_textures, int nr_event_textures, struct polyobj *po) { struct dungeon_renderer *r = xcalloc(1, sizeof(struct dungeon_renderer)); - + r->version = version; gfx_load_shader(&r->shader, "shaders/dungeon.v.glsl", "shaders/dungeon.f.glsl"); r->local_transform = glGetUniformLocation(r->shader.program, "local_transform"); r->proj_transform = glGetUniformLocation(r->shader.program, "proj_transform"); r->alpha_mod = glGetUniformLocation(r->shader.program, "alpha_mod"); r->use_lightmap = glGetUniformLocation(r->shader.program, "use_lightmap"); r->light_texture = glGetUniformLocation(r->shader.program, "light_texture"); + r->use_fog = glGetUniformLocation(r->shader.program, "use_fog"); + r->uv_offset = glGetUniformLocation(r->shader.program, "uv_offset"); + r->uv_scale = glGetUniformLocation(r->shader.program, "uv_scale"); + glUseProgram(r->shader.program); + glUniform1i(r->use_fog, version != DRAW_FIELD); + glUniform2f(r->uv_offset, 0.0f, 0.0f); + glUniform2f(r->uv_scale, 1.0f, 1.0f); + glUseProgram(0); 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); @@ -433,6 +464,8 @@ struct dungeon_renderer *dungeon_renderer_create(enum draw_dungeon_version versi r->skybox = skybox_create(version, dtx); + r->enable_lightmap = true; + r->draw_obj_flags = (1 << NR_DRAW_OBJ_FLAGS) - 1; return r; } @@ -470,7 +503,8 @@ void dungeon_renderer_free(struct dungeon_renderer *r) static void set_lightmap_texture(struct dungeon_renderer *r, int texture_index) { - struct material *material = texture_index >= 0 ? get_material(r, DTX_LIGHTMAP, texture_index) : NULL; + struct material *material = (r->enable_lightmap && texture_index >= 0) + ? get_material(r, DTX_LIGHTMAP, texture_index) : NULL; glUniform1i(r->use_lightmap, !!material); if (material) { glActiveTexture(GL_TEXTURE0 + LIGHT_TEXTURE_UNIT); @@ -504,13 +538,13 @@ static void draw_door(struct dungeon_renderer *r, GLuint texture, float angle, m glm_mat4_copy(transform, m); m[3][0] += dx; m[3][2] += dz; - glm_rotate_y(m, angle * (M_PI/180), m); + glm_rotate_y(m, glm_rad(angle), m); draw(r, r->door_left_geometry, texture, m); glm_mat4_copy(transform, m); m[3][0] -= dx; m[3][2] -= dz; - glm_rotate_y(m, angle * -(M_PI/180), m); + glm_rotate_y(m, -glm_rad(angle), m); draw(r, r->door_right_geometry, texture, m); } @@ -551,7 +585,7 @@ static void draw_floating_marker(struct dungeon_renderer *r, const struct marker glm_mat4_pick3t(view_mat, r); glm_mat4_ins3(r, m); } else { - float angle = t / -(M_PI * 100.0); + float angle = t / -(GLM_PIf * 100.f); glm_rotate_y(m, angle, m); } @@ -594,7 +628,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re float y = 2.0 * cell->y; float z = -2.0 * cell->z; - if (cell->floor >= 0) { + if (cell->floor >= 0 && r->draw_obj_flags & (1 << DRAW_FLOOR)) { struct material *material = get_material(r, DTX_FLOOR, cell->floor); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -607,20 +641,32 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re set_lightmap_texture(r, -1); } } - if (cell->ceiling >= 0) { + if (cell->ceiling >= 0 && r->draw_obj_flags & (1 << DRAW_CEILING)) { struct material *material = get_material(r, DTX_CEILING, cell->ceiling); if (material && material->opaque == render_opaque) { - mat4 m = MAT4( - -1, 0, 0, x, - 0, 0, -1, y+1, - 0, -1, 0, z, - 0, 0, 0, 1); - set_lightmap_texture(r, cell->lightmap_ceiling); - draw(r, r->wall_geometry, material->texture, m); - set_lightmap_texture(r, -1); + if (r->version == DRAW_FIELD) { + // Draw as a billboard. + mat4 m; + vec3 pos = {x, y, z}; + glm_translate_make(m, pos); + mat3 r_bill; + glm_mat4_pick3t(view_transform, r_bill); + glm_mat4_ins3(r_bill, m); + glm_scale_uni(m, 1.7f); + draw(r, r->wall_geometry, material->texture, m); + } else { + mat4 m = MAT4( + -1, 0, 0, x, + 0, 0, -1, y+1, + 0, -1, 0, z, + 0, 0, 0, 1); + set_lightmap_texture(r, cell->lightmap_ceiling); + draw(r, r->wall_geometry, material->texture, m); + set_lightmap_texture(r, -1); + } } } - if (cell->north_wall >= 0) { + if (cell->north_wall >= 0 && r->draw_obj_flags & (1 << DRAW_WALL)) { struct material *material = get_material(r, DTX_WALL, cell->north_wall); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -633,7 +679,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re set_lightmap_texture(r, -1); } } - if (cell->south_wall >= 0) { + if (cell->south_wall >= 0 && r->draw_obj_flags & (1 << DRAW_WALL)) { struct material *material = get_material(r, DTX_WALL, cell->south_wall); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -646,7 +692,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re set_lightmap_texture(r, -1); } } - if (cell->east_wall >= 0) { + if (cell->east_wall >= 0 && r->draw_obj_flags & (1 << DRAW_WALL)) { struct material *material = get_material(r, DTX_WALL, cell->east_wall); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -659,7 +705,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re set_lightmap_texture(r, -1); } } - if (cell->west_wall >= 0) { + if (cell->west_wall >= 0 && r->draw_obj_flags & (1 << DRAW_WALL)) { struct material *material = get_material(r, DTX_WALL, cell->west_wall); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -672,7 +718,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re set_lightmap_texture(r, -1); } } - if (cell->north_door >= 0) { + if (cell->north_door >= 0 && r->draw_obj_flags & (1 << DRAW_DOOR)) { struct material *material = get_material(r, DTX_DOOR, cell->north_door); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -683,7 +729,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re draw_door(r, material->texture, cell->north_door_angle, m, -1, 0); } } - if (cell->south_door >= 0) { + if (cell->south_door >= 0 && r->draw_obj_flags & (1 << DRAW_DOOR)) { struct material *material = get_material(r, DTX_DOOR, cell->south_door); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -694,7 +740,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re draw_door(r, material->texture, cell->south_door_angle, m, 1, 0); } } - if (cell->east_door >= 0) { + if (cell->east_door >= 0 && r->draw_obj_flags & (1 << DRAW_DOOR)) { struct material *material = get_material(r, DTX_DOOR, cell->east_door); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -705,7 +751,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re draw_door(r, material->texture, cell->east_door_angle, m, 0, -1); } } - if (cell->west_door >= 0) { + if (cell->west_door >= 0 && r->draw_obj_flags & (1 << DRAW_DOOR)) { struct material *material = get_material(r, DTX_DOOR, cell->west_door); if (material && material->opaque == render_opaque) { mat4 m = MAT4( @@ -716,7 +762,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re draw_door(r, material->texture, cell->west_door_angle, m, 0, 1); } } - if (cell->stairs_texture >= 0) { + if (cell->stairs_texture >= 0 && r->draw_obj_flags & (1 << DRAW_STAIRS)) { struct material *material = get_material(r, DTX_STAIRS, cell->stairs_texture); if (material && material->opaque == render_opaque) { mat4 m; @@ -744,7 +790,7 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re glCullFace(GL_BACK); } } - if (cell->polyobj_index >= 0) { + if (cell->polyobj_index >= 0 && r->draw_obj_flags & (1 << DRAW_POLYOBJ)) { vec3 pos = { x + cell->polyobj_position_x, y + cell->polyobj_position_y - 1, @@ -762,7 +808,75 @@ static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool re } } -void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells, int nr_cells, mat4 view_transform, mat4 proj_transform) +static void draw_character(struct dungeon_renderer *r, struct drawfield_character *chara, mat4 view_mat) +{ + if (!chara->show || chara->sprite <= 0) + return; + struct sact_sprite *sp = sact_try_get_sprite(chara->sprite); + if (!sp || !sp->texture.handle) + return; + + if (chara->cols == 0) chara->cols = 1; + if (chara->rows == 0) chara->rows = 1; + glUseProgram(r->shader.program); + glUniform2f(r->uv_offset, (float)(chara->cg_index % chara->cols) / chara->cols, (float)(chara->cg_index / chara->cols) / chara->rows); + glUniform2f(r->uv_scale, 1.0f / chara->cols, 1.0f / chara->rows); + + mat4 m; + glm_translate_make(m, chara->pos); + + // Make it a billboard of 2.0 x 2.0 + mat3 r_bill; + glm_mat4_pick3t(view_mat, r_bill); + glm_mat4_ins3(r_bill, m); + + draw(r, r->wall_geometry, sp->texture.handle, m); +} + +struct character_z { + struct drawfield_character *chara; + float z; +}; + +static int compare_character_z(const void *a, const void *b) +{ + const struct character_z *cha = a; + const struct character_z *chb = b; + if (cha->z < chb->z) + return -1; + if (cha->z > chb->z) + return 1; + return 0; +} + +static void draw_characters(struct dungeon_renderer *r, struct drawfield_character *characters, mat4 view_transform) +{ + if (!characters) + return; + + struct character_z sorted_characters[DRAWFIELD_NR_CHARACTERS]; + int n = 0; + for (int i = 0; i < DRAWFIELD_NR_CHARACTERS; i++) { + struct drawfield_character *chara = characters + i; + if (!chara->show || chara->sprite <= 0) + continue; + sorted_characters[n].chara = chara; + vec4 pos; + glm_mat4_mulv(view_transform, (vec4){chara->pos[0], chara->pos[1], chara->pos[2], 1}, pos); + sorted_characters[n].z = pos[2]; + n++; + } + + qsort(sorted_characters, n, sizeof(struct character_z), compare_character_z); + + for (int i = 0; i < n; i++) + draw_character(r, sorted_characters[i].chara, view_transform); + + glUniform2f(r->uv_offset, 0.0f, 0.0f); + glUniform2f(r->uv_scale, 1.0f, 1.0f); +} + +void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells, int nr_cells, struct drawfield_character *characters, mat4 view_transform, mat4 proj_transform) { glUseProgram(r->shader.program); glUniformMatrix4fv(r->shader.view_transform, 1, GL_FALSE, view_transform[0]); @@ -777,11 +891,15 @@ void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells // Render the skybox. skybox_render(r->skybox, view_transform, proj_transform); - glUseProgram(r->shader.program); - // Render transparent objects, from far to near. + glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // DrawField: draw characters. + draw_characters(r, characters, view_transform); + + // Render transparent objects, from far to near. for (int i = nr_cells - 1; i >= 0; i--) draw_cell(r, cells[i], false, view_transform); @@ -865,3 +983,25 @@ void dungeon_renderer_set_raster_amp(struct dungeon_renderer *r, float amp) { r->raster_amp = amp; } + +void dungeon_renderer_enable_lightmap(struct dungeon_renderer *r, bool enable) +{ + r->enable_lightmap = enable; +} + +bool dungeon_renderer_get_draw_obj_flag(struct dungeon_renderer *r, int type) +{ + if (type < 0 || type >= NR_DRAW_OBJ_FLAGS) + return false; + return r->draw_obj_flags & (1 << type); +} + +void dungeon_renderer_set_draw_obj_flag(struct dungeon_renderer *r, int type, bool flag) +{ + if (type < 0 || type >= NR_DRAW_OBJ_FLAGS) + return; + if (flag) + r->draw_obj_flags |= (1 << type); + else + r->draw_obj_flags &= ~(1 << type); +} diff --git a/src/dungeon/skybox.c b/src/dungeon/skybox.c index 4518f61..8c3390f 100644 --- a/src/dungeon/skybox.c +++ b/src/dungeon/skybox.c @@ -36,8 +36,8 @@ struct skybox { struct skybox *skybox_create(enum draw_dungeon_version version, struct dtx *dtx) { - if (version == DRAW_DUNGEON_2) { - // Skybox is not used in Dungeons & Dolls. + if (version == DRAW_DUNGEON_2 || version == DRAW_FIELD) { + // Skybox is not used in these games. return NULL; }; diff --git a/src/ffi.c b/src/ffi.c index a8418a0..2fe5ce0 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -436,6 +436,7 @@ extern struct static_library lib_DrawDungeon; extern struct static_library lib_DrawDungeon2; extern struct static_library lib_DrawDungeon14; extern struct static_library lib_DrawEffect; +extern struct static_library lib_DrawField; extern struct static_library lib_DrawGraph; extern struct static_library lib_DrawMovie; extern struct static_library lib_DrawMovie2; @@ -549,6 +550,7 @@ static struct static_library *static_libraries[] = { &lib_DrawDungeon2, &lib_DrawDungeon14, &lib_DrawEffect, + &lib_DrawField, &lib_DrawGraph, &lib_DrawMovie, &lib_DrawMovie2, diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index b1e7d35..827a80e 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -17,8 +17,10 @@ #include #include #include +#include #include "system4.h" +#include "system4/string.h" #include "dungeon/dgn.h" #include "dungeon/dungeon.h" @@ -62,6 +64,11 @@ static int DrawDungeon14_Init(int surface) return dungeon_init(DRAW_DUNGEON_14, surface); } +static int DrawField_Init(int surface) +{ + return dungeon_init(DRAW_FIELD, surface); +} + static void DrawDungeon_Release(int surface) { if (!dungeon_get_context(surface)) @@ -77,6 +84,14 @@ static void DrawDungeon_SetDrawFlag(int surface, int flag) ctx->draw_enabled = flag; } +static bool DrawDungeon_GetDrawFlag(int surface) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx) + return false; + return ctx->draw_enabled; +} + static bool DrawDungeon_BeginLoad(int surface, int num) { struct dungeon_context *ctx = dungeon_get_context(surface); @@ -99,8 +114,23 @@ static bool DrawDungeon_IsSucceededLoading(int surface) } //float DrawDungeon_GetLoadingPercent(int surface); -//int DrawDungeon_LoadFromFile(int surface, struct string *file_name, int num); -//int DrawDungeon_LoadTexture(int surface, struct string *file_name); + +static int DrawDungeon_LoadFromFile(int surface, struct string *file_name, int num) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx) + return false; + return dungeon_load_dungeon(ctx, file_name->text, num); +} + +static int DrawDungeon_LoadTexture(int surface, struct string *file_name) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx) + return false; + return dungeon_load_texture(ctx, file_name->text); +} + //int DrawDungeon_LoadEventTexture(int surface, struct string *file_name); static int DrawDungeon_GetMapX(int surface) @@ -248,6 +278,7 @@ HLL_QUIET_UNIMPLEMENTED(0, int, DrawDungeon, GetDrawHalfFlag, int surface); //int DrawDungeon_CalcNumofWalk2(int surface); HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, SetInterlaceMode, int surface, int flag); HLL_QUIET_UNIMPLEMENTED(1, bool, DrawDungeon, SetDirect3DMode, int surface, int flag); +HLL_QUIET_UNIMPLEMENTED(1, bool, DrawDungeon, GetDirect3DMode, int surface); HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, SaveDrawSettingFlag, int direct3D, int interlace, int half); HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, GetDrawSettingFlag, int *direct3D, int *half); HLL_QUIET_UNIMPLEMENTED(1, bool, DrawDungeon, IsDrawSettingFile, void); @@ -278,8 +309,8 @@ HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, RestartTimer, void); 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_EXPORT(LoadFromFile, DrawDungeon_LoadFromFile), \ + HLL_EXPORT(LoadTexture, DrawDungeon_LoadTexture), \ HLL_TODO_EXPORT(LoadEventTexture, DrawDungeon_LoadEventTexture), \ HLL_EXPORT(GetMapX, DrawDungeon_GetMapX), \ HLL_EXPORT(GetMapY, DrawDungeon_GetMapY), \ @@ -469,3 +500,410 @@ HLL_LIBRARY(DrawDungeon14, HLL_EXPORT(GetDrawMapObjectFlag, DrawDungeon14_GetDrawMapObjectFlag), HLL_EXPORT(SetDrawMapObjectFlag, DrawDungeon14_SetDrawMapObjectFlag) ); + +//bool DrawField_BeginLoad(int nSurface, struct string *szFileName, int nNum); +//bool DrawField_IsLoadEnd(int nSurface); +//bool DrawField_StopLoad(int nSurface); +//float DrawField_GetLoadPercent(int nSurface); +//bool DrawField_IsLoadSucceeded(int nSurface); +//bool DrawField_BeginLoadTexture(int nSurface, struct string *szFileName); +//bool DrawField_IsLoadTextureEnd(int nSurface); +//bool DrawField_StopLoadTexture(int nSurface); +//float DrawField_GetLoadTexturePercent(int nSurface); +//bool DrawField_IsLoadTextureSucceeded(int nSurface); +//void DrawField_UpdateTexture(int nSurface); +//bool DrawField_GetDoorNAngle(int nSurface, int nX, int nY, int nZ, float *pfAngle); +//bool DrawField_GetDoorWAngle(int nSurface, int nX, int nY, int nZ, float *pfAngle); +//bool DrawField_GetDoorSAngle(int nSurface, int nX, int nY, int nZ, float *pfAngle); +//bool DrawField_GetDoorEAngle(int nSurface, int nX, int nY, int nZ, float *pfAngle); +//bool DrawField_SetDoorNAngle(int nSurface, int nX, int nY, int nZ, float fAngle); +//bool DrawField_SetDoorWAngle(int nSurface, int nX, int nY, int nZ, float fAngle); +//bool DrawField_SetDoorSAngle(int nSurface, int nX, int nY, int nZ, float fAngle); +//bool DrawField_SetDoorEAngle(int nSurface, int nX, int nY, int nZ, float fAngle); + +CELL_SETTER(DrawField_SetDoorNLock, int, cell->north_door_lock, true); +CELL_SETTER(DrawField_SetDoorWLock, int, cell->west_door_lock, true); +CELL_SETTER(DrawField_SetDoorSLock, int, cell->south_door_lock, true); +CELL_SETTER(DrawField_SetDoorELock, int, cell->east_door_lock, true); + +static bool DrawField_GetDoorNLock(int surface, int x, int y, int z, int *lock) +{ + struct dgn_cell *cell = dungeon_get_cell(surface, x, y, z); + if (!cell || cell->north_door == -1) + return false; + *lock = cell->north_door_lock; + return true; +} + +static bool DrawField_GetDoorWLock(int surface, int x, int y, int z, int *lock) +{ + struct dgn_cell *cell = dungeon_get_cell(surface, x, y, z); + if (!cell || cell->west_door == -1) + return false; + *lock = cell->west_door_lock; + return true; +} + +static bool DrawField_GetDoorSLock(int surface, int x, int y, int z, int *lock) +{ + struct dgn_cell *cell = dungeon_get_cell(surface, x, y, z); + if (!cell || cell->south_door == -1) + return false; + *lock = cell->south_door_lock; + return true; +} + +static bool DrawField_GetDoorELock(int surface, int x, int y, int z, int *lock) +{ + struct dgn_cell *cell = dungeon_get_cell(surface, x, y, z); + if (!cell || cell->east_door == -1) + return false; + *lock = cell->east_door_lock; + return true; +} + +//void DrawField_SetTexStair(int nSurface, int nX, int nY, int nZ, int nTexture, int nType); +//void DrawField_SetShadowTexFloor(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexCeiling(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexWallN(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexWallW(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexWallS(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexWallE(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexDoorN(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexDoorW(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexDoorS(int nSurface, int nX, int nY, int nZ, int nTexture); +//void DrawField_SetShadowTexDoorE(int nSurface, int nX, int nY, int nZ, int nTexture); + +static void DrawField_CalcShadowMap(int surface) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return; + return dgn_calc_lightmap(ctx->dgn); +} + +HLL_QUIET_UNIMPLEMENTED(, void, DrawField, SetLooked, int surface, int x, int y, int z, bool flag); +HLL_WARN_UNIMPLEMENTED(false, bool, DrawField, SetHideDrawMapFloor, int surface, int floor, bool hide); +//bool DrawField_SetHideDrawMapWall(int nSurface, int nWall, bool bHide); + +static void DrawField_SetDrawShadowMap(int surface, bool draw) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->renderer) + return; + dungeon_renderer_enable_lightmap(ctx->renderer, draw); +} + +static float DrawField_CosDeg(float deg) +{ + return cosf(glm_rad(deg)); +} + +static float DrawField_SinDeg(float deg) +{ + return sinf(glm_rad(deg)); +} + +static float DrawField_TanDeg(float deg) +{ + return tanf(glm_rad(deg)); +} + +static float DrawField_Atan2(float y, float x) +{ + return glm_deg(atan2f(y, x)); +} + +//bool DrawField_TransPos2DToPos3DOnPlane(int surface, int nScreenX, int nScreenY, float fPlaneY, float *pfX, float *pfY, float *pfZ); +//bool DrawField_TransPos3DToPos2D(int nSurace, float fX, float fY, float fZ, int *pnScreenX, int *pnScreenY); + +static int DrawField_GetCharaNumMax(int surface) +{ + return DRAWFIELD_NR_CHARACTERS; +} + +//void DrawField_SetCharaZBias(int surface, float fZBias0, float fZBias1, float fZBias2, float fZBias3); + +HLL_QUIET_UNIMPLEMENTED(, void, DrawField, SetCenterOffsetY, int surface, float y); +//void DrawField_SetBuilBoard(int surface, int num, int sprite); + +static void DrawField_SetSphereTheta(int surface, float x, float y, float z) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return; + ctx->dgn->sphere_theta[0] = x; + ctx->dgn->sphere_theta[1] = y; + ctx->dgn->sphere_theta[2] = z; +} + +static void DrawField_SetSphereColor(int surface, float top, float bottom) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return; + ctx->dgn->sphere_color_top = top; + ctx->dgn->sphere_color_bottom = bottom; +} + +static bool DrawField_GetSphereTheta(int surface, float *x, float *y, float *z) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return false; + *x = ctx->dgn->sphere_theta[0]; + *y = ctx->dgn->sphere_theta[1]; + *z = ctx->dgn->sphere_theta[2]; + return true; +} + +static bool DrawField_GetSphereColor(int surface, float *top, float *bottom) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return false; + *top = ctx->dgn->sphere_color_top; + *bottom = ctx->dgn->sphere_color_bottom; + return true; +} + +static bool DrawField_GetBackColor(int surface, int *r, int *g, int *b) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return false; + *r = ctx->dgn->back_color_r; + *g = ctx->dgn->back_color_g; + *b = ctx->dgn->back_color_b; + return true; +} + +static void DrawField_SetBackColor(int surface, int r, int g, int b) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->dgn) + return; + ctx->dgn->back_color_r = r; + ctx->dgn->back_color_g = g; + ctx->dgn->back_color_b = b; +} + +//int DrawField_GetPolyObj(int surface, int nX, int nY, int nZ); +//float DrawField_GetPolyObjMag(int surface, int nX, int nY, int nZ); +//float DrawField_GetPolyObjRotateH(int surface, int nX, int nY, int nZ); +//float DrawField_GetPolyObjRotateP(int surface, int nX, int nY, int nZ); +//float DrawField_GetPolyObjRotateB(int surface, int nX, int nY, int nZ); +//float DrawField_GetPolyObjOffsetX(int surface, int nX, int nY, int nZ); +//float DrawField_GetPolyObjOffsetY(int surface, int nX, int nY, int nZ); +//float DrawField_GetPolyObjOffsetZ(int surface, int nX, int nY, int nZ); +//void DrawField_SetPolyObj(int surface, int nX, int nY, int nZ, int nPolyObj); +//void DrawField_SetPolyObjMag(int surface, int nX, int nY, int nZ, float fMag); +//void DrawField_SetPolyObjRotateH(int surface, int nX, int nY, int nZ, float fRotateH); +//void DrawField_SetPolyObjRotateP(int surface, int nX, int nY, int nZ, float fRotateP); +//void DrawField_SetPolyObjRotateB(int surface, int nX, int nY, int nZ, float fRotateB); +//void DrawField_SetPolyObjOffsetX(int surface, int nX, int nY, int nZ, float fOffsetX); +//void DrawField_SetPolyObjOffsetY(int surface, int nX, int nY, int nZ, float fOffsetY); +//void DrawField_SetPolyObjOffsetZ(int surface, int nX, int nY, int nZ, float fOffsetZ); + +static void DrawField_SetDrawObjFlag(int surface, int type, bool flag) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->renderer) + return; + dungeon_renderer_set_draw_obj_flag(ctx->renderer, type, flag); +} + +static bool DrawField_GetDrawObjFlag(int surface, int type) +{ + struct dungeon_context *ctx = dungeon_get_context(surface); + if (!ctx || !ctx->renderer) + return false; + return dungeon_renderer_get_draw_obj_flag(ctx->renderer, type); +} + +//int DrawField_GetNumofTexSound(int nSurface, int nType); + +HLL_LIBRARY(DrawField, + HLL_EXPORT(Init, DrawField_Init), + HLL_EXPORT(Release, DrawDungeon_Release), + HLL_EXPORT(SetDrawFlag, DrawDungeon_SetDrawFlag), + HLL_EXPORT(GetDrawFlag, DrawDungeon_GetDrawFlag), + HLL_EXPORT(LoadFromFile, DrawDungeon_LoadFromFile), + HLL_EXPORT(LoadTexture, DrawDungeon_LoadTexture), + HLL_TODO_EXPORT(LoadEventTexture, DrawDungeon_LoadEventTexture), + HLL_TODO_EXPORT(BeginLoad, DrawField_BeginLoad), + HLL_TODO_EXPORT(IsLoadEnd, DrawField_IsLoadEnd), + HLL_TODO_EXPORT(StopLoad, DrawField_StopLoad), + HLL_TODO_EXPORT(GetLoadPercent, DrawField_GetLoadPercent), + HLL_TODO_EXPORT(IsLoadSucceeded, DrawField_IsLoadSucceeded), + HLL_TODO_EXPORT(BeginLoadTexture, DrawField_BeginLoadTexture), + HLL_TODO_EXPORT(IsLoadTextureEnd, DrawField_IsLoadTextureEnd), + HLL_TODO_EXPORT(StopLoadTexture, DrawField_StopLoadTexture), + HLL_TODO_EXPORT(GetLoadTexturePercent, DrawField_GetLoadTexturePercent), + HLL_TODO_EXPORT(IsLoadTextureSucceeded, DrawField_IsLoadTextureSucceeded), + HLL_TODO_EXPORT(UpdateTexture, DrawField_UpdateTexture), + HLL_EXPORT(SetCamera, dungeon_set_camera), + HLL_EXPORT(GetMapX, DrawDungeon_GetMapX), + HLL_EXPORT(GetMapY, DrawDungeon_GetMapY), + HLL_EXPORT(GetMapZ, DrawDungeon_GetMapZ), + HLL_EXPORT(IsInMap, DrawDungeon_IsInMap), + HLL_EXPORT(IsFloor, DrawDungeon_IsFloor), + 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_TODO_EXPORT(GetDoorNAngle, DrawField_GetDoorNAngle), + HLL_TODO_EXPORT(GetDoorWAngle, DrawField_GetDoorWAngle), + HLL_TODO_EXPORT(GetDoorSAngle, DrawField_GetDoorSAngle), + HLL_TODO_EXPORT(GetDoorEAngle, DrawField_GetDoorEAngle), + HLL_TODO_EXPORT(SetDoorNAngle, DrawField_SetDoorNAngle), + HLL_TODO_EXPORT(SetDoorWAngle, DrawField_SetDoorWAngle), + HLL_TODO_EXPORT(SetDoorSAngle, DrawField_SetDoorSAngle), + HLL_TODO_EXPORT(SetDoorEAngle, DrawField_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(SetDoorNLock, DrawField_SetDoorNLock), + HLL_EXPORT(SetDoorWLock, DrawField_SetDoorWLock), + HLL_EXPORT(SetDoorSLock, DrawField_SetDoorSLock), + HLL_EXPORT(SetDoorELock, DrawField_SetDoorELock), + HLL_EXPORT(GetDoorNLock, DrawField_GetDoorNLock), + HLL_EXPORT(GetDoorWLock, DrawField_GetDoorWLock), + HLL_EXPORT(GetDoorSLock, DrawField_GetDoorSLock), + HLL_EXPORT(GetDoorELock, DrawField_GetDoorELock), + 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(SetTexStair, DrawField_SetTexStair), + HLL_TODO_EXPORT(SetShadowTexFloor, DrawField_SetShadowTexFloor), + HLL_TODO_EXPORT(SetShadowTexCeiling, DrawField_SetShadowTexCeiling), + HLL_TODO_EXPORT(SetShadowTexWallN, DrawField_SetShadowTexWallN), + HLL_TODO_EXPORT(SetShadowTexWallW, DrawField_SetShadowTexWallW), + HLL_TODO_EXPORT(SetShadowTexWallS, DrawField_SetShadowTexWallS), + HLL_TODO_EXPORT(SetShadowTexWallE, DrawField_SetShadowTexWallE), + HLL_TODO_EXPORT(SetShadowTexDoorN, DrawField_SetShadowTexDoorN), + HLL_TODO_EXPORT(SetShadowTexDoorW, DrawField_SetShadowTexDoorW), + HLL_TODO_EXPORT(SetShadowTexDoorS, DrawField_SetShadowTexDoorS), + HLL_TODO_EXPORT(SetShadowTexDoorE, DrawField_SetShadowTexDoorE), + HLL_EXPORT(CalcShadowMap, DrawField_CalcShadowMap), + 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(SetPlayerPos, dungeon_set_player_pos), + HLL_EXPORT(SetWalked, dungeon_set_walked), + HLL_EXPORT(SetLooked, DrawField_SetLooked), + HLL_EXPORT(SetHideDrawMapFloor, DrawField_SetHideDrawMapFloor), + HLL_TODO_EXPORT(SetHideDrawMapWall, DrawField_SetHideDrawMapWall), + HLL_EXPORT(SetDrawHalfFlag, DrawDungeon_SetDrawHalfFlag), + HLL_EXPORT(GetDrawHalfFlag, DrawDungeon_GetDrawHalfFlag), + HLL_EXPORT(SetInterlaceMode, DrawDungeon_SetInterlaceMode), + HLL_EXPORT(SetDirect3DMode, DrawDungeon_SetDirect3DMode), + HLL_EXPORT(GetDirect3DMode, DrawDungeon_GetDirect3DMode), + HLL_EXPORT(SaveDrawSettingFlag, DrawDungeon_SaveDrawSettingFlag), + HLL_EXPORT(SetPerspective, dungeon_set_perspective), + HLL_EXPORT(SetDrawShadowMap, DrawField_SetDrawShadowMap), + HLL_TODO_EXPORT(CalcNumofFloor, DrawField_CalcNumofFloor), + HLL_TODO_EXPORT(CalcNumofWalk, DrawField_CalcNumofWalk), + HLL_TODO_EXPORT(CalcNumofWalk2, DrawField_CalcNumofWalk2), + HLL_EXPORT(IsPVSData, DrawDungeon_IsPVSData), + HLL_EXPORT(CosDeg, DrawField_CosDeg), + HLL_EXPORT(SinDeg, DrawField_SinDeg), + HLL_EXPORT(TanDeg, DrawField_TanDeg), + HLL_EXPORT(Sqrt, sqrtf), + HLL_EXPORT(Atan2, DrawField_Atan2), + HLL_TODO_EXPORT(TransPos2DToPos3DOnPlane, DrawField_TransPos2DToPos3DOnPlane), + HLL_TODO_EXPORT(TransPos3DToPos2D, DrawField_TransPos3DToPos2D), + HLL_EXPORT(GetCharaNumMax, DrawField_GetCharaNumMax), + HLL_EXPORT(SetCharaSprite, dungeon_set_chara_sprite), + HLL_EXPORT(SetCharaPos, dungeon_set_chara_pos), + HLL_EXPORT(SetCharaCG, dungeon_set_chara_cg), + HLL_EXPORT(SetCharaCGInfo, dungeon_set_chara_cg_info), + HLL_TODO_EXPORT(SetCharaZBias, DrawField_SetCharaZBias), + HLL_EXPORT(SetCharaShow, dungeon_set_chara_show), + HLL_EXPORT(SetCenterOffsetY, DrawField_SetCenterOffsetY), + HLL_TODO_EXPORT(SetBuilBoard, DrawField_SetBuilBoard), + HLL_EXPORT(SetSphereTheta, DrawField_SetSphereTheta), + HLL_EXPORT(SetSphereColor, DrawField_SetSphereColor), + HLL_EXPORT(GetSphereTheta, DrawField_GetSphereTheta), + HLL_EXPORT(GetSphereColor, DrawField_GetSphereColor), + HLL_EXPORT(GetBackColor, DrawField_GetBackColor), + HLL_EXPORT(SetBackColor, DrawField_SetBackColor), + HLL_TODO_EXPORT(GetPolyObj, DrawField_GetPolyObj), + HLL_TODO_EXPORT(GetPolyObjMag, DrawField_GetPolyObjMag), + HLL_TODO_EXPORT(GetPolyObjRotateH, DrawField_GetPolyObjRotateH), + HLL_TODO_EXPORT(GetPolyObjRotateP, DrawField_GetPolyObjRotateP), + HLL_TODO_EXPORT(GetPolyObjRotateB, DrawField_GetPolyObjRotateB), + HLL_TODO_EXPORT(GetPolyObjOffsetX, DrawField_GetPolyObjOffsetX), + HLL_TODO_EXPORT(GetPolyObjOffsetY, DrawField_GetPolyObjOffsetY), + HLL_TODO_EXPORT(GetPolyObjOffsetZ, DrawField_GetPolyObjOffsetZ), + HLL_TODO_EXPORT(SetPolyObj, DrawField_SetPolyObj), + HLL_TODO_EXPORT(SetPolyObjMag, DrawField_SetPolyObjMag), + HLL_TODO_EXPORT(SetPolyObjRotateH, DrawField_SetPolyObjRotateH), + HLL_TODO_EXPORT(SetPolyObjRotateP, DrawField_SetPolyObjRotateP), + HLL_TODO_EXPORT(SetPolyObjRotateB, DrawField_SetPolyObjRotateB), + HLL_TODO_EXPORT(SetPolyObjOffsetX, DrawField_SetPolyObjOffsetX), + HLL_TODO_EXPORT(SetPolyObjOffsetY, DrawField_SetPolyObjOffsetY), + HLL_TODO_EXPORT(SetPolyObjOffsetZ, DrawField_SetPolyObjOffsetZ), + HLL_EXPORT(SetDrawObjFlag, DrawField_SetDrawObjFlag), + HLL_EXPORT(GetDrawObjFlag, DrawField_GetDrawObjFlag), + HLL_EXPORT(GetTexSound, DrawDungeon_GetTexSound), + HLL_TODO_EXPORT(GetNumofTexSound, DrawField_GetNumofTexSound) + );