Skip to content

Commit

Permalink
We have the convience factor of TEXTURE doing something. Bumps versio…
Browse files Browse the repository at this point in the history
…n, we're ready for public comment!
  • Loading branch information
tngreene committed Nov 3, 2021
1 parent df7b69d commit 30a93ab
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 22 deletions.
2 changes: 1 addition & 1 deletion io_xplane2blender/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"name": "Import-Export: X-Plane (.obj)",
"description": "Import and Export X-Plane objects/planes (.obj format)",
"author": "Ted Greene, Ben Supnik",
"version": (4, 1, 0),
"version": (4, 2, 0),
"blender": (2, 80, 0),
"location": "File > Import/Export > X-Plane",
"warning": "",
Expand Down
12 changes: 10 additions & 2 deletions io_xplane2blender/importer/xplane_imp_cmd_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,6 @@ def chunk(it, size):
self.datablock_info,
mesh_src=me,
)
test_creation_helpers.set_material(ob, "Material")

return ob
else:
Expand Down Expand Up @@ -427,6 +426,9 @@ def __init__(self, filepath: Path):

self.root_collection.xplane.is_exportable_collection = True
self.vt_table = VTTable([], [])
self.texture: Optional[Path] = None
# self.texture_lit:Optional[Path] = Path()
# self.texture_normal:Optiona[Path] = Path()

