mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-12 17:28:14 +03:00
Merge branch 'master' of https://github.com/nunuhara/xsystem4
This commit is contained in:
+20
-14
@@ -45,19 +45,7 @@ struct dgn_cell {
|
||||
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 unknown[13];
|
||||
int32_t enterable;
|
||||
int32_t enterable_north;
|
||||
int32_t enterable_south;
|
||||
@@ -72,7 +60,7 @@ struct dgn_cell {
|
||||
// uint32_t i;
|
||||
// char *s;
|
||||
// } pairs[6];
|
||||
int32_t unknown;
|
||||
// int32_t unknown;
|
||||
int32_t battle_background;
|
||||
|
||||
// The below exist only in version 13
|
||||
@@ -91,11 +79,25 @@ struct dgn_cell {
|
||||
// int32_t unused2; // always -1
|
||||
|
||||
// Runtime data (not stored in .dgn)
|
||||
int x, y, z;
|
||||
int event_blend_rate;
|
||||
int32_t floor_event2;
|
||||
int32_t north_event2;
|
||||
int32_t south_event2;
|
||||
int32_t east_event2;
|
||||
int32_t west_event2;
|
||||
struct dgn_cell **visible_cells;
|
||||
};
|
||||
|
||||
struct pvs_run_lengths {
|
||||
int32_t invisible_cells;
|
||||
int32_t visible_cells;
|
||||
};
|
||||
|
||||
struct packed_pvs {
|
||||
struct pvs_run_lengths *run_lengths;
|
||||
int nr_run_lengths;
|
||||
int nr_visible_cells;
|
||||
};
|
||||
|
||||
struct dgn {
|
||||
@@ -105,6 +107,7 @@ struct dgn {
|
||||
uint32_t size_z;
|
||||
// uint32_t unknown[10];
|
||||
struct dgn_cell *cells;
|
||||
struct packed_pvs *pvs;
|
||||
};
|
||||
|
||||
struct dgn *dgn_parse(uint8_t *data, size_t size);
|
||||
@@ -118,4 +121,7 @@ static inline bool dgn_is_in_map(struct dgn *dgn, uint32_t x, uint32_t y, uint32
|
||||
return x < dgn->size_x && y < dgn->size_y && z < dgn->size_z;
|
||||
}
|
||||
|
||||
// Returns a list of cells visible from (x, y, z), sorted by distance from (x, y, z).
|
||||
struct dgn_cell **dgn_get_visible_cells(struct dgn *dgn, int x, int y, int z, int *nr_cells_out);
|
||||
|
||||
#endif /* SYSTEM4_DGN_H */
|
||||
|
||||
@@ -25,9 +25,7 @@
|
||||
struct dgn;
|
||||
struct dtx;
|
||||
struct tes;
|
||||
struct mesh;
|
||||
struct skybox;
|
||||
struct event_markers;
|
||||
struct dungeon_renderer;
|
||||
struct dungeon_map;
|
||||
|
||||
struct camera {
|
||||
@@ -54,10 +52,7 @@ struct dungeon_context {
|
||||
struct dgn *dgn;
|
||||
struct dtx *dtx;
|
||||
struct tes *tes;
|
||||
struct mesh **meshes;
|
||||
int nr_meshes;
|
||||
struct skybox *skybox;
|
||||
struct event_markers *events;
|
||||
struct dungeon_renderer *renderer;
|
||||
GLuint depth_buffer;
|
||||
};
|
||||
|
||||
@@ -66,18 +61,6 @@ 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);
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/* 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_EVENT_MARKERS_H
|
||||
#define SYSTEM4_DUNGEON_EVENT_MARKERS_H
|
||||
|
||||
#include <cglm/types.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 mat4 view_transform, const mat4 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);
|
||||
|
||||
#endif /* SYSTEM4_DUNGEON_EVENT_MARKERS_H */
|
||||
@@ -1,55 +0,0 @@
|
||||
/* 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_MESH_H
|
||||
#define SYSTEM4_DUNGEON_MESH_H
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <cglm/types.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 mat4 local_transform, const mat4 view_transform, const mat4 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);
|
||||
|
||||
#endif /* SYSTEM4_DUNGEON_MESH_H */
|
||||
@@ -14,20 +14,18 @@
|
||||
* along with this program; if not, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#version 140
|
||||
#ifndef SYSTEM4_DUNGEON_RENDERER_H
|
||||
#define SYSTEM4_DUNGEON_RENDERER_H
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform float alpha_mod;
|
||||
#include <cglm/cglm.h>
|
||||
#include <GL/glew.h>
|
||||
|
||||
in float dist;
|
||||
out vec4 frag_color;
|
||||
struct dgn_cell;
|
||||
struct dtx;
|
||||
struct dungeon_renderer;
|
||||
|
||||
const float FOG_MAX_DIST = 20.0; // FIXME
|
||||
const vec3 FOG_COLOR = vec3(0.0, 0.0, 0.0);
|
||||
struct dungeon_renderer *dungeon_renderer_create(struct dtx *dtx, GLuint *event_textures, int nr_event_textures);
|
||||
void dungeon_renderer_free(struct dungeon_renderer *r);
|
||||
void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells, int nr_cells, mat4 view_transform, mat4 proj_transform);
|
||||
|
||||
void 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);
|
||||
}
|
||||
#endif /* SYSTEM4_DUNGEON_RENDERER_H */
|
||||
@@ -17,6 +17,7 @@
|
||||
#version 140
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform float alpha_mod;
|
||||
|
||||
in float dist;
|
||||
in vec2 tex_coord;
|
||||
@@ -27,9 +28,7 @@ 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);
|
||||
frag_color = vec4(mix(FOG_COLOR, vec3(texel), fog_factor), texel.a * alpha_mod);
|
||||
}
|
||||
|
||||
@@ -22,12 +22,11 @@ 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);
|
||||
vec4 pos = view_transform * local_transform * vec4(vertex_pos, 1.0);
|
||||
dist = abs(pos.z);
|
||||
gl_Position = proj_transform * pos;
|
||||
tex_coord = vertex_uv;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/* 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
|
||||
}
|
||||
+106
-14
@@ -44,8 +44,21 @@ struct dgn *dgn_parse(uint8_t *data, size_t size)
|
||||
|
||||
int nr_cells = dgn->size_x * dgn->size_y * dgn->size_z;
|
||||
dgn->cells = xcalloc(nr_cells, sizeof(struct dgn_cell));
|
||||
uint32_t x = 0, y = 0, z = 0;
|
||||
for (int i = 0; i < nr_cells; i++) {
|
||||
struct dgn_cell *cell = &dgn->cells[i];
|
||||
cell->x = x;
|
||||
cell->y = y;
|
||||
cell->z = z;
|
||||
if (++x == dgn->size_x) {
|
||||
x = 0;
|
||||
if (++y == dgn->size_y) {
|
||||
y = 0;
|
||||
z++;
|
||||
}
|
||||
}
|
||||
cell->event_blend_rate = 255;
|
||||
|
||||
cell->floor = buffer_read_int32(&r);
|
||||
cell->ceiling = buffer_read_int32(&r);
|
||||
cell->north_wall = buffer_read_int32(&r);
|
||||
@@ -58,19 +71,7 @@ struct dgn *dgn_parse(uint8_t *data, size_t size)
|
||||
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);
|
||||
buffer_skip(&r, 13 * 4);
|
||||
cell->enterable = buffer_read_int32(&r);
|
||||
cell->enterable_north = buffer_read_int32(&r);
|
||||
cell->enterable_south = buffer_read_int32(&r);
|
||||
@@ -86,7 +87,7 @@ struct dgn *dgn_parse(uint8_t *data, size_t size)
|
||||
buffer_skip(&r, 4);
|
||||
buffer_skip(&r, strlen(buffer_strdata(&r)) + 1);
|
||||
}
|
||||
cell->unknown = buffer_read_int32(&r);
|
||||
buffer_skip(&r, 4);
|
||||
cell->battle_background = buffer_read_int32(&r);
|
||||
if (dgn->version != DGN_VER_GALZOO)
|
||||
continue;
|
||||
@@ -105,12 +106,60 @@ struct dgn *dgn_parse(uint8_t *data, size_t size)
|
||||
cell->roof_underside_texture = buffer_read_int32(&r);
|
||||
buffer_skip(&r, 4);
|
||||
}
|
||||
if (buffer_read_u8(&r) != 0 || buffer_read_int32(&r) != 1) {
|
||||
dgn_free(dgn);
|
||||
return NULL;
|
||||
}
|
||||
dgn->pvs = xcalloc(nr_cells, sizeof(struct packed_pvs));
|
||||
for (int i = 0; i < nr_cells; i++) {
|
||||
struct packed_pvs *pvs = &dgn->pvs[i];
|
||||
int32_t len = buffer_read_int32(&r);
|
||||
if (len % 8 != 4) {
|
||||
WARNING("dgn_parse: unexpected PVS length");
|
||||
dgn_free(dgn);
|
||||
return NULL;
|
||||
}
|
||||
if (buffer_read_int32(&r) != nr_cells) {
|
||||
WARNING("dgn_parse: bad PVS");
|
||||
dgn_free(dgn);
|
||||
return NULL;
|
||||
}
|
||||
pvs->nr_run_lengths = (len - 4) / 8;
|
||||
pvs->run_lengths = xmalloc(pvs->nr_run_lengths * sizeof(struct pvs_run_lengths));
|
||||
int32_t total = 0;
|
||||
for (int j = 0; j < pvs->nr_run_lengths; j++) {
|
||||
int32_t invisible = buffer_read_int32(&r);
|
||||
int32_t visible = buffer_read_int32(&r);
|
||||
pvs->run_lengths[j].invisible_cells = invisible;
|
||||
pvs->run_lengths[j].visible_cells = visible;
|
||||
pvs->nr_visible_cells += visible;
|
||||
total += invisible + visible;
|
||||
}
|
||||
if (total != nr_cells) {
|
||||
WARNING("dgn_parse: bad PVS");
|
||||
dgn_free(dgn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return dgn;
|
||||
}
|
||||
|
||||
void dgn_free(struct dgn *dgn)
|
||||
{
|
||||
int nr_cells = dgn->size_x * dgn->size_y * dgn->size_z;
|
||||
|
||||
for (int i = 0; i < nr_cells; i++) {
|
||||
if (dgn->cells[i].visible_cells)
|
||||
free(dgn->cells[i].visible_cells);
|
||||
}
|
||||
free(dgn->cells);
|
||||
|
||||
if (dgn->pvs) {
|
||||
for (int i = 0; i < nr_cells; i++)
|
||||
free(dgn->pvs[i].run_lengths);
|
||||
free(dgn->pvs);
|
||||
}
|
||||
|
||||
free(dgn);
|
||||
}
|
||||
|
||||
@@ -125,3 +174,46 @@ struct dgn_cell *dgn_cell_at(struct dgn *dgn, uint32_t x, uint32_t y, uint32_t z
|
||||
{
|
||||
return &dgn->cells[dgn_cell_index(dgn, x, y, z)];
|
||||
}
|
||||
|
||||
struct pvs_cell {
|
||||
struct dgn_cell *cell;
|
||||
int distance;
|
||||
};
|
||||
|
||||
static int pvs_cell_compare(const void *a, const void *b)
|
||||
{
|
||||
return ((struct pvs_cell *)a)->distance - ((struct pvs_cell *)b)->distance;
|
||||
}
|
||||
|
||||
struct dgn_cell **dgn_get_visible_cells(struct dgn *dgn, int x, int y, int z, int *nr_cells_out)
|
||||
{
|
||||
int cell_index = dgn_cell_index(dgn, x, y, z);
|
||||
struct dgn_cell *cell = &dgn->cells[cell_index];
|
||||
struct packed_pvs *pvs = &dgn->pvs[cell_index];
|
||||
if (!cell->visible_cells) {
|
||||
struct pvs_cell *pvs_cells = xmalloc(pvs->nr_visible_cells * sizeof(struct pvs_cell));
|
||||
|
||||
struct pvs_cell *dst = pvs_cells;
|
||||
struct dgn_cell *src = dgn->cells;
|
||||
for (int i = 0; i < pvs->nr_run_lengths; i++) {
|
||||
src += pvs->run_lengths[i].invisible_cells;
|
||||
for (int j = 0; j < pvs->run_lengths[i].visible_cells; j++) {
|
||||
int dx = src->x - x;
|
||||
int dy = src->y - y;
|
||||
int dz = src->z - z;
|
||||
*dst++ = (struct pvs_cell){
|
||||
.cell = src++,
|
||||
.distance = dx * dx + dy * dy + dz * dz
|
||||
};
|
||||
}
|
||||
}
|
||||
qsort(pvs_cells, pvs->nr_visible_cells, sizeof(struct pvs_cell), pvs_cell_compare);
|
||||
|
||||
cell->visible_cells = xmalloc(pvs->nr_visible_cells * sizeof(struct cell *));
|
||||
for (int i = 0; i < pvs->nr_visible_cells; i++)
|
||||
cell->visible_cells[i] = pvs_cells[i].cell;
|
||||
free(pvs_cells);
|
||||
}
|
||||
*nr_cells_out = pvs->nr_visible_cells;
|
||||
return cell->visible_cells;
|
||||
}
|
||||
|
||||
+50
-274
@@ -21,6 +21,7 @@
|
||||
#include <cglm/cglm.h>
|
||||
#include <GL/glew.h>
|
||||
#include "system4.h"
|
||||
#include "system4/alk.h"
|
||||
#include "system4/archive.h"
|
||||
#include "system4/cg.h"
|
||||
#include "system4/dlf.h"
|
||||
@@ -28,10 +29,8 @@
|
||||
#include "dungeon/dgn.h"
|
||||
#include "dungeon/dtx.h"
|
||||
#include "dungeon/dungeon.h"
|
||||
#include "dungeon/event_markers.h"
|
||||
#include "dungeon/map.h"
|
||||
#include "dungeon/mesh.h"
|
||||
#include "dungeon/skybox.h"
|
||||
#include "dungeon/renderer.h"
|
||||
#include "dungeon/tes.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "sact.h"
|
||||
@@ -63,7 +62,6 @@ struct dungeon_context *dungeon_context_create(int surface)
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
ctx->map = dungeon_map_create();
|
||||
mesh_init();
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -76,14 +74,10 @@ void dungeon_context_free(struct dungeon_context *ctx)
|
||||
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);
|
||||
if (ctx->renderer)
|
||||
dungeon_renderer_free(ctx->renderer);
|
||||
|
||||
glDeleteRenderbuffers(1, &ctx->depth_buffer);
|
||||
mesh_fini();
|
||||
dungeon_map_free(ctx->map);
|
||||
|
||||
struct sact_sprite *sp = sact_get_sprite(ctx->surface);
|
||||
@@ -93,72 +87,45 @@ void dungeon_context_free(struct dungeon_context *ctx)
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static struct mesh **create_meshes(struct dtx *dtx, int *nr_meshes)
|
||||
static GLuint *load_event_textures(int *nr_textures_out)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
*nr_meshes = nr_types * dtx->nr_columns;
|
||||
return meshes;
|
||||
}
|
||||
free(path);
|
||||
if (!alk)
|
||||
return NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
bool dungeon_load(struct dungeon_context *ctx, int num)
|
||||
@@ -199,11 +166,13 @@ bool dungeon_load(struct dungeon_context *ctx, int num)
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx->meshes = create_meshes(ctx->dtx, &ctx->nr_meshes);
|
||||
ctx->skybox = skybox_create(ctx->dtx);
|
||||
ctx->events = event_markers_create();
|
||||
int nr_event_textures;
|
||||
GLuint *event_textures = load_event_textures(&nr_event_textures);
|
||||
if (!event_textures)
|
||||
return false;
|
||||
|
||||
ctx->renderer = dungeon_renderer_create(ctx->dtx, event_textures, nr_event_textures);
|
||||
|
||||
populate_meshes(ctx);
|
||||
dungeon_map_init(ctx);
|
||||
|
||||
ctx->loaded = true;
|
||||
@@ -257,208 +226,15 @@ void dungeon_render(struct dungeon_context *ctx)
|
||||
model_view_matrix(&ctx->camera, view_transform);
|
||||
glm_perspective(M_PI / 3.0, (float)texture->w / texture->h, 0.5, 100.0, proj_transform);
|
||||
|
||||
// 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, view_transform, proj_transform);
|
||||
}
|
||||
|
||||
// Render the skybox.
|
||||
skybox_render(ctx->skybox, view_transform, proj_transform);
|
||||
|
||||
// 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, view_transform, proj_transform);
|
||||
}
|
||||
|
||||
// Render event markers.
|
||||
event_markers_render(ctx->events, view_transform, proj_transform);
|
||||
int dgn_x = round(ctx->camera.pos[0] / 2.0);
|
||||
int dgn_y = round(ctx->camera.pos[1] / 2.0);
|
||||
int dgn_z = round(ctx->camera.pos[2] / -2.0);
|
||||
int nr_cells;
|
||||
struct dgn_cell **cells = dgn_get_visible_cells(ctx->dgn, dgn_x, dgn_y, dgn_z, &nr_cells);
|
||||
dungeon_renderer_render(ctx->renderer, cells, nr_cells, view_transform, proj_transform);
|
||||
|
||||
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);
|
||||
dungeon_map_update_cell(ctx, x, y, z);
|
||||
}
|
||||
|
||||
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);
|
||||
dungeon_map_update_cell(ctx, 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;
|
||||
if (texture >= 0)
|
||||
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;
|
||||
if (texture >= 0)
|
||||
mesh_add_north_wall(ctx_mesh(ctx, DTX_WALL, cell->north_wall), x, y, z);
|
||||
dungeon_map_update_cell(ctx, 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;
|
||||
if (texture >= 0)
|
||||
mesh_add_south_wall(ctx_mesh(ctx, DTX_WALL, cell->south_wall), x, y, z);
|
||||
dungeon_map_update_cell(ctx, 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;
|
||||
if (texture >= 0)
|
||||
mesh_add_east_wall(ctx_mesh(ctx, DTX_WALL, cell->east_wall), x, y, z);
|
||||
dungeon_map_update_cell(ctx, 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;
|
||||
if (texture >= 0)
|
||||
mesh_add_west_wall(ctx_mesh(ctx, DTX_WALL, cell->west_wall), x, y, z);
|
||||
dungeon_map_update_cell(ctx, 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;
|
||||
if (texture >= 0)
|
||||
mesh_add_north_wall(ctx_mesh(ctx, DTX_DOOR, cell->north_door), x, y, z);
|
||||
dungeon_map_update_cell(ctx, 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;
|
||||
if (texture >= 0)
|
||||
mesh_add_south_wall(ctx_mesh(ctx, DTX_DOOR, cell->south_door), x, y, z);
|
||||
dungeon_map_update_cell(ctx, 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;
|
||||
if (texture >= 0)
|
||||
mesh_add_east_wall(ctx_mesh(ctx, DTX_DOOR, cell->east_door), x, y, z);
|
||||
dungeon_map_update_cell(ctx, 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;
|
||||
if (texture >= 0)
|
||||
mesh_add_west_wall(ctx_mesh(ctx, DTX_DOOR, cell->west_door), x, y, z);
|
||||
dungeon_map_update_cell(ctx, x, y, z);
|
||||
}
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
/* 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 event_type;
|
||||
int texture_index;
|
||||
int texture_count;
|
||||
int floor_marker_type;
|
||||
};
|
||||
|
||||
static const struct marker_info rance6_marker_info[] = {
|
||||
{ 11, 41, 3, MAGIC_CIRCLE}, // treasure chest
|
||||
{ 12, 51, 7, RED_OCTAGRAM}, // enemy
|
||||
{ 14, 8, 5, MAGIC_CIRCLE}, // green star
|
||||
{ 15, 21, 10, MAGIC_CIRCLE}, // heart
|
||||
{ 16, 45, 5, MAGIC_CIRCLE}, // BP cross
|
||||
{ 17, 58, 5, MAGIC_CIRCLE}, // exit
|
||||
{ 18, 31, 10, MAGIC_CIRCLE}, // teleporter
|
||||
{140, 13, 5, RED_OCTAGRAM}, // red star
|
||||
{0},
|
||||
};
|
||||
|
||||
const struct marker_info *get_marker_info(int event_type)
|
||||
{
|
||||
for (const struct marker_info *info = rance6_marker_info; info->event_type; info++) {
|
||||
if (info->event_type == event_type)
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static 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 mat4 view_transform, const mat4 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, 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[0]);
|
||||
glUniformMatrix4fv(em->proj_transform, 1, GL_FALSE, proj_transform[0]);
|
||||
|
||||
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) {
|
||||
// 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;
|
||||
}
|
||||
@@ -1,363 +0,0 @@
|
||||
/* 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 mat4 local_transform, const mat4 view_transform, const mat4 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[0]);
|
||||
glUniformMatrix4fv(mesh_shader.s.view_transform, 1, GL_FALSE, view_transform[0]);
|
||||
glUniformMatrix4fv(mesh_shader.proj_transform, 1, GL_FALSE, proj_transform[0]);
|
||||
|
||||
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,477 @@
|
||||
/* 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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <cglm/cglm.h>
|
||||
#include <GL/glew.h>
|
||||
#include "system4.h"
|
||||
#include "system4/cg.h"
|
||||
|
||||
#include "dungeon/dgn.h"
|
||||
#include "dungeon/dtx.h"
|
||||
#include "dungeon/renderer.h"
|
||||
#include "dungeon/skybox.h"
|
||||
#include "gfx/gfx.h"
|
||||
|
||||
struct marker_info {
|
||||
int event_type;
|
||||
int texture_index;
|
||||
int texture_count;
|
||||
int floor_marker;
|
||||
};
|
||||
|
||||
enum rance6_floor_marker {
|
||||
MAGIC_CIRCLE = 1,
|
||||
RED_OCTAGRAM = 63,
|
||||
};
|
||||
|
||||
static const struct marker_info rance6_marker_info[] = {
|
||||
{ 11, 41, 3, MAGIC_CIRCLE}, // treasure chest
|
||||
{ 12, 51, 7, RED_OCTAGRAM}, // enemy
|
||||
{ 14, 8, 5, MAGIC_CIRCLE}, // green star
|
||||
{ 15, 21, 10, MAGIC_CIRCLE}, // heart
|
||||
{ 16, 45, 5, MAGIC_CIRCLE}, // BP cross
|
||||
{ 17, 58, 5, MAGIC_CIRCLE}, // exit
|
||||
{ 18, 31, 10, MAGIC_CIRCLE}, // teleporter
|
||||
{140, 13, 5, RED_OCTAGRAM}, // red star
|
||||
{0},
|
||||
};
|
||||
|
||||
static const struct marker_info *get_marker_info(int event_type)
|
||||
{
|
||||
for (const struct marker_info *info = rance6_marker_info; info->event_type; info++) {
|
||||
if (info->event_type == event_type)
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct geometry;
|
||||
struct material;
|
||||
|
||||
struct dungeon_renderer {
|
||||
struct shader shader;
|
||||
// Uniform variable locations
|
||||
GLint local_transform;
|
||||
GLint proj_transform;
|
||||
GLuint alpha_mod;
|
||||
// Attribute variable locations
|
||||
GLint vertex_uv;
|
||||
|
||||
struct geometry *wall_geometry;
|
||||
struct geometry *stairs_geometry;
|
||||
|
||||
struct material *materials;
|
||||
int nr_materials;
|
||||
int nr_dtx_columns;
|
||||
|
||||
GLuint *event_textures;
|
||||
int nr_event_textures;
|
||||
|
||||
struct skybox *skybox;
|
||||
};
|
||||
|
||||
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 vao;
|
||||
GLuint attr_buffer;
|
||||
int nr_vertices;
|
||||
};
|
||||
|
||||
static struct geometry *geometry_create(struct dungeon_renderer *r, const struct vertex *vertices, size_t size)
|
||||
{
|
||||
struct geometry *g = xcalloc(1, sizeof(struct geometry));
|
||||
g->nr_vertices = size / sizeof(struct vertex);
|
||||
|
||||
glGenVertexArrays(1, &g->vao);
|
||||
glBindVertexArray(g->vao);
|
||||
glGenBuffers(1, &g->attr_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g->attr_buffer);
|
||||
|
||||
glEnableVertexAttribArray(r->shader.vertex);
|
||||
glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)0);
|
||||
glEnableVertexAttribArray(r->vertex_uv);
|
||||
glVertexAttribPointer(r->vertex_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)(3 * sizeof(GLfloat)));
|
||||
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
return g;
|
||||
}
|
||||
|
||||
static void geometry_free(struct geometry *g)
|
||||
{
|
||||
glDeleteVertexArrays(1, &g->vao);
|
||||
glDeleteBuffers(1, &g->attr_buffer);
|
||||
free(g);
|
||||
}
|
||||
|
||||
struct material {
|
||||
GLuint texture;
|
||||
bool opaque;
|
||||
};
|
||||
|
||||
static void init_material(struct material *m, struct dtx *dtx, int type, int index)
|
||||
{
|
||||
struct cg *cg = dtx_create_cg(dtx, type, index);
|
||||
if (!cg)
|
||||
return;
|
||||
glGenTextures(1, &m->texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m->texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
|
||||
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);
|
||||
m->opaque = !cg->metrics.has_alpha;
|
||||
cg_free(cg);
|
||||
}
|
||||
|
||||
static void delete_material(struct material *m)
|
||||
{
|
||||
if (m->texture)
|
||||
glDeleteTextures(1, &m->texture);
|
||||
}
|
||||
|
||||
static struct material *get_material(struct dungeon_renderer *r, int type, int index)
|
||||
{
|
||||
struct material *m = &r->materials[type * r->nr_dtx_columns + index];
|
||||
if (!m->texture)
|
||||
return NULL;
|
||||
return m;
|
||||
}
|
||||
|
||||
struct dungeon_renderer *dungeon_renderer_create(struct dtx *dtx, GLuint *event_textures, int nr_event_textures)
|
||||
{
|
||||
struct dungeon_renderer *r = xcalloc(1, sizeof(struct dungeon_renderer));
|
||||
|
||||
gfx_load_shader(&r->shader, "shaders/dungeon.v.glsl", "shaders/dungeon.f.glsl");
|
||||
r->local_transform = glGetUniformLocation(r->shader.program, "local_transform");
|
||||
r->proj_transform = glGetUniformLocation(r->shader.program, "proj_transform");
|
||||
r->alpha_mod = glGetUniformLocation(r->shader.program, "alpha_mod");
|
||||
r->vertex_uv = glGetAttribLocation(r->shader.program, "vertex_uv");
|
||||
|
||||
r->wall_geometry = geometry_create(r, wall_vertices, sizeof(wall_vertices));
|
||||
r->stairs_geometry = geometry_create(r, stairs_vertices, sizeof(stairs_vertices));
|
||||
|
||||
const int nr_types = DTX_DOOR + 1;
|
||||
r->materials = xcalloc(nr_types * dtx->nr_columns, sizeof(struct material));
|
||||
for (int type = 0; type < nr_types; type++) {
|
||||
for (int i = 0; i < dtx->nr_columns; i++) {
|
||||
init_material(&r->materials[type * dtx->nr_columns + i], dtx, type, i);
|
||||
}
|
||||
}
|
||||
r->nr_dtx_columns = dtx->nr_columns;
|
||||
r->nr_materials = nr_types * dtx->nr_columns;
|
||||
|
||||
r->event_textures = event_textures;
|
||||
r->nr_event_textures = nr_event_textures;
|
||||
|
||||
r->skybox = skybox_create(dtx);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void dungeon_renderer_free(struct dungeon_renderer *r)
|
||||
{
|
||||
glDeleteProgram(r->shader.program);
|
||||
|
||||
geometry_free(r->wall_geometry);
|
||||
geometry_free(r->stairs_geometry);
|
||||
|
||||
for (int i = 0; i < r->nr_materials; i++)
|
||||
delete_material(&r->materials[i]);
|
||||
free(r->materials);
|
||||
|
||||
glDeleteTextures(r->nr_event_textures, r->event_textures);
|
||||
free(r->event_textures);
|
||||
|
||||
skybox_free(r->skybox);
|
||||
|
||||
free(r);
|
||||
}
|
||||
|
||||
static void draw(struct dungeon_renderer *r, struct geometry *geometry, GLuint texture, mat4 transform)
|
||||
{
|
||||
glUseProgram(r->shader.program);
|
||||
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, transform[0]);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glUniform1i(r->shader.texture, 0);
|
||||
|
||||
glBindVertexArray(geometry->vao);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, geometry->nr_vertices);
|
||||
glBindVertexArray(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
static void draw_floor_marker(struct dungeon_renderer *r, const struct marker_info *info, float x, float y, float z, uint32_t t)
|
||||
{
|
||||
float rad = t / 400.0;
|
||||
mat4 rot;
|
||||
glm_euler((vec3){0, 0, rad}, rot);
|
||||
rot[3][3] /= 0.75; // scale
|
||||
mat4 trans = MAT4(
|
||||
1, 0, 0, x,
|
||||
0, 0, 1, y-1,
|
||||
0, -1, 0, z,
|
||||
0, 0, 0, 1);
|
||||
glm_mul(trans, rot, trans);
|
||||
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0, -2.0);
|
||||
draw(r, r->wall_geometry, r->event_textures[info->floor_marker], trans);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glDepthFunc(GL_LESS);
|
||||
}
|
||||
|
||||
static void draw_floating_marker(struct dungeon_renderer *r, const struct marker_info *info, float x, float y, float z, int blend_rate, uint32_t t, mat4 v)
|
||||
{
|
||||
int frame = t / 100; // 100ms per frame
|
||||
int texture = info->texture_index + frame % info->texture_count;
|
||||
mat4 billboard = MAT4(
|
||||
v[0][0], v[0][1], v[0][2], x,
|
||||
v[1][0], v[1][1], v[1][2], y,
|
||||
v[2][0], v[2][1], v[2][2], z,
|
||||
0, 0, 0, 1);
|
||||
glUniform1f(r->alpha_mod, blend_rate / 255.0);
|
||||
draw(r, r->wall_geometry, r->event_textures[texture], billboard);
|
||||
glUniform1f(r->alpha_mod, 1.0);
|
||||
}
|
||||
|
||||
static void draw_cell(struct dungeon_renderer *r, struct dgn_cell *cell, bool render_opaque, mat4 view_transform)
|
||||
{
|
||||
float x = 2.0 * cell->x;
|
||||
float y = 2.0 * cell->y;
|
||||
float z = -2.0 * cell->z;
|
||||
|
||||
if (cell->floor >= 0) {
|
||||
struct material *material = get_material(r, DTX_FLOOR, cell->floor);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
1, 0, 0, x,
|
||||
0, 0, 1, y-1,
|
||||
0, -1, 0, z,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->ceiling >= 0) {
|
||||
struct material *material = get_material(r, DTX_CEILING, cell->ceiling);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
-1, 0, 0, x,
|
||||
0, 0, -1, y+1,
|
||||
0, -1, 0, z,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->north_wall >= 0) {
|
||||
struct material *material = get_material(r, DTX_WALL, cell->north_wall);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, 1, z-1,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->south_wall >= 0) {
|
||||
struct material *material = get_material(r, DTX_WALL, cell->south_wall);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
-1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, -1, z+1,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->east_wall >= 0) {
|
||||
struct material *material = get_material(r, DTX_WALL, cell->east_wall);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
0, 0, -1, x+1,
|
||||
0, 1, 0, y,
|
||||
1, 0, 0, z,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->west_wall >= 0) {
|
||||
struct material *material = get_material(r, DTX_WALL, cell->west_wall);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
0, 0, 1, x-1,
|
||||
0, 1, 0, y,
|
||||
-1, 0, 0, z,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->north_door >= 0) {
|
||||
struct material *material = get_material(r, DTX_DOOR, cell->north_door);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, 1, z-1,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->south_door >= 0) {
|
||||
struct material *material = get_material(r, DTX_DOOR, cell->south_door);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
-1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, -1, z+1,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->east_door >= 0) {
|
||||
struct material *material = get_material(r, DTX_DOOR, cell->east_door);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
0, 0, -1, x+1,
|
||||
0, 1, 0, y,
|
||||
1, 0, 0, z,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->west_door >= 0) {
|
||||
struct material *material = get_material(r, DTX_DOOR, cell->west_door);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 m = MAT4(
|
||||
0, 0, 1, x-1,
|
||||
0, 1, 0, y,
|
||||
-1, 0, 0, z,
|
||||
0, 0, 0, 1);
|
||||
draw(r, r->wall_geometry, material->texture, m);
|
||||
}
|
||||
}
|
||||
if (cell->stairs_texture >= 0) {
|
||||
struct material *material = get_material(r, DTX_STAIRS, cell->stairs_texture);
|
||||
if (material && material->opaque == render_opaque) {
|
||||
mat4 matrices[4] = {
|
||||
MAT4(
|
||||
1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, 1, z,
|
||||
0, 0, 0, 1),
|
||||
MAT4(
|
||||
0, 0, 1, x,
|
||||
0, 1, 0, y,
|
||||
-1, 0, 0, z,
|
||||
0, 0, 0, 1),
|
||||
MAT4(
|
||||
-1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, -1, z,
|
||||
0, 0, 0, 1),
|
||||
MAT4(
|
||||
0, 0, -1, x,
|
||||
0, 1, 0, y,
|
||||
1, 0, 0, z,
|
||||
0, 0, 0, 1)
|
||||
};
|
||||
draw(r, r->stairs_geometry, material->texture, matrices[cell->stairs_orientation]);
|
||||
}
|
||||
}
|
||||
if (cell->floor_event && !render_opaque) {
|
||||
const struct marker_info *info = get_marker_info(cell->floor_event);
|
||||
if (info) {
|
||||
uint32_t t = SDL_GetTicks();
|
||||
draw_floor_marker(r, info, x, y, z, t);
|
||||
draw_floating_marker(r, info, x, y, z, cell->event_blend_rate, t, view_transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dungeon_renderer_render(struct dungeon_renderer *r, struct dgn_cell **cells, int nr_cells, mat4 view_transform, mat4 proj_transform)
|
||||
{
|
||||
glUseProgram(r->shader.program);
|
||||
glUniformMatrix4fv(r->shader.view_transform, 1, GL_FALSE, view_transform[0]);
|
||||
glUniformMatrix4fv(r->proj_transform, 1, GL_FALSE, proj_transform[0]);
|
||||
glUniform1f(r->alpha_mod, 1.0);
|
||||
|
||||
// Render opaque objects, from near to far.
|
||||
glDisable(GL_BLEND);
|
||||
for (int i = 0; i < nr_cells; i++)
|
||||
draw_cell(r, cells[i], true, view_transform);
|
||||
|
||||
// Render the skybox.
|
||||
skybox_render(r->skybox, view_transform, proj_transform);
|
||||
|
||||
glUseProgram(r->shader.program);
|
||||
// Render transparent objects, from far to near.
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
for (int i = nr_cells - 1; i >= 0; i--)
|
||||
draw_cell(r, cells[i], false, view_transform);
|
||||
|
||||
glUseProgram(0);
|
||||
}
|
||||
+41
-28
@@ -186,7 +186,7 @@ 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) \
|
||||
#define CELL_SETTER(name, expr, update_map) \
|
||||
static void name(int surface, int x, int y, int z, int value) \
|
||||
{ \
|
||||
struct dungeon_context *ctx = dungeon_get_context(surface); \
|
||||
@@ -194,28 +194,41 @@ CELL_GETTER(DrawDungeon_GetBattleBack, -1, cell->battle_background);
|
||||
return; \
|
||||
struct dgn_cell *cell = dgn_cell_at(ctx->dgn, x, y, z); \
|
||||
expr = value; \
|
||||
dungeon_map_update_cell(ctx, x, y, z); \
|
||||
if (update_map) \
|
||||
dungeon_map_update_cell(ctx, x, y, z); \
|
||||
}
|
||||
|
||||
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);
|
||||
CELL_SETTER(DrawDungeon_SetEvFloor, cell->floor_event, true);
|
||||
CELL_SETTER(DrawDungeon_SetEvWallN, cell->north_event, true);
|
||||
CELL_SETTER(DrawDungeon_SetEvWallW, cell->west_event, true);
|
||||
CELL_SETTER(DrawDungeon_SetEvWallS, cell->south_event, true);
|
||||
CELL_SETTER(DrawDungeon_SetEvWallE, cell->east_event, true);
|
||||
CELL_SETTER(DrawDungeon_SetEvFloor2, cell->floor_event2, false);
|
||||
CELL_SETTER(DrawDungeon_SetEvWallN2, cell->north_event2, false);
|
||||
CELL_SETTER(DrawDungeon_SetEvWallW2, cell->west_event2, false);
|
||||
CELL_SETTER(DrawDungeon_SetEvWallS2, cell->south_event2, false);
|
||||
CELL_SETTER(DrawDungeon_SetEvWallE2, cell->east_event2, false);
|
||||
//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);
|
||||
CELL_SETTER(DrawDungeon_SetEvRate, cell->event_blend_rate, false);
|
||||
CELL_SETTER(DrawDungeon_SetEnter, cell->enterable, false);
|
||||
CELL_SETTER(DrawDungeon_SetEnterN, cell->enterable_north, true);
|
||||
CELL_SETTER(DrawDungeon_SetEnterW, cell->enterable_west, true);
|
||||
CELL_SETTER(DrawDungeon_SetEnterS, cell->enterable_south, true);
|
||||
CELL_SETTER(DrawDungeon_SetEnterE, cell->enterable_east, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexFloor, cell->floor, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexCeiling, cell->ceiling, false);
|
||||
CELL_SETTER(DrawDungeon_SetTexWallN, cell->north_wall, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexWallW, cell->west_wall, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexWallS, cell->south_wall, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexWallE, cell->east_wall, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexDoorN, cell->north_door, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexDoorW, cell->west_door, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexDoorS, cell->south_door, true);
|
||||
CELL_SETTER(DrawDungeon_SetTexDoorE, cell->east_door, true);
|
||||
//void DrawDungeon_SetSkyTextureSet(int surface, int set);
|
||||
|
||||
HLL_WARN_UNIMPLEMENTED( , void, DrawDungeon, SetDrawMapRadar, int surface, int flag);
|
||||
@@ -311,7 +324,7 @@ HLL_LIBRARY(DrawDungeon,
|
||||
HLL_EXPORT(SetDoorWAngle, DrawDungeon_SetDoorWAngle),
|
||||
HLL_EXPORT(SetDoorSAngle, DrawDungeon_SetDoorSAngle),
|
||||
HLL_EXPORT(SetDoorEAngle, DrawDungeon_SetDoorEAngle),
|
||||
HLL_EXPORT(SetEvFloor, dungeon_set_event_floor),
|
||||
HLL_EXPORT(SetEvFloor, DrawDungeon_SetEvFloor),
|
||||
HLL_EXPORT(SetEvWallN, DrawDungeon_SetEvWallN),
|
||||
HLL_EXPORT(SetEvWallW, DrawDungeon_SetEvWallW),
|
||||
HLL_EXPORT(SetEvWallS, DrawDungeon_SetEvWallS),
|
||||
@@ -322,22 +335,22 @@ HLL_LIBRARY(DrawDungeon,
|
||||
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(SetEvRate, DrawDungeon_SetEvRate),
|
||||
HLL_EXPORT(SetEnter, DrawDungeon_SetEnter),
|
||||
HLL_EXPORT(SetEnterN, DrawDungeon_SetEnterN),
|
||||
HLL_EXPORT(SetEnterW, DrawDungeon_SetEnterW),
|
||||
HLL_EXPORT(SetEnterS, DrawDungeon_SetEnterS),
|
||||
HLL_EXPORT(SetEnterE, DrawDungeon_SetEnterE),
|
||||
HLL_EXPORT(SetTexFloor, 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_EXPORT(SetTexFloor, DrawDungeon_SetTexFloor),
|
||||
HLL_EXPORT(SetTexCeiling, DrawDungeon_SetTexCeiling),
|
||||
HLL_EXPORT(SetTexWallN, DrawDungeon_SetTexWallN),
|
||||
HLL_EXPORT(SetTexWallW, DrawDungeon_SetTexWallW),
|
||||
HLL_EXPORT(SetTexWallS, DrawDungeon_SetTexWallS),
|
||||
HLL_EXPORT(SetTexWallE, DrawDungeon_SetTexWallE),
|
||||
HLL_EXPORT(SetTexDoorN, DrawDungeon_SetTexDoorN),
|
||||
HLL_EXPORT(SetTexDoorW, DrawDungeon_SetTexDoorW),
|
||||
HLL_EXPORT(SetTexDoorS, DrawDungeon_SetTexDoorS),
|
||||
HLL_EXPORT(SetTexDoorE, DrawDungeon_SetTexDoorE),
|
||||
HLL_TODO_EXPORT(SetSkyTextureSet, DrawDungeon_SetSkyTextureSet),
|
||||
HLL_EXPORT(DrawMap, dungeon_map_draw),
|
||||
HLL_EXPORT(SetMapAllViewFlag, dungeon_map_set_all_view),
|
||||
|
||||
+1
-2
@@ -22,9 +22,8 @@ xsystem4 = ['audio.c',
|
||||
'dungeon/dgn.c',
|
||||
'dungeon/dtx.c',
|
||||
'dungeon/dungeon.c',
|
||||
'dungeon/event_markers.c',
|
||||
'dungeon/map.c',
|
||||
'dungeon/mesh.c',
|
||||
'dungeon/renderer.c',
|
||||
'dungeon/skybox.c',
|
||||
'dungeon/tes.c',
|
||||
|
||||
|
||||
Reference in New Issue
Block a user