mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 18:00:25 +02:00
1070 lines
31 KiB
C
1070 lines
31 KiB
C
/*
|
|
MODELS.C
|
|
|
|
symbols in this file:
|
|
00112DB0 0430:
|
|
_render_model_parts (0000)
|
|
001131E0 0110:
|
|
_model_interpolate_node_orientations (0000)
|
|
001132F0 0090:
|
|
_model_get_node_orientations (0000)
|
|
00113380 0140:
|
|
_model_get_node_matrices (0000)
|
|
001134C0 0110:
|
|
_model_node_matrices_from_orientations (0000)
|
|
001135D0 00a0:
|
|
_model_find_marker (0000)
|
|
00113670 0030:
|
|
_model_get_default_inverse_matrix (0000)
|
|
001136A0 0070:
|
|
_model_find_node (0000)
|
|
00113710 0010:
|
|
_model_geometry_part_build_tangent_matrices (0000)
|
|
00113720 0860:
|
|
_render_model (0000)
|
|
00113F80 01d0:
|
|
_model_get_marker_by_name (0000)
|
|
00114150 0070:
|
|
_model_build_tangent_matrices (0000)
|
|
0027F98C 000d:
|
|
??_C@_0N@PBHIAIOK@render_model?$AA@ (0000)
|
|
0027F9A0 0061:
|
|
??_C@_0GB@CAHPCM@part?9?$DOcentroid_secondary_node_in@ (0000)
|
|
0027FA08 005d:
|
|
??_C@_0FN@MLJHGCND@part?9?$DOcentroid_primary_node_inde@ (0000)
|
|
0027FA68 002c:
|
|
??_C@_0CM@MBIKHGBC@?$CBTEST_FLAG?$CIflags?0?5_render_model_@ (0000)
|
|
0027FA94 001f:
|
|
??_C@_0BP@PJEILNMK@c?3?2halo?2SOURCE?2models?2models?4c?$AA@ (0000)
|
|
0027FAB4 001e:
|
|
??_C@_0BO@FFDGBNA@node?9?$DOparent_node_index?$CB?$DNNONE?$AA@ (0000)
|
|
0027FAD8 0064:
|
|
??_C@_0GE@EAOMEKOC@?$CIactual_detail_level_index?5?$DO?$DN?50?$CJ@ (0000)
|
|
0027FB3C 001e:
|
|
??_C@_0BO@INPHBEBB@actual_detail_level_index?5?$DO?50?$AA@ (0000)
|
|
0027FB60 0060:
|
|
??_C@_0GA@CEBIGMGH@geometry_detail_level_index?$DO?$DN0?5?$CG@ (0000)
|
|
0027FBC0 0009:
|
|
??_C@_08OEDKDIOB@lighting?$AA@ (0000)
|
|
0027FBD0 0073:
|
|
??_C@_0HD@NKPBNIND@object_marker?9?$DOnode_index?$DO?$DN0?5?$CG?$CG?5@ (0000)
|
|
0027FC44 0008:
|
|
??_C@_07LGFKJAB@markers?$AA@ (0000)
|
|
0027FC4C 000e:
|
|
??_C@_0O@BKFGBDDJ@node_matrices?$AA@ (0000)
|
|
0030A390 05f8:
|
|
_render_model_section (0000)
|
|
00456650 0088:
|
|
_default_function_values (0000)
|
|
_default_render_model_change_colors (0000)
|
|
_default_render_model_effect (0000)
|
|
_default_render_model_region_permutation_indices (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#include "cseries/profile.h"
|
|
#include "models.h"
|
|
|
|
#include "model_definitions.h"
|
|
|
|
#include "game/game.h"
|
|
#include "math/real_math.h"
|
|
#include "objects/objects.h"
|
|
#include "rasterizer/rasterizer_geometry.h"
|
|
#include "render/render.h"
|
|
#include "render/render_debug.h"
|
|
#include "scenario/scenario.h"
|
|
#include "scenario/scenario_definitions.h"
|
|
#include "shaders/shader_definitions.h"
|
|
#include "shaders/shaders.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
NUMBER_OF_DETAIL_LEVELS_PER_MODEL = 5,
|
|
CORTANA_MODEL_NODE_LIST_CHECKSUM = 124371095,
|
|
};
|
|
|
|
enum
|
|
{
|
|
_scenario_cortana_hack_bit = 0,
|
|
_scenario_demo_ui_bit,
|
|
NUMBER_OF_SCENARIO_FLAGS
|
|
};
|
|
|
|
enum
|
|
{
|
|
_rasterizer_geometry_no_sort_bit = 0,
|
|
_rasterizer_geometry_no_queue_bit,
|
|
_rasterizer_geometry_no_fog_bit,
|
|
_rasterizer_geometry_no_zbuffer_bit,
|
|
_rasterizer_geometry_sky_bit,
|
|
_rasterizer_geometry_viewspace_bit,
|
|
_rasterizer_geometry_atmospheric_fog_but_no_planar_fog_bit,
|
|
_rasterizer_geometry_first_person_bit,
|
|
_rasterizer_geometry_parts_define_local_nodes_bit,
|
|
NUMBER_OF_RASTERIZER_GEOMETRY_FLAGS
|
|
};
|
|
|
|
enum
|
|
{
|
|
_render_model_immediate_bit = 0,
|
|
_render_model_shadow_bit,
|
|
_render_model_no_planar_fog_bit,
|
|
_render_model_first_person_bit,
|
|
NUMBER_OF_RENDER_MODEL_FLAGS
|
|
};
|
|
|
|
enum
|
|
{
|
|
_render_model_pass_solid = 0,
|
|
_render_model_pass_decal,
|
|
_render_model_pass_transparent,
|
|
NUMBER_OF_RENDER_MODEL_PASSES
|
|
};
|
|
|
|
enum
|
|
{
|
|
_model_geometry_part_stripped_bit = 0,
|
|
_model_geometry_part_local_nodes_bit,
|
|
NUMBER_OF_MODEL_GEOMETRY_PART_FLAGS
|
|
};
|
|
|
|
enum
|
|
{
|
|
_shader_type_screen = 0,
|
|
_shader_type_effect,
|
|
_shader_type_decal,
|
|
_shader_type_environment,
|
|
_shader_type_model,
|
|
_shader_type_transparent_generic,
|
|
_shader_type_transparent_chicago,
|
|
_shader_type_transparent_water,
|
|
_shader_type_transparent_glass,
|
|
_shader_type_transparent_meter,
|
|
_shader_type_transparent_plasma,
|
|
NUMBER_OF_SHADER_TYPES
|
|
};
|
|
|
|
enum
|
|
{
|
|
_shader_model_detail_after_reflection_bit = 0,
|
|
_shader_model_two_sided_bit,
|
|
_shader_model_not_alpha_tested_bit,
|
|
_shader_model_alpha_blended_decal_bit,
|
|
_shader_model_true_atmospheric_fog_bit,
|
|
_shader_model_nocull_two_sided_bit,
|
|
NUMBER_OF_SHADER_MODEL_FLAGS
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
struct model_shader_reference
|
|
{
|
|
struct tag_reference shader;
|
|
short permutation_index;
|
|
word pad;
|
|
long unused[3];
|
|
};
|
|
|
|
struct model_geometry
|
|
{
|
|
byte reserved[0x24];
|
|
struct tag_block parts;
|
|
};
|
|
|
|
struct model_geometry_part
|
|
{
|
|
unsigned long flags;
|
|
short shader_index;
|
|
char previous_part_index;
|
|
char next_part_index;
|
|
short centroid_primary_node_index;
|
|
short centroid_secondary_node_index;
|
|
real centroid_primary_node_weight;
|
|
real centroid_secondary_node_weight;
|
|
real_point3d centroid;
|
|
struct tag_block uncompressed_vertices;
|
|
struct tag_block compressed_vertices;
|
|
struct tag_block triangles;
|
|
struct triangle_buffer triangle_buffer;
|
|
struct vertex_buffer vertex_buffer;
|
|
};
|
|
|
|
typedef char verify_model_shader_reference_size[sizeof(struct model_shader_reference) == 0x20 ? 1 : -1];
|
|
typedef char verify_model_geometry_part_size[sizeof(struct model_geometry_part) == 0x68 ? 1 : -1];
|
|
|
|
struct shader_model_definition
|
|
{
|
|
struct shader shader;
|
|
word flags;
|
|
short type;
|
|
byte reserved_before_translucency[0xC];
|
|
real translucency;
|
|
};
|
|
|
|
struct rasterizer_model_skinning
|
|
{
|
|
real_matrix4x3 const *node_matrices;
|
|
short node_matrix_count;
|
|
word pad;
|
|
};
|
|
|
|
struct render_sort_filth
|
|
{
|
|
short *previous_group_presorted_index_reference;
|
|
short *next_group_presorted_index_reference;
|
|
short group_index;
|
|
short next_part_index;
|
|
short part_index;
|
|
word pad;
|
|
};
|
|
|
|
struct render_model_effect
|
|
{
|
|
short type;
|
|
word pad;
|
|
real intensity;
|
|
byte reserved[0x20];
|
|
};
|
|
|
|
struct rasterizer_model_begin_parameters
|
|
{
|
|
unsigned long geometry_flags;
|
|
long unique_identifier;
|
|
struct rasterizer_model_skinning skinning;
|
|
struct render_lighting lighting;
|
|
struct render_animation animation;
|
|
struct render_model_effect effect;
|
|
real_point3d centroid;
|
|
real radius;
|
|
real_vector2d base_map_scale;
|
|
};
|
|
|
|
typedef char verify_render_model_effect_size[sizeof(struct render_model_effect) == 0x28 ? 1 : -1];
|
|
typedef char verify_rasterizer_model_begin_parameters_size[sizeof(struct rasterizer_model_begin_parameters) == 0xCC ? 1 : -1];
|
|
|
|
struct rasterizer_debug_options
|
|
{
|
|
byte reserved[8];
|
|
short debug_model_lod;
|
|
byte trailing[0x5E];
|
|
};
|
|
|
|
typedef char verify_rasterizer_debug_options_size[sizeof(struct rasterizer_debug_options) == 0x68 ? 1 : -1];
|
|
|
|
/* ---------- prototypes */
|
|
|
|
#include "rasterizer/rasterizer_models.h"
|
|
|
|
static void render_model_parts(
|
|
struct model const *model,
|
|
char const *region_permutation_indices,
|
|
struct rasterizer_model_skinning const *skinning,
|
|
long object_index,
|
|
short geometry_detail_level_index,
|
|
short forced_shader_permutation_index,
|
|
long flags);
|
|
|
|
/* ---------- globals */
|
|
|
|
extern struct rasterizer_debug_options rasterizer_debug_options;
|
|
extern boolean rasterizer_model_cortana_hack;
|
|
|
|
extern boolean render_model_nodes;
|
|
extern boolean render_model_markers;
|
|
extern boolean render_model_vertex_counts;
|
|
extern boolean render_model_index_counts;
|
|
extern boolean render_model_no_geometry;
|
|
|
|
static real default_function_values[MAXIMUM_FUNCTION_VALUES_PER_MODEL] = { 0 };
|
|
static real_rgb_color default_render_model_change_colors[MAXIMUM_CHANGE_COLORS_PER_MODEL] = { 0 };
|
|
static struct render_model_effect default_render_model_effect = { 0 };
|
|
static char default_render_model_region_permutation_indices[MAXIMUM_REGIONS_PER_MODEL] = { 0 };
|
|
|
|
struct profile_section render_model_section = { "render_model", NONE, TRUE };
|
|
|
|
/* ---------- private code */
|
|
|
|
static void render_model_parts(
|
|
struct model const *model,
|
|
char const *region_permutation_indices,
|
|
struct rasterizer_model_skinning const *skinning,
|
|
long object_index,
|
|
short geometry_detail_level_index,
|
|
short forced_shader_permutation_index,
|
|
long flags)
|
|
{
|
|
boolean immediate = TEST_FLAG(flags, _render_model_immediate_bit);
|
|
short last_pass = TEST_FLAG(flags, _render_model_shadow_bit) ? _render_model_pass_solid : _render_model_pass_transparent;
|
|
struct render_sort_filth sort_filth[MAXIMUM_PARTS_PER_MODEL_GEOMETRY];
|
|
real_point3d centroid;
|
|
short pass;
|
|
|
|
for (pass = _render_model_pass_solid; pass<=last_pass; pass++)
|
|
{
|
|
short sort_filth_count = 0;
|
|
short region_index;
|
|
short i, j;
|
|
|
|
for (region_index = 0; region_index<model->regions.count; region_index++)
|
|
{
|
|
struct model_region *region = TAG_BLOCK_GET_ELEMENT(&model->regions, region_index, struct model_region);
|
|
char permutation_index = region_permutation_indices[region_index];
|
|
|
|
if (permutation_index!=NONE)
|
|
{
|
|
struct model_region_permutation *permutation = TAG_BLOCK_GET_ELEMENT(
|
|
®ion->permutations,
|
|
permutation_index,
|
|
struct model_region_permutation);
|
|
short geometry_index = permutation->geometry_indices[geometry_detail_level_index];
|
|
|
|
if (!render_model_no_geometry && geometry_index!=NONE)
|
|
{
|
|
struct model_geometry *geometry = TAG_BLOCK_GET_ELEMENT(&model->geometries, geometry_index, struct model_geometry);
|
|
short part_index;
|
|
|
|
for (part_index = 0; part_index<geometry->parts.count; part_index++)
|
|
{
|
|
struct model_geometry_part *part = TAG_BLOCK_GET_ELEMENT(&geometry->parts, part_index, struct model_geometry_part);
|
|
struct model_shader_reference *shader_reference = TAG_BLOCK_GET_ELEMENT(
|
|
&model->shaders,
|
|
part->shader_index,
|
|
struct model_shader_reference);
|
|
struct shader *shader = shader_definition_get(shader_reference->shader.index);
|
|
|
|
if (shader_type_is_valid_for_model(shader->base.type) &&
|
|
!TEST_FLAG(part->flags, _model_geometry_part_stripped_bit))
|
|
{
|
|
if (shader_type_is_transparent(shader->base.type))
|
|
{
|
|
if (pass==_render_model_pass_transparent)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\models\\models.c", 442, !TEST_FLAG(flags, _render_model_shadow_bit));
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\models\\models.c",
|
|
445,
|
|
part->centroid_primary_node_index>=0 && part->centroid_primary_node_index<model->nodes.count);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\models\\models.c",
|
|
446,
|
|
part->centroid_secondary_node_index>=0 && part->centroid_secondary_node_index<model->nodes.count);
|
|
|
|
matrix4x3_transform_point(
|
|
&skinning->node_matrices[part->centroid_primary_node_index],
|
|
&part->centroid,
|
|
¢roid);
|
|
rasterizer_model_transparent_geometry_submit(
|
|
shader,
|
|
forced_shader_permutation_index ? forced_shader_permutation_index : shader_reference->permutation_index,
|
|
&part->triangle_buffer,
|
|
NONE,
|
|
part->triangle_buffer.count,
|
|
&part->vertex_buffer,
|
|
NONE,
|
|
¢roid,
|
|
&sort_filth[sort_filth_count]);
|
|
|
|
if (sort_filth_count<MAXIMUM_PARTS_PER_MODEL_GEOMETRY &&
|
|
sort_filth[sort_filth_count].group_index!=NONE &&
|
|
!immediate &&
|
|
(part->next_part_index>0 || part->previous_part_index>0))
|
|
{
|
|
sort_filth[sort_filth_count].part_index = part_index;
|
|
sort_filth[sort_filth_count].next_part_index = part->next_part_index;
|
|
sort_filth_count++;
|
|
}
|
|
}
|
|
}
|
|
else if (shader->base.type==_shader_type_model &&
|
|
TEST_FLAG(((struct shader_model_definition *)shader_get_and_verify_type(shader, _shader_type_model))->flags, _shader_model_alpha_blended_decal_bit))
|
|
{
|
|
if (pass==_render_model_pass_decal)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\models\\models.c", 491, !TEST_FLAG(flags, _render_model_shadow_bit));
|
|
|
|
rasterizer_model_draw(
|
|
shader,
|
|
forced_shader_permutation_index ? forced_shader_permutation_index : shader_reference->permutation_index,
|
|
&part->triangle_buffer,
|
|
NONE,
|
|
part->triangle_buffer.count,
|
|
&part->vertex_buffer,
|
|
NONE);
|
|
}
|
|
}
|
|
else if (pass==_render_model_pass_solid)
|
|
{
|
|
if (TEST_FLAG(flags, _render_model_shadow_bit))
|
|
{
|
|
rasterizer_environment_shadow_model_draw(
|
|
shader,
|
|
forced_shader_permutation_index ? forced_shader_permutation_index : shader_reference->permutation_index,
|
|
&part->triangle_buffer,
|
|
&part->vertex_buffer);
|
|
}
|
|
else
|
|
{
|
|
rasterizer_model_draw(
|
|
shader,
|
|
forced_shader_permutation_index ? forced_shader_permutation_index : shader_reference->permutation_index,
|
|
&part->triangle_buffer,
|
|
NONE,
|
|
part->triangle_buffer.count,
|
|
&part->vertex_buffer,
|
|
NONE);
|
|
rasterizer_debug_model_vertices(object_index, skinning, part);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i<sort_filth_count; i++)
|
|
{
|
|
for (j = 0; j<sort_filth_count; j++)
|
|
{
|
|
if (sort_filth[i].next_part_index==sort_filth[j].part_index && sort_filth[i].next_part_index>0)
|
|
{
|
|
*sort_filth[i].next_group_presorted_index_reference = sort_filth[j].group_index;
|
|
*sort_filth[j].previous_group_presorted_index_reference = sort_filth[i].group_index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* ---------- public code */
|
|
|
|
void model_interpolate_node_orientations(
|
|
struct model const *model,
|
|
struct real_orientation *original_node_orientations,
|
|
struct real_orientation *target_node_orientations,
|
|
short frame_index,
|
|
short frame_count)
|
|
{
|
|
real fraction = (real)(frame_index + 1) / (real)frame_count;
|
|
real inverse_fraction = 1.f - fraction;
|
|
short node_index;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\models\\models.c",
|
|
579,
|
|
frame_count>0);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\models\\models.c",
|
|
580,
|
|
frame_index<frame_count);
|
|
|
|
for (node_index = 0; node_index < model->nodes.count; node_index++)
|
|
{
|
|
struct real_orientation *target = &target_node_orientations[node_index];
|
|
struct real_orientation *original = &original_node_orientations[node_index];
|
|
|
|
target->scale = original->scale * inverse_fraction + target->scale * fraction;
|
|
quaternions_interpolate_and_normalize(
|
|
&original->rotation,
|
|
&target->rotation,
|
|
fraction,
|
|
&target->rotation);
|
|
target->translation.x = original->translation.x * inverse_fraction + target->translation.x * fraction;
|
|
target->translation.y = original->translation.y * inverse_fraction + target->translation.y * fraction;
|
|
target->translation.z = original->translation.z * inverse_fraction + target->translation.z * fraction;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void model_get_node_orientations(
|
|
struct model const *model,
|
|
real_orientation *node_orientations)
|
|
{
|
|
short node_index;
|
|
|
|
for (node_index = 0; node_index<model->nodes.count; node_index++)
|
|
{
|
|
struct model_node *node = TAG_BLOCK_GET_ELEMENT(&model->nodes, node_index, struct model_node);
|
|
|
|
node_orientations[node_index].rotation = node->default_rotation;
|
|
node_orientations[node_index].translation = node->default_translation;
|
|
node_orientations[node_index].scale = 1.f;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void model_get_node_matrices(
|
|
struct model const *model,
|
|
real_matrix4x3 *node_matrices,
|
|
real_point3d const *origin,
|
|
real_vector3d const *forward,
|
|
real_vector3d const *up)
|
|
{
|
|
short node_queue[MAXIMUM_NODES_PER_MODEL];
|
|
short read_index, write_index;
|
|
|
|
node_queue[0] = 0;
|
|
read_index = 0;
|
|
write_index = 1;
|
|
|
|
while (read_index!=write_index)
|
|
{
|
|
short node_index = node_queue[read_index++];
|
|
struct model_node *node = TAG_BLOCK_GET_ELEMENT(&model->nodes, node_index, struct model_node);
|
|
real_matrix4x3 node_matrix;
|
|
|
|
matrix4x3_from_point_and_quaternion(&node_matrix, &node->default_translation, &node->default_rotation);
|
|
|
|
if (node_index == 0)
|
|
{
|
|
matrix4x3_from_point_and_vectors(
|
|
&node_matrices[node_index],
|
|
origin ? origin : global_origin3d,
|
|
forward ? forward : global_forward3d,
|
|
up ? up : global_up3d);
|
|
matrix4x3_multiply(&node_matrices[node_index], &node_matrix, &node_matrices[node_index]);
|
|
}
|
|
else
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\models\\models.c", 650, node->parent_node_index!=NONE);
|
|
matrix4x3_multiply(&node_matrices[node->parent_node_index], &node_matrix, &node_matrices[node_index]);
|
|
}
|
|
|
|
if (node->next_sibling_node_index!=NONE)
|
|
{
|
|
node_queue[write_index++] = node->next_sibling_node_index;
|
|
}
|
|
if (node->first_child_node_index!=NONE)
|
|
{
|
|
node_queue[write_index++] = node->first_child_node_index;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void model_node_matrices_from_orientations(
|
|
struct model const *model,
|
|
real_matrix4x3 *node_matrices,
|
|
real_orientation const *node_orientations,
|
|
real_point3d const *origin,
|
|
real_vector3d const *forward,
|
|
real_vector3d const *up)
|
|
{
|
|
real_matrix4x3 root_matrix;
|
|
|
|
matrix4x3_from_point_and_vectors(&root_matrix, origin, forward, up);
|
|
|
|
if (model->nodes.count>0)
|
|
{
|
|
short node_queue[MAXIMUM_NODES_PER_MODEL];
|
|
short read_index = 0;
|
|
short write_index = 1;
|
|
|
|
node_queue[0] = 0;
|
|
|
|
do
|
|
{
|
|
short node_index = node_queue[read_index++];
|
|
struct model_node *node = TAG_BLOCK_GET_ELEMENT(&model->nodes, node_index, struct model_node);
|
|
real_matrix4x3 const *parent_matrix = node_index==0 ? &root_matrix : &node_matrices[node->parent_node_index];
|
|
real_matrix4x3 node_matrix;
|
|
|
|
matrix4x3_from_orientation(&node_matrix, &node_orientations[node_index]);
|
|
matrix4x3_multiply(parent_matrix, &node_matrix, &node_matrices[node_index]);
|
|
|
|
if (node->next_sibling_node_index!=NONE)
|
|
{
|
|
node_queue[write_index++] = node->next_sibling_node_index;
|
|
}
|
|
if (node->first_child_node_index!=NONE)
|
|
{
|
|
node_queue[write_index++] = node->first_child_node_index;
|
|
}
|
|
}
|
|
while (read_index!=write_index);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
short model_find_marker(
|
|
long model_index,
|
|
char const *name)
|
|
{
|
|
if (model_index != NONE && name && *name)
|
|
{
|
|
struct model *model = model_definition_get(model_index);
|
|
short lower_bound = 0;
|
|
short upper_bound = (short)model->markers.count - 1;
|
|
|
|
while (lower_bound <= upper_bound)
|
|
{
|
|
short marker_index = (short)((lower_bound + upper_bound) / 2);
|
|
struct model_marker *marker = TAG_BLOCK_GET_ELEMENT(
|
|
&model->markers,
|
|
marker_index,
|
|
struct model_marker);
|
|
long comparison = _stricmp(name, marker->name);
|
|
|
|
if (comparison == 0)
|
|
{
|
|
return marker_index;
|
|
}
|
|
if (comparison < 0)
|
|
{
|
|
upper_bound = marker_index - 1;
|
|
}
|
|
else
|
|
{
|
|
lower_bound = marker_index + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NONE;
|
|
}
|
|
|
|
real_matrix4x3 *model_get_default_inverse_matrix(
|
|
struct model *model,
|
|
short node_index)
|
|
{
|
|
struct model_node *node = TAG_BLOCK_GET_ELEMENT(&model->nodes, node_index, struct model_node);
|
|
|
|
return &node->runtime_default_inverse_matrix;
|
|
}
|
|
|
|
short model_find_node(
|
|
long model_index,
|
|
char const *name)
|
|
{
|
|
if (model_index!=NONE)
|
|
{
|
|
short node_index;
|
|
struct model *model = model_definition_get(model_index);
|
|
|
|
for (node_index = 0; node_index<model->nodes.count; node_index++)
|
|
{
|
|
struct model_node *node = TAG_BLOCK_GET_ELEMENT(&model->nodes, node_index, struct model_node);
|
|
|
|
if (!csstrcmp(node->name, name))
|
|
{
|
|
return node_index;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NONE;
|
|
}
|
|
|
|
short model_get_marker_by_name(
|
|
long model_index,
|
|
char const *name,
|
|
byte const *region_permutations,
|
|
short const *node_remapping_table,
|
|
short node_count,
|
|
real_matrix4x3 const *node_matrices,
|
|
boolean mirrored_flag,
|
|
struct object_marker *markers,
|
|
short maximum_marker_count)
|
|
{
|
|
short result = 0;
|
|
short marker_index = model_find_marker(model_index, name);
|
|
|
|
match_assert("c:\\halo\\SOURCE\\models\\models.c", 760, node_matrices);
|
|
match_assert("c:\\halo\\SOURCE\\models\\models.c", 761, markers);
|
|
|
|
if (marker_index!=NONE)
|
|
{
|
|
short i;
|
|
|
|
struct model *model = model_definition_get(model_index);
|
|
struct model_marker* marker = TAG_BLOCK_GET_ELEMENT(&model->markers, marker_index, struct model_marker);
|
|
|
|
for (i =0; i<marker->instances.count; i++)
|
|
{
|
|
struct model_marker_instance* instance = TAG_BLOCK_GET_ELEMENT(&marker->instances, i, struct model_marker_instance);
|
|
if (!region_permutations ||
|
|
region_permutations[instance->region_index]==instance->permutation_index)
|
|
{
|
|
struct object_marker *object_marker;
|
|
|
|
if (result>=maximum_marker_count)
|
|
{
|
|
break;
|
|
}
|
|
|
|
object_marker = &markers[result++];
|
|
object_marker->node_index = node_remapping_table ? node_remapping_table[instance->node_index] : instance->node_index;
|
|
matrix4x3_from_point_and_quaternion(&object_marker->node_matrix, &instance->translation, &instance->rotation);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\models\\models.c",
|
|
785,
|
|
object_marker->node_index>=0 && object_marker->node_index<(node_remapping_table ? node_count : model->nodes.count));
|
|
|
|
matrix4x3_multiply(&node_matrices[object_marker->node_index], &object_marker->node_matrix, &object_marker->matrix);
|
|
if (mirrored_flag)
|
|
{
|
|
negate_vector3d(&object_marker->matrix.left, &object_marker->matrix.left);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void model_build_tangent_matrices(
|
|
struct model *model)
|
|
{
|
|
short geometry_index;
|
|
|
|
for (geometry_index = 0; geometry_index < model->geometries.count; geometry_index++)
|
|
{
|
|
struct model_geometry *geometry = TAG_BLOCK_GET_ELEMENT(
|
|
&model->geometries,
|
|
geometry_index,
|
|
struct model_geometry);
|
|
short part_index;
|
|
|
|
for (part_index = 0; part_index < geometry->parts.count; part_index++)
|
|
{
|
|
struct model_geometry_part *part = TAG_BLOCK_GET_ELEMENT(
|
|
&geometry->parts,
|
|
part_index,
|
|
struct model_geometry_part);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void model_geometry_part_build_tangent_matrices(
|
|
struct model_geometry_part *part)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void render_model(
|
|
long model_index,
|
|
real level_of_detail_pixels,
|
|
real_matrix4x3 const *node_matrices,
|
|
char const *region_permutation_indices,
|
|
real_rgb_color const *change_colors,
|
|
real const *function_values,
|
|
struct render_lighting const *lighting,
|
|
real_point3d const *centroid,
|
|
real radius,
|
|
struct render_model_effect const *model_effect,
|
|
long unique_identifier,
|
|
short forced_shader_permutation_index,
|
|
unsigned long flags)
|
|
{
|
|
struct model *model = model_definition_get(model_index);
|
|
|
|
profile_enter(render_model_section);
|
|
|
|
match_assert("c:\\halo\\SOURCE\\models\\models.c", 82, lighting);
|
|
|
|
if (model->node_list_checksum==CORTANA_MODEL_NODE_LIST_CHECKSUM &&
|
|
TEST_FLAG(global_scenario_get()->flags, _scenario_cortana_hack_bit))
|
|
{
|
|
rasterizer_model_cortana_hack = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rasterizer_model_cortana_hack = FALSE;
|
|
}
|
|
|
|
if (level_of_detail_pixels>=model->detail_cutoff_pixels[0] || TEST_FLAG(flags, _render_model_shadow_bit))
|
|
{
|
|
real_matrix4x3 relative_node_matrices[MAXIMUM_NODES_PER_MODEL];
|
|
struct rasterizer_model_begin_parameters model_parameters;
|
|
short geometry_detail_level_index;
|
|
short node_index;
|
|
|
|
if (!region_permutation_indices)
|
|
{
|
|
region_permutation_indices = default_render_model_region_permutation_indices;
|
|
}
|
|
if (!model_effect)
|
|
{
|
|
model_effect = &default_render_model_effect;
|
|
}
|
|
if (!change_colors)
|
|
{
|
|
change_colors = default_render_model_change_colors;
|
|
}
|
|
if (!function_values)
|
|
{
|
|
function_values = default_function_values;
|
|
}
|
|
if (!centroid)
|
|
{
|
|
centroid = &node_matrices->position;
|
|
}
|
|
|
|
if (node_matrices)
|
|
{
|
|
for (node_index = 0; node_index<model->nodes.count; node_index++)
|
|
{
|
|
struct model_node *node = TAG_BLOCK_GET_ELEMENT(&model->nodes, node_index, struct model_node);
|
|
|
|
matrix4x3_multiply(
|
|
&node_matrices[node_index],
|
|
&node->runtime_default_inverse_matrix,
|
|
&relative_node_matrices[node_index]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (node_index = 0; node_index<model->nodes.count; node_index++)
|
|
{
|
|
relative_node_matrices[node_index] = render.frustum.world_to_view;
|
|
}
|
|
}
|
|
|
|
geometry_detail_level_index = NUMBER_OF_DETAIL_LEVELS_PER_MODEL-1;
|
|
while (geometry_detail_level_index>0 &&
|
|
level_of_detail_pixels<model->detail_cutoff_pixels[geometry_detail_level_index])
|
|
{
|
|
geometry_detail_level_index--;
|
|
}
|
|
if (rasterizer_debug_options.debug_model_lod!=NONE)
|
|
{
|
|
geometry_detail_level_index = PIN(rasterizer_debug_options.debug_model_lod, 0, NUMBER_OF_DETAIL_LEVELS_PER_MODEL-1);
|
|
}
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\models\\models.c",
|
|
169,
|
|
geometry_detail_level_index>=0 && geometry_detail_level_index<NUMBER_OF_DETAIL_LEVELS_PER_MODEL);
|
|
|
|
if (!TEST_FLAG(flags, _render_model_shadow_bit))
|
|
{
|
|
if (render_model_nodes)
|
|
{
|
|
for (node_index = 0; node_index<model->nodes.count; node_index++)
|
|
{
|
|
struct model_node *node = TAG_BLOCK_GET_ELEMENT(&model->nodes, node_index, struct model_node);
|
|
|
|
if (node->parent_node_index!=NONE)
|
|
{
|
|
render_debug_line(
|
|
TRUE,
|
|
&node_matrices[node_index].position,
|
|
&node_matrices[node->parent_node_index].position,
|
|
global_real_argb_white);
|
|
}
|
|
render_debug_matrix(TRUE, &node_matrices[node_index], 0.05f);
|
|
}
|
|
}
|
|
|
|
if (render_model_markers)
|
|
{
|
|
short marker_index;
|
|
|
|
for (marker_index = 0; marker_index<model->markers.count; marker_index++)
|
|
{
|
|
struct model_marker *marker = TAG_BLOCK_GET_ELEMENT(&model->markers, marker_index, struct model_marker);
|
|
short instance_index;
|
|
|
|
for (instance_index = 0; instance_index<marker->instances.count; instance_index++)
|
|
{
|
|
struct model_marker_instance *instance = TAG_BLOCK_GET_ELEMENT(
|
|
&marker->instances,
|
|
instance_index,
|
|
struct model_marker_instance);
|
|
|
|
if (region_permutation_indices[instance->region_index]==instance->permutation_index)
|
|
{
|
|
real_matrix4x3 marker_matrix;
|
|
|
|
matrix4x3_from_point_and_quaternion(&marker_matrix, &instance->translation, &instance->rotation);
|
|
matrix4x3_multiply(&node_matrices[instance->node_index], &marker_matrix, &marker_matrix);
|
|
render_debug_matrix(FALSE, &marker_matrix, 0.05f);
|
|
render_debug_string_at_point(FALSE, &marker_matrix.position, marker->name, global_real_argb_white);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (render_model_vertex_counts || render_model_index_counts)
|
|
{
|
|
short maximum_actual_detail_level_index = geometry_detail_level_index;
|
|
boolean has_unstripped_parts = FALSE;
|
|
short vertex_count = 0;
|
|
short index_count = 0;
|
|
short region_index;
|
|
real distance;
|
|
|
|
for (region_index = 0; region_index<model->regions.count; region_index++)
|
|
{
|
|
struct model_region *region = TAG_BLOCK_GET_ELEMENT(&model->regions, region_index, struct model_region);
|
|
char permutation_index = region_permutation_indices[region_index];
|
|
|
|
if (permutation_index!=NONE)
|
|
{
|
|
struct model_region_permutation *permutation = TAG_BLOCK_GET_ELEMENT(
|
|
®ion->permutations,
|
|
permutation_index,
|
|
struct model_region_permutation);
|
|
short actual_detail_level_index;
|
|
short geometry_index;
|
|
|
|
for (actual_detail_level_index = geometry_detail_level_index+1;
|
|
actual_detail_level_index<NUMBER_OF_DETAIL_LEVELS_PER_MODEL;
|
|
actual_detail_level_index++)
|
|
{
|
|
if (permutation->geometry_indices[actual_detail_level_index]!=
|
|
permutation->geometry_indices[geometry_detail_level_index])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
match_assert("c:\\halo\\SOURCE\\models\\models.c", 247, actual_detail_level_index > 0);
|
|
actual_detail_level_index--;
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\models\\models.c",
|
|
249,
|
|
(actual_detail_level_index >= 0) && (actual_detail_level_index < NUMBER_OF_DETAIL_LEVELS_PER_MODEL));
|
|
maximum_actual_detail_level_index = MAX(maximum_actual_detail_level_index, actual_detail_level_index);
|
|
|
|
geometry_index = permutation->geometry_indices[geometry_detail_level_index];
|
|
if (geometry_index!=NONE)
|
|
{
|
|
struct model_geometry *geometry = TAG_BLOCK_GET_ELEMENT(&model->geometries, geometry_index, struct model_geometry);
|
|
short part_index;
|
|
|
|
for (part_index = 0; part_index<geometry->parts.count; part_index++)
|
|
{
|
|
struct model_geometry_part *part = TAG_BLOCK_GET_ELEMENT(&geometry->parts, part_index, struct model_geometry_part);
|
|
|
|
vertex_count+= part->vertex_buffer.count;
|
|
switch (part->triangle_buffer.type)
|
|
{
|
|
case _triangle_buffer_type_triangles:
|
|
index_count+= 3*part->triangle_buffer.count;
|
|
has_unstripped_parts = TRUE;
|
|
break;
|
|
case _triangle_buffer_type_precompiled_strip:
|
|
index_count+= part->triangle_buffer.count+2;
|
|
break;
|
|
default:
|
|
match_assert("c:\\halo\\SOURCE\\models\\models.c", 276, !"unreachable");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
distance = fabs(
|
|
render.frustum.world_to_view.forward.k*centroid->x +
|
|
render.frustum.world_to_view.left.k*centroid->y +
|
|
render.frustum.world_to_view.up.k*centroid->z +
|
|
render.frustum.world_to_view.position.z);
|
|
level_of_detail_pixels = distance/render.frustum.projection_world_to_screen.j*level_of_detail_pixels*0.5f;
|
|
if (level_of_detail_pixels>0.0001f)
|
|
{
|
|
real_argb_color const *detail_level_colors[NUMBER_OF_DETAIL_LEVELS_PER_MODEL];
|
|
real_argb_color const *color;
|
|
char string[256];
|
|
real_point3d point;
|
|
|
|
detail_level_colors[0] = global_real_argb_blue;
|
|
detail_level_colors[1] = global_real_argb_green;
|
|
detail_level_colors[2] = global_real_argb_yellow;
|
|
detail_level_colors[3] = global_real_argb_orange;
|
|
detail_level_colors[4] = global_real_argb_red;
|
|
color = detail_level_colors[maximum_actual_detail_level_index];
|
|
if (has_unstripped_parts && (game_time_get()+model_index)%30<15)
|
|
{
|
|
color = global_real_argb_white;
|
|
}
|
|
|
|
csstrcpy(string, "");
|
|
if (render_model_vertex_counts)
|
|
{
|
|
_snprintf(string+csstrlen(string), sizeof(string)-csstrlen(string), "%d", vertex_count);
|
|
}
|
|
if (render_model_vertex_counts && render_model_index_counts)
|
|
{
|
|
_snprintf(string+csstrlen(string), sizeof(string)-csstrlen(string), "/");
|
|
}
|
|
if (render_model_index_counts)
|
|
{
|
|
_snprintf(string+csstrlen(string), sizeof(string)-csstrlen(string), "%d", index_count);
|
|
}
|
|
|
|
set_real_point3d(&point, centroid->x, centroid->y, centroid->z+level_of_detail_pixels);
|
|
render_debug_string_at_point(FALSE, &point, string, color);
|
|
}
|
|
}
|
|
}
|
|
|
|
model_parameters.unique_identifier = unique_identifier;
|
|
model_parameters.lighting = *lighting;
|
|
model_parameters.centroid = *centroid;
|
|
model_parameters.radius = radius;
|
|
model_parameters.effect = *model_effect;
|
|
model_parameters.animation.colors = change_colors;
|
|
model_parameters.animation.values = function_values;
|
|
model_parameters.skinning.node_matrices = relative_node_matrices;
|
|
model_parameters.skinning.node_matrix_count = model->nodes.count;
|
|
model_parameters.geometry_flags = 0;
|
|
model_parameters.base_map_scale = model->base_map_scale;
|
|
|
|
if (TEST_FLAG(flags, _render_model_immediate_bit))
|
|
{
|
|
model_parameters.geometry_flags = FLAG(_rasterizer_geometry_no_sort_bit) |
|
|
FLAG(_rasterizer_geometry_no_queue_bit) |
|
|
FLAG(_rasterizer_geometry_no_fog_bit) |
|
|
FLAG(_rasterizer_geometry_no_zbuffer_bit) |
|
|
FLAG(_rasterizer_geometry_sky_bit);
|
|
}
|
|
SET_FLAG(model_parameters.geometry_flags, _rasterizer_geometry_atmospheric_fog_but_no_planar_fog_bit, TEST_FLAG(flags, _render_model_no_planar_fog_bit));
|
|
SET_FLAG(model_parameters.geometry_flags, _rasterizer_geometry_first_person_bit, TEST_FLAG(flags, _render_model_first_person_bit));
|
|
|
|
if (TEST_FLAG(flags, _render_model_shadow_bit))
|
|
{
|
|
rasterizer_environment_shadow_model_begin(&model_parameters);
|
|
}
|
|
else
|
|
{
|
|
rasterizer_model_begin(&model_parameters, FALSE);
|
|
}
|
|
render_model_parts(
|
|
model,
|
|
region_permutation_indices,
|
|
&model_parameters.skinning,
|
|
unique_identifier,
|
|
geometry_detail_level_index,
|
|
forced_shader_permutation_index,
|
|
flags);
|
|
if (TEST_FLAG(flags, _render_model_shadow_bit))
|
|
{
|
|
rasterizer_environment_shadow_model_end();
|
|
}
|
|
else
|
|
{
|
|
rasterizer_model_end();
|
|
}
|
|
}
|
|
|
|
rasterizer_model_cortana_hack = FALSE;
|
|
|
|
profile_exit(render_model_section);
|
|
|
|
return;
|
|
}
|