# Although we don't end up making this, it is useful for tree problems
self.root_intermediate_datablock = IntermediateDatablock(
Expand Down Expand Up @@ -1128,13 +1130,19 @@ def fill_in_eulers(

if out_block.datablock_type == "EMPTY":
ob = test_creation_helpers.create_datablock_empty(
out_block.datablock_info
out_block.datablock_info,
empty_display_size=0.05,
)
elif out_block.datablock_type == "MESH":
try:
ob = out_block.build_mesh(self.vt_table)
except ValueError:
ob = None
else:
if self.texture:
test_creation_helpers.set_material(
ob, "Material", texture_image=self.texture
)

if ob:
ob.matrix_local = out_block.bake_matrix.copy()
Expand Down
13 changes: 12 additions & 1 deletion io_xplane2blender/importer/xplane_imp_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import pathlib
import re
from dataclasses import dataclass, field
from pathlib import Path
from pprint import pprint
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

Expand Down Expand Up @@ -143,7 +144,17 @@ def scan_float(s_itr:iter)
# def scan_(last=False, msg_missing=f"Could not convert parameter {lineno} _true, default=None)->value:
# Throws parser error if needed
# def _try to swallow all exceptions if the only thing that should happen is the line getting ignored on bad data. Otherwise we can go into more crazy exception hanlding cases
if directive == "VT":
if directive == "TEXTURE":
try:
texture_path = (filepath.parent / Path(components[0])).resolve()
except IndexError:
logger.warn(f"TEXTURE directive given but was empty")
else:
if texture_path.exists():
builder.texture = texture_path
else:
logger.warn(f"'{str(texture_path)}' is not a real file")
elif directive == "VT":
components[:3] = vec_x_to_b(list(map(float, components[:3])))
components[3:6] = vec_x_to_b(list(map(float, components[3:6])))
components[6:8] = list(map(float, components[6:8]))
Expand Down
74 changes: 57 additions & 17 deletions io_xplane2blender/tests/test_creation_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import typing
from collections import namedtuple
from dataclasses import dataclass
from pathlib import Path
from typing import *

import bpy
Expand Down Expand Up @@ -455,6 +456,8 @@ def create_datablock_armature(
def create_datablock_empty(
info: DatablockInfo,
scene: Optional[Union[bpy.types.Scene, str]] = None,
empty_display_type: str = "PLAIN_AXES",
empty_display_size=1,
) -> bpy.types.Object:
"""
Creates a datablock empty and links it to a scene and collection.
Expand All @@ -468,7 +471,8 @@ def create_datablock_empty(
scene = bpy.context.scene
set_collection(ob, info.collection)

ob.empty_display_type = "PLAIN_AXES"
ob.empty_display_type = empty_display_type
ob.empty_display_size = empty_display_size
ob.location = info.location
ob.rotation_mode = info.rotation_mode
set_rotation(ob, info.rotation, info.rotation_mode)
Expand Down Expand Up @@ -620,30 +624,38 @@ def create_datablock_light(
return ob


def create_image_from_disk(
filename: str, filepath: str = "//tex/{}"
) -> bpy.types.Image:
def create_image_from_disk(filepath: Union[Path, str]) -> bpy.types.Image:
"""
Create an image from a .png file on disk.
Returns image or raises OSError
"""
assert os.path.splitext(filename)[1] == ".png"
filepath = str(filepath)
assert os.path.splitext(filepath)[1] in {".dds", ".png"}
# Load image file. Change here if the snippet folder is
# not located in you home directory.
realpath = bpy.path.abspath(filepath.format(filename))
realpath = bpy.path.abspath(filepath.format(filepath))
try:
img = bpy.data.images.load(realpath)
img = bpy.data.images.load(realpath, check_existing=True)
img.filepath = bpy.path.relpath(realpath)
return img
except (RuntimeError, ValueError): # Couldn't load or make relative path
raise OSError("Cannot load image %s" % realpath)


def create_material(material_name: str):
def create_material(
material_name: str,
texture_image: Optional[Union[bpy.types.Image, Path, str]] = None,
):
"""
Create a material and optionally give it a texture
"""
try:
return bpy.data.materials[material_name]
except:
return bpy.data.materials.new(material_name)
mat = get_material(material_name)
except KeyError:
mat = bpy.data.materials.new(material_name)

return mat


def create_material_default() -> bpy.types.Material:
Expand All @@ -664,6 +676,10 @@ def create_scene(name: str) -> bpy.types.Scene:
def get_image(name: str) -> Optional[bpy.types.Image]:
"""
New images will be created in //tex and will be a .png
TODO: This API is incomplete, what if None found? What should happen?
Creating a new image is almost never what you want, unlike creating a bland cube
I vote KeyError which makes this a useless wrapper
"""
return bpy.data.images.get(name)

Expand Down Expand Up @@ -915,7 +931,8 @@ def set_animation_data(
else:
dataref_prop.value = kf_info.dataref_value
# Multiple assignment isn't harmful
dataref_prop.loop = kf_info.dataref_loop
if kf_info.dataref_loop is not None:
dataref_prop.loop = kf_info.dataref_loop

if not kf_info.location and not kf_info.rotation:
continue
Expand Down Expand Up @@ -1027,18 +1044,41 @@ def set_manipulator_settings(
def set_material(
blender_object: bpy.types.Object,
material_name: str = "Material",
material_props: Optional[Dict[str, Any]] = None,
create_missing: bool = True,
texture_image: Optional[Union[bpy.types.Image, Path, str]] = None,
):
"""
Sets blender_object's 1st material slot to 'material_name'.
Optionally a texture_image is used to set up a basic
shader with Base Color set to Image Texture
Raises OSError if texture_image is a path and not a real image
"""

mat = create_material(material_name)
try:
blender_object.material_slots[0].material = mat
except IndexError:
blender_object.data.materials.append(mat)
if material_props:
for prop, value in material_props.items():
setattr(mat.xplane.manip, prop, value)

if texture_image:
mat.use_nodes = True
tex_node = mat.node_tree.nodes.new("ShaderNodeTexImage")
if isinstance(texture_image, bpy.types.Image):
tex_node.image = texture_image
elif isinstance(texture_image, Path) or texture_image.endswith(
(".png", ".dds")
):
tex_node.image = create_image_from_disk(texture_image)
else:
tex_node.image = get_image(texture_image)

bsdf_node = mat.node_tree.nodes["Principled BSDF"]

# TODO: We should make it nice and move it so it isn't overlapping
mat.node_tree.links.new(
tex_node.outputs["Color"], bsdf_node.inputs["Base Color"]
)


def set_parent(blender_object: bpy.types.Object, parent_info: ParentInfo) -> None:
Expand Down
2 changes: 1 addition & 1 deletion io_xplane2blender/xplane_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
CURRENT_ADDON_VERSION: Tuple[int, int, int] = bl_info["version"]

# The current build type, must be a member of XPlane2BlenderVersion.BUILD_TYPE
CURRENT_BUILD_TYPE = xplane_constants.BUILD_TYPE_BETA
CURRENT_BUILD_TYPE = xplane_constants.BUILD_TYPE_ALPHA

# The current build type version, must be > 0
# if not BUILD_TYPE_DEV or BULD_TYPE_LEGACY
Expand Down

0 comments on commit 30a93ab

Please sign in to comment.