20kdm2: add bezier patch rendering

This commit is contained in:
Zack Buhman 2025-04-28 00:52:59 -05:00
parent bbb3b8f8a3
commit f7abfa14cf
8 changed files with 491 additions and 90 deletions

View File

@ -71,6 +71,7 @@
#include "bsp/20kdm2/textures/sfx/flame8.data.h"
#include "q3bsp/q3bsp.h"
#include "q3bsp/q3bsp_patch.hpp"
#include "bsp/20kdm2/maps/20kdm2.bsp.h"
#include "bsp/20kdm2/texture.h"
@ -252,7 +253,7 @@ void global_polygon_type_4(ta_parameter_writer& writer,
;
const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::cull_if_negative
| isp_tsp_instruction_word::culling_mode::no_culling // cull_if_negative
;
const uint32_t tsp_instruction_word = tsp_instruction_word::fog_control::no_fog
@ -601,7 +602,7 @@ float light_intensity(vec3 light_vec, vec3 n)
static vec3 light_vec = {20, -20, -20};
static inline void transfer_face(ta_parameter_writer& writer, q3bsp_face_t * face, int * last_texture, int * last_lm_index)
static inline void transfer_face_meshverts(ta_parameter_writer& writer, q3bsp_face_t * face)
{
uint8_t * buf = reinterpret_cast<uint8_t *>(bsp_start);
q3bsp_header_t * header = reinterpret_cast<q3bsp_header_t *>(buf);
@ -617,26 +618,6 @@ static inline void transfer_face(ta_parameter_writer& writer, q3bsp_face_t * fac
int triangles = face->n_meshverts / 3;
int textures_length = (sizeof (textures)) / (sizeof (textures[0]));
bool has_texture = 1 &&
(face->texture >= 0) &&
(face->texture < textures_length) &&
(textures[face->texture].size != 0);
if (!has_texture)
return;
if (face->texture != *last_texture || face->lm_index != *last_lm_index) {
*last_texture = face->texture;
*last_lm_index = face->lm_index;
if (has_texture) {
global_texture_lightmap(writer, face->texture, face->lm_index);
} else {
//global_polygon_type_1(writer, 0, 0, 0);
}
}
for (int j = 0; j < triangles; j++) {
int aix = mv[j * 3 + 0].offset + face->vertex;
@ -657,60 +638,133 @@ static inline void transfer_face(ta_parameter_writer& writer, q3bsp_face_t * fac
float li0 = light_intensity(light_vec, n);
const float li1 = 2.0;
if (has_texture) {
float v_mul = textures[face->texture].v_mul;
vec2 at = {vert[aix].texcoord[0], vert[aix].texcoord[1] * v_mul};
vec2 bt = {vert[bix].texcoord[0], vert[bix].texcoord[1] * v_mul};
vec2 ct = {vert[cix].texcoord[0], vert[cix].texcoord[1] * v_mul};
float v_mul = textures[face->texture].v_mul;
vec2 at = {vert[aix].texture[0], vert[aix].texture[1] * v_mul};
vec2 bt = {vert[bix].texture[0], vert[bix].texture[1] * v_mul};
vec2 ct = {vert[cix].texture[0], vert[cix].texture[1] * v_mul};
vec2 alm = {vert[aix].lightmapcoord[0], vert[aix].lightmapcoord[1]};
vec2 blm = {vert[bix].lightmapcoord[0], vert[bix].lightmapcoord[1]};
vec2 clm = {vert[cix].lightmapcoord[0], vert[cix].lightmapcoord[1]};
vec2 alm = {vert[aix].lightmap[0], vert[aix].lightmap[1]};
vec2 blm = {vert[bix].lightmap[0], vert[bix].lightmap[1]};
vec2 clm = {vert[cix].lightmap[0], vert[cix].lightmap[1]};
if (ap.z < 0 || bp.z < 0 || cp.z < 0) {
render_clip_tri_type_13(writer,
ap,
bp,
cp,
at,
bt,
ct,
alm,
blm,
clm,
li0,
li1);
} else {
vec3 aps = screen_transform(ap);
vec3 bps = screen_transform(bp);
vec3 cps = screen_transform(cp);
render_tri_type_13(writer,
aps,
bps,
cps,
at,
bt,
ct,
alm,
blm,
clm,
li0,
li1);
}
if (ap.z < 0 || bp.z < 0 || cp.z < 0) {
render_clip_tri_type_13(writer,
ap,
bp,
cp,
at,
bt,
ct,
alm,
blm,
clm,
li0,
li1);
} else {
/*
render_tri_type_2(writer,
screen_transform(ap),
screen_transform(bp),
screen_transform(cp),
li);
*/
vec3 aps = screen_transform(ap);
vec3 bps = screen_transform(bp);
vec3 cps = screen_transform(cp);
render_tri_type_13(writer,
aps,
bps,
cps,
at,
bt,
ct,
alm,
blm,
clm,
li0,
li1);
}
}
}
void transfer_faces(ta_parameter_writer& writer)
static inline void transfer_face_patch_surfaces(ta_parameter_writer& writer, const mat4x4& trans, q3bsp_face_t * face, int face_ix)
{
using namespace q3bsp_patch;
patch * patch = NULL;
for (int i = 0; i < patch_count; i++) {
if (patches[i].face_ix == face_ix) {
patch = &patches[i];
break;
}
}
assert(patch != nullptr);
const int width = face->size[0];
const int height = face->size[1];
const int h_surfaces = (width - 1) / 2;
const int v_surfaces = (height - 1) / 2;
const int surface_count = h_surfaces * v_surfaces;
assert(surface_count > 0);
const vertex_plm * vertices = &patch_vertices[patch->vertex_ix];
const bezier::triangle * triangles = &patch_triangles[patch->triangle_ix];
const int triangle_count = surface_count * triangles_per_surface;
for (int i = 0; i < triangle_count; i++) {
vis_tri_count += 1;
const bezier::triangle * triangle = &triangles[i];
assert(triangle->a >= 0 && triangle->b >= 0 && triangle->c >= 0);
if (triangle->a == triangle->b && triangle->b == triangle->c) {
printf("face_ix %d %d\n", face_ix, i);
printf(" %d %d %d\n", triangle->a, triangle->b, triangle->c);
assert(false);
}
const vertex_plm * av = &vertices[triangle->a];
const vertex_plm * bv = &vertices[triangle->b];
const vertex_plm * cv = &vertices[triangle->c];
vec3 ap = trans * av->l;
vec3 bp = trans * bv->l;
vec3 cp = trans * cv->l;
if (ap.z < 0 || bp.z < 0 || cp.z < 0) {
continue;
//printf("cont %f %f %f\n", ap.x, ap.y, ap.z);
}
/*
printf("%f %f %f\n", ap.x, ap.y, ap.z);
printf("%f %f %f\n", bp.x, bp.y, bp.z);
printf("%f %f %f\n", cp.x, cp.y, cp.z);
*/
vec3 aps = screen_transform(ap);
vec3 bps = screen_transform(bp);
vec3 cps = screen_transform(cp);
const vec2& at = av->m;
const vec2& bt = bv->m;
const vec2& ct = cv->m;
const vec2& alm = av->n;
const vec2& blm = bv->n;
const vec2& clm = cv->n;
float li0 = 1.0;
float li1 = 2.0;
render_tri_type_13(writer,
aps,
bps,
cps,
at,
bt,
ct,
alm,
blm,
clm,
li0,
li1);
}
}
void transfer_faces(ta_parameter_writer& writer, const mat4x4& trans)
{
uint8_t * buf = reinterpret_cast<uint8_t *>(bsp_start);
q3bsp_header_t * header = reinterpret_cast<q3bsp_header_t *>(buf);
@ -723,8 +777,30 @@ void transfer_faces(ta_parameter_writer& writer)
int last_texture = -1;
int last_lm_index = -1;
const int textures_length = (sizeof (textures)) / (sizeof (textures[0]));
for (int i = 0; i < face_count; i++) {
transfer_face(writer, &faces[i], &last_texture, &last_lm_index);
q3bsp_face_t * face = &faces[i];
bool has_texture =
(face->texture >= 0) &&
(face->texture < textures_length) &&
(textures[face->texture].size != 0);
if (!has_texture)
continue;
if (face->texture != last_texture || face->lm_index != last_lm_index) {
last_texture = face->texture;
last_lm_index = face->lm_index;
global_texture_lightmap(writer, face->texture, face->lm_index);
}
if (face->type == FACE_TYPE_POLYGON || face->type == FACE_TYPE_MESH)
transfer_face_meshverts(writer, face);
if (face->type == FACE_TYPE_PATCH)
transfer_face_patch_surfaces(writer, trans, face, i);
}
}
@ -803,9 +879,9 @@ static inline void transfer_face_billboard(ta_parameter_writer& writer, q3bsp_fa
continue;
}
vec2 at = {vert[aix].texcoord[0], vert[aix].texcoord[1]};
vec2 bt = {vert[bix].texcoord[0], vert[bix].texcoord[1]};
vec2 ct = {vert[cix].texcoord[0], vert[cix].texcoord[1]};
vec2 at = {vert[aix].texture[0], vert[aix].texture[1]};
vec2 bt = {vert[bix].texture[0], vert[bix].texture[1]};
vec2 ct = {vert[cix].texture[0], vert[cix].texture[1]};
render_tri_type_7(writer,
screen_transform(ap),
@ -1250,12 +1326,35 @@ void render_leaf_faces(ta_parameter_writer& writer, const mat4x4& trans, q3bsp_l
int last_texture = -1;
int last_lm_index = -1;
const int textures_length = (sizeof (textures)) / (sizeof (textures[0]));
for (int i = 0; i < leaf->n_leaffaces; i++) {
int face_ix = lf[i].face;
if (face_cache[face_ix] != 0)
continue;
face_cache[face_ix] = 1;
transfer_face(writer, &faces[face_ix], &last_texture, &last_lm_index);
q3bsp_face_t * face = &faces[face_ix];
bool has_texture =
(face->texture >= 0) &&
(face->texture < textures_length) &&
(textures[face->texture].size != 0);
if (!has_texture)
continue;
if (face->texture != last_texture || face->lm_index != last_lm_index) {
last_texture = face->texture;
last_lm_index = face->lm_index;
global_texture_lightmap(writer, face->texture, face->lm_index);
}
if (face->type == FACE_TYPE_POLYGON || face->type == FACE_TYPE_MESH)
transfer_face_meshverts(writer, face);
if (face->type == FACE_TYPE_PATCH)
transfer_face_patch_surfaces(writer, trans, face, face_ix);
}
}
@ -1398,7 +1497,7 @@ void transfer_scene(ta_parameter_writer& writer, const mat4x4& screen_trans, con
q3bsp_direntry * fe = &header->direntries[LUMP_FACES];
int face_count = fe->length / (sizeof (struct q3bsp_face));
//transfer_faces(writer);
//transfer_faces(writer, trans);
//transfer_icosphere(writer, trans);
//render_matrix(writer, screen_trans);
@ -1548,7 +1647,8 @@ void transfer_textures()
printf("lightmap base: %d\n", lightmap_base);
int textures_length = (sizeof (textures)) / (sizeof (textures[0]));
const int textures_length = (sizeof (textures)) / (sizeof (textures[0]));
for (int i = 0; i < textures_length; i++) {
uint32_t offset = texture_memory_alloc.texture.start + font_base + lightmap_base + textures[i].offset;
void * dst = reinterpret_cast<void *>(&ta_fifo_texture_memory[offset / 4]);
@ -1805,6 +1905,8 @@ int main()
| isp_feed_cfg::pre_sort_mode
;
holly.FPU_SHAD_SCALE = fpu_shad_scale::simple_shadow_enable::parameter_selection_volume_mode;
system.IML6NRM = istnrm::end_of_render_tsp
| istnrm::v_blank_in
| istnrm::end_of_transferring_opaque_modifier_volume_list;
@ -1838,9 +1940,10 @@ int main()
0.0, 0.0, 0.0, 1.0,
};
do_get_condition();
q3bsp_patch::triangulate_patches(bsp_start);
printf("patch_count %d\n", q3bsp_patch::patch_count);
holly.FPU_SHAD_SCALE = fpu_shad_scale::simple_shadow_enable::parameter_selection_volume_mode;
do_get_condition();
while (1) {
maple::dma_wait_complete();

View File

@ -13,6 +13,7 @@ BSP_20KDM2_OBJ = \
maple/maple.o \
font/font_bitmap.o \
font/verite_8x16/verite_8x16.data.o \
q3bsp/q3bsp_patch.o \
bsp/20kdm2/maps/20kdm2.bsp.o \
bsp/20kdm2/textures/e7/e7walldesign01b.data.o \
bsp/20kdm2/textures/e7/e7steptop2.data.o \

104
math/bezier.hpp Normal file
View File

@ -0,0 +1,104 @@
#include <tuple>
#include "math/vec.hpp"
namespace bezier {
template <typename T, int L, int M, int N>
struct vec_lmn {
vec<L, T> l;
vec<M, T> m;
vec<N, T> n;
};
struct triangle {
int a;
int b;
int c;
};
template <typename T, int L, int M, int N>
constexpr inline
vec_lmn<T, L, M, N>
interpolate_quadratic(const T d,
const vec<L, T>& l1, const vec<M, T>& m1, const vec<N, T>& n1,
const vec<L, T>& l2, const vec<M, T>& m2, const vec<N, T>& n2,
const vec<L, T>& l3, const vec<M, T>& m3, const vec<N, T>& n3)
{
T invd = 1.0 - d;
T d1 = invd * invd;
T d2 = 2.0 * d * invd;
T d3 = d * d;
vec<L, T> l;
for (int i = 0; i < L; i++) {
l[i] = l1[i] * d1 + l2[i] * d2 + l3[i] * d3;
};
vec<M, T> m;
for (int i = 0; i < M; i++) {
m[i] = m1[i] * d1 + m2[i] * d2 + m3[i] * d3;
}
vec<N, T> n;
for (int i = 0; i < N; i++) {
n[i] = n1[i] * d1 + n2[i] * d2 + n3[i] * d3;
};
return {l, m, n};
}
template <typename T, int L, int M, int N>
constexpr inline
vec_lmn<T, L, M, N>
interpolate_quadratic(const T d,
const vec_lmn<T, L, M, N>& va,
const vec_lmn<T, L, M, N>& vb,
const vec_lmn<T, L, M, N>& vc)
{
return interpolate_quadratic<T>(d,
va.l, va.m, va.n,
vb.l, vb.m, vb.n,
vc.l, vc.m, vc.n);
}
template <typename T, int L, int M, int N>
constexpr inline
void
tessellate(const int level,
const vec_lmn<T, L, M, N> * control, // [9]
vec_lmn<T, L, M, N> * vertices, // [2 * level * level]
triangle * triangles,
int vertex_base = 0)
{
vec_lmn<T, L, M, N> column[3][level + 1];
T inv_level = 1.0 / level;
for (int i = 0; i <= level; i++) {
T d = inv_level * i;
column[0][i] = interpolate_quadratic(d, control[0], control[3], control[6]);
column[1][i] = interpolate_quadratic(d, control[1], control[4], control[7]);
column[2][i] = interpolate_quadratic(d, control[2], control[5], control[8]);
}
for (int i = 0; i <= level; i++) {
for (int j = 0; j <= level; j++) {
T d = inv_level * j;
*vertices++ = interpolate_quadratic(d, column[0][i], column[1][i], column[2][i]);
}
}
for (int i = 0; i < level; i++) {
for (int j = 0; j < level; j++) {
int ix = vertex_base + j * (level + 1) + i;
*triangles++ = {ix + 0,
ix + (level + 1) + 0,
ix + (level + 1) + 1};
*triangles++ = {ix + 0,
ix + (level + 1) + 1,
ix + 1};
}
}
}
}

View File

@ -1,5 +1,3 @@
#include <tuple>
#include "vec.hpp"
namespace geometry {

View File

@ -105,15 +105,32 @@ void print_faces(uint8_t * buf, struct q3bsp_header * header)
q3bsp_direntry * fe = &header->direntries[LUMP_FACES];
q3bsp_face_t * faces = reinterpret_cast<q3bsp_face_t *>(&buf[fe->offset]);
q3bsp_direntry * ve = &header->direntries[LUMP_VERTEXES];
q3bsp_vertex_t * vertexes = reinterpret_cast<q3bsp_vertex_t *>(&buf[ve->offset]);
int count = fe->length / (sizeof (struct q3bsp_face));
printf("faces count: %d\n", count);
for (int i = 0; i < count; i++) {
q3bsp_face_t * face = &faces[i];
if (face->texture == 23 || face->texture == 24 || face->type == 4){
printf("face [%d]\n", i);
printf(" type=%d n_vertexes=%d n_meshverts=%d texture=%d lightmap=%d\n", face->type, face->n_vertexes, face->n_meshverts, face->texture, face->lm_index);
//printf("faces count: %d\n", count);
for (int face_ix = 0; face_ix < count; face_ix++) {
q3bsp_face_t * face = &faces[face_ix];
if (face->type != 2)
continue;
//printf("face [%d]\n", face_ix);
//printf(" type=%d n_vertexes=%d n_meshverts=%d texture=%d lightmap=%d size=(%d,%d)\n", face->type, face->n_vertexes, face->n_meshverts, face->texture, face->lm_index, face->size[0], face->size[1]);
//printf("[");
printf("(%d, %d)", face->size[0], face->size[1]);
/*
for (int i = 0 ; i < face->n_vertexes; i++) {
q3bsp_vertex_t * vertex = &vertexes[face->vertex + i];
printf("(%.00f,%.00f,%.00f)", (vertex->position[0]), (vertex->position[1]), (vertex->position[2]));
if (i < face->n_vertexes - 1)
printf(",");
}
*/
//printf("],");
printf("\n");
}
}

View File

@ -1,3 +1,5 @@
#pragma once
#include <stdint.h>
typedef struct q3bsp_direntry {
@ -29,7 +31,7 @@ enum q3bsp_lumps {
LUMP_LIGHTMAPS = 14,
LUMP_LIGHTVOLS = 15,
LUMP_VISDATA = 16,
} q3bsp_lumps;
};
/*
typedef struct q3bsp_entity {
@ -96,8 +98,8 @@ typedef struct q3bsp_brushside {
typedef struct q3bsp_vertex {
float position[3];
float texcoord[2];
float lightmapcoord[2];
float texture[2];
float lightmap[2];
float normal[3];
uint8_t color[4];
} q3bsp_vertex_t;
@ -112,10 +114,17 @@ typedef struct q3bsp_effect {
int unknown;
} q3bsp_effect_t;
enum q3bsp_face_type {
FACE_TYPE_POLYGON = 1,
FACE_TYPE_PATCH = 2,
FACE_TYPE_MESH = 3,
FACE_TYPE_BILLBOARD = 4,
};
typedef struct q3bsp_face {
int texture;
int effect;
int type;
int type; // enum q3bsp_face_type
int vertex;
int n_vertexes;
int meshvert;

138
q3bsp/q3bsp_patch.cpp Normal file
View File

@ -0,0 +1,138 @@
#include "math/vec2.hpp"
#include "math/vec3.hpp"
#include "q3bsp/q3bsp.h"
#include "q3bsp/q3bsp_patch.hpp"
#include "assert.h"
namespace q3bsp_patch {
using vec2 = vec<2, float>;
using vec3 = vec<3, float>;
vertex_plm patch_vertices[max_surface_count * max_vertices_per_surface];
constexpr int max_patch_vertices = (sizeof (patch_vertices)) / (sizeof (vertex_plm));
bezier::triangle patch_triangles[max_surface_count * max_triangles_per_surface];
constexpr int max_patch_triangles = (sizeof (patch_triangles)) / ((sizeof (int)) * 3);
patch patches[max_patch_count];
int patch_count = 0;
static int triangulate_patch(const q3bsp_vertex_t * vertexes,
const int width,
const int height,
vertex_plm * p_vtx,
bezier::triangle * p_tri)
{
const int h_surfaces = (width - 1) / 2;
const int v_surfaces = (height - 1) / 2;
int vertex_base = 0;
for (int j = 0; j < v_surfaces; j++) {
for (int k = 0; k < h_surfaces; k++) {
int ix = j * width * 2 + k * 2;
const q3bsp_vertex_t * a = &vertexes[ix + width * 0 + 0];
const q3bsp_vertex_t * b = &vertexes[ix + width * 0 + 1];
const q3bsp_vertex_t * c = &vertexes[ix + width * 0 + 2];
const q3bsp_vertex_t * d = &vertexes[ix + width * 1 + 0];
const q3bsp_vertex_t * e = &vertexes[ix + width * 1 + 1];
const q3bsp_vertex_t * f = &vertexes[ix + width * 1 + 2];
const q3bsp_vertex_t * g = &vertexes[ix + width * 2 + 0];
const q3bsp_vertex_t * h = &vertexes[ix + width * 2 + 1];
const q3bsp_vertex_t * i = &vertexes[ix + width * 2 + 2];
const vec3 a_p = {a->position[0], a->position[1], a->position[2]};
const vec3 b_p = {b->position[0], b->position[1], b->position[2]};
const vec3 c_p = {c->position[0], c->position[1], c->position[2]};
const vec3 d_p = {d->position[0], d->position[1], d->position[2]};
const vec3 e_p = {e->position[0], e->position[1], e->position[2]};
const vec3 f_p = {f->position[0], f->position[1], f->position[2]};
const vec3 g_p = {g->position[0], g->position[1], g->position[2]};
const vec3 h_p = {h->position[0], h->position[1], h->position[2]};
const vec3 i_p = {i->position[0], i->position[1], i->position[2]};
const vec2 a_t = {a->texture[0], a->texture[1]};
const vec2 b_t = {b->texture[0], b->texture[1]};
const vec2 c_t = {c->texture[0], c->texture[1]};
const vec2 d_t = {d->texture[0], d->texture[1]};
const vec2 e_t = {e->texture[0], e->texture[1]};
const vec2 f_t = {f->texture[0], f->texture[1]};
const vec2 g_t = {g->texture[0], g->texture[1]};
const vec2 h_t = {h->texture[0], h->texture[1]};
const vec2 i_t = {i->texture[0], i->texture[1]};
const vec2 a_l = {a->lightmap[0], a->lightmap[1]};
const vec2 b_l = {b->lightmap[0], b->lightmap[1]};
const vec2 c_l = {c->lightmap[0], c->lightmap[1]};
const vec2 d_l = {d->lightmap[0], d->lightmap[1]};
const vec2 e_l = {e->lightmap[0], e->lightmap[1]};
const vec2 f_l = {f->lightmap[0], f->lightmap[1]};
const vec2 g_l = {g->lightmap[0], g->lightmap[1]};
const vec2 h_l = {h->lightmap[0], h->lightmap[1]};
const vec2 i_l = {i->lightmap[0], i->lightmap[1]};
const vertex_plm control[9] = {
{a_p, a_t, a_l}, {b_p, b_t, b_l}, {c_p, c_t, c_l},
{d_p, d_t, d_l}, {e_p, e_t, e_l}, {f_p, f_t, f_l},
{g_p, g_t, g_l}, {h_p, h_t, h_l}, {i_p, i_t, i_l},
};
bezier::tessellate<float, 3, 2, 2>(level,
control,
p_vtx,
p_tri,
vertex_base);
p_vtx += vertices_per_surface;
p_tri += triangles_per_surface;
vertex_base += vertices_per_surface;
}
}
return h_surfaces * v_surfaces;
}
void triangulate_patches(const void * bsp)
{
const uint8_t * buf = reinterpret_cast<const uint8_t *>(bsp);
const q3bsp_header_t * header = reinterpret_cast<const q3bsp_header_t *>(buf);
const q3bsp_direntry * fe = &header->direntries[LUMP_FACES];
const q3bsp_face_t * faces = reinterpret_cast<const q3bsp_face_t *>(&buf[fe->offset]);
const q3bsp_direntry * ve = &header->direntries[LUMP_VERTEXES];
const q3bsp_vertex_t * vertexes = reinterpret_cast<const q3bsp_vertex_t *>(&buf[ve->offset]);
int face_count = fe->length / (sizeof (struct q3bsp_face));
int vertex_ix = 0;
int triangle_ix = 0;
for (int i = 0; i < face_count; i++) {
const q3bsp_face_t * face = &faces[i];
if (face->type == FACE_TYPE_PATCH) {
assert(vertex_ix < max_patch_vertices);
assert(triangle_ix < max_patch_triangles);
int surface_count = triangulate_patch(&vertexes[face->vertex],
face->size[0],
face->size[1],
&patch_vertices[vertex_ix],
&patch_triangles[triangle_ix]);
assert(patch_count < max_patch_count);
patches[patch_count].face_ix = i;
patches[patch_count].vertex_ix = vertex_ix;
patches[patch_count].triangle_ix = triangle_ix;
patch_count += 1;
vertex_ix += vertices_per_surface * surface_count;
triangle_ix += triangles_per_surface * surface_count;
}
}
assert(vertex_ix <= max_patch_vertices);
assert(triangle_ix <= max_patch_triangles);
}
}

31
q3bsp/q3bsp_patch.hpp Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include "math/bezier.hpp"
namespace q3bsp_patch {
constexpr int max_patch_count = 16; // 12
constexpr int max_surface_count = 32; // 20
constexpr int max_level = 3;
constexpr int level = 3;
constexpr int max_vertices_per_surface = (max_level + 1) * (max_level + 1);
constexpr int max_triangles_per_surface = max_level * max_level * 2;
constexpr int vertices_per_surface = (level + 1) * (level + 1);
constexpr int triangles_per_surface = level * level * 2;
void triangulate_patches(const void * bsp);
extern int patch_count;
using vertex_plm = bezier::vec_lmn<float, 3, 2, 2>;
struct patch {
int face_ix;
int vertex_ix;
int triangle_ix;
};
extern vertex_plm patch_vertices[];
extern bezier::triangle patch_triangles[];
extern patch patches[];
}