Merge pull request #331 from kichikuou/POLv4

SealEngine: Support POL v4 format
This commit is contained in:
Nunuhara Cabbage
2026-04-25 20:37:33 -07:00
committed by GitHub
6 changed files with 165 additions and 23 deletions
+7
View File
@@ -76,6 +76,8 @@ vec3 dir_lights_diffuse(vec3 norm)
#endif // ENGINE == REIGN_ENGINE
uniform sampler2D tex;
uniform sampler2D blend_tex;
uniform bool use_blend_texture;
uniform sampler2D alpha_texture;
uniform sampler2D light_texture;
uniform sampler2D shadow_texture;
@@ -98,6 +100,8 @@ in vec4 shadow_frag_pos;
in float dist;
in vec3 eye;
in vec3 normal;
in float blend_weight;
in vec2 blend_tex_coord;
out vec4 frag_color;
void main() {
@@ -119,6 +123,9 @@ void main() {
frag_rgb = texel.rgb;
} else {
texel = texture(tex, tex_coord);
if (use_blend_texture) {
texel = mix(texel, texture(blend_tex, blend_tex_coord), blend_weight);
}
if (diffuse_type == DIFFUSE_EMISSIVE) {
frag_rgb = texel.rgb;
} else {
+6
View File
@@ -72,6 +72,8 @@ in vec4 vertex_color;
in vec4 vertex_tangent;
in ivec4 vertex_bone_index;
in vec4 vertex_bone_weight;
in float vertex_blend_weight;
in vec2 vertex_blend_uv;
out vec2 tex_coord;
out vec2 light_tex_coord;
@@ -81,6 +83,8 @@ out vec4 shadow_frag_pos;
out float dist;
out vec3 eye;
out vec3 normal;
out float blend_weight;
out vec2 blend_tex_coord;
void main() {
mat4 local_bone_transform = local_transform;
@@ -117,6 +121,8 @@ void main() {
tex_coord = vertex_uv + uv_scroll;
light_tex_coord = vertex_light_uv + uv_scroll;
color_mod = vertex_color;
blend_weight = vertex_blend_weight;
blend_tex_coord = vertex_blend_uv + uv_scroll;
dist = -view_pos.z;
shadow_frag_pos = shadow_transform * world_pos;
+12 -1
View File
@@ -74,6 +74,7 @@ struct material {
GLuint alpha_map;
GLuint light_map;
GLuint normal_map;
GLuint blend_texture;
float specular_strength;
float specular_shininess;
float shadow_darkness;
@@ -108,6 +109,8 @@ enum RE_attribute_location {
VATTR_LIGHT_UV,
VATTR_COLOR,
VATTR_TANGENT,
VATTR_BLEND_WEIGHT,
VATTR_BLEND_UV,
};
struct shadow_renderer {
@@ -185,6 +188,8 @@ struct RE_renderer {
GLint alpha_mode;
GLint alpha_texture;
GLint uv_scroll;
GLint blend_tex;
GLint use_blend_texture;
GLuint billboard_vao;
GLuint billboard_attr_buffer;
@@ -431,7 +436,7 @@ struct pol_material {
struct pol_material_group {
struct pol_material m;
uint32_t nr_children;
struct pol_material *children;
struct pol_material_group *children;
};
enum mesh_flags {
@@ -461,6 +466,10 @@ struct pol_mesh {
vec3 *colors;
uint32_t nr_alphas;
float *alphas;
uint32_t nr_blend_uvs;
vec2 *blend_uvs;
uint32_t nr_blend_weights;
float *blend_weights;
uint32_t nr_triangles;
struct pol_triangle *triangles;
// Parameters in .opr file.
@@ -486,6 +495,8 @@ struct pol_triangle {
uint32_t light_uv_index[3];
uint32_t color_index[3];
uint32_t alpha_index[3];
uint32_t blend_uv_index[3];
uint32_t blend_weight_index[3];
vec3 normals[3];
uint32_t material_group_index;
};
+43 -2
View File
@@ -54,6 +54,11 @@ struct vertex_bones {
GLfloat bone_weight[NR_WEIGHTS];
};
struct vertex_blend {
GLfloat blend_weight;
GLfloat blend_uv[2];
};
static bool is_transparent_mesh(const struct pol_mesh *mesh)
{
if (re_plugin_version == RE_REIGN_PLUGIN)
@@ -202,6 +207,8 @@ static void destroy_material(struct material *material)
glDeleteTextures(1, &material->light_map);
if (material->normal_map)
glDeleteTextures(1, &material->normal_map);
if (material->blend_texture)
glDeleteTextures(1, &material->blend_texture);
}
static int cmp_by_bone_weight(const void *lhs, const void *rhs)
@@ -276,6 +283,7 @@ static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_
bool has_vertex_colors = m->nr_colors > 0 || m->nr_alphas > 0;
bool has_normal_map = model->materials[material].normal_map != 0;
bool has_bones = !!model->bone_map;
bool has_blend = m->blend_weights && model->materials[material].blend_texture;
GLsizei stride = sizeof(struct vertex_common);
if (has_light_map)
@@ -286,6 +294,8 @@ static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_
stride += sizeof(struct vertex_tangent);
if (has_bones)
stride += sizeof(struct vertex_bones);
if (has_blend)
stride += sizeof(struct vertex_blend);
void *buffer = xmalloc(m->nr_triangles * 3 * stride);
uint8_t *ptr = buffer;
@@ -336,6 +346,14 @@ static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_
}
}
}
if (has_blend) {
struct vertex_blend *v_blend = buf_alloc(&ptr, sizeof(struct vertex_blend));
v_blend->blend_weight = m->blend_weights[t->blend_weight_index[j]];
if (m->blend_uvs)
glm_vec2_copy(m->blend_uvs[t->blend_uv_index[j]], v_blend->blend_uv);
else
glm_vec2_copy(m->uvs[t->uv_index[j]], v_blend->blend_uv);
}
nr_vertices++;
}
}
@@ -412,6 +430,18 @@ static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_
glDisableVertexAttribArray(VATTR_BONE_WEIGHT);
glVertexAttrib4f(VATTR_BONE_WEIGHT, 0.0, 0.0, 0.0, 0.0);
}
if (has_blend) {
glEnableVertexAttribArray(VATTR_BLEND_WEIGHT);
glVertexAttribPointer(VATTR_BLEND_WEIGHT, 1, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_blend, blend_weight));
glEnableVertexAttribArray(VATTR_BLEND_UV);
glVertexAttribPointer(VATTR_BLEND_UV, 2, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_blend, blend_uv));
base += sizeof(struct vertex_blend);
} else {
glDisableVertexAttribArray(VATTR_BLEND_WEIGHT);
glVertexAttrib1f(VATTR_BLEND_WEIGHT, 0.0);
glDisableVertexAttribArray(VATTR_BLEND_UV);
glVertexAttrib2f(VATTR_BLEND_UV, 0.0, 0.0);
}
assert((intptr_t)base == stride);
glBufferData(GL_ARRAY_BUFFER, mesh->nr_vertices * stride, buffer, GL_STATIC_DRAW);
@@ -543,8 +573,19 @@ struct model *model_load(struct archive *aar, const char *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], amt, aar, path);
struct pol_material_group *child = &pol->materials[i].children[j];
if (child->nr_children >= 2) {
// Group node: texture blending (base + blend)
init_material(&model->materials[material_offsets[i] + j],
&child->children[0].m, amt, aar, path);
if (child->children[1].m.textures[COLOR_MAP]) {
model->materials[material_offsets[i] + j].blend_texture =
load_texture(aar, path, child->children[1].m.textures[COLOR_MAP], NULL);
}
} else {
init_material(&model->materials[material_offsets[i] + j],
&child->m, amt, aar, path);
}
}
}
+83 -20
View File
@@ -70,15 +70,14 @@ static uint32_t parse_material_attributes(const char *name)
return flags;
}
static void parse_material(struct buffer *r, struct pol_material *m)
static void parse_textures(struct buffer *r, int pol_version, struct pol_material *m)
{
m->name = read_cstring(r);
m->flags = parse_material_attributes(m->name);
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 (pol_version >= 3)
buffer_skip(r, 8); // 2 unknown float params
if ((unsigned)type < MAX_TEXTURE_TYPE) {
m->textures[type] = filename;
} else {
@@ -95,29 +94,60 @@ static void destroy_material(struct pol_material *m)
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]);
destroy_material_group(&mg->children[i]);
free(mg->children);
}
}
// Material tree layout:
// level 0: top-level material per pol->materials[]. Either a textured leaf
// or a group containing sub-materials, never both.
// level 1: sub-material. Either a textured leaf or, in v4 only, a "blend
// group" (is_group=1) with exactly 2 leaf children.
// level 2: leaf children of a v4 blend group; cannot themselves be a group.
static void parse_material_group(struct buffer *r, int pol_version,
struct pol_material_group *mg, int level)
{
mg->m.name = read_cstring(r);
mg->m.flags = parse_material_attributes(mg->m.name);
bool is_group = false;
if (pol_version >= 4)
is_group = buffer_read_int32(r);
if (is_group) {
if (level >= 2)
ERROR("material group nesting too deep");
uint32_t uk = buffer_read_int32(r);
if (uk != 0)
ERROR("unexpected nonzero value in material group: %u", uk);
mg->nr_children = buffer_read_int32(r);
if (level == 1 && mg->nr_children != 2)
ERROR("blend group must have 2 children, got %u", mg->nr_children);
} else {
parse_textures(r, pol_version, &mg->m);
if (pol_version >= 4) {
uint32_t uk = buffer_read_int32(r);
if (uk != 0)
ERROR("unexpected nonzero value in material leaf: %u", uk);
} else if (level == 0) {
mg->nr_children = buffer_read_int32(r);
}
}
if (mg->nr_children > 0) {
mg->children = xcalloc(mg->nr_children, sizeof(struct pol_material_group));
for (uint32_t i = 0; i < mg->nr_children; i++)
parse_material_group(r, pol_version, &mg->children[i], level + 1);
}
}
static void parse_vertex(struct buffer *r, int pol_version, struct pol_vertex *v)
{
read_position(r, v->pos);
@@ -151,6 +181,11 @@ static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle
t->light_uv_index[1] = buffer_read_int32(r) - mesh->nr_uvs;
t->light_uv_index[2] = buffer_read_int32(r) - mesh->nr_uvs;
}
if (mesh->blend_uvs) {
t->blend_uv_index[0] = buffer_read_int32(r) - mesh->nr_uvs - mesh->nr_light_uvs;
t->blend_uv_index[1] = buffer_read_int32(r) - mesh->nr_uvs - mesh->nr_light_uvs;
t->blend_uv_index[2] = buffer_read_int32(r) - mesh->nr_uvs - mesh->nr_light_uvs;
}
t->color_index[0] = buffer_read_int32(r);
t->color_index[1] = buffer_read_int32(r);
@@ -160,6 +195,11 @@ static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle
t->alpha_index[1] = buffer_read_int32(r);
t->alpha_index[2] = buffer_read_int32(r);
}
if (mesh->blend_weights) {
t->blend_weight_index[0] = buffer_read_int32(r);
t->blend_weight_index[1] = buffer_read_int32(r);
t->blend_weight_index[2] = buffer_read_int32(r);
}
read_direction(r, t->normals[0]);
read_direction(r, t->normals[1]);
@@ -227,6 +267,17 @@ static struct pol_mesh *parse_mesh(struct buffer *r, const struct pol *pol)
}
}
if (pol->version >= 4) {
mesh->nr_blend_uvs = buffer_read_int32(r);
if (mesh->nr_blend_uvs > 0) {
mesh->blend_uvs = xcalloc(mesh->nr_blend_uvs, sizeof(vec2));
for (uint32_t i = 0; i < mesh->nr_blend_uvs; i++) {
mesh->blend_uvs[i][0] = buffer_read_float(r);
mesh->blend_uvs[i][1] = buffer_read_float(r);
}
}
}
mesh->nr_colors = buffer_read_int32(r);
if (mesh->nr_colors > 0) {
mesh->colors = xcalloc(mesh->nr_colors, sizeof(vec3));
@@ -254,6 +305,16 @@ static struct pol_mesh *parse_mesh(struct buffer *r, const struct pol *pol)
}
}
if (pol->version >= 4) {
mesh->nr_blend_weights = buffer_read_int32(r);
if (mesh->nr_blend_weights > 0) {
mesh->blend_weights = xcalloc(mesh->nr_blend_weights, sizeof(float));
for (uint32_t i = 0; i < mesh->nr_blend_weights; i++) {
mesh->blend_weights[i] = buffer_read_u8(r) / 255.f;
}
}
}
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++) {
@@ -280,8 +341,10 @@ static void free_mesh(struct pol_mesh *mesh)
free(mesh->vertices);
free(mesh->uvs);
free(mesh->light_uvs);
free(mesh->blend_uvs);
free(mesh->colors);
free(mesh->alphas);
free(mesh->blend_weights);
free(mesh->triangles);
free(mesh);
}
@@ -310,7 +373,7 @@ struct pol *pol_parse(uint8_t *data, size_t size)
struct pol *pol = xcalloc(1, sizeof(struct pol));
pol->version = buffer_read_int32(&r);
if (pol->version != 1 && pol->version != 2) {
if (pol->version != 1 && pol->version != 2 && pol->version != 4) {
WARNING("unknown POL version: %d", pol->version);
free(pol);
return NULL;
@@ -318,7 +381,7 @@ struct pol *pol_parse(uint8_t *data, size_t size)
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]);
parse_material_group(&r, pol->version, &pol->materials[i], 0);
}
pol->nr_meshes = buffer_read_int32(&r);
+14
View File
@@ -39,6 +39,7 @@ enum {
LIGHT_TEXTURE_UNIT,
NORMAL_TEXTURE_UNIT,
SHADOW_TEXTURE_UNIT,
BLEND_TEXTURE_UNIT,
};
enum {
@@ -89,6 +90,8 @@ static GLuint load_shader(const char *vertex_shader_path, const char *fragment_s
glBindAttribLocation(program, VATTR_LIGHT_UV, "vertex_light_uv");
glBindAttribLocation(program, VATTR_COLOR, "vertex_color");
glBindAttribLocation(program, VATTR_TANGENT, "vertex_tangent");
glBindAttribLocation(program, VATTR_BLEND_WEIGHT, "vertex_blend_weight");
glBindAttribLocation(program, VATTR_BLEND_UV, "vertex_blend_uv");
glLinkProgram(program);
@@ -258,6 +261,8 @@ struct RE_renderer *RE_renderer_new(void)
r->alpha_mode = glGetUniformLocation(r->program, "alpha_mode");
r->alpha_texture = glGetUniformLocation(r->program, "alpha_texture");
r->uv_scroll = glGetUniformLocation(r->program, "uv_scroll");
r->blend_tex = glGetUniformLocation(r->program, "blend_tex");
r->use_blend_texture = glGetUniformLocation(r->program, "use_blend_texture");
glGenRenderbuffers(1, &r->depth_buffer);
@@ -447,6 +452,15 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d
glUniform1i(r->alpha_mode, mesh->is_transparent ? ALPHA_BLEND : ALPHA_TEST);
}
if (material->blend_texture) {
glUniform1i(r->use_blend_texture, GL_TRUE);
glActiveTexture(GL_TEXTURE0 + BLEND_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->blend_texture);
glUniform1i(r->blend_tex, BLEND_TEXTURE_UNIT);
} else {
glUniform1i(r->use_blend_texture, GL_FALSE);
}
vec2 uv_scroll;
glm_vec2_scale(mesh->uv_scroll, r->last_frame_timestamp / 1000.f, uv_scroll);
glUniform2fv(r->uv_scroll, 1, uv_scroll);