|
|
@ -660,7 +660,7 @@ class PlasmaLinkingBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz |
|
|
|
share.link_input(share_anim_stage, "stage", "stage_refs") |
|
|
|
share.link_input(share_anim_stage, "stage", "stage_refs") |
|
|
|
share.link_output(linkingnode, "hosts", "shareBookSeek") |
|
|
|
share.link_output(linkingnode, "hosts", "shareBookSeek") |
|
|
|
|
|
|
|
|
|
|
|
def sanity_check(self): |
|
|
|
def sanity_check(self, exporter): |
|
|
|
if self.clickable is None: |
|
|
|
if self.clickable is None: |
|
|
|
raise ExportError("{}: Linking Book modifier requires a clickable!", self.id_data.name) |
|
|
|
raise ExportError("{}: Linking Book modifier requires a clickable!", self.id_data.name) |
|
|
|
if self.seek_point is None: |
|
|
|
if self.seek_point is None: |
|
|
@ -724,88 +724,18 @@ class PlasmaNotePopupModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz): |
|
|
|
if self.id_data.type == "MESH": |
|
|
|
if self.id_data.type == "MESH": |
|
|
|
return self.id_data |
|
|
|
return self.id_data |
|
|
|
|
|
|
|
|
|
|
|
def sanity_check(self): |
|
|
|
def sanity_check(self, exporter: Exporter): |
|
|
|
page_type = helpers.get_page_type(self.id_data.plasma_object.page) |
|
|
|
page_type = helpers.get_page_type(self.id_data.plasma_object.page) |
|
|
|
if page_type != "room": |
|
|
|
if page_type != "room": |
|
|
|
raise ExportError(f"Note Popup modifiers should be in a 'room' page, not a '{page_type}' page!") |
|
|
|
raise ExportError(f"Note Popup modifiers should be in a 'room' page, not a '{page_type}' page!") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# It's OK if multiple note popups point to the same GUI page, |
|
|
|
|
|
|
|
# they just need to have the same camera. |
|
|
|
|
|
|
|
exporter.gui.check_pre_export(self.gui_page, pl_id="note_popup", camera=self.gui_camera) |
|
|
|
|
|
|
|
|
|
|
|
def pre_export(self, exporter: Exporter, bo: bpy.types.Object): |
|
|
|
def pre_export(self, exporter: Exporter, bo: bpy.types.Object): |
|
|
|
guidialog_object = utils.create_empty_object(f"{self.gui_page}_NoteDialog") |
|
|
|
# The GUI converter will debounce duplicate GUI dialogs. |
|
|
|
guidialog_object.plasma_object.enabled = True |
|
|
|
yield from exporter.gui.create_note_gui(self.gui_page, self.gui_camera) |
|
|
|
guidialog_object.plasma_object.page = self.gui_page |
|
|
|
|
|
|
|
yield guidialog_object |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
guidialog_mod: PlasmaGameGuiDialogModifier = guidialog_object.plasma_modifiers.gui_dialog |
|
|
|
|
|
|
|
guidialog_mod.enabled = True |
|
|
|
|
|
|
|
guidialog_mod.is_modal = True |
|
|
|
|
|
|
|
if self.gui_camera: |
|
|
|
|
|
|
|
guidialog_mod.camera_object = self.gui_camera |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
# Abuse the GUI Dialog's lookat caLculation to make us a camera that looks at everything |
|
|
|
|
|
|
|
# the artist has placed into the GUI page. We want to do this NOW because we will very |
|
|
|
|
|
|
|
# soon be adding more objects into the GUI page. |
|
|
|
|
|
|
|
camera_object = yield utils.create_camera_object(f"{self.key_name}_GUICamera") |
|
|
|
|
|
|
|
camera_object.data.angle = math.radians(45.0) |
|
|
|
|
|
|
|
camera_object.data.lens_unit = "FOV" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
visible_objects = [ |
|
|
|
|
|
|
|
i for i in exporter.get_objects(self.gui_page) |
|
|
|
|
|
|
|
if i.type == "MESH" and i.data.materials |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
camera_object.matrix_world = exporter.gui.calc_camera_matrix( |
|
|
|
|
|
|
|
bpy.context.scene, |
|
|
|
|
|
|
|
visible_objects, |
|
|
|
|
|
|
|
camera_object.data.angle |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
clipping = exporter.gui.calc_clipping( |
|
|
|
|
|
|
|
camera_object.matrix_world, |
|
|
|
|
|
|
|
bpy.context.scene, |
|
|
|
|
|
|
|
visible_objects, |
|
|
|
|
|
|
|
camera_object.data.angle |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
camera_object.data.clip_start = clipping.hither |
|
|
|
|
|
|
|
camera_object.data.clip_end = clipping.yonder |
|
|
|
|
|
|
|
guidialog_mod.camera_object = camera_object |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Begin creating the object for the clickoff plane. We want to yield it immediately |
|
|
|
|
|
|
|
# to the exporter in case something goes wrong during the export, allowing the stale |
|
|
|
|
|
|
|
# object to be cleaned up. |
|
|
|
|
|
|
|
click_plane_object = utils.BMeshObject(f"{self.key_name}_Exit") |
|
|
|
|
|
|
|
click_plane_object.matrix_world = guidialog_mod.camera_object.matrix_world |
|
|
|
|
|
|
|
click_plane_object.plasma_object.enabled = True |
|
|
|
|
|
|
|
click_plane_object.plasma_object.page = self.gui_page |
|
|
|
|
|
|
|
yield click_plane_object |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# We have a camera on guidialog_mod.camera_object. We will now use it to generate the |
|
|
|
|
|
|
|
# points for the click-off plane button. |
|
|
|
|
|
|
|
# TODO: Allow this to be configurable to 4:3, 16:9, or 21:9? |
|
|
|
|
|
|
|
with ExitStack() as stack: |
|
|
|
|
|
|
|
stack.enter_context(exporter.gui.generate_camera_render_settings(bpy.context.scene)) |
|
|
|
|
|
|
|
toggle = stack.enter_context(helpers.GoodNeighbor()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Temporarily adjust the clipping plane out to the farthest point we can find to ensure |
|
|
|
|
|
|
|
# that the click-off button ecompasses everything. This is a bit heavy-handed, but if |
|
|
|
|
|
|
|
# you want more refined control, you won't be using this helper. |
|
|
|
|
|
|
|
clipping = max((guidialog_mod.camera_object.data.clip_start, guidialog_mod.camera_object.data.clip_end)) |
|
|
|
|
|
|
|
toggle.track(guidialog_mod.camera_object.data, "clip_start", clipping - 0.1) |
|
|
|
|
|
|
|
view_frame = guidialog_mod.camera_object.data.view_frame(bpy.context.scene) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
click_plane_object.data.materials.append(exporter.gui.transparent_material) |
|
|
|
|
|
|
|
with click_plane_object as click_plane_mesh: |
|
|
|
|
|
|
|
verts = [click_plane_mesh.verts.new(i) for i in view_frame] |
|
|
|
|
|
|
|
face = click_plane_mesh.faces.new(verts) |
|
|
|
|
|
|
|
# TODO: Ensure the face is pointing toward the camera! |
|
|
|
|
|
|
|
# I feel like we should be fine by assuming that Blender returns the viewframe |
|
|
|
|
|
|
|
# verts in the correct order, but this is Blender... So test that assumption carefully. |
|
|
|
|
|
|
|
# TODO: Apparently not! |
|
|
|
|
|
|
|
face.normal_flip() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# We've now created the mesh object - handle the GUI Button stuff |
|
|
|
|
|
|
|
click_plane_object.plasma_modifiers.gui_button.enabled = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# NOTE: We will be using xDialogToggle.py, so we use a special tag ID instead of the |
|
|
|
|
|
|
|
# close dialog procedure. |
|
|
|
|
|
|
|
click_plane_object.plasma_modifiers.gui_control.tag_id = 99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Auto-generate a six-foot cube region around the clickable if none was provided. |
|
|
|
# Auto-generate a six-foot cube region around the clickable if none was provided. |
|
|
|
if self.clickable_region is None: |
|
|
|
if self.clickable_region is None: |
|
|
|