collada/header: precalculate fully linearized node list

This commit is contained in:
Zack Buhman 2026-01-27 13:05:43 -06:00
parent 2860311f8a
commit e4bb6c2616
5 changed files with 45 additions and 94 deletions

View File

@ -41,6 +41,10 @@ class State:
# channel nodes: node_id to list of sanitized target names
node_animation_channels: Dict[str, set]
# linearized_nodes
linearized_nodes: List[types.Node]
node_parents: Dict[int, int]
def __init__(self):
self.vertex_buffer = BytesIO()
self.index_buffer = BytesIO()
@ -50,6 +54,8 @@ class State:
self.symbol_names = {}
self.emitted_input_elements_arrays = {}
self.node_animation_channels = defaultdict(set)
self.linearized_nodes = []
self.node_parents = {}
def sanitize_name(state, name, value, *, allow_slash=False):
assert name is not None, value
@ -284,13 +290,13 @@ def get_node_name_id(node):
assert name is not None, node
return name
def render_node_children(state, collada, node_name, nodes):
yield f"node const * const node_children_{node_name}[] = {{"
for node in nodes:
node_name_id = get_node_name_id(node)
node_name = sanitize_name(state, node_name_id, node)
yield "&node_{node_name},"
yield "};"
#def render_node_children(state, collada, node_name, nodes):
# yield f"node const * const node_children_{node_name}[] = {{"
# for node in nodes:
# node_name_id = get_node_name_id(node)
# node_name = sanitize_name(state, node_name_id, node)
# yield "&node_{node_name},"
# yield "};"
def render_node_channels(state, collada, node, node_name):
if node.id is None:
@ -304,14 +310,10 @@ def render_node_channels(state, collada, node, node_name):
yield f"&node_channel_{target_name},"
yield "};"
def render_node(state, collada, node):
# render children first
for child_node in node.nodes:
yield from render_node(state, collada, child_node)
def render_node(state, collada, node, node_index):
node_name_id = get_node_name_id(node)
node_name = sanitize_name(state, node_name_id, node)
yield from render_node_children(state, collada, node_name, node.nodes)
#yield from render_node_children(state, collada, node_name, node.nodes)
yield from render_node_transforms(state, collada, node_name, node.transformation_elements)
yield from render_node_instance_geometries(state, collada, node_name, node.instance_geometries)
yield from render_node_channels(state, collada, node, node_name)
@ -322,6 +324,8 @@ def render_node(state, collada, node):
}[node.type]
yield f"node const node_{node_name} = {{"
yield f".parent_index = {state.node_parents[node_index]},"
yield ""
yield f".type = node_type::{type},"
yield ""
yield f".transforms = transforms_{node_name},"
@ -332,22 +336,34 @@ def render_node(state, collada, node):
yield ""
yield f".channels = node_channels_{node_name},"
yield f".channels_count = {len(state.node_animation_channels[node.id])},"
yield ""
yield f".nodes = node_children_{node_name},"
yield f".nodes_count = {len(node.nodes)},"
#yield ""
#yield f".nodes = node_children_{node_name},"
#yield f".nodes_count = {len(node.nodes)},"
yield "};"
def linear_nodes(collada):
def traverse_node(state, parent_node_index, node):
assert parent_node_index < len(state.linearized_nodes)
node_index = len(state.linearized_nodes)
state.linearized_nodes.append(node)
assert node_index not in state.node_parents
state.node_parents[node_index] = parent_node_index
for child_node in node.nodes:
traverse_node(state, node_index, child_node)
def linearize_nodes(state, collada):
for library_visual_scenes in collada.library_visual_scenes:
for visual_scene in library_visual_scenes.visual_scenes:
for node in visual_scene.nodes:
yield node
traverse_node(state, -1, node)
def render_library_visual_scenes(state, collada):
for node in linear_nodes(collada):
yield from render_node(state, collada, node)
linearize_nodes(state, collada)
for node_index, node in enumerate(state.linearized_nodes):
yield from render_node(state, collada, node, node_index)
yield "node const * const nodes[] = {"
for node in linear_nodes(collada):
for node_index, node in enumerate(state.linearized_nodes):
node_name_id = get_node_name_id(node)
node_name = sanitize_name(state, node_name_id, node)
yield f"&node_{node_name},"

View File

