Merge pull request #21 from kichikuou/DrawDungeon

Initial implementation of DrawDungeon.hll (Rance VI)
This commit is contained in:
Nunuhara Cabbage
2021-05-08 09:21:48 -07:00
committed by GitHub
30 changed files with 2443 additions and 3 deletions
+1
View File
@@ -17,6 +17,7 @@ First install the dependencies (corresponding Debian package in parentheses):
* chibi-scheme [optional, for debugger]
* bison (bison)
* cglm (libcglm-dev) [optional, fetched by meson if not available]
* flex (flex)
* meson (meson)
* libffi (libffi-dev)
+119
View File
@@ -0,0 +1,119 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_DGN_H
#define SYSTEM4_DGN_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/*
* Dungeon data is a collection of cells indexed by three integers (x, y, z).
* X increases from west to east, Y increases from down to up, Z increases from
* south to north.
*/
enum dgn_version {
DGN_VER_RANCE6 = 10,
DGN_VER_GALZOO = 13,
};
struct dgn_cell {
int32_t floor;
int32_t ceiling;
int32_t north_wall;
int32_t south_wall;
int32_t east_wall;
int32_t west_wall;
int32_t north_door;
int32_t south_door;
int32_t east_door;
int32_t west_door;
int32_t stairs_texture;
int32_t stairs_orientation;
int32_t attr12;
int32_t attr13;
int32_t attr14;
int32_t attr15;
int32_t attr16;
int32_t attr17;
int32_t attr18;
int32_t attr19;
int32_t attr20;
int32_t attr21;
int32_t attr22;
int32_t attr23;
int32_t attr24;
int32_t enterable;
int32_t enterable_north;
int32_t enterable_south;
int32_t enterable_east;
int32_t enterable_west;
int32_t floor_event;
int32_t north_event;
int32_t south_event;
int32_t east_event;
int32_t west_event;
// struct {
// uint32_t i;
// char *s;
// } pairs[6];
int32_t unknown;
int32_t battle_background;
// The below exist only in version 13
int32_t polyobj_index;
float polyobj_scale;
float polyobj_rotation_y;
float polyobj_rotation_z;
float polyobj_rotation_x;
float polyobj_position_x;
float polyobj_position_y;
float polyobj_position_z;
int32_t roof_orientation;
int32_t roof_texture;
// int32_t unused1; // always -1
int32_t roof_underside_texture;
// int32_t unused2; // always -1
// Runtime data (not stored in .dgn)
int32_t floor_event2;
int32_t north_event2;
int32_t south_event2;
int32_t east_event2;
int32_t west_event2;
};
struct dgn {
uint32_t version; // 10: Rance VI, 13: GALZOO Island
uint32_t size_x;
uint32_t size_y;
uint32_t size_z;
// uint32_t unknown[10];
struct dgn_cell *cells;
};
struct dgn *dgn_parse(uint8_t *data, size_t size);
void dgn_free(struct dgn *dgn);
struct dgn_cell *dgn_cell_at(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z);
static inline bool dgn_is_in_map(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z)
{
return x < dgn->size_x && y < dgn->size_y && z < dgn->size_z;
}
#endif /* SYSTEM4_DGN_H */
+50
View File
@@ -0,0 +1,50 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_DTX_H
#define SYSTEM4_DTX_H
#include <stdint.h>
#include <stddef.h>
struct cg;
enum dtx_texture_type {
DTX_WALL = 0,
DTX_FLOOR = 1,
DTX_CEILING = 2,
DTX_STAIRS = 3,
DTX_DOOR = 4,
DTX_SKYBOX = 5,
};
struct dtx_entry {
uint32_t size;
uint8_t *data;
};
struct dtx {
uint32_t version; // 0: Rance IV, 1: GALZOO Island
int nr_rows;
int nr_columns;
struct dtx_entry *entries;
};
struct dtx *dtx_parse(uint8_t *data, size_t size);
void dtx_free(struct dtx *dtx);
struct cg *dtx_create_cg(struct dtx *dtx, int type, int index);
#endif /* SYSTEM4_DTX_H */
+83
View File
@@ -0,0 +1,83 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_DUNGEON_H
#define SYSTEM4_DUNGEON_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <GL/glew.h>
struct dgn;
struct dtx;
struct tes;
struct mesh;
struct skybox;
struct event_markers;
struct camera {
float pos[3];
float angle;
float angle_p;
};
/*
* Dungeon rendering context.
*
* A dungeon cell at (x, y, z) is rendered in a 2x2x2 cube centered at
* (2*x, 2*y, -2*z) in the world coordinates. Note that Z is flipped, because
* OpenGL uses a right-handed coordinate system while dungeon data is left-
* handed.
*/
struct dungeon_context {
int surface;
bool loaded;
bool draw_enabled;
struct camera camera;
struct dgn *dgn;
struct dtx *dtx;
struct tes *tes;
struct mesh **meshes;
int nr_meshes;
struct skybox *skybox;
struct event_markers *events;
GLuint depth_buffer;
};
struct dungeon_context *dungeon_context_create(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_event_floor(int surface, int x, int y, int z, int event);
void dungeon_set_event_blend_rate(int surface, int x, int y, int z, int rate);
void dungeon_set_texture_floor(int surface, int x, int y, int z, int texture);
void dungeon_set_texture_ceiling(int surface, int x, int y, int z, int texture);
void dungeon_set_texture_north(int surface, int x, int y, int z, int texture);
void dungeon_set_texture_south(int surface, int x, int y, int z, int texture);
void dungeon_set_texture_east(int surface, int x, int y, int z, int texture);
void dungeon_set_texture_west(int surface, int x, int y, int z, int texture);
void dungeon_set_door_north(int surface, int x, int y, int z, int texture);
void dungeon_set_door_south(int surface, int x, int y, int z, int texture);
void dungeon_set_door_east(int surface, int x, int y, int z, int texture);
void dungeon_set_door_west(int surface, int x, int y, int z, int texture);
struct dungeon_context *dungeon_get_context(int surface);
void dungeon_update(void);
#endif /* SYSTEM4_DUNGEON_H */
+25
View File
@@ -0,0 +1,25 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <GL/glew.h>
struct event_markers;
struct event_markers *event_markers_create(void);
void event_markers_free(struct event_markers *em);
void event_markers_render(struct event_markers *em, const GLfloat *view_transform, const GLfloat *proj_transform);
void event_markers_set(struct event_markers *em, int x, int y, int z, int event_type);
void event_markers_set_blend_rate(struct event_markers *em, int x, int y, int z, int rate);
+49
View File
@@ -0,0 +1,49 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <GL/glew.h>
/*
* A mesh represents a set of objects with the same shape and texture.
*/
struct mesh;
enum mesh_type {
MESH_WALL,
MESH_STAIRS,
MESH_TYPE_MAX,
};
void mesh_init(void);
void mesh_fini(void);
struct mesh *mesh_create(enum mesh_type type, GLuint texture, bool has_alpha);
void mesh_free(struct mesh *m);
bool mesh_is_transparent(struct mesh *m);
void mesh_render(struct mesh *m, const GLfloat *local_transform, const GLfloat *view_transform, const GLfloat *proj_transform);
void mesh_add_floor(struct mesh *m, int x, int y, int z);
void mesh_add_ceiling(struct mesh *m, int x, int y, int z);
void mesh_add_north_wall(struct mesh *m, int x, int y, int z);
void mesh_add_south_wall(struct mesh *m, int x, int y, int z);
void mesh_add_east_wall(struct mesh *m, int x, int y, int z);
void mesh_add_west_wall(struct mesh *m, int x, int y, int z);
void mesh_add_stairs(struct mesh *m, int x, int y, int z, int orientation);
void mesh_remove_floor(struct mesh *m, int x, int y, int z);
void mesh_remove_ceiling(struct mesh *m, int x, int y, int z);
void mesh_remove_north_wall(struct mesh *m, int x, int y, int z);
void mesh_remove_south_wall(struct mesh *m, int x, int y, int z);
void mesh_remove_east_wall(struct mesh *m, int x, int y, int z);
void mesh_remove_west_wall(struct mesh *m, int x, int y, int z);
+24
View File
@@ -0,0 +1,24 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <GL/glew.h>
struct dtx;
struct skybox;
struct skybox *skybox_create(struct dtx *dtx);
void skybox_free(struct skybox *s);
void skybox_render(struct skybox *s, const GLfloat *view_transform, const GLfloat *proj_transform);
+39
View File
@@ -0,0 +1,39 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_TES_H
#define SYSTEM4_TES_H
#include <stdint.h>
#include <stddef.h>
struct tes {
int nr_columns;
int nr_rows;
int *entries;
};
struct tes *tes_parse(uint8_t *data, size_t size);
void tes_free(struct tes *tes);
static inline int tes_get(struct tes *tes, int type, int index)
{
if (type < 0 || type >= tes->nr_rows || index < 0 || index >= tes->nr_columns)
return -1;
return tes->entries[type * tes->nr_columns + index];
}
#endif /* SYSTEM4_TES_H */
+1
View File
@@ -38,6 +38,7 @@ typedef struct texture {
GLfloat world_transform[16];
int w, h;
bool has_alpha;
bool flip_y;
int alpha_mod;
enum draw_method draw_method;
} Texture;
+1
View File
@@ -15,6 +15,7 @@ tj = dependency('libturbojpeg')
webp = dependency('libwebp')
png = dependency('libpng')
chibi = dependency('chibi-scheme', required : get_option('debugger'))
cglm = dependency('cglm', fallback : ['cglm', 'cglm_dep'])
flex = find_program('flex')
bison = find_program('bison')
+35
View File
@@ -0,0 +1,35 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#version 140
uniform sampler2D tex;
in float dist;
in vec2 tex_coord;
out vec4 frag_color;
const float FOG_MAX_DIST = 20.0; // FIXME
const vec3 FOG_COLOR = vec3(0.0, 0.0, 0.0);
void main() {
vec4 texel = texture(tex, tex_coord);
if (texel.a < 0.2)
discard;
float fog_factor = (FOG_MAX_DIST - dist) / FOG_MAX_DIST;
fog_factor = clamp(fog_factor, 0.0, 1.0);
frag_color = vec4(mix(FOG_COLOR, vec3(texel), fog_factor), texel.a);
}
+34
View File
@@ -0,0 +1,34 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#version 140
uniform mat4 local_transform;
uniform mat4 view_transform;
uniform mat4 proj_transform;
in vec3 vertex_pos;
in vec2 vertex_uv;
in mat4 instance_transform;
out float dist;
out vec2 tex_coord;
void main() {
vec4 pos = view_transform * instance_transform * local_transform * vec4(vertex_pos, 1.0);
dist = abs(pos.z);
gl_Position = proj_transform * pos;
tex_coord = vertex_uv;
}
+27
View File
@@ -0,0 +1,27 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#version 140
uniform samplerCube tex;
in vec3 tex_coord;
out vec4 frag_color;
void main() {
// Flip Z because the coordinate system for cubemaps is left-handed.
frag_color = texture(tex, vec3(tex_coord.xy, -tex_coord.z));
}
+29
View File
@@ -0,0 +1,29 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#version 140
uniform mat4 view_transform;
uniform mat4 proj_transform;
in vec3 vertex_pos;
out vec3 tex_coord;
void main() {
vec4 pos = proj_transform * mat4(mat3(view_transform)) * vec4(vertex_pos, 1.0);
gl_Position = pos.xyww;
tex_coord = vertex_pos;
}
+33
View File
@@ -0,0 +1,33 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#version 140
uniform sampler2D tex;
uniform float alpha_mod;
in float dist;
out vec4 frag_color;
const float FOG_MAX_DIST = 20.0; // FIXME
const vec3 FOG_COLOR = vec3(0.0, 0.0, 0.0);
void main() {
vec4 texel = texture(tex, gl_PointCoord);
float fog_factor = (FOG_MAX_DIST - dist) / FOG_MAX_DIST;
fog_factor = clamp(fog_factor, 0.0, 1.0);
frag_color = vec4(mix(FOG_COLOR, vec3(texel), fog_factor), texel.a * alpha_mod);
}
+30
View File
@@ -0,0 +1,30 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#version 140
uniform mat4 view_transform;
uniform mat4 proj_transform;
in vec3 vertex_pos;
out float dist;
void main() {
vec4 pos = view_transform * vec4(vertex_pos, 1.0);
dist = abs(pos.z);
gl_Position = proj_transform * pos;
gl_PointSize = 600 / dist; // FIXME
}
+122
View File
@@ -0,0 +1,122 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include "system4.h"
#include "system4/buffer.h"
#include "dungeon/dgn.h"
#include "vm.h"
struct dgn *dgn_parse(uint8_t *data, size_t size)
{
struct buffer r;
buffer_init(&r, data, size);
if (strncmp(buffer_strdata(&r), "DUGN", 4))
return NULL;
buffer_skip(&r, 4);
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);
buffer_skip(&r, 40);
int nr_cells = dgn->size_x * dgn->size_y * dgn->size_z;
dgn->cells = xcalloc(nr_cells, sizeof(struct dgn_cell));
for (int i = 0; i < nr_cells; i++) {
struct dgn_cell *cell = &dgn->cells[i];
cell->floor = buffer_read_int32(&r);
cell->ceiling = buffer_read_int32(&r);
cell->north_wall = buffer_read_int32(&r);
cell->south_wall = buffer_read_int32(&r);
cell->east_wall = buffer_read_int32(&r);
cell->west_wall = buffer_read_int32(&r);
cell->north_door = buffer_read_int32(&r);
cell->south_door = buffer_read_int32(&r);
cell->east_door = buffer_read_int32(&r);
cell->west_door = buffer_read_int32(&r);
cell->stairs_texture = buffer_read_int32(&r);
cell->stairs_orientation = buffer_read_int32(&r);
cell->attr12 = buffer_read_int32(&r);
cell->attr13 = buffer_read_int32(&r);
cell->attr14 = buffer_read_int32(&r);
cell->attr15 = buffer_read_int32(&r);
cell->attr16 = buffer_read_int32(&r);
cell->attr17 = buffer_read_int32(&r);
cell->attr18 = buffer_read_int32(&r);
cell->attr19 = buffer_read_int32(&r);
cell->attr20 = buffer_read_int32(&r);
cell->attr21 = buffer_read_int32(&r);
cell->attr22 = buffer_read_int32(&r);
cell->attr23 = buffer_read_int32(&r);
cell->attr24 = buffer_read_int32(&r);
cell->enterable = buffer_read_int32(&r);
cell->enterable_north = buffer_read_int32(&r);
cell->enterable_south = buffer_read_int32(&r);
cell->enterable_east = buffer_read_int32(&r);
cell->enterable_west = buffer_read_int32(&r);
cell->floor_event = buffer_read_int32(&r);
cell->north_event = buffer_read_int32(&r);
cell->south_event = buffer_read_int32(&r);
cell->east_event = buffer_read_int32(&r);
cell->west_event = buffer_read_int32(&r);
// Skip (int32, string) pairs
for (int j = 0; j < 6; j++) {
buffer_skip(&r, 4);
buffer_skip(&r, strlen(buffer_strdata(&r)) + 1);
}
cell->unknown = buffer_read_int32(&r);
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);
cell->roof_underside_texture = buffer_read_int32(&r);
buffer_skip(&r, 4);
}
return dgn;
}
void dgn_free(struct dgn *dgn)
{
free(dgn->cells);
free(dgn);
}
struct dgn_cell *dgn_cell_at(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z)
{
if (x >= dgn->size_x || y >= dgn->size_y || z >= dgn->size_z)
VM_ERROR("cell location out of range: (%d, %d, %d)", x, y, z);
return &dgn->cells[(z * dgn->size_y + y) * dgn->size_x + x];
}
+79
View File
@@ -0,0 +1,79 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include "system4.h"
#include "system4/buffer.h"
#include "system4/cg.h"
#include "dungeon/dtx.h"
struct dtx *dtx_parse(uint8_t *data, size_t size)
{
struct buffer r;
buffer_init(&r, data, size);
if (strncmp(buffer_strdata(&r), "DTEX", 4)) {
WARNING("dtx_parse: not a DTX file");
return NULL;
}
buffer_skip(&r, 4);
struct dtx *dtx = xcalloc(1, sizeof(struct dtx));
dtx->version = buffer_read_int32(&r);
dtx->nr_rows = buffer_read_int32(&r);
dtx->nr_columns = buffer_read_int32(&r);
dtx->entries = xcalloc(dtx->nr_rows * dtx->nr_columns, sizeof(struct dtx_entry));
for (int i = 0; i < dtx->nr_rows; i++) {
int nr_items = buffer_read_int32(&r);
if (nr_items != dtx->nr_columns) {
WARNING("dtx_parse: unexpected number of items");
dtx_free(dtx);
return NULL;
}
for (int j = 0; j < nr_items; j++) {
uint32_t size = buffer_read_int32(&r);
if (!size)
continue;
uint8_t *data = xmalloc(size);
buffer_read_bytes(&r, data, size);
dtx->entries[i * nr_items + j].size = size;
dtx->entries[i * nr_items + j].data = data;
}
}
return dtx;
}
void dtx_free(struct dtx *dtx)
{
int nr_entries = dtx->nr_rows * dtx->nr_columns;
for (int i = 0; i < nr_entries; i++) {
if (dtx->entries[i].data)
free(dtx->entries[i].data);
}
free(dtx->entries);
free(dtx);
}
struct cg *dtx_create_cg(struct dtx *dtx, int type, int index)
{
if (type < 0 || type >= dtx->nr_rows || index < 0 || index >= dtx->nr_columns)
return NULL;
struct dtx_entry *entry = &dtx->entries[type * dtx->nr_columns + index];
if (!entry->data)
return NULL;
return cg_load_buffer(entry->data, entry->size);
}
+441
View File
@@ -0,0 +1,441 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <errno.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <cglm/cglm.h>
#include <GL/glew.h>
#include "system4.h"
#include "system4/archive.h"
#include "system4/cg.h"
#include "system4/dlf.h"
#include "dungeon/dgn.h"
#include "dungeon/dtx.h"
#include "dungeon/dungeon.h"
#include "dungeon/event_markers.h"
#include "dungeon/mesh.h"
#include "dungeon/skybox.h"
#include "dungeon/tes.h"
#include "gfx/gfx.h"
#include "sact.h"
#include "sprite.h"
#include "vm.h"
#include "xsystem4.h"
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
struct dungeon_context *dungeon_context_create(int surface)
{
struct dungeon_context *ctx = xcalloc(1, sizeof(struct dungeon_context));
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.
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);
mesh_init();
return ctx;
}
void dungeon_context_free(struct dungeon_context *ctx)
{
if (ctx->dgn)
dgn_free(ctx->dgn);
if (ctx->dtx)
dtx_free(ctx->dtx);
if (ctx->tes)
tes_free(ctx->tes);
for (int i = 0; i < ctx->nr_meshes; i++)
mesh_free(ctx->meshes[i]);
free(ctx->meshes);
skybox_free(ctx->skybox);
event_markers_free(ctx->events);
glDeleteRenderbuffers(1, &ctx->depth_buffer);
mesh_fini();
struct sact_sprite *sp = sact_get_sprite(ctx->surface);
if (sp)
sprite_get_texture(sp)->flip_y = false;
free(ctx);
}
static struct mesh **create_meshes(struct dtx *dtx, int *nr_meshes)
{
const int nr_types = DTX_DOOR + 1;
struct mesh **meshes = xcalloc(nr_types * dtx->nr_columns, sizeof(struct mesh *));
for (int type = 0; type < nr_types; type++) {
enum mesh_type mtype = type == DTX_STAIRS ? MESH_STAIRS : MESH_WALL;
for (int i = 0; i < dtx->nr_columns; i++) {
struct cg *cg = dtx_create_cg(dtx, type, i);
if (!cg)
continue;
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
meshes[type * dtx->nr_columns + i] = mesh_create(mtype, texture, cg->metrics.has_alpha);
cg_free(cg);
}
}
*nr_meshes = nr_types * dtx->nr_columns;
return meshes;
}
static inline struct mesh *ctx_mesh(struct dungeon_context *ctx, int type, int index)
{
return ctx->meshes[type * ctx->dtx->nr_columns + index];
}
static void populate_meshes(struct dungeon_context *ctx)
{
struct dgn_cell *cell = ctx->dgn->cells;
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++, cell++) {
if (cell->floor >= 0)
mesh_add_floor(ctx_mesh(ctx, DTX_FLOOR, cell->floor), x, y, z);
if (cell->ceiling >= 0)
mesh_add_ceiling(ctx_mesh(ctx, DTX_CEILING, cell->ceiling), x, y, z);
if (cell->north_wall >= 0)
mesh_add_north_wall(ctx_mesh(ctx, DTX_WALL, cell->north_wall), x, y, z);
if (cell->south_wall >= 0)
mesh_add_south_wall(ctx_mesh(ctx, DTX_WALL, cell->south_wall), x, y, z);
if (cell->east_wall >= 0)
mesh_add_east_wall(ctx_mesh(ctx, DTX_WALL, cell->east_wall), x, y, z);
if (cell->west_wall >= 0)
mesh_add_west_wall(ctx_mesh(ctx, DTX_WALL, cell->west_wall), x, y, z);
if (cell->north_door >= 0)
mesh_add_north_wall(ctx_mesh(ctx, DTX_DOOR, cell->north_door), x, y, z);
if (cell->south_door >= 0)
mesh_add_south_wall(ctx_mesh(ctx, DTX_DOOR, cell->south_door), x, y, z);
if (cell->east_door >= 0)
mesh_add_east_wall(ctx_mesh(ctx, DTX_DOOR, cell->east_door), x, y, z);
if (cell->west_door >= 0)
mesh_add_west_wall(ctx_mesh(ctx, DTX_DOOR, cell->west_door), x, y, z);
if (cell->stairs_texture >= 0)
mesh_add_stairs(ctx_mesh(ctx, DTX_STAIRS, cell->stairs_texture), x, y, z, cell->stairs_orientation);
if (cell->floor_event)
event_markers_set(ctx->events, x, y, z, cell->floor_event);
}
}
}
}
bool dungeon_load(struct dungeon_context *ctx, int num)
{
if (ctx->loaded)
VM_ERROR("Dungeon is already loaded");
char *path = gamedir_path("Data/DungeonData.dlf");
int error = ARCHIVE_SUCCESS;
struct archive *dlf = (struct archive *)dlf_open(path, ARCHIVE_MMAP, &error);
if (error == ARCHIVE_FILE_ERROR) {
WARNING("dlf_open(\"%s\"): %s", path, strerror(errno));
} else if (error == ARCHIVE_BAD_ARCHIVE_ERROR) {
WARNING("dlf_open(\"%s\"): invalid .dlf file", path);
}
free(path);
if (!dlf)
return false;
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);
if (!ctx->dgn || !ctx->dtx) {
WARNING("Cannot load dungeon %d", num);
return false;
}
ctx->meshes = create_meshes(ctx->dtx, &ctx->nr_meshes);
ctx->skybox = skybox_create(ctx->dtx);
ctx->events = event_markers_create();
populate_meshes(ctx);
ctx->loaded = true;
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);
if (!ctx)
return;
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;
}
static void model_view_matrix(struct camera *camera, mat4 out)
{
// 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),
};
vec3 eye;
glm_vec3_sub(camera->pos, d, eye);
vec3 up = {0.0, 1.0, 0.0};
glm_lookat(eye, camera->pos, up, out);
}
void dungeon_render(struct dungeon_context *ctx)
{
struct sact_sprite *sp = sact_get_sprite(ctx->surface);
sprite_dirty(sp);
struct texture *texture = sprite_get_texture(sp);
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, texture, 0, 0, texture->w, texture->h);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ctx->depth_buffer);
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
ERROR("Incomplete framebuffer");
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
mat4 local_transform, view_transform, proj_transform;
glm_mat4_identity(local_transform);
model_view_matrix(&ctx->camera, view_transform);
glm_perspective(M_PI / 3.0, (float)texture->w / texture->h, 0.5, 100.0, proj_transform);
// Render opaque objects.
glDisable(GL_BLEND);
for (int i = 0; i < ctx->nr_meshes; i++) {
struct mesh *m = ctx->meshes[i];
if (m && !mesh_is_transparent(m))
mesh_render(m, local_transform[0], view_transform[0], proj_transform[0]);
}
// Render the skybox.
skybox_render(ctx->skybox, view_transform[0], proj_transform[0]);
// Render transparent objects.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (int i = 0; i < ctx->nr_meshes; i++) {
struct mesh *m = ctx->meshes[i];
if (m && mesh_is_transparent(m))
mesh_render(m, local_transform[0], view_transform[0], proj_transform[0]);
}
// Render event markers.
event_markers_render(ctx->events, view_transform[0], proj_transform[0]);
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);
}
void dungeon_set_event_floor(int surface, int x, int y, int z, int event)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
cell->floor_event = event;
event_markers_set(ctx->events, x, y, z, cell->floor_event);
}
void dungeon_set_event_blend_rate(int surface, int x, int y, int z, int rate)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx)
return;
event_markers_set_blend_rate(ctx->events, x, y, z, rate);
}
void dungeon_set_texture_floor(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->floor == texture)
return;
if (cell->floor >= 0)
mesh_remove_floor(ctx_mesh(ctx, DTX_FLOOR, cell->floor), x, y, z);
cell->floor = texture;
mesh_add_floor(ctx_mesh(ctx, DTX_FLOOR, cell->floor), x, y, z);
}
void dungeon_set_texture_ceiling(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->ceiling == texture)
return;
if (cell->ceiling >= 0)
mesh_remove_ceiling(ctx_mesh(ctx, DTX_CEILING, cell->ceiling), x, y, z);
cell->ceiling = texture;
mesh_add_ceiling(ctx_mesh(ctx, DTX_CEILING, cell->ceiling), x, y, z);
}
void dungeon_set_texture_north(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->north_wall == texture)
return;
if (cell->north_wall >= 0)
mesh_remove_north_wall(ctx_mesh(ctx, DTX_WALL, cell->north_wall), x, y, z);
cell->north_wall = texture;
mesh_add_north_wall(ctx_mesh(ctx, DTX_WALL, cell->north_wall), x, y, z);
}
void dungeon_set_texture_south(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->south_wall == texture)
return;
if (cell->south_wall >= 0)
mesh_remove_south_wall(ctx_mesh(ctx, DTX_WALL, cell->south_wall), x, y, z);
cell->south_wall = texture;
mesh_add_south_wall(ctx_mesh(ctx, DTX_WALL, cell->south_wall), x, y, z);
}
void dungeon_set_texture_east(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->east_wall == texture)
return;
if (cell->east_wall >= 0)
mesh_remove_east_wall(ctx_mesh(ctx, DTX_WALL, cell->east_wall), x, y, z);
cell->east_wall = texture;
mesh_add_east_wall(ctx_mesh(ctx, DTX_WALL, cell->east_wall), x, y, z);
}
void dungeon_set_texture_west(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->west_wall == texture)
return;
if (cell->west_wall >= 0)
mesh_remove_west_wall(ctx_mesh(ctx, DTX_WALL, cell->west_wall), x, y, z);
cell->west_wall = texture;
mesh_add_west_wall(ctx_mesh(ctx, DTX_WALL, cell->west_wall), x, y, z);
}
void dungeon_set_door_north(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->north_door == texture)
return;
if (cell->north_door >= 0)
mesh_remove_north_wall(ctx_mesh(ctx, DTX_DOOR, cell->north_door), x, y, z);
cell->north_door = texture;
mesh_add_north_wall(ctx_mesh(ctx, DTX_DOOR, cell->north_door), x, y, z);
}
void dungeon_set_door_south(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->south_door == texture)
return;
if (cell->south_door >= 0)
mesh_remove_south_wall(ctx_mesh(ctx, DTX_DOOR, cell->south_door), x, y, z);
cell->south_door = texture;
mesh_add_south_wall(ctx_mesh(ctx, DTX_DOOR, cell->south_door), x, y, z);
}
void dungeon_set_door_east(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->east_door == texture)
return;
if (cell->east_door >= 0)
mesh_remove_east_wall(ctx_mesh(ctx, DTX_DOOR, cell->east_door), x, y, z);
cell->east_door = texture;
mesh_add_east_wall(ctx_mesh(ctx, DTX_DOOR, cell->east_door), x, y, z);
}
void dungeon_set_door_west(int surface, int x, int y, int z, int texture)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return;
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z);
if (cell->west_door == texture)
return;
if (cell->west_door >= 0)
mesh_remove_west_wall(ctx_mesh(ctx, DTX_DOOR, cell->west_door), x, y, z);
cell->west_door = texture;
mesh_add_west_wall(ctx_mesh(ctx, DTX_DOOR, cell->west_door), x, y, z);
}
+271
View File
@@ -0,0 +1,271 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdlib.h>
#include <cglm/cglm.h>
#include <GL/glew.h>
#include "system4.h"
#include "system4/alk.h"
#include "system4/cg.h"
#include "dungeon/event_markers.h"
#include "dungeon/mesh.h"
#include "gfx/gfx.h"
#include "xsystem4.h"
enum floor_marker_type {
MAGIC_CIRCLE,
RED_OCTAGRAM,
NR_FLOOR_MARKER_TYPE
};
struct marker_info {
int texture_index;
int texture_count;
int floor_marker_type;
};
#define MAX_MARKER_INFO 19
static const struct marker_info rance6_marker_info[MAX_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
};
const struct marker_info *get_marker_info(unsigned event_type)
{
static const struct marker_info null_marker_info = {};
if (event_type >= MAX_MARKER_INFO)
return &null_marker_info;
return &rance6_marker_info[event_type];
}
static inline uint32_t cell_id(int x, int y, int z) {
return x << 16 | y << 8 | z;
}
struct event_sprite {
uint32_t cell_id;
int event_type;
GLfloat pos[3];
int alpha_mod; // 0-255
};
struct event_markers {
GLuint *event_textures;
int nr_event_textures;
struct mesh *floor_markers[NR_FLOOR_MARKER_TYPE];
// For rendering sprites
struct shader sprite_shader;
GLint proj_transform;
GLuint alpha_mod;
struct event_sprite *sprites;
int nr_sprites;
int cap_sprites;
GLuint vao;
GLuint pos_buffer;
};
static int find_event_sprite(struct event_markers *em, int x, int y, int z)
{
uint32_t id = cell_id(x, y, z);
for (int i = 0; i < em->nr_sprites; i++) {
if (em->sprites[i].cell_id == id)
return i;
}
return -1;
}
static GLuint *load_event_textures(int *nr_textures_out)
{
char *path = gamedir_path("Data/Event.alk");
int error = ARCHIVE_SUCCESS;
struct alk_archive *alk = alk_open(path, ARCHIVE_MMAP, &error);
if (error == ARCHIVE_FILE_ERROR) {
WARNING("alk_open(\"%s\"): %s", path, strerror(errno));
} else if (error == ARCHIVE_BAD_ARCHIVE_ERROR) {
WARNING("alk_open(\"%s\"): invalid .alk file", path);
}
free(path);
if (!alk)
return NULL;
GLuint *textures = xcalloc(alk->nr_files, sizeof(GLuint));
glGenTextures(alk->nr_files, textures);
for (int i = 0; i < alk->nr_files; i++) {
struct archive_data *dfile = archive_get(&alk->ar, i);
if (!dfile)
continue;
struct cg *cg = cg_load_data(dfile);
archive_free_data(dfile);
if (!cg) {
WARNING("Event.alk: cannot load cg %d", i);
continue;
}
glBindTexture(GL_TEXTURE_2D, textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
cg_free(cg);
}
*nr_textures_out = alk->nr_files;
archive_free(&alk->ar);
return textures;
}
struct event_markers *event_markers_create(void)
{
struct event_markers *em = xcalloc(1, sizeof(struct event_markers));
gfx_load_shader(&em->sprite_shader, "shaders/dungeon_sprite.v.glsl", "shaders/dungeon_sprite.f.glsl");
em->proj_transform = glGetUniformLocation(em->sprite_shader.program, "proj_transform");
em->alpha_mod = glGetUniformLocation(em->sprite_shader.program, "alpha_mod");
em->event_textures = load_event_textures(&em->nr_event_textures);
if (!em->event_textures)
return em;
em->floor_markers[MAGIC_CIRCLE] = mesh_create(MESH_WALL, em->event_textures[1], true);
em->floor_markers[RED_OCTAGRAM] = mesh_create(MESH_WALL, em->event_textures[63], true);
em->nr_sprites = 0;
em->cap_sprites = 16;
em->sprites = xcalloc(em->cap_sprites, sizeof(struct event_sprite));
glGenVertexArrays(1, &em->vao);
glBindVertexArray(em->vao);
glGenBuffers(1, &em->pos_buffer);
glBindBuffer(GL_ARRAY_BUFFER, em->pos_buffer);
glEnableVertexAttribArray(em->sprite_shader.vertex);
glVertexAttribPointer(em->sprite_shader.vertex, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
return em;
}
void event_markers_free(struct event_markers *em)
{
for (int i = 0; i < NR_FLOOR_MARKER_TYPE; i++)
mesh_free(em->floor_markers[i]);
glDeleteVertexArrays(1, &em->vao);
glDeleteBuffers(1, &em->pos_buffer);
glDeleteProgram(em->sprite_shader.program);
glDeleteTextures(em->nr_event_textures, em->event_textures);
free(em->event_textures);
free(em->sprites);
free(em);
}
void event_markers_render(struct event_markers *em, const GLfloat *view_transform, const GLfloat *proj_transform)
{
uint32_t t = SDL_GetTicks();
// Draw floor markers
mat4 local_transform;
glm_mat4_identity(local_transform);
float rad = t / 400.0;
local_transform[0][0] = cos(rad);
local_transform[0][1] = sin(rad);
local_transform[1][0] = -sin(rad);
local_transform[1][1] = cos(rad);
local_transform[3][3] /= 0.75;
glDepthFunc(GL_LEQUAL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0, -2.0);
for (int i = 0; i < NR_FLOOR_MARKER_TYPE; i++)
mesh_render(em->floor_markers[i], local_transform[0], view_transform, proj_transform);
glDisable(GL_POLYGON_OFFSET_FILL);
glDepthFunc(GL_LESS);
// Draw sprites
glUseProgram(em->sprite_shader.program);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glEnable(GL_POINT_SPRITE);
glUniformMatrix4fv(em->sprite_shader.view_transform, 1, GL_FALSE, view_transform);
glUniformMatrix4fv(em->proj_transform, 1, GL_FALSE, proj_transform);
glBindVertexArray(em->vao);
glActiveTexture(GL_TEXTURE0);
glUniform1i(em->sprite_shader.texture, 0);
glBindBuffer(GL_ARRAY_BUFFER, em->pos_buffer);
int frame = t / 100; // 100ms per frame
struct event_sprite *sp = em->sprites;
for (int i = 0; i < em->nr_sprites; i++, sp++) {
const struct marker_info *info = get_marker_info(sp->event_type);
int texture = info->texture_index + frame % info->texture_count;
glUniform1f(em->alpha_mod, sp->alpha_mod / 255.0);
glBindTexture(GL_TEXTURE_2D, em->event_textures[texture]);
glBufferData(GL_ARRAY_BUFFER, 3 * sizeof(GLfloat), sp->pos, GL_STREAM_DRAW);
glDrawArrays(GL_POINTS, 0, 1);
}
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
glDisable(GL_POINT_SPRITE);
}
void event_markers_set(struct event_markers *em, int x, int y, int z, int event_type)
{
int i = find_event_sprite(em, x, y, z);
if (i >= 0) {
if (event_type == em->sprites[i].event_type)
return;
// Remove old marker
const struct marker_info *old_info = get_marker_info(em->sprites[i].event_type);
mesh_remove_floor(em->floor_markers[old_info->floor_marker_type], x, y, z);
if (i != em->nr_sprites - 1)
em->sprites[i] = em->sprites[em->nr_sprites - 1];
em->nr_sprites--;
}
const struct marker_info *info = get_marker_info(event_type);
if (info->texture_count) {
// Add a new marker
if (em->nr_sprites == em->cap_sprites) {
em->cap_sprites *= 2;
em->sprites = xrealloc_array(em->sprites, em->nr_sprites, em->cap_sprites, sizeof(struct event_sprite));
}
struct event_sprite *sp = &em->sprites[em->nr_sprites++];
sp->cell_id = cell_id(x, y, z);
sp->event_type = event_type;
sp->pos[0] = x * 2.0;
sp->pos[1] = y * 2.0;
sp->pos[2] = z * -2.0;
sp->alpha_mod = 255;
mesh_add_floor(em->floor_markers[info->floor_marker_type], x, y, z);
}
}
void event_markers_set_blend_rate(struct event_markers *em, int x, int y, int z, int alpha_mod)
{
int i = find_event_sprite(em, x, y, z);
if (i < 0)
return;
em->sprites[i].alpha_mod = alpha_mod;
}
+363
View File
@@ -0,0 +1,363 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <cglm/cglm.h>
#include <GL/glew.h>
#include "system4.h"
#include "dungeon/mesh.h"
#include "gfx/gfx.h"
struct mesh_shader {
struct shader s;
// Uniform variable locations
GLint local_transform;
GLint proj_transform;
// Attribute variable locations
GLint vertex_uv;
GLint instance_transform;
};
static struct mesh_shader mesh_shader;
struct vertex {
GLfloat x, y, z, u, v;
};
static const struct vertex wall_vertices[] = {
{-1.0, 1.0, 0.0, 0.0, 0.0},
{-1.0, -1.0, 0.0, 0.0, 1.0},
{ 1.0, 1.0, 0.0, 1.0, 0.0},
{ 1.0, -1.0, 0.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},
{ 1, 3/3.f, -2/3.f, 1, 1/12.f},
{-1, 3/3.f, -2/3.f, 0, 1/12.f},
{ 1, 2/3.f, -2/3.f, 1, 2/12.f},
{-1, 2/3.f, -2/3.f, 0, 2/12.f},
{ 1, 2/3.f, -1/3.f, 1, 3/12.f},
{-1, 2/3.f, -1/3.f, 0, 3/12.f},
{ 1, 1/3.f, -1/3.f, 1, 4/12.f},
{-1, 1/3.f, -1/3.f, 0, 4/12.f},
{ 1, 1/3.f, 0/3.f, 1, 5/12.f},
{-1, 1/3.f, 0/3.f, 0, 5/12.f},
{ 1, 0/3.f, 0/3.f, 1, 6/12.f},
{-1, 0/3.f, 0/3.f, 0, 6/12.f},
{ 1, 0/3.f, 1/3.f, 1, 7/12.f},
{-1, 0/3.f, 1/3.f, 0, 7/12.f},
{ 1, -1/3.f, 1/3.f, 1, 8/12.f},
{-1, -1/3.f, 1/3.f, 0, 8/12.f},
{ 1, -1/3.f, 2/3.f, 1, 9/12.f},
{-1, -1/3.f, 2/3.f, 0, 9/12.f},
{ 1, -2/3.f, 2/3.f, 1, 10/12.f},
{-1, -2/3.f, 2/3.f, 0, 10/12.f},
{ 1, -2/3.f, 3/3.f, 1, 11/12.f},
{-1, -2/3.f, 3/3.f, 0, 11/12.f},
{ 1, -3/3.f, 3/3.f, 1, 12/12.f},
{-1, -3/3.f, 3/3.f, 0, 12/12.f},
};
struct geometry {
GLuint attr_buffer;
int nr_vertices;
};
static struct geometry *geometries[MESH_TYPE_MAX];
static struct geometry *geometry_create(const struct vertex *vertices, size_t size)
{
struct geometry *g = xcalloc(1, sizeof(struct geometry));
g->nr_vertices = size / sizeof(struct vertex);
glGenBuffers(1, &g->attr_buffer);
glBindBuffer(GL_ARRAY_BUFFER, g->attr_buffer);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
return g;
}
static void geometry_free(struct geometry *g)
{
glDeleteBuffers(1, &g->attr_buffer);
free(g);
}
static void geometry_bind(const struct geometry *g)
{
glBindBuffer(GL_ARRAY_BUFFER, g->attr_buffer);
glEnableVertexAttribArray(mesh_shader.s.vertex);
glVertexAttribPointer(mesh_shader.s.vertex, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)0);
glEnableVertexAttribArray(mesh_shader.vertex_uv);
glVertexAttribPointer(mesh_shader.vertex_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)(3 * sizeof(GLfloat)));
}
void mesh_init(void)
{
gfx_load_shader(&mesh_shader.s, "shaders/dungeon.v.glsl", "shaders/dungeon.f.glsl");
mesh_shader.local_transform = glGetUniformLocation(mesh_shader.s.program, "local_transform");
mesh_shader.proj_transform = glGetUniformLocation(mesh_shader.s.program, "proj_transform");
mesh_shader.vertex_uv = glGetAttribLocation(mesh_shader.s.program, "vertex_uv");
mesh_shader.instance_transform = glGetAttribLocation(mesh_shader.s.program, "instance_transform");
geometries[MESH_WALL] = geometry_create(wall_vertices, sizeof(wall_vertices));
geometries[MESH_STAIRS] = geometry_create(stairs_vertices, sizeof(stairs_vertices));
}
void mesh_fini(void)
{
for (int i = 0; i < MESH_TYPE_MAX; i++)
geometry_free(geometries[i]);
glDeleteProgram(mesh_shader.s.program);
}
struct mesh {
const struct geometry *geometry;
GLuint vao;
GLuint texture;
GLuint instance_buffer;
mat4 *instances;
int nr_instances;
int cap_instances;
uint32_t *cell_ids;
bool has_alpha;
bool dirty;
};
struct mesh *mesh_create(enum mesh_type type, GLuint texture, bool has_alpha)
{
struct mesh *m = xcalloc(1, sizeof(struct mesh));
m->geometry = geometries[type];
m->texture = texture;
m->has_alpha = has_alpha;
m->nr_instances = 0;
m->cap_instances = 16;
m->instances = xcalloc(m->cap_instances, sizeof(mat4));
m->cell_ids = xcalloc(m->cap_instances, sizeof(uint32_t));
m->dirty = false;
glGenVertexArrays(1, &m->vao);
glBindVertexArray(m->vao);
geometry_bind(m->geometry);
glGenBuffers(1, &m->instance_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m->instance_buffer);
for (int i = 0; i < 4; i++) {
GLuint index = mesh_shader.instance_transform + i;
glEnableVertexAttribArray(index);
glVertexAttribPointer(index, 4, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (const void *)(i * 4 * sizeof(GLfloat)));
glVertexAttribDivisor(index, 1);
}
glBindVertexArray(0);
return m;
}
void mesh_free(struct mesh *m)
{
if (!m)
return;
glDeleteTextures(1, &m->texture);
glDeleteBuffers(1, &m->instance_buffer);
glDeleteVertexArrays(1, &m->vao);
free(m->instances);
free(m->cell_ids);
free(m);
}
bool mesh_is_transparent(struct mesh *m)
{
return m->has_alpha;
}
void mesh_render(struct mesh *m, const GLfloat *local_transform, const GLfloat *view_transform, const GLfloat *proj_transform)
{
if (!m || !m->nr_instances)
return;
if (m->dirty) {
glBindBuffer(GL_ARRAY_BUFFER, m->instance_buffer);
glBufferData(GL_ARRAY_BUFFER, m->nr_instances * sizeof(mat4), m->instances, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m->dirty = false;
}
glUseProgram(mesh_shader.s.program);
glUniformMatrix4fv(mesh_shader.local_transform, 1, GL_FALSE, local_transform);
glUniformMatrix4fv(mesh_shader.s.view_transform, 1, GL_FALSE, view_transform);
glUniformMatrix4fv(mesh_shader.proj_transform, 1, GL_FALSE, proj_transform);
glBindVertexArray(m->vao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m->texture);
glUniform1i(mesh_shader.s.texture, 0);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, m->geometry->nr_vertices, m->nr_instances);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
enum wall_face {
NORTH,
SOUTH,
EAST,
WEST,
FLOOR,
CEILING
};
static inline uint32_t cell_id(int x, int y, int z, int face)
{
return x << 24 | y << 16 | z << 8 | face;
}
static void mesh_add(struct mesh *m, mat4 instance, uint32_t cell_id)
{
if (!m)
return;
if (m->nr_instances == m->cap_instances) {
m->cap_instances *= 2;
m->instances = xrealloc_array(m->instances, m->nr_instances, m->cap_instances, sizeof(mat4));
m->cell_ids = xrealloc_array(m->cell_ids, m->nr_instances, m->cap_instances, sizeof(uint32_t));
}
memcpy(m->instances[m->nr_instances], instance, sizeof(mat4));
m->cell_ids[m->nr_instances] = cell_id;
m->nr_instances++;
m->dirty = true;
}
static void mesh_remove(struct mesh *m, uint32_t cell_id)
{
if (!m)
return;
for (int i = 0; i < m->nr_instances; i++) {
if (m->cell_ids[i] != cell_id)
continue;
if (i != m->nr_instances - 1) {
memcpy(m->instances[i], m->instances[m->nr_instances - 1], sizeof(mat4));
m->cell_ids[i] = m->cell_ids[m->nr_instances - 1];
}
m->nr_instances--;
m->dirty = true;
return;
}
ERROR("mesh_remove: cannot find cell id %x", cell_id);
}
void mesh_add_floor(struct mesh *m, int x, int y, int z)
{
mat4 mat = {
{ 1, 0, 0, 0},
{ 0, 0, -1, 0},
{ 0, 1, 0, 0},
{ 2*x, 2*y-1, -2*z, 1}
};
mesh_add(m, mat, cell_id(x, y, z, FLOOR));
}
void mesh_add_ceiling(struct mesh *m, int x, int y, int z)
{
mat4 mat = {
{ -1, 0, 0, 0},
{ 0, 0, -1, 0},
{ 0, -1, 0, 0},
{2*x, 2*y+1, -2*z, 1}
};
mesh_add(m, mat, cell_id(x, y, z, CEILING));
}
void mesh_add_north_wall(struct mesh *m, int x, int y, int z)
{
mat4 mat = {
{ 1, 0, 0, 0},
{ 0, 1, 0, 0},
{ 0, 0, 1, 0},
{2*x, 2*y, -2*z-1, 1}
};
mesh_add(m, mat, cell_id(x, y, z, NORTH));
}
void mesh_add_south_wall(struct mesh *m, int x, int y, int z)
{
mat4 mat = {
{ -1, 0, 0, 0},
{ 0, 1, 0, 0},
{ 0, 0, -1, 0},
{2*x, 2*y, -2*z+1, 1}
};
mesh_add(m, mat, cell_id(x, y, z, SOUTH));
}
void mesh_add_east_wall(struct mesh *m, int x, int y, int z)
{
mat4 mat = {
{ 0, 0, 1, 0},
{ 0, 1, 0, 0},
{ -1, 0, 0, 0},
{2*x+1, 2*y, -2*z, 1}
};
mesh_add(m, mat, cell_id(x, y, z, EAST));
}
void mesh_add_west_wall(struct mesh *m, int x, int y, int z)
{
mat4 mat = {
{ 0, 0, -1, 0},
{ 0, 1, 0, 0},
{ 1, 0, 0, 0},
{2*x-1, 2*y, -2*z, 1}
};
mesh_add(m, mat, cell_id(x, y, z, WEST));
}
void mesh_add_stairs(struct mesh *m, int x, int y, int z, int orientation)
{
mat4 matrices[4] = {
{{ 1, 0, 0, 0}, {0, 1, 0, 0}, { 0, 0, 1, 0}, {2*x, 2*y, -2*z, 1}},
{{ 0, 0, -1, 0}, {0, 1, 0, 0}, { 1, 0, 0, 0}, {2*x, 2*y, -2*z, 1}},
{{-1, 0, 0, 0}, {0, 1, 0, 0}, { 0, 0, -1, 0}, {2*x, 2*y, -2*z, 1}},
{{ 0, 0, 1, 0}, {0, 1, 0, 0}, {-1, 0, 0, 0}, {2*x, 2*y, -2*z, 1}}
};
mesh_add(m, matrices[orientation], 0);
}
void mesh_remove_floor(struct mesh *m, int x, int y, int z)
{
mesh_remove(m, cell_id(x, y, z, FLOOR));
}
void mesh_remove_ceiling(struct mesh *m, int x, int y, int z)
{
mesh_remove(m, cell_id(x, y, z, CEILING));
}
void mesh_remove_north_wall(struct mesh *m, int x, int y, int z)
{
mesh_remove(m, cell_id(x, y, z, NORTH));
}
void mesh_remove_south_wall(struct mesh *m, int x, int y, int z)
{
mesh_remove(m, cell_id(x, y, z, SOUTH));
}
void mesh_remove_east_wall(struct mesh *m, int x, int y, int z)
{
mesh_remove(m, cell_id(x, y, z, EAST));
}
void mesh_remove_west_wall(struct mesh *m, int x, int y, int z)
{
mesh_remove(m, cell_id(x, y, z, WEST));
}
+132
View File
@@ -0,0 +1,132 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <GL/glew.h>
#include "system4.h"
#include "system4/cg.h"
#include "dungeon/dtx.h"
#include "dungeon/skybox.h"
#include "gfx/gfx.h"
struct skybox {
struct shader shader;
GLint proj_transform;
GLuint vao;
GLuint attr_buffer;
GLuint index_buffer;
GLuint texture;
int nr_indices;
};
struct skybox *skybox_create(struct dtx *dtx)
{
struct skybox *s = xcalloc(1, sizeof(struct skybox));
gfx_load_shader(&s->shader, "shaders/dungeon_skybox.v.glsl", "shaders/dungeon_skybox.f.glsl");
s->proj_transform = glGetUniformLocation(s->shader.program, "proj_transform");
// Set up a vertex array.
const GLfloat vertices[] = {
-1.0, 1.0, -1.0,
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
};
const GLushort indices[] = {
0, 1, 2, 2, 3, 0,
4, 1, 0, 0, 5, 4,
2, 6, 7, 7, 3, 2,
4, 5, 7, 7, 6, 4,
0, 3, 7, 7, 5, 0,
1, 4, 2, 2, 4, 6,
};
glGenVertexArrays(1, &s->vao);
glBindVertexArray(s->vao);
glGenBuffers(1, &s->attr_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->attr_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(s->shader.vertex);
glVertexAttribPointer(s->shader.vertex, 3, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &s->index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindVertexArray(0);
s->nr_indices = sizeof(indices) / sizeof(GLushort);
// Set up a cubemap texture.
glGenTextures(1, &s->texture);
glBindTexture(GL_TEXTURE_CUBE_MAP, s->texture);
const GLenum targets[6] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // north
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // west
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, // south
GL_TEXTURE_CUBE_MAP_POSITIVE_X, // east
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, // bottom
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // top
};
for (int i = 0; i < 6; i++) {
struct cg *cg = dtx_create_cg(dtx, DTX_SKYBOX, i);
if (!cg) {
WARNING("Cannot load skybox texture %d", i);
continue;
}
glTexImage2D(targets[i], 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
cg_free(cg);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
return s;
}
void skybox_free(struct skybox *s)
{
glDeleteVertexArrays(1, &s->vao);
glDeleteBuffers(1, &s->attr_buffer);
glDeleteBuffers(1, &s->index_buffer);
glDeleteTextures(1, &s->texture);
glDeleteProgram(s->shader.program);
free(s);
}
void skybox_render(struct skybox *s, const GLfloat *view_transform, const GLfloat *proj_transform)
{
glDepthFunc(GL_LEQUAL);
glUseProgram(s->shader.program);
glUniformMatrix4fv(s->shader.view_transform, 1, GL_FALSE, view_transform);
glUniformMatrix4fv(s->proj_transform, 1, GL_FALSE, proj_transform);
glBindVertexArray(s->vao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, s->texture);
glUniform1i(s->shader.texture, 0);
glDrawElements(GL_TRIANGLES, s->nr_indices, GL_UNSIGNED_SHORT, NULL);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glDepthFunc(GL_LESS);
}
+46
View File
@@ -0,0 +1,46 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include "system4.h"
#include "system4/buffer.h"
#include "dungeon/tes.h"
struct tes *tes_parse(uint8_t *data, size_t size)
{
struct buffer r;
buffer_init(&r, data, size);
if (memcmp(buffer_strdata(&r), "TES\0\0\0\0\0", 8))
return NULL;
buffer_skip(&r, 8);
struct tes *tes = xcalloc(1, sizeof(struct tes));
tes->nr_columns = buffer_read_int32(&r);
tes->nr_rows = buffer_read_int32(&r);
int nr_items = tes->nr_rows * tes->nr_columns;
tes->entries = xcalloc(nr_items, sizeof(int));
for (int i = 0; i < nr_items; i++)
tes->entries[i] = buffer_read_int32(&r);
return tes;
}
void tes_free(struct tes *tes)
{
free(tes->entries);
free(tes);
}
+2
View File
@@ -150,6 +150,7 @@ extern struct static_library lib_Confirm;
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_DrawGraph;
extern struct static_library lib_DrawMovie2;
extern struct static_library lib_DrawPluginManager;
@@ -190,6 +191,7 @@ static struct static_library *static_libraries[] = {
&lib_Confirm2,
&lib_CrayfishLogViewer,
&lib_DataFile,
&lib_DrawDungeon,
&lib_DrawGraph,
&lib_DrawMovie2,
&lib_DrawPluginManager,
+377
View File
@@ -0,0 +1,377 @@
/* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "system4.h"
#include "dungeon/dgn.h"
#include "dungeon/dungeon.h"
#include "dungeon/tes.h"
#include "hll.h"
static struct dungeon_context *current_context = NULL;
struct dungeon_context *dungeon_get_context(int surface)
{
if (!current_context || surface != current_context->surface)
return NULL;
return current_context;
}
void dungeon_update(void)
{
if (current_context && current_context->loaded && current_context->draw_enabled)
dungeon_render(current_context);
}
static struct dgn_cell *dungeon_get_cell(int surface, int x, int y, int z)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn || !dgn_is_in_map(ctx->dgn, x, y, z))
return NULL;
return dgn_cell_at(ctx->dgn, x, y, z);
}
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;
}
static void DrawDungeon_Release(int surface)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx)
return;
dungeon_context_free(ctx);
current_context = NULL;
}
static void DrawDungeon_SetDrawFlag(int surface, int flag)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx)
return;
ctx->draw_enabled = flag;
}
static bool DrawDungeon_BeginLoad(int surface, int num)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx)
return false;
return dungeon_load(ctx, num);
}
static bool DrawDungeon_IsLoading(int surface)
{
return false; // We don't use background loading.
}
static bool DrawDungeon_IsSucceededLoading(int surface)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx)
return false;
return ctx->loaded;
}
//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);
//int DrawDungeon_LoadEventTexture(int surface, struct string *file_name);
static int DrawDungeon_GetMapX(int surface)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return -1;
return ctx->dgn->size_x;
}
static int DrawDungeon_GetMapY(int surface)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return -1;
return ctx->dgn->size_y;
}
static int DrawDungeon_GetMapZ(int surface)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return -1;
return ctx->dgn->size_z;
}
static int DrawDungeon_IsInMap(int surface, int x, int y, int z)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->dgn)
return -1;
return dgn_is_in_map(ctx->dgn, x, y, z);
}
#define CELL_GETTER(name, defval, expr) \
static int name(int surface, int x, int y, int z) \
{ \
struct dgn_cell *cell = dungeon_get_cell(surface, x, y, z); \
if (!cell) \
return defval; \
return expr; \
}
CELL_GETTER(DrawDungeon_IsFloor, 0, cell->floor != -1);
//bool DrawDungeon_IsFloorFillTexture(int surface, int x, int y, int z);
CELL_GETTER(DrawDungeon_IsStair, 0, cell->stairs_orientation != -1);
CELL_GETTER(DrawDungeon_IsStairN, 0, cell->stairs_orientation == 0);
CELL_GETTER(DrawDungeon_IsStairW, 0, cell->stairs_orientation == 1);
CELL_GETTER(DrawDungeon_IsStairS, 0, cell->stairs_orientation == 2);
CELL_GETTER(DrawDungeon_IsStairE, 0, cell->stairs_orientation == 3);
CELL_GETTER(DrawDungeon_IsWallN, 0, cell->north_wall != -1);
CELL_GETTER(DrawDungeon_IsWallW, 0, cell->west_wall != -1);
CELL_GETTER(DrawDungeon_IsWallS, 0, cell->south_wall != -1);
CELL_GETTER(DrawDungeon_IsWallE, 0, cell->east_wall != -1);
CELL_GETTER(DrawDungeon_IsDoorN, 0, cell->north_door != -1);
CELL_GETTER(DrawDungeon_IsDoorW, 0, cell->west_door != -1);
CELL_GETTER(DrawDungeon_IsDoorS, 0, cell->south_door != -1);
CELL_GETTER(DrawDungeon_IsDoorE, 0, cell->east_door != -1);
CELL_GETTER(DrawDungeon_IsEnter, 0, cell->enterable);
CELL_GETTER(DrawDungeon_IsEnterN, 0, cell->enterable_north);
CELL_GETTER(DrawDungeon_IsEnterW, 0, cell->enterable_west);
CELL_GETTER(DrawDungeon_IsEnterS, 0, cell->enterable_south);
CELL_GETTER(DrawDungeon_IsEnterE, 0, cell->enterable_east);
CELL_GETTER(DrawDungeon_GetEvFloor, 0, cell->floor_event);
CELL_GETTER(DrawDungeon_GetEvWallN, 0, cell->north_event);
CELL_GETTER(DrawDungeon_GetEvWallW, 0, cell->west_event);
CELL_GETTER(DrawDungeon_GetEvWallS, 0, cell->south_event);
CELL_GETTER(DrawDungeon_GetEvWallE, 0, cell->east_event);
CELL_GETTER(DrawDungeon_GetEvFloor2, 0, cell->floor_event2);
CELL_GETTER(DrawDungeon_GetEvWallN2, 0, cell->north_event2);
CELL_GETTER(DrawDungeon_GetEvWallW2, 0, cell->west_event2);
CELL_GETTER(DrawDungeon_GetEvWallS2, 0, cell->south_event2);
CELL_GETTER(DrawDungeon_GetEvWallE2, 0, cell->east_event2);
CELL_GETTER(DrawDungeon_GetTexFloor, -1, cell->floor);
CELL_GETTER(DrawDungeon_GetTexCeiling, -1, cell->ceiling);
CELL_GETTER(DrawDungeon_GetTexWallN, -1, cell->north_wall);
CELL_GETTER(DrawDungeon_GetTexWallW, -1, cell->west_wall);
CELL_GETTER(DrawDungeon_GetTexWallS, -1, cell->south_wall);
CELL_GETTER(DrawDungeon_GetTexWallE, -1, cell->east_wall);
CELL_GETTER(DrawDungeon_GetTexDoorN, -1, cell->north_door);
CELL_GETTER(DrawDungeon_GetTexDoorW, -1, cell->west_door);
CELL_GETTER(DrawDungeon_GetTexDoorS, -1, cell->south_door);
CELL_GETTER(DrawDungeon_GetTexDoorE, -1, cell->east_door);
CELL_GETTER(DrawDungeon_GetTexStair, -1, cell->stairs_texture);
CELL_GETTER(DrawDungeon_GetBattleBack, -1, cell->battle_background);
#define CELL_SETTER(name, expr) \
static void name(int surface, int x, int y, int z, int value) \
{ \
struct dgn_cell *cell = dungeon_get_cell(surface, x, y, z); \
if (cell) \
expr = value; \
}
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDoorNAngle, int surface, int x, int y, int z, float angle);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDoorWAngle, int surface, int x, int y, int z, float angle);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDoorSAngle, int surface, int x, int y, int z, float angle);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDoorEAngle, int surface, int x, int y, int z, float angle);
CELL_SETTER(DrawDungeon_SetEvWallN, cell->north_event);
CELL_SETTER(DrawDungeon_SetEvWallW, cell->west_event);
CELL_SETTER(DrawDungeon_SetEvWallS, cell->south_event);
CELL_SETTER(DrawDungeon_SetEvWallE, cell->east_event);
CELL_SETTER(DrawDungeon_SetEvFloor2, cell->floor_event2);
CELL_SETTER(DrawDungeon_SetEvWallN2, cell->north_event2);
CELL_SETTER(DrawDungeon_SetEvWallW2, cell->west_event2);
CELL_SETTER(DrawDungeon_SetEvWallS2, cell->south_event2);
CELL_SETTER(DrawDungeon_SetEvWallE2, cell->east_event2);
//void DrawDungeon_SetEvMag(int surface, int x, int y, int z, float mag);
CELL_SETTER(DrawDungeon_SetEnter, cell->enterable);
CELL_SETTER(DrawDungeon_SetEnterN, cell->enterable_north);
CELL_SETTER(DrawDungeon_SetEnterW, cell->enterable_west);
CELL_SETTER(DrawDungeon_SetEnterS, cell->enterable_south);
CELL_SETTER(DrawDungeon_SetEnterE, cell->enterable_east);
//void DrawDungeon_SetSkyTextureSet(int surface, int set);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, DrawMap, int surface, int sprite);
//void DrawDungeon_SetMapAllViewFlag(int surfacce, int flag);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDrawMapFloor, int surface, int floor);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, DrawLMap, int surface, int sprite);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetMapCG, int surface, int index, int sprite);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDrawLMapFloor, int surface, int floor);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDrawMapRadar, int surface, int flag);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDrawHalfFlag, int surface, int flag);
HLL_WARN_UNIMPLEMENTED(0, int, DrawDungeon, GetDrawHalfFlag, int surface);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetWalked, int surface, int x, int y, int z, int flag);
//void DrawDungeon_SetWalkedAll(int surface);
//int DrawDungeon_CalcNumofFloor(int surface);
//int DrawDungeon_CalcNumofWalk(int surface);
//int DrawDungeon_CalcNumofWalk2(int surface);
HLL_WARN_UNIMPLEMENTED(0, int, DrawDungeon, CalcConquer, int surface);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetInterlaceMode, int surface, int flag);
HLL_WARN_UNIMPLEMENTED(1, bool, DrawDungeon, SetDirect3DMode, int surface, int flag);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SaveDrawSettingFlag, int direct3D, int interlace, int half);
//void DrawDungeon_GetDrawSettingFlag(int *direct3D, int *half);
HLL_WARN_UNIMPLEMENTED(1, bool, DrawDungeon, IsDrawSettingFile, void);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, DeleteDrawSettingFile, void);
HLL_WARN_UNIMPLEMENTED(1, bool, DrawDungeon, IsSSEFlag, void);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetSSEFlag, bool flag);
bool DrawDungeon_IsPVSData(int surface)
{
return false;
}
static int DrawDungeon_GetTexSound(int surface, int type, int num)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
if (!ctx || !ctx->tes)
return -1;
return tes_get(ctx->tes, type, num);
}
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, StopTimer, void);
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, RestartTimer, void);
HLL_WARN_UNIMPLEMENTED(0, bool, DrawDungeon, LoadWalkData, int surface, int map, struct page **anWalkData);
HLL_WARN_UNIMPLEMENTED(1, bool, DrawDungeon, SaveWalkData, int surface, int map, struct page **anWalkData);
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, dungeon_set_event_floor),
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, dungeon_set_event_blend_rate),
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, dungeon_set_texture_floor),
HLL_EXPORT(SetTexCeiling, dungeon_set_texture_ceiling),
HLL_EXPORT(SetTexWallN, dungeon_set_texture_north),
HLL_EXPORT(SetTexWallW, dungeon_set_texture_west),
HLL_EXPORT(SetTexWallS, dungeon_set_texture_south),
HLL_EXPORT(SetTexWallE, dungeon_set_texture_east),
HLL_EXPORT(SetTexDoorN, dungeon_set_door_north),
HLL_EXPORT(SetTexDoorW, dungeon_set_door_west),
HLL_EXPORT(SetTexDoorS, dungeon_set_door_south),
HLL_EXPORT(SetTexDoorE, dungeon_set_door_east),
HLL_TODO_EXPORT(SetSkyTextureSet, DrawDungeon_SetSkyTextureSet),
HLL_EXPORT(DrawMap, DrawDungeon_DrawMap),
HLL_TODO_EXPORT(SetMapAllViewFlag, DrawDungeon_SetMapAllViewFlag),
HLL_EXPORT(SetDrawMapFloor, DrawDungeon_SetDrawMapFloor),
HLL_EXPORT(DrawLMap, DrawDungeon_DrawLMap),
HLL_EXPORT(SetMapCG, DrawDungeon_SetMapCG),
HLL_EXPORT(SetDrawLMapFloor, DrawDungeon_SetDrawLMapFloor),
HLL_EXPORT(SetDrawMapRadar, DrawDungeon_SetDrawMapRadar),
HLL_EXPORT(SetDrawHalfFlag, DrawDungeon_SetDrawHalfFlag),
HLL_EXPORT(GetDrawHalfFlag, DrawDungeon_GetDrawHalfFlag),
HLL_EXPORT(SetWalked, DrawDungeon_SetWalked),
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, DrawDungeon_CalcConquer),
HLL_EXPORT(SetInterlaceMode, DrawDungeon_SetInterlaceMode),
HLL_EXPORT(SetDirect3DMode, DrawDungeon_SetDirect3DMode),
HLL_EXPORT(SaveDrawSettingFlag, DrawDungeon_SaveDrawSettingFlag),
HLL_TODO_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, DrawDungeon_LoadWalkData),
HLL_EXPORT(SaveWalkData, DrawDungeon_SaveWalkData)
);
+3 -1
View File
@@ -30,6 +30,7 @@
#include "gfx/gfx.h"
#include "sact.h"
#include "vm/page.h"
#include "dungeon/dungeon.h"
#include "xsystem4.h"
static struct sact_sprite **sprites = NULL;
@@ -63,7 +64,7 @@ static void realloc_sprite_table(int n)
memset(sprites + old_nr_sprites, 0, sizeof(struct sact_sprite*) * (nr_sprites - old_nr_sprites));
}
// NOTE: Used externally by DrawGraph and SengokuRanceFont
// NOTE: Used externally by DrawGraph, SengokuRanceFont and dungeon.c
struct sact_sprite *sact_get_sprite(int sp)
{
if (sp < -1)
@@ -126,6 +127,7 @@ int sact_GetMainSurfaceNumber(void)
int sact_Update(void)
{
handle_events();
dungeon_update();
if (sact_dirty) {
sprite_render_scene();
sprite_flip();
+10 -1
View File
@@ -17,6 +17,14 @@ xsystem4 = ['audio.c',
'video.c',
'vm.c',
'dungeon/dgn.c',
'dungeon/dtx.c',
'dungeon/dungeon.c',
'dungeon/event_markers.c',
'dungeon/mesh.c',
'dungeon/skybox.c',
'dungeon/tes.c',
'hll/ACXLoader.c',
'hll/ADVSYS.c',
'hll/AliceLogo.c',
@@ -31,6 +39,7 @@ xsystem4 = ['audio.c',
'hll/Confirm2.c',
'hll/CrayfishLogViewer.c',
'hll/DataFile.c',
'hll/DrawDungeon.c',
'hll/DrawGraph.c',
'hll/DrawMovie2.c',
'hll/DrawPluginManager.c',
@@ -58,7 +67,7 @@ xsystem4 = ['audio.c',
'hll/VSFile.c',
]
xsystem4_deps = [libm, zlib, sdl2, sdl2ttf, sdl2mixer, ffi, gl, glew, libsys4_dep]
xsystem4_deps = [libm, zlib, sdl2, sdl2ttf, sdl2mixer, ffi, gl, glew, cglm, libsys4_dep]
if chibi.found()
xsystem4_deps += chibi
xsystem4 += 'debugger.c'
+13
View File
@@ -155,6 +155,7 @@ static int gl_initialize(void)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindVertexArray(0);
return 0;
}
@@ -234,6 +235,7 @@ 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;
@@ -326,6 +328,7 @@ void gfx_prepare_job(struct gfx_render_job *job)
*/
void gfx_run_job(struct gfx_render_job *job)
{
glBindVertexArray(sdl.gl.vao);
glEnableVertexAttribArray(job->shader->vertex);
glBindBuffer(GL_ARRAY_BUFFER, sdl.gl.vbo);
@@ -335,6 +338,7 @@ void gfx_run_job(struct gfx_render_job *job)
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, NULL);
glDisableVertexAttribArray(job->shader->vertex);
glBindVertexArray(0);
glUseProgram(0);
}
@@ -381,6 +385,10 @@ void gfx_render_texture(struct texture *t, Rectangle *r)
t->world_transform[12] = 0;
t->world_transform[13] = 0;
}
if (t->flip_y) {
t->world_transform[13] += t->world_transform[5];
t->world_transform[5] *= -1;
}
struct gfx_render_job job = {
.shader = &default_shader.s,
@@ -391,6 +399,10 @@ void gfx_render_texture(struct texture *t, Rectangle *r)
};
gfx_render(&job);
if (t->flip_y) {
t->world_transform[5] *= -1;
t->world_transform[13] -= t->world_transform[5];
}
if (t->draw_method != DRAW_METHOD_NORMAL || t->alpha_mod != 255)
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
}
@@ -415,6 +427,7 @@ 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;
+3
View File
@@ -0,0 +1,3 @@
[wrap-git]
url = https://github.com/recp/cglm.git
revision = v0.8.2