591 lines
19 KiB
C
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;
|
|
}
|