@ -43,17 +43,9 @@ namespace collada_scene {
HRESULT load_scene(collada::descriptor const * const descriptor);
void render();
typedef void (collada_scene::scene_state::* const apply_node_func_t)(collada::node const * const node,
node_instance * node_instance);
private:
HRESULT load_layouts();
void allocate_node_instances();
node_instance * apply_node_instances1(collada::node const * const node,
node_instance * node_instance,
apply_node_func_t func);
void apply_node_instances(apply_node_func_t func);
void allocate_node_instance(collada::node const * const node,
node_instance * node_instance);

View File

@ -277,6 +277,8 @@ namespace collada {
//////////////////////////////////////////////////////////////////////
struct node {
int const parent_index;
node_type const type;
transform const * const transforms;
@ -288,8 +290,8 @@ namespace collada {
channel const * const * const channels;
int const channels_count;
node const * const * const nodes;
int const nodes_count;
//node const * const * const nodes;
//int const nodes_count;
};
struct descriptor {

View File

@ -510,9 +510,6 @@ geometry const * const geometries[] = {
&geometry_geom_plane001,
};
node const * const node_children_node_environmentambientlight[] = {
};
transform const transforms_node_environmentambientlight[] = {
};
@ -532,12 +529,6 @@ node const node_node_environmentambientlight = {
.channels = node_channels_node_environmentambientlight,
.channels_count = 0,
.nodes = node_children_node_environmentambientlight,
.nodes_count = 0,
};
node const * const node_children_node_cube[] = {
};
transform const transforms_node_cube[] = {
@ -583,8 +574,8 @@ instance_geometry const instance_geometries_node_cube[] = {
};
channel const * const node_channels_node_cube[] = {
&node_channel_node_cube_translation_y,
&node_channel_node_cube_translation_x,
&node_channel_node_cube_translation_y,
};
node const node_node_cube = {
@ -598,12 +589,6 @@ node const node_node_cube = {
.channels = node_channels_node_cube,
.channels_count = 2,
.nodes = node_children_node_cube,
.nodes_count = 0,
};
node const * const node_children_node_cylinder001[] = {
};
transform const transforms_node_cylinder001[] = {
@ -638,12 +623,6 @@ node const node_node_cylinder001 = {
.channels = node_channels_node_cylinder001,
.channels_count = 0,
.nodes = node_children_node_cylinder001,
.nodes_count = 0,
};
node const * const node_children_node_plane001[] = {
};
transform const transforms_node_plane001[] = {
@ -686,9 +665,6 @@ node const node_node_plane001 = {
.channels = node_channels_node_plane001,
.channels_count = 0,
.nodes = node_children_node_plane001,
.nodes_count = 0,
};
node const * const nodes[] = {

View File

@ -67,15 +67,6 @@ namespace collada_scene {
return S_OK;
}
static int count_nodes(node const * const node)
{
int count = 1;
for (int i = 0; i < node->nodes_count; i++) {
count += count_nodes(node->nodes[i]);
}
return count;
}
static void initialize_node_transforms(node const * const node,
node_instance * node_instance)
{
@ -113,38 +104,13 @@ namespace collada_scene {
initialize_node_transforms(node, node_instance);
}
node_instance * scene_state::apply_node_instances1(node const * const node,
node_instance * node_instance,
apply_node_func_t func)
{
(this->*func)(node, node_instance);
node_instance = &node_instance[1];
for (int i = 0; i < node->nodes_count; i++) {
node_instance = apply_node_instances1(node->nodes[i], node_instance, func);
}
return node_instance;
}
void scene_state::apply_node_instances(apply_node_func_t func)
{
node_instance * node_instance = m_nodeInstances;
for (int i = 0; i < m_descriptor->nodes_count; i++) {
node_instance = apply_node_instances1(m_descriptor->nodes[i], node_instance, func);
}
}
void scene_state::allocate_node_instances()
{
int count = 0;
m_nodeInstances = New<node_instance>(m_descriptor->nodes_count);
for (int i = 0; i < m_descriptor->nodes_count; i++) {
count += count_nodes(m_descriptor->nodes[i]);
allocate_node_instance(m_descriptor->nodes[i], &m_nodeInstances[i]);
}
m_nodeInstances = New<node_instance>(count);
apply_node_instances(&scene_state::allocate_node_instance);
}
HRESULT scene_state::load_scene(collada::descriptor const * const descriptor)
@ -383,7 +349,6 @@ namespace collada_scene {
for (int i = 0; i < m_descriptor->nodes_count; i++) {
node const& node = *m_descriptor->nodes[i];
assert(node.nodes_count == 0);
if (node.type != node_type::NODE)
continue;