Skip to content

Commit

Permalink
Parse H2 .light tags and generate them in Blender scenario imports
Browse files Browse the repository at this point in the history
  • Loading branch information
General-101 committed Oct 26, 2024
1 parent 001f25d commit ae0062c
Show file tree
Hide file tree
Showing 8 changed files with 394 additions and 88 deletions.
139 changes: 69 additions & 70 deletions io_scene_halo/file_tag/build_scene/build_lightmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,76 +64,75 @@ def process_mesh(SBSP_ASSET, random_color_gen, tag_block, poop_name, material_co

triangle_start = 0
for part in render_data.parts:
if not PartTypeEnum.transparent.value == part.part_type:
strip_length = part.strip_length
strip_start = part.strip_start_index

triangle_indices = render_data.strip_indices[strip_start : (strip_start + strip_length)]
triangle_length = int(len(triangle_indices) / 3)
for idx in range(triangle_length):
triangle_index = (idx * 3)
v0 = triangle_indices[triangle_index]
v1 = triangle_indices[triangle_index + 1]
v2 = triangle_indices[triangle_index + 2]

vertex_list = [render_data.raw_vertices[v0], render_data.raw_vertices[v1], render_data.raw_vertices[v2]]
for vertex_idx, vertex in enumerate(vertex_list):
loop_index = (triangle_start * 3) + triangle_index + vertex_idx

U0 = vertex.texcoord[0]
V0 = vertex.texcoord[1]
U1 = vertex.primary_lightmap_texcoord[0]
V1 = vertex.primary_lightmap_texcoord[1]

render_layer_uv.data[loop_index].uv = (U0, 1 - V0)
lightmap_layer_uv.data[loop_index].uv = (U1, V1)

material = None
if not part.material_index == -1 and material_count > 0 and part.material_index < material_count:
material = SBSP_ASSET.materials[part.material_index]

if material:
material_path = material.shader.name
if global_functions.string_empty_check(material_path):
material_path = material.old_shader.name

material_directory = os.path.dirname(material_path)
material_name = os.path.basename(material_path)

collection_prefix = shader_collection_dic.get(material_directory)
if not collection_prefix == None:
material_name = "%s %s" % (collection_prefix, material_name)
else:
print("Could not find a collection for: %s" % material_path)

for material_property in material.properties:
property_enum = PropertyTypeEnum(material_property.property_type)
property_value = material_property.real_value
if PropertyTypeEnum.lightmap_resolution == property_enum:
material_name += " lm:%s" % property_value

elif PropertyTypeEnum.lightmap_power == property_enum:
material_name += " lp:%s" % property_value

elif PropertyTypeEnum.lightmap_half_life == property_enum:
material_name += " hl:%s" % property_value

elif PropertyTypeEnum.lightmap_diffuse_scale == property_enum:
material_name += " ds:%s" % property_value

mat = bpy.data.materials.get(material_name)
if mat is None:
mat = bpy.data.materials.new(name=material_name)

if not mat in mesh.materials.values():
mesh.materials.append(mat)

mat.diffuse_color = random_color_gen.next()
material_index = mesh.materials.values().index(mat)
for triangle_idx in range(triangle_length):
mesh.polygons[triangle_start + triangle_idx].material_index = material_index

triangle_start += triangle_length
strip_length = part.strip_length
strip_start = part.strip_start_index

triangle_indices = render_data.strip_indices[strip_start : (strip_start + strip_length)]
triangle_length = int(len(triangle_indices) / 3)
for idx in range(triangle_length):
triangle_index = (idx * 3)
v0 = triangle_indices[triangle_index]
v1 = triangle_indices[triangle_index + 1]
v2 = triangle_indices[triangle_index + 2]

vertex_list = [render_data.raw_vertices[v0], render_data.raw_vertices[v1], render_data.raw_vertices[v2]]
for vertex_idx, vertex in enumerate(vertex_list):
loop_index = (triangle_start * 3) + triangle_index + vertex_idx

U0 = vertex.texcoord[0]
V0 = vertex.texcoord[1]
U1 = vertex.primary_lightmap_texcoord[0]
V1 = vertex.primary_lightmap_texcoord[1]

render_layer_uv.data[loop_index].uv = (U0, 1 - V0)
lightmap_layer_uv.data[loop_index].uv = (U1, V1)

material = None
if not part.material_index == -1 and material_count > 0 and part.material_index < material_count:
material = SBSP_ASSET.materials[part.material_index]

if material:
material_path = material.shader.name
if global_functions.string_empty_check(material_path):
material_path = material.old_shader.name

material_directory = os.path.dirname(material_path)
material_name = os.path.basename(material_path)

collection_prefix = shader_collection_dic.get(material_directory)
if not collection_prefix == None:
material_name = "%s %s" % (collection_prefix, material_name)
else:
print("Could not find a collection for: %s" % material_path)

for material_property in material.properties:
property_enum = PropertyTypeEnum(material_property.property_type)
property_value = material_property.real_value
if PropertyTypeEnum.lightmap_resolution == property_enum:
material_name += " lm:%s" % property_value

elif PropertyTypeEnum.lightmap_power == property_enum:
material_name += " lp:%s" % property_value

elif PropertyTypeEnum.lightmap_half_life == property_enum:
material_name += " hl:%s" % property_value

elif PropertyTypeEnum.lightmap_diffuse_scale == property_enum:
material_name += " ds:%s" % property_value

mat = bpy.data.materials.get(material_name)
if mat is None:
mat = bpy.data.materials.new(name=material_name)

if not mat in mesh.materials.values():
mesh.materials.append(mat)

mat.diffuse_color = random_color_gen.next()
material_index = mesh.materials.values().index(mat)
for triangle_idx in range(triangle_length):
mesh.polygons[triangle_start + triangle_idx].material_index = material_index

triangle_start += triangle_length

return mesh

Expand Down
57 changes: 57 additions & 0 deletions io_scene_halo/file_tag/build_scene/generate_h2_scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from ..h2.file_scenario.format import DataTypesEnum, ObjectFlags, ClassificationEnum
from . import build_lightmap as build_scene_lightmap
from ..h2.file_scenario.mesh_helper.build_mesh import get_object
from ...file_tag.h2.file_light.format import ShapeTypeEnum, DefaultLightmapSettingEnum

def generate_skies(context, level_root, tag_block, report):
asset_collection = bpy.data.collections.get("Skies")
Expand Down Expand Up @@ -272,6 +273,60 @@ def generate_object_elements(level_root, collection_name, palette, tag_block, co
if not ob == None:
bpy.data.objects.remove(ob, do_unlink=True)

def generate_light_volumes_elements(level_root, collection_name, palette, tag_block, context, game_version, file_version, fix_rotations, report, random_color_gen):
asset_collection = bpy.data.collections.get(collection_name)
if asset_collection == None:
asset_collection = bpy.data.collections.new(collection_name)
context.scene.collection.children.link(asset_collection)

asset_collection.hide_render = False

light_data = []
light_tags = []
for palette_idx, palette_element in enumerate(palette):
light_name = "%s_%s" % (os.path.basename(palette_element.name), palette_idx)
ASSET = parse_tag(palette_element, report, "halo2", "retail")
light_shape_type = ShapeTypeEnum(ASSET.shape_type)
if light_shape_type == ShapeTypeEnum.sphere:
light_type = "POINT"
elif light_shape_type == ShapeTypeEnum.orthogonal:
light_type = "AREA"
else:
light_type = "SPOT"

light = bpy.data.lights.new(light_name, light_type)
if light_shape_type == ShapeTypeEnum.orthogonal:
light.shape = 'SQUARE'

light_data.append(light)
light_tags.append(ASSET)

for element in tag_block:
pallete_item = light_tags[element.palette_index]
emission_setting = DefaultLightmapSettingEnum(pallete_item.default_lightmap_setting)
if not emission_setting == DefaultLightmapSettingEnum.dynamic_only:
light_name = "%s_%s" % (os.path.basename(palette_element.name), palette_idx)

light_data_element = light_data[element.palette_index]
root = bpy.data.objects.new(light_name, light_data_element)
asset_collection.objects.link(root)

root.parent = level_root
root.location = element.position * 100
ob_scale = element.scale
if ob_scale > 0.0:
root.scale = (ob_scale, ob_scale, ob_scale)

rotation = Euler((radians(0.0), radians(0.0), radians(0.0)), 'XYZ')
roll = Euler((radians(element.rotation[2]), radians(0.0), radians(0.0)), 'XYZ')
pitch = Euler((radians(0.0), -radians(element.rotation[1]), radians(0.0)), 'XYZ')
yaw = Euler((radians(0.0), radians(0.0), radians(element.rotation[0])), 'XYZ')
rotation.rotate(yaw)
rotation.rotate(pitch)
rotation.rotate(roll)

root.rotation_euler = rotation

def generate_netgame_equipment_elements(level_root, tag_block, context, game_version, file_version, fix_rotations, report, random_color_gen):
asset_collection = bpy.data.collections.get("Netgame Equipment")
if asset_collection == None:
Expand Down Expand Up @@ -791,6 +846,8 @@ def generate_scenario_scene(context, H2_ASSET, game_version, game_title, file_ve
generate_object_elements(level_root, "Crates", H2_ASSET.crates_palette, H2_ASSET.crates, context, game_version, file_version, fix_rotations, report, random_color_gen)
if len(H2_ASSET.creatures) > 0:
generate_object_elements(level_root, "Creatures", H2_ASSET.creatures_palette, H2_ASSET.creatures, context, game_version, file_version, fix_rotations, report, random_color_gen)
if len(H2_ASSET.light_volumes) > 0:
generate_light_volumes_elements(level_root, "Lights", H2_ASSET.light_volume_palette, H2_ASSET.light_volumes, context, game_version, file_version, fix_rotations, report, random_color_gen)
if len(H2_ASSET.player_starting_locations) > 0:
generate_empties(context, level_root, "Player Starting Locations", H2_ASSET.player_starting_locations)
if len(H2_ASSET.netgame_flags) > 0:
Expand Down
11 changes: 0 additions & 11 deletions io_scene_halo/file_tag/h2/file_light/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#
# ##### END MIT LICENSE BLOCK #####

from mathutils import Vector
from enum import Flag, Enum, auto

class LightFlags(Flag):
Expand Down Expand Up @@ -111,16 +110,6 @@ class EffectFalloffFunctionEnum(Enum):
zero = auto()
one = auto()

class EffectFalloffFunctionEnum(Enum):
linear = 0
late = auto()
very_late = auto()
early = auto()
very_early = auto()
cosine = auto()
zero = auto()
one = auto()

class FadeEnum(Enum):
fade_very_far = 0
fade_far = auto()
Expand Down
Loading

0 comments on commit ae0062c

Please sign in to comment.