mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-05 21:37:59 +03:00
Merge pull request #21 from kichikuou/DrawDungeon
Initial implementation of DrawDungeon.hll (Rance VI)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/recp/cglm.git
|
||||
revision = v0.8.2
|
||||
+1
-1
Submodule subprojects/libsys4 updated: d536a2eeed...44a027b72a
Reference in New Issue
Block a user