Merge pull request #52 from kichikuou/3d

Initial implementation of ReignEngine HLL
This commit is contained in:
Nunuhara Cabbage
2022-06-03 21:51:42 -07:00
committed by GitHub
15 changed files with 2345 additions and 7 deletions
+3 -1
View File
@@ -17,9 +17,11 @@
#ifndef SYSTEM4_PLUGIN_H
#define SYSTEM4_PLUGIN_H
struct sact_sprite;
struct draw_plugin {
const char *name;
void (*update)(struct draw_plugin *);
void (*update)(struct sact_sprite *);
};
#endif /* SYSTEM4_PLUGIN_H */
+97
View File
@@ -0,0 +1,97 @@
/* Copyright (C) 2022 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_REIGN_H
#define SYSTEM4_REIGN_H
#define RE_MAX_INSTANCES 32
#include <cglm/types.h>
#include "plugin.h"
struct RE_options {
int anti_aliasing;
int wait_vsync;
};
extern struct RE_options RE_options;
struct RE_camera {
vec3 pos;
float pitch, roll, yaw; // in degrees
};
struct RE_plugin {
struct draw_plugin plugin;
int sprite;
struct RE_instance *instances[RE_MAX_INSTANCES];
struct archive *aar;
struct RE_renderer *renderer;
struct RE_camera camera;
mat4 proj_transform;
// Settings.
int render_mode;
int shadow_mode;
int bump_mode;
int bloom_mode;
int glare_mode;
int fog_mode;
int specular_mode;
int light_map_mode;
int soft_fog_edge_mode;
int ssao_mode;
int vertex_blend_mode;
int shader_precision_mode;
int texture_filter_mode;
bool use_power2_texture;
int shadow_map_resolution_level;
int texture_resolution_level;
float global_ambient_r;
float global_ambient_g;
float global_ambient_b;
float post_effect_filter_y;
float post_effect_filter_cb;
float post_effect_filter_cr;
};
struct RE_instance {
struct RE_plugin *plugin;
struct model *model;
int type;
vec3 pos;
float pitch, roll, yaw; // in degrees
vec3 vec;
vec3 scale;
bool draw;
bool local_transform_needs_update;
mat4 local_transform;
};
struct RE_plugin *RE_plugin_new(void);
void RE_plugin_free(struct RE_plugin *plugin);
bool RE_plugin_bind(struct RE_plugin *plugin, int sprite);
bool RE_plugin_unbind(struct RE_plugin *plugin);
bool RE_set_projection(struct RE_plugin *plugin, float width, float height, float near, float far, float deg);
int RE_create_instance(struct RE_plugin *plugin);
bool RE_release_instance(struct RE_plugin *plugin, int instance);
bool RE_instance_load(struct RE_instance *instance, const char *name);
void RE_render(struct sact_sprite *sp);
void RE_debug_print(struct RE_plugin *p);
#endif /* SYSTEM4_REIGN_H */
+25
View File
@@ -0,0 +1,25 @@
/* Copyright (C) 2022 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/>.
*/
uniform sampler2D tex;
in vec2 tex_coord;
out vec4 frag_color;
void main() {
// TODO: Implement lighting.
frag_color = texture(tex, tex_coord);
}
+29
View File
@@ -0,0 +1,29 @@
/* Copyright (C) 2022 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/>.
*/
uniform mat4 local_transform;
uniform mat4 view_transform;
uniform mat4 proj_transform;
in vec3 vertex_pos;
in vec3 vertex_normal;
in vec2 vertex_uv;
out vec2 tex_coord;
void main() {
gl_Position = proj_transform * view_transform * local_transform * vec4(vertex_pos, 1.0);
tex_coord = vertex_uv;
}
+138
View File
@@ -0,0 +1,138 @@
/* Copyright (C) 2022 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_3D_3D_INTERNAL_H
#define SYSTEM4_3D_3D_INTERNAL_H
#include <cglm/types.h>
#include "system4/archive.h"
#include "gfx/gl.h"
#include "gfx/gfx.h"
struct model {
char *name;
int nr_meshes;
struct mesh *meshes;
int nr_materials;
struct material *materials;
};
struct mesh {
GLuint vao;
GLuint attr_buffer;
int nr_vertices;
int material;
};
struct material {
GLuint color_map;
bool opaque;
};
struct RE_renderer {
struct shader shader;
GLuint depth_buffer;
// Uniform variable locations
GLint local_transform;
GLint proj_transform;
// Attribute variable locations
GLint vertex_normal;
GLint vertex_uv;
};
// model.c
struct model *model_load(struct archive *aar, const char *path, struct RE_renderer *renderer);
void model_free(struct model *model);
// renderer.c
struct RE_renderer *RE_renderer_new(struct texture *texture);
void RE_renderer_free(struct RE_renderer *r);
// parser.c
struct pol {
int32_t version;
uint32_t nr_materials;
struct pol_material_group *materials;
uint32_t nr_meshes;
struct pol_mesh **meshes;
uint32_t nr_bones;
struct pol_bone *bones;
};
enum pol_texture_type {
COLOR_MAP = 1,
MAX_TEXTURE_TYPE
};
struct pol_material {
char *name;
char *textures[MAX_TEXTURE_TYPE];
};
struct pol_material_group {
struct pol_material m;
uint32_t nr_children;
struct pol_material *children;
};
struct pol_mesh {
char *name;
uint32_t material;
uint32_t nr_vertices;
struct pol_vertex *vertices;
uint32_t nr_uvs;
vec2 *uvs;
uint32_t nr_triangles;
struct pol_triangle *triangles;
};
struct pol_vertex {
vec3 pos;
uint32_t nr_weights;
struct pol_bone_weight *weights;
};
struct pol_bone_weight {
uint32_t bone;
float weight;
};
struct pol_triangle {
uint32_t vert_index[3];
uint32_t uv_index[3];
vec3 normals[3];
uint32_t material; // index in the material group
};
struct pol_bone {
char *name;
uint32_t id;
int32_t parent;
vec3 pos;
versor rotq;
};
struct pol *pol_parse(uint8_t *data, size_t size);
void pol_free(struct pol *pol);
#endif /* SYSTEM4_3D_3D_INTERNAL_H */
+209
View File
@@ -0,0 +1,209 @@
/* Copyright (C) 2022 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 <cglm/cglm.h>
#include "system4.h"
#include "system4/aar.h"
#include "system4/cg.h"
#include "3d_internal.h"
#include "reign.h"
struct vertex {
GLfloat pos[3];
GLfloat normal[3];
GLfloat uv[2];
};
static bool init_material(struct material *material, const struct pol_material *m, struct archive *aar, const char *path)
{
if (!m->textures[COLOR_MAP]) {
WARNING("No color texture");
return false;
}
char *texture_path = xmalloc(strlen(path) + strlen(m->textures[COLOR_MAP]) + 2);
sprintf(texture_path, "%s\\%s", path, m->textures[COLOR_MAP]);
struct archive_data *dfile = archive_get_by_name(aar, texture_path);
if (!dfile) {
WARNING("cannot load texture %s", texture_path);
free(texture_path);
return false;
}
struct cg *cg = cg_load_data(dfile);
archive_free_data(dfile);
if (!cg) {
WARNING("cg_load_data failed: %s", texture_path);
free(texture_path);
return false;
}
free(texture_path);
glGenTextures(1, &material->color_map);
glBindTexture(GL_TEXTURE_2D, material->color_map);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
material->opaque = !cg->metrics.has_alpha;
cg_free(cg);
return true;
}
static void destroy_material(struct material *material)
{
if (material->color_map)
glDeleteTextures(1, &material->color_map);
}
static void add_mesh(struct model *model, struct pol_mesh *m, int material_index, int material, struct RE_renderer *r)
{
struct vertex *buf = xmalloc(m->nr_triangles * 3 * sizeof(struct vertex));
int v = 0;
for (uint32_t i = 0; i < m->nr_triangles; i++) {
struct pol_triangle *t = &m->triangles[i];
if (material_index >= 0 && t->material != (uint32_t)material_index)
continue;
for (int j = 0; j < 3; j++) {
glm_vec3_copy(m->vertices[t->vert_index[j]].pos, buf[v].pos);
glm_vec3_copy(t->normals[j], buf[v].normal);
glm_vec2_copy(m->uvs[t->uv_index[j]], buf[v].uv);
v++;
}
}
if (v == 0) {
free(buf);
return;
}
model->meshes = xrealloc_array(model->meshes, model->nr_meshes, model->nr_meshes + 1, sizeof(struct mesh));
struct mesh *mesh = &model->meshes[model->nr_meshes++];
mesh->material = material;
mesh->nr_vertices = v;
glGenVertexArrays(1, &mesh->vao);
glBindVertexArray(mesh->vao);
glGenBuffers(1, &mesh->attr_buffer);
glBindBuffer(GL_ARRAY_BUFFER, mesh->attr_buffer);
glEnableVertexAttribArray(r->shader.vertex);
glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)0);
glEnableVertexAttribArray(r->vertex_normal);
glVertexAttribPointer(r->vertex_normal, 3, GL_FLOAT, GL_TRUE, sizeof(struct vertex), (const void *)offsetof(struct vertex, normal));
glEnableVertexAttribArray(r->vertex_uv);
glVertexAttribPointer(r->vertex_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)offsetof(struct vertex, uv));
glBufferData(GL_ARRAY_BUFFER, mesh->nr_vertices * sizeof(struct vertex), buf, GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
free(buf);
}
static void destroy_mesh(struct mesh *mesh)
{
glDeleteVertexArrays(1, &mesh->vao);
glDeleteBuffers(1, &mesh->attr_buffer);
}
struct model *model_load(struct archive *aar, const char *path, struct RE_renderer *r)
{
if (path[0] == '\0')
return NULL;
const char *basename = strrchr(path, '\\');
basename = basename ? basename + 1 : path;
char *polname = xmalloc(strlen(path) + strlen(basename) + 6);
sprintf(polname, "%s\\%s.POL", path, basename);
struct archive_data *dfile = archive_get_by_name(aar, polname);
if (!dfile) {
WARNING("%s: not found", polname);
free(polname);
return NULL;
}
struct pol *pol = pol_parse(dfile->data, dfile->size);
archive_free_data(dfile);
if (!pol) {
WARNING("%s: parse error", polname);
free(polname);
return NULL;
}
struct model *model = xcalloc(1, sizeof(struct model));
model->name = polname;
// Materials
int *material_offsets = xmalloc(pol->nr_materials * sizeof(int));
for (uint32_t i = 0; i < pol->nr_materials; i++) {
material_offsets[i] = model->nr_materials;
if (pol->materials[i].nr_children)
model->nr_materials += pol->materials[i].nr_children;
else
model->nr_materials++;
}
model->materials = xcalloc(model->nr_materials, sizeof(struct material));
for (uint32_t i = 0; i < pol->nr_materials; i++) {
if (pol->materials[i].nr_children == 0) {
init_material(&model->materials[material_offsets[i]],
&pol->materials[i].m, aar, path);
continue;
}
for (uint32_t j = 0; j < pol->materials[i].nr_children; j++) {
init_material(&model->materials[material_offsets[i] + j],
&pol->materials[i].children[j], aar, path);
}
}
// Meshes
for (uint32_t i = 0; i < pol->nr_meshes; i++) {
if (!pol->meshes[i])
continue;
struct pol_material_group *mg = &pol->materials[pol->meshes[i]->material];
int m_off = material_offsets[pol->meshes[i]->material];
if (mg->nr_children == 0) {
add_mesh(model, pol->meshes[i], -1, m_off, r);
continue;
}
for (uint32_t j = 0; j < mg->nr_children; j++) {
add_mesh(model, pol->meshes[i], j, m_off + j, r);
}
}
free(material_offsets);
pol_free(pol);
return model;
}
void model_free(struct model *model)
{
for (int i = 0; i < model->nr_meshes; i++)
destroy_mesh(&model->meshes[i]);
free(model->meshes);
for (int i = 0; i < model->nr_materials; i++)
destroy_material(&model->materials[i]);
free(model->materials);
free(model->name);
free(model);
}
+286
View File
@@ -0,0 +1,286 @@
/* Copyright (C) 2022 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 <cglm/cglm.h>
#include "system4.h"
#include "system4/buffer.h"
#include "3d_internal.h"
#define METERS_PER_INCH 0.0254
static char *read_cstring(struct buffer *r)
{
char *s = strdup(buffer_strdata(r));
buffer_skip(r, strlen(s) + 1);
return s;
}
static void read_position(struct buffer *r, vec3 v)
{
// left->right handed system
v[0] = buffer_read_float(r) * METERS_PER_INCH;
v[1] = buffer_read_float(r) * METERS_PER_INCH;
v[2] = -buffer_read_float(r) * METERS_PER_INCH;
}
static void read_direction(struct buffer *r, vec3 v)
{
// left->right handed system
v[0] = buffer_read_float(r);
v[1] = buffer_read_float(r);
v[2] = -buffer_read_float(r);
}
static void read_quaternion(struct buffer *r, versor q)
{
// left->right handed system
float w = buffer_read_float(r);
float x = -buffer_read_float(r);
float y = -buffer_read_float(r);
float z = buffer_read_float(r);
glm_quat_init(q, x, y, z, w);
}
static void parse_material(struct buffer *r, struct pol_material *m)
{
m->name = read_cstring(r);
int nr_textures = buffer_read_int32(r);
for (int i = 0; i < nr_textures; i++) {
char *filename = read_cstring(r);
int type = buffer_read_int32(r);
if ((unsigned)type < MAX_TEXTURE_TYPE) {
m->textures[type] = filename;
} else {
WARNING("invalid texture type %d", type);
free(filename);
}
}
}
static void destroy_material(struct pol_material *m)
{
free(m->name);
for (int i = 0; i < MAX_TEXTURE_TYPE; i++)
free(m->textures[i]);
}
static void parse_material_group(struct buffer *r, struct pol_material_group *mg)
{
parse_material(r, &mg->m);
mg->nr_children = buffer_read_int32(r);
if (mg->nr_children > 0) {
mg->children = xcalloc(mg->nr_children, sizeof(struct pol_material));
for (uint32_t i = 0; i < mg->nr_children; i++) {
parse_material(r, &mg->children[i]);
}
}
}
static void destroy_material_group(struct pol_material_group *mg)
{
destroy_material(&mg->m);
if (mg->children) {
for (uint32_t i = 0; i < mg->nr_children; i++)
destroy_material(&mg->children[i]);
free(mg->children);
}
}
static void parse_vertex(struct buffer *r, int pol_version, struct pol_vertex *v)
{
read_position(r, v->pos);
v->nr_weights = pol_version == 1 ? buffer_read_int32(r) : buffer_read_u16(r);
if (v->nr_weights) {
v->weights = xcalloc(v->nr_weights, sizeof(struct pol_bone_weight));
for (uint32_t i = 0; i < v->nr_weights; i++) {
v->weights[i].bone = pol_version == 1 ? buffer_read_int32(r) : buffer_read_u16(r);
v->weights[i].weight = buffer_read_float(r);
}
}
}
static void destroy_vertex(struct pol_vertex *v)
{
if (v->weights)
free(v->weights);
}
static void parse_triangle(struct buffer *r, int unknowns_length, struct pol_triangle *t)
{
t->vert_index[0] = buffer_read_int32(r);
t->vert_index[1] = buffer_read_int32(r);
t->vert_index[2] = buffer_read_int32(r);
t->uv_index[0] = buffer_read_int32(r);
t->uv_index[1] = buffer_read_int32(r);
t->uv_index[2] = buffer_read_int32(r);
buffer_skip(r, unknowns_length);
read_direction(r, t->normals[0]);
read_direction(r, t->normals[1]);
read_direction(r, t->normals[2]);
t->material = buffer_read_int32(r);
}
static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version)
{
int type = buffer_read_int32(r);
if (type != 0) {
if (type != -1)
WARNING("unknown mesh type: %d", type);
return NULL;
}
struct pol_mesh *mesh = xcalloc(1, sizeof(struct pol_mesh));
mesh->name = read_cstring(r);
mesh->material = buffer_read_int32(r);
mesh->nr_vertices = buffer_read_int32(r);
mesh->vertices = xcalloc(mesh->nr_vertices, sizeof(struct pol_vertex));
for (uint32_t i = 0; i < mesh->nr_vertices; i++) {
parse_vertex(r, pol_version, &mesh->vertices[i]);
}
mesh->nr_uvs = buffer_read_int32(r);
mesh->uvs = xcalloc(mesh->nr_uvs, sizeof(vec2));
for (uint32_t i = 0; i < mesh->nr_uvs; i++) {
mesh->uvs[i][0] = buffer_read_float(r);
mesh->uvs[i][1] = buffer_read_float(r);
}
int triangle_unknowns_length = 12;
int nr_unknown_f64s = buffer_read_int32(r);
if (nr_unknown_f64s) {
buffer_skip(r, nr_unknown_f64s * 8);
triangle_unknowns_length += 12;
}
if (pol_version == 1) {
int nr_unknown_vecs = buffer_read_int32(r);
buffer_skip(r, nr_unknown_vecs * 12);
} else {
int nr_unknown_ints = buffer_read_int32(r);
buffer_skip(r, nr_unknown_ints * 4);
int nr_unknown_bytes = buffer_read_int32(r);
if (nr_unknown_bytes) {
buffer_skip(r, nr_unknown_bytes);
triangle_unknowns_length += 12;
}
}
mesh->nr_triangles = buffer_read_int32(r);
mesh->triangles = xcalloc(mesh->nr_triangles, sizeof(struct pol_triangle));
for (uint32_t i = 0; i < mesh->nr_triangles; i++) {
parse_triangle(r, triangle_unknowns_length, &mesh->triangles[i]);
}
if (pol_version == 1) {
if (buffer_read_int32(r) != 1)
WARNING("unexpected mesh footer");
if (buffer_read_int32(r) != 0)
WARNING("unexpected mesh footer");
}
return mesh;
}
static void free_mesh(struct pol_mesh *mesh)
{
if (!mesh)
return;
free(mesh->name);
for (uint32_t i = 0; i < mesh->nr_vertices; i++)
destroy_vertex(&mesh->vertices[i]);
free(mesh->vertices);
free(mesh->uvs);
free(mesh->triangles);
free(mesh);
}
static void parse_bone(struct buffer *r, struct pol_bone *bone)
{
bone->name = read_cstring(r);
bone->id = buffer_read_int32(r);
bone->parent = buffer_read_int32(r);
read_position(r, bone->pos);
read_quaternion(r, bone->rotq);
}
static void destroy_bone(struct pol_bone *bone)
{
free(bone->name);
}
struct pol *pol_parse(uint8_t *data, size_t size)
{
struct buffer r;
buffer_init(&r, data, size);
if (memcmp(buffer_strdata(&r), "POL\0", 4))
return NULL;
buffer_skip(&r, 4);
struct pol *pol = xcalloc(1, sizeof(struct pol));
pol->version = buffer_read_int32(&r);
if (pol->version != 1 && pol->version != 2) {
WARNING("unknown POL version: %d", pol->version);
free(pol);
return NULL;
}
pol->nr_materials = buffer_read_int32(&r);
pol->materials = xcalloc(pol->nr_materials, sizeof(struct pol_material_group));
for (uint32_t i = 0; i < pol->nr_materials; i++) {
parse_material_group(&r, &pol->materials[i]);
}
pol->nr_meshes = buffer_read_int32(&r);
pol->meshes = xcalloc(pol->nr_meshes, sizeof(struct pol_mesh *));
for (uint32_t i = 0; i < pol->nr_meshes; i++) {
pol->meshes[i] = parse_mesh(&r, pol->version);
}
pol->nr_bones = buffer_read_int32(&r);
if (pol->nr_bones) {
pol->bones = xcalloc(pol->nr_bones, sizeof(struct pol_bone));
for (uint32_t i = 0; i < pol->nr_bones; i++) {
parse_bone(&r, &pol->bones[i]);
}
}
if (buffer_remaining(&r) != 0) {
WARNING("extra data at end");
}
return pol;
}
void pol_free(struct pol *pol)
{
for (uint32_t i = 0; i < pol->nr_materials; i++)
destroy_material_group(&pol->materials[i]);
free(pol->materials);
for (uint32_t i = 0; i < pol->nr_meshes; i++)
free_mesh(pol->meshes[i]);
free(pol->meshes);
for (uint32_t i = 0; i < pol->nr_bones; i++)
destroy_bone(&pol->bones[i]);
free(pol->bones);
free(pol);
}
+166
View File
@@ -0,0 +1,166 @@
/* Copyright (C) 2022 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cglm/cglm.h>
#include "system4.h"
#include "system4/aar.h"
#include "3d_internal.h"
#include "reign.h"
#include "sact.h"
#include "xsystem4.h"
static struct RE_instance *create_instance(struct RE_plugin *plugin)
{
struct RE_instance *instance = xcalloc(1, sizeof(struct RE_instance));
instance->plugin = plugin;
instance->scale[0] = 1.0;
instance->scale[1] = 1.0;
instance->scale[2] = 1.0;
glm_mat4_identity(instance->local_transform);
return instance;
}
static void free_instance(struct RE_instance *instance)
{
if (instance->model)
model_free(instance->model);
free(instance);
}
struct RE_plugin *RE_plugin_new(void)
{
char *aar_path = gamedir_path("Data/ReignData.red");
int error = ARCHIVE_SUCCESS;
struct archive *aar = (struct archive *)aar_open(aar_path, ARCHIVE_MMAP, &error);
if (error == ARCHIVE_FILE_ERROR) {
WARNING("aar_open(\"%s\"): %s", display_utf0(aar_path), strerror(errno));
} else if (error == ARCHIVE_BAD_ARCHIVE_ERROR) {
WARNING("aar_open(\"%s\"): invalid AAR archive", display_utf0(aar_path));
}
free(aar_path);
if (!aar)
return NULL;
struct RE_plugin *plugin = xcalloc(1, sizeof(struct RE_plugin));
plugin->plugin.name = "ReignEngine";
plugin->plugin.update = RE_render;
plugin->aar = aar;
return plugin;
}
void RE_plugin_free(struct RE_plugin *plugin)
{
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
if (plugin->instances[i])
free_instance(plugin->instances[i]);
}
archive_free(plugin->aar);
if (plugin->renderer)
RE_renderer_free(plugin->renderer);
free(plugin);
}
bool RE_plugin_bind(struct RE_plugin *plugin, int sprite)
{
struct sact_sprite *sp = sact_try_get_sprite(sprite);
if (!sp)
return false;
plugin->renderer = RE_renderer_new(sprite_get_texture(sp));
plugin->sprite = sprite;
sprite_bind_plugin(sp, &plugin->plugin);
return true;
}
bool RE_plugin_unbind(struct RE_plugin *plugin)
{
if (!plugin || !plugin->renderer)
return false;
struct sact_sprite *sp = sact_try_get_sprite(plugin->sprite);
if (sp)
sprite_bind_plugin(sp, NULL);
RE_renderer_free(plugin->renderer);
plugin->renderer = NULL;
plugin->sprite = 0;
return true;
}
bool RE_set_projection(struct RE_plugin *plugin, float width, float height, float near, float far, float deg)
{
if (!plugin)
return false;
glm_perspective(glm_rad(deg), width / height, near, far, plugin->proj_transform);
return true;
}
int RE_create_instance(struct RE_plugin *plugin)
{
if (!plugin)
return -1;
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
if (!plugin->instances[i]) {
plugin->instances[i] = create_instance(plugin);
return i;
}
}
WARNING("too many instances");
return -1;
}
bool RE_release_instance(struct RE_plugin *plugin, int instance)
{
if (!plugin || !plugin->instances[instance])
return false;
free_instance(plugin->instances[instance]);
plugin->instances[instance] = NULL;
return true;
}
bool RE_instance_load(struct RE_instance *instance, const char *name)
{
if (!instance)
return false;
if (instance->model)
model_free(instance->model);
instance->model = model_load(instance->plugin->aar, name, instance->plugin->renderer);
return !!instance->model;
}
void RE_debug_print(struct RE_plugin *p)
{
printf("camera = { x: %f, y: %f, z: %f, pitch: %f, roll: %f, yaw: %f }",
p->camera.pos[0], p->camera.pos[1], p->camera.pos[2],
p->camera.pitch, p->camera.roll, p->camera.yaw);
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
struct RE_instance *inst = p->instances[i];
if (!inst || !inst->model)
continue;
printf("[%d] = {", i);
printf(" name: \"%s\",", inst->model->name);
printf(" type: %d,", inst->type);
printf(" draw: %d,", inst->draw);
printf(" pos: { x: %f, y: %f, z: %f },", inst->pos[0], inst->pos[1], inst->pos[2]);
printf(" vec: { x: %f, y: %f, z: %f },", inst->vec[0], inst->vec[1], inst->vec[2]);
printf(" scale: { x: %f, y: %f, z: %f },", inst->scale[0], inst->scale[1], inst->scale[2]);
printf("}");
}
}
+152
View File
@@ -0,0 +1,152 @@
/* Copyright (C) 2022 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 <cglm/cglm.h>
#include "system4.h"
#include "3d_internal.h"
#include "reign.h"
#include "sact.h"
struct RE_renderer *RE_renderer_new(struct texture *texture)
{
struct RE_renderer *r = xcalloc(1, sizeof(struct RE_renderer));
gfx_load_shader(&r->shader, "shaders/reign.v.glsl", "shaders/reign.f.glsl");
r->local_transform = glGetUniformLocation(r->shader.program, "local_transform");
r->proj_transform = glGetUniformLocation(r->shader.program, "proj_transform");
r->vertex_normal = glGetAttribLocation(r->shader.program, "vertex_normal");
r->vertex_uv = glGetAttribLocation(r->shader.program, "vertex_uv");
glGenRenderbuffers(1, &r->depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, r->depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, texture->w, texture->h);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
return r;
}
void RE_renderer_free(struct RE_renderer *r)
{
glDeleteProgram(r->shader.program);
glDeleteRenderbuffers(1, &r->depth_buffer);
free(r);
}
static void calc_view_matrix(struct RE_camera *camera, mat4 out)
{
vec3 front = { 0.0, 0.0, -1.0 };
vec3 euler = {
glm_rad(camera->pitch),
glm_rad(camera->yaw),
glm_rad(camera->roll)
};
mat4 rot;
glm_euler(euler, rot);
glm_mat4_mulv3(rot, front, 0.0, front);
vec3 up = {0.0, 1.0, 0.0};
glm_look(camera->pos, front, up, out);
}
static void update_local_transform(struct RE_instance *inst)
{
vec3 euler = {
glm_rad(inst->pitch),
glm_rad(inst->yaw),
glm_rad(inst->roll)
};
mat4 rot;
glm_euler(euler, rot);
glm_translate_make(inst->local_transform, inst->pos);
glm_mat4_mul(inst->local_transform, rot, inst->local_transform);
glm_scale(inst->local_transform, inst->scale);
inst->local_transform_needs_update = false;
}
static void render_instance(struct RE_instance *inst, struct RE_renderer *r, mat4 view_transform, mat4 proj_transform)
{
if (!inst->draw || !inst->model)
return;
if (inst->local_transform_needs_update)
update_local_transform(inst);
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]);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, inst->local_transform[0]);
struct model *model = inst->model;
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, model->materials[mesh->material].color_map);
glUniform1i(r->shader.texture, 0);
glBindVertexArray(mesh->vao);
glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
glUseProgram(0);
}
void RE_render(struct sact_sprite *sp)
{
struct RE_plugin *plugin = (struct RE_plugin *)sp->plugin;
struct RE_renderer *r = plugin->renderer;
if (!r)
return;
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, r->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 view_transform;
calc_view_matrix(&plugin->camera, view_transform);
// Tweak the projection transform so that the rendering result is vertically
// flipped. If we render the scene normally, the resulting image will be
// bottom-up (the first pixel is at the bottom-left), but we want a top-down
// image (the first pixel is at the top-left). This changes the coordinate
// system from right-handed to left-handed, we also need to reverse the
// winding order.
plugin->proj_transform[1][1] *= -1;
glFrontFace(GL_CW);
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
if (plugin->instances[i])
render_instance(plugin->instances[i], r, view_transform, plugin->proj_transform);
}
plugin->proj_transform[1][1] *= -1;
glFrontFace(GL_CCW);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
}
+3 -4
View File
@@ -45,7 +45,7 @@
#define M_PI (3.14159265358979323846)
#endif
static void dungeon_render(struct draw_plugin *plugin);
static void dungeon_render(struct sact_sprite *sp);
struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int surface)
{
@@ -257,12 +257,11 @@ static void model_view_matrix(struct camera *camera, mat4 out)
glm_lookat(eye, camera->pos, up, out);
}
static void dungeon_render(struct draw_plugin *plugin)
static void dungeon_render(struct sact_sprite *sp)
{
struct dungeon_context *ctx = (struct dungeon_context *)plugin;
struct dungeon_context *ctx = (struct dungeon_context *)sp->plugin;
if (!ctx->loaded || !ctx->draw_enabled)
return;
struct sact_sprite *sp = sact_get_sprite(ctx->surface);
sprite_dirty(sp);
struct texture *texture = sprite_get_texture(sp);
+2
View File
@@ -338,6 +338,7 @@ extern struct static_library lib_OutputLog;
extern struct static_library lib_PassRegister;
extern struct static_library lib_PlayDemo;
extern struct static_library lib_PlayMovie;
extern struct static_library lib_ReignEngine;
extern struct static_library lib_SACT2;
extern struct static_library lib_SACTDX;
extern struct static_library lib_SengokuRanceFont;
@@ -401,6 +402,7 @@ static struct static_library *static_libraries[] = {
&lib_PassRegister,
&lib_PlayDemo,
&lib_PlayMovie,
&lib_ReignEngine,
&lib_SACT2,
&lib_SACTDX,
&lib_SengokuRanceFont,
File diff suppressed because it is too large Load Diff
+6
View File
@@ -31,6 +31,11 @@ xsystem4 = [version_h,
'video.c',
'vm.c',
'3d/model.c',
'3d/parser.c',
'3d/reign.c',
'3d/renderer.c',
'dungeon/dgn.c',
'dungeon/dtx.c',
'dungeon/dungeon.c',
@@ -98,6 +103,7 @@ xsystem4 = [version_h,
'hll/PassRegister.c',
'hll/PlayDemo.c',
'hll/PlayMovie.c',
'hll/ReignEngine.c',
'hll/SACT2.c',
'hll/SengokuRanceFont.c',
'hll/SoundFilePlayer.c',
+1 -1
View File
@@ -338,7 +338,7 @@ void sprite_call_plugins(void)
{
struct sact_sprite *sp;
LIST_FOREACH(sp, &sprites_with_plugins, entry) {
sp->plugin->update(sp->plugin);
sp->plugin->update(sp);
}
}