collada: render make and resource files

This commit is contained in:
Zack Buhman 2026-01-29 18:41:34 -06:00
parent 5f0f933224
commit af165a3843
7 changed files with 90 additions and 31 deletions

3
.gitignore vendored
View File

@ -11,4 +11,5 @@ __pycache__
*.pyc *.pyc
.\#* .\#*
\#* \#*
*.gch *.gch
image/*.DDS

View File

@ -53,7 +53,9 @@ SHADERS = \
SCENES = \ SCENES = \
src/scenes/curve_interpolation/curve_interpolation.cpp src/scenes/curve_interpolation/curve_interpolation.cpp
$(BUILD_TYPE)/%.res: %.rc $(SHADERS) $(SCENES) include curve_interpolation.mk
$(BUILD_TYPE)/%.res: %.rc $(SHADERS) $(SCENES) $(IMAGES)
@mkdir -p $(@D) @mkdir -p $(@D)
$(WINDRES) -O coff -I$(BUILD_TYPE)/effect -o $@ $< $(WINDRES) -O coff -I$(BUILD_TYPE)/effect -o $@ $<
@ -70,10 +72,11 @@ include/scenes/%.hpp: $(COLLADA_PY_SOURCE)
src/scenes/%.cpp: scenes/%.DAE include/scenes/%.hpp src/scenes/%.cpp: scenes/%.DAE include/scenes/%.hpp
@mkdir -p $(@D) @mkdir -p $(@D)
PYTHONPATH=. python -m collada.main $< $@ $(<:.DAE=.vtx) $(<:.DAE=.idx) PYTHONPATH=. python -m collada.main $< $@ $(<:.DAE=.vtx) $(<:.DAE=.idx) $(notdir $(<:.DAE=.rc)) $(notdir $(<:.DAE=.mk))
OBJS = \ OBJS = \
$(BUILD_TYPE)/main.res \ $(BUILD_TYPE)/main.res \
$(BUILD_TYPE)/curve_interpolation.res \
$(BUILD_TYPE)/robot_player.obj \ $(BUILD_TYPE)/robot_player.obj \
$(BUILD_TYPE)/cube.obj \ $(BUILD_TYPE)/cube.obj \
$(BUILD_TYPE)/main.obj \ $(BUILD_TYPE)/main.obj \

View File

@ -87,7 +87,8 @@ def _validate_name_value(name, value):
def sanitize_resource_name(state, name, value): def sanitize_resource_name(state, name, value):
_validate_name_value(name, value) _validate_name_value(name, value)
assert '/' not in name, name assert '/' not in name, name
resource_name = _sanitize(name).upper() resource_name = f'_{_sanitize(name).upper()}'
assert resource_name not in state.resource_names or state.resource_names[resource_name] is value assert resource_name not in state.resource_names or state.resource_names[resource_name] is value
state.resource_names[resource_name] = value state.resource_names[resource_name] = value
return resource_name return resource_name
@ -480,7 +481,7 @@ def render_opt_texture(state, profile_common, field_name, texture):
image_id = surface.parameter_type.init_from.uri image_id = surface.parameter_type.init_from.uri
image_index = state.image_indices[image_id] image_index = state.image_indices[image_id]
yield f".{field_name} = {{ .image_index = {image_index} }}," yield f".{field_name} = {{ .image_index = {image_index} }}, // {image_id}"
def render_opt_color_or_texture(state, profile_common, field_name, color_or_texture): def render_opt_color_or_texture(state, profile_common, field_name, color_or_texture):
if color_or_texture is None: if color_or_texture is None:
@ -796,14 +797,6 @@ def render_library_lights(state, collada):
for light in library_lights.lights: for light in library_lights.lights:
yield from render_light(state, collada, light) yield from render_light(state, collada, light)
def escape_space(s):
def _escape_space(s):
for c in s:
if c == ' ':
yield '\\'
yield c
return str(_escape_space(s))
def image_resource_name(state, uri): def image_resource_name(state, uri):
uri = unquote(uri) uri = unquote(uri)
prefix = "file:///" prefix = "file:///"
@ -816,7 +809,7 @@ def image_resource_name(state, uri):
filename = os.path.split(path)[1] filename = os.path.split(path)[1]
assert filename not in state.image_paths, filename assert filename not in state.image_paths, filename
state.image_paths[filename] = path state.image_paths[filename] = path
return sanitize_resource_name(state, filename, path.lower()) return sanitize_resource_name(state, filename, path)
def render_image(state, collada, image, image_index): def render_image(state, collada, image, image_index):
assert image.id is not None assert image.id is not None
@ -827,7 +820,7 @@ def render_image(state, collada, image, image_index):
resource_name = image_resource_name(state, image.image_source.uri) resource_name = image_resource_name(state, image.image_source.uri)
image_name = sanitize_name(state, image.id, image) image_name = sanitize_name(state, image.id, image)
yield f"// image_index: {image_index}" yield f"// {image.id}"
yield f"image const image_{image_name} = {{" yield f"image const image_{image_name} = {{"
yield f'.resource_name = L"{resource_name}",' yield f'.resource_name = L"{resource_name}",'
yield "};" yield "};"

View File

@ -1,5 +1,5 @@
import sys import sys
from os import path import os.path
from collada import parse from collada import parse
from collada import header from collada import header
@ -7,25 +7,57 @@ from collada import header
def usage(): def usage():
name = sys.argv[0] name = sys.argv[0]
print("usage (source):") print("usage (source):")
print(f" {name} [input_collada.dae] [output_source.cpp] [output_vertex.vtx] [output_vertex.idx]") print(f" {name} [input_collada.dae] [output_source.cpp] [output_vertex.vtx] [output_vertex.idx] [output_resource.rc]")
print("usage (header):") print("usage (header):")
print(f" {name} [output_header.hpp]") print(f" {name} [output_header.hpp]")
sys.exit(1) sys.exit(1)
def parse_namespace(filename): def parse_namespace(filename):
namespace = path.splitext(path.split(filename)[1])[0] namespace = os.path.splitext(os.path.split(filename)[1])[0]
return namespace return namespace
def render_resource_file(state, f):
for resource_name, path in state.resource_names.items():
filename = os.path.split(path)[1]
filename = os.path.splitext(filename)[0]
f.write(f'{resource_name} RCDATA "image/{filename}.DDS"\r\n'.encode('ascii'))
def escape_space(s):
def _escape_space(s):
for c in s:
if c == ' ':
yield '\\'
yield c
return "".join(_escape_space(s))
def render_makefile(state, f):
for _, path in state.resource_names.items():
filename = os.path.split(path)[1]
filename, ext = os.path.splitext(filename)
filename = escape_space(filename)
escaped = escape_space(path)
escaped_dds = os.path.splitext(filename)
f.write(f"IMAGES += image/{filename}.DDS\r\n".encode('ascii'))
f.write(f"image/{filename}.DDS: {escaped}\r\n".encode('ascii'))
f.write('\ttexconv10.exe -nologo "$<"\r\n'.encode('ascii'))
f.write(f'\tmv "$(<:.{ext[1:]}=.DDS)" "$@"\r\n\r\n'.encode('ascii'))
def main(): def main():
try: try:
input_collada = sys.argv[1] input_collada = sys.argv[1]
output_source = sys.argv[2] output_source = sys.argv[2]
output_vertex = sys.argv[3] output_vertex = sys.argv[3]
output_index = sys.argv[4] output_index = sys.argv[4]
output_resource = sys.argv[5]
output_makefile = sys.argv[6]
assert input_collada.lower().endswith(".dae") assert input_collada.lower().endswith(".dae")
assert output_source.lower().endswith(".cpp") assert output_source.lower().endswith(".cpp")
assert output_vertex.lower().endswith(".vtx") assert output_vertex.lower().endswith(".vtx")
assert output_index.lower().endswith(".idx") assert output_index.lower().endswith(".idx")
assert output_resource.lower().endswith(".rc")
assert output_makefile.lower().endswith(".mk")
except Exception as e: except Exception as e:
usage() usage()
@ -44,6 +76,12 @@ def main():
with open(output_index, 'wb') as f: with open(output_index, 'wb') as f:
f.write(state.index_buffer.getvalue()) f.write(state.index_buffer.getvalue())
with open(output_resource, 'wb') as f:
render_resource_file(state, f)
with open(output_makefile, 'wb') as f:
render_makefile(state, f)
def main_header(): def main_header():
try: try:
output_header = sys.argv[1] output_header = sys.argv[1]

20
curve_interpolation.mk Normal file
View File

@ -0,0 +1,20 @@
IMAGES += image/american_cherry.DDS
image/american_cherry.DDS: C:/Program\ Files/Common\ Files/Autodesk\ Shared/Materials/Textures/1/Mats/american_cherry.png
texconv10.exe -nologo "$<"
mv "$(<:.png=.DDS)" "$@"
IMAGES += image/102.DDS
image/102.DDS: C:/Program\ Files/Common\ Files/Autodesk\ Shared/Materials/Textures/3/Mats/102.png
texconv10.exe -nologo "$<"
mv "$(<:.png=.DDS)" "$@"
IMAGES += image/Finishes.Flooring.Tile.Square.Medium\ Blue.DDS
image/Finishes.Flooring.Tile.Square.Medium\ Blue.DDS: C:/Program\ Files/Common\ Files/Autodesk\ Shared/Materials/Textures/3/Mats/Finishes.Flooring.Tile.Square.Medium\ Blue.png
texconv10.exe -nologo "$<"
mv "$(<:.png=.DDS)" "$@"
IMAGES += image/SiteWork.Planting.Grass.Bermuda1.DDS
image/SiteWork.Planting.Grass.Bermuda1.DDS: C:/Program\ Files/Common\ Files/Autodesk\ Shared/Materials/Textures/3/Mats/SiteWork.Planting.Grass.Bermuda1.jpg
texconv10.exe -nologo "$<"
mv "$(<:.jpg=.DDS)" "$@"

4
curve_interpolation.rc Normal file
View File

@ -0,0 +1,4 @@
_AMERICAN_CHERRY_PNG RCDATA "image/american_cherry.DDS"
_102_PNG RCDATA "image/102.DDS"
_FINISHES_FLOORING_TILE_SQUARE_MEDIUM_BLUE_PNG RCDATA "image/Finishes.Flooring.Tile.Square.Medium Blue.DDS"
_SITEWORK_PLANTING_GRASS_BERMUDA1_JPG RCDATA "image/SiteWork.Planting.Grass.Bermuda1.DDS"

View File

@ -667,24 +667,24 @@ channel const node_channel_node_light_translation_z = {
.target_attribute = target_attribute::Z, .target_attribute = target_attribute::Z,
}; };
// image_index: 0 // american_cherry_png
image const image_american_cherry_png = { image const image_american_cherry_png = {
.resource_name = L"AMERICAN_CHERRY_PNG", .resource_name = L"_AMERICAN_CHERRY_PNG",
}; };
// image_index: 1 // _02_png
image const image__02_png = { image const image__02_png = {
.resource_name = L"102_PNG", .resource_name = L"_102_PNG",
}; };
// image_index: 2 // Finishes_Flooring_Tile_Square_Medium_Blue_png
image const image_finishes_flooring_tile_square_medium_blue_png = { image const image_finishes_flooring_tile_square_medium_blue_png = {
.resource_name = L"FINISHES_FLOORING_TILE_SQUARE_MEDIUM_BLUE_PNG", .resource_name = L"_FINISHES_FLOORING_TILE_SQUARE_MEDIUM_BLUE_PNG",
}; };
// image_index: 3 // SiteWork_Planting_Grass_Bermuda1_jpg
image const image_sitework_planting_grass_bermuda1_jpg = { image const image_sitework_planting_grass_bermuda1_jpg = {
.resource_name = L"SITEWORK_PLANTING_GRASS_BERMUDA1_JPG", .resource_name = L"_SITEWORK_PLANTING_GRASS_BERMUDA1_JPG",
}; };
image const * const images[] = { image const * const images[] = {
@ -945,7 +945,7 @@ effect const effect_grass = {
}, },
.diffuse = { .diffuse = {
.type = color_or_texture_type::TEXTURE, .type = color_or_texture_type::TEXTURE,
.texture = { .image_index = 3 }, .texture = { .image_index = 3 }, // SiteWork_Planting_Grass_Bermuda1_jpg
}, },
.specular = { .specular = {
.type = color_or_texture_type::COLOR, .type = color_or_texture_type::COLOR,
@ -979,11 +979,11 @@ effect const effect_wood = {
}, },
.diffuse = { .diffuse = {
.type = color_or_texture_type::TEXTURE, .type = color_or_texture_type::TEXTURE,
.texture = { .image_index = 0 }, .texture = { .image_index = 0 }, // american_cherry_png
}, },
.specular = { .specular = {
.type = color_or_texture_type::TEXTURE, .type = color_or_texture_type::TEXTURE,
.texture = { .image_index = 2 }, .texture = { .image_index = 2 }, // Finishes_Flooring_Tile_Square_Medium_Blue_png
}, },
.shininess = 10.0f, .shininess = 10.0f,
.reflective = { .reflective = {
@ -1629,9 +1629,9 @@ instance_light const instance_lights_node_geosphere[] = {
}; };
channel const * const node_channels_node_geosphere[] = { channel const * const node_channels_node_geosphere[] = {
&node_channel_node_geosphere_scale,
&node_channel_node_geosphere_inversescaleaxisrotation, &node_channel_node_geosphere_inversescaleaxisrotation,
&node_channel_node_geosphere_scaleaxisrotation, &node_channel_node_geosphere_scaleaxisrotation,
&node_channel_node_geosphere_scale,
}; };
node const node_node_geosphere = { node const node_node_geosphere = {
@ -1670,8 +1670,8 @@ instance_light const instance_lights_node_light[] = {
channel const * const node_channels_node_light[] = { channel const * const node_channels_node_light[] = {
&node_channel_node_light_translation_z, &node_channel_node_light_translation_z,
&node_channel_node_light_translation_x,
&node_channel_node_light_translation_y, &node_channel_node_light_translation_y,
&node_channel_node_light_translation_x,
}; };
node const node_node_light = { node const node_node_light = {