Files
Nuake-custom/Nuake/Vendors/libmap/c/geo_generator.c
2025-01-30 22:41:17 -05:00

591 lines
19 KiB
C

#include "../h/geo_generator.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "../h/face.h"
#include "../h/brush.h"
#include "../h/entity.h"
#include "../h/libmap_math.h"
const vec3 UP_VECTOR = {0.0, 0.0, 1.0};
const vec3 RIGHT_VECTOR = {0.0, 1.0, 0.0};
const vec3 FORWARD_VECTOR = {1.0, 0.0, 0.0};
bool smooth_normals = false;
int wind_entity_idx = 0;
int wind_brush_idx = 0;
int wind_face_idx = 0;
vec3 wind_face_center;
vec3 wind_face_basis;
vec3 wind_face_normal;
int sort_vertices_by_winding(const void *lhs_in, const void *rhs_in)
{
const vec3 *lhs = (const vec3 *)lhs_in;
const vec3 *rhs = (const vec3 *)rhs_in;
face *face_inst = &entities[wind_entity_idx].brushes[wind_brush_idx].faces[wind_face_idx];
face_geometry *face_geo_inst = &entity_geo[wind_entity_idx].brushes[wind_brush_idx].faces[wind_face_idx];
vec3 u = vec3_normalize(wind_face_basis);
vec3 v = vec3_normalize(vec3_cross(u, wind_face_normal));
vec3 local_lhs = vec3_sub(*lhs, wind_face_center);
double lhs_pu = vec3_dot(local_lhs, u);
double lhs_pv = vec3_dot(local_lhs, v);
vec3 local_rhs = vec3_sub(*rhs, wind_face_center);
double rhs_pu = vec3_dot(local_rhs, u);
double rhs_pv = vec3_dot(local_rhs, v);
double lhs_angle = atan2(lhs_pv, lhs_pu);
double rhs_angle = atan2(rhs_pv, rhs_pu);
if (lhs_angle < rhs_angle)
{
return -1;
}
else if (lhs_angle > rhs_angle)
{
return 1;
}
return 0;
}
void geo_generator_run()
{
entity_geo = malloc(entity_count * sizeof(entity_geometry));
for (int e = 0; e < entity_count; ++e)
{
entity *ent_inst = &entities[e];
entity_geometry *entity_geo_inst = &entity_geo[e];
*entity_geo_inst = (entity_geometry){0};
entity_geo_inst->brushes = malloc(ent_inst->brush_count * sizeof(brush_geometry));
for (int b = 0; b < ent_inst->brush_count; ++b)
{
brush *brush_inst = &ent_inst->brushes[b];
brush_geometry *brush_geo_inst = &entity_geo_inst->brushes[b];
*brush_geo_inst = (brush_geometry){0};
brush_geo_inst->faces = malloc(brush_inst->face_count * sizeof(face_geometry));
for (int f = 0; f < brush_inst->face_count; ++f)
{
face_geometry *face_geo_inst = &brush_geo_inst->faces[f];
*face_geo_inst = (face_geometry){0};
}
}
}
for (int e = 0; e < entity_count; ++e)
{
entity *ent_inst = &entities[e];
ent_inst->center = (vec3){0.0, 0.0, 0.0};
for (int b = 0; b < ent_inst->brush_count; ++b)
{
brush *brush_inst = &ent_inst->brushes[b];
brush_inst->center = (vec3){0.0, 0.0, 0.0};
int vert_count = 0;
generate_brush_vertices(e, b);
brush_geometry *brush_geo_inst = &entity_geo[e].brushes[b];
for (int f = 0; f < brush_inst->face_count; f++)
{
face_geometry *face_geo_inst = &brush_geo_inst->faces[f];
for (int v = 0; v < face_geo_inst->vertex_count; ++v)
{
brush_inst->center = vec3_add(brush_inst->center, face_geo_inst->vertices[v].vertex);
vert_count++;
}
}
if (vert_count > 0)
{
brush_inst->center = vec3_div_double(brush_inst->center, vert_count);
}
ent_inst->center = vec3_add(ent_inst->center, brush_inst->center);
}
if (ent_inst->brush_count > 0)
{
ent_inst->center = vec3_div_double(ent_inst->center, ent_inst->brush_count);
}
}
// Wind face vertices
for (int e = 0; e < entity_count; ++e)
{
entity *entity_inst = &entities[e];
entity_geometry *entity_geo_inst = &entity_geo[e];
for (int b = 0; b < entity_inst->brush_count; ++b)
{
brush *brush_inst = &entity_inst->brushes[b];
brush_geometry *brush_geo_inst = &entity_geo_inst->brushes[b];
for (int f = 0; f < brush_inst->face_count; ++f)
{
face *face_inst = &brush_inst->faces[f];
face_geometry *face_geo_inst = &brush_geo_inst->faces[f];
if (face_geo_inst->vertex_count < 3)
{
continue;
}
wind_entity_idx = e;
wind_brush_idx = b;
wind_face_idx = f;
wind_face_basis = vec3_sub(face_geo_inst->vertices[1].vertex, face_geo_inst->vertices[0].vertex);
wind_face_center = (vec3){0};
wind_face_normal = face_inst->plane_normal;
for (int v = 0; v < face_geo_inst->vertex_count; ++v)
{
wind_face_center = vec3_add(wind_face_center, face_geo_inst->vertices[v].vertex);
}
wind_face_center = vec3_div_double(wind_face_center, face_geo_inst->vertex_count);
qsort(face_geo_inst->vertices, face_geo_inst->vertex_count, sizeof(face_vertex), sort_vertices_by_winding);
wind_entity_idx = 0;
}
}
}
// Index face vertices
for (int e = 0; e < entity_count; ++e)
{
entity *entity_inst = &entities[e];
entity_geometry *entity_geo_inst = &entity_geo[e];
for (int b = 0; b < entity_inst->brush_count; ++b)
{
brush *brush_inst = &entity_inst->brushes[b];
brush_geometry *brush_geo_inst = &entity_geo_inst->brushes[b];
for (int f = 0; f < brush_inst->face_count; ++f)
{
face_geometry *face_geo_inst = &brush_geo_inst->faces[f];
if (face_geo_inst->vertex_count < 3)
{
continue;
}
face_geo_inst->indices = malloc((face_geo_inst->vertex_count - 2) * 3 * sizeof(int));
for (int i = 0; i < face_geo_inst->vertex_count - 2; i++)
{
face_geo_inst->indices[face_geo_inst->index_count++] = 0;
face_geo_inst->indices[face_geo_inst->index_count++] = i + 1;
face_geo_inst->indices[face_geo_inst->index_count++] = i + 2;
}
}
}
}
}
void generate_brush_vertices(int entity_idx, int brush_idx)
{
entity *ent_inst = &entities[entity_idx];
brush *brush_inst = &ent_inst->brushes[brush_idx];
for (int f0 = 0; f0 < brush_inst->face_count; ++f0)
{
for (int f1 = 0; f1 < brush_inst->face_count; ++f1)
{
for (int f2 = 0; f2 < brush_inst->face_count; ++f2)
{
vec3 vertex = (vec3){0};
if (intersect_faces(brush_inst->faces[f0], brush_inst->faces[f1], brush_inst->faces[f2], &vertex))
{
if (vertex_in_hull(brush_inst->faces, brush_inst->face_count, vertex))
{
face *face_inst = &entities[entity_idx].brushes[brush_idx].faces[f0];
face_geometry *face_geo_inst = &entity_geo[entity_idx].brushes[brush_idx].faces[f0];
vec3 normal;
const char* phong_property = map_data_get_entity_property(entity_idx, "_phong");
bool phong = phong_property != NULL && strcmp(phong_property, "1") == 0;
if (phong)
{
const char* phong_angle_property = map_data_get_entity_property(entity_idx, "_phong_angle");
if (phong_angle_property == NULL)
{
phong_angle_property = "89";
}
if (phong_angle_property != NULL)
{
double threshold = cos((atof(phong_angle_property) + 0.01) * 0.0174533);
normal = brush_inst->faces[f0].plane_normal;
if (vec3_dot(brush_inst->faces[f0].plane_normal, brush_inst->faces[f1].plane_normal) > threshold)
{
normal = vec3_add(normal, brush_inst->faces[f1].plane_normal);
}
if (vec3_dot(brush_inst->faces[f0].plane_normal, brush_inst->faces[f2].plane_normal) > threshold)
{
normal = vec3_add(normal, brush_inst->faces[f2].plane_normal);
}
normal = vec3_normalize(normal);
}
else
{
normal = vec3_normalize(
vec3_add(
brush_inst->faces[f0].plane_normal,
vec3_add(
brush_inst->faces[f1].plane_normal,
brush_inst->faces[f2].plane_normal)));
}
}
else
{
normal = face_inst->plane_normal;
}
texture_data *texture = map_data_get_texture(face_inst->texture_idx);
vertex_uv uv;
if (face_inst->is_valve_uv)
{
uv = get_valve_uv(vertex, face_inst, texture->width, texture->height);
}
else
{
uv = get_standard_uv(vertex, face_inst, texture->width, texture->height);
}
vertex_tangent tangent;
if (face_inst->is_valve_uv)
{
tangent = get_valve_tangent(face_inst);
}
else
{
tangent = get_standard_tangent(face_inst);
}
bool unique_vertex = true;
int duplicate_index = -1;
for (int v = 0; v < face_geo_inst->vertex_count; ++v)
{
vec3 comp_vertex = face_geo_inst->vertices[v].vertex;
if (vec3_length(vec3_sub(vertex, comp_vertex)) < CMP_EPSILON)
{
unique_vertex = false;
duplicate_index = v;
break;
}
}
if (unique_vertex)
{
face_geo_inst->vertex_count++;
face_geo_inst->vertices = realloc(face_geo_inst->vertices, face_geo_inst->vertex_count * sizeof(face_vertex));
face_geo_inst->vertices[face_geo_inst->vertex_count - 1] = (face_vertex){vertex, normal, uv, tangent};
}
else if(phong)
{
face_geo_inst->vertices[duplicate_index].normal = vec3_add(face_geo_inst->vertices[duplicate_index].normal, normal);
}
}
}
}
}
}
for (int f = 0; f < brush_inst->face_count; ++f)
{
face_geometry *face_geo_inst = &entity_geo[entity_idx].brushes[brush_idx].faces[f];
for (int v = 0; v < face_geo_inst->vertex_count; ++v)
{
face_geo_inst->vertices[v].normal = vec3_normalize(face_geo_inst->vertices[v].normal);
}
}
}
bool intersect_faces(face f0, face f1, face f2, vec3 *o_vertex)
{
vec3 normal0 = f0.plane_normal;
vec3 normal1 = f1.plane_normal;
vec3 normal2 = f2.plane_normal;
double denom = vec3_dot(vec3_cross(normal0, normal1), normal2);
if (denom < CMP_EPSILON)
{
return false;
}
if (o_vertex)
{
*o_vertex = vec3_div_double(
vec3_add(
vec3_add(
vec3_mul_double(
vec3_cross(normal1, normal2),
f0.plane_dist),
vec3_mul_double(
vec3_cross(normal2, normal0),
f1.plane_dist)),
vec3_mul_double(
vec3_cross(normal0, normal1),
f2.plane_dist)),
denom);
}
return true;
}
bool vertex_in_hull(face *faces, int face_count, vec3 vertex)
{
for (int f = 0; f < face_count; f++)
{
face face_inst = faces[f];
double proj = vec3_dot(face_inst.plane_normal, vertex);
if (proj > face_inst.plane_dist && fabs(face_inst.plane_dist - proj) > CMP_EPSILON)
{
return false;
}
}
return true;
}
vertex_uv get_standard_uv(vec3 vertex, const face *face, int texture_width, int texture_height)
{
vertex_uv uv_out;
double du = fabs(vec3_dot(face->plane_normal, UP_VECTOR));
double dr = fabs(vec3_dot(face->plane_normal, RIGHT_VECTOR));
double df = fabs(vec3_dot(face->plane_normal, FORWARD_VECTOR));
if (du >= dr && du >= df)
{
uv_out = (vertex_uv){vertex.x, -vertex.y};
}
else if (dr >= du && dr >= df)
{
uv_out = (vertex_uv){vertex.x, -vertex.z};
}
else if (df >= du && df >= dr)
{
uv_out = (vertex_uv){vertex.y, -vertex.z};
}
vertex_uv rotated;
double angle = DEG_TO_RAD(face->uv_extra.rot);
rotated.u = uv_out.u * cos(angle) - uv_out.v * sin(angle);
rotated.v = uv_out.u * sin(angle) + uv_out.v * cos(angle);
uv_out = rotated;
uv_out.u /= texture_width;
uv_out.v /= texture_height;
uv_out.u /= face->uv_extra.scale_x;
uv_out.v /= face->uv_extra.scale_y;
uv_out.u += face->uv_standard.u / texture_width;
uv_out.v += face->uv_standard.v / texture_height;
return uv_out;
}
vertex_uv get_valve_uv(vec3 vertex, const face *face, int texture_width, int texture_height)
{
vertex_uv uv_out;
vec3 u_axis = face->uv_valve.u.axis;
double u_shift = face->uv_valve.u.offset;
vec3 v_axis = face->uv_valve.v.axis;
double v_shift = face->uv_valve.v.offset;
uv_out.u = vec3_dot(u_axis, vertex);
uv_out.v = vec3_dot(v_axis, vertex);
uv_out.u /= texture_width;
uv_out.v /= texture_height;
uv_out.u /= face->uv_extra.scale_x;
uv_out.v /= face->uv_extra.scale_y;
uv_out.u += u_shift / texture_width;
uv_out.v += v_shift / texture_height;
return uv_out;
}
double sign(double v)
{
if (v > 0)
{
return 1.0;
}
else if (v < 0)
{
return -1.0;
}
return 0.0;
}
vertex_tangent get_standard_tangent(const face *face)
{
vertex_tangent tangent_out;
double du = vec3_dot(face->plane_normal, UP_VECTOR);
double dr = vec3_dot(face->plane_normal, RIGHT_VECTOR);
double df = vec3_dot(face->plane_normal, FORWARD_VECTOR);
double dua = fabs(du);
double dra = fabs(dr);
double dfa = fabs(df);
vec3 u_axis;
double v_sign = 0;
if (dua >= dra && dua >= dfa)
{
u_axis = FORWARD_VECTOR;
v_sign = sign(du);
}
else if (dra >= dua && dra >= dfa)
{
u_axis = FORWARD_VECTOR;
v_sign = -sign(dr);
}
else if (dfa >= dua && dfa >= dra)
{
u_axis = RIGHT_VECTOR;
v_sign = sign(df);
}
v_sign *= sign(face->uv_extra.scale_y);
u_axis = vec3_rotate(u_axis, face->plane_normal, -face->uv_extra.rot * v_sign);
tangent_out.x = u_axis.x;
tangent_out.y = u_axis.y;
tangent_out.z = u_axis.z;
tangent_out.w = v_sign;
return tangent_out;
}
vertex_tangent get_valve_tangent(const face *face)
{
vertex_tangent tangent_out;
vec3 u_axis = vec3_normalize(face->uv_valve.u.axis);
vec3 v_axis = vec3_normalize(face->uv_valve.v.axis);
double v_sign = -sign(vec3_dot(vec3_cross(face->plane_normal, u_axis), v_axis));
tangent_out.x = u_axis.x;
tangent_out.y = u_axis.y;
tangent_out.z = u_axis.z;
tangent_out.w = v_sign;
return tangent_out;
}
void geo_generator_print_entities()
{
for (int e = 0; e < entity_count; ++e)
{
entity *entity_inst = &entities[e];
entity_geometry *entity_geo_inst = &entity_geo[e];
printf("Entity %d\n", e);
for (int b = 0; b < entity_inst->brush_count; ++b)
{
brush *brush_inst = &entity_inst->brushes[b];
brush_geometry *brush_geo_inst = &entity_geo_inst->brushes[b];
printf("Brush %d\n", b);
for (int f = 0; f < brush_inst->face_count; ++f)
{
face_geometry *face_geo_inst = &brush_geo_inst->faces[f];
printf("Face %d\n", f);
for (int i = 0; i < face_geo_inst->vertex_count; ++i)
{
face_vertex vertex = face_geo_inst->vertices[i];
printf("vertex: (%f %f %f), normal: (%f %f %f)\n",
vertex.vertex.x, vertex.vertex.y, vertex.vertex.z,
vertex.normal.x, vertex.normal.y, vertex.normal.z);
}
puts("Indices:");
for (int i = 0; i < (face_geo_inst->vertex_count - 2) * 3; ++i)
{
printf("index: %d\n", face_geo_inst->indices[i]);
}
}
putchar('\n');
putchar('\n');
}
}
}
const entity_geometry *geo_generator_get_entities()
{
return entity_geo;
}
int geo_generator_get_brush_vertex_count(int entity_idx, int brush_idx)
{
int vertex_count = 0;
brush *brush_inst = &entities[entity_idx].brushes[brush_idx];
brush_geometry *brush_geo_inst = &entity_geo[entity_idx].brushes[brush_idx];
for (int i = 0; i < brush_inst->face_count; ++i)
{
face_geometry *face_geo_inst = &brush_geo_inst->faces[i];
vertex_count = vertex_count + face_geo_inst->vertex_count;
}
return vertex_count;
}
int geo_generator_get_brush_index_count(int entity_idx, int brush_idx)
{
int index_count = 0;
brush *brush_inst = &entities[entity_idx].brushes[brush_idx];
brush_geometry *brush_geo_inst = &entity_geo[entity_idx].brushes[brush_idx];
for (int i = 0; i < brush_inst->face_count; ++i)
{
face_geometry *face_geo_inst = &brush_geo_inst->faces[i];
index_count = index_count + face_geo_inst->index_count;
}
return index_count;
}