MaterialEditor BasicTests added to AutomatedTesting for AR (#3022)
* MaterialEditor BasicTests added to AutomatedTesting for AR Signed-off-by: Scott Murray <scottmur@amazon.com> * launch_and_validate_results adding a waiter.wait_for to the log monitor so the log file exists Signed-off-by: Scott Murray <scottmur@amazon.com>
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
"""
|
||||
Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
import azlmbr.materialeditor will fail with a ModuleNotFound error when using this script with Editor.exe
|
||||
This is because azlmbr.materialeditor only binds to MaterialEditor.exe and not Editor.exe
|
||||
You need to launch this script with MaterialEditor.exe in order for azlmbr.materialeditor to appear.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import azlmbr.atom
|
||||
import azlmbr.materialeditor as materialeditor
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.atomtools.general as general
|
||||
|
||||
|
||||
def is_close(actual, expected, buffer=sys.float_info.min):
|
||||
"""
|
||||
:param actual: actual value
|
||||
:param expected: expected value
|
||||
:param buffer: acceptable variation from expected
|
||||
:return: bool
|
||||
"""
|
||||
return abs(actual - expected) < buffer
|
||||
|
||||
|
||||
def compare_colors(color1, color2, buffer=0.00001):
|
||||
"""
|
||||
Compares the red, green and blue properties of a color allowing a slight variance of buffer
|
||||
:param color1: first color to compare
|
||||
:param color2: second color
|
||||
:param buffer: allowed variance in individual color value
|
||||
:return: bool
|
||||
"""
|
||||
return (
|
||||
is_close(color1.r, color2.r, buffer)
|
||||
and is_close(color1.g, color2.g, buffer)
|
||||
and is_close(color1.b, color2.b, buffer)
|
||||
)
|
||||
|
||||
|
||||
def open_material(file_path):
|
||||
"""
|
||||
:return: uuid of material document opened
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "OpenDocument", file_path)
|
||||
|
||||
|
||||
def is_open(document_id):
|
||||
"""
|
||||
:return: bool
|
||||
"""
|
||||
return materialeditor.MaterialDocumentRequestBus(bus.Event, "IsOpen", document_id)
|
||||
|
||||
|
||||
def save_document(document_id):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "SaveDocument", document_id)
|
||||
|
||||
|
||||
def save_document_as_copy(document_id, target_path):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(
|
||||
bus.Broadcast, "SaveDocumentAsCopy", document_id, target_path
|
||||
)
|
||||
|
||||
|
||||
def save_document_as_child(document_id, target_path):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(
|
||||
bus.Broadcast, "SaveDocumentAsChild", document_id, target_path
|
||||
)
|
||||
|
||||
|
||||
def save_all():
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "SaveAllDocuments")
|
||||
|
||||
|
||||
def close_document(document_id):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "CloseDocument", document_id)
|
||||
|
||||
|
||||
def close_all_documents():
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "CloseAllDocuments")
|
||||
|
||||
|
||||
def close_all_except_selected(document_id):
|
||||
"""
|
||||
:return: bool success
|
||||
"""
|
||||
return materialeditor.MaterialDocumentSystemRequestBus(bus.Broadcast, "CloseAllDocumentsExcept", document_id)
|
||||
|
||||
|
||||
def get_property(document_id, property_name):
|
||||
"""
|
||||
:return: property value or invalid value if the document is not open or the property_name can't be found
|
||||
"""
|
||||
return materialeditor.MaterialDocumentRequestBus(bus.Event, "GetPropertyValue", document_id, property_name)
|
||||
|
||||
|
||||
def set_property(document_id, property_name, value):
|
||||
materialeditor.MaterialDocumentRequestBus(bus.Event, "SetPropertyValue", document_id, property_name, value)
|
||||
|
||||
|
||||
def is_pane_visible(pane_name):
|
||||
"""
|
||||
:return: bool
|
||||
"""
|
||||
return materialeditor.MaterialEditorWindowRequestBus(bus.Broadcast, "IsDockWidgetVisible", pane_name)
|
||||
|
||||
|
||||
def set_pane_visibility(pane_name, value):
|
||||
materialeditor.MaterialEditorWindowRequestBus(bus.Broadcast, "SetDockWidgetVisible", pane_name, value)
|
||||
|
||||
|
||||
def select_lighting_config(config_name):
|
||||
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "SelectLightingPresetByName", config_name)
|
||||
|
||||
|
||||
def set_grid_enable_disable(value):
|
||||
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "SetGridEnabled", value)
|
||||
|
||||
|
||||
def get_grid_enable_disable():
|
||||
"""
|
||||
:return: bool
|
||||
"""
|
||||
return azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "GetGridEnabled")
|
||||
|
||||
|
||||
def set_shadowcatcher_enable_disable(value):
|
||||
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "SetShadowCatcherEnabled", value)
|
||||
|
||||
|
||||
def get_shadowcatcher_enable_disable():
|
||||
"""
|
||||
:return: bool
|
||||
"""
|
||||
return azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "GetShadowCatcherEnabled")
|
||||
|
||||
|
||||
def select_model_config(configname):
|
||||
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "SelectModelPresetByName", configname)
|
||||
|
||||
|
||||
def wait_for_condition(function, timeout_in_seconds=1.0):
|
||||
# type: (function, float) -> bool
|
||||
"""
|
||||
Function to run until it returns True or timeout is reached
|
||||
the function can have no parameters and
|
||||
waiting idle__wait_* is handled here not in the function
|
||||
|
||||
:param function: a function that returns a boolean indicating a desired condition is achieved
|
||||
:param timeout_in_seconds: when reached, function execution is abandoned and False is returned
|
||||
"""
|
||||
with Timeout(timeout_in_seconds) as t:
|
||||
while True:
|
||||
try:
|
||||
general.idle_wait_frames(1)
|
||||
except Exception:
|
||||
print("WARNING: Couldn't wait for frame")
|
||||
|
||||
if t.timed_out:
|
||||
return False
|
||||
|
||||
ret = function()
|
||||
if not isinstance(ret, bool):
|
||||
raise TypeError("return value for wait_for_condition function must be a bool")
|
||||
if ret:
|
||||
return True
|
||||
|
||||
|
||||
class Timeout:
|
||||
# type: (float) -> None
|
||||
"""
|
||||
contextual timeout
|
||||
:param seconds: float seconds to allow before timed_out is True
|
||||
"""
|
||||
|
||||
def __init__(self, seconds):
|
||||
self.seconds = seconds
|
||||
|
||||
def __enter__(self):
|
||||
self.die_after = time.time() + self.seconds
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
pass
|
||||
|
||||
@property
|
||||
def timed_out(self):
|
||||
return time.time() > self.die_after
|
||||
|
||||
|
||||
screenshotsFolder = os.path.join(azlmbr.paths.devroot, "AtomTest", "Cache" "pc", "Screenshots")
|
||||
|
||||
|
||||
class ScreenshotHelper:
|
||||
"""
|
||||
A helper to capture screenshots and wait for them.
|
||||
"""
|
||||
|
||||
def __init__(self, idle_wait_frames_callback):
|
||||
super().__init__()
|
||||
self.done = False
|
||||
self.capturedScreenshot = False
|
||||
self.max_frames_to_wait = 60
|
||||
|
||||
self.idle_wait_frames_callback = idle_wait_frames_callback
|
||||
|
||||
def capture_screenshot_blocking(self, filename):
|
||||
"""
|
||||
Capture a screenshot and block the execution until the screenshot has been written to the disk.
|
||||
"""
|
||||
self.handler = azlmbr.atom.FrameCaptureNotificationBusHandler()
|
||||
self.handler.connect()
|
||||
self.handler.add_callback("OnCaptureFinished", self.on_screenshot_captured)
|
||||
|
||||
self.done = False
|
||||
self.capturedScreenshot = False
|
||||
success = azlmbr.atom.FrameCaptureRequestBus(azlmbr.bus.Broadcast, "CaptureScreenshot", filename)
|
||||
if success:
|
||||
self.wait_until_screenshot()
|
||||
print("Screenshot taken.")
|
||||
else:
|
||||
print("screenshot failed")
|
||||
return self.capturedScreenshot
|
||||
|
||||
def on_screenshot_captured(self, parameters):
|
||||
# the parameters come in as a tuple
|
||||
if parameters[0]:
|
||||
print("screenshot saved: {}".format(parameters[1]))
|
||||
self.capturedScreenshot = True
|
||||
else:
|
||||
print("screenshot failed: {}".format(parameters[1]))
|
||||
self.done = True
|
||||
self.handler.disconnect()
|
||||
|
||||
def wait_until_screenshot(self):
|
||||
frames_waited = 0
|
||||
while self.done == False:
|
||||
self.idle_wait_frames_callback(1)
|
||||
if frames_waited > self.max_frames_to_wait:
|
||||
print("timeout while waiting for the screenshot to be written")
|
||||
self.handler.disconnect()
|
||||
break
|
||||
else:
|
||||
frames_waited = frames_waited + 1
|
||||
print("(waited {} frames)".format(frames_waited))
|
||||
|
||||
|
||||
def capture_screenshot(file_path):
|
||||
return ScreenshotHelper(azlmbr.atomtools.general.idle_wait_frames).capture_screenshot_blocking(
|
||||
os.path.join(file_path)
|
||||
)
|
||||
Reference in New Issue
Block a user