Merge branch 'main' into Atom/mriegger/PLS
This commit is contained in:
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Game" UpAxis="Y" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="0" PositionPrecision="1" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Game (fast decode)" UpAxis="Y" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="lz4hc" PlaybackFromMemory="0" PositionPrecision="1" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Game (Z-up)" UpAxis="Z" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="0" PositionPrecision="1" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Game (fast decode, Z-up)" UpAxis="Z" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="lz4hc" PlaybackFromMemory="0" PositionPrecision="1" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Prerendered" UpAxis="Y" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="0" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Prerendered (Z-up)" UpAxis="Z" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="0" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Rigids Only" UpAxis="Y" MeshPrediction="0" UseBFrames="0" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="1" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Rigids Only (Z-up)" UpAxis="Z" MeshPrediction="0" UseBFrames="0" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="1" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Uncompressed (fastest compile)" UpAxis="Y" MeshPrediction="0" UseBFrames="0" IndexFrameDistance="10" BlockCompressionFormat="store" PlaybackFromMemory="0" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Uncompressed (fastest compile, Z-up)" UpAxis="Z" MeshPrediction="0" UseBFrames="0" IndexFrameDistance="10" BlockCompressionFormat="store" PlaybackFromMemory="0" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9c36d7bc993ddf616f478115a123efabda5b4b833a4e6524312f43c228ae0902
|
||||
size 487003
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration UpAxis="Y" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="15" BlockCompressionFormat="deflate" PlaybackFromMemory="1"/>
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:96a21446422b834ea90a5d38eaaca309fdee31dc3cc03c0e9c094b39ec3a459d
|
||||
size 4715164
|
||||
@@ -1,17 +0,0 @@
|
||||
<Material MtlFlags="524544" vertModifType="0">
|
||||
<SubMaterials>
|
||||
<Material Name="mat01_white" MtlFlags="524416" Shader="Illum" GenMask="12000020040003" StringGenMask="%ALLOW_SILHOUETTE_POM%ALLOW_SPECULAR_ANTIALIASING%EMITTANCE_MAP%NORMAL_MAP%SPECULAR_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_default" Diffuse="1,1,1,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="174.72" vertModifType="0" LayerAct="1">
|
||||
<Textures>
|
||||
<Texture Map="Diffuse" File="engineassets/textures/white.dds"/>
|
||||
</Textures>
|
||||
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
|
||||
</Material>
|
||||
<Material Name="mat02_grey" MtlFlags="524416" Shader="Illum" GenMask="10000000000003" StringGenMask="%ALLOW_SILHOUETTE_POM%ALLOW_SPECULAR_ANTIALIASING%SUBSURFACE_SCATTERING" SurfaceType="mat_default" Diffuse="0.5,0.5,0.5,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
|
||||
<Textures>
|
||||
<Texture Map="Diffuse" File="engineassets/textures/white.dds"/>
|
||||
</Textures>
|
||||
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
|
||||
</Material>
|
||||
</SubMaterials>
|
||||
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
|
||||
</Material>
|
||||
@@ -8,3 +8,8 @@
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(GEM_DEPENDENCIES
|
||||
Gem::Atom_RHI_Metal.Private
|
||||
Gem::Atom_RHI_Null.Private
|
||||
)
|
||||
@@ -8,3 +8,10 @@
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(GEM_DEPENDENCIES
|
||||
Gem::Atom_RHI_Null.Private
|
||||
Gem::Atom_RHI_Null.Builders
|
||||
Gem::Atom_RHI_Metal.Private
|
||||
Gem::Atom_RHI_Metal.Builders
|
||||
)
|
||||
@@ -1,75 +0,0 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
#
|
||||
# This is a pytest module to test the in-Editor Python API from ViewPane.h
|
||||
#
|
||||
import pytest
|
||||
pytest.importorskip('ly_test_tools')
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
from hydra_utils import launch_test_case
|
||||
|
||||
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
|
||||
@pytest.mark.parametrize('project', ['AutomatedTesting'])
|
||||
@pytest.mark.parametrize('level', ['auto_test'])
|
||||
class TestLegacyCryMaterialsCommandsAutomation(object):
|
||||
|
||||
def test_Legacy_CryMaterials(self, request, editor, level, launcher_platform):
|
||||
|
||||
unexpected_lines=[]
|
||||
expected_lines = [
|
||||
# "Material Settings/Shader updated correctly", # Disabled, SPEC-3590
|
||||
# "Material Settings/Surface Type updated correctly", # Disabled, SPEC-3590
|
||||
"Texture Maps/Diffuse/Tiling/IsTileU updated correctly",
|
||||
"Texture Maps/Diffuse/Tiling/TileU updated correctly",
|
||||
"Texture Maps/Diffuse/Rotator/Type updated correctly",
|
||||
"Texture Maps/Diffuse/Rotator/Amplitude updated correctly",
|
||||
"Texture Maps/Diffuse/Oscillator/AmplitudeU updated correctly",
|
||||
"Opacity Settings/Opacity updated correctly",
|
||||
"Opacity Settings/AlphaTest updated correctly",
|
||||
"Opacity Settings/Additive updated correctly",
|
||||
"Lighting Settings/Diffuse Color updated correctly",
|
||||
"Lighting Settings/Specular Color updated correctly",
|
||||
"Lighting Settings/Emissive Intensity updated correctly",
|
||||
"Lighting Settings/Emissive Color updated correctly",
|
||||
"Advanced/Allow layer activation updated correctly",
|
||||
"Advanced/2 Sided updated correctly",
|
||||
"Advanced/No Shadow updated correctly",
|
||||
"Advanced/Use Scattering updated correctly",
|
||||
"Advanced/Hide After Breaking updated correctly",
|
||||
"Advanced/Fog Volume Shading Quality High updated correctly",
|
||||
"Advanced/Blend Terrain Color updated correctly",
|
||||
"Advanced/Voxel Coverage updated correctly",
|
||||
"Advanced/Propagate Opacity Settings updated correctly",
|
||||
"Advanced/Propagate Lighting Settings updated correctly",
|
||||
"Advanced/Propagate Advanced Settings updated correctly",
|
||||
"Advanced/Propagate Texture Maps updated correctly",
|
||||
"Advanced/Propagate Shader Params updated correctly",
|
||||
"Advanced/Propagate Shader Generation updated correctly",
|
||||
"Advanced/Propagate Vertex Deformation updated correctly",
|
||||
# "Shader Params/Blend Factor updated correctly", # Disabled, SPEC-3590
|
||||
# "Shader Params/Indirect bounce color updated correctly", # Disabled, SPEC-3590
|
||||
"Vertex Deformation/Type updated correctly",
|
||||
"Vertex Deformation/Wave Length X updated correctly",
|
||||
"Vertex Deformation/Wave X/Level updated correctly",
|
||||
"Vertex Deformation/Wave X/Amplitude updated correctly",
|
||||
"Vertex Deformation/Wave X/Phase updated correctly",
|
||||
"Vertex Deformation/Wave X/Frequency updated correctly"
|
||||
]
|
||||
|
||||
test_case_file = os.path.join(os.path.dirname(__file__), 'CryMaterialsCommands_test_case.py')
|
||||
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
|
||||
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
# Tests the legacy Python API for CryMaterials while the Editor is running
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.material as material
|
||||
import azlmbr.math as math
|
||||
|
||||
materialName = 'materials/ter_layer_green'
|
||||
print(f'Starting CryMaterial test case using material {materialName}')
|
||||
|
||||
|
||||
def MaterialPropertyTest(property, value, doReset=True):
|
||||
try:
|
||||
# get old value and attempt to set new value
|
||||
oldValue = material.get_property(materialName, property)
|
||||
if oldValue == value:
|
||||
print(f'>>> `{property}` already set to {oldValue}')
|
||||
return
|
||||
material.set_property(materialName, property, value)
|
||||
|
||||
# test that the set new value worked
|
||||
newValue = material.get_property(materialName, property)
|
||||
if oldValue != newValue:
|
||||
print(f"{property} updated correctly")
|
||||
|
||||
# reset back to old value
|
||||
if doReset:
|
||||
material.set_property(materialName, property, oldValue)
|
||||
except:
|
||||
print(f'!!! hit an exception when setting `{property}` to {value}')
|
||||
|
||||
|
||||
color = math.Color()
|
||||
color.r = 255.0
|
||||
color.g = 128.0
|
||||
color.b = 64.0
|
||||
color.a = 0.0
|
||||
|
||||
# Material Settings
|
||||
# MaterialPropertyTest("Material Settings/Shader", "Geometrybeam") # Disabled, SPEC-3590
|
||||
# MaterialPropertyTest("Material Settings/Surface Type", "grass") # Disabled, SPEC-3590
|
||||
|
||||
# Texture Maps
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/IsTileU", False)
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/IsTileV", False)
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/TileU", 0.42)
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Rotator/Type", 'Oscillated Rotation')
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Rotator/Amplitude", 42.0)
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Oscillator/TypeU", 'Fixed Moving')
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Oscillator/AmplitudeU", 42.0)
|
||||
|
||||
# Vertex Deformation
|
||||
MaterialPropertyTest("Vertex Deformation/Type", 'Sin Wave')
|
||||
MaterialPropertyTest("Vertex Deformation/Wave Length X", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Type", 'Perlin 3D')
|
||||
MaterialPropertyTest("Vertex Deformation/Noise Scale", math.Vector3(1.1, 2.2, 3.3))
|
||||
|
||||
# Opacity Settings
|
||||
MaterialPropertyTest("Opacity Settings/Opacity", 42)
|
||||
MaterialPropertyTest("Opacity Settings/AlphaTest", 2)
|
||||
MaterialPropertyTest("Opacity Settings/Additive", True)
|
||||
|
||||
# Lighting Settings
|
||||
MaterialPropertyTest("Lighting Settings/Diffuse Color", color)
|
||||
MaterialPropertyTest("Lighting Settings/Specular Color", color)
|
||||
MaterialPropertyTest("Lighting Settings/Emissive Intensity", 42.0)
|
||||
MaterialPropertyTest("Lighting Settings/Emissive Color", color)
|
||||
MaterialPropertyTest("Lighting Settings/Specular Level", 2.0)
|
||||
|
||||
# Advanced
|
||||
MaterialPropertyTest("Advanced/Allow layer activation", False)
|
||||
MaterialPropertyTest("Advanced/2 Sided", True)
|
||||
MaterialPropertyTest("Advanced/No Shadow", True)
|
||||
MaterialPropertyTest("Advanced/Use Scattering", True)
|
||||
MaterialPropertyTest("Advanced/Hide After Breaking", True)
|
||||
MaterialPropertyTest("Advanced/Fog Volume Shading Quality High", True)
|
||||
MaterialPropertyTest("Advanced/Blend Terrain Color", True)
|
||||
MaterialPropertyTest("Advanced/Voxel Coverage", 0.42)
|
||||
# --- MaterialPropertyTest("Advanced/Link to Material", "materials/ter_layer_blue") # Works, but clears on UI refresh
|
||||
MaterialPropertyTest("Advanced/Propagate Opacity Settings", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Lighting Settings", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Advanced Settings", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Texture Maps", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Shader Params", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Shader Generation", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Vertex Deformation", True)
|
||||
|
||||
# Shader parameters vary with each Shader, just testing a couple of them...
|
||||
# MaterialPropertyTest("Shader Params/Blend Factor", 7.0, False) # Disabled, SPEC-3590
|
||||
# MaterialPropertyTest("Shader Params/Indirect bounce color", color, False) # Disabled, SPEC-3590
|
||||
|
||||
### These values are reset to False when set. Left them here commented for reference.
|
||||
# MaterialPropertyTest("Shader Generation Params/Dust & Turbulence", True)
|
||||
# MaterialPropertyTest("Shader Generation Params/Receive Shadows", True)
|
||||
# MaterialPropertyTest("Shader Generation Params/UV Vignetting", True)
|
||||
|
||||
# Vertex Deformation
|
||||
MaterialPropertyTest("Vertex Deformation/Type", "Sin Wave")
|
||||
MaterialPropertyTest("Vertex Deformation/Wave Length X", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Wave X/Level", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Wave X/Amplitude", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Wave X/Phase", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Wave X/Frequency", 42.0)
|
||||
|
||||
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
|
||||
+8
-17
@@ -161,20 +161,6 @@ def run():
|
||||
# Deletion/Undo/Redo test
|
||||
verify_deletion_undo_redo(self.component_name, entity_obj)
|
||||
|
||||
# Area Light Component
|
||||
area_light = "Area Light"
|
||||
ComponentTests(
|
||||
area_light, lambda entity_obj: verify_required_component_addition(
|
||||
entity_obj, ["Capsule Shape"], area_light))
|
||||
|
||||
# Decal Component
|
||||
material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
|
||||
material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Decal (Atom)", lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Material", material_asset))
|
||||
|
||||
# DepthOfField Component
|
||||
camera_entity = hydra.Entity("camera_entity")
|
||||
camera_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), ["Camera"])
|
||||
@@ -185,6 +171,14 @@ def run():
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Camera Entity", camera_entity.id))
|
||||
|
||||
# Decal Component
|
||||
material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
|
||||
material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Decal (Atom)", lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Material", material_asset))
|
||||
|
||||
# Directional Light Component
|
||||
ComponentTests(
|
||||
"Directional Light",
|
||||
@@ -213,9 +207,6 @@ def run():
|
||||
# Physical Sky Component
|
||||
ComponentTests("Physical Sky")
|
||||
|
||||
# Point Light Component
|
||||
ComponentTests("Point Light")
|
||||
|
||||
# PostFX Layer Component
|
||||
ComponentTests("PostFX Layer")
|
||||
|
||||
|
||||
@@ -27,194 +27,6 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsMain(object):
|
||||
|
||||
@pytest.mark.test_case_id(
|
||||
"C32078117", # Area Light
|
||||
"C32078130", # Display Mapper
|
||||
"C32078129", # Light
|
||||
"C32078131", # Radius Weight Modifier
|
||||
"C32078127", # PostFX Layer
|
||||
"C32078126", # Point Light
|
||||
"C32078125", # Physical Sky
|
||||
"C32078115", # Global Skylight (IBL)
|
||||
"C32078121", # Exposure Control
|
||||
"C32078120", # Directional Light
|
||||
"C32078119", # DepthOfField
|
||||
"C32078118") # Decal
|
||||
def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
# Area Light Component
|
||||
"Area Light Entity successfully created",
|
||||
"Area Light_test: Component added to the entity: True",
|
||||
"Area Light_test: Component removed after UNDO: True",
|
||||
"Area Light_test: Component added after REDO: True",
|
||||
"Area Light_test: Entered game mode: True",
|
||||
"Area Light_test: Entity enabled after adding required components: True",
|
||||
"Area Light_test: Entity is hidden: True",
|
||||
"Area Light_test: Entity is shown: True",
|
||||
"Area Light_test: Entity deleted: True",
|
||||
"Area Light_test: UNDO entity deletion works: True",
|
||||
"Area Light_test: REDO entity deletion works: True",
|
||||
# Decal Component
|
||||
"Decal (Atom) Entity successfully created",
|
||||
"Decal (Atom)_test: Component added to the entity: True",
|
||||
"Decal (Atom)_test: Component removed after UNDO: True",
|
||||
"Decal (Atom)_test: Component added after REDO: True",
|
||||
"Decal (Atom)_test: Entered game mode: True",
|
||||
"Decal (Atom)_test: Exit game mode: True",
|
||||
"Decal (Atom) Controller|Configuration|Material: SUCCESS",
|
||||
"Decal (Atom)_test: Entity is hidden: True",
|
||||
"Decal (Atom)_test: Entity is shown: True",
|
||||
"Decal (Atom)_test: Entity deleted: True",
|
||||
"Decal (Atom)_test: UNDO entity deletion works: True",
|
||||
"Decal (Atom)_test: REDO entity deletion works: True",
|
||||
# DepthOfField Component
|
||||
"DepthOfField Entity successfully created",
|
||||
"DepthOfField_test: Component added to the entity: True",
|
||||
"DepthOfField_test: Component removed after UNDO: True",
|
||||
"DepthOfField_test: Component added after REDO: True",
|
||||
"DepthOfField_test: Entered game mode: True",
|
||||
"DepthOfField_test: Exit game mode: True",
|
||||
"DepthOfField_test: Entity disabled initially: True",
|
||||
"DepthOfField_test: Entity enabled after adding required components: True",
|
||||
"DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
|
||||
"DepthOfField_test: Entity is hidden: True",
|
||||
"DepthOfField_test: Entity is shown: True",
|
||||
"DepthOfField_test: Entity deleted: True",
|
||||
"DepthOfField_test: UNDO entity deletion works: True",
|
||||
"DepthOfField_test: REDO entity deletion works: True",
|
||||
# Directional Light Component
|
||||
"Directional Light Entity successfully created",
|
||||
"Directional Light_test: Component added to the entity: True",
|
||||
"Directional Light_test: Component removed after UNDO: True",
|
||||
"Directional Light_test: Component added after REDO: True",
|
||||
"Directional Light_test: Entered game mode: True",
|
||||
"Directional Light_test: Exit game mode: True",
|
||||
"Directional Light Controller|Configuration|Shadow|Camera: SUCCESS",
|
||||
"Directional Light_test: Entity is hidden: True",
|
||||
"Directional Light_test: Entity is shown: True",
|
||||
"Directional Light_test: Entity deleted: True",
|
||||
"Directional Light_test: UNDO entity deletion works: True",
|
||||
"Directional Light_test: REDO entity deletion works: True",
|
||||
# Exposure Control Component
|
||||
"Exposure Control Entity successfully created",
|
||||
"Exposure Control_test: Component added to the entity: True",
|
||||
"Exposure Control_test: Component removed after UNDO: True",
|
||||
"Exposure Control_test: Component added after REDO: True",
|
||||
"Exposure Control_test: Entered game mode: True",
|
||||
"Exposure Control_test: Exit game mode: True",
|
||||
"Exposure Control_test: Entity disabled initially: True",
|
||||
"Exposure Control_test: Entity enabled after adding required components: True",
|
||||
"Exposure Control_test: Entity is hidden: True",
|
||||
"Exposure Control_test: Entity is shown: True",
|
||||
"Exposure Control_test: Entity deleted: True",
|
||||
"Exposure Control_test: UNDO entity deletion works: True",
|
||||
"Exposure Control_test: REDO entity deletion works: True",
|
||||
# Global Skylight (IBL) Component
|
||||
"Global Skylight (IBL) Entity successfully created",
|
||||
"Global Skylight (IBL)_test: Component added to the entity: True",
|
||||
"Global Skylight (IBL)_test: Component removed after UNDO: True",
|
||||
"Global Skylight (IBL)_test: Component added after REDO: True",
|
||||
"Global Skylight (IBL)_test: Entered game mode: True",
|
||||
"Global Skylight (IBL)_test: Exit game mode: True",
|
||||
"Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
|
||||
"Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
|
||||
"Global Skylight (IBL)_test: Entity is hidden: True",
|
||||
"Global Skylight (IBL)_test: Entity is shown: True",
|
||||
"Global Skylight (IBL)_test: Entity deleted: True",
|
||||
"Global Skylight (IBL)_test: UNDO entity deletion works: True",
|
||||
"Global Skylight (IBL)_test: REDO entity deletion works: True",
|
||||
# Physical Sky Component
|
||||
"Physical Sky Entity successfully created",
|
||||
"Physical Sky component was added to entity",
|
||||
"Entity has a Physical Sky component",
|
||||
"Physical Sky_test: Component added to the entity: True",
|
||||
"Physical Sky_test: Component removed after UNDO: True",
|
||||
"Physical Sky_test: Component added after REDO: True",
|
||||
"Physical Sky_test: Entered game mode: True",
|
||||
"Physical Sky_test: Exit game mode: True",
|
||||
"Physical Sky_test: Entity is hidden: True",
|
||||
"Physical Sky_test: Entity is shown: True",
|
||||
"Physical Sky_test: Entity deleted: True",
|
||||
"Physical Sky_test: UNDO entity deletion works: True",
|
||||
"Physical Sky_test: REDO entity deletion works: True",
|
||||
# Point Light Component
|
||||
"Point Light Entity successfully created",
|
||||
"Point Light_test: Component added to the entity: True",
|
||||
"Point Light_test: Component removed after UNDO: True",
|
||||
"Point Light_test: Component added after REDO: True",
|
||||
"Point Light_test: Entered game mode: True",
|
||||
"Point Light_test: Exit game mode: True",
|
||||
"Point Light_test: Entity is hidden: True",
|
||||
"Point Light_test: Entity is shown: True",
|
||||
"Point Light_test: Entity deleted: True",
|
||||
"Point Light_test: UNDO entity deletion works: True",
|
||||
"Point Light_test: REDO entity deletion works: True",
|
||||
# PostFX Layer Component
|
||||
"PostFX Layer Entity successfully created",
|
||||
"PostFX Layer_test: Component added to the entity: True",
|
||||
"PostFX Layer_test: Component removed after UNDO: True",
|
||||
"PostFX Layer_test: Component added after REDO: True",
|
||||
"PostFX Layer_test: Entered game mode: True",
|
||||
"PostFX Layer_test: Exit game mode: True",
|
||||
"PostFX Layer_test: Entity is hidden: True",
|
||||
"PostFX Layer_test: Entity is shown: True",
|
||||
"PostFX Layer_test: Entity deleted: True",
|
||||
"PostFX Layer_test: UNDO entity deletion works: True",
|
||||
"PostFX Layer_test: REDO entity deletion works: True",
|
||||
# Radius Weight Modifier Component
|
||||
"Radius Weight Modifier Entity successfully created",
|
||||
"Radius Weight Modifier_test: Component added to the entity: True",
|
||||
"Radius Weight Modifier_test: Component removed after UNDO: True",
|
||||
"Radius Weight Modifier_test: Component added after REDO: True",
|
||||
"Radius Weight Modifier_test: Entered game mode: True",
|
||||
"Radius Weight Modifier_test: Exit game mode: True",
|
||||
"Radius Weight Modifier_test: Entity is hidden: True",
|
||||
"Radius Weight Modifier_test: Entity is shown: True",
|
||||
"Radius Weight Modifier_test: Entity deleted: True",
|
||||
"Radius Weight Modifier_test: UNDO entity deletion works: True",
|
||||
"Radius Weight Modifier_test: REDO entity deletion works: True",
|
||||
# Light Component
|
||||
"Light Entity successfully created",
|
||||
"Light_test: Component added to the entity: True",
|
||||
"Light_test: Component removed after UNDO: True",
|
||||
"Light_test: Component added after REDO: True",
|
||||
"Light_test: Entered game mode: True",
|
||||
"Light_test: Exit game mode: True",
|
||||
"Light_test: Entity is hidden: True",
|
||||
"Light_test: Entity is shown: True",
|
||||
"Light_test: Entity deleted: True",
|
||||
"Light_test: UNDO entity deletion works: True",
|
||||
"Light_test: REDO entity deletion works: True",
|
||||
# Display Mapper Component
|
||||
"Display Mapper Entity successfully created",
|
||||
"Display Mapper_test: Component added to the entity: True",
|
||||
"Display Mapper_test: Component removed after UNDO: True",
|
||||
"Display Mapper_test: Component added after REDO: True",
|
||||
"Display Mapper_test: Entered game mode: True",
|
||||
"Display Mapper_test: Exit game mode: True",
|
||||
"Display Mapper_test: Entity is hidden: True",
|
||||
"Display Mapper_test: Entity is shown: True",
|
||||
"Display Mapper_test: Entity deleted: True",
|
||||
"Display Mapper_test: UNDO entity deletion works: True",
|
||||
"Display Mapper_test: REDO entity deletion works: True",
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
"failed to open",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_AddedToEntity.py",
|
||||
timeout=EDITOR_TIMEOUT,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
# It requires at least one test
|
||||
def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
|
||||
pass
|
||||
|
||||
@@ -19,6 +19,170 @@ import pytest
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsSandbox(object):
|
||||
|
||||
# It requires at least one test
|
||||
def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
|
||||
pass
|
||||
@pytest.mark.test_case_id(
|
||||
"C32078117", # Area Light
|
||||
"C32078130", # Display Mapper
|
||||
"C32078129", # Light
|
||||
"C32078131", # Radius Weight Modifier
|
||||
"C32078127", # PostFX Layer
|
||||
"C32078126", # Point Light
|
||||
"C32078125", # Physical Sky
|
||||
"C32078115", # Global Skylight (IBL)
|
||||
"C32078121", # Exposure Control
|
||||
"C32078120", # Directional Light
|
||||
"C32078119", # DepthOfField
|
||||
"C32078118") # Decal
|
||||
def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
# Decal Component
|
||||
"Decal (Atom) Entity successfully created",
|
||||
"Decal (Atom)_test: Component added to the entity: True",
|
||||
"Decal (Atom)_test: Component removed after UNDO: True",
|
||||
"Decal (Atom)_test: Component added after REDO: True",
|
||||
"Decal (Atom)_test: Entered game mode: True",
|
||||
"Decal (Atom)_test: Exit game mode: True",
|
||||
"Decal (Atom) Controller|Configuration|Material: SUCCESS",
|
||||
"Decal (Atom)_test: Entity is hidden: True",
|
||||
"Decal (Atom)_test: Entity is shown: True",
|
||||
"Decal (Atom)_test: Entity deleted: True",
|
||||
"Decal (Atom)_test: UNDO entity deletion works: True",
|
||||
"Decal (Atom)_test: REDO entity deletion works: True",
|
||||
# DepthOfField Component
|
||||
"DepthOfField Entity successfully created",
|
||||
"DepthOfField_test: Component added to the entity: True",
|
||||
"DepthOfField_test: Component removed after UNDO: True",
|
||||
"DepthOfField_test: Component added after REDO: True",
|
||||
"DepthOfField_test: Entered game mode: True",
|
||||
"DepthOfField_test: Exit game mode: True",
|
||||
"DepthOfField_test: Entity disabled initially: True",
|
||||
"DepthOfField_test: Entity enabled after adding required components: True",
|
||||
"DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
|
||||
"DepthOfField_test: Entity is hidden: True",
|
||||
"DepthOfField_test: Entity is shown: True",
|
||||
"DepthOfField_test: Entity deleted: True",
|
||||
"DepthOfField_test: UNDO entity deletion works: True",
|
||||
"DepthOfField_test: REDO entity deletion works: True",
|
||||
# Directional Light Component
|
||||
"Directional Light Entity successfully created",
|
||||
"Directional Light_test: Component added to the entity: True",
|
||||
"Directional Light_test: Component removed after UNDO: True",
|
||||
"Directional Light_test: Component added after REDO: True",
|
||||
"Directional Light_test: Entered game mode: True",
|
||||
"Directional Light_test: Exit game mode: True",
|
||||
"Directional Light Controller|Configuration|Shadow|Camera: SUCCESS",
|
||||
"Directional Light_test: Entity is hidden: True",
|
||||
"Directional Light_test: Entity is shown: True",
|
||||
"Directional Light_test: Entity deleted: True",
|
||||
"Directional Light_test: UNDO entity deletion works: True",
|
||||
"Directional Light_test: REDO entity deletion works: True",
|
||||
# Exposure Control Component
|
||||
"Exposure Control Entity successfully created",
|
||||
"Exposure Control_test: Component added to the entity: True",
|
||||
"Exposure Control_test: Component removed after UNDO: True",
|
||||
"Exposure Control_test: Component added after REDO: True",
|
||||
"Exposure Control_test: Entered game mode: True",
|
||||
"Exposure Control_test: Exit game mode: True",
|
||||
"Exposure Control_test: Entity disabled initially: True",
|
||||
"Exposure Control_test: Entity enabled after adding required components: True",
|
||||
"Exposure Control_test: Entity is hidden: True",
|
||||
"Exposure Control_test: Entity is shown: True",
|
||||
"Exposure Control_test: Entity deleted: True",
|
||||
"Exposure Control_test: UNDO entity deletion works: True",
|
||||
"Exposure Control_test: REDO entity deletion works: True",
|
||||
# Global Skylight (IBL) Component
|
||||
"Global Skylight (IBL) Entity successfully created",
|
||||
"Global Skylight (IBL)_test: Component added to the entity: True",
|
||||
"Global Skylight (IBL)_test: Component removed after UNDO: True",
|
||||
"Global Skylight (IBL)_test: Component added after REDO: True",
|
||||
"Global Skylight (IBL)_test: Entered game mode: True",
|
||||
"Global Skylight (IBL)_test: Exit game mode: True",
|
||||
"Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
|
||||
"Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
|
||||
"Global Skylight (IBL)_test: Entity is hidden: True",
|
||||
"Global Skylight (IBL)_test: Entity is shown: True",
|
||||
"Global Skylight (IBL)_test: Entity deleted: True",
|
||||
"Global Skylight (IBL)_test: UNDO entity deletion works: True",
|
||||
"Global Skylight (IBL)_test: REDO entity deletion works: True",
|
||||
# Physical Sky Component
|
||||
"Physical Sky Entity successfully created",
|
||||
"Physical Sky component was added to entity",
|
||||
"Entity has a Physical Sky component",
|
||||
"Physical Sky_test: Component added to the entity: True",
|
||||
"Physical Sky_test: Component removed after UNDO: True",
|
||||
"Physical Sky_test: Component added after REDO: True",
|
||||
"Physical Sky_test: Entered game mode: True",
|
||||
"Physical Sky_test: Exit game mode: True",
|
||||
"Physical Sky_test: Entity is hidden: True",
|
||||
"Physical Sky_test: Entity is shown: True",
|
||||
"Physical Sky_test: Entity deleted: True",
|
||||
"Physical Sky_test: UNDO entity deletion works: True",
|
||||
"Physical Sky_test: REDO entity deletion works: True",
|
||||
# PostFX Layer Component
|
||||
"PostFX Layer Entity successfully created",
|
||||
"PostFX Layer_test: Component added to the entity: True",
|
||||
"PostFX Layer_test: Component removed after UNDO: True",
|
||||
"PostFX Layer_test: Component added after REDO: True",
|
||||
"PostFX Layer_test: Entered game mode: True",
|
||||
"PostFX Layer_test: Exit game mode: True",
|
||||
"PostFX Layer_test: Entity is hidden: True",
|
||||
"PostFX Layer_test: Entity is shown: True",
|
||||
"PostFX Layer_test: Entity deleted: True",
|
||||
"PostFX Layer_test: UNDO entity deletion works: True",
|
||||
"PostFX Layer_test: REDO entity deletion works: True",
|
||||
# Radius Weight Modifier Component
|
||||
"Radius Weight Modifier Entity successfully created",
|
||||
"Radius Weight Modifier_test: Component added to the entity: True",
|
||||
"Radius Weight Modifier_test: Component removed after UNDO: True",
|
||||
"Radius Weight Modifier_test: Component added after REDO: True",
|
||||
"Radius Weight Modifier_test: Entered game mode: True",
|
||||
"Radius Weight Modifier_test: Exit game mode: True",
|
||||
"Radius Weight Modifier_test: Entity is hidden: True",
|
||||
"Radius Weight Modifier_test: Entity is shown: True",
|
||||
"Radius Weight Modifier_test: Entity deleted: True",
|
||||
"Radius Weight Modifier_test: UNDO entity deletion works: True",
|
||||
"Radius Weight Modifier_test: REDO entity deletion works: True",
|
||||
# Light Component
|
||||
"Light Entity successfully created",
|
||||
"Light_test: Component added to the entity: True",
|
||||
"Light_test: Component removed after UNDO: True",
|
||||
"Light_test: Component added after REDO: True",
|
||||
"Light_test: Entered game mode: True",
|
||||
"Light_test: Exit game mode: True",
|
||||
"Light_test: Entity is hidden: True",
|
||||
"Light_test: Entity is shown: True",
|
||||
"Light_test: Entity deleted: True",
|
||||
"Light_test: UNDO entity deletion works: True",
|
||||
"Light_test: REDO entity deletion works: True",
|
||||
# Display Mapper Component
|
||||
"Display Mapper Entity successfully created",
|
||||
"Display Mapper_test: Component added to the entity: True",
|
||||
"Display Mapper_test: Component removed after UNDO: True",
|
||||
"Display Mapper_test: Component added after REDO: True",
|
||||
"Display Mapper_test: Entered game mode: True",
|
||||
"Display Mapper_test: Exit game mode: True",
|
||||
"Display Mapper_test: Entity is hidden: True",
|
||||
"Display Mapper_test: Entity is shown: True",
|
||||
"Display Mapper_test: Entity deleted: True",
|
||||
"Display Mapper_test: UNDO entity deletion works: True",
|
||||
"Display Mapper_test: REDO entity deletion works: True",
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
"failed to open",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_AddedToEntity.py",
|
||||
timeout=EDITOR_TIMEOUT,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
+38
-15
@@ -20,7 +20,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
class Tests():
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
find_cylinder = ("Cylinder entity found", "Cylinder entity not found")
|
||||
find_terrain = ("Terrain found", "Terrain not found")
|
||||
create_terrain = ("Terrain entity created successfully", "Failed to create Terrain Entity")
|
||||
find_terrain = ("Terrain entity found", "Terrain entity not found")
|
||||
add_physx_shape_collider = ("Added PhysX Shape Collider", "Failed to add PhysX Shape Collider")
|
||||
add_box_shape = ("Added Box Shape", "Failed to add Box Shape")
|
||||
cylinder_above_terrain = ("Cylinder position above ground", "Cylinder is not above the ground")
|
||||
time_out = ("No time out occurred", "A time out occurred, please validate level setup")
|
||||
touched_ground = ("Touched ground before time out", "Did not touch ground before time out")
|
||||
@@ -40,11 +43,12 @@ def C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain():
|
||||
Once game mode is entered, the cylinder should fall toward and collide with the terrain.
|
||||
|
||||
Steps:
|
||||
1) Open level and enter game mode
|
||||
2) Retrieve entities and positions
|
||||
3) Wait for cylinder to collide with terrain OR time out
|
||||
4) Exit game mode
|
||||
5) Close the editor
|
||||
1) Open level and create terrain Entity.
|
||||
2) Enter Game Mode.
|
||||
3) Retrieve entities and positions
|
||||
4) Wait for cylinder to collide with terrain OR time out
|
||||
5) Exit game mode
|
||||
6) Close the editor
|
||||
|
||||
:return:
|
||||
"""
|
||||
@@ -54,29 +58,48 @@ def C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain():
|
||||
import ImportPathHelper as imports
|
||||
|
||||
imports.init()
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus
|
||||
import azlmbr.math as math
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Global time out
|
||||
TIME_OUT = 1.0
|
||||
|
||||
# 1) Open level / Enter game mode
|
||||
# 1) Open level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain")
|
||||
|
||||
# Create terrain entity
|
||||
terrain = EditorEntity.create_editor_entity_at([30.0, 30.0, 33.96], "Terrain")
|
||||
Report.result(Tests.create_terrain, terrain.id.IsValid())
|
||||
|
||||
terrain.add_component("PhysX Shape Collider")
|
||||
Report.result(Tests.add_physx_shape_collider, terrain.has_component("PhysX Shape Collider"))
|
||||
|
||||
box_shape_component = terrain.add_component("Box Shape")
|
||||
Report.result(Tests.add_box_shape, terrain.has_component("Box Shape"))
|
||||
|
||||
box_shape_component.set_component_property_value("Box Shape|Box Configuration|Dimensions",
|
||||
math.Vector3(1024.0, 1024.0, 0.01))
|
||||
|
||||
# 2)Enter game mode
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
|
||||
# 2) Retrieve entities and positions
|
||||
# 3) Retrieve entities and positions
|
||||
cylinder_id = general.find_game_entity("PhysX_Cylinder")
|
||||
Report.critical_result(Tests.find_cylinder, cylinder_id.IsValid())
|
||||
|
||||
|
||||
terrain_id = general.find_game_entity("Terrain")
|
||||
Report.critical_result(Tests.find_terrain, terrain_id.IsValid())
|
||||
|
||||
terrain_id = general.find_game_entity("PhysX_Terrain")
|
||||
Report.critical_result(Tests.find_terrain, terrain_id.IsValid())
|
||||
|
||||
cylinder_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTM", cylinder_id).GetPosition()
|
||||
terrain_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTM", terrain_id).GetPosition()
|
||||
cylinder_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", cylinder_id)
|
||||
#Cylinder position is 64,84,35
|
||||
terrain_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", terrain_id)
|
||||
Report.info_vector3(cylinder_pos, "Cylinder:")
|
||||
Report.info_vector3(terrain_pos, "Terrain:")
|
||||
Report.critical_result(
|
||||
@@ -104,13 +127,13 @@ def C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain():
|
||||
handler.connect(cylinder_id)
|
||||
handler.add_callback("OnCollisionBegin", on_collision_begin)
|
||||
|
||||
# 3) Wait for the cylinder to hit the ground OR time out
|
||||
# 4) Wait for the cylinder to hit the ground OR time out
|
||||
test_completed = helper.wait_for_condition((lambda: TouchGround.value), TIME_OUT)
|
||||
|
||||
Report.critical_result(Tests.time_out, test_completed)
|
||||
Report.result(Tests.touched_ground, TouchGround.value)
|
||||
|
||||
# 4) Exit game mode
|
||||
# 5) Exit game mode
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
|
||||
|
||||
@@ -34,4 +34,61 @@ class TestAutomation(TestAutomationBase):
|
||||
|
||||
def test_C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC(self, request, workspace, editor, launcher_platform):
|
||||
from . import C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4044459_Material_DynamicFriction(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4044459_Material_DynamicFriction as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15425929_Undo_Redo(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4976243_Collision_SameCollisionGroupDiffCollisionLayers(self, request, workspace, editor,
|
||||
launcher_platform):
|
||||
from . import C4976243_Collision_SameCollisionGroupDiffCollisionLayers as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C14654881_CharacterController_SwitchLevels(self, request, workspace, editor, launcher_platform):
|
||||
from . import C14654881_CharacterController_SwitchLevels as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
def test_C17411467_AddPhysxRagdollComponent(self, request, workspace, editor, launcher_platform):
|
||||
from . import C17411467_AddPhysxRagdollComponent as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C12712453_ScriptCanvas_MultipleRaycastNode(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12712453_ScriptCanvas_MultipleRaycastNode as test_module
|
||||
# Fixme: unexpected_lines = ["Assert"] + test_module.Lines.unexpected
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxsystemconfiguration.setreg','C4982593_PhysXCollider_CollisionLayer.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C4982593_PhysXCollider_CollisionLayerTest(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982593_PhysXCollider_CollisionLayerTest as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C18243586_Joints_HingeLeadFollowerCollide(self, request, workspace, editor, launcher_platform):
|
||||
from . import C18243586_Joints_HingeLeadFollowerCollide as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982803_Enable_PxMesh_Option(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982803_Enable_PxMesh_Option as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain(self, request, workspace, editor, launcher_platform):
|
||||
from . import C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
@@ -52,11 +52,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4976207_PhysXRigidBodies_KinematicBehavior as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5932042_PhysXForceRegion_LinearDamping(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5932042_PhysXForceRegion_LinearDamping as test_module
|
||||
@@ -92,11 +87,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4976194_RigidBody_PhysXComponentIsValid as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4044459_Material_DynamicFriction(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4044459_Material_DynamicFriction as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5932045_ForceRegion_Spline(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5932045_ForceRegion_Spline as test_module
|
||||
@@ -208,26 +198,11 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C18981526_Material_RestitutionCombinePriority as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15425929_Undo_Redo(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15308217_NoCrash_LevelSwitch(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15308217_NoCrash_LevelSwitch as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C12868580_ForceRegion_SplineModifiedTransform(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12868580_ForceRegion_SplineModifiedTransform as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4976243_Collision_SameCollisionGroupDiffCollisionLayers(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4976243_Collision_SameCollisionGroupDiffCollisionLayers as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C12712455_ScriptCanvas_ShapeCastVerification(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12712455_ScriptCanvas_ShapeCastVerification as test_module
|
||||
@@ -248,17 +223,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C6131473_StaticSlice_OnDynamicSliceSpawn as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982798_Collider_ColliderRotationOffset(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982798_Collider_ColliderRotationOffset as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C12712453_ScriptCanvas_MultipleRaycastNode(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12712453_ScriptCanvas_MultipleRaycastNode as test_module
|
||||
# Fixme: unexpected_lines = ["Assert"] + test_module.Lines.unexpected
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5959808_ForceRegion_PositionOffset(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5959808_ForceRegion_PositionOffset as test_module
|
||||
@@ -275,7 +239,7 @@ class TestAutomation(TestAutomationBase):
|
||||
def test_C13895144_Ragdoll_ChangeLevel(self, request, workspace, editor, launcher_platform):
|
||||
from . import C13895144_Ragdoll_ChangeLevel as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5968759_ForceRegion_ExertsSeveralForcesOnRigidBody(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5968759_ForceRegion_ExertsSeveralForcesOnRigidBody as test_module
|
||||
@@ -305,11 +269,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C5296614_PhysXMaterial_ColliderShape as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C6090547_ForceRegion_ParentChildForceRegions(self, request, workspace, editor, launcher_platform):
|
||||
from . import C6090547_ForceRegion_ParentChildForceRegions as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982595_Collider_TriggerDisablesCollision(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982595_Collider_TriggerDisablesCollision as test_module
|
||||
@@ -320,11 +279,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C14976307_Gravity_SetGravityWorks as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C14654881_CharacterController_SwitchLevels(self, request, workspace, editor, launcher_platform):
|
||||
from . import C14654881_CharacterController_SwitchLevels as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15556261_PhysXMaterials_CharacterControllerMaterialAssignment(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15556261_PhysXMaterials_CharacterControllerMaterialAssignment as test_module
|
||||
@@ -374,18 +328,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4044461_Material_Restitution as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxsystemconfiguration.setreg','C4982593_PhysXCollider_CollisionLayer.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C4982593_PhysXCollider_CollisionLayerTest(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982593_PhysXCollider_CollisionLayerTest as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxsystemconfiguration.setreg','C3510644_Collider_CollisionGroups.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C3510644_Collider_CollisionGroups(self, request, workspace, editor, launcher_platform):
|
||||
from . import C3510644_Collider_CollisionGroups as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxdefaultsceneconfiguration.setreg','C14902097_ScriptCanvas_PreUpdateEvent.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C14902097_ScriptCanvas_PreUpdateEvent(self, request, workspace, editor, launcher_platform):
|
||||
@@ -415,11 +357,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C18243589_Joints_BallSoftLimitsConstrained as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C18243586_Joints_HingeLeadFollowerCollide(self, request, workspace, editor, launcher_platform):
|
||||
from . import C18243586_Joints_HingeLeadFollowerCollide as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C18243591_Joints_BallLeadFollowerCollide(self, request, workspace, editor, launcher_platform):
|
||||
from . import C18243591_Joints_BallLeadFollowerCollide as test_module
|
||||
@@ -441,21 +378,11 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C14861500_DefaultSetting_ColliderShape as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C19578021_ShapeCollider_CanBeAdded(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19578021_ShapeCollider_CanBeAdded as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C19723164_ShapeCollider_WontCrashEditor(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19723164_ShapeColliders_WontCrashEditor as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982803_Enable_PxMesh_Option(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982803_Enable_PxMesh_Option as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982800_PhysXColliderShape_CanBeSelected(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982800_PhysXColliderShape_CanBeSelected as test_module
|
||||
@@ -471,10 +398,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4982802_PhysXColliderShape_CanBeSelected as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
def test_C17411467_AddPhysxRagdollComponent(self, request, workspace, editor, launcher_platform):
|
||||
from . import C17411467_AddPhysxRagdollComponent as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
def test_C12905528_ForceRegion_WithNonTriggerCollider(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12905528_ForceRegion_WithNonTriggerCollider as test_module
|
||||
# Fixme: expected_lines = ["[Warning] (PhysX Force Region) - Please ensure collider component marked as trigger exists in entity"]
|
||||
@@ -522,4 +445,35 @@ class TestAutomation(TestAutomationBase):
|
||||
|
||||
def test_C100000_RigidBody_EnablingGravityWorksPoC(self, request, workspace, editor, launcher_platform):
|
||||
from . import C100000_RigidBody_EnablingGravityWorksPoC as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxsystemconfiguration.setreg','C3510644_Collider_CollisionGroups.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C3510644_Collider_CollisionGroups(self, request, workspace, editor, launcher_platform):
|
||||
from . import C3510644_Collider_CollisionGroups as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982798_Collider_ColliderRotationOffset(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982798_Collider_ColliderRotationOffset as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15308217_NoCrash_LevelSwitch(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15308217_NoCrash_LevelSwitch as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C6090547_ForceRegion_ParentChildForceRegions(self, request, workspace, editor, launcher_platform):
|
||||
from . import C6090547_ForceRegion_ParentChildForceRegions as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C19578021_ShapeCollider_CanBeAdded(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19578021_ShapeCollider_CanBeAdded as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15425929_Undo_Redo(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
"""
|
||||
|
||||
# This suite consists of all test cases that are passing and have been verified.
|
||||
|
||||
import pytest
|
||||
import os
|
||||
import sys
|
||||
|
||||
from .FileManagement import FileManagement as fm
|
||||
from ly_test_tools import LAUNCHERS
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
|
||||
|
||||
from base import TestAutomationBase
|
||||
|
||||
|
||||
revert_physics_config = fm.file_revert_list(['physxdebugconfiguration.setreg', 'physxdefaultsceneconfiguration.setreg', 'physxsystemconfiguration.setreg'], 'AutomatedTesting/Registry')
|
||||
|
||||
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
class TestAutomation(TestAutomationBase):
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_C19536274_GetCollisionName_PrintsName(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19536274_GetCollisionName_PrintsName as test_module
|
||||
# Fixme: expected_lines=["Layer Name: Right"]
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_C19536277_GetCollisionName_PrintsNothing(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19536277_GetCollisionName_PrintsNothing as test_module
|
||||
# All groups present in the PhysX Collider that could show up in test
|
||||
# Fixme: collision_groups = ["All", "None", "All_NoTouchBend", "All_3", "None_1", "All_NoTouchBend_1", "All_2", "None_1_1", "All_NoTouchBend_1_1", "All_1", "None_1_1_1", "All_NoTouchBend_1_1_1", "All_4", "None_1_1_1_1", "All_NoTouchBend_1_1_1_1", "GroupLeft", "GroupRight"]
|
||||
# Fixme: for group in collision_groups:
|
||||
# Fixme: unexpected_lines.append(f"GroupName: {group}")
|
||||
# Fixme: expected_lines=["GroupName: "]
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
"""
|
||||
|
||||
# This suite consists of all test cases that are passing and have been verified.
|
||||
|
||||
import pytest
|
||||
import os
|
||||
import sys
|
||||
|
||||
from .FileManagement import FileManagement as fm
|
||||
from ly_test_tools import LAUNCHERS
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
|
||||
|
||||
from base import TestAutomationBase
|
||||
|
||||
|
||||
revert_physics_config = fm.file_revert_list(['physxdebugconfiguration.setreg', 'physxdefaultsceneconfiguration.setreg', 'physxsystemconfiguration.setreg'], 'AutomatedTesting/Registry')
|
||||
|
||||
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
class TestAutomation(TestAutomationBase):
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_C19536274_GetCollisionName_PrintsName(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19536274_GetCollisionName_PrintsName as test_module
|
||||
# Fixme: expected_lines=["Layer Name: Right"]
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_C19536277_GetCollisionName_PrintsNothing(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19536277_GetCollisionName_PrintsNothing as test_module
|
||||
# All groups present in the PhysX Collider that could show up in test
|
||||
# Fixme: collision_groups = ["All", "None", "All_NoTouchBend", "All_3", "None_1", "All_NoTouchBend_1", "All_2", "None_1_1", "All_NoTouchBend_1_1", "All_1", "None_1_1_1", "All_NoTouchBend_1_1_1", "All_4", "None_1_1_1_1", "All_NoTouchBend_1_1_1_1", "GroupLeft", "GroupRight"]
|
||||
# Fixme: for group in collision_groups:
|
||||
# Fixme: unexpected_lines.append(f"GroupName: {group}")
|
||||
# Fixme: expected_lines=["GroupName: "]
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:231d5ac32c95334eeb1cbf77ea0bceae1d8010de3290dfdbd991abb46d18bae6
|
||||
size 6844
|
||||
oid sha256:83af66a6db4ff2b4df7212099b661a96668cfb326d8984e41b16506ec0062141
|
||||
size 5844
|
||||
|
||||
@@ -38,6 +38,13 @@
|
||||
"Gems/PrimitiveAssets"
|
||||
]
|
||||
},
|
||||
"MaterialEditor":
|
||||
{
|
||||
"SourcePaths":
|
||||
[
|
||||
"Gems/Atom/Tools/MaterialEditor"
|
||||
]
|
||||
},
|
||||
"UiBasics":
|
||||
{
|
||||
"SourcePaths":
|
||||
|
||||
+4
-2
@@ -75,7 +75,9 @@ foreach(restricted_platform ${PAL_RESTRICTED_PLATFORMS})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(scripts)
|
||||
if(NOT INSTALLED_ENGINE)
|
||||
add_subdirectory(scripts)
|
||||
endif()
|
||||
|
||||
# SPEC-1417 will investigate and fix this
|
||||
if(NOT PAL_PLATFORM_NAME STREQUAL "Mac")
|
||||
@@ -125,5 +127,5 @@ if(NOT INSTALLED_ENGINE)
|
||||
ly_setup_o3de_install()
|
||||
|
||||
# IMPORTANT: must be included last
|
||||
include(cmake/CPack.cmake)
|
||||
include(cmake/Packaging.cmake)
|
||||
endif()
|
||||
|
||||
@@ -10,5 +10,4 @@
|
||||
#
|
||||
|
||||
add_subdirectory(CryCommon)
|
||||
add_subdirectory(CryFont)
|
||||
add_subdirectory(CrySystem)
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
Matrix34 m_matInv;
|
||||
Vec3 m_eyePosInWS;
|
||||
Vec3 m_eyePosInOS;
|
||||
Plane m_volumeTraceStartPlane;
|
||||
Plane_tpl<f32> m_volumeTraceStartPlane;
|
||||
AABB m_renderBoundsOS;
|
||||
bool m_viewerInsideVolume;
|
||||
bool m_nearPlaneIntersectsVolume;
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
|
||||
virtual void mfPrepare(bool bCheckOverflow);
|
||||
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
|
||||
virtual void mfGetPlane(Plane& pl);
|
||||
virtual void mfGetPlane(Plane_tpl<f32>& pl);
|
||||
|
||||
virtual void Create(uint32 nVerticesCount, SVF_P3F_C4B_T2F* pVertices, uint32 nIndicesCount, const void* pIndices, uint32 nIndexSizeof);
|
||||
void ReleaseOcean();
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
virtual ~CREWaterVolume();
|
||||
virtual void mfPrepare(bool bCheckOverflow);
|
||||
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
|
||||
virtual void mfGetPlane(Plane& pl);
|
||||
virtual void mfGetPlane(Plane_tpl<f32>& pl);
|
||||
virtual void mfCenter(Vec3& vCenter, CRenderObject* pObj);
|
||||
|
||||
virtual void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
Vec3 m_center;
|
||||
AABB m_WSBBox;
|
||||
|
||||
Plane m_fogPlane;
|
||||
Plane_tpl<f32> m_fogPlane;
|
||||
float m_fogDensity;
|
||||
Vec3 m_fogColor;
|
||||
bool m_fogColorAffectedBySun;
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
#include <CryCommon/ISystem.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
/*!
|
||||
* Signal LY to create an ICryFont
|
||||
*/
|
||||
class CryFontCreationRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
|
||||
virtual bool CreateCryFont([[maybe_unused]] SSystemGlobalEnvironment& env, [[maybe_unused]] const SSystemInitParams& initParams) {return false;} //! return false to fall back to default CryFont initialization
|
||||
};
|
||||
using CryFontCreationRequestBus = AZ::EBus<CryFontCreationRequests>;
|
||||
|
||||
}
|
||||
@@ -594,7 +594,7 @@ public:
|
||||
ILINE const Vec3& GetFPVertex(int nId) const; //get far-plane vertices
|
||||
ILINE const Vec3& GetPPVertex(int nId) const; //get projection-plane vertices
|
||||
|
||||
ILINE const Plane* GetFrustumPlane(int numplane) const { return &m_fp[numplane]; }
|
||||
ILINE const Plane_tpl<f32>* GetFrustumPlane(int numplane) const { return &m_fp[numplane]; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Z-Buffer ranges.
|
||||
@@ -720,7 +720,7 @@ private:
|
||||
Vec3 m_cltn, m_crtn, m_clbn, m_crbn; //this are the 4 vertices of the near-plane in cam-space
|
||||
Vec3 m_cltf, m_crtf, m_clbf, m_crbf; //this are the 4 vertices of the farclip-plane in cam-space
|
||||
|
||||
Plane m_fp [FRUSTUM_PLANES]; //
|
||||
Plane_tpl<f32> m_fp [FRUSTUM_PLANES]; //
|
||||
uint32 m_idx1[FRUSTUM_PLANES], m_idy1[FRUSTUM_PLANES], m_idz1[FRUSTUM_PLANES]; //
|
||||
uint32 m_idx2[FRUSTUM_PLANES], m_idy2[FRUSTUM_PLANES], m_idz2[FRUSTUM_PLANES]; //
|
||||
|
||||
@@ -742,7 +742,7 @@ public:
|
||||
m_crtp = arrvVerts[2];
|
||||
m_crbp = arrvVerts[3];
|
||||
}
|
||||
inline void SetFrustumPlane(int i, const Plane& plane)
|
||||
inline void SetFrustumPlane(int i, const Plane_tpl<f32>& plane)
|
||||
{
|
||||
m_fp[i] = plane;
|
||||
//do not break strict aliasing rules, use union instead of reinterpret_casts
|
||||
@@ -1180,12 +1180,12 @@ inline void CCamera::UpdateFrustum()
|
||||
//-------------------------------------------------------------------------------
|
||||
//--- calculate the six frustum-planes using the frustum edges in world-space ---
|
||||
//-------------------------------------------------------------------------------
|
||||
m_fp[FR_PLANE_NEAR ] = Plane::CreatePlane(m_crtn + GetPosition(), m_cltn + GetPosition(), m_crbn + GetPosition());
|
||||
m_fp[FR_PLANE_RIGHT ] = Plane::CreatePlane(m_crbf + GetPosition(), m_crtf + GetPosition(), GetPosition());
|
||||
m_fp[FR_PLANE_LEFT ] = Plane::CreatePlane(m_cltf + GetPosition(), m_clbf + GetPosition(), GetPosition());
|
||||
m_fp[FR_PLANE_TOP ] = Plane::CreatePlane(m_crtf + GetPosition(), m_cltf + GetPosition(), GetPosition());
|
||||
m_fp[FR_PLANE_BOTTOM] = Plane::CreatePlane(m_clbf + GetPosition(), m_crbf + GetPosition(), GetPosition());
|
||||
m_fp[FR_PLANE_FAR ] = Plane::CreatePlane(m_crtf + GetPosition(), m_crbf + GetPosition(), m_cltf + GetPosition()); //clip-plane
|
||||
m_fp[FR_PLANE_NEAR ] = Plane_tpl<f32>::CreatePlane(m_crtn + GetPosition(), m_cltn + GetPosition(), m_crbn + GetPosition());
|
||||
m_fp[FR_PLANE_RIGHT ] = Plane_tpl<f32>::CreatePlane(m_crbf + GetPosition(), m_crtf + GetPosition(), GetPosition());
|
||||
m_fp[FR_PLANE_LEFT ] = Plane_tpl<f32>::CreatePlane(m_cltf + GetPosition(), m_clbf + GetPosition(), GetPosition());
|
||||
m_fp[FR_PLANE_TOP ] = Plane_tpl<f32>::CreatePlane(m_crtf + GetPosition(), m_cltf + GetPosition(), GetPosition());
|
||||
m_fp[FR_PLANE_BOTTOM] = Plane_tpl<f32>::CreatePlane(m_clbf + GetPosition(), m_crbf + GetPosition(), GetPosition());
|
||||
m_fp[FR_PLANE_FAR ] = Plane_tpl<f32>::CreatePlane(m_crtf + GetPosition(), m_crbf + GetPosition(), m_cltf + GetPosition()); //clip-plane
|
||||
|
||||
uint32 rh = m_Matrix.IsOrthonormalRH();
|
||||
if (rh == 0)
|
||||
|
||||
@@ -1168,17 +1168,6 @@ namespace Distance {
|
||||
return fDist2;
|
||||
}
|
||||
|
||||
// Compute both the min and max distances of a box to a plane, in the sense of the plane normal.
|
||||
inline void AABB_Plane(float* pfDistMin, float* pfDistMax, const AABB& box, const Plane& pl)
|
||||
{
|
||||
float fDist0 = pl.DistFromPlane(box.min),
|
||||
fDistX = (box.max.x - box.min.x) * pl.n.x,
|
||||
fDistY = (box.max.y - box.min.y) * pl.n.y,
|
||||
fDistZ = (box.max.z - box.min.z) * pl.n.z;
|
||||
*pfDistMin = fDist0 + min(fDistX, 0.f) + min(fDistY, 0.f) + min(fDistZ, 0.f);
|
||||
*pfDistMax = fDist0 + max(fDistX, 0.f) + max(fDistY, 0.f) + max(fDistZ, 0.f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Distance: Sphere_Triangle
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <Cry_Geo.h>
|
||||
|
||||
namespace Intersect {
|
||||
inline bool Ray_Plane(const Ray& ray, const Plane& plane, Vec3& output, bool bSingleSidePlane = true)
|
||||
inline bool Ray_Plane(const Ray& ray, const Plane_tpl<f32>& plane, Vec3& output, bool bSingleSidePlane = true)
|
||||
{
|
||||
float cosine = plane.n | ray.direction;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Intersect {
|
||||
return true; //intersection occurred
|
||||
}
|
||||
|
||||
inline bool Line_Plane(const Line& line, const Plane& plane, Vec3& output, bool bSingleSidePlane = true)
|
||||
inline bool Line_Plane(const Line& line, const Plane_tpl<f32>& plane, Vec3& output, bool bSingleSidePlane = true)
|
||||
{
|
||||
float cosine = plane.n | line.direction;
|
||||
|
||||
|
||||
@@ -945,29 +945,6 @@ namespace Overlap {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
*
|
||||
* we use the SEPARATING-AXIS-TEST for OBB/Plane overlap.
|
||||
*
|
||||
* Example:
|
||||
* bool result=Overlap::OBB_Plane( pos,obb, plane );
|
||||
*
|
||||
*/
|
||||
inline bool OBB_Plane(const Vec3& pos, const OBB& obb, const Plane& plane)
|
||||
{
|
||||
//the new center-position in world-space
|
||||
Vec3 p = obb.m33 * obb.c + pos;
|
||||
//extract the orientation-vectors from the columns of the 3x3 matrix
|
||||
//and scale them by the half-lengths
|
||||
Vec3 ax = Vec3(obb.m33.m00, obb.m33.m10, obb.m33.m20) * obb.h.x;
|
||||
Vec3 ay = Vec3(obb.m33.m01, obb.m33.m11, obb.m33.m21) * obb.h.y;
|
||||
Vec3 az = Vec3(obb.m33.m02, obb.m33.m12, obb.m33.m22) * obb.h.z;
|
||||
//check OBB against Plane, using the plane-normal as separating axis
|
||||
return fabsf(plane | p) < (fabsf(plane.n | ax) + fabsf(plane.n | ay) + fabsf(plane.n | az));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
*
|
||||
* we use the SEPARATING AXIS TEST to check if a triangle and AABB overlap.
|
||||
@@ -1214,7 +1191,7 @@ namespace Overlap {
|
||||
|
||||
//test if the box intersects the plane of the triangle
|
||||
//compute plane equation of triangle: normal*x+d=0
|
||||
Plane plane = Plane::CreatePlane((e0 % e1), v0);
|
||||
Plane_tpl<f32> plane = Plane_tpl<f32>::CreatePlane((e0 % e1), v0);
|
||||
|
||||
Vec3 vmin, vmax;
|
||||
if (plane.n.x > 0.0f)
|
||||
@@ -1505,7 +1482,7 @@ namespace Overlap {
|
||||
|
||||
//test if the box overlaps the plane of the triangle
|
||||
//compute plane equation of triangle: normal*x+d=0
|
||||
Plane plane = Plane::CreatePlane((e0 % e1), v0);
|
||||
Plane_tpl<f32> plane = Plane_tpl<f32>::CreatePlane((e0 % e1), v0);
|
||||
|
||||
Vec3 vmin, vmax;
|
||||
if (plane.n.x > 0.0f)
|
||||
|
||||
@@ -458,7 +458,7 @@ struct SClipVolumeBlendInfo
|
||||
{
|
||||
static const int BlendPlaneCount = 2;
|
||||
|
||||
Plane blendPlanes[BlendPlaneCount];
|
||||
Plane_tpl<f32> blendPlanes[BlendPlaneCount];
|
||||
struct IClipVolume* blendVolumes[BlendPlaneCount];
|
||||
};
|
||||
|
||||
|
||||
@@ -731,8 +731,8 @@ struct IWaterVolumeRenderNode
|
||||
virtual void SetAuxPhysParams(pe_params_area*) = 0;
|
||||
|
||||
virtual void CreateOcean(uint64 volumeID, /* TBD */ bool keepSerializationParams = false) = 0;
|
||||
virtual void CreateArea(uint64 volumeID, const Vec3* pVertices, unsigned int numVertices, const Vec2& surfUVScale, const Plane& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
|
||||
virtual void CreateRiver(uint64 volumeID, const Vec3* pVertices, unsigned int numVertices, float uTexCoordBegin, float uTexCoordEnd, const Vec2& surfUVScale, const Plane& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
|
||||
virtual void CreateArea(uint64 volumeID, const Vec3* pVertices, unsigned int numVertices, const Vec2& surfUVScale, const Plane_tpl<f32>& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
|
||||
virtual void CreateRiver(uint64 volumeID, const Vec3* pVertices, unsigned int numVertices, float uTexCoordBegin, float uTexCoordEnd, const Vec2& surfUVScale, const Plane_tpl<f32>& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
|
||||
virtual void CreateRiver(uint64 volumeID, const AZStd::vector<AZ::Vector3>& verticies, const AZ::Transform& transform, float uTexCoordBegin, float uTexCoordEnd, const AZ::Vector2& surfUVScale, const AZ::Plane& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
|
||||
|
||||
virtual void SetAreaPhysicsArea(const Vec3* pVertices, unsigned int numVertices, bool keepSerializationParams = false) = 0;
|
||||
|
||||
@@ -52,7 +52,6 @@ struct SShaderItem;
|
||||
class ITexture;
|
||||
struct IMaterial;
|
||||
struct SParam;
|
||||
class CMaterial;
|
||||
struct SShaderSerializeContext;
|
||||
struct IAnimNode;
|
||||
struct SSkinningData;
|
||||
|
||||
@@ -119,7 +119,7 @@ struct IRenderElement
|
||||
virtual void mfCenter(Vec3& centr, CRenderObject* pObj) = 0;
|
||||
virtual void mfGetBBox(Vec3& vMins, Vec3& vMaxs) = 0;
|
||||
virtual void mfReset() = 0;
|
||||
virtual void mfGetPlane(Plane& pl) = 0;
|
||||
virtual void mfGetPlane(Plane_tpl<f32>& pl) = 0;
|
||||
virtual void mfExport(struct SShaderSerializeContext& SC) = 0;
|
||||
virtual void mfImport(struct SShaderSerializeContext& SC, uint32& offset) = 0;
|
||||
virtual void mfPrecache(const SShaderItem& SH) = 0;
|
||||
@@ -265,7 +265,7 @@ public:
|
||||
void mfPrecache([[maybe_unused]] const SShaderItem& SH) override {}
|
||||
void mfExport([[maybe_unused]] struct SShaderSerializeContext& SC) override { CryFatalError("mfExport has not been implemented for this render element type"); }
|
||||
void mfImport([[maybe_unused]] struct SShaderSerializeContext& SC, [[maybe_unused]] uint32& offset) override { CryFatalError("mfImport has not been implemented for this render element type"); }
|
||||
void mfGetPlane(Plane& pl) override;
|
||||
void mfGetPlane(Plane_tpl<f32>& pl) override;
|
||||
void* mfGetPointer([[maybe_unused]] ESrcPointer ePT, [[maybe_unused]] int* Stride, [[maybe_unused]] EParamType Type, [[maybe_unused]] ESrcPointer Dst, [[maybe_unused]] int Flags) override { return nullptr; }
|
||||
|
||||
uint16 mfGetFlags() override { return m_Flags; }
|
||||
|
||||
@@ -1,845 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : CCryFont class.
|
||||
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include "CryFont.h"
|
||||
#include "CryPath.h"
|
||||
#include "FFont.h"
|
||||
#include "FontTexture.h"
|
||||
#include "FontRenderer.h"
|
||||
#include "ILocalizationManager.h"
|
||||
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzFramework/Archive/IArchive.h>
|
||||
|
||||
// Static member definitions
|
||||
const Vec2i CCryFont::defaultGlyphSize = Vec2i(ICryFont::defaultGlyphSizeX, ICryFont::defaultGlyphSizeY);
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
static void DumpFontTexture(IConsoleCmdArgs* pArgs)
|
||||
{
|
||||
if (pArgs->GetArgCount() != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pFontName = pArgs->GetArg(1);
|
||||
|
||||
if (pFontName && *pFontName && *pFontName != '0')
|
||||
{
|
||||
string fontFile("@devroot@/");
|
||||
fontFile += pFontName;
|
||||
fontFile += ".bmp";
|
||||
|
||||
CFFont* pFont = (CFFont*) gEnv->pCryFont->GetFont(pFontName);
|
||||
if (pFont)
|
||||
{
|
||||
pFont->GetFontTexture()->WriteToFile(fontFile.c_str());
|
||||
gEnv->pLog->LogWithType(IMiniLog::eInputResponse, "Dumped \"%s\" texture to \"%s\"!", pFontName, fontFile.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpFontNames([[maybe_unused]] IConsoleCmdArgs* pArgs)
|
||||
{
|
||||
string names = gEnv->pCryFont->GetLoadedFontNames();
|
||||
gEnv->pLog->LogWithType(IMiniLog::eInputResponse, "Currently loaded fonts: %s", names.c_str());
|
||||
}
|
||||
|
||||
static void ReloadFonts([[maybe_unused]] IConsoleCmdArgs* pArgs)
|
||||
{
|
||||
gEnv->pCryFont->ReloadAllFonts();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
//! Stores paths to styled font assets for a given set of languages
|
||||
//! This struct stores the XML data contained within the <font> tag of
|
||||
//! an enclosing <fontfamily> definition:
|
||||
//!
|
||||
//! <fontfamily name="FontFamilyName">
|
||||
//! <font lang="Language1, Language2">
|
||||
//! <file path="regular.font" />
|
||||
//! <file path="bold.font" tags="b" />
|
||||
//! <file path="italic.font" tags="i" />
|
||||
//! <file path="bolditalic.font" tags="b,i" />
|
||||
//! </font>
|
||||
//! </fontfamily>
|
||||
struct FontTagXml
|
||||
{
|
||||
//! \return True if all font asset paths are non-empty, false otherwise
|
||||
bool IsValid() const
|
||||
{
|
||||
// Note that "lang" can be empty
|
||||
return !m_fontFilename.empty()
|
||||
&& !m_boldFontFilename.empty()
|
||||
&& !m_italicFontFilename.empty()
|
||||
&& !m_boldItalicFontFilename.empty();
|
||||
}
|
||||
|
||||
string m_lang; //!< Stores a comma-separated list of languages this collection of fonts applies to.
|
||||
//!< If this is an empty string, it implies that these set of fonts will be applied
|
||||
//!< by default (when a language is being used but no fonts in the font family are
|
||||
//!< mapped to that language).
|
||||
|
||||
string m_fontFilename; //!< Font used when no styling is applied.
|
||||
string m_boldFontFilename; //!< Bold-styled font
|
||||
string m_italicFontFilename; //!< Italic-styled font
|
||||
string m_boldItalicFontFilename; //!< Bold-italic-styled font
|
||||
};
|
||||
|
||||
//! Stores parsed font family XML data.
|
||||
//! This struct contains the name of the font family and a list of font
|
||||
//! file XML data for all the language-specific mappings of this
|
||||
//! font family.
|
||||
//!
|
||||
//! Example XML:
|
||||
//!
|
||||
//! <fontfamily name="FontFamilyName">
|
||||
//! <font>
|
||||
//! <file path="regular.font" />
|
||||
//! <file path="bold.font" tags="b" />
|
||||
//! <file path="italic.font" tags="i" />
|
||||
//! <file path="bolditalic.font" tags="b,i" />
|
||||
//! </font>
|
||||
//! <font lang="korean">
|
||||
//! <file path="../korean/korean-regular.font" />
|
||||
//! <file path="../korean/korean-italic.font" tags="b" />
|
||||
//! <file path="../korean/korean-bold.font" tags="i" />
|
||||
//! <file path="../korean/korean-bolditalic.font" tags="b,i" />
|
||||
//! </font>
|
||||
//! <font lang="chinesesimplified">
|
||||
//! <file path="../chinesesimplified/chinesesimplified-regular.font" />
|
||||
//! <file path="../chinesesimplified/chinesesimplified-bold.font" tags="b" />
|
||||
//! <file path="../chinesesimplified/chinesesimplified-italic.font" tags="i" />
|
||||
//! <file path="../chinesesimplified/chinesesimplified-bolditalic.font" tags="b,i" />
|
||||
//! </font>
|
||||
//! </fontfamily>
|
||||
struct FontFamilyTagXml
|
||||
{
|
||||
//! Returns true if all font file fields were parsed, false otherwise.
|
||||
bool IsValid() const
|
||||
{
|
||||
for (const FontTagXml& fontTagXml : m_fontTagsXml)
|
||||
{
|
||||
if (!fontTagXml.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Every font family must have a name
|
||||
return !m_fontFamilyName.empty();
|
||||
}
|
||||
|
||||
string m_fontFamilyName; //!< Value of the "name" font-family tag attribute
|
||||
AZStd::list<FontTagXml> m_fontTagsXml; //!< List of child <font> tag data.
|
||||
};
|
||||
|
||||
//! Returns true if the XML tree was traversed successfully, false otherwise.
|
||||
//!
|
||||
//! Note that, if this function returns true, it simply means that there were
|
||||
//! no unexpected structure issues with the given XML tree, it doesn't
|
||||
//! necessarily mean that all the required fields were parsed.
|
||||
bool ParseFontFamilyXml(const XmlNodeRef& node, FontFamilyTagXml& xmlData)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// <fontfamily>
|
||||
if (AZStd::string(node->getTag()) == "fontfamily")
|
||||
{
|
||||
const int numAttributes = node->getNumAttributes();
|
||||
|
||||
if (numAttributes <= 0)
|
||||
{
|
||||
// Expecting at least one attribute
|
||||
return false;
|
||||
}
|
||||
|
||||
string name;
|
||||
|
||||
for (int i = 0, count = node->getNumAttributes(); i < count; ++i)
|
||||
{
|
||||
const char* key = "";
|
||||
const char* value = "";
|
||||
if (node->getAttributeByIndex(i, &key, &value))
|
||||
{
|
||||
if (string(key) == "name")
|
||||
{
|
||||
name = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unexpected font tag attribute
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
name.Trim();
|
||||
if (!name.empty())
|
||||
{
|
||||
xmlData.m_fontFamilyName = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Font family must have a name
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// <font>
|
||||
if (AZStd::string(node->getTag()) == "font")
|
||||
{
|
||||
xmlData.m_fontTagsXml.push_back(FontTagXml());
|
||||
|
||||
string lang;
|
||||
for (int i = 0, count = node->getNumAttributes(); i < count; ++i)
|
||||
{
|
||||
const char* key = "";
|
||||
const char* value = "";
|
||||
if (node->getAttributeByIndex(i, &key, &value))
|
||||
{
|
||||
if (string(key) == "lang")
|
||||
{
|
||||
lang = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unexpected font tag attribute
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lang.Trim();
|
||||
if (!lang.empty())
|
||||
{
|
||||
xmlData.m_fontTagsXml.back().m_lang = lang;
|
||||
}
|
||||
}
|
||||
|
||||
// <file>
|
||||
else if (AZStd::string(node->getTag()) == "file")
|
||||
{
|
||||
const int numAttributes = node->getNumAttributes();
|
||||
|
||||
if (numAttributes <= 0)
|
||||
{
|
||||
// Expecting at least one attribute
|
||||
return false;
|
||||
}
|
||||
|
||||
string path;
|
||||
string tags;
|
||||
|
||||
for (int i = 0, count = node->getNumAttributes(); i < count; ++i)
|
||||
{
|
||||
const char* key = "";
|
||||
const char* value = "";
|
||||
if (node->getAttributeByIndex(i, &key, &value))
|
||||
{
|
||||
if (string(key) == "path")
|
||||
{
|
||||
path = value;
|
||||
}
|
||||
else if (string(key) == "tags")
|
||||
{
|
||||
tags = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unexpected font tag attribute
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tags.Trim();
|
||||
if (tags.empty())
|
||||
{
|
||||
xmlData.m_fontTagsXml.back().m_fontFilename = path;
|
||||
}
|
||||
else if (tags == "b")
|
||||
{
|
||||
xmlData.m_fontTagsXml.back().m_boldFontFilename = path;
|
||||
}
|
||||
else if (tags == "i")
|
||||
{
|
||||
xmlData.m_fontTagsXml.back().m_italicFontFilename = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We'll just assume any other tag indicates bold italic
|
||||
xmlData.m_fontTagsXml.back().m_boldItalicFontFilename = path;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0, count = node->getChildCount(); i < count; ++i)
|
||||
{
|
||||
XmlNodeRef child = node->getChild(i);
|
||||
if (!ParseFontFamilyXml(child, xmlData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Only attempt XML file load if file exists.
|
||||
//! There are use-cases where the XML path is not fully known (such as
|
||||
//! when referencing font family names from font family XML files), and
|
||||
//! attempting to load the XML files directly via ISystem() methods can
|
||||
//! produce a lot of warning noise.
|
||||
XmlNodeRef SafeLoadXmlFromFile(const string& xmlPath)
|
||||
{
|
||||
if (gEnv->pCryPak->IsFileExist(xmlPath.c_str()))
|
||||
{
|
||||
return GetISystem()->LoadXmlFromFile(xmlPath.c_str());
|
||||
}
|
||||
|
||||
return XmlNodeRef();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CCryFont::CCryFont(ISystem* pSystem)
|
||||
: m_pSystem(pSystem)
|
||||
, m_fonts()
|
||||
, m_rndPropIsRGBA(false)
|
||||
, m_rndPropHalfTexelOffset(0.5f)
|
||||
{
|
||||
assert(m_pSystem);
|
||||
|
||||
CryLogAlways("Using FreeType %d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
|
||||
|
||||
// Persist fonts for application lifetime to prevent unnecessary work
|
||||
REGISTER_CVAR(r_persistFontFamilies, r_persistFontFamilies, VF_NULL, "Persist loaded font families for lifetime of application.");
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
REGISTER_COMMAND("r_DumpFontTexture", DumpFontTexture, 0,
|
||||
"Dumps the specified font's texture to a bitmap file\n"
|
||||
"Use r_DumpFontTexture to get the loaded font names\n"
|
||||
"Usage: r_DumpFontTexture <fontname>");
|
||||
REGISTER_COMMAND("r_DumpFontNames", DumpFontNames, 0,
|
||||
"Logs a list of fonts currently loaded");
|
||||
REGISTER_COMMAND("r_ReloadFonts", ReloadFonts, VF_NULL,
|
||||
"Reload all fonts");
|
||||
#endif
|
||||
}
|
||||
|
||||
CCryFont::~CCryFont()
|
||||
{
|
||||
// Persist fonts for application lifetime to prevent unnecessary work
|
||||
m_persistedFontFamilies.clear();
|
||||
|
||||
for (FontMapItor it = m_fonts.begin(), itEnd = m_fonts.end(); it != itEnd; )
|
||||
{
|
||||
CFFont* pFont = it->second;
|
||||
++it; // iterate as Release() below will remove font from the map
|
||||
SAFE_RELEASE(pFont);
|
||||
}
|
||||
}
|
||||
|
||||
void CCryFont::Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
IFFont* CCryFont::NewFont(const char* pFontName)
|
||||
{
|
||||
string name = pFontName;
|
||||
name.MakeLower();
|
||||
|
||||
FontMapItor it = m_fonts.find(CONST_TEMP_STRING(name.c_str()));
|
||||
if (it != m_fonts.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
CFFont* pFont = new CFFont(m_pSystem, this, name.c_str());
|
||||
m_fonts.insert(FontMapItor::value_type(name, pFont));
|
||||
return pFont;
|
||||
}
|
||||
|
||||
IFFont* CCryFont::GetFont(const char* pFontName) const
|
||||
{
|
||||
FontMapConstItor it = m_fonts.find(CONST_TEMP_STRING(string(pFontName).MakeLower()));
|
||||
return it != m_fonts.end() ? it->second : 0;
|
||||
}
|
||||
|
||||
FontFamilyPtr CCryFont::LoadFontFamily(const char* pFontFamilyName)
|
||||
{
|
||||
FontFamilyPtr fontFamily(nullptr);
|
||||
string fontFamilyPath;
|
||||
string fontFamilyFullPath;
|
||||
|
||||
XmlNodeRef root = LoadFontFamilyXml(pFontFamilyName, fontFamilyPath, fontFamilyFullPath);
|
||||
|
||||
if (root)
|
||||
{
|
||||
FontFamilyTagXml xmlData;
|
||||
const bool parseSuccess = ParseFontFamilyXml(root, xmlData);
|
||||
if (parseSuccess && xmlData.IsValid())
|
||||
{
|
||||
const char* currentLanguage = gEnv->pSystem->GetLocalizationManager()->GetLanguage();
|
||||
FontTagXml* defaultFont = nullptr;
|
||||
FontTagXml* langSpecificFont = nullptr;
|
||||
|
||||
// Note that we don't break out of this for-loop early because we
|
||||
// want to find both the default font family and the
|
||||
// language-specific font family. We prefer the lang-specific
|
||||
// family but will fall back on the default if it doesn't exist.
|
||||
for (FontTagXml& fontTagXml : xmlData.m_fontTagsXml)
|
||||
{
|
||||
if (fontTagXml.m_lang.empty())
|
||||
{
|
||||
defaultFont = &fontTagXml;
|
||||
}
|
||||
else
|
||||
{
|
||||
int searchPos = 0;
|
||||
string langToken;
|
||||
|
||||
// "lang" font-tag attribute could be comma-separated
|
||||
while (!(langToken = fontTagXml.m_lang.Tokenize(",", searchPos)).empty())
|
||||
{
|
||||
if (langToken.Trim() == currentLanguage)
|
||||
{
|
||||
langSpecificFont = &fontTagXml;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (langSpecificFont || defaultFont)
|
||||
{
|
||||
// Prefer lang-specific font-family over default, if it exists
|
||||
FontTagXml* fontTagXml = langSpecificFont ? langSpecificFont : defaultFont;
|
||||
|
||||
// Pre-pend font family's path to make font family XML paths
|
||||
// relative to font family file
|
||||
fontTagXml->m_fontFilename = fontFamilyPath + fontTagXml->m_fontFilename;
|
||||
fontTagXml->m_boldFontFilename = fontFamilyPath + fontTagXml->m_boldFontFilename;
|
||||
fontTagXml->m_italicFontFilename = fontFamilyPath + fontTagXml->m_italicFontFilename;
|
||||
fontTagXml->m_boldItalicFontFilename = fontFamilyPath + fontTagXml->m_boldItalicFontFilename;
|
||||
|
||||
IFFont* normal = LoadFont(fontTagXml->m_fontFilename.c_str());
|
||||
IFFont* bold = LoadFont(fontTagXml->m_boldFontFilename.c_str());
|
||||
IFFont* italic = LoadFont(fontTagXml->m_italicFontFilename.c_str());
|
||||
IFFont* boldItalic = LoadFont(fontTagXml->m_boldItalicFontFilename.c_str());
|
||||
|
||||
// Only continue if all fonts were created successfully
|
||||
if (normal && bold && italic && boldItalic)
|
||||
{
|
||||
fontFamily.reset(new FontFamily(),
|
||||
[this](FontFamily* pFontFamily)
|
||||
{
|
||||
ReleaseFontFamily(pFontFamily);
|
||||
});
|
||||
|
||||
// Map the font family name both by path and by name defined
|
||||
// within the Font Family XML itself. This allows font
|
||||
// families to also be referenced simply by name.
|
||||
if (!AddFontFamilyToMaps(fontFamilyFullPath, xmlData.m_fontFamilyName, fontFamily))
|
||||
{
|
||||
SAFE_RELEASE(normal);
|
||||
SAFE_RELEASE(bold);
|
||||
SAFE_RELEASE(italic);
|
||||
SAFE_RELEASE(boldItalic);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fontFamily->familyName = xmlData.m_fontFamilyName;
|
||||
fontFamily->normal = normal;
|
||||
fontFamily->bold = bold;
|
||||
fontFamily->italic = italic;
|
||||
fontFamily->boldItalic = boldItalic;
|
||||
}
|
||||
else
|
||||
{
|
||||
SAFE_RELEASE(normal);
|
||||
SAFE_RELEASE(bold);
|
||||
SAFE_RELEASE(italic);
|
||||
SAFE_RELEASE(boldItalic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fontFamily)
|
||||
{
|
||||
// Unable to load font family XML, so load font normally and associate
|
||||
// it with a font family
|
||||
IFFont* pFont = LoadFont(pFontFamilyName);
|
||||
|
||||
if (pFont)
|
||||
{
|
||||
// Create a font family from a single font by assigning all the
|
||||
// font family stylings to the same font
|
||||
fontFamily.reset(new FontFamily(),
|
||||
[this](FontFamily* pFontFamily)
|
||||
{
|
||||
ReleaseFontFamily(pFontFamily);
|
||||
});
|
||||
|
||||
// Use filepath as familyName so font loading/unloading doesn't break with duplicate file names
|
||||
fontFamily->familyName = pFontFamilyName;
|
||||
|
||||
if (!AddFontFamilyToMaps(pFontFamilyName, fontFamily->familyName, fontFamily))
|
||||
{
|
||||
SAFE_RELEASE(pFont);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Assign all stylings to the same font
|
||||
fontFamily->normal = pFont;
|
||||
fontFamily->bold = pFont;
|
||||
fontFamily->italic = pFont;
|
||||
fontFamily->boldItalic = pFont;
|
||||
|
||||
// The other three stylings need to have their ref count
|
||||
// incremented (even though in this particular case its all the
|
||||
// same font) because when ReleaseFontFamily executes all fonts
|
||||
// in the family will be (corresondingly) Release'd.
|
||||
fontFamily->bold->AddRef();
|
||||
fontFamily->italic->AddRef();
|
||||
fontFamily->boldItalic->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
// Persist fonts for application lifetime to prevent unnecessary work
|
||||
if (r_persistFontFamilies > 0)
|
||||
{
|
||||
m_persistedFontFamilies.emplace_back(FontFamilyPtr(fontFamily));
|
||||
}
|
||||
|
||||
return fontFamily;
|
||||
}
|
||||
|
||||
FontFamilyPtr CCryFont::GetFontFamily(const char* pFontFamilyName)
|
||||
{
|
||||
FontFamilyPtr fontFamily = nullptr;
|
||||
|
||||
// The given string could either be: a font family name (defined in font
|
||||
// family XML), a file path (for regular fonts mapped as font families),
|
||||
// or just the filename of a font itself. Fonts are mapped by font family
|
||||
// name or by filepath, so attempt lookup using the map first since it's
|
||||
// the fastest.
|
||||
string loweredName = string(pFontFamilyName).Trim().MakeLower();
|
||||
auto it = m_fontFamilies.find(PathUtil::MakeGamePath(loweredName).c_str());
|
||||
if (it != m_fontFamilies.end())
|
||||
{
|
||||
fontFamily = FontFamilyPtr(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Iterate through all fonts, returning the first match where simply
|
||||
// the filename of a font could be a match. This case will likely be
|
||||
// hit when text markup references a font that doesn't belong to a
|
||||
// font family.
|
||||
for (const auto& fontFamilyIter : m_fontFamilies)
|
||||
{
|
||||
const AZStd::string& mappedFontFamilyName = fontFamilyIter.first;
|
||||
string mappedFilenameNoExtension = PathUtil::GetFileName(mappedFontFamilyName.c_str());
|
||||
|
||||
string searchStringFilenameNoExtension = PathUtil::GetFileName(loweredName);
|
||||
|
||||
if (mappedFilenameNoExtension == searchStringFilenameNoExtension)
|
||||
{
|
||||
fontFamily = FontFamilyPtr(fontFamilyIter.second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fontFamily;
|
||||
}
|
||||
|
||||
void CCryFont::AddCharsToFontTextures(FontFamilyPtr pFontFamily, const char* pChars, int glyphSizeX, int glyphSizeY)
|
||||
{
|
||||
pFontFamily->normal->AddCharsToFontTexture(pChars, glyphSizeX, glyphSizeY);
|
||||
pFontFamily->bold->AddCharsToFontTexture(pChars, glyphSizeX, glyphSizeY);
|
||||
pFontFamily->italic->AddCharsToFontTexture(pChars, glyphSizeX, glyphSizeY);
|
||||
pFontFamily->boldItalic->AddCharsToFontTexture(pChars, glyphSizeX, glyphSizeY);
|
||||
}
|
||||
|
||||
void CCryFont::SetRendererProperties(IRenderer* pRenderer)
|
||||
{
|
||||
if (pRenderer)
|
||||
{
|
||||
m_rndPropIsRGBA = (pRenderer->GetFeatures() & RFT_RGBA) != 0;
|
||||
m_rndPropHalfTexelOffset = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void CCryFont::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
if (!pSizer->Add(*this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pSizer->AddObject(m_fonts);
|
||||
}
|
||||
|
||||
string CCryFont::GetLoadedFontNames() const
|
||||
{
|
||||
string ret;
|
||||
for (FontMapConstItor it = m_fonts.begin(), itEnd = m_fonts.end(); it != itEnd; ++it)
|
||||
{
|
||||
CFFont* pFont = it->second;
|
||||
if (pFont)
|
||||
{
|
||||
if (!ret.empty())
|
||||
{
|
||||
ret += ",";
|
||||
}
|
||||
ret += pFont->GetName();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CCryFont::OnLanguageChanged()
|
||||
{
|
||||
ReloadAllFonts();
|
||||
|
||||
EBUS_EVENT(LanguageChangeNotificationBus, LanguageChanged);
|
||||
}
|
||||
|
||||
void CCryFont::ReloadAllFonts()
|
||||
{
|
||||
// Persist fonts for application lifetime to prevent unnecessary work
|
||||
m_persistedFontFamilies.clear();
|
||||
|
||||
AZStd::list<AZStd::string> fontFamilyFilenames;
|
||||
AZStd::list<FontFamily*> fontFamilyWeakPtrs;
|
||||
|
||||
// Iterate through all currently loaded font families
|
||||
for (auto it : m_fontFamilyReverseLookup)
|
||||
{
|
||||
fontFamilyWeakPtrs.push_back(it.first);
|
||||
fontFamilyFilenames.push_back(it.second->first);
|
||||
}
|
||||
|
||||
// Release font-family resources and unmap them
|
||||
for (auto fontFamily : fontFamilyWeakPtrs)
|
||||
{
|
||||
ReleaseFontFamily(fontFamily);
|
||||
}
|
||||
|
||||
// Reload the font families
|
||||
for (auto familyFilename : fontFamilyFilenames)
|
||||
{
|
||||
LoadFontFamily(familyFilename.c_str());
|
||||
}
|
||||
|
||||
// All UI text components need to reload their font assets (both in-game
|
||||
// and in-editor).
|
||||
EBUS_EVENT(FontNotificationBus, OnFontsReloaded);
|
||||
}
|
||||
|
||||
void CCryFont::UnregisterFont(const char* pFontName)
|
||||
{
|
||||
FontMapItor it = m_fonts.find(CONST_TEMP_STRING(pFontName));
|
||||
|
||||
#if defined(AZ_ENABLE_TRACING)
|
||||
IFFont* fontPtr = it->second;
|
||||
#endif
|
||||
|
||||
if (it != m_fonts.end())
|
||||
{
|
||||
m_fonts.erase(it);
|
||||
}
|
||||
|
||||
#if defined(AZ_ENABLE_TRACING)
|
||||
// Make sure the font being released isn't currently in use by a font family.
|
||||
// If it is, the FontFamily will have a dangling pointer and will cause a
|
||||
// crash when the FontFamily eventually gets released.
|
||||
for (auto reverseMapEntry : m_fontFamilyReverseLookup)
|
||||
{
|
||||
FontFamily* fontFamily = reverseMapEntry.first;
|
||||
AZ_Assert(fontFamily->normal != fontPtr,
|
||||
"The following font is being freed but still in use by a FontFamily: %s",
|
||||
pFontName);
|
||||
AZ_Assert(fontFamily->italic != fontPtr,
|
||||
"The following font is being freed but still in use by a FontFamily: %s",
|
||||
pFontName);
|
||||
AZ_Assert(fontFamily->bold != fontPtr,
|
||||
"The following font is being freed but still in use by a FontFamily: %s",
|
||||
pFontName);
|
||||
AZ_Assert(fontFamily->boldItalic != fontPtr,
|
||||
"The following font is being freed but still in use by a FontFamily: %s",
|
||||
pFontName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
IFFont* CCryFont::LoadFont(const char* pFontName)
|
||||
{
|
||||
string fontName = pFontName;
|
||||
fontName.MakeLower();
|
||||
|
||||
IFFont* font = GetFont(fontName);
|
||||
if (font)
|
||||
{
|
||||
font->AddRef(); // use existing loaded font
|
||||
}
|
||||
else
|
||||
{
|
||||
// attempt to create and load a new font, use the font pathname as the font name
|
||||
font = NewFont(fontName);
|
||||
if (!font)
|
||||
{
|
||||
string errorMsg = "Error creating a new font named ";
|
||||
errorMsg += fontName;
|
||||
errorMsg += ".";
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, errorMsg.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// creating font adds one to its refcount so no need for AddRef here
|
||||
if (!font->Load(fontName))
|
||||
{
|
||||
string errorMsg = "Error loading a font from ";
|
||||
errorMsg += fontName;
|
||||
errorMsg += ".";
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, errorMsg);
|
||||
font->Release();
|
||||
font = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
void CCryFont::ReleaseFontFamily(FontFamily* pFontFamily)
|
||||
{
|
||||
// Ensure that Font Family was mapped prior to destruction
|
||||
const bool isMapped = m_fontFamilyReverseLookup.find(pFontFamily) != m_fontFamilyReverseLookup.end();
|
||||
if (!isMapped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that the FontFamily is mapped both by filename and by "family name"
|
||||
auto it = m_fontFamilyReverseLookup[pFontFamily];
|
||||
m_fontFamilies.erase(it);
|
||||
string familyName(pFontFamily->familyName);
|
||||
m_fontFamilies.erase(familyName.MakeLower().c_str());
|
||||
|
||||
// Reverse lookup is used to avoid needing to store filename path with
|
||||
// the font family, so we need to remove that entry also.
|
||||
m_fontFamilyReverseLookup.erase(pFontFamily);
|
||||
|
||||
SAFE_RELEASE(pFontFamily->normal);
|
||||
SAFE_RELEASE(pFontFamily->bold);
|
||||
SAFE_RELEASE(pFontFamily->italic);
|
||||
SAFE_RELEASE(pFontFamily->boldItalic);
|
||||
}
|
||||
|
||||
bool CCryFont::AddFontFamilyToMaps(const char* pFontFamilyFilename, const char* pFontFamilyName, FontFamilyPtr fontFamily)
|
||||
{
|
||||
if (!pFontFamilyFilename || !pFontFamilyName || !fontFamily.get())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't support "updating" mapped values.
|
||||
AZStd::string loweredFilename(PathUtil::MakeGamePath(string(pFontFamilyFilename)).c_str());
|
||||
AZStd::to_lower<AZStd::string::iterator>(loweredFilename.begin(), loweredFilename.end());
|
||||
if (m_fontFamilies.find(loweredFilename) != m_fontFamilies.end())
|
||||
{
|
||||
string warnMsg;
|
||||
warnMsg.Format("Couldn't load Font Family '%s': already loaded", pFontFamilyFilename);
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, warnMsg.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Similarly, we don't support Font Family XMLs that have the same font
|
||||
// family name (we assume all Font Family names are unique).
|
||||
AZStd::string loweredFontFamilyName(pFontFamilyName);
|
||||
AZStd::to_lower<AZStd::string::iterator>(loweredFontFamilyName.begin(), loweredFontFamilyName.end());
|
||||
if (m_fontFamilies.find(loweredFontFamilyName) != m_fontFamilies.end())
|
||||
{
|
||||
string warnMsg;
|
||||
warnMsg.Format("Couldn't load Font Family '%s': already loaded", pFontFamilyName);
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, warnMsg.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// First, insert by filename
|
||||
AZStd::pair<AZStd::string, AZStd::weak_ptr<FontFamily>> insertPair(loweredFilename, fontFamily);
|
||||
auto iterPosition = m_fontFamilies.insert(insertPair).first;
|
||||
m_fontFamilyReverseLookup[fontFamily.get()] = iterPosition;
|
||||
|
||||
// Then, by Font Family name
|
||||
AZStd::pair<AZStd::string, AZStd::weak_ptr<FontFamily>> nameInsertPair(loweredFontFamilyName, fontFamily);
|
||||
m_fontFamilies.insert(nameInsertPair);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
XmlNodeRef CCryFont::LoadFontFamilyXml(const char* pFontFamilyName, string& outputDirectory, string& outputFullPath)
|
||||
{
|
||||
outputFullPath = pFontFamilyName;
|
||||
outputDirectory = PathUtil::GetPath(pFontFamilyName);
|
||||
XmlNodeRef root = SafeLoadXmlFromFile(outputFullPath);
|
||||
|
||||
// When parsing a <font> tag in markup, only the font name is given and
|
||||
// not a path, so we try to build a "best guess" path from the name.
|
||||
if (!root)
|
||||
{
|
||||
string fileNoExtension(PathUtil::GetFileName(pFontFamilyName));
|
||||
string fileExtension(PathUtil::GetExt(pFontFamilyName));
|
||||
|
||||
if (fileExtension.empty())
|
||||
{
|
||||
fileExtension = ".fontfamily";
|
||||
}
|
||||
|
||||
// Try: "fonts/fontName.fontfamily"
|
||||
outputDirectory = string("fonts/");
|
||||
outputFullPath = outputDirectory + fileNoExtension + fileExtension;
|
||||
root = SafeLoadXmlFromFile(outputFullPath);
|
||||
|
||||
// Finally, try: "fonts/fontName/fontName.fontfamily"
|
||||
if (!root)
|
||||
{
|
||||
outputDirectory = string("fonts/") + fileNoExtension + "/";
|
||||
outputFullPath = outputDirectory + fileNoExtension + fileExtension;
|
||||
root = SafeLoadXmlFromFile(outputFullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
EXPORTS
|
||||
ModuleInitISystem @2
|
||||
CryModuleGetMemoryInfo @8
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRYFONT_CRYFONT_H
|
||||
#define CRYINCLUDE_CRYFONT_CRYFONT_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include <IXml.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/smart_ptr/weak_ptr.h>
|
||||
#include <map>
|
||||
|
||||
class CFFont;
|
||||
|
||||
|
||||
class CCryFont
|
||||
: public ICryFont
|
||||
{
|
||||
friend class CFFont;
|
||||
|
||||
public:
|
||||
|
||||
static const Vec2i defaultGlyphSize; //!< Default glyph size indicates that glyphs in the font texture
|
||||
//!< should be rendered at the maximum resolution supported by
|
||||
//!< the font texture's glyph cell/slot configuration (configured
|
||||
//!< via font XML).
|
||||
|
||||
public:
|
||||
CCryFont(ISystem* pSystem);
|
||||
virtual ~CCryFont();
|
||||
|
||||
virtual void Release();
|
||||
virtual IFFont* NewFont(const char* pFontName);
|
||||
virtual IFFont* GetFont(const char* pFontName) const;
|
||||
virtual FontFamilyPtr LoadFontFamily(const char* pFontFamilyName) override;
|
||||
virtual FontFamilyPtr GetFontFamily(const char* pFontFamilyName) override;
|
||||
virtual void AddCharsToFontTextures(FontFamilyPtr pFontFamily, const char* pChars, int glyphSizeX = ICryFont::defaultGlyphSizeX, int glyphSizeY = ICryFont::defaultGlyphSizeY) override;
|
||||
virtual void SetRendererProperties(IRenderer* pRenderer);
|
||||
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
virtual string GetLoadedFontNames() const;
|
||||
virtual void OnLanguageChanged() override;
|
||||
virtual void ReloadAllFonts() override;
|
||||
|
||||
public:
|
||||
void UnregisterFont(const char* pFontName);
|
||||
bool RndPropIsRGBA() const { return m_rndPropIsRGBA; }
|
||||
float RndPropHalfTexelOffset() const { return m_rndPropHalfTexelOffset; }
|
||||
|
||||
private:
|
||||
typedef std::map<string, CFFont*> FontMap;
|
||||
typedef FontMap::iterator FontMapItor;
|
||||
typedef FontMap::const_iterator FontMapConstItor;
|
||||
|
||||
typedef AZStd::map<AZStd::string, AZStd::weak_ptr<FontFamily>> FontFamilyMap;
|
||||
typedef AZStd::map<FontFamily*, FontFamilyMap::iterator> FontFamilyReverseLookupMap;
|
||||
|
||||
private:
|
||||
//! Convenience method for loading fonts
|
||||
IFFont* LoadFont(const char* fontName);
|
||||
|
||||
//! Called when final FontFamily shared_ptr is destroyed; do not call directly.
|
||||
void ReleaseFontFamily(FontFamily* pFontFamily);
|
||||
|
||||
//! Adds new entries into both font family maps for the given font family
|
||||
//!
|
||||
//! Note that it's not possible to update Font Family mappings with this
|
||||
//! method. The only way to do that would be to release the font family
|
||||
//! and re-load it with the new values.
|
||||
//!
|
||||
//! \return True only if the Font Family was added to the maps, false for all other cases (such as
|
||||
//! when the font family is already mapped).
|
||||
bool AddFontFamilyToMaps(const char* pFontFamilyFilename, const char* pFontFamilyName, FontFamilyPtr fontFamily);
|
||||
|
||||
//! Internal method that (possibly) makes several attempts at locating and loading a given font family XML.
|
||||
//! \param pFontFamilyName The name of the font family, or path to a font family file.
|
||||
//! \param outputDirectory Path to loaded font family (no filename), may need resolving with PathUtil::MakeGamePath.
|
||||
//! \param outputFullPath Full path to loaded font family, may need resolving with PathUtil::MakeGamePath.
|
||||
XmlNodeRef LoadFontFamilyXml(const char* pFontFamilyName, string& outputDirectory, string& outputFullPath);
|
||||
|
||||
private:
|
||||
FontMap m_fonts;
|
||||
FontFamilyMap m_fontFamilies; //!< Map font family names to weak ptrs so we can construct shared_ptrs but not keep a ref ourselves.
|
||||
FontFamilyReverseLookupMap m_fontFamilyReverseLookup; //<! FontFamily pointer reverse-lookup for quick removal
|
||||
ISystem* m_pSystem;
|
||||
bool m_rndPropIsRGBA;
|
||||
float m_rndPropHalfTexelOffset;
|
||||
|
||||
int r_persistFontFamilies = 1; //!< Persist fonts for application lifetime to prevent unnecessary work; enabled by default.
|
||||
AZStd::vector<FontFamilyPtr> m_persistedFontFamilies; //!< Stores persisted fonts (if "persist font families" is enabled)
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CRYINCLUDE_CRYFONT_CRYFONT_H
|
||||
@@ -1,111 +0,0 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Russian resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
|
||||
#pragma code_page(1251)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Russian resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// German (Germany) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "000904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Amazon.com, Inc."
|
||||
VALUE "FileVersion", "1, 0, 0, 1"
|
||||
VALUE "LegalCopyright", "Portions of this file Copyright (c) Amazon.com, Inc. or its affiliates. All Rights Reserved. Original file Copyright (c) Crytek GMBH. Used under license by Amazon.com, Inc. and its affiliates."
|
||||
VALUE "ProductName", "Lumberyard"
|
||||
VALUE "ProductVersion", "1, 0, 0, 1"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x9, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // German (Germany) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define CRYFONT_EXPORTS
|
||||
|
||||
#include <platform.h>
|
||||
|
||||
#include <IFont.h>
|
||||
|
||||
#include <ILog.h>
|
||||
#include <IConsole.h>
|
||||
#include <IRenderer.h>
|
||||
#include <CrySizer.h>
|
||||
|
||||
#define USE_NULLFONT
|
||||
|
||||
#if defined(DEDICATED_SERVER)
|
||||
#define USE_NULLFONT_ALWAYS 1
|
||||
#endif
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#pragma once
|
||||
#ifndef CRYINCLUDE_CRYFONT_FBITMAP_H
|
||||
#define CRYINCLUDE_CRYFONT_FBITMAP_H
|
||||
|
||||
|
||||
class CFBitmap
|
||||
{
|
||||
public:
|
||||
CFBitmap();
|
||||
~CFBitmap();
|
||||
|
||||
int Blur(int iIterations);
|
||||
int Scale(float fScaleX, float fScaleY);
|
||||
|
||||
int BlitFrom(CFBitmap* pSrc, int iSX, int iSY, int iDX, int iDY, int iW, int iH);
|
||||
int BlitTo(CFBitmap* pDst, int iDX, int iDY, int iSX, int iSY, int iW, int iH);
|
||||
|
||||
int Create(int iWidth, int iHeight);
|
||||
int Release();
|
||||
|
||||
int SaveBitmap(const string& szFileName);
|
||||
int Get32Bpp(unsigned int** pBuffer)
|
||||
{
|
||||
(*pBuffer) = new unsigned int[m_iWidth * m_iHeight];
|
||||
|
||||
if (!(*pBuffer))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iDataSize = m_iWidth * m_iHeight;
|
||||
|
||||
for (int i = 0; i < iDataSize; i++)
|
||||
{
|
||||
(*pBuffer)[i] = (m_pData[i] << 24) | (m_pData[i] << 16) | (m_pData[i] << 8) | (m_pData[i]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GetWidth() { return m_iWidth; }
|
||||
int GetHeight() { return m_iHeight; }
|
||||
|
||||
void SetRenderData(void* pRenderData) { m_pIRenderData = pRenderData; };
|
||||
void* GetRenderData() { return m_pIRenderData; };
|
||||
|
||||
void GetMemoryUsage (class ICrySizer* pSizer);
|
||||
|
||||
unsigned char* GetData() { return m_pData; }
|
||||
|
||||
public:
|
||||
|
||||
int m_iWidth;
|
||||
int m_iHeight;
|
||||
|
||||
unsigned char* m_pData;
|
||||
void* m_pIRenderData;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_CRYFONT_FBITMAP_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Font class.
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYFONT_FFONT_H
|
||||
#define CRYINCLUDE_CRYFONT_FFONT_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include <vector>
|
||||
#include <Cry_Math.h>
|
||||
#include <Cry_Color.h>
|
||||
#include <CryString.h>
|
||||
#include "CryFont.h"
|
||||
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
|
||||
struct ISystem;
|
||||
class CFontTexture;
|
||||
|
||||
|
||||
class CFFont
|
||||
: public IFFont
|
||||
, public IFFont_RenderProxy
|
||||
{
|
||||
public:
|
||||
//! Determines how characters of different sizes should be handled during render.
|
||||
enum class SizeBehavior
|
||||
{
|
||||
Scale, //!< Default behavior; glyphs rendered at different sizes are rendered on scaled geometry
|
||||
Rerender //!< Similar to Scale, but the glyph in the font texture is re-rendered to match the target
|
||||
//!< size, as long as the size isn't greater than the maximum glyph/slot resolution as
|
||||
//!< configured for the font texture in the font XML.
|
||||
};
|
||||
|
||||
//! The hinting visual algorithm to be used (when hinting is enabled)
|
||||
enum class HintStyle
|
||||
{
|
||||
Normal, //!< Default hinting behavior provided by font renderer
|
||||
Light //!< Produces fuzzier glyphs but more accurately tracks glyph shape
|
||||
};
|
||||
|
||||
//! Chooses whether hinting info should be obtained from the font, turned off entirely, or automatically generated
|
||||
enum class HintBehavior
|
||||
{
|
||||
Default, //!< Obtain hinting data from font itself
|
||||
AutoHint, //!< Procedurally derive hinting information from glyph
|
||||
NoHinting, //!< Disable hinting entirely
|
||||
};
|
||||
|
||||
//! Simple struct used to communicate font hinting parameters to font renderer.
|
||||
struct FontHintParams
|
||||
{
|
||||
FontHintParams() : hintStyle(HintStyle::Normal), hintBehavior(HintBehavior::Default) { }
|
||||
|
||||
HintStyle hintStyle;
|
||||
HintBehavior hintBehavior;
|
||||
};
|
||||
|
||||
struct SRenderingPass
|
||||
{
|
||||
ColorB m_color;
|
||||
Vec2 m_posOffset;
|
||||
int m_blendSrc;
|
||||
int m_blendDest;
|
||||
|
||||
SRenderingPass()
|
||||
: m_color(255, 255, 255, 255)
|
||||
, m_posOffset(0, 0)
|
||||
, m_blendSrc(GS_BLSRC_SRCALPHA)
|
||||
, m_blendDest(GS_BLDST_ONEMINUSSRCALPHA)
|
||||
{
|
||||
}
|
||||
|
||||
void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const {}
|
||||
};
|
||||
|
||||
struct SEffect
|
||||
{
|
||||
string m_name;
|
||||
std::vector<SRenderingPass> m_passes;
|
||||
|
||||
SEffect(const char* name)
|
||||
: m_name(name)
|
||||
{
|
||||
assert(name);
|
||||
}
|
||||
|
||||
SRenderingPass* AddPass()
|
||||
{
|
||||
m_passes.push_back(SRenderingPass());
|
||||
return &m_passes[m_passes.size() - 1];
|
||||
}
|
||||
|
||||
void ClearPasses()
|
||||
{
|
||||
m_passes.resize(0);
|
||||
}
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(m_name);
|
||||
pSizer->AddObject(m_passes);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<SEffect> Effects;
|
||||
typedef Effects::iterator EffectsIt;
|
||||
|
||||
public:
|
||||
virtual int32 AddRef() override;
|
||||
virtual int32 Release() override;
|
||||
virtual bool Load(const char* pFontFilePath, unsigned int width, unsigned int height, unsigned int widthNumSlots, unsigned int heightNumSlots, unsigned int flags, float sizeRatio);
|
||||
virtual bool Load(const char* pXMLFile);
|
||||
virtual void Free();
|
||||
virtual void DrawString(float x, float y, const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx);
|
||||
virtual void DrawString(float x, float y, float z, const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx);
|
||||
virtual Vec2 GetTextSize(const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx);
|
||||
virtual size_t GetTextLength(const char* pStr, const bool asciiMultiLine) const;
|
||||
virtual void WrapText(string& result, float maxWidth, const char* pStr, const STextDrawContext& ctx);
|
||||
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
virtual void GetGradientTextureCoord(float& minU, float& minV, float& maxU, float& maxV) const;
|
||||
virtual unsigned int GetEffectId(const char* pEffectName) const;
|
||||
virtual unsigned int GetNumEffects() const;
|
||||
virtual const char* GetEffectName(unsigned int effectId) const;
|
||||
virtual Vec2 GetMaxEffectOffset(unsigned int effectId) const;
|
||||
virtual bool DoesEffectHaveTransparency(unsigned int effectId) const;
|
||||
virtual void AddCharsToFontTexture(const char* pChars, int glyphSizeX = ICryFont::defaultGlyphSizeX, int glyphSizeY = ICryFont::defaultGlyphSizeY) override;
|
||||
virtual Vec2 GetKerning(uint32_t leftGlyph, uint32_t rightGlyph, const STextDrawContext& ctx) const override;
|
||||
virtual float GetAscender(const STextDrawContext& ctx) const override;
|
||||
virtual float GetBaseline(const STextDrawContext& ctx) const override;
|
||||
|
||||
virtual uint32 GetNumQuadsForText(const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx);
|
||||
virtual uint32 WriteTextQuadsToBuffers(SVF_P2F_C4B_T2F_F4B* verts, uint16* indices, uint32 maxQuads, float x, float y, float z, const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx);
|
||||
virtual int GetFontTextureId();
|
||||
virtual uint32 GetFontTextureVersion();
|
||||
|
||||
virtual float GetSizeRatio() const override { return m_sizeRatio; }
|
||||
|
||||
public:
|
||||
virtual void RenderCallback(float x, float y, float z, const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx);
|
||||
|
||||
public:
|
||||
CFFont(ISystem* pSystem, CCryFont* pCryFont, const char* pFontName);
|
||||
|
||||
bool InitTexture();
|
||||
bool InitCache();
|
||||
|
||||
CFontTexture* GetFontTexture() const { return m_pFontTexture; }
|
||||
const string& GetName() const { return m_name; }
|
||||
|
||||
SEffect* AddEffect(const char* pEffectName);
|
||||
SEffect* GetDefaultEffect();
|
||||
|
||||
private:
|
||||
virtual ~CFFont();
|
||||
|
||||
void Prepare(const char* pStr, bool updateTexture, const Vec2i& glyphSize = CCryFont::defaultGlyphSize);
|
||||
void DrawStringUInternal(float x, float y, float z, const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx);
|
||||
Vec2 GetTextSizeUInternal(const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx);
|
||||
|
||||
using AddFunction = AZStd::function<void(const Vec3&, const Vec3&, const Vec3&, const Vec3&, const Vec2&, const Vec2&, const Vec2&, const Vec2&, uint32)>;
|
||||
using BeginPassFunction = AZStd::function<void(const SRenderingPass* pPass)>;
|
||||
|
||||
//! This function is used by both RenderCallback and WriteTextQuadsToBuffers
|
||||
//! To do this is takes two function pointers that implement the appropriate AddQuad and BeginPass behavior
|
||||
void CreateQuadsForText(float x, float y, float z, const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx,
|
||||
AddFunction AddQuad, BeginPassFunction BeginPass);
|
||||
|
||||
struct TextScaleInfoInternal
|
||||
{
|
||||
TextScaleInfoInternal(const Vec2& _scale, float _rcpCellWidth)
|
||||
: scale(_scale), rcpCellWidth(_rcpCellWidth) { }
|
||||
|
||||
Vec2 scale;
|
||||
float rcpCellWidth;
|
||||
};
|
||||
|
||||
TextScaleInfoInternal CalculateScaleInternal(const STextDrawContext& ctx) const;
|
||||
|
||||
Vec2 GetRestoredFontSize(const STextDrawContext& ctx) const;
|
||||
|
||||
private:
|
||||
string m_name;
|
||||
string m_curPath;
|
||||
|
||||
CFontTexture* m_pFontTexture;
|
||||
|
||||
size_t m_fontBufferSize;
|
||||
unsigned char* m_pFontBuffer;
|
||||
|
||||
int m_texID;
|
||||
uint32 m_textureVersion;
|
||||
|
||||
ISystem* m_pSystem;
|
||||
|
||||
AZStd::recursive_mutex m_fontMutex; //!< Controls access between main and render threads. It's common for one thread
|
||||
//!< to add un-cached glyphs to the font texture while another is accessing the
|
||||
//!< font texture.
|
||||
|
||||
CCryFont* m_pCryFont;
|
||||
|
||||
bool m_fontTexDirty;
|
||||
|
||||
Effects m_effects;
|
||||
|
||||
SVF_P3F_C4B_T2F* m_pDrawVB;
|
||||
|
||||
volatile int32 m_nRefCount;
|
||||
|
||||
bool m_monospacedFont; //!< True if this font is fixed/monospaced, false otherwise (obtained from FreeType)
|
||||
|
||||
float m_sizeRatio = IFFontConstants::defaultSizeRatio;
|
||||
SizeBehavior m_sizeBehavior = SizeBehavior::Scale; //!< Changes how glyphs rendered at different sizes are rendered.
|
||||
FontHintParams m_fontHintParams; //!< How the font should be hinted when its loaded and rendered to the font texture
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CRYINCLUDE_CRYFONT_FFONT_H
|
||||
@@ -1,448 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : XML parsing to load a font.
|
||||
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include "FFont.h"
|
||||
#include "FontTexture.h"
|
||||
#include <Cry_Math.h>
|
||||
#include <CryPath.h>
|
||||
|
||||
#if defined(WIN32) || defined(WIN64)
|
||||
# include <shlobj.h>
|
||||
# include <StringUtils.h>
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Xml parser implementation
|
||||
|
||||
enum
|
||||
{
|
||||
|
||||
ELEMENT_UNKNOWN = 0,
|
||||
ELEMENT_FONT = 1,
|
||||
ELEMENT_EFFECT = 2,
|
||||
ELEMENT_EFFECTFILE = 3,
|
||||
ELEMENT_PASS = 4,
|
||||
ELEMENT_PASS_COLOR = 5,
|
||||
ELEMENT_PASS_POSOFFSET = 12,
|
||||
ELEMENT_PASS_BLEND = 14
|
||||
};
|
||||
|
||||
static inline int GetBlendModeFromString(const string& str, bool dst)
|
||||
{
|
||||
int blend = GS_BLSRC_ONE;
|
||||
|
||||
if (str == "zero")
|
||||
{
|
||||
blend = dst ? GS_BLDST_ZERO : GS_BLSRC_ZERO;
|
||||
}
|
||||
else if (str == "one")
|
||||
{
|
||||
blend = dst ? GS_BLDST_ONE : GS_BLSRC_ONE;
|
||||
}
|
||||
else if (str == "srcalpha" ||
|
||||
str == "src_alpha")
|
||||
{
|
||||
blend = dst ? GS_BLDST_SRCALPHA : GS_BLSRC_SRCALPHA;
|
||||
}
|
||||
else if (str == "invsrcalpha" ||
|
||||
str == "inv_src_alpha")
|
||||
{
|
||||
blend = dst ? GS_BLDST_ONEMINUSSRCALPHA : GS_BLSRC_ONEMINUSSRCALPHA;
|
||||
}
|
||||
else if (str == "dstalpha" ||
|
||||
str == "dst_alpha")
|
||||
{
|
||||
blend = dst ? GS_BLDST_DSTALPHA : GS_BLSRC_DSTALPHA;
|
||||
}
|
||||
else if (str == "invdstalpha" ||
|
||||
str == "inv_dst_alpha")
|
||||
{
|
||||
blend = dst ? GS_BLDST_ONEMINUSDSTALPHA : GS_BLSRC_ONEMINUSDSTALPHA;
|
||||
}
|
||||
else if (str == "dstcolor" ||
|
||||
str == "dst_color")
|
||||
{
|
||||
blend = GS_BLSRC_DSTCOL;
|
||||
}
|
||||
else if (str == "srccolor" ||
|
||||
str == "src_color")
|
||||
{
|
||||
blend = GS_BLDST_SRCCOL;
|
||||
}
|
||||
else if (str == "invdstcolor" ||
|
||||
str == "inv_dst_color")
|
||||
{
|
||||
blend = GS_BLSRC_ONEMINUSDSTCOL;
|
||||
}
|
||||
else if (str == "invsrccolor" ||
|
||||
str == "inv_src_color")
|
||||
{
|
||||
blend = GS_BLDST_ONEMINUSSRCCOL;
|
||||
}
|
||||
|
||||
return blend;
|
||||
}
|
||||
|
||||
class CXmlFontShader
|
||||
{
|
||||
public:
|
||||
CXmlFontShader(CFFont* pFont)
|
||||
{
|
||||
m_pFont = pFont;
|
||||
m_nElement = ELEMENT_UNKNOWN;
|
||||
m_pEffect = NULL;
|
||||
m_pPass = NULL;
|
||||
m_FontTexSize.set(0, 0);
|
||||
|
||||
static const int defaultSlotWidthSize = 16;
|
||||
static const int defaultSlotHeightSize = 8;
|
||||
m_SlotSizes.set(defaultSlotWidthSize, defaultSlotHeightSize);
|
||||
|
||||
m_FontSmoothAmount = 0;
|
||||
m_FontSmoothMethod = FONT_SMOOTH_NONE;
|
||||
}
|
||||
|
||||
~CXmlFontShader()
|
||||
{
|
||||
}
|
||||
|
||||
void ScanXmlNodesRecursively(XmlNodeRef node)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FoundElement(node->getTag());
|
||||
|
||||
for (int i = 0, count = node->getNumAttributes(); i < count; ++i)
|
||||
{
|
||||
const char* key = "";
|
||||
const char* value = "";
|
||||
if (node->getAttributeByIndex(i, &key, &value))
|
||||
{
|
||||
FoundAttribute(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0, count = node->getChildCount(); i < count; ++i)
|
||||
{
|
||||
XmlNodeRef child = node->getChild(i);
|
||||
ScanXmlNodesRecursively(child);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// notify methods
|
||||
void FoundElement(const string& name)
|
||||
{
|
||||
//MessageBox(NULL, string("[" + name + "]").c_str(), "FoundElement", MB_OK);
|
||||
// process the previous element
|
||||
switch (m_nElement)
|
||||
{
|
||||
case ELEMENT_FONT:
|
||||
{
|
||||
if (!m_FontTexSize.x || !m_FontTexSize.y)
|
||||
{
|
||||
m_FontTexSize.set(512, 512);
|
||||
}
|
||||
|
||||
bool fontLoaded = m_pFont->Load(m_strFontPath.c_str(), m_FontTexSize.x, m_FontTexSize.y, m_SlotSizes.x, m_SlotSizes.y, TTFFLAG_CREATE(m_FontSmoothMethod, m_FontSmoothAmount), m_SizeRatio);
|
||||
#if defined(WIN32) || defined(WIN64)
|
||||
if (!fontLoaded)
|
||||
{
|
||||
TCHAR sysFontPath[MAX_PATH];
|
||||
if (SUCCEEDED(SHGetFolderPath(0, CSIDL_FONTS, 0, SHGFP_TYPE_DEFAULT, sysFontPath)))
|
||||
{
|
||||
const char* pFontPath = m_strFontPath.c_str();
|
||||
const char* pFontName = CryStringUtils::FindFileNameInPath(pFontPath);
|
||||
|
||||
string newFontPath(sysFontPath);
|
||||
newFontPath += "/";
|
||||
newFontPath += pFontName;
|
||||
m_pFont->Load(newFontPath, m_FontTexSize.x, m_FontTexSize.y, m_SlotSizes.x, m_SlotSizes.y, TTFFLAG_CREATE(m_FontSmoothMethod, m_FontSmoothAmount), m_SizeRatio);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Translate the m_nElement name to a define
|
||||
if (name == "font")
|
||||
{
|
||||
m_nElement = ELEMENT_FONT;
|
||||
}
|
||||
else if (name == "effect")
|
||||
{
|
||||
m_nElement = ELEMENT_EFFECT;
|
||||
}
|
||||
else if (name == "effectfile")
|
||||
{
|
||||
m_nElement = ELEMENT_EFFECTFILE;
|
||||
}
|
||||
else if (name == "pass")
|
||||
{
|
||||
m_pPass = NULL;
|
||||
m_nElement = ELEMENT_PASS;
|
||||
if (m_pEffect)
|
||||
{
|
||||
m_pPass = m_pEffect->AddPass();
|
||||
}
|
||||
}
|
||||
else if (name == "color")
|
||||
{
|
||||
m_nElement = ELEMENT_PASS_COLOR;
|
||||
}
|
||||
else if (name == "pos" ||
|
||||
name == "offset")
|
||||
{
|
||||
m_nElement = ELEMENT_PASS_POSOFFSET;
|
||||
}
|
||||
else if (name == "blend" ||
|
||||
name == "blending")
|
||||
{
|
||||
m_nElement = ELEMENT_PASS_BLEND;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nElement = ELEMENT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void FoundAttribute(const string& name, const string& value)
|
||||
{
|
||||
//MessageBox(NULL, string(name + "\n" + value).c_str(), "FoundAttribute", MB_OK);
|
||||
switch (m_nElement)
|
||||
{
|
||||
case ELEMENT_FONT:
|
||||
if (name == "path")
|
||||
{
|
||||
m_strFontPath = value;
|
||||
}
|
||||
else if (name == "w")
|
||||
{
|
||||
m_FontTexSize.x = (long)atof(value.c_str());
|
||||
}
|
||||
else if (name == "h")
|
||||
{
|
||||
m_FontTexSize.y = (long)atof(value.c_str());
|
||||
}
|
||||
else if (name == "widthslots")
|
||||
{
|
||||
m_SlotSizes.x = (int)atoi(value.c_str());
|
||||
}
|
||||
else if (name == "heightslots")
|
||||
{
|
||||
m_SlotSizes.y = (int)atoi(value.c_str());
|
||||
}
|
||||
else if (name == "sizeratio")
|
||||
{
|
||||
m_SizeRatio = static_cast<float>(atof(value.c_str()));
|
||||
}
|
||||
else if (name == "smooth")
|
||||
{
|
||||
if (value == "blur")
|
||||
{
|
||||
m_FontSmoothMethod = FONT_SMOOTH_BLUR;
|
||||
}
|
||||
else if (value == "supersample")
|
||||
{
|
||||
m_FontSmoothMethod = FONT_SMOOTH_SUPERSAMPLE;
|
||||
}
|
||||
else if (value == "none")
|
||||
{
|
||||
m_FontSmoothMethod = FONT_SMOOTH_NONE;
|
||||
}
|
||||
}
|
||||
else if (name == "smooth_amount")
|
||||
{
|
||||
m_FontSmoothAmount = (long)atof(value.c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_EFFECT:
|
||||
if (name == "name")
|
||||
{
|
||||
if (value == "default")
|
||||
{
|
||||
m_pEffect = m_pFont->GetDefaultEffect();
|
||||
m_pEffect->ClearPasses();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pEffect = m_pFont->AddEffect(value.c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_EFFECTFILE:
|
||||
if (name == "path")
|
||||
{
|
||||
m_strFontEffectPath = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_PASS_COLOR:
|
||||
if (!m_pPass)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (name == "r")
|
||||
{
|
||||
m_pPass->m_color.r = (uint8)((float)atof(value.c_str()) * 255.0f);
|
||||
}
|
||||
else if (name == "g")
|
||||
{
|
||||
m_pPass->m_color.g = (uint8)((float)atof(value.c_str()) * 255.0f);
|
||||
}
|
||||
else if (name == "b")
|
||||
{
|
||||
m_pPass->m_color.b = (uint8)((float)atof(value.c_str()) * 255.0f);
|
||||
}
|
||||
else if (name == "a")
|
||||
{
|
||||
m_pPass->m_color.a = (uint8)((float)atof(value.c_str()) * 255.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_PASS_POSOFFSET:
|
||||
if (!m_pPass)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (name == "x")
|
||||
{
|
||||
m_pPass->m_posOffset.x = (float)atoi(value.c_str());
|
||||
}
|
||||
else if (name == "y")
|
||||
{
|
||||
m_pPass->m_posOffset.y = (float)atoi(value.c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_PASS_BLEND:
|
||||
if (!m_pPass)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (name == "src")
|
||||
{
|
||||
m_pPass->m_blendSrc = GetBlendModeFromString(value, false);
|
||||
}
|
||||
else if (name == "dst")
|
||||
{
|
||||
m_pPass->m_blendDest = GetBlendModeFromString(value, true);
|
||||
}
|
||||
else if (name == "type")
|
||||
{
|
||||
if (value == "modulate")
|
||||
{
|
||||
m_pPass->m_blendSrc = GS_BLSRC_SRCALPHA;
|
||||
m_pPass->m_blendDest = GS_BLDST_ONEMINUSSRCALPHA;
|
||||
}
|
||||
else if (value == "additive")
|
||||
{
|
||||
m_pPass->m_blendSrc = GS_BLSRC_SRCALPHA;
|
||||
m_pPass->m_blendDest = GS_BLDST_ONE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case ELEMENT_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
CFFont* m_pFont;
|
||||
|
||||
unsigned long m_nElement;
|
||||
|
||||
CFFont::SEffect* m_pEffect;
|
||||
CFFont::SRenderingPass* m_pPass;
|
||||
|
||||
string m_strFontPath;
|
||||
string m_strFontEffectPath;
|
||||
vector2l m_FontTexSize;
|
||||
Vec2i m_SlotSizes;
|
||||
float m_SizeRatio = IFFontConstants::defaultSizeRatio;
|
||||
|
||||
int m_FontSmoothMethod;
|
||||
int m_FontSmoothAmount;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Main loading function
|
||||
bool CFFont::Load(const char* pXMLFile)
|
||||
{
|
||||
m_curPath = "";
|
||||
if (pXMLFile)
|
||||
{
|
||||
m_curPath = PathUtil::GetPath(pXMLFile);
|
||||
}
|
||||
|
||||
XmlNodeRef root = GetISystem()->LoadXmlFromFile(pXMLFile);
|
||||
if (!root)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CXmlFontShader xmlfs(this);
|
||||
xmlfs.ScanXmlNodesRecursively(root);
|
||||
|
||||
// if this was not a valid font XML file then return false
|
||||
if (!m_pFontTexture || !m_pFontBuffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// if there was a font effect file then parse that for effects
|
||||
if (!xmlfs.m_strFontEffectPath.empty())
|
||||
{
|
||||
XmlNodeRef fontEffectRoot = GetISystem()->LoadXmlFromFile(xmlfs.m_strFontEffectPath.c_str());
|
||||
if (!fontEffectRoot)
|
||||
{
|
||||
AZ_Warning("Font", false, "Error parsing font file %s, 'effectfile' pathname %s could not be found.",
|
||||
pXMLFile, xmlfs.m_strFontEffectPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_effects.size() > 1 || (m_effects.size() == 1 && (m_effects[0].m_name != "default" || m_effects[0].m_passes.size() > 1)))
|
||||
{
|
||||
AZ_Warning("Font", false, "Error parsing font file %s, 'effectfile' and 'effect' cannot both be used in the same font file.",
|
||||
pXMLFile);
|
||||
m_effects.clear();
|
||||
}
|
||||
|
||||
// parse the font effects file, adding to this font object
|
||||
CXmlFontShader xmlfsEffect(this);
|
||||
xmlfsEffect.ScanXmlNodesRecursively(fontEffectRoot);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
//
|
||||
// Purpose:
|
||||
// - Render a glyph outline into a bitmap using FreeType 2
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include "FontRenderer.h"
|
||||
|
||||
#include <freetype/ftoutln.h>
|
||||
#include <freetype/ftglyph.h>
|
||||
#include <freetype/ftimage.h>
|
||||
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
|
||||
// Sizes are defined in in 26.6 fixed float format (TT_F26Dot6), where
|
||||
// 1 unit is 1/64 of a pixel.
|
||||
static const int fractionalPixelUnits = 64;
|
||||
|
||||
namespace
|
||||
{
|
||||
FT_Int32 GetLoadFlags(CFFont::HintBehavior hintBehavior)
|
||||
{
|
||||
switch (hintBehavior)
|
||||
{
|
||||
case CFFont::HintBehavior::NoHinting:
|
||||
{
|
||||
return FT_LOAD_NO_HINTING;
|
||||
break;
|
||||
}
|
||||
case CFFont::HintBehavior::AutoHint:
|
||||
{
|
||||
return FT_LOAD_FORCE_AUTOHINT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FT_LOAD_DEFAULT;
|
||||
}
|
||||
|
||||
FT_Int32 GetLoadTarget(CFFont::HintStyle hintStyle)
|
||||
{
|
||||
if (hintStyle == CFFont::HintStyle::Light)
|
||||
{
|
||||
return FT_LOAD_TARGET_LIGHT;
|
||||
}
|
||||
|
||||
return FT_LOAD_TARGET_NORMAL;
|
||||
}
|
||||
|
||||
FT_Render_Mode GetRenderMode(CFFont::HintStyle hintStyle)
|
||||
{
|
||||
// We use the hint style to drive the render mode also. These should
|
||||
// usually be correlated with each other for best results, even though
|
||||
// they could technically be different.
|
||||
if (hintStyle == CFFont::HintStyle::Light)
|
||||
{
|
||||
return FT_RENDER_MODE_LIGHT;
|
||||
}
|
||||
|
||||
return FT_RENDER_MODE_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CFontRenderer::CFontRenderer()
|
||||
: m_pLibrary(0)
|
||||
, m_pFace(0)
|
||||
, m_pGlyph(0)
|
||||
, m_fSizeRatio(IFFontConstants::defaultSizeRatio)
|
||||
, m_pEncoding(FONT_ENCODING_UNICODE)
|
||||
, m_iGlyphBitmapWidth(0)
|
||||
, m_iGlyphBitmapHeight(0)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CFontRenderer::~CFontRenderer()
|
||||
{
|
||||
FT_Done_Face(m_pFace);
|
||||
;
|
||||
FT_Done_FreeType(m_pLibrary);
|
||||
m_pFace = NULL;
|
||||
m_pLibrary = NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontRenderer::LoadFromFile(const string& szFileName)
|
||||
{
|
||||
int iError = FT_Init_FreeType(&m_pLibrary);
|
||||
|
||||
if (iError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_pFace)
|
||||
{
|
||||
FT_Done_Face(m_pFace);
|
||||
m_pFace = 0;
|
||||
}
|
||||
|
||||
iError = FT_New_Face(m_pLibrary, szFileName.c_str(), 0, &m_pFace);
|
||||
|
||||
if (iError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SetEncoding(FONT_ENCODING_UNICODE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontRenderer::LoadFromMemory(unsigned char* pBuffer, int iBufferSize)
|
||||
{
|
||||
int iError = FT_Init_FreeType(&m_pLibrary);
|
||||
|
||||
if (iError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_pFace)
|
||||
{
|
||||
FT_Done_Face(m_pFace);
|
||||
m_pFace = 0;
|
||||
}
|
||||
iError = FT_New_Memory_Face(m_pLibrary, pBuffer, iBufferSize, 0, &m_pFace);
|
||||
|
||||
if (iError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SetEncoding(FONT_ENCODING_UNICODE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontRenderer::Release()
|
||||
{
|
||||
FT_Done_Face(m_pFace);
|
||||
;
|
||||
FT_Done_FreeType(m_pLibrary);
|
||||
m_pFace = NULL;
|
||||
m_pLibrary = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontRenderer::SetGlyphBitmapSize(int iWidth, int iHeight, float sizeRatio)
|
||||
{
|
||||
m_iGlyphBitmapWidth = iWidth;
|
||||
m_iGlyphBitmapHeight = iHeight;
|
||||
|
||||
// Assign the given scale for texture slots as long as its positive
|
||||
m_fSizeRatio = sizeRatio > 0.0f ? sizeRatio : m_fSizeRatio;
|
||||
|
||||
FT_Set_Pixel_Sizes(m_pFace, (int)(m_iGlyphBitmapWidth * m_fSizeRatio), (int)(m_iGlyphBitmapHeight * m_fSizeRatio));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontRenderer::GetGlyphBitmapSize(int* pWidth, int* pHeight)
|
||||
{
|
||||
if (pWidth)
|
||||
{
|
||||
*pWidth = m_iGlyphBitmapWidth;
|
||||
}
|
||||
|
||||
if (pHeight)
|
||||
{
|
||||
*pHeight = m_iGlyphBitmapHeight;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontRenderer::SetEncoding(FT_Encoding pEncoding)
|
||||
{
|
||||
if (FT_Select_Charmap(m_pFace, pEncoding))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontRenderer::GetGlyph(CGlyphBitmap* pGlyphBitmap, int* iHoriAdvance, uint8* iGlyphWidth, uint8* iGlyphHeight, AZ::s32& iCharOffsetX, AZ::s32& iCharOffsetY, int iX, int iY, int iCharCode, const CFFont::FontHintParams& fontHintParams)
|
||||
{
|
||||
FT_Int32 loadFlags = GetLoadFlags(fontHintParams.hintBehavior);
|
||||
loadFlags |= GetLoadTarget(fontHintParams.hintStyle);
|
||||
|
||||
int iError = FT_Load_Char(m_pFace, iCharCode, loadFlags);
|
||||
|
||||
if (iError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
FT_Render_Mode renderMode = GetRenderMode(fontHintParams.hintStyle);
|
||||
|
||||
m_pGlyph = m_pFace->glyph;
|
||||
|
||||
iError = FT_Render_Glyph(m_pGlyph, renderMode);
|
||||
|
||||
if (iError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iHoriAdvance)
|
||||
{
|
||||
*iHoriAdvance = m_pGlyph->metrics.horiAdvance / fractionalPixelUnits;
|
||||
}
|
||||
|
||||
if (iGlyphWidth)
|
||||
{
|
||||
*iGlyphWidth = m_pGlyph->bitmap.width;
|
||||
}
|
||||
|
||||
if (iGlyphHeight)
|
||||
{
|
||||
*iGlyphHeight = m_pGlyph->bitmap.rows;
|
||||
}
|
||||
|
||||
unsigned char* pBuffer = pGlyphBitmap->GetBuffer();
|
||||
AZ_Assert(pBuffer, "CGlyphBitmap: bad buffer");
|
||||
|
||||
uint32 dwGlyphWidth = pGlyphBitmap->GetWidth();
|
||||
iCharOffsetX = m_pGlyph->bitmap_left;
|
||||
iCharOffsetY = (static_cast<AZ::s32>(round(m_iGlyphBitmapHeight * m_fSizeRatio)) - m_pGlyph->bitmap_top);
|
||||
|
||||
const int textureSlotBufferWidth = pGlyphBitmap->GetWidth();
|
||||
const int textureSlotBufferHeight = pGlyphBitmap->GetHeight();
|
||||
|
||||
// might happen if font characters are too big or cache dimenstions in font.xml is too small "<font path="VeraMono.ttf" w="320" h="368"/>"
|
||||
const bool charWidthFits = iX + m_pGlyph->bitmap.width <= textureSlotBufferWidth;
|
||||
const bool charHeightFits = iY + m_pGlyph->bitmap.rows <= textureSlotBufferHeight;
|
||||
const bool charFitsInSlot = charWidthFits && charHeightFits;
|
||||
AZ_Error("Font", charFitsInSlot, "Character code %d doesn't fit in font texture; check 'sizeRatio' attribute in font XML or adjust this character's sizing in the font.", iCharCode);
|
||||
|
||||
// Since we might be re-rendering/overwriting a glyph that already exists
|
||||
// in the font texture, clear the contents of this particular slot so no
|
||||
// artifacts of the previous glyph remain.
|
||||
pGlyphBitmap->Clear();
|
||||
|
||||
// Restrict iteration to smallest of either the texture slot or glyph
|
||||
// bitmap buffer ranges
|
||||
const int bufferMaxIterWidth = AZStd::GetMin<int>(textureSlotBufferWidth, m_pGlyph->bitmap.width);
|
||||
const int bufferMaxIterHeight = AZStd::GetMin<int>(textureSlotBufferHeight, m_pGlyph->bitmap.rows);
|
||||
|
||||
for (int i = 0; i < bufferMaxIterHeight; i++)
|
||||
{
|
||||
int iNewY = i + iY;
|
||||
|
||||
for (int j = 0; j < bufferMaxIterWidth; j++)
|
||||
{
|
||||
unsigned char cColor = m_pGlyph->bitmap.buffer[(i * m_pGlyph->bitmap.width) + j];
|
||||
int iOffset = iNewY * dwGlyphWidth + iX + j;
|
||||
|
||||
if (iOffset >= (int)dwGlyphWidth * m_iGlyphBitmapHeight)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pBuffer[iOffset] = cColor;
|
||||
// pBuffer[iOffset] = cColor/2+32; // debug - visualize character in a block
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CFontRenderer::GetGlyphScaled([[maybe_unused]] CGlyphBitmap* pGlyphBitmap, [[maybe_unused]] int* iGlyphWidth, [[maybe_unused]] int* iGlyphHeight, [[maybe_unused]] int iX, [[maybe_unused]] int iY, [[maybe_unused]] float fScaleX, [[maybe_unused]] float fScaleY, [[maybe_unused]] int iCharCode)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Vec2 CFontRenderer::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph)
|
||||
{
|
||||
FT_Vector kerningOffsets;
|
||||
kerningOffsets.x = kerningOffsets.y = 0;
|
||||
|
||||
if (FT_HAS_KERNING(m_pFace))
|
||||
{
|
||||
const FT_UInt leftGlyphIndex = FT_Get_Char_Index(m_pFace, leftGlyph);
|
||||
const FT_UInt rightGlyphIndex = FT_Get_Char_Index(m_pFace, rightGlyph);
|
||||
|
||||
[[maybe_unused]] FT_Error ftError = FT_Get_Kerning(m_pFace, leftGlyphIndex, rightGlyphIndex, FT_KERNING_DEFAULT, &kerningOffsets);
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
if (0 != ftError)
|
||||
{
|
||||
string warnMsg;
|
||||
warnMsg.Format("FT_Get_Kerning returned %d", ftError);
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, warnMsg.c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return Vec2(azlossy_cast<float>(kerningOffsets.x / fractionalPixelUnits), azlossy_cast<float>(kerningOffsets.y / fractionalPixelUnits));
|
||||
}
|
||||
|
||||
float CFontRenderer::GetAscenderToHeightRatio()
|
||||
{
|
||||
return (static_cast<float>(m_pFace->ascender) / static_cast<float>(m_pFace->height));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
int CFontRenderer::FT_GetIndex(int iCharCode)
|
||||
{
|
||||
if (iCharCode < 256)
|
||||
{
|
||||
int iIndex = 0;
|
||||
int iUnicode;
|
||||
|
||||
// try unicode
|
||||
for (int i = 0; i < m_pFace->num_charmaps; i++)
|
||||
{
|
||||
if ((m_pFace->charmaps[i]->platform_id == 3) && (m_pFace->charmaps[i]->encoding_id == 1))
|
||||
{
|
||||
iUnicode = i;
|
||||
|
||||
FT_Set_Charmap(m_pFace, m_pFace->charmaps[i]);
|
||||
|
||||
iIndex = FT_Get_Char_Index(m_pFace, iCharCode);
|
||||
|
||||
// not unicode, try ascii
|
||||
if (iIndex == 0)
|
||||
{
|
||||
for (int i = 0; i < m_pFace->num_charmaps; i++)
|
||||
{
|
||||
if ((m_pFace->charmaps[i]->platform_id == 0) && (m_pFace->charmaps[i]->encoding_id == 0))
|
||||
{
|
||||
FT_Set_Charmap(m_pFace, m_pFace->charmaps[i]);
|
||||
|
||||
iIndex = FT_Get_Char_Index(m_pFace, iCharCode);
|
||||
|
||||
// not ascii either, reuse unicode default "missing char"
|
||||
if (iIndex == 0)
|
||||
{
|
||||
FT_Set_Charmap(m_pFace, m_pFace->charmaps[iUnicode]);
|
||||
|
||||
return FT_Get_Char_Index(m_pFace, iCharCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < m_pFace->num_charmaps; i++)
|
||||
{
|
||||
if ((m_pFace->charmaps[i]->platform_id == 3) && (m_pFace->charmaps[i]->encoding_id == 1))
|
||||
{
|
||||
FT_Set_Charmap(m_pFace, m_pFace->charmaps[i]);
|
||||
|
||||
return FT_Get_Char_Index(m_pFace, iCharCode);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // #if !defined(USE_NULLFONT_ALWAYS)
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Render a glyph outline into a bitmap using FreeType 2
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#ifndef CRYINCLUDE_CRYFONT_FONTRENDERER_H
|
||||
#define CRYINCLUDE_CRYFONT_FONTRENDERER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include "GlyphBitmap.h"
|
||||
#include "FFont.h"
|
||||
#include <ft2build.h>
|
||||
#pragma push_macro("generic")
|
||||
#define generic GenericFromFreeTypeLibrary
|
||||
#include <freetype/freetype.h>
|
||||
#undef generic
|
||||
#pragma pop_macro("generic")
|
||||
|
||||
|
||||
// Corresponds to the Unicode character set. This value covers all versions of the Unicode repertoire,
|
||||
// including ASCII and Latin-1. Most fonts include a Unicode charmap, but not all of them.
|
||||
#define FONT_ENCODING_UNICODE (FT_ENCODING_UNICODE)
|
||||
|
||||
// Corresponds to the Microsoft Symbol encoding, used to encode mathematical symbols in the 32..255 character code range.
|
||||
// For more information, see `http://www.ceviz.net/symbol.htm'.
|
||||
#define FONT_ENCODING_SYMBOL (FT_ENCODING_MS_SYMBOL)
|
||||
|
||||
// Corresponds to Microsoft's Japanese SJIS encoding.
|
||||
// More info at `http://langsupport.japanreference.com/encoding.shtml'. See note on multi-byte encodings below.
|
||||
#define FONT_ENCODING_SJIS (FT_ENCODING_MS_SJIS)
|
||||
|
||||
// Corresponds to the encoding system for Simplified Chinese, as used in China. Only found in some TrueType fonts.
|
||||
#define FONT_ENCODING_GB2312 (FT_ENCODING_MS_GB2312)
|
||||
|
||||
// Corresponds to the encoding system for Traditional Chinese, as used in Taiwan and Hong Kong. Only found in some TrueType fonts.
|
||||
#define FONT_ENCODING_BIG5 (FT_ENCODING_MS_BIG5)
|
||||
|
||||
// Corresponds to the Korean encoding system known as Wansung.
|
||||
// This is a Microsoft encoding that is only found in some TrueType fonts.
|
||||
// For more information, see `http://www.microsoft.com/typography/unicode/949.txt'.
|
||||
#define FONT_ENCODING_WANSUNG (FT_ENCODING_MS_WANSUNG)
|
||||
|
||||
// The Korean standard character set (KS C-5601-1992), which corresponds to Windows code page 1361.
|
||||
// This character set includes all possible Hangeul character combinations. Only found on some rare TrueType fonts.
|
||||
#define FONT_ENCODING_JOHAB (FT_ENCODING_MS_JOHAB)
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
class CFontRenderer
|
||||
{
|
||||
public:
|
||||
|
||||
CFontRenderer();
|
||||
~CFontRenderer();
|
||||
|
||||
int LoadFromFile(const string& szFileName);
|
||||
int LoadFromMemory(unsigned char* pBuffer, int iBufferSize);
|
||||
int Release();
|
||||
|
||||
int SetGlyphBitmapSize(int iWidth, int iHeight, float sizeRatio);
|
||||
int GetGlyphBitmapSize(int* pWidth, int* pHeight);
|
||||
|
||||
int SetSizeRatio(float fSizeRatio) { m_fSizeRatio = fSizeRatio; return 1; };
|
||||
float GetSizeRatio() { return m_fSizeRatio; };
|
||||
|
||||
int SetEncoding(FT_Encoding pEncoding);
|
||||
FT_Encoding GetEncoding() { return m_pEncoding; };
|
||||
|
||||
//! Populates the given pGlyphBitmap's buffer from the FreeType bitmap buffer
|
||||
//! \param iCharCode Used as a character index to retrieve the FreeType glyph and it's associated bitmap buffer for the character
|
||||
//! \param pGlyphBitmap The FreeType glyph buffer is essentially copied into this CGlyphBitmap buffer
|
||||
int GetGlyph(CGlyphBitmap* pGlyphBitmap, int* iHoriAdvance, uint8* iGlyphWidth, uint8* iGlyphHeight, AZ::s32& iCharOffsetX, AZ::s32& iCharOffsetY, int iX, int iY, int iCharCode, const CFFont::FontHintParams& glyphFlags = CFFont::FontHintParams());
|
||||
int GetGlyphScaled(CGlyphBitmap* pGlyphBitmap, int* iGlyphWidth, int* iGlyphHeight, int iX, int iY, float fScaleX, float fScaleY, int iCharCode);
|
||||
|
||||
void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const {}
|
||||
|
||||
bool GetMonospaced() const { return FT_IS_FIXED_WIDTH(m_pFace) != 0; }
|
||||
|
||||
Vec2 GetKerning(uint32_t leftGlyph, uint32_t rightGlyph);
|
||||
|
||||
float GetAscenderToHeightRatio();
|
||||
|
||||
private:
|
||||
|
||||
FT_Library m_pLibrary;
|
||||
FT_Face m_pFace;
|
||||
FT_GlyphSlot m_pGlyph;
|
||||
float m_fSizeRatio;
|
||||
|
||||
FT_Encoding m_pEncoding;
|
||||
|
||||
int m_iGlyphBitmapWidth;
|
||||
int m_iGlyphBitmapHeight;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYFONT_FONTRENDERER_H
|
||||
|
||||
#endif // #if !defined(USE_NULLFONT_ALWAYS)
|
||||
@@ -1,633 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Purpose:
|
||||
// - Create and update a texture with the most recently used glyphs
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include "FontTexture.h"
|
||||
#include "UnicodeIterator.h"
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef GetCharWidth
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CFontTexture::CFontTexture()
|
||||
: m_wSlotUsage(1)
|
||||
, m_iWidth(0)
|
||||
, m_iHeight(0)
|
||||
, m_fInvWidth(0.0f)
|
||||
, m_fInvHeight(0.0f)
|
||||
, m_iCellWidth(0)
|
||||
, m_iCellHeight(0)
|
||||
, m_fTextureCellWidth(0)
|
||||
, m_fTextureCellHeight(0)
|
||||
, m_iWidthCellCount(0)
|
||||
, m_iHeightCellCount(0)
|
||||
, m_nTextureSlotCount(0)
|
||||
, m_pBuffer(0)
|
||||
, m_iSmoothMethod(FONT_SMOOTH_NONE)
|
||||
, m_iSmoothAmount(FONT_SMOOTH_AMOUNT_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CFontTexture::~CFontTexture()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::CreateFromFile(const string& szFileName, int iWidth, int iHeight, int iSmoothMethod, int iSmoothAmount, int iWidthCellCount, int iHeightCellCount)
|
||||
{
|
||||
if (!m_pGlyphCache.LoadFontFromFile(szFileName))
|
||||
{
|
||||
Release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!Create(iWidth, iHeight, iSmoothMethod, iSmoothAmount, iWidthCellCount, iHeightCellCount))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::CreateFromMemory(unsigned char* pFileData, int iDataSize, int iWidth, int iHeight, int iSmoothMethod, int iSmoothAmount, int iWidthCellCount, int iHeightCellCount, float sizeRatio)
|
||||
{
|
||||
if (!m_pGlyphCache.LoadFontFromMemory(pFileData, iDataSize))
|
||||
{
|
||||
Release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!Create(iWidth, iHeight, iSmoothMethod, iSmoothAmount, iWidthCellCount, iHeightCellCount, sizeRatio))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::Create(int iWidth, int iHeight, int iSmoothMethod, int iSmoothAmount, int iWidthCellCount, int iHeightCellCount, float sizeRatio)
|
||||
{
|
||||
m_pBuffer = new FONT_TEXTURE_TYPE[iWidth * iHeight];
|
||||
if (!m_pBuffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(m_pBuffer, 0, iWidth * iHeight * sizeof(FONT_TEXTURE_TYPE));
|
||||
|
||||
if (!(iWidthCellCount * iHeightCellCount))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_iWidth = iWidth;
|
||||
m_iHeight = iHeight;
|
||||
m_fInvWidth = 1.0f / (float)iWidth;
|
||||
m_fInvHeight = 1.0f / (float)iHeight;
|
||||
|
||||
m_iWidthCellCount = iWidthCellCount;
|
||||
m_iHeightCellCount = iHeightCellCount;
|
||||
m_nTextureSlotCount = m_iWidthCellCount * m_iHeightCellCount;
|
||||
|
||||
m_iSmoothMethod = iSmoothMethod;
|
||||
m_iSmoothAmount = iSmoothAmount;
|
||||
|
||||
m_iCellWidth = m_iWidth / m_iWidthCellCount;
|
||||
m_iCellHeight = m_iHeight / m_iHeightCellCount;
|
||||
|
||||
m_fTextureCellWidth = m_iCellWidth * m_fInvWidth;
|
||||
m_fTextureCellHeight = m_iCellHeight * m_fInvHeight;
|
||||
|
||||
if (!m_pGlyphCache.Create(FONT_GLYPH_CACHE_SIZE, m_iCellWidth, m_iCellHeight, iSmoothMethod, iSmoothAmount, sizeRatio))
|
||||
{
|
||||
Release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!CreateSlotList(m_nTextureSlotCount))
|
||||
{
|
||||
Release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::Release()
|
||||
{
|
||||
delete[] m_pBuffer;
|
||||
m_pBuffer = 0;
|
||||
|
||||
ReleaseSlotList();
|
||||
|
||||
m_pSlotTable.clear();
|
||||
|
||||
m_pGlyphCache.Release();
|
||||
|
||||
m_iWidthCellCount = 0;
|
||||
m_iHeightCellCount = 0;
|
||||
m_nTextureSlotCount = 0;
|
||||
|
||||
m_iWidth = 0;
|
||||
m_iHeight = 0;
|
||||
m_fInvWidth = 0.0f;
|
||||
m_fInvHeight = 0.0f;
|
||||
|
||||
m_iCellWidth = 0;
|
||||
m_iCellHeight = 0;
|
||||
|
||||
m_iSmoothMethod = 0;
|
||||
m_iSmoothAmount = 0;
|
||||
|
||||
m_fTextureCellWidth = 0.0f;
|
||||
m_fTextureCellHeight = 0.0f;
|
||||
|
||||
m_wSlotUsage = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
uint32 CFontTexture::GetSlotChar(int iSlot) const
|
||||
{
|
||||
return m_pSlotList[iSlot]->cCurrentChar;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CTextureSlot* CFontTexture::GetCharSlot(uint32 cChar, const Vec2i& glyphSize)
|
||||
{
|
||||
CryFont::FontTexture::CTextureSlotKey slotKey = GetTextureSlotKey(cChar, glyphSize);
|
||||
CTextureSlotTableItor pItor = m_pSlotTable.find(slotKey);
|
||||
|
||||
if (pItor != m_pSlotTable.end())
|
||||
{
|
||||
return pItor->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CTextureSlot* CFontTexture::GetLRUSlot()
|
||||
{
|
||||
uint16 wMaxSlotAge = 0;
|
||||
CTextureSlot* pLRUSlot = 0;
|
||||
CTextureSlot* pSlot;
|
||||
|
||||
CTextureSlotListItor pItor = m_pSlotList.begin();
|
||||
|
||||
while (pItor != m_pSlotList.end())
|
||||
{
|
||||
pSlot = *pItor;
|
||||
|
||||
if (pSlot->wSlotUsage == 0)
|
||||
{
|
||||
return pSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16 slotAge = m_wSlotUsage - pSlot->wSlotUsage;
|
||||
if (slotAge > wMaxSlotAge)
|
||||
{
|
||||
pLRUSlot = pSlot;
|
||||
wMaxSlotAge = slotAge;
|
||||
}
|
||||
}
|
||||
|
||||
++pItor;
|
||||
}
|
||||
|
||||
return pLRUSlot;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CTextureSlot* CFontTexture::GetMRUSlot()
|
||||
{
|
||||
uint16 wMinSlotAge = 0xFFFF;
|
||||
CTextureSlot* pMRUSlot = 0;
|
||||
CTextureSlot* pSlot;
|
||||
|
||||
CTextureSlotListItor pItor = m_pSlotList.begin();
|
||||
|
||||
while (pItor != m_pSlotList.end())
|
||||
{
|
||||
pSlot = *pItor;
|
||||
|
||||
if (pSlot->wSlotUsage != 0)
|
||||
{
|
||||
uint16 slotAge = m_wSlotUsage - pSlot->wSlotUsage;
|
||||
if (slotAge > wMinSlotAge)
|
||||
{
|
||||
pMRUSlot = pSlot;
|
||||
wMinSlotAge = slotAge;
|
||||
}
|
||||
}
|
||||
|
||||
++pItor;
|
||||
}
|
||||
|
||||
return pMRUSlot;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::PreCacheString(const char* szString, int* pUpdated, float sizeRatio, const Vec2i& glyphSize, const CFFont::FontHintParams& fontHintParams)
|
||||
{
|
||||
Vec2i clampedGlyphSize = ClampGlyphSize(glyphSize, m_iCellWidth, m_iCellHeight);
|
||||
|
||||
uint16 wSlotUsage = m_wSlotUsage++;
|
||||
int iUpdated = 0;
|
||||
|
||||
uint32 cChar;
|
||||
for (Unicode::CIterator<const char*, false> it(szString); *it; ++it)
|
||||
{
|
||||
cChar = *it;
|
||||
CTextureSlot* pSlot = GetCharSlot(cChar, clampedGlyphSize);
|
||||
|
||||
if (!pSlot)
|
||||
{
|
||||
pSlot = GetLRUSlot();
|
||||
|
||||
if (!pSlot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!UpdateSlot(pSlot->iTextureSlot, wSlotUsage, cChar, sizeRatio, clampedGlyphSize, fontHintParams))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
++iUpdated;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSlot->wSlotUsage = wSlotUsage;
|
||||
}
|
||||
}
|
||||
|
||||
if (pUpdated)
|
||||
{
|
||||
*pUpdated = iUpdated;
|
||||
}
|
||||
|
||||
if (iUpdated)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void CFontTexture::GetTextureCoord(CTextureSlot* pSlot, float texCoords[4],
|
||||
int& iCharSizeX, int& iCharSizeY, int& iCharOffsetX, int& iCharOffsetY,
|
||||
const Vec2i& glyphSize) const
|
||||
{
|
||||
if (!pSlot)
|
||||
{
|
||||
return; // expected behavior
|
||||
}
|
||||
|
||||
// Re-rendered glyphs are stored at smaller sizes than glyphs rendered at
|
||||
// the (maximum) font texture slot resolution. We scale the returned width
|
||||
// and height of the (actual) rendered glyph sizes so its transparent to
|
||||
// callers that the glyph is actually smaller (from being re-rendered).
|
||||
const float requestSizeWidthScale = AZ::GetMin<float>(1.0f, GetRequestSizeWidthScale(glyphSize));
|
||||
const float requestSizeHeightScale = AZ::GetMin<float>(1.0f, GetRequestSizeHeightScale(glyphSize));
|
||||
const float invRequestSizeWidthScale = 1.0f / requestSizeWidthScale;
|
||||
const float invRequestSizeHeightScale = 1.0f / requestSizeHeightScale;
|
||||
|
||||
// The inverse scale grows as the glyph size decreases. Once the glyph size
|
||||
// reaches the font texture's max slot dimensions, we cap width/height scale
|
||||
// since the text draw context will apply normal (as opposed to re-rendered)
|
||||
// scaling.
|
||||
int iChWidth = static_cast<int>(pSlot->iCharWidth * invRequestSizeWidthScale);
|
||||
int iChHeight = static_cast<int>(pSlot->iCharHeight * invRequestSizeHeightScale);
|
||||
|
||||
float slotCoord0 = pSlot->vTexCoord[0];
|
||||
float slotCoord1 = pSlot->vTexCoord[1];
|
||||
texCoords[0] = slotCoord0 - m_fInvWidth; // extra pixel for nicer bilinear filter
|
||||
texCoords[1] = slotCoord1 - m_fInvHeight; // extra pixel for nicer bilinear filter
|
||||
|
||||
// UV coordinates also must be scaled relative to the re-rendered glyph size
|
||||
// as well. Width scale must be capped at 1.0f since glyph can't grow
|
||||
// beyond the slot's resolution.
|
||||
texCoords[2] = slotCoord0 + (((float)iChWidth * m_fInvWidth) * requestSizeWidthScale);
|
||||
texCoords[3] = slotCoord1 + (((float)iChHeight * m_fInvHeight) * requestSizeHeightScale);
|
||||
|
||||
iCharSizeX = iChWidth + 1; // extra pixel for nicer bilinear filter
|
||||
iCharSizeY = iChHeight + 1; // extra pixel for nicer bilinear filter
|
||||
|
||||
// Offsets are scaled accordingly when the rendered glyph size is smaller
|
||||
// than the glyph/slot dimensions, but otherwise we expect the text draw
|
||||
// context to apply scaling beyond that.
|
||||
iCharOffsetX = static_cast<int>(pSlot->iCharOffsetX * invRequestSizeWidthScale);
|
||||
iCharOffsetY = static_cast<int>(pSlot->iCharOffsetY * invRequestSizeHeightScale);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::GetCharacterWidth(uint32 cChar) const
|
||||
{
|
||||
CTextureSlotTableItorConst pItor = m_pSlotTable.find(GetTextureSlotKey(cChar));
|
||||
|
||||
if (pItor == m_pSlotTable.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const CTextureSlot& rSlot = *pItor->second;
|
||||
|
||||
// For proportional fonts, add one pixel of spacing for aesthetic reasons
|
||||
int proportionalOffset = GetMonospaced() ? 0 : 1;
|
||||
|
||||
return rSlot.iCharWidth + proportionalOffset;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::GetHorizontalAdvance(uint32 cChar, const Vec2i& glyphSize) const
|
||||
{
|
||||
CTextureSlotTableItorConst pItor = m_pSlotTable.find(GetTextureSlotKey(cChar, glyphSize));
|
||||
|
||||
if (pItor == m_pSlotTable.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const CTextureSlot& rSlot = *pItor->second;
|
||||
|
||||
// Re-rendered glyphs are stored at smaller sizes than glyphs rendered at
|
||||
// the (maximum) font texture slot resolution. We scale the returned width
|
||||
// and height of the (actual) rendered glyph sizes so its transparent to
|
||||
// callers that the glyph is actually smaller (from being re-rendered).
|
||||
const float requestSizeWidthScale = GetRequestSizeWidthScale(glyphSize);
|
||||
const float invRequestSizeWidthScale = 1.0f / requestSizeWidthScale;
|
||||
|
||||
// Only multiply by 1.0f when glyphsize is greater than cell width because we assume that callers
|
||||
// will use the font draw text context to scale the value appropriately.
|
||||
return static_cast<int>(rSlot.iHoriAdvance * AZ::GetMax<float>(1.0f, invRequestSizeWidthScale));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
int CFontTexture::GetCharHeightByChar(wchar_t cChar)
|
||||
{
|
||||
CTextureSlotTableItor pItor = m_pSlotTable.find(cChar);
|
||||
|
||||
if (pItor != m_pSlotTable.end())
|
||||
{
|
||||
return pItor->second->iCharHeight;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::WriteToFile([[maybe_unused]] const string& szFileName)
|
||||
{
|
||||
#ifdef WIN32
|
||||
AZ::IO::FileIOStream outputFile(szFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary);
|
||||
|
||||
if (!outputFile.IsOpen())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
BITMAPFILEHEADER pHeader;
|
||||
BITMAPINFOHEADER pInfoHeader;
|
||||
|
||||
memset(&pHeader, 0, sizeof(BITMAPFILEHEADER));
|
||||
memset(&pInfoHeader, 0, sizeof(BITMAPINFOHEADER));
|
||||
|
||||
pHeader.bfType = 0x4D42;
|
||||
pHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + m_iWidth * m_iHeight * 3;
|
||||
pHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
||||
|
||||
pInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
pInfoHeader.biWidth = m_iWidth;
|
||||
pInfoHeader.biHeight = m_iHeight;
|
||||
pInfoHeader.biPlanes = 1;
|
||||
pInfoHeader.biBitCount = 24;
|
||||
pInfoHeader.biCompression = 0;
|
||||
pInfoHeader.biSizeImage = m_iWidth * m_iHeight * 3;
|
||||
|
||||
outputFile.Write(sizeof(BITMAPFILEHEADER), &pHeader);
|
||||
outputFile.Write(sizeof(BITMAPINFOHEADER), &pInfoHeader);
|
||||
|
||||
unsigned char cRGB[3];
|
||||
|
||||
for (int i = m_iHeight - 1; i >= 0; i--)
|
||||
{
|
||||
for (int j = 0; j < m_iWidth; j++)
|
||||
{
|
||||
cRGB[0] = m_pBuffer[(i * m_iWidth) + j];
|
||||
cRGB[1] = *cRGB;
|
||||
|
||||
cRGB[2] = *cRGB;
|
||||
|
||||
outputFile.Write(3, cRGB);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
Vec2 CFontTexture::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph)
|
||||
{
|
||||
return m_pGlyphCache.GetKerning(leftGlyph, rightGlyph);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
float CFontTexture::GetAscenderToHeightRatio()
|
||||
{
|
||||
return m_pGlyphCache.GetAscenderToHeightRatio();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::CreateSlotList(int iListSize)
|
||||
{
|
||||
int y, x;
|
||||
|
||||
for (int i = 0; i < iListSize; i++)
|
||||
{
|
||||
CTextureSlot* pTextureSlot = new CTextureSlot;
|
||||
|
||||
if (!pTextureSlot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pTextureSlot->iTextureSlot = i;
|
||||
pTextureSlot->Reset();
|
||||
|
||||
y = i / m_iWidthCellCount;
|
||||
x = i % m_iWidthCellCount;
|
||||
|
||||
pTextureSlot->vTexCoord[0] = (float)(x * m_fTextureCellWidth) + (0.5f / (float)m_iWidth);
|
||||
pTextureSlot->vTexCoord[1] = (float)(y * m_fTextureCellHeight) + (0.5f / (float)m_iHeight);
|
||||
|
||||
m_pSlotList.push_back(pTextureSlot);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::ReleaseSlotList()
|
||||
{
|
||||
CTextureSlotListItor pItor = m_pSlotList.begin();
|
||||
|
||||
while (pItor != m_pSlotList.end())
|
||||
{
|
||||
delete (*pItor);
|
||||
|
||||
pItor = m_pSlotList.erase(pItor);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CFontTexture::UpdateSlot(int iSlot, uint16 wSlotUsage, uint32 cChar, float sizeRatio, const Vec2i& glyphSize, const CFFont::FontHintParams& fontHintParams)
|
||||
{
|
||||
CTextureSlot* pSlot = m_pSlotList[iSlot];
|
||||
|
||||
if (!pSlot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
CTextureSlotTableItor pItor = m_pSlotTable.find(GetTextureSlotKey(pSlot->cCurrentChar, pSlot->glyphSize));
|
||||
|
||||
if (pItor != m_pSlotTable.end())
|
||||
{
|
||||
m_pSlotTable.erase(pItor);
|
||||
}
|
||||
m_pSlotTable.insert(AZStd::pair<CryFont::FontTexture::CTextureSlotKey, CTextureSlot*>(GetTextureSlotKey(cChar, glyphSize), pSlot));
|
||||
pSlot->glyphSize = glyphSize;
|
||||
pSlot->wSlotUsage = wSlotUsage;
|
||||
pSlot->cCurrentChar = cChar;
|
||||
|
||||
int iWidth = 0;
|
||||
int iHeight = 0;
|
||||
|
||||
// blit the char glyph into the texture
|
||||
int x = pSlot->iTextureSlot % m_iWidthCellCount;
|
||||
int y = pSlot->iTextureSlot / m_iWidthCellCount;
|
||||
|
||||
CGlyphBitmap* pGlyphBitmap;
|
||||
|
||||
if (glyphSize.x > 0 && glyphSize.y > 0)
|
||||
{
|
||||
m_pGlyphCache.SetGlyphBitmapSize(glyphSize.x, glyphSize.y, sizeRatio);
|
||||
}
|
||||
|
||||
if (!m_pGlyphCache.GetGlyph(&pGlyphBitmap, &pSlot->iHoriAdvance, &iWidth, &iHeight, pSlot->iCharOffsetX, pSlot->iCharOffsetY, cChar, glyphSize, fontHintParams))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pSlot->iCharWidth = iWidth;
|
||||
pSlot->iCharHeight = iHeight;
|
||||
|
||||
// Add a pixel along width and height to avoid artifacts being rendered
|
||||
// from a previous glyph in this slot due to bilinear filtering. The source
|
||||
// glyph bitmap buffer is presumed to be cleared prior to FreeType rendering
|
||||
// to the bitmap.
|
||||
const int blitWidth = AZ::GetMin<int>(iWidth + 1, m_iCellWidth);
|
||||
const int blitHeight = AZ::GetMin<int>(iHeight + 1, m_iCellHeight);
|
||||
|
||||
pGlyphBitmap->BlitTo8(m_pBuffer, 0, 0,
|
||||
blitWidth, blitHeight, x * m_iCellWidth, y * m_iCellHeight, m_iWidth);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void CFontTexture::CreateGradientSlot()
|
||||
{
|
||||
CTextureSlot* pSlot = GetGradientSlot();
|
||||
assert(pSlot->cCurrentChar == (uint32)~0); // 0 needs to be unused spot
|
||||
|
||||
pSlot->Reset();
|
||||
pSlot->iCharWidth = m_iCellWidth - 2;
|
||||
pSlot->iCharHeight = m_iCellHeight - 2;
|
||||
pSlot->SetNotReusable();
|
||||
|
||||
int x = pSlot->iTextureSlot % m_iWidthCellCount;
|
||||
int y = pSlot->iTextureSlot / m_iWidthCellCount;
|
||||
|
||||
assert(sizeof(*m_pBuffer) == sizeof(uint8));
|
||||
uint8* pBuffer = &m_pBuffer[x * m_iCellWidth + y * m_iCellHeight * m_iWidth];
|
||||
|
||||
for (uint32 dwY = 0; dwY < pSlot->iCharHeight; ++dwY)
|
||||
{
|
||||
for (uint32 dwX = 0; dwX < pSlot->iCharWidth; ++dwX)
|
||||
{
|
||||
pBuffer[dwX + dwY * m_iWidth] = dwY * 255 / (pSlot->iCharHeight - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CTextureSlot* CFontTexture::GetGradientSlot()
|
||||
{
|
||||
return m_pSlotList[0];
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CryFont::FontTexture::CTextureSlotKey CFontTexture::GetTextureSlotKey(uint32 cChar, const Vec2i& glyphSize) const
|
||||
{
|
||||
const Vec2i clampedGlyphSize(ClampGlyphSize(glyphSize, m_iCellWidth, m_iCellHeight));
|
||||
return CryFont::FontTexture::CTextureSlotKey(clampedGlyphSize, cChar);
|
||||
}
|
||||
|
||||
Vec2i CFontTexture::ClampGlyphSize(const Vec2i& glyphSize, int cellWidth, int cellHeight)
|
||||
{
|
||||
const Vec2i maxCellDimensions(cellWidth, cellHeight);
|
||||
Vec2i clampedGlyphSize(glyphSize);
|
||||
|
||||
const bool hasZeroDimension = glyphSize.x == 0 || glyphSize.y == 0;
|
||||
const bool isDefaultSize = glyphSize == CCryFont::defaultGlyphSize;
|
||||
const bool exceedsDimensions = glyphSize.x > cellWidth || glyphSize.y > cellHeight;
|
||||
const bool useMaxCellDimension = hasZeroDimension || isDefaultSize || exceedsDimensions;
|
||||
if (useMaxCellDimension)
|
||||
{
|
||||
clampedGlyphSize = maxCellDimensions;
|
||||
}
|
||||
|
||||
return clampedGlyphSize;
|
||||
}
|
||||
|
||||
#endif // #if !defined(USE_NULLFONT_ALWAYS)
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRYFONT_FONTTEXTURE_H
|
||||
#define CRYINCLUDE_CRYFONT_FONTTEXTURE_H
|
||||
#pragma once
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include "GlyphCache.h"
|
||||
#include "GlyphBitmap.h"
|
||||
#include "CryFont.h"
|
||||
#include "FFont.h"
|
||||
|
||||
typedef uint8 FONT_TEXTURE_TYPE;
|
||||
|
||||
// the number of slots in the glyph cache
|
||||
// each slot ocupies ((glyph_bitmap_width * glyph_bitmap_height) + 24) bytes
|
||||
#define FONT_GLYPH_CACHE_SIZE (1)
|
||||
|
||||
// the glyph spacing in font texels between characters in proportional font mode (more correct would be to take the value in the character)
|
||||
#define FONT_GLYPH_PROP_SPACING (1)
|
||||
|
||||
// the size of a rendered space, this value gets multiplied by the default characted width
|
||||
#define FONT_SPACE_SIZE (0.5f)
|
||||
|
||||
// don't draw this char (used to avoid drawing color codes)
|
||||
#define FONT_NOT_DRAWABLE_CHAR (0xffff)
|
||||
|
||||
// smoothing methods
|
||||
#define FONT_SMOOTH_NONE 0
|
||||
#define FONT_SMOOTH_BLUR 1
|
||||
#define FONT_SMOOTH_SUPERSAMPLE 2
|
||||
|
||||
// smoothing amounts
|
||||
#define FONT_SMOOTH_AMOUNT_NONE 0
|
||||
#define FONT_SMOOTH_AMOUNT_2X 1
|
||||
#define FONT_SMOOTH_AMOUNT_4X 2
|
||||
|
||||
//! Stores glyph meta-data read from the font (FreeType).
|
||||
//!
|
||||
//! \sa CCacheSlot
|
||||
typedef struct CTextureSlot
|
||||
{
|
||||
Vec2i glyphSize = CCryFont::defaultGlyphSize; //!< Size of the rendered glyph stored in the font texture
|
||||
uint16 wSlotUsage; //!< For LRU strategy, 0xffff is never released
|
||||
uint32 cCurrentChar; //!< ~0 if not used for characters
|
||||
int iTextureSlot;
|
||||
int iHoriAdvance; //!< Advance width. See FT_Glyph_Metrics::horiAdvance.
|
||||
float vTexCoord[2]; //!< Character position in the texture (not yet half texel corrected)
|
||||
uint8 iCharWidth; //!< Glyph width (in pixel)
|
||||
uint8 iCharHeight; //!< Glyph height (in pixel)
|
||||
AZ::s32 iCharOffsetX; //!< Glyph's left-side bearing (in pixels). See FT_GlyphSlotRec::bitmap_left.
|
||||
AZ::s32 iCharOffsetY; //!< Glyph's top bearing (in pixels). See FT_GlyphSlotRec::bitmap_top.
|
||||
|
||||
void Reset()
|
||||
{
|
||||
wSlotUsage = 0;
|
||||
cCurrentChar = ~0;
|
||||
iHoriAdvance = 0;
|
||||
iCharWidth = 0;
|
||||
iCharHeight = 0;
|
||||
iCharOffsetX = 0;
|
||||
iCharOffsetY = 0;
|
||||
}
|
||||
|
||||
void SetNotReusable()
|
||||
{
|
||||
wSlotUsage = 0xffff;
|
||||
}
|
||||
|
||||
void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const {}
|
||||
} CTextureSlot;
|
||||
|
||||
|
||||
typedef std::vector<CTextureSlot*> CTextureSlotList;
|
||||
typedef std::vector<CTextureSlot*>::iterator CTextureSlotListItor;
|
||||
|
||||
namespace CryFont
|
||||
{
|
||||
namespace FontTexture
|
||||
{
|
||||
//! Height and width pair for glyph size mapping
|
||||
typedef Vec2i CGlyphSizeType;
|
||||
|
||||
//! Pair for mapping a height and width size to a UTF32 character/glyph
|
||||
typedef AZStd::pair<CGlyphSizeType, uint32> CTextureSlotKey;
|
||||
|
||||
//! Hasher for texture slot table keys (glyphsize-char code pair)
|
||||
//!
|
||||
//! Instead of creating our own custom hash, the types are broken down to their
|
||||
//! native types (ints) and passed to existing hashes that handle those types.
|
||||
struct HashTextureSlotTableKey
|
||||
{
|
||||
typedef CTextureSlotKey ArgumentType;
|
||||
typedef AZStd::size_t ResultType;
|
||||
typedef AZStd::pair<int32, int32> Int32Pair;
|
||||
typedef AZStd::pair<Int32Pair, uint32> Int32PairU32Pair;
|
||||
ResultType operator()(const ArgumentType& value) const
|
||||
{
|
||||
// Utiliize existing hash function for pairs of ints
|
||||
AZStd::hash<Int32PairU32Pair> pairHash;
|
||||
return pairHash(Int32PairU32Pair(Int32Pair(value.first.x, value.first.y), value.second));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//! Maps size-speicifc UTF32 glyphs to their corresponding texture slots
|
||||
typedef AZStd::unordered_map<CryFont::FontTexture::CTextureSlotKey, CTextureSlot*, CryFont::FontTexture::HashTextureSlotTableKey> CTextureSlotTable;
|
||||
|
||||
typedef CTextureSlotTable::iterator CTextureSlotTableItor;
|
||||
typedef CTextureSlotTable::const_iterator CTextureSlotTableItorConst;
|
||||
|
||||
#ifdef WIN64
|
||||
#undef GetCharWidth
|
||||
#undef GetCharHeight
|
||||
#endif
|
||||
|
||||
//! Stores the glyphs of a font within a single texture.
|
||||
//!
|
||||
//! The texture resolution is configurable, as is the number of slots within
|
||||
//! the texture.
|
||||
//!
|
||||
//! A texture slot contains a single glyph within the font and are uniform
|
||||
//! size throughout the font texture (each slot occupies the same size
|
||||
//! regardless of the size of a glyph being stored, so a '.' occupies the
|
||||
//! same amount of space as a 'W', for example).
|
||||
//!
|
||||
//! Font glyph buffers are read from FreeType and copied into the texture.
|
||||
//!
|
||||
//! \sa CTextureSlot, CFontRenderer
|
||||
class CFontTexture
|
||||
{
|
||||
public:
|
||||
CFontTexture();
|
||||
~CFontTexture();
|
||||
|
||||
int CreateFromFile(const string& szFileName, int iWidth, int iHeight, int iSmoothMethod, int iSmoothAmount, int iWidthCharCount = 16, int iHeightCharCount = 16);
|
||||
|
||||
//! Default texture slot width/height is 16x8 slots, allowing for 128 glyphs to be stored in the font texture. This was
|
||||
//! previously 16x16, allowing 256 glyphs to be stored. For reference, there are 95 printable ASCII characters, so by
|
||||
//! reducing the number of slots, the height of the font texture can be halved (for some nice memory savings). We may
|
||||
//! want to make this configurable in the font XML (especially for languages with a large number of printable chars).
|
||||
int CreateFromMemory(unsigned char* pFileData, int iDataSize, int iWidth, int iHeight, int iSmoothMethod, int iSmoothAmount, int iWidthCharCount, int iHeightCharCount, float sizeRatio);
|
||||
|
||||
int Create(int iWidth, int iHeight, int iSmoothMethod, int iSmoothAmount, int iWidthCharCount = 16, int iHeightCharCount = 16, float sizeRatio = IFFontConstants::defaultSizeRatio);
|
||||
int Release();
|
||||
|
||||
int SetEncoding(FT_Encoding pEncoding) { return m_pGlyphCache.SetEncoding(pEncoding); }
|
||||
FT_Encoding GetEncoding() { return m_pGlyphCache.GetEncoding(); }
|
||||
|
||||
int GetCellWidth() { return m_iCellWidth; }
|
||||
int GetCellHeight() { return m_iCellHeight; }
|
||||
|
||||
int GetWidth() { return m_iWidth; }
|
||||
int GetHeight() { return m_iHeight; }
|
||||
|
||||
int GetWidthCellCount() { return m_iWidthCellCount; }
|
||||
int GetHeightCellCount() { return m_iHeightCellCount; }
|
||||
|
||||
float GetTextureCellWidth() { return m_fTextureCellWidth; }
|
||||
float GetTextureCellHeight() { return m_fTextureCellHeight; }
|
||||
|
||||
FONT_TEXTURE_TYPE* GetBuffer() { return m_pBuffer; }
|
||||
|
||||
uint32 GetSlotChar(int iSlot) const;
|
||||
CTextureSlot* GetCharSlot(uint32 cChar, const Vec2i& glyphSize = CCryFont::defaultGlyphSize);
|
||||
CTextureSlot* GetGradientSlot();
|
||||
|
||||
CTextureSlot* GetLRUSlot();
|
||||
CTextureSlot* GetMRUSlot();
|
||||
|
||||
//! Returns 1 if texture updated, returns 2 if texture not updated, returns 0 on error
|
||||
//! \param szString A string of glyphs (UTF8) to added to the font texture (if they don't already exist in the font texture)
|
||||
//! \param pUpdated is the number of slots updated
|
||||
//! \param sizeRatio A sizing scale that gets applied to all glyphs sizes before they are stored in the font texture.
|
||||
//! \param glyphSize The resolution to render the glyphs in szString at.
|
||||
//! \param glyphFlags Controls hinting behavior for glyphs rendered to the font texture.
|
||||
int PreCacheString(const char* szString, int* pUpdated = 0, float sizeRatio = IFFontConstants::defaultSizeRatio, const Vec2i& glyphSize = CCryFont::defaultGlyphSize, const CFFont::FontHintParams& glyphFlags = CFFont::FontHintParams());
|
||||
// Arguments:
|
||||
// pSlot - function does nothing if this pointer is 0
|
||||
void GetTextureCoord(CTextureSlot * pSlot, float texCoords[4], int& iCharSizeX, int& iCharSizeY, int& iCharOffsetX, int& iCharOffsetY, const Vec2i& glyphSize = CCryFont::defaultGlyphSize) const;
|
||||
int GetCharacterWidth(uint32 cChar) const;
|
||||
//! Gets the horizontal advance for the given glyph/char.
|
||||
//! \param cChar The glyph (UTF32) to get the horizontal advance for.
|
||||
//! \param glyphSize The rendered size of the glyph to get the advance for (the same glyph could be stored in the font texture at multiple sizes).
|
||||
int GetHorizontalAdvance(uint32 cChar, const Vec2i& glyphSize = CCryFont::defaultGlyphSize) const;
|
||||
// int GetCharHeightByChar(wchar_t cChar);
|
||||
|
||||
// useful for special feature rendering interleaved with fonts (e.g. box behind the text)
|
||||
void CreateGradientSlot();
|
||||
|
||||
int WriteToFile(const string& szFileName);
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(*this));
|
||||
pSizer->AddObject(m_pGlyphCache);
|
||||
pSizer->AddObject(m_pSlotList);
|
||||
//pSizer->AddContainer(m_pSlotTable);
|
||||
pSizer->AddObject(m_pBuffer, m_iWidth * m_iHeight * sizeof(FONT_TEXTURE_TYPE));
|
||||
}
|
||||
|
||||
bool GetMonospaced() const { return m_pGlyphCache.GetMonospaced(); }
|
||||
|
||||
Vec2 GetKerning(uint32_t leftGlyph, uint32_t rightGlyph);
|
||||
|
||||
float GetAscenderToHeightRatio();
|
||||
|
||||
public: // ---------------------------------------------------------------
|
||||
|
||||
//! Clamps the given glyph size to the given max cell width and height dimensions.
|
||||
static Vec2i ClampGlyphSize(const Vec2i& glyphSize, int cellWidth, int cellHeight);
|
||||
|
||||
private: // ---------------------------------------------------------------
|
||||
|
||||
int CreateSlotList(int iListSize);
|
||||
int ReleaseSlotList();
|
||||
|
||||
//! Updates the given font texture slot with the given glyph (UTF8) with the given parameters. If the glyph doesn't
|
||||
//! exist in the font texture at the given size, then the glyph will be rendered to the font texture with the given
|
||||
//! parameters.
|
||||
//! \param iSlot Index of the texture slot to update within the slot list.
|
||||
//! \param wSlotUsage Used for LRU strategy to determine how many times a glyph is referenced for retention within the font texture (before eviction).
|
||||
//! \param cChar UTF32 glyph to store within the slot.
|
||||
//! \param sizeRatio A sizing scale that should be applied to the glyph before being stored within the font texture.
|
||||
//! \param glyphSize The size of the glyph to be rendered at within the font texture.
|
||||
//! \param glyphFlags Specifies hinting behavior that should be applied to the glyph when rendered to the font texture.
|
||||
int UpdateSlot(int iSlot, uint16 wSlotUsage, uint32 cChar, float sizeRatio, const Vec2i& glyphSize = CCryFont::defaultGlyphSize, const CFFont::FontHintParams& glyphFlags = CFFont::FontHintParams());
|
||||
|
||||
CryFont::FontTexture::CTextureSlotKey GetTextureSlotKey(uint32 cChar, const Vec2i& glyphSize = CCryFont::defaultGlyphSize) const;
|
||||
|
||||
//! Calculates scaling info that should be applied when the rendered glyph size doesn't match the maximum glyph slot resolution.
|
||||
//!
|
||||
//! Glyphs can be re-rendered to glyph slots at smaller resolutions for pixel-perfect resolution (rather than applying a scale
|
||||
//! to glyphs rendered at larger sizes). These scaling values allow clients of the font texture to use the glyphs without regard
|
||||
//! to whether the glyphs have been re-rendered or not.
|
||||
float GetRequestSizeWidthScale(const Vec2i& glyphSize) const
|
||||
{
|
||||
const int cellWidth = m_iCellWidth == 0 ? 1 : m_iCellWidth;
|
||||
const float invCellWidth = 1.0f / cellWidth;
|
||||
return glyphSize.x > 0 ? glyphSize.x * invCellWidth : 1.0f;
|
||||
}
|
||||
|
||||
//! Calculates scaling info that should be applied when the rendered glyph size doesn't match the maximum glyph slot resolution.
|
||||
//!
|
||||
//! Glyphs can be re-rendered to glyph slots at smaller resolutions for pixel-perfect resolution (rather than applying a scale
|
||||
//! to glyphs rendered at larger sizes). These scaling values allow clients of the font texture to use the glyphs without regard
|
||||
//! to whether the glyphs have been re-rendered or not.
|
||||
float GetRequestSizeHeightScale(const Vec2i& glyphSize) const
|
||||
{
|
||||
const int cellHeight = m_iCellHeight == 0 ? 1 : m_iCellHeight;
|
||||
const float invCellHeight = 1.0f / cellHeight;
|
||||
return glyphSize.y > 0 ? glyphSize.y * invCellHeight : 1.0f;
|
||||
}
|
||||
|
||||
// --------------------------------
|
||||
|
||||
int m_iWidth; // whole texture cache width
|
||||
int m_iHeight; // whole texture cache height
|
||||
|
||||
float m_fInvWidth;
|
||||
float m_fInvHeight;
|
||||
|
||||
int m_iCellWidth;
|
||||
int m_iCellHeight;
|
||||
|
||||
float m_fTextureCellWidth;
|
||||
float m_fTextureCellHeight;
|
||||
|
||||
int m_iWidthCellCount;
|
||||
int m_iHeightCellCount;
|
||||
|
||||
int m_nTextureSlotCount;
|
||||
|
||||
int m_iSmoothMethod;
|
||||
int m_iSmoothAmount;
|
||||
|
||||
CGlyphCache m_pGlyphCache;
|
||||
CTextureSlotList m_pSlotList;
|
||||
CTextureSlotTable m_pSlotTable;
|
||||
|
||||
FONT_TEXTURE_TYPE* m_pBuffer; // [y*iWidth * x] x=0..iWidth-1, y=0..iHeight-1
|
||||
|
||||
uint16 m_wSlotUsage;
|
||||
};
|
||||
|
||||
#endif // #if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#endif // CRYINCLUDE_CRYFONT_FONTTEXTURE_H
|
||||
@@ -1,396 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Purpose:
|
||||
// - Hold a glyph bitmap and blit it to the main texture
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
#include "GlyphBitmap.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CGlyphBitmap::CGlyphBitmap()
|
||||
: m_iWidth(0)
|
||||
, m_iHeight(0)
|
||||
, m_pBuffer(0)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CGlyphBitmap::~CGlyphBitmap()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::Create(int iWidth, int iHeight)
|
||||
{
|
||||
Release();
|
||||
|
||||
m_pBuffer = new unsigned char[iWidth * iHeight];
|
||||
|
||||
if (!m_pBuffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_iWidth = iWidth;
|
||||
m_iHeight = iHeight;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::Release()
|
||||
{
|
||||
if (m_pBuffer)
|
||||
{
|
||||
delete[] m_pBuffer;
|
||||
}
|
||||
m_pBuffer = 0;
|
||||
m_iWidth = m_iHeight = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::Blur(int iIterations)
|
||||
{
|
||||
int cSum;
|
||||
int yOffset;
|
||||
int yupOffset;
|
||||
int ydownOffset;
|
||||
|
||||
for (int i = 0; i < iIterations; i++)
|
||||
{
|
||||
for (int y = 0; y < m_iHeight; y++)
|
||||
{
|
||||
yOffset = y * m_iWidth;
|
||||
|
||||
if (y - 1 >= 0)
|
||||
{
|
||||
yupOffset = (y - 1) * m_iWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
yupOffset = (y) * m_iWidth;
|
||||
}
|
||||
|
||||
if (y + 1 < m_iHeight)
|
||||
{
|
||||
ydownOffset = (y + 1) * m_iWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
ydownOffset = (y) * m_iWidth;
|
||||
}
|
||||
|
||||
for (int x = 0; x < m_iWidth; x++)
|
||||
{
|
||||
cSum = m_pBuffer[yupOffset + x] + m_pBuffer[ydownOffset + x];
|
||||
|
||||
if (x - 1 >= 0)
|
||||
{
|
||||
cSum += m_pBuffer[yOffset + x - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
cSum += m_pBuffer[yOffset + x];
|
||||
}
|
||||
|
||||
if (x + 1 < m_iWidth)
|
||||
{
|
||||
cSum += m_pBuffer[yOffset + x + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
cSum += m_pBuffer[yOffset + x];
|
||||
}
|
||||
|
||||
m_pBuffer[yOffset + x] = cSum >> 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::Scale(float fScaleX, float fScaleY)
|
||||
{
|
||||
int iNewWidth = (int)(m_iWidth * fScaleX);
|
||||
int iNewHeight = (int)(m_iHeight * fScaleY);
|
||||
|
||||
unsigned char* pNewBuffer = new unsigned char[iNewWidth * iNewHeight];
|
||||
|
||||
if (!pNewBuffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float xFactor = m_iWidth / (float)iNewWidth;
|
||||
float yFactor = m_iHeight / (float)iNewHeight;
|
||||
|
||||
float xFractioned, yFractioned, xFraction, yFraction, oneMinusX, oneMinusY, fR0, fR1;
|
||||
int xCeil, yCeil, xFloor, yFloor, yNewOffset;
|
||||
|
||||
unsigned char c0, c1, c2, c3;
|
||||
|
||||
for (int y = 0; y < iNewHeight; ++y)
|
||||
{
|
||||
yFractioned = y * yFactor;
|
||||
yFloor = (int)floor_tpl(yFractioned);
|
||||
yCeil = yFloor + 1;
|
||||
|
||||
if (yCeil >= m_iHeight)
|
||||
{
|
||||
yCeil = yFloor;
|
||||
}
|
||||
|
||||
yFraction = yFractioned - yFloor;
|
||||
oneMinusY = 1.0f - yFraction;
|
||||
|
||||
yNewOffset = y * iNewWidth;
|
||||
|
||||
for (int x = 0; x < iNewWidth; ++x)
|
||||
{
|
||||
xFractioned = x * xFactor;
|
||||
xFloor = (int)floor_tpl(xFractioned);
|
||||
xCeil = xFloor + 1;
|
||||
|
||||
if (xCeil >= m_iWidth)
|
||||
{
|
||||
xCeil = xFloor;
|
||||
}
|
||||
|
||||
xFraction = xFractioned - xFloor;
|
||||
oneMinusX = 1.0f - xFraction;
|
||||
|
||||
c0 = m_pBuffer[yFloor * m_iWidth + xFloor];
|
||||
c1 = m_pBuffer[yFloor * m_iWidth + xCeil];
|
||||
c2 = m_pBuffer[yCeil * m_iWidth + xFloor];
|
||||
c3 = m_pBuffer[yCeil * m_iWidth + xCeil];
|
||||
|
||||
fR0 = (oneMinusX * c0 + xFraction * c1);
|
||||
fR1 = (oneMinusX * c2 + xFraction * c3);
|
||||
|
||||
pNewBuffer[yNewOffset + x] = (unsigned char)((oneMinusY * fR0) + (yFraction * fR1));
|
||||
}
|
||||
}
|
||||
|
||||
m_iWidth = iNewWidth;
|
||||
m_iHeight = iNewHeight;
|
||||
|
||||
delete[] m_pBuffer;
|
||||
m_pBuffer = pNewBuffer;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::Clear()
|
||||
{
|
||||
memset(m_pBuffer, 0, m_iWidth * m_iHeight);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::BlitTo8(unsigned char* pBuffer, int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, int iDestY, int iDestWidth)
|
||||
{
|
||||
int ySrcOffset, yDestOffset;
|
||||
|
||||
for (int y = 0; y < iSrcHeight; y++)
|
||||
{
|
||||
ySrcOffset = (iSrcY + y) * m_iWidth;
|
||||
yDestOffset = (iDestY + y) * iDestWidth;
|
||||
|
||||
for (int x = 0; x < iSrcWidth; x++)
|
||||
{
|
||||
pBuffer[yDestOffset + iDestX + x] = m_pBuffer[ySrcOffset + iSrcX + x];
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::BlitTo32(unsigned int* pBuffer, int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, int iDestY, int iDestWidth)
|
||||
{
|
||||
int ySrcOffset, yDestOffset;
|
||||
char cColor;
|
||||
|
||||
for (int y = 0; y < iSrcHeight; y++)
|
||||
{
|
||||
ySrcOffset = (iSrcY + y) * m_iWidth;
|
||||
yDestOffset = (iDestY + y) * iDestWidth;
|
||||
|
||||
for (int x = 0; x < iSrcWidth; x++)
|
||||
{
|
||||
cColor = m_pBuffer[ySrcOffset + iSrcX + x];
|
||||
|
||||
pBuffer[yDestOffset + iDestX + x] = (cColor << 24) | (255 << 16) | (255 << 8) | 255;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::BlitScaledTo8(unsigned char* pBuffer, [[maybe_unused]] int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, [[maybe_unused]] int iDestY, int iDestWidth, int iDestHeight, int iDestBufferWidth)
|
||||
{
|
||||
int iNewWidth = (int)iDestWidth;
|
||||
int iNewHeight = (int)iDestHeight;
|
||||
|
||||
unsigned char* pNewBuffer = pBuffer;
|
||||
|
||||
float xFactor = iSrcWidth / (float)iNewWidth;
|
||||
float yFactor = iSrcHeight / (float)iNewHeight;
|
||||
|
||||
float xFractioned, yFractioned, xFraction, yFraction, oneMinusX, oneMinusY, fR0, fR1;
|
||||
int xCeil, yCeil, xFloor, yFloor, yNewOffset;
|
||||
|
||||
unsigned char c0, c1, c2, c3;
|
||||
|
||||
for (int y = 0; y < iNewHeight; ++y)
|
||||
{
|
||||
yFractioned = y * yFactor;
|
||||
yFloor = (int)floor_tpl(yFractioned);
|
||||
yCeil = yFloor + 1;
|
||||
|
||||
yFraction = yFractioned - yFloor;
|
||||
oneMinusY = 1.0f - yFraction;
|
||||
|
||||
yNewOffset = y * iDestBufferWidth;
|
||||
|
||||
yFloor += iSrcY;
|
||||
yCeil += iSrcY;
|
||||
|
||||
if (yCeil >= m_iHeight)
|
||||
{
|
||||
yCeil = yFloor;
|
||||
}
|
||||
|
||||
for (int x = 0; x < iNewWidth; ++x)
|
||||
{
|
||||
xFractioned = x * xFactor;
|
||||
xFloor = (int)floor_tpl(xFractioned);
|
||||
xCeil = xFloor + 1;
|
||||
|
||||
xFraction = xFractioned - xFloor;
|
||||
oneMinusX = 1.0f - xFraction;
|
||||
|
||||
xFloor += iSrcY;
|
||||
xCeil += iSrcY;
|
||||
|
||||
if (xCeil >= m_iWidth)
|
||||
{
|
||||
xCeil = xFloor;
|
||||
}
|
||||
|
||||
c0 = m_pBuffer[yFloor * m_iWidth + xFloor];
|
||||
c1 = m_pBuffer[yFloor * m_iWidth + xCeil];
|
||||
c2 = m_pBuffer[yCeil * m_iWidth + xFloor];
|
||||
c3 = m_pBuffer[yCeil * m_iWidth + xCeil];
|
||||
|
||||
fR0 = (oneMinusX * c0 + xFraction * c1);
|
||||
fR1 = (oneMinusX * c2 + xFraction * c3);
|
||||
|
||||
pNewBuffer[yNewOffset + x + iDestX] = (unsigned char)((oneMinusY * fR0) + (yFraction * fR1));
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if __GNUC__ >= 4 && __GNUC__MINOR__ < 7
|
||||
#pragma GCC diagnostic ignored "-Woverflow"
|
||||
#endif
|
||||
#endif
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphBitmap::BlitScaledTo32(unsigned char* pBuffer, [[maybe_unused]] int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, [[maybe_unused]] int iDestY, int iDestWidth, int iDestHeight, int iDestBufferWidth)
|
||||
{
|
||||
int iNewWidth = (int)iDestWidth;
|
||||
int iNewHeight = (int)iDestHeight;
|
||||
|
||||
unsigned char* pNewBuffer = pBuffer;
|
||||
|
||||
float xFactor = iSrcWidth / (float)iNewWidth;
|
||||
float yFactor = iSrcHeight / (float)iNewHeight;
|
||||
|
||||
float xFractioned, yFractioned, xFraction, yFraction, oneMinusX, oneMinusY, fR0, fR1;
|
||||
int xCeil, yCeil, xFloor, yFloor, yNewOffset;
|
||||
|
||||
unsigned char c0, c1, c2, c3, cColor;
|
||||
|
||||
for (int y = 0; y < iNewHeight; ++y)
|
||||
{
|
||||
yFractioned = y * yFactor;
|
||||
yFloor = (int)floor_tpl(yFractioned);
|
||||
yCeil = yFloor + 1;
|
||||
|
||||
yFraction = yFractioned - yFloor;
|
||||
oneMinusY = 1.0f - yFraction;
|
||||
|
||||
yNewOffset = y * iDestBufferWidth;
|
||||
|
||||
yFloor += iSrcY;
|
||||
yCeil += iSrcY;
|
||||
|
||||
if (yCeil >= m_iHeight)
|
||||
{
|
||||
yCeil = yFloor;
|
||||
}
|
||||
|
||||
for (int x = 0; x < iNewWidth; ++x)
|
||||
{
|
||||
xFractioned = x * xFactor;
|
||||
xFloor = (int)floor_tpl(xFractioned);
|
||||
xCeil = xFloor + 1;
|
||||
|
||||
xFraction = xFractioned - xFloor;
|
||||
oneMinusX = 1.0f - xFraction;
|
||||
|
||||
xFloor += iSrcY;
|
||||
xCeil += iSrcY;
|
||||
|
||||
if (xCeil >= m_iWidth)
|
||||
{
|
||||
xCeil = xFloor;
|
||||
}
|
||||
|
||||
c0 = m_pBuffer[yFloor * m_iWidth + xFloor];
|
||||
c1 = m_pBuffer[yFloor * m_iWidth + xCeil];
|
||||
c2 = m_pBuffer[yCeil * m_iWidth + xFloor];
|
||||
c3 = m_pBuffer[yCeil * m_iWidth + xCeil];
|
||||
|
||||
fR0 = (oneMinusX * c0 + xFraction * c1);
|
||||
fR1 = (oneMinusX * c2 + xFraction * c3);
|
||||
|
||||
cColor = (unsigned char)((oneMinusY * fR0) + (yFraction * fR1));
|
||||
|
||||
pNewBuffer[yNewOffset + x + iDestX] = 0xffffff | (cColor << 24);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#if __GNUC__ >= 4 && __GNUC__MINOR__ < 7
|
||||
#pragma GCC diagnostic error "-Woverflow"
|
||||
#endif
|
||||
#endif
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Purpose : Hold a glyph bitmap and blit it to the main texture
|
||||
|
||||
#ifndef CRYINCLUDE_CRYFONT_GLYPHBITMAP_H
|
||||
#define CRYINCLUDE_CRYFONT_GLYPHBITMAP_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
class CGlyphBitmap
|
||||
{
|
||||
public:
|
||||
CGlyphBitmap();
|
||||
~CGlyphBitmap();
|
||||
|
||||
int Create(int iWidth, int iHeight);
|
||||
int Release();
|
||||
|
||||
unsigned char* GetBuffer() { return m_pBuffer; };
|
||||
|
||||
int Blur(int iIterations);
|
||||
int Scale(float fScaleX, float fScaleY);
|
||||
|
||||
int Clear();
|
||||
|
||||
int BlitTo8(unsigned char* pBuffer, int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, int iDestY, int iDestWidth);
|
||||
int BlitTo32(unsigned int* pBuffer, int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, int iDestY, int iDestWidth);
|
||||
|
||||
int BlitScaledTo8(unsigned char* pBuffer, int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, int iDestY, int iDestWidth, int iDestHeight, int iDestBufferWidth);
|
||||
int BlitScaledTo32(unsigned char* pBuffer, int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, int iDestY, int iDestWidth, int iDestHeight, int iDestBufferWidth);
|
||||
|
||||
int GetWidth() { return m_iWidth; }
|
||||
int GetHeight() { return m_iHeight; }
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(m_pBuffer, m_iWidth * m_iHeight);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
unsigned char* m_pBuffer;
|
||||
int m_iWidth;
|
||||
int m_iHeight;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYFONT_GLYPHBITMAP_H
|
||||
@@ -1,433 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Purpose:
|
||||
// - Manage and cache glyphs, retrieving them from the renderer as needed
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include "GlyphCache.h"
|
||||
#include "FontTexture.h"
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CGlyphCache::CGlyphCache()
|
||||
: m_dwUsage(1)
|
||||
, m_iGlyphBitmapWidth(0)
|
||||
, m_iGlyphBitmapHeight(0)
|
||||
, m_pScaleBitmap(0)
|
||||
{
|
||||
m_pCacheTable.clear();
|
||||
m_pSlotList.clear();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CGlyphCache::~CGlyphCache()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::Create(int iCacheSize, int iGlyphBitmapWidth, int iGlyphBitmapHeight, int iSmoothMethod, int iSmoothAmount, float sizeRatio)
|
||||
{
|
||||
m_iSmoothMethod = iSmoothMethod;
|
||||
m_iSmoothAmount = iSmoothAmount;
|
||||
|
||||
m_iGlyphBitmapWidth = iGlyphBitmapWidth;
|
||||
m_iGlyphBitmapHeight = iGlyphBitmapHeight;
|
||||
|
||||
|
||||
if (!CreateSlotList(iCacheSize))
|
||||
{
|
||||
ReleaseSlotList();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iScaledGlyphWidth = 0;
|
||||
int iScaledGlyphHeight = 0;
|
||||
|
||||
switch (m_iSmoothMethod)
|
||||
{
|
||||
case FONT_SMOOTH_SUPERSAMPLE:
|
||||
{
|
||||
switch (m_iSmoothAmount)
|
||||
{
|
||||
case FONT_SMOOTH_AMOUNT_2X:
|
||||
iScaledGlyphWidth = m_iGlyphBitmapWidth << 1;
|
||||
iScaledGlyphHeight = m_iGlyphBitmapHeight << 1;
|
||||
break;
|
||||
case FONT_SMOOTH_AMOUNT_4X:
|
||||
iScaledGlyphWidth = m_iGlyphBitmapWidth << 2;
|
||||
iScaledGlyphHeight = m_iGlyphBitmapHeight << 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (iScaledGlyphWidth)
|
||||
{
|
||||
m_pScaleBitmap = new CGlyphBitmap;
|
||||
|
||||
if (!m_pScaleBitmap)
|
||||
{
|
||||
Release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_pScaleBitmap->Create(iScaledGlyphWidth, iScaledGlyphHeight))
|
||||
{
|
||||
Release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_pFontRenderer.SetGlyphBitmapSize(iScaledGlyphWidth, iScaledGlyphHeight, sizeRatio);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pFontRenderer.SetGlyphBitmapSize(m_iGlyphBitmapWidth, m_iGlyphBitmapHeight, sizeRatio);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::Release()
|
||||
{
|
||||
ReleaseSlotList();
|
||||
|
||||
m_pCacheTable.clear();
|
||||
|
||||
if (m_pScaleBitmap)
|
||||
{
|
||||
m_pScaleBitmap->Release();
|
||||
|
||||
delete m_pScaleBitmap;
|
||||
|
||||
m_pScaleBitmap = 0;
|
||||
}
|
||||
|
||||
m_iGlyphBitmapWidth = 0;
|
||||
m_iGlyphBitmapHeight = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::LoadFontFromFile(const string& szFileName)
|
||||
{
|
||||
return m_pFontRenderer.LoadFromFile(szFileName);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::LoadFontFromMemory(unsigned char* pFileBuffer, int iDataSize)
|
||||
{
|
||||
return m_pFontRenderer.LoadFromMemory(pFileBuffer, iDataSize);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::ReleaseFont()
|
||||
{
|
||||
m_pFontRenderer.Release();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::GetGlyphBitmapSize(int* pWidth, int* pHeight)
|
||||
{
|
||||
if (pWidth)
|
||||
{
|
||||
*pWidth = m_iGlyphBitmapWidth;
|
||||
}
|
||||
|
||||
if (pHeight)
|
||||
{
|
||||
*pHeight = m_iGlyphBitmapWidth;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void CGlyphCache::SetGlyphBitmapSize(int width, int height, float sizeRatio)
|
||||
{
|
||||
m_pFontRenderer.SetGlyphBitmapSize(width, height, sizeRatio);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::PreCacheGlyph(uint32 cChar, const Vec2i& glyphSize, const CFFont::FontHintParams& fontHintParams)
|
||||
{
|
||||
CCacheTable::iterator pItor = m_pCacheTable.find(GetCacheSlotKey(cChar, glyphSize));
|
||||
|
||||
if (pItor != m_pCacheTable.end())
|
||||
{
|
||||
pItor->second->dwUsage = m_dwUsage;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
CCacheSlot* pSlot = GetLRUSlot();
|
||||
|
||||
if (!pSlot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pSlot->dwUsage > 0)
|
||||
{
|
||||
UnCacheGlyph(pSlot->cCurrentChar, pSlot->glyphSize);
|
||||
}
|
||||
|
||||
if (m_pScaleBitmap)
|
||||
{
|
||||
int iOffsetMult = 1;
|
||||
|
||||
switch (m_iSmoothAmount)
|
||||
{
|
||||
case FONT_SMOOTH_AMOUNT_2X:
|
||||
iOffsetMult = 2;
|
||||
break;
|
||||
case FONT_SMOOTH_AMOUNT_4X:
|
||||
iOffsetMult = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
m_pScaleBitmap->Clear();
|
||||
|
||||
if (!m_pFontRenderer.GetGlyph(m_pScaleBitmap, &pSlot->iHoriAdvance, &pSlot->iCharWidth, &pSlot->iCharHeight, pSlot->iCharOffsetX, pSlot->iCharOffsetY, 0, 0, cChar, fontHintParams))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pSlot->iCharWidth >>= iOffsetMult >> 1;
|
||||
pSlot->iCharHeight >>= iOffsetMult >> 1;
|
||||
|
||||
m_pScaleBitmap->BlitScaledTo8(pSlot->pGlyphBitmap.GetBuffer(), 0, 0, m_pScaleBitmap->GetWidth(), m_pScaleBitmap->GetHeight(), 0, 0, pSlot->pGlyphBitmap.GetWidth(), pSlot->pGlyphBitmap.GetHeight(), pSlot->pGlyphBitmap.GetWidth());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_pFontRenderer.GetGlyph(&pSlot->pGlyphBitmap, &pSlot->iHoriAdvance, &pSlot->iCharWidth, &pSlot->iCharHeight, pSlot->iCharOffsetX, pSlot->iCharOffsetY, 0, 0, cChar, fontHintParams))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_iSmoothMethod == FONT_SMOOTH_BLUR)
|
||||
{
|
||||
pSlot->pGlyphBitmap.Blur(m_iSmoothAmount);
|
||||
}
|
||||
|
||||
pSlot->dwUsage = m_dwUsage;
|
||||
pSlot->cCurrentChar = cChar;
|
||||
pSlot->glyphSize = glyphSize;
|
||||
|
||||
m_pCacheTable.insert(AZStd::pair<CryFont::GlyphCache::CCacheTableKey, CCacheSlot*>(GetCacheSlotKey(cChar, glyphSize), pSlot));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CGlyphCache::UnCacheGlyph(uint32 cChar, const Vec2i& glyphSize)
|
||||
{
|
||||
CCacheTable::iterator pItor = m_pCacheTable.find(GetCacheSlotKey(cChar, glyphSize));
|
||||
|
||||
if (pItor != m_pCacheTable.end())
|
||||
{
|
||||
CCacheSlot* pSlot = pItor->second;
|
||||
|
||||
pSlot->Reset();
|
||||
|
||||
m_pCacheTable.erase(pItor);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::GlyphCached(uint32 cChar, const Vec2i& glyphSize)
|
||||
{
|
||||
return (m_pCacheTable.find(GetCacheSlotKey(cChar, glyphSize)) != m_pCacheTable.end());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CCacheSlot* CGlyphCache::GetLRUSlot()
|
||||
{
|
||||
unsigned int dwMinUsage = 0xffffffff;
|
||||
CCacheSlot* pLRUSlot = 0;
|
||||
CCacheSlot* pSlot;
|
||||
|
||||
CCacheSlotListItor pItor = m_pSlotList.begin();
|
||||
|
||||
while (pItor != m_pSlotList.end())
|
||||
{
|
||||
pSlot = *pItor;
|
||||
|
||||
if (pSlot->dwUsage == 0)
|
||||
{
|
||||
return pSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pSlot->dwUsage < dwMinUsage)
|
||||
{
|
||||
pLRUSlot = pSlot;
|
||||
dwMinUsage = pSlot->dwUsage;
|
||||
}
|
||||
}
|
||||
|
||||
pItor++;
|
||||
}
|
||||
|
||||
return pLRUSlot;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CCacheSlot* CGlyphCache::GetMRUSlot()
|
||||
{
|
||||
unsigned int dwMaxUsage = 0;
|
||||
CCacheSlot* pMRUSlot = 0;
|
||||
CCacheSlot* pSlot;
|
||||
|
||||
CCacheSlotListItor pItor = m_pSlotList.begin();
|
||||
|
||||
while (pItor != m_pSlotList.end())
|
||||
{
|
||||
pSlot = *pItor;
|
||||
|
||||
if (pSlot->dwUsage != 0)
|
||||
{
|
||||
if (pSlot->dwUsage > dwMaxUsage)
|
||||
{
|
||||
pMRUSlot = pSlot;
|
||||
dwMaxUsage = pSlot->dwUsage;
|
||||
}
|
||||
}
|
||||
|
||||
pItor++;
|
||||
}
|
||||
|
||||
return pMRUSlot;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::GetGlyph(CGlyphBitmap** pGlyph, int* piHoriAdvance, int* piWidth, int* piHeight, AZ::s32& iCharOffsetX, AZ::s32& iCharOffsetY, uint32 cChar, const Vec2i& glyphSize, const CFFont::FontHintParams& fontHintParams)
|
||||
{
|
||||
CCacheTable::iterator pItor = m_pCacheTable.find(GetCacheSlotKey(cChar, glyphSize));
|
||||
|
||||
if (pItor == m_pCacheTable.end())
|
||||
{
|
||||
if (!PreCacheGlyph(cChar, glyphSize, fontHintParams))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pItor = m_pCacheTable.find(GetCacheSlotKey(cChar, glyphSize));
|
||||
|
||||
pItor->second->dwUsage = m_dwUsage++;
|
||||
(*pGlyph) = &pItor->second->pGlyphBitmap;
|
||||
|
||||
if (piHoriAdvance)
|
||||
{
|
||||
*piHoriAdvance = pItor->second->iHoriAdvance;
|
||||
}
|
||||
|
||||
if (piWidth)
|
||||
{
|
||||
*piWidth = pItor->second->iCharWidth;
|
||||
}
|
||||
|
||||
if (piHeight)
|
||||
{
|
||||
*piHeight = pItor->second->iCharHeight;
|
||||
}
|
||||
|
||||
iCharOffsetX = pItor->second->iCharOffsetX;
|
||||
iCharOffsetY = pItor->second->iCharOffsetY;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
Vec2 CGlyphCache::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph)
|
||||
{
|
||||
return m_pFontRenderer.GetKerning(leftGlyph, rightGlyph);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
float CGlyphCache::GetAscenderToHeightRatio()
|
||||
{
|
||||
return m_pFontRenderer.GetAscenderToHeightRatio();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::CreateSlotList(int iListSize)
|
||||
{
|
||||
for (int i = 0; i < iListSize; i++)
|
||||
{
|
||||
CCacheSlot* pCacheSlot = new CCacheSlot;
|
||||
|
||||
if (!pCacheSlot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pCacheSlot->pGlyphBitmap.Create(m_iGlyphBitmapWidth, m_iGlyphBitmapHeight))
|
||||
{
|
||||
delete pCacheSlot;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pCacheSlot->Reset();
|
||||
|
||||
pCacheSlot->iCacheSlot = i;
|
||||
|
||||
m_pSlotList.push_back(pCacheSlot);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int CGlyphCache::ReleaseSlotList()
|
||||
{
|
||||
CCacheSlotListItor pItor = m_pSlotList.begin();
|
||||
|
||||
while (pItor != m_pSlotList.end())
|
||||
{
|
||||
(*pItor)->pGlyphBitmap.Release();
|
||||
|
||||
delete (*pItor);
|
||||
|
||||
pItor = m_pSlotList.erase(pItor);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
CryFont::GlyphCache::CCacheTableKey CGlyphCache::GetCacheSlotKey(uint32 cChar, const Vec2i& glyphSize) const
|
||||
{
|
||||
const Vec2i clampedGlyphSize = CFontTexture::ClampGlyphSize(glyphSize, m_iGlyphBitmapWidth, m_iGlyphBitmapHeight);
|
||||
return CryFont::GlyphCache::CCacheTableKey(clampedGlyphSize, cChar);
|
||||
}
|
||||
|
||||
#endif // #if !defined(USE_NULLFONT_ALWAYS)
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
// Purpose:
|
||||
// - Manage and cache glyphs, retrieving them from the renderer as needed
|
||||
|
||||
#ifndef CRYINCLUDE_CRYFONT_GLYPHCACHE_H
|
||||
#define CRYINCLUDE_CRYFONT_GLYPHCACHE_H
|
||||
#pragma once
|
||||
|
||||
#if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#include <vector>
|
||||
#include "GlyphBitmap.h"
|
||||
#include "FontRenderer.h"
|
||||
#include "CryFont.h"
|
||||
#include <StlUtils.h>
|
||||
|
||||
//! Glyph cache slots store the bitmap buffer and glyph metadata from FreeType.
|
||||
//!
|
||||
//! This bitmap buffer is eventually copied to a CFontTexture texture buffer.
|
||||
//! A glyph cache slot bitmap buffer only holds a single glyph, whereas the
|
||||
//! CFontTexture stores multiple glyphs in a grid (row/col) format.
|
||||
typedef struct CCacheSlot
|
||||
{
|
||||
Vec2i glyphSize = CCryFont::defaultGlyphSize; //!< The render resolution of the glyph in the glyph bitmap
|
||||
unsigned int dwUsage;
|
||||
int iCacheSlot;
|
||||
int iHoriAdvance; //!< Advance width. See FT_Glyph_Metrics::horiAdvance.
|
||||
uint32 cCurrentChar;
|
||||
|
||||
uint8 iCharWidth; //!< Glyph width (in pixel)
|
||||
uint8 iCharHeight; //!< Glyph height (in pixel)
|
||||
AZ::s32 iCharOffsetX; //!< Glyph's left-side bearing (in pixels). See FT_GlyphSlotRec::bitmap_left.
|
||||
AZ::s32 iCharOffsetY; //!< Glyph's top bearing (in pixels). See FT_GlyphSlotRec::bitmap_top.
|
||||
|
||||
CGlyphBitmap pGlyphBitmap; //!< Contains a buffer storing a copy of the glyph from FreeType
|
||||
|
||||
void Reset()
|
||||
{
|
||||
dwUsage = 0;
|
||||
cCurrentChar = ~0;
|
||||
|
||||
iCharWidth = 0;
|
||||
iCharHeight = 0;
|
||||
iCharOffsetX = 0;
|
||||
iCharOffsetY = 0;
|
||||
|
||||
pGlyphBitmap.Clear();
|
||||
}
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(*this));
|
||||
pSizer->AddObject(pGlyphBitmap);
|
||||
}
|
||||
} CCacheSlot;
|
||||
|
||||
namespace CryFont
|
||||
{
|
||||
namespace GlyphCache
|
||||
{
|
||||
//! Height and width pair for glyph size mapping
|
||||
typedef Vec2i CCacheTableGlyphSizeType;
|
||||
|
||||
//! Pair for mapping a height and width size to a UTF32 character/glyph
|
||||
typedef AZStd::pair<CCacheTableGlyphSizeType, uint32> CCacheTableKey;
|
||||
|
||||
//! Hasher for glyph cache table keys (glyphsize-char code pair)
|
||||
//!
|
||||
//! Instead of creating our own custom hash, the types are broken down to their
|
||||
//! native types (ints) and passed to existing hashes that handle those types.
|
||||
struct HashGlyphCacheTableKey
|
||||
{
|
||||
typedef CCacheTableKey ArgumentType;
|
||||
typedef AZStd::size_t ResultType;
|
||||
typedef AZStd::pair<int32, int32> Int32Pair;
|
||||
typedef AZStd::pair<Int32Pair, uint32> Int32PairU32Pair;
|
||||
ResultType operator()(const ArgumentType& value) const
|
||||
{
|
||||
AZStd::hash<Int32PairU32Pair> pairHash;
|
||||
return pairHash(Int32PairU32Pair(Int32Pair(value.first.x, value.first.y), value.second));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//! Maps size-speicifc UTF32 glyphs to their corresponding cache slots
|
||||
typedef AZStd::unordered_map<CryFont::GlyphCache::CCacheTableKey, CCacheSlot*, CryFont::GlyphCache::HashGlyphCacheTableKey> CCacheTable;
|
||||
|
||||
typedef std::vector<CCacheSlot*> CCacheSlotList;
|
||||
typedef std::vector<CCacheSlot*>::iterator CCacheSlotListItor;
|
||||
|
||||
|
||||
#ifdef WIN64
|
||||
#undef GetCharWidth
|
||||
#undef GetCharHeight
|
||||
#endif
|
||||
|
||||
//! The glyph cache maps UTF32 codepoints to their corresponding FreeType data.
|
||||
//!
|
||||
//! This cache is used to associate font glyph info (read from FreeType) with
|
||||
//! UTF32 codepoints. Ultimately the glyph info will be read into a font texture
|
||||
//! (CFontTexture) to avoid future FreeType lookups.
|
||||
//!
|
||||
//! If a CFontTexture is missing a glyph that is currently stored in the glyph
|
||||
//! cache, the cached data can be returned instead of having to be rendered from
|
||||
//! FreeType again.
|
||||
//!
|
||||
//! \sa CFontTexture
|
||||
class CGlyphCache
|
||||
{
|
||||
public:
|
||||
CGlyphCache();
|
||||
~CGlyphCache();
|
||||
|
||||
int Create(int iCacheSize, int iGlyphBitmapWidth, int iGlyphBitmapHeight, int iSmoothMethod, int iSmoothAmount, float sizeRatio);
|
||||
int Release();
|
||||
|
||||
int LoadFontFromFile(const string& szFileName);
|
||||
int LoadFontFromMemory(unsigned char* pFileBuffer, int iDataSize);
|
||||
int ReleaseFont();
|
||||
|
||||
int SetEncoding(FT_Encoding pEncoding) { return m_pFontRenderer.SetEncoding(pEncoding); };
|
||||
FT_Encoding GetEncoding() { return m_pFontRenderer.GetEncoding(); };
|
||||
|
||||
int GetGlyphBitmapSize(int* pWidth, int* pHeight);
|
||||
void SetGlyphBitmapSize(int width, int height, float sizeRatio);
|
||||
|
||||
int PreCacheGlyph(uint32 cChar, const Vec2i& glyphSize = CCryFont::defaultGlyphSize, const CFFont::FontHintParams& glyphFlags = CFFont::FontHintParams());
|
||||
int UnCacheGlyph(uint32 cChar, const Vec2i& glyphSize = CCryFont::defaultGlyphSize);
|
||||
int GlyphCached(uint32 cChar, const Vec2i& glyphSize = CCryFont::defaultGlyphSize);
|
||||
|
||||
CCacheSlot* GetLRUSlot();
|
||||
CCacheSlot* GetMRUSlot();
|
||||
|
||||
//! Obtains glyph information for the given UTF32 codepoint.
|
||||
//! This information is obtained from a CCacheSlot that corresponds to
|
||||
//! the given codepoint. If the codepoint doesn't exist within the cache
|
||||
//! table (m_pCacheTable), then the information is obtain from FreeType
|
||||
//! directly via CFontRenderer.
|
||||
//!
|
||||
//! Ultimately the glyph bitmap is copied into a font texture
|
||||
//! (CFontTexture). Once the glyph is copied into the font texture then
|
||||
//! the font texture is referenced directly rather than relying on the
|
||||
//! glyph cache or FreeType.
|
||||
//!
|
||||
//! \sa CFontRenderer::GetGlyph, CFontTexture::UpdateSlot
|
||||
int GetGlyph(CGlyphBitmap** pGlyph, int* piHoriAdvance, int* piWidth, int* piHeight, AZ::s32& iCharOffsetX, AZ::s32& iCharOffsetY, uint32 cChar, const Vec2i& glyphSize = CCryFont::defaultGlyphSize, const CFFont::FontHintParams& glyphFlags = CFFont::FontHintParams());
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(m_pSlotList);
|
||||
//pSizer->AddContainer(m_pCacheTable);
|
||||
pSizer->AddObject(m_pScaleBitmap);
|
||||
pSizer->AddObject(m_pFontRenderer);
|
||||
}
|
||||
|
||||
bool GetMonospaced() const { return m_pFontRenderer.GetMonospaced(); }
|
||||
|
||||
Vec2 GetKerning(uint32_t leftGlyph, uint32_t rightGlyph);
|
||||
|
||||
float GetAscenderToHeightRatio();
|
||||
|
||||
private:
|
||||
|
||||
//! Returns a key for the cache table where the given char is mapped at the given size.
|
||||
CryFont::GlyphCache::CCacheTableKey GetCacheSlotKey(uint32 cChar, const Vec2i& glyphSize = CCryFont::defaultGlyphSize) const;
|
||||
|
||||
int CreateSlotList(int iListSize);
|
||||
int ReleaseSlotList();
|
||||
|
||||
CCacheSlotList m_pSlotList;
|
||||
CCacheTable m_pCacheTable;
|
||||
|
||||
int m_iGlyphBitmapWidth;
|
||||
int m_iGlyphBitmapHeight;
|
||||
|
||||
int m_iSmoothMethod;
|
||||
int m_iSmoothAmount;
|
||||
|
||||
CGlyphBitmap* m_pScaleBitmap;
|
||||
|
||||
CFontRenderer m_pFontRenderer;
|
||||
|
||||
unsigned int m_dwUsage;
|
||||
};
|
||||
|
||||
#endif // #if !defined(USE_NULLFONT_ALWAYS)
|
||||
|
||||
#endif // CRYINCLUDE_CRYFONT_GLYPHCACHE_H
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Create the font interface.
|
||||
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
|
||||
#include <IEngineModule.h>
|
||||
#include <CryExtension/ICryFactory.h>
|
||||
#include <CryExtension/Impl/ClassWeaver.h>
|
||||
|
||||
#include "CryFont.h"
|
||||
#if defined(USE_NULLFONT)
|
||||
#include "NullFont.h"
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
struct CSystemEventListner_Font
|
||||
: public ISystemEventListener
|
||||
{
|
||||
public:
|
||||
virtual void OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case ESYSTEM_EVENT_LEVEL_POST_UNLOAD:
|
||||
{
|
||||
STLALLOCATOR_CLEANUP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
static CSystemEventListner_Font g_system_event_listener_font;
|
||||
|
||||
///////////////////////////////////////////////
|
||||
extern "C" ICryFont * CreateCryFontInterface(ISystem * pSystem)
|
||||
{
|
||||
ModuleInitISystem(pSystem, "CryFont");
|
||||
|
||||
if (gEnv->IsDedicated())
|
||||
{
|
||||
#if defined(USE_NULLFONT)
|
||||
return new CCryNullFont();
|
||||
#else
|
||||
// The NULL font implementation must be present for all platforms
|
||||
// supporting running as a pure dedicated server.
|
||||
pSystem->GetILog()->LogError("Missing NULL font implementation for dedicated server");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(USE_NULLFONT) && defined(USE_NULLFONT_ALWAYS)
|
||||
return new CCryNullFont();
|
||||
#else
|
||||
pSystem->GetISystemEventDispatcher()->RegisterListener(&g_system_event_listener_font);
|
||||
return new CCryFont(pSystem);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CEngineModule_CryFont
|
||||
: public IEngineModule
|
||||
{
|
||||
CRYINTERFACE_SIMPLE(IEngineModule)
|
||||
CRYGENERATE_SINGLETONCLASS(CEngineModule_CryFont, "EngineModule_CryFont", 0x6758643f43214957, 0x9b920d898d31f434)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual const char* GetName() const {
|
||||
return "CryFont";
|
||||
};
|
||||
virtual const char* GetCategory() const { return "CryEngine"; };
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual bool Initialize(SSystemGlobalEnvironment& env, [[maybe_unused]] const SSystemInitParams& initParams)
|
||||
{
|
||||
ISystem* pSystem = env.pSystem;
|
||||
env.pCryFont = CreateCryFontInterface(pSystem);
|
||||
return env.pCryFont != 0;
|
||||
}
|
||||
};
|
||||
|
||||
CRYREGISTER_SINGLETON_CLASS(CEngineModule_CryFont)
|
||||
|
||||
CEngineModule_CryFont::CEngineModule_CryFont()
|
||||
{
|
||||
};
|
||||
|
||||
CEngineModule_CryFont::~CEngineModule_CryFont()
|
||||
{
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Dummy font implementation (dedicated server)
|
||||
|
||||
#include "CryFont_precompiled.h"
|
||||
|
||||
#if defined(USE_NULLFONT)
|
||||
|
||||
#include "NullFont.h"
|
||||
|
||||
CNullFont CCryNullFont::ms_nullFont;
|
||||
|
||||
#endif // USE_NULLFONT
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Dummy font implementation (dedicated server)
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYFONT_NULLFONT_H
|
||||
#define CRYINCLUDE_CRYFONT_NULLFONT_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#if defined(USE_NULLFONT)
|
||||
|
||||
#include <IFont.h>
|
||||
|
||||
class CNullFont
|
||||
: public IFFont
|
||||
{
|
||||
public:
|
||||
CNullFont() {}
|
||||
virtual ~CNullFont() {}
|
||||
|
||||
virtual int32 AddRef() { return 0; };
|
||||
virtual int32 Release() { return 0; };
|
||||
|
||||
virtual bool Load([[maybe_unused]] const char* pFontFilePath, [[maybe_unused]] unsigned int width, [[maybe_unused]] unsigned int height, [[maybe_unused]] unsigned int widthNumSlots, [[maybe_unused]] unsigned int heightNumSlots, [[maybe_unused]] unsigned int flags, [[maybe_unused]] float sizeRatio) { return true; }
|
||||
virtual bool Load([[maybe_unused]] const char* pXMLFile) { return true; }
|
||||
virtual void Free() {}
|
||||
|
||||
virtual void DrawString([[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] const char* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) {}
|
||||
virtual void DrawString([[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z, [[maybe_unused]] const char* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) {}
|
||||
|
||||
virtual void DrawStringW([[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] const wchar_t* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) {}
|
||||
virtual void DrawStringW([[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z, [[maybe_unused]] const wchar_t* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) {}
|
||||
|
||||
virtual Vec2 GetTextSize([[maybe_unused]] const char* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) { return Vec2(0.0f, 0.0f); }
|
||||
virtual Vec2 GetTextSizeW([[maybe_unused]] const wchar_t* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) { return Vec2(0.0f, 0.0f); }
|
||||
|
||||
virtual size_t GetTextLength([[maybe_unused]] const char* pStr, [[maybe_unused]] const bool asciiMultiLine) const { return 0; }
|
||||
virtual size_t GetTextLengthW([[maybe_unused]] const wchar_t* pStr, [[maybe_unused]] const bool asciiMultiLine) const { return 0; }
|
||||
|
||||
virtual void WrapText(string& result, [[maybe_unused]] float maxWidth, const char* pStr, [[maybe_unused]] const STextDrawContext& ctx) { result = pStr; }
|
||||
virtual void WrapTextW(wstring& result, [[maybe_unused]] float maxWidth, const wchar_t* pStr, [[maybe_unused]] const STextDrawContext& ctx) { result = pStr; }
|
||||
|
||||
virtual void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const {}
|
||||
|
||||
virtual void GetGradientTextureCoord([[maybe_unused]] float& minU, [[maybe_unused]] float& minV, [[maybe_unused]] float& maxU, [[maybe_unused]] float& maxV) const {}
|
||||
|
||||
virtual unsigned int GetEffectId([[maybe_unused]] const char* pEffectName) const { return 0; }
|
||||
virtual unsigned int GetNumEffects() const { return 0; }
|
||||
virtual const char* GetEffectName([[maybe_unused]] unsigned int effectId) const { return nullptr; }
|
||||
virtual Vec2 GetMaxEffectOffset([[maybe_unused]] unsigned int effectId) const { return Vec2(); }
|
||||
virtual bool DoesEffectHaveTransparency([[maybe_unused]] unsigned int effectId) const { return false; }
|
||||
|
||||
virtual void AddCharsToFontTexture([[maybe_unused]] const char* pChars, [[maybe_unused]] int glyphSizeX, [[maybe_unused]] int glyphSizeY) override {}
|
||||
virtual Vec2 GetKerning([[maybe_unused]] uint32_t leftGlyph, [[maybe_unused]] uint32_t rightGlyph, [[maybe_unused]] const STextDrawContext& ctx) const override { return Vec2(); }
|
||||
virtual float GetAscender([[maybe_unused]] const STextDrawContext& ctx) const override { return 0.0f; }
|
||||
virtual float GetBaseline([[maybe_unused]] const STextDrawContext& ctx) const override { return 0.0f; }
|
||||
virtual float GetSizeRatio() const override { return IFFontConstants::defaultSizeRatio; }
|
||||
virtual uint32 GetNumQuadsForText([[maybe_unused]] const char* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) { return 0; }
|
||||
virtual uint32 WriteTextQuadsToBuffers([[maybe_unused]] SVF_P2F_C4B_T2F_F4B* verts, [[maybe_unused]] uint16* indices, [[maybe_unused]] uint32 maxQuads, [[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z, [[maybe_unused]] const char* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) { return 0; }
|
||||
virtual int GetFontTextureId() { return -1; }
|
||||
virtual uint32 GetFontTextureVersion() { return 0; }
|
||||
};
|
||||
|
||||
class CCryNullFont
|
||||
: public ICryFont
|
||||
{
|
||||
public:
|
||||
virtual void Release() {}
|
||||
virtual IFFont* NewFont([[maybe_unused]] const char* pFontName) { return &ms_nullFont; }
|
||||
virtual IFFont* GetFont([[maybe_unused]] const char* pFontName) const { return &ms_nullFont; }
|
||||
virtual FontFamilyPtr LoadFontFamily([[maybe_unused]] const char* pFontFamilyName) override { CRY_ASSERT(false); return nullptr; }
|
||||
virtual FontFamilyPtr GetFontFamily([[maybe_unused]] const char* pFontFamilyName) override { CRY_ASSERT(false); return nullptr; }
|
||||
virtual void AddCharsToFontTextures(FontFamilyPtr pFontFamily, [[maybe_unused]] const char* pChars, [[maybe_unused]] int glyphSizeX, [[maybe_unused]] int glyphSizeY) override {};
|
||||
virtual void SetRendererProperties([[maybe_unused]] IRenderer* pRenderer) {}
|
||||
virtual void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const {}
|
||||
virtual string GetLoadedFontNames() const { return ""; }
|
||||
virtual void OnLanguageChanged() override { }
|
||||
virtual void ReloadAllFonts() override { }
|
||||
|
||||
private:
|
||||
static CNullFont ms_nullFont;
|
||||
};
|
||||
|
||||
#endif // USE_NULLFONT
|
||||
|
||||
#endif // CRYINCLUDE_CRYFONT_NULLFONT_H
|
||||
@@ -1,16 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
# Platform specific cmake file for configuring target compiler/link properties
|
||||
# based on the active platform
|
||||
# NOTE: functions in cmake are global, therefore adding functions to this file
|
||||
# is being avoided to prevent overriding functions declared in other targets platfrom
|
||||
# specific cmake files
|
||||
@@ -1,33 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
CryFont.cpp
|
||||
FFont.cpp
|
||||
FFontXML.cpp
|
||||
FontRenderer.cpp
|
||||
FontTexture.cpp
|
||||
GlyphBitmap.cpp
|
||||
GlyphCache.cpp
|
||||
ICryFont.cpp
|
||||
NullFont.cpp
|
||||
CryFont.h
|
||||
FBitmap.h
|
||||
FFont.h
|
||||
FontRenderer.h
|
||||
FontTexture.h
|
||||
GlyphBitmap.h
|
||||
GlyphCache.h
|
||||
NullFont.h
|
||||
resource.h
|
||||
CryFont_precompiled.h
|
||||
CryFont_precompiled.cpp
|
||||
)
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#define VS_VERSION_INFO 1
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -90,8 +90,6 @@ ly_add_target(
|
||||
AZ::AzCore
|
||||
Legacy::CryCommon
|
||||
Legacy::CryCommon.EngineSettings.Static
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::CryFont
|
||||
)
|
||||
|
||||
################################################################################
|
||||
|
||||
@@ -52,11 +52,7 @@
|
||||
# define cpuid(op, eax, ebx, ecx, edx) __asm__("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (op) : "cc");
|
||||
#endif
|
||||
|
||||
#if defined(AZ_MONOLITHIC_BUILD)
|
||||
extern int g_CpuFlags;
|
||||
#else
|
||||
int g_CpuFlags;
|
||||
#endif
|
||||
|
||||
struct SAutoMaxPriority
|
||||
{
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzFramework/Logging/MissingAssetLogger.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzFramework/API/AtomActiveInterface.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
|
||||
@@ -1162,31 +1161,6 @@ void CSystem::SleepIfInactive()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
if (!AZ::Interface<AzFramework::AtomActiveInterface>::Get())
|
||||
{
|
||||
WIN_HWND hRendWnd = GetIRenderer()->GetHWND();
|
||||
if (!hRendWnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ_TRACE_METHOD();
|
||||
// Loop here waiting for window to be activated.
|
||||
for (int nLoops = 0; nLoops < 5; nLoops++)
|
||||
{
|
||||
WIN_HWND hActiveWnd = ::GetActiveWindow();
|
||||
if (hActiveWnd == hRendWnd)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::PumpSystemEventLoopUntilEmpty);
|
||||
Sleep(5);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -676,17 +676,11 @@ private:
|
||||
//! @name Initialization routines
|
||||
//@{
|
||||
bool InitConsole();
|
||||
bool InitRenderer(WIN_HINSTANCE hinst, WIN_HWND hwnd, const SSystemInitParams& initParams);
|
||||
|
||||
bool InitFont(const SSystemInitParams& initParams);
|
||||
bool InitFileSystem();
|
||||
bool InitFileSystem_LoadEngineFolders(const SSystemInitParams& initParams);
|
||||
bool InitStreamEngine();
|
||||
bool Init3DEngine(const SSystemInitParams& initParams);
|
||||
bool InitAudioSystem(const SSystemInitParams& initParams);
|
||||
bool InitShine(const SSystemInitParams& initParams);
|
||||
bool OpenRenderLibrary(int type, const SSystemInitParams& initParams);
|
||||
bool OpenRenderLibrary(const char* t_rend, const SSystemInitParams& initParams);
|
||||
|
||||
//@}
|
||||
|
||||
@@ -738,9 +732,6 @@ private:
|
||||
bool GetWinGameFolder(char* szMyDocumentsPath, int maxPathSize);
|
||||
#endif
|
||||
|
||||
//! \brief Initializes the given IFFont member variable with the given name (internal use only).
|
||||
bool LoadFontInternal(IFFont*& font, const string& fontName);
|
||||
|
||||
public:
|
||||
void EnableFloatExceptions(int type);
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
#include <StringUtils.h>
|
||||
#include <IThreadManager.h>
|
||||
|
||||
#include "CryFontBus.h"
|
||||
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
|
||||
@@ -70,7 +68,6 @@
|
||||
#include <LyShine/Bus/UiSystemBus.h>
|
||||
#include <AzFramework/Logging/MissingAssetLogger.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
#include <AzFramework/API/AtomActiveInterface.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
@@ -247,24 +244,6 @@ CUNIXConsole* pUnixConsole;
|
||||
|
||||
#define LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME "Libs/Localization/localization.xml"
|
||||
|
||||
#define LOAD_LEGACY_RENDERER_FOR_EDITOR false // If you set this to true you must also set 'ed_useAtomNativeViewport' to false (see /Code/Sandbox/Editor/ViewManager.cpp)
|
||||
#define LOAD_LEGACY_RENDERER_FOR_LAUNCHER false
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Where possible, these are defaults used to initialize cvars
|
||||
// System.cfg can then be used to override them
|
||||
// This includes the Game DLL, although it is loaded elsewhere
|
||||
|
||||
#define DLL_FONT "CryFont"
|
||||
#define DLL_3DENGINE "Cry3DEngine"
|
||||
#define DLL_RENDERER_DX9 "CryRenderD3D9"
|
||||
#define DLL_RENDERER_DX11 "CryRenderD3D11"
|
||||
#define DLL_RENDERER_DX12 "CryRenderD3D12"
|
||||
#define DLL_RENDERER_METAL "CryRenderMetal"
|
||||
#define DLL_RENDERER_GL "CryRenderGL"
|
||||
#define DLL_RENDERER_NULL "CryRenderNULL"
|
||||
#define DLL_SHINE "LyShine"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#if defined(WIN32) || defined(LINUX) || defined(APPLE)
|
||||
# define DLL_MODULE_INIT_ISYSTEM "ModuleInitISystem"
|
||||
@@ -1079,58 +1058,6 @@ void CSystem::ShutdownModuleLibraries()
|
||||
#endif // !defined(AZ_MONOLITHIC_BUILD)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::OpenRenderLibrary([[maybe_unused]] const char* t_rend, const SSystemInitParams& initParams)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION(GetISystem());
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_6
|
||||
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
|
||||
#endif
|
||||
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
|
||||
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
|
||||
#else
|
||||
|
||||
if (gEnv->IsDedicated())
|
||||
{
|
||||
return OpenRenderLibrary(R_NULL_RENDERER, initParams);
|
||||
}
|
||||
|
||||
if (AZ::Interface<AzFramework::AtomActiveInterface>::Get())
|
||||
{
|
||||
return OpenRenderLibrary(R_DX11_RENDERER, initParams);
|
||||
}
|
||||
else if (azstricmp(t_rend, "DX9") == 0)
|
||||
{
|
||||
return OpenRenderLibrary(R_DX9_RENDERER, initParams);
|
||||
}
|
||||
else if (azstricmp(t_rend, "DX11") == 0)
|
||||
{
|
||||
return OpenRenderLibrary(R_DX11_RENDERER, initParams);
|
||||
}
|
||||
else if (azstricmp(t_rend, "DX12") == 0)
|
||||
{
|
||||
return OpenRenderLibrary(R_DX12_RENDERER, initParams);
|
||||
}
|
||||
else if (azstricmp(t_rend, "GL") == 0)
|
||||
{
|
||||
return OpenRenderLibrary(R_GL_RENDERER, initParams);
|
||||
}
|
||||
else if (azstricmp(t_rend, "METAL") == 0)
|
||||
{
|
||||
return OpenRenderLibrary(R_METAL_RENDERER, initParams);
|
||||
}
|
||||
else if (azstricmp(t_rend, "NULL") == 0)
|
||||
{
|
||||
return OpenRenderLibrary(R_NULL_RENDERER, initParams);
|
||||
}
|
||||
|
||||
AZ_Assert(false, "Unknown renderer type: %s", t_rend);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1220,126 +1147,6 @@ wstring GetErrorStringUnsupportedGPU(const char* gpuName, unsigned int gpuVendor
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CSystem::OpenRenderLibrary(int type, const SSystemInitParams& initParams)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
#if defined(WIN32) || defined(WIN64)
|
||||
if (!gEnv->IsDedicated())
|
||||
{
|
||||
unsigned int gpuVendorId = 0, gpuDeviceId = 0, totVidMem = 0;
|
||||
char gpuName[256];
|
||||
Win32SysInspect::DXFeatureLevel featureLevel = Win32SysInspect::DXFL_Undefined;
|
||||
Win32SysInspect::GetGPUInfo(gpuName, sizeof(gpuName), gpuVendorId, gpuDeviceId, totVidMem, featureLevel);
|
||||
|
||||
if (m_env.IsEditor())
|
||||
{
|
||||
#if defined(EXTERNAL_CRASH_REPORTING)
|
||||
CrashHandler::CrashHandlerBase::AddAnnotation("dx.feature.level", Win32SysInspect::GetFeatureLevelAsString(featureLevel));
|
||||
CrashHandler::CrashHandlerBase::AddAnnotation("gpu.name", gpuName);
|
||||
CrashHandler::CrashHandlerBase::AddAnnotation("gpu.vendorId", std::to_string(gpuVendorId));
|
||||
CrashHandler::CrashHandlerBase::AddAnnotation("gpu.deviceId", std::to_string(gpuDeviceId));
|
||||
CrashHandler::CrashHandlerBase::AddAnnotation("gpu.memory", std::to_string(totVidMem));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (featureLevel < Win32SysInspect::DXFL_11_0)
|
||||
{
|
||||
const char logMsgFmt[] ("Unsupported GPU configuration!\n- %s (vendor = 0x%.4x, device = 0x%.4x)\n- Dedicated video memory: %d MB\n- Feature level: %s\n");
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, logMsgFmt, gpuName, gpuVendorId, gpuDeviceId, totVidMem >> 20, GetFeatureLevelAsString(featureLevel));
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
const bool allowPrompts = m_env.pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "noprompt") == 0;
|
||||
#else
|
||||
const bool allowPrompts = true;
|
||||
#endif // !defined(_RELEASE)
|
||||
if (allowPrompts)
|
||||
{
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Asking user if they wish to continue...");
|
||||
const int mbRes = MessageBoxW(0, GetErrorStringUnsupportedGPU(gpuName, gpuVendorId, gpuDeviceId).c_str(), L"Open 3D Engine", MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2 | MB_DEFAULT_DESKTOP_ONLY);
|
||||
if (mbRes == IDCANCEL)
|
||||
{
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "User chose to cancel startup due to unsupported GPU.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !defined(_RELEASE)
|
||||
const bool obeyGPUCheck = m_env.pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "anygpu") == 0;
|
||||
#else
|
||||
const bool obeyGPUCheck = true;
|
||||
#endif // !defined(_RELEASE)
|
||||
if (obeyGPUCheck)
|
||||
{
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "No prompts allowed and unsupported GPU check active. Treating unsupported GPU as error and exiting.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "User chose to continue despite unsupported GPU!");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_7
|
||||
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
|
||||
#endif
|
||||
|
||||
if (gEnv->IsDedicated())
|
||||
{
|
||||
type = R_NULL_RENDERER;
|
||||
}
|
||||
const char* libname = "";
|
||||
if (AZ::Interface<AzFramework::AtomActiveInterface>::Get())
|
||||
{
|
||||
libname = DLL_RENDERER_NULL;
|
||||
}
|
||||
else if (type == R_DX9_RENDERER)
|
||||
{
|
||||
libname = DLL_RENDERER_DX9;
|
||||
}
|
||||
else if (type == R_DX11_RENDERER)
|
||||
{
|
||||
libname = DLL_RENDERER_DX11;
|
||||
}
|
||||
else if (type == R_DX12_RENDERER)
|
||||
{
|
||||
libname = DLL_RENDERER_DX12;
|
||||
}
|
||||
else if (type == R_NULL_RENDERER)
|
||||
{
|
||||
libname = DLL_RENDERER_NULL;
|
||||
}
|
||||
else if (type == R_GL_RENDERER)
|
||||
{
|
||||
libname = DLL_RENDERER_GL;
|
||||
}
|
||||
else if (type == R_METAL_RENDERER)
|
||||
{
|
||||
libname = DLL_RENDERER_METAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Renderer did not initialize correctly; no valid renderer specified.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InitializeEngineModule(libname, "EngineModule_CryRenderer", initParams))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_env.pRenderer)
|
||||
{
|
||||
AZ_Assert(false, "Renderer did not initialize correctly; it could not be found in the system environment.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::InitConsole()
|
||||
@@ -1391,123 +1198,6 @@ ICVar* CSystem::attachVariable (const char* szVarName, int* pContainer, const ch
|
||||
return pVar;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::InitRenderer(WIN_HINSTANCE hinst, WIN_HWND hwnd, const SSystemInitParams& initParams)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION(GetISystem());
|
||||
|
||||
if (m_pUserCallback)
|
||||
{
|
||||
m_pUserCallback->OnInitProgress("Initializing Renderer...");
|
||||
}
|
||||
|
||||
if (m_bEditor)
|
||||
{
|
||||
m_env.pConsole->GetCVar("r_Width");
|
||||
|
||||
// save current screen width/height/bpp, so they can be restored on shutdown
|
||||
m_iWidth = m_env.pConsole->GetCVar("r_Width")->GetIVal();
|
||||
m_iHeight = m_env.pConsole->GetCVar("r_Height")->GetIVal();
|
||||
m_iColorBits = m_env.pConsole->GetCVar("r_ColorBits")->GetIVal();
|
||||
}
|
||||
|
||||
if (!OpenRenderLibrary(m_rDriver->GetString(), initParams))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(AZ_PLATFORM_IOS) || defined(AZ_PLATFORM_ANDROID)
|
||||
if (m_rWidthAndHeightAsFractionOfScreenSize->GetFlags() & VF_WASINCONFIG)
|
||||
{
|
||||
int displayWidth = 0;
|
||||
int displayHeight = 0;
|
||||
if (GetPrimaryPhysicalDisplayDimensions(displayWidth, displayHeight))
|
||||
{
|
||||
// Ideally we would probably want to clamp this at the source,
|
||||
// but I don't believe cvars support specifying a valid range.
|
||||
float scaleFactor = 1.0f;
|
||||
|
||||
if(IsTablet())
|
||||
{
|
||||
scaleFactor = AZ::GetClamp(m_rTabletWidthAndHeightAsFractionOfScreenSize->GetFVal(), 0.1f, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
scaleFactor = AZ::GetClamp(m_rWidthAndHeightAsFractionOfScreenSize->GetFVal(), 0.1f, 1.0f);
|
||||
}
|
||||
|
||||
displayWidth *= scaleFactor;
|
||||
displayHeight *= scaleFactor;
|
||||
|
||||
const int maxWidth = m_rMaxWidth->GetIVal();
|
||||
if (maxWidth > 0 && maxWidth < displayWidth)
|
||||
{
|
||||
const float widthScaleFactor = static_cast<float>(maxWidth) / static_cast<float>(displayWidth);
|
||||
displayWidth *= widthScaleFactor;
|
||||
displayHeight *= widthScaleFactor;
|
||||
}
|
||||
|
||||
const int maxHeight = m_rMaxHeight->GetIVal();
|
||||
if (maxHeight > 0 && maxHeight < displayHeight)
|
||||
{
|
||||
const float heightScaleFactor = static_cast<float>(maxHeight) / static_cast<float>(displayHeight);
|
||||
displayWidth *= heightScaleFactor;
|
||||
displayHeight *= heightScaleFactor;
|
||||
}
|
||||
|
||||
m_rWidth->Set(displayWidth);
|
||||
m_rHeight->Set(displayHeight);
|
||||
}
|
||||
}
|
||||
#endif // defined(AZ_PLATFORM_IOS) || defined(AZ_PLATFORM_ANDROID)
|
||||
|
||||
if (m_env.pRenderer)
|
||||
{
|
||||
// This is crucial as textures suffix are hard coded to context and we need to initialize
|
||||
// the texture semantics to look it up.
|
||||
m_env.pRenderer->InitTexturesSemantics();
|
||||
|
||||
#ifdef WIN32
|
||||
SCustomRenderInitArgs args;
|
||||
args.appStartedFromMediaCenter = strstr(initParams.szSystemCmdLine, "ReLaunchMediaCenter") != 0;
|
||||
|
||||
m_hWnd = m_env.pRenderer->Init(0, 0, m_rWidth->GetIVal(), m_rHeight->GetIVal(), m_rColorBits->GetIVal(), m_rDepthBits->GetIVal(), m_rStencilBits->GetIVal(), m_rFullscreen->GetIVal() ? true : false, initParams.bEditor, hinst, hwnd, false, &args, initParams.bShaderCacheGen);
|
||||
//Timur, Not very clean code, we need to push new hwnd value to the system init params, so other modules can used when initializing.
|
||||
(const_cast<SSystemInitParams*>(&initParams))->hWnd = m_hWnd;
|
||||
|
||||
|
||||
bool retVal = (initParams.bShaderCacheGen || m_hWnd != 0);
|
||||
AZ_Assert(retVal, "Renderer failed to initialize correctly.");
|
||||
return retVal;
|
||||
#else // WIN32
|
||||
WIN_HWND h = m_env.pRenderer->Init(0, 0, m_rWidth->GetIVal(), m_rHeight->GetIVal(), m_rColorBits->GetIVal(), m_rDepthBits->GetIVal(), m_rStencilBits->GetIVal(), m_rFullscreen->GetIVal() ? true : false, initParams.bEditor, hinst, hwnd, false, nullptr, initParams.bShaderCacheGen);
|
||||
|
||||
#if (defined(LINUX) && !defined(AZ_PLATFORM_ANDROID))
|
||||
return true;
|
||||
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
|
||||
#elif defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_8
|
||||
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
|
||||
#endif
|
||||
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
|
||||
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
|
||||
#else
|
||||
bool retVal = (initParams.bShaderCacheGen || h != 0);
|
||||
if (retVal)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ_Assert(false, "Renderer failed to initialize correctly.");
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::InitFileSystem()
|
||||
{
|
||||
@@ -1662,68 +1352,6 @@ bool CSystem::InitStreamEngine()
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::InitFont(const SSystemInitParams& initParams)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION(GetISystem());
|
||||
|
||||
bool fontInited = false;
|
||||
AZ::CryFontCreationRequestBus::BroadcastResult(fontInited, &AZ::CryFontCreationRequests::CreateCryFont, m_env, initParams);
|
||||
if (!fontInited && !InitializeEngineModule(DLL_FONT, "EngineModule_CryFont", initParams))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_env.pCryFont)
|
||||
{
|
||||
AZ_Assert(false, "Font System did not initialize correctly; it could not be found in the system environment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gEnv->IsDedicated())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!LoadFontInternal(m_pIFont, "default"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LoadFontInternal(m_pIFontUi, "default-ui"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::Init3DEngine(const SSystemInitParams& initParams)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION(GetISystem());
|
||||
|
||||
if (!InitializeEngineModule(DLL_3DENGINE, "EngineModule_Cry3DEngine", initParams))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_env.p3DEngine)
|
||||
{
|
||||
AZ_Assert(false, "3D Engine did not initialize correctly; it could not be found in the system environment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_env.p3DEngine->Init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_pProcess = m_env.p3DEngine;
|
||||
m_pProcess->SetFlags(PROC_3DENGINE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::InitAudioSystem(const SSystemInitParams& initParams)
|
||||
{
|
||||
@@ -2785,42 +2413,6 @@ AZ_POP_DISABLE_WARNING
|
||||
}
|
||||
InlineInitializationProcessing("CSystem::Init InitLocalizations");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// RENDERER
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const bool loadLegacyRenderer = gEnv->IsEditor() ?
|
||||
LOAD_LEGACY_RENDERER_FOR_EDITOR :
|
||||
LOAD_LEGACY_RENDERER_FOR_LAUNCHER;
|
||||
if (loadLegacyRenderer && !startupParams.bSkipRenderer)
|
||||
{
|
||||
AZ_Assert(CryMemory::IsHeapValid(), "CryMemory must be valid before initializing renderer.");
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Renderer initialization");
|
||||
|
||||
if (!InitRenderer(m_hInst, m_hWnd, startupParams))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
AZ_Assert(CryMemory::IsHeapValid(), "CryMemory must be valid after initializing renderer.");
|
||||
if (m_env.pRenderer)
|
||||
{
|
||||
bool bMultiGPUEnabled = false;
|
||||
m_env.pRenderer->EF_Query(EFQ_MultiGPUEnabled, bMultiGPUEnabled);
|
||||
if (bMultiGPUEnabled)
|
||||
{
|
||||
LoadConfiguration("mgpu.cfg");
|
||||
}
|
||||
}
|
||||
|
||||
InlineInitializationProcessing("CSystem::Init InitRenderer");
|
||||
|
||||
if (m_env.pCryFont)
|
||||
{
|
||||
m_env.pCryFont->SetRendererProperties(m_env.pRenderer);
|
||||
}
|
||||
|
||||
AZ_Assert(m_env.pRenderer || startupParams.bSkipRenderer, "The renderer did not initialize correctly.");
|
||||
}
|
||||
|
||||
#if !defined(AZ_RELEASE_BUILD) && defined(AZ_PLATFORM_ANDROID)
|
||||
m_thermalInfoHandler = AZStd::make_unique<ThermalInfoAndroidHandler>();
|
||||
#endif
|
||||
@@ -2869,21 +2461,6 @@ AZ_POP_DISABLE_WARNING
|
||||
|
||||
m_env.pRenderer->SetViewport(0, 0, screenWidth, screenHeight);
|
||||
|
||||
// Skip splash screen rendering
|
||||
if (!AZ::Interface<AzFramework::AtomActiveInterface>::Get())
|
||||
{
|
||||
// make sure it's rendered in full screen mode when triple buffering is enabled as well
|
||||
for (size_t n = 0; n < 3; n++)
|
||||
{
|
||||
m_env.pRenderer->BeginFrame();
|
||||
m_env.pRenderer->SetCullMode(R_CULL_NONE);
|
||||
m_env.pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST);
|
||||
m_env.pRenderer->Draw2dImageStretchMode(true);
|
||||
m_env.pRenderer->Draw2dImage(x * vx, y * vy, w * vx, h * vy, pTex->GetTextureID(), 0.0f, 1.0f, 1.0f, 0.0f);
|
||||
m_env.pRenderer->Draw2dImageStretchMode(false);
|
||||
m_env.pRenderer->EndFrame();
|
||||
}
|
||||
}
|
||||
#if defined(AZ_PLATFORM_IOS) || defined(AZ_PLATFORM_MAC)
|
||||
// Pump system events in order to update the screen
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::PumpSystemEventLoopUntilEmpty);
|
||||
@@ -2928,24 +2505,10 @@ AZ_POP_DISABLE_WARNING
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// FONT
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
if (!startupParams.bSkipFont)
|
||||
{
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Font initialization");
|
||||
if (!InitFont(startupParams))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
InlineInitializationProcessing("CSystem::Init InitFonts");
|
||||
|
||||
// The last update to the loading screen message was 'Initializing CryFont...'
|
||||
// Compiling the default system textures can be the lengthiest portion of
|
||||
// editor initialization, so it is useful to inform users that they are waiting on
|
||||
// the necessary default textures to compile, and that they are not waiting on CryFont.
|
||||
// the necessary default textures to compile.
|
||||
if (m_pUserCallback)
|
||||
{
|
||||
m_pUserCallback->OnInitProgress("First time asset processing - may take a minute...");
|
||||
@@ -3040,28 +2603,6 @@ AZ_POP_DISABLE_WARNING
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Init 3d engine
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
if (loadLegacyRenderer && !startupParams.bSkipRenderer && !startupParams.bShaderCacheGen)
|
||||
{
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Initializing 3D Engine");
|
||||
INDENT_LOG_DURING_SCOPE();
|
||||
|
||||
if (!Init3DEngine(startupParams))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// try flush to keep renderer busy
|
||||
if (m_env.pRenderer)
|
||||
{
|
||||
m_env.pRenderer->TryFlush();
|
||||
}
|
||||
|
||||
InlineInitializationProcessing("CSystem::Init Init3DEngine");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SERVICE NETWORK
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -4223,24 +3764,3 @@ void CSystem::SetAssertVisible(bool bAssertVisble)
|
||||
{
|
||||
m_bIsAsserting = bAssertVisble;
|
||||
}
|
||||
|
||||
bool CSystem::LoadFontInternal(IFFont*& font, const string& fontName)
|
||||
{
|
||||
font = m_env.pCryFont->NewFont(fontName);
|
||||
if (!font)
|
||||
{
|
||||
AZ_Assert(false, "Could not instantiate the default font.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
string szFontPath = "Fonts/" + fontName + ".font";
|
||||
|
||||
if (!font->Load(szFontPath.c_str()))
|
||||
{
|
||||
AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, "Could not load font: %s. Make sure the program is running from the correct working directory.", szFontPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -239,8 +239,13 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
|
||||
CheckReady();
|
||||
m_initComplete = true;
|
||||
|
||||
// *After* setting initComplete to true, check to see if the assets are already ready.
|
||||
// This check needs to wait until after setting initComplete because if they *are* ready, we want the final call to
|
||||
// RemoveWaitingAsset to trigger the OnAssetContainerReady/Canceled event. If we call CheckReady() *before* setting
|
||||
// initComplete, if all the assets are ready, the event will never get triggered.
|
||||
CheckReady();
|
||||
}
|
||||
|
||||
bool AssetContainer::IsReady() const
|
||||
|
||||
@@ -142,27 +142,44 @@ namespace AZ
|
||||
void SetBasis(const Vector3& basisX, const Vector3& basisY, const Vector3& basisZ);
|
||||
//! @}
|
||||
|
||||
Matrix3x3 operator*(const Matrix3x3& rhs) const;
|
||||
|
||||
//! Calculates (this->GetTranspose() * rhs).
|
||||
Matrix3x3 TransposedMultiply(const Matrix3x3& rhs) const;
|
||||
|
||||
//! Post-multiplies the matrix by a vector.
|
||||
Vector3 operator*(const Vector3& rhs) const;
|
||||
|
||||
Matrix3x3 operator+(const Matrix3x3& rhs) const;
|
||||
Matrix3x3 operator-(const Matrix3x3& rhs) const;
|
||||
|
||||
Matrix3x3 operator*(float multiplier) const;
|
||||
Matrix3x3 operator/(float divisor) const;
|
||||
|
||||
Matrix3x3 operator-() const;
|
||||
|
||||
Matrix3x3& operator*=(const Matrix3x3& rhs);
|
||||
//! Operator for matrix-matrix addition.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator+(const Matrix3x3& rhs) const;
|
||||
Matrix3x3& operator+=(const Matrix3x3& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for matrix-matrix substraction.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator-(const Matrix3x3& rhs) const;
|
||||
Matrix3x3& operator-=(const Matrix3x3& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for matrix-matrix multiplication.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator*(const Matrix3x3& rhs) const;
|
||||
Matrix3x3& operator*=(const Matrix3x3& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for multiplying all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator*(float multiplier) const;
|
||||
Matrix3x3& operator*=(float multiplier);
|
||||
//! @}
|
||||
|
||||
//! Operator for dividing all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator/(float divisor) const;
|
||||
Matrix3x3& operator/=(float divisor);
|
||||
//! @}
|
||||
|
||||
//! Operator for negating all matrix's elements
|
||||
[[nodiscard]] Matrix3x3 operator-() const;
|
||||
|
||||
bool operator==(const Matrix3x3& rhs) const;
|
||||
bool operator!=(const Matrix3x3& rhs) const;
|
||||
@@ -187,7 +204,10 @@ namespace AZ
|
||||
//! @}
|
||||
|
||||
//! Gets the scale part of the transformation, i.e. the length of the scale components.
|
||||
Vector3 RetrieveScale() const;
|
||||
[[nodiscard]] Vector3 RetrieveScale() const;
|
||||
|
||||
//! Gets the squared scale part of the transformation (the squared length of the basis vectors).
|
||||
[[nodiscard]] Vector3 RetrieveScaleSq() const;
|
||||
|
||||
//! Gets the scale part of the transformation as in RetrieveScale, and also removes this scaling from the matrix.
|
||||
Vector3 ExtractScale();
|
||||
@@ -195,6 +215,9 @@ namespace AZ
|
||||
//! Quick multiplication by a scale matrix, equivalent to m*=Matrix3x3::CreateScale(scale).
|
||||
void MultiplyByScale(const Vector3& scale);
|
||||
|
||||
//! Returns a matrix with the reciprocal scale, keeping the same rotation and translation.
|
||||
[[nodiscard]] Matrix3x3 GetReciprocalScaled() const;
|
||||
|
||||
//! Polar decomposition, M=U*H, U is orthogonal (unitary) and H is symmetric (hermitian).
|
||||
//! This function returns the orthogonal part only
|
||||
Matrix3x3 GetPolarDecomposition() const;
|
||||
@@ -241,7 +264,9 @@ namespace AZ
|
||||
//! Note that this is not the usual multiplication order for transformations.
|
||||
Vector3& operator*=(Vector3& lhs, const Matrix3x3& rhs);
|
||||
|
||||
//! Pre-multiplies the matrix by a scalar.
|
||||
Matrix3x3 operator*(float lhs, const Matrix3x3& rhs);
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
#include <AzCore/Math/Matrix3x3.inl>
|
||||
|
||||
@@ -392,14 +392,6 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator*(const Matrix3x3& rhs) const
|
||||
{
|
||||
Matrix3x3 result;
|
||||
Simd::Vec3::Mat3x3Multiply(GetSimdValues(), rhs.GetSimdValues(), result.GetSimdValues());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::TransposedMultiply(const Matrix3x3& rhs) const
|
||||
{
|
||||
Matrix3x3 result;
|
||||
@@ -416,51 +408,12 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator+(const Matrix3x3& rhs) const
|
||||
{
|
||||
return Matrix3x3(Simd::Vec3::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
, Simd::Vec3::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue())
|
||||
, Simd::Vec3::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator-(const Matrix3x3& rhs) const
|
||||
{
|
||||
return Matrix3x3(Simd::Vec3::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
, Simd::Vec3::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue())
|
||||
, Simd::Vec3::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator*(float multiplier) const
|
||||
{
|
||||
const Simd::Vec3::FloatType mulVec = Simd::Vec3::Splat(multiplier);
|
||||
return Matrix3x3(Simd::Vec3::Mul(m_rows[0].GetSimdValue(), mulVec)
|
||||
, Simd::Vec3::Mul(m_rows[1].GetSimdValue(), mulVec)
|
||||
, Simd::Vec3::Mul(m_rows[2].GetSimdValue(), mulVec));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator/(float divisor) const
|
||||
{
|
||||
const Simd::Vec3::FloatType divVec = Simd::Vec3::Splat(divisor);
|
||||
return Matrix3x3(Simd::Vec3::Div(m_rows[0].GetSimdValue(), divVec)
|
||||
, Simd::Vec3::Div(m_rows[1].GetSimdValue(), divVec)
|
||||
, Simd::Vec3::Div(m_rows[2].GetSimdValue(), divVec));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator-() const
|
||||
{
|
||||
const Simd::Vec3::FloatType zeroVec = Simd::Vec3::ZeroFloat();
|
||||
return Matrix3x3(Simd::Vec3::Sub(zeroVec, m_rows[0].GetSimdValue())
|
||||
, Simd::Vec3::Sub(zeroVec, m_rows[1].GetSimdValue())
|
||||
, Simd::Vec3::Sub(zeroVec, m_rows[2].GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator*=(const Matrix3x3& rhs)
|
||||
{
|
||||
*this = *this * rhs;
|
||||
return *this;
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec3::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec3::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -471,6 +424,17 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator-(const Matrix3x3& rhs) const
|
||||
{
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec3::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec3::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator-=(const Matrix3x3& rhs)
|
||||
{
|
||||
*this = *this - rhs;
|
||||
@@ -478,6 +442,33 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator*(const Matrix3x3& rhs) const
|
||||
{
|
||||
Matrix3x3 result;
|
||||
Simd::Vec3::Mat3x3Multiply(GetSimdValues(), rhs.GetSimdValues(), result.GetSimdValues());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator*=(const Matrix3x3& rhs)
|
||||
{
|
||||
*this = *this * rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator*(float multiplier) const
|
||||
{
|
||||
const Simd::Vec3::FloatType mulVec = Simd::Vec3::Splat(multiplier);
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Mul(m_rows[0].GetSimdValue(), mulVec),
|
||||
Simd::Vec3::Mul(m_rows[1].GetSimdValue(), mulVec),
|
||||
Simd::Vec3::Mul(m_rows[2].GetSimdValue(), mulVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator*=(float multiplier)
|
||||
{
|
||||
*this = *this * multiplier;
|
||||
@@ -485,6 +476,18 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator/(float divisor) const
|
||||
{
|
||||
const Simd::Vec3::FloatType divVec = Simd::Vec3::Splat(divisor);
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Div(m_rows[0].GetSimdValue(), divVec),
|
||||
Simd::Vec3::Div(m_rows[1].GetSimdValue(), divVec),
|
||||
Simd::Vec3::Div(m_rows[2].GetSimdValue(), divVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator/=(float divisor)
|
||||
{
|
||||
*this = *this / divisor;
|
||||
@@ -492,6 +495,18 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator-() const
|
||||
{
|
||||
const Simd::Vec3::FloatType zeroVec = Simd::Vec3::ZeroFloat();
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Sub(zeroVec, m_rows[0].GetSimdValue()),
|
||||
Simd::Vec3::Sub(zeroVec, m_rows[1].GetSimdValue()),
|
||||
Simd::Vec3::Sub(zeroVec, m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE bool Matrix3x3::operator==(const Matrix3x3& rhs) const
|
||||
{
|
||||
return (Simd::Vec3::CmpAllEq(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
@@ -552,6 +567,12 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x3::RetrieveScaleSq() const
|
||||
{
|
||||
return Vector3(GetBasisX().GetLengthSq(), GetBasisY().GetLengthSq(), GetBasisZ().GetLengthSq());
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x3::ExtractScale()
|
||||
{
|
||||
const Vector3 x = GetBasisX();
|
||||
@@ -584,6 +605,14 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::GetReciprocalScaled() const
|
||||
{
|
||||
Matrix3x3 result = *this;
|
||||
result.MultiplyByScale(RetrieveScaleSq().GetReciprocal());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Matrix3x3::GetPolarDecomposition(Matrix3x3* orthogonalOut, Matrix3x3* symmetricOut) const
|
||||
{
|
||||
*orthogonalOut = GetPolarDecomposition();
|
||||
@@ -679,8 +708,6 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 operator*(float lhs, const Matrix3x3& rhs)
|
||||
{
|
||||
const Simd::Vec3::FloatType lhsVec = Simd::Vec3::Splat(lhs);
|
||||
const Simd::Vec3::FloatType* rows = rhs.GetSimdValues();
|
||||
return Matrix3x3(Simd::Vec3::Mul(lhsVec, rows[0]), Simd::Vec3::Mul(lhsVec, rows[1]), Simd::Vec3::Mul(lhsVec, rows[2]));
|
||||
return rhs * lhs;
|
||||
}
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -225,11 +225,38 @@ namespace AZ
|
||||
//! Sets the three basis vectors and the translation.
|
||||
void SetBasisAndTranslation(const Vector3& basisX, const Vector3& basisY, const Vector3& basisZ, const Vector3& translation);
|
||||
|
||||
//! Operator for matrix-matrix multiplication.
|
||||
[[nodiscard]] Matrix3x4 operator*(const Matrix3x4& rhs) const;
|
||||
//! Operator for matrix-matrix addition.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator+(const Matrix3x4& rhs) const;
|
||||
Matrix3x4& operator+=(const Matrix3x4& rhs);
|
||||
//! @}
|
||||
|
||||
//! Compound assignment operator for matrix-matrix multiplication.
|
||||
//! Operator for matrix-matrix substraction.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator-(const Matrix3x4& rhs) const;
|
||||
Matrix3x4& operator-=(const Matrix3x4& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for matrix-matrix multiplication.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator*(const Matrix3x4& rhs) const;
|
||||
Matrix3x4& operator*=(const Matrix3x4& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for multiplying all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator*(float multiplier) const;
|
||||
Matrix3x4& operator*=(float multiplier);
|
||||
//! @}
|
||||
|
||||
//! Operator for dividing all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator/(float divisor) const;
|
||||
Matrix3x4& operator/=(float divisor);
|
||||
//! @}
|
||||
|
||||
//! Operator for negating all matrix's elements
|
||||
[[nodiscard]] Matrix3x4 operator-() const;
|
||||
|
||||
//! Operator for transforming a Vector3.
|
||||
[[nodiscard]] Vector3 operator*(const Vector3& rhs) const;
|
||||
@@ -274,12 +301,18 @@ namespace AZ
|
||||
//! Gets the scale part of the transformation (the length of the basis vectors).
|
||||
[[nodiscard]] Vector3 RetrieveScale() const;
|
||||
|
||||
//! Gets the squared scale part of the transformation (the squared length of the basis vectors).
|
||||
[[nodiscard]] Vector3 RetrieveScaleSq() const;
|
||||
|
||||
//! Gets the scale part of the transformation as in RetrieveScale, and also removes this scaling from the matrix.
|
||||
Vector3 ExtractScale();
|
||||
|
||||
//! Multiplies the basis vectors of the matrix by the elements of the scale specified.
|
||||
void MultiplyByScale(const Vector3& scale);
|
||||
|
||||
//! Returns a matrix with the reciprocal scale, keeping the same rotation and translation.
|
||||
[[nodiscard]] Matrix3x4 GetReciprocalScaled() const;
|
||||
|
||||
//! Tests if the 3x3 part of the matrix is orthogonal.
|
||||
bool IsOrthogonal(float tolerance = Constants::Tolerance) const;
|
||||
|
||||
@@ -335,6 +368,10 @@ namespace AZ
|
||||
|
||||
Vector4 m_rows[RowCount];
|
||||
};
|
||||
|
||||
//! Pre-multiplies the matrix by a scalar.
|
||||
Matrix3x4 operator*(float lhs, const Matrix3x4& rhs);
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
#include <AzCore/Math/Matrix3x4.inl>
|
||||
|
||||
@@ -472,6 +472,42 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator+(const Matrix3x4& rhs) const
|
||||
{
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4& Matrix3x4::operator+=(const Matrix3x4& rhs)
|
||||
{
|
||||
*this = *this + rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator-(const Matrix3x4& rhs) const
|
||||
{
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4& Matrix3x4::operator-=(const Matrix3x4& rhs)
|
||||
{
|
||||
*this = *this - rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator*(const Matrix3x4& rhs) const
|
||||
{
|
||||
Matrix3x4 result;
|
||||
@@ -487,6 +523,56 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator*(float multiplier) const
|
||||
{
|
||||
const Simd::Vec4::FloatType mulVec = Simd::Vec4::Splat(multiplier);
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Mul(m_rows[0].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[1].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[2].GetSimdValue(), mulVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4& Matrix3x4::operator*=(float multiplier)
|
||||
{
|
||||
*this = *this * multiplier;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator/(float divisor) const
|
||||
{
|
||||
const Simd::Vec4::FloatType divVec = Simd::Vec4::Splat(divisor);
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Div(m_rows[0].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[1].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[2].GetSimdValue(), divVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4& Matrix3x4::operator/=(float divisor)
|
||||
{
|
||||
*this = *this / divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator-() const
|
||||
{
|
||||
const Simd::Vec4::FloatType zeroVec = Simd::Vec4::ZeroFloat();
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x4::operator*(const Vector3& rhs) const
|
||||
{
|
||||
return Vector3
|
||||
@@ -583,6 +669,12 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x4::RetrieveScaleSq() const
|
||||
{
|
||||
return Vector3(GetColumn(0).GetLengthSq(), GetColumn(1).GetLengthSq(), GetColumn(2).GetLengthSq());
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x4::ExtractScale()
|
||||
{
|
||||
const Vector3 scale = RetrieveScale();
|
||||
@@ -600,6 +692,14 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::GetReciprocalScaled() const
|
||||
{
|
||||
Matrix3x4 result = *this;
|
||||
result.MultiplyByScale(RetrieveScaleSq().GetReciprocal());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Matrix3x4::Orthogonalize()
|
||||
{
|
||||
*this = GetOrthogonalized();
|
||||
@@ -660,4 +760,10 @@ namespace AZ
|
||||
{
|
||||
return reinterpret_cast<Simd::Vec4::FloatType*>(m_rows);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 operator*(float lhs, const Matrix3x4& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -171,14 +171,38 @@ namespace AZ
|
||||
void SetTranslation(const Vector3& v);
|
||||
//! @}
|
||||
|
||||
Matrix4x4 operator+(const Matrix4x4& rhs) const;
|
||||
//! Operator for matrix-matrix addition.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator+(const Matrix4x4& rhs) const;
|
||||
Matrix4x4& operator+=(const Matrix4x4& rhs);
|
||||
//! @}
|
||||
|
||||
Matrix4x4 operator-(const Matrix4x4& rhs) const;
|
||||
//! Operator for matrix-matrix substraction.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator-(const Matrix4x4& rhs) const;
|
||||
Matrix4x4& operator-=(const Matrix4x4& rhs);
|
||||
//! @}
|
||||
|
||||
Matrix4x4 operator*(const Matrix4x4& rhs) const;
|
||||
//! Operator for matrix-matrix multiplication.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator*(const Matrix4x4& rhs) const;
|
||||
Matrix4x4& operator*=(const Matrix4x4& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for multiplying all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator*(float multiplier) const;
|
||||
Matrix4x4& operator*=(float multiplier);
|
||||
//! @}
|
||||
|
||||
//! Operator for dividing all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator/(float divisor) const;
|
||||
Matrix4x4& operator/=(float divisor);
|
||||
//! @}
|
||||
|
||||
//! Operator for negating all matrix's elements
|
||||
[[nodiscard]] Matrix4x4 operator-() const;
|
||||
|
||||
//! Post-multiplies the matrix by a vector.
|
||||
//! Assumes that the w-component of the Vector3 is 1.0.
|
||||
@@ -222,7 +246,10 @@ namespace AZ
|
||||
//! @}
|
||||
|
||||
//! Gets the scale part of the transformation, i.e. the length of the scale components.
|
||||
Vector3 RetrieveScale() const;
|
||||
[[nodiscard]] Vector3 RetrieveScale() const;
|
||||
|
||||
//! Gets the squared scale part of the transformation (the squared length of the basis vectors).
|
||||
[[nodiscard]] Vector3 RetrieveScaleSq() const;
|
||||
|
||||
//! Gets the scale part of the transformation as in RetrieveScale, and also removes this scaling from the matrix.
|
||||
Vector3 ExtractScale();
|
||||
@@ -230,6 +257,9 @@ namespace AZ
|
||||
//! Quick multiplication by a scale matrix, equivalent to m*=Matrix4x4::CreateScale(scale).
|
||||
void MultiplyByScale(const Vector3& scale);
|
||||
|
||||
//! Returns a matrix with the reciprocal scale, keeping the same rotation and translation.
|
||||
[[nodiscard]] Matrix4x4 GetReciprocalScaled() const;
|
||||
|
||||
bool IsClose(const Matrix4x4& rhs, float tolerance = Constants::Tolerance) const;
|
||||
|
||||
bool operator==(const Matrix4x4& rhs) const;
|
||||
@@ -270,6 +300,10 @@ namespace AZ
|
||||
//! Pre-multiplies the matrix by a vector in-place.
|
||||
//! Note that this is not the usual multiplication order for transformations.
|
||||
Vector4& operator*=(Vector4& lhs, const Matrix4x4& rhs);
|
||||
}
|
||||
|
||||
//! Pre-multiplies the matrix by a scalar.
|
||||
Matrix4x4 operator*(float lhs, const Matrix4x4& rhs);
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
#include <AzCore/Math/Matrix4x4.inl>
|
||||
|
||||
@@ -480,20 +480,12 @@ namespace AZ
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator+(const Matrix4x4& rhs) const
|
||||
{
|
||||
return Matrix4x4
|
||||
( Simd::Vec4::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
, Simd::Vec4::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue())
|
||||
, Simd::Vec4::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
, Simd::Vec4::Add(m_rows[3].GetSimdValue(), rhs.m_rows[3].GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator-(const Matrix4x4& rhs) const
|
||||
{
|
||||
return Matrix4x4
|
||||
( Simd::Vec4::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
, Simd::Vec4::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue())
|
||||
, Simd::Vec4::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
, Simd::Vec4::Sub(m_rows[3].GetSimdValue(), rhs.m_rows[3].GetSimdValue()));
|
||||
(
|
||||
Simd::Vec4::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[3].GetSimdValue(), rhs.m_rows[3].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4& Matrix4x4::operator+=(const Matrix4x4& rhs)
|
||||
@@ -502,6 +494,18 @@ namespace AZ
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator-(const Matrix4x4& rhs) const
|
||||
{
|
||||
return Matrix4x4
|
||||
(
|
||||
Simd::Vec4::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[3].GetSimdValue(), rhs.m_rows[3].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4& Matrix4x4::operator-=(const Matrix4x4& rhs)
|
||||
{
|
||||
*this = *this - rhs;
|
||||
@@ -523,6 +527,59 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator*(float multiplier) const
|
||||
{
|
||||
const Simd::Vec4::FloatType mulVec = Simd::Vec4::Splat(multiplier);
|
||||
return Matrix4x4
|
||||
(
|
||||
Simd::Vec4::Mul(m_rows[0].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[1].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[2].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[3].GetSimdValue(), mulVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4& Matrix4x4::operator*=(float multiplier)
|
||||
{
|
||||
*this = *this * multiplier;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator/(float divisor) const
|
||||
{
|
||||
const Simd::Vec4::FloatType divVec = Simd::Vec4::Splat(divisor);
|
||||
return Matrix4x4
|
||||
(
|
||||
Simd::Vec4::Div(m_rows[0].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[1].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[2].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[3].GetSimdValue(), divVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4& Matrix4x4::operator/=(float divisor)
|
||||
{
|
||||
*this = *this / divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator-() const
|
||||
{
|
||||
const Simd::Vec4::FloatType zeroVec = Simd::Vec4::ZeroFloat();
|
||||
return Matrix4x4
|
||||
(
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[2].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[3].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix4x4::operator*(const Vector3& rhs) const
|
||||
{
|
||||
return Vector3(Simd::Vec4::Mat4x4TransformPoint3(GetSimdValues(), rhs.GetSimdValue()));
|
||||
@@ -595,6 +652,12 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix4x4::RetrieveScaleSq() const
|
||||
{
|
||||
return Vector3(GetBasisX().GetLengthSq(), GetBasisY().GetLengthSq(), GetBasisZ().GetLengthSq());
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix4x4::ExtractScale()
|
||||
{
|
||||
Vector4 x = GetBasisX();
|
||||
@@ -619,6 +682,14 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::GetReciprocalScaled() const
|
||||
{
|
||||
Matrix4x4 result = *this;
|
||||
result.MultiplyByScale(RetrieveScaleSq().GetReciprocal());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE bool Matrix4x4::IsClose(const Matrix4x4& rhs, float tolerance) const
|
||||
{
|
||||
const Simd::Vec4::FloatType vecTolerance = Simd::Vec4::Splat(tolerance);
|
||||
@@ -702,4 +773,10 @@ namespace AZ
|
||||
lhs = lhs * rhs;
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 operator*(float lhs, const Matrix4x4& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -816,7 +816,7 @@ namespace AZ
|
||||
template<size_t Index>
|
||||
static void ReflectUnpackMethodFold(BehaviorContext::ClassBuilder<ContainerType>& builder)
|
||||
{
|
||||
AZStd::string methodName = AZStd::string::format("Get%ld", Index);
|
||||
const AZStd::string methodName = AZStd::string::format("Get%zu", Index);
|
||||
builder->Method(methodName.data(), [](ContainerType& value) { return AZStd::get<Index>(value); })
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::TupleGetFunctionIndex, Index)
|
||||
|
||||
@@ -97,7 +97,8 @@ namespace AZ
|
||||
return context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
|
||||
AZStd::string::format("Failed to retrieve rtti information for %s.", classData->m_name));
|
||||
}
|
||||
AZ_Assert(classData->m_azRtti->GetTypeId() == typeId, "Type id mismatch during deserialization of a json file. (%s vs %s)");
|
||||
AZ_Assert(classData->m_azRtti->GetTypeId() == typeId, "Type id mismatch during deserialization of a json file. (%s vs %s)",
|
||||
classData->m_azRtti->GetTypeId().ToString<AZStd::string>().c_str(), typeId.ToString<AZStd::string>().c_str());
|
||||
|
||||
void** objectPtr = reinterpret_cast<void**>(object);
|
||||
bool isNull = *objectPtr == nullptr;
|
||||
@@ -512,27 +513,24 @@ namespace AZ
|
||||
if (*object)
|
||||
{
|
||||
const AZ::Uuid& actualClassId = rtti.GetActualUuid(*object);
|
||||
if (actualClassId != objectType)
|
||||
const SerializeContext::ClassData* actualClassData = context.GetSerializeContext()->FindClassData(actualClassId);
|
||||
if (!actualClassData)
|
||||
{
|
||||
const SerializeContext::ClassData* actualClassData = context.GetSerializeContext()->FindClassData(actualClassId);
|
||||
if (!actualClassData)
|
||||
{
|
||||
status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
|
||||
AZStd::string::format("Unable to find serialization information for type %s.", actualClassId.ToString<AZStd::string>().c_str()));
|
||||
return ResolvePointerResult::FullyProcessed;
|
||||
}
|
||||
status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
|
||||
AZStd::string::format("Unable to find serialization information for type %s.", actualClassId.ToString<AZStd::string>().c_str()));
|
||||
return ResolvePointerResult::FullyProcessed;
|
||||
}
|
||||
|
||||
if (actualClassData->m_factory)
|
||||
{
|
||||
actualClassData->m_factory->Destroy(*object);
|
||||
*object = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = context.Report(Tasks::RetrieveInfo, Outcomes::Catastrophic,
|
||||
"Unable to find the factory needed to clear out the default value.");
|
||||
return ResolvePointerResult::FullyProcessed;
|
||||
}
|
||||
if (actualClassData->m_factory)
|
||||
{
|
||||
actualClassData->m_factory->Destroy(*object);
|
||||
*object = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = context.Report(Tasks::RetrieveInfo, Outcomes::Catastrophic,
|
||||
"Unable to find the factory needed to clear out the default value.");
|
||||
return ResolvePointerResult::FullyProcessed;
|
||||
}
|
||||
}
|
||||
status = ResultCode(Tasks::ReadField, Outcomes::Success);
|
||||
|
||||
@@ -38,6 +38,20 @@ namespace AZ
|
||||
};
|
||||
|
||||
//! Core class to handle serialization to and from json documents.
|
||||
//! The Json Serialization works by taking a default constructed object and then apply the information found in the JSON document
|
||||
//! on top of that object. This allows the Json Serialization to avoid storing default values and helps guarantee that the final
|
||||
//! object is in a valid state even if non-fatal issues are encountered.
|
||||
//! Note on containers: Containers such as vector or map are always considered to be empty even if there's entries in the provided
|
||||
//! default object. During deserialization entries will be appended to any existing values. A flag is provided to automatically
|
||||
//! clear containers during deserialization.
|
||||
//! Note on maps: If the key for map containers such as unordered_map can be interpret as a string the Json Serialization will use
|
||||
//! a JSON Object to store the data in instead of an array with key/value objects.
|
||||
//! Note on pointers: The Json Serialization assumes that are always constructed, so a default JSON value of "{}" is interpret as
|
||||
//! creating a new default instance even if the default value is a null pointer. A JSON Null needs to be explicitly stored in
|
||||
//! the JSON Document in order to default or explicitly set a pointer to null.
|
||||
//! Note on pointer memory: Objects created/destroyed by the Json Serialization for pointers require that the AZ_CLASS_ALLOCATOR is
|
||||
//! declared and the object is created using aznew or memory is allocated using azmalloc. Without these the application may
|
||||
//! crash if the Json Serialization tries to create or destroy an object pointed to by a pointer.
|
||||
class JsonSerialization final
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -23,13 +23,6 @@ namespace AZ
|
||||
{
|
||||
namespace JSR = JsonSerializationResult;
|
||||
|
||||
if (IsExplicitDefault(inputValue))
|
||||
{
|
||||
// Do nothing if the input is an explicit default.
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed,
|
||||
"Default value for smart pointer requested so no change was made.");
|
||||
}
|
||||
|
||||
const SerializeContext::ClassData* containerClass = context.GetSerializeContext()->FindClassData(outputValueTypeId);
|
||||
if (!containerClass)
|
||||
{
|
||||
@@ -153,8 +146,7 @@ namespace AZ
|
||||
|
||||
if (defaultValue)
|
||||
{
|
||||
bool typesMatch = false;
|
||||
auto defaultInputCallback = [&defaultValue, &inputPtrType, &typesMatch]
|
||||
auto defaultInputCallback = [&defaultValue]
|
||||
(void* elementPtr, const Uuid&, const SerializeContext::ClassData*, const SerializeContext::ClassElement*)
|
||||
{
|
||||
defaultValue = elementPtr;
|
||||
@@ -164,11 +156,6 @@ namespace AZ
|
||||
}
|
||||
|
||||
JSR::ResultCode result = ContinueStoring(outputValue, inputValue, defaultValue, inputPtrType, context, Flags::ResolvePointer);
|
||||
if (result.GetOutcome() == JSR::Outcomes::DefaultsUsed)
|
||||
{
|
||||
outputValue = GetExplicitDefault();
|
||||
return context.Report(result, "Smart pointer used all defaults.");
|
||||
}
|
||||
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted ?
|
||||
"Successfully processed smart pointer." : "A problem occurred while processing a smart pointer.");
|
||||
}
|
||||
|
||||
@@ -330,4 +330,163 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// The AssetManagerStreamerImmediateCompletionTests class adjusts the asset loading to force it to complete immediately,
|
||||
// while still within the callstack for GetAsset(). This can be used to test various conditions in which the load thread
|
||||
// completes more rapidly than expected, and can expose subtle race conditions.
|
||||
// There are a few key things that this class does to make this work:
|
||||
// - The file I/O streamer is mocked
|
||||
// - The asset stream data is mocked to a 0-byte length for the asset so that the stream load will bypass the I/O streamer and
|
||||
// just immediately return completion.
|
||||
// - The number of JobManager threads is set to 0, forcing jobs to execute synchronously inline when they are started.
|
||||
// With these changes, GetAssetInternal() will queue the stream, which will immediately call the callback that creates LoadAssetJob,
|
||||
// which immediately executes in-place to process the asset due to the synchronous JobManager.
|
||||
// Note that if we just created the asset in a Ready state, most of the asset loading code is completely bypassed, and so we
|
||||
// wouldn't be able to test for race conditions in the AssetContainer.
|
||||
//
|
||||
// This class also unregisters the catalog and asset handler before shutting down the asset manager. This is done to catch
|
||||
// any outstanding asset references that exist due to loads not completing and cleaning up successfully.
|
||||
struct AssetManagerStreamerImmediateCompletionTests : public BaseAssetManagerTest,
|
||||
public AZ::Data::AssetCatalogRequestBus::Handler,
|
||||
public AZ::Data::AssetHandler,
|
||||
public AZ::Data::AssetCatalog
|
||||
{
|
||||
static inline const AZ::Uuid TestAssetId{"{E970B177-5F45-44EB-A2C4-9F29D9A0B2A2}"};
|
||||
static inline constexpr AZStd::string_view TestAssetPath = "test";
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
AssetManager::Descriptor desc;
|
||||
AssetManager::Create(desc);
|
||||
|
||||
// Register the handler and catalog after creation, because we intend to destroy them before AssetManager destruction.
|
||||
// The specific asset we load is irrelevant, so register EmptyAsset.
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(this, AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
AZ::Data::AssetManager::Instance().RegisterCatalog(this, AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
|
||||
// Intercept messages for finding assets by name so that we can mock out the asset we're loading.
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// Unregister before destroying AssetManager.
|
||||
// This will catch any assets that got stuck in a loading state without getting cleaned up.
|
||||
AZ::Data::AssetManager::Instance().UnregisterCatalog(this);
|
||||
AZ::Data::AssetManager::Instance().UnregisterHandler(this);
|
||||
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
|
||||
|
||||
AssetManager::Destroy();
|
||||
BaseAssetManagerTest::TearDown();
|
||||
}
|
||||
|
||||
size_t GetNumJobManagerThreads() const override
|
||||
{
|
||||
// Return 0 threads so that the Job Manager executes jobs synchronously inline. This lets us finish a load while still
|
||||
// in the callstack that initiates the load.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a mock streamer instead of a real one, since we don't really want to load an asset.
|
||||
IO::IStreamer* CreateStreamer() override
|
||||
{
|
||||
m_mockStreamer = AZStd::make_unique<StreamerWrapper>();
|
||||
return &(m_mockStreamer->m_mockStreamer);
|
||||
}
|
||||
|
||||
void DestroyStreamer([[maybe_unused]] IO::IStreamer* streamer) override
|
||||
{
|
||||
m_mockStreamer = nullptr;
|
||||
}
|
||||
|
||||
// AssetHandler implementation
|
||||
|
||||
// Minimalist mock to create a new EmptyAsset with the desired asset ID.
|
||||
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type) override
|
||||
{
|
||||
return new EmptyAsset(id);
|
||||
}
|
||||
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
// The mocked-out Asset Catalog handles EmptyAsset types.
|
||||
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override
|
||||
{
|
||||
assetTypes.push_back(AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
}
|
||||
|
||||
// This is a mocked-out load, so just immediately return completion without doing anything.
|
||||
AZ::Data::AssetHandler::LoadResult LoadAssetData(
|
||||
[[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
[[maybe_unused]] AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB)
|
||||
{
|
||||
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
|
||||
}
|
||||
|
||||
// AssetCatalogRequestBus implementation
|
||||
|
||||
// Minimalist mocks to provide our desired asset path or asset id
|
||||
AZStd::string GetAssetPathById([[maybe_unused]] const AZ::Data::AssetId& id) override
|
||||
{
|
||||
return TestAssetPath;
|
||||
}
|
||||
AZ::Data::AssetId GetAssetIdByPath(
|
||||
[[maybe_unused]] const char* path, [[maybe_unused]] const AZ::Data::AssetType& typeToRegister,
|
||||
[[maybe_unused]] bool autoRegisterIfNotFound) override
|
||||
{
|
||||
return TestAssetId;
|
||||
}
|
||||
|
||||
// Return the mocked-out information for our test asset
|
||||
AZ::Data::AssetInfo GetAssetInfoById([[maybe_unused]] const AZ::Data::AssetId& id) override
|
||||
{
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
assetInfo.m_assetId = TestAssetId;
|
||||
assetInfo.m_assetType = AZ::AzTypeInfo<EmptyAsset>::Uuid();
|
||||
assetInfo.m_relativePath = TestAssetPath;
|
||||
return assetInfo;
|
||||
}
|
||||
|
||||
// AssetCatalog implementation
|
||||
|
||||
// Set the mocked-out asset load to have a 0-byte length so that the load skips I/O and immediately returns success
|
||||
AZ::Data::AssetStreamInfo GetStreamInfoForLoad(
|
||||
[[maybe_unused]] const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override
|
||||
{
|
||||
EXPECT_TRUE(type == AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
AZ::Data::AssetStreamInfo info;
|
||||
info.m_dataOffset = 0;
|
||||
info.m_streamName = TestAssetPath;
|
||||
info.m_dataLen = 0;
|
||||
info.m_streamFlags = AZ::IO::OpenMode::ModeRead;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<StreamerWrapper> m_mockStreamer;
|
||||
};
|
||||
|
||||
// This test will verify that even if the asset loading stream/job returns immediately, all of the loading
|
||||
// code works successfully. The test here is fairly simple - it just loads the asset and verifies that it
|
||||
// loaded successfully. The bulk of the test is really in the setup class above, where the load is forced
|
||||
// to complete immediately. Also, the true failure condition is caught in the setup class too, which is
|
||||
// the presence of any assets at the point that the asset handler is unregistered. If they're present, then
|
||||
// the immediate load wasn't truly successful, as it left around extra references to the asset that haven't
|
||||
// been cleaned up.
|
||||
TEST_F(AssetManagerStreamerImmediateCompletionTests, LoadAssetWithImmediateJobCompletion_WorksSuccessfully)
|
||||
{
|
||||
AZ::Data::AssetLoadParameters loadParams;
|
||||
|
||||
auto testAsset =
|
||||
AssetManager::Instance().GetAsset<EmptyAsset>(TestAssetId, AZ::Data::AssetLoadBehavior::Default, loadParams);
|
||||
|
||||
AZ::Data::AssetManager::Instance().DispatchEvents();
|
||||
EXPECT_TRUE(testAsset.IsReady());
|
||||
}
|
||||
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -24,6 +24,13 @@ namespace UnitTest
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EmptyAsset, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(EmptyAsset, "{098E3F7F-13AC-414B-9B4E-49B5AD1BD7FE}", AZ::Data::AssetData);
|
||||
|
||||
EmptyAsset(
|
||||
const AZ::Data::AssetId& assetId = AZ::Data::AssetId(),
|
||||
AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
|
||||
: AZ::Data::AssetData(assetId, status)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// EmptyAssetWithNoHandler: no data contained within, and no AssetHandler registered for this type
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
@@ -251,19 +252,19 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 * m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(66.0f, 72.0f, 78.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(156.0f, 171.0f, 186.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(246.0f, 270.0f, 294.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(66.0f, 72.0f, 78.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(156.0f, 171.0f, 186.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(246.0f, 270.0f, 294.0f)));
|
||||
|
||||
Matrix3x3 m4 = m1;
|
||||
m4 *= m2;
|
||||
AZ_TEST_ASSERT(m4.GetRow(0).IsClose(Vector3(66.0f, 72.0f, 78.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(1).IsClose(Vector3(156.0f, 171.0f, 186.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(2).IsClose(Vector3(246.0f, 270.0f, 294.0f)));
|
||||
EXPECT_THAT(m4.GetRow(0), IsClose(Vector3(66.0f, 72.0f, 78.0f)));
|
||||
EXPECT_THAT(m4.GetRow(1), IsClose(Vector3(156.0f, 171.0f, 186.0f)));
|
||||
EXPECT_THAT(m4.GetRow(2), IsClose(Vector3(246.0f, 270.0f, 294.0f)));
|
||||
m3 = m1.TransposedMultiply(m2);
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(138.0f, 150.0f, 162.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(168.0f, 183.0f, 198.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(198.0f, 216.0f, 234.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(138.0f, 150.0f, 162.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(168.0f, 183.0f, 198.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(198.0f, 216.0f, 234.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestVectorMultiplication)
|
||||
@@ -277,11 +278,11 @@ namespace UnitTest
|
||||
m2.SetRow(1, 10.0f, 11.0f, 12.0f);
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
AZ_TEST_ASSERT((m1 * Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(14.0f, 32.0f, 50.0f)));
|
||||
EXPECT_THAT((m1 * Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(14.0f, 32.0f, 50.0f)));
|
||||
Vector3 v1(1.0f, 2.0f, 3.0f);
|
||||
AZ_TEST_ASSERT((v1 * m1).IsClose(Vector3(30.0f, 36.0f, 42.0f)));
|
||||
EXPECT_THAT((v1 * m1), IsClose(Vector3(30.0f, 36.0f, 42.0f)));
|
||||
v1 *= m1;
|
||||
AZ_TEST_ASSERT(v1.IsClose(Vector3(30.0f, 36.0f, 42.0f)));
|
||||
EXPECT_THAT(v1, IsClose(Vector3(30.0f, 36.0f, 42.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestSum)
|
||||
@@ -296,15 +297,15 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 + m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(20.0f, 22.0f, 24.0f)));
|
||||
|
||||
m3 = m1;
|
||||
m3 += m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(20.0f, 22.0f, 24.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestDifference)
|
||||
@@ -319,14 +320,14 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 - m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
m3 = m1;
|
||||
m3 -= m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestScalarMultiplication)
|
||||
@@ -341,18 +342,18 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 * 2.0f;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
m3 = m1;
|
||||
m3 *= 2.0f;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
m3 = 2.0f * m1;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestScalarDivision)
|
||||
@@ -367,18 +368,32 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 / 0.5f;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
m3 = m1;
|
||||
m3 /= 0.5f;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
m3 = -m1;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-1.0f, -2.0f, -3.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-4.0f, -5.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-7.0f, -8.0f, -9.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestNegation)
|
||||
{
|
||||
Matrix3x3 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f);
|
||||
m1.SetRow(1, 4.0f, 5.0f, 6.0f);
|
||||
m1.SetRow(2, 7.0f, 8.0f, 9.0f);
|
||||
EXPECT_THAT(-(-m1), IsClose(m1));
|
||||
EXPECT_THAT(-Matrix3x3::CreateZero(), IsClose(Matrix3x3::CreateZero()));
|
||||
|
||||
Matrix3x3 m2 = -m1;
|
||||
EXPECT_THAT(m2.GetRow(0), IsClose(Vector3(-1.0f, -2.0f, -3.0f)));
|
||||
EXPECT_THAT(m2.GetRow(1), IsClose(Vector3(-4.0f, -5.0f, -6.0f)));
|
||||
EXPECT_THAT(m2.GetRow(2), IsClose(Vector3(-7.0f, -8.0f, -9.0f)));
|
||||
|
||||
Matrix3x3 m3 = m1 + (-m1);
|
||||
EXPECT_THAT(m3, IsClose(Matrix3x3::CreateZero()));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestTranspose)
|
||||
@@ -425,11 +440,33 @@ namespace UnitTest
|
||||
TEST(MATH_Matrix3x3, TestScaleAccess)
|
||||
{
|
||||
Matrix3x3 m1 = Matrix3x3::CreateRotationX(DegToRad(40.0f)) * Matrix3x3::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
|
||||
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
AZ_TEST_ASSERT(m1.ExtractScale().IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3::CreateOne()));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
EXPECT_THAT(m1.ExtractScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3::CreateOne()));
|
||||
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
|
||||
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3(3.0f, 4.0f, 5.0f)));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(3.0f, 4.0f, 5.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestScaleSqAccess)
|
||||
{
|
||||
Matrix3x3 m1 = Matrix3x3::CreateRotationX(DegToRad(40.0f)) * Matrix3x3::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(4.0f, 9.0f, 16.0f)));
|
||||
m1.ExtractScale();
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3::CreateOne()));
|
||||
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(9.0f, 16.0f, 25.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestReciprocalScaled)
|
||||
{
|
||||
Matrix3x3 orthogonalMatrix = Matrix3x3::CreateRotationX(DegToRad(40.0f));
|
||||
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
|
||||
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
|
||||
AZ::Matrix3x3 scaledMatrix = orthogonalMatrix;
|
||||
scaledMatrix.MultiplyByScale(scale);
|
||||
AZ::Matrix3x3 reciprocalScaledMatrix = orthogonalMatrix;
|
||||
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
|
||||
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestPolarDecomposition)
|
||||
|
||||
@@ -467,21 +467,136 @@ namespace UnitTest
|
||||
EXPECT_THAT(matrix.Multiply3x3(axisDirection), IsClose(forwardDirection));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, MultiplyByMatrix3x4)
|
||||
TEST(MATH_Matrix3x4, TestMatrixMultiplication)
|
||||
{
|
||||
const AZ::Matrix3x4 matrix1 = AZ::Matrix3x4::CreateFromValue(1.2f);
|
||||
const AZ::Matrix3x4 matrix2 = AZ::Matrix3x4::CreateDiagonal(AZ::Vector3(1.3f, 1.5f, 0.4f));
|
||||
const AZ::Matrix3x4 matrix3 = AZ::Matrix3x4::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion(0.42f, 0.46f, -0.66f, 0.42f), AZ::Vector3(2.8f, -3.7f, 1.6f));
|
||||
const AZ::Matrix3x4 matrix4 = AZ::Matrix3x4::CreateRotationX(-0.7f) * AZ::Matrix3x4::CreateScale(AZ::Vector3(0.6f, 1.3f, 0.7f));
|
||||
AZ::Matrix3x4 matrix5 = matrix1;
|
||||
matrix5 *= matrix4;
|
||||
const AZ::Vector3 vector(1.9f, 2.3f, 0.2f);
|
||||
EXPECT_TRUE((matrix1 * (matrix2 * matrix3)).IsClose((matrix1 * matrix2) * matrix3));
|
||||
EXPECT_THAT((matrix3 * matrix4) * vector, IsClose(matrix3 * (matrix4 * vector)));
|
||||
EXPECT_TRUE((matrix2 * AZ::Matrix3x4::Identity()).IsClose(matrix2));
|
||||
EXPECT_TRUE((matrix3 * AZ::Matrix3x4::Identity()).IsClose(AZ::Matrix3x4::Identity() * matrix3));
|
||||
EXPECT_TRUE(matrix5.IsClose(matrix1 * matrix4));
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
AZ::Matrix3x4 m3 = m1 * m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(74.0f, 80.0f, 86.0f, 96.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(206.0f, 224.0f, 242.0f, 268.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(338.0f, 368.0f, 398.0f, 440.0f)));
|
||||
AZ::Matrix3x4 m4 = m1;
|
||||
m4 *= m2;
|
||||
EXPECT_THAT(m4.GetRow(0), IsClose(AZ::Vector4(74.0f, 80.0f, 86.0f, 96.0f)));
|
||||
EXPECT_THAT(m4.GetRow(1), IsClose(AZ::Vector4(206.0f, 224.0f, 242.0f, 268.0f)));
|
||||
EXPECT_THAT(m4.GetRow(2), IsClose(AZ::Vector4(338.0f, 368.0f, 398.0f, 440.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestSum)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 + m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
|
||||
|
||||
m3 = m1;
|
||||
m3 += m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestDifference)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 - m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
m3 = m1;
|
||||
m3 -= m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestScalarMultiplication)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 * 2.0f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
m3 = m1;
|
||||
m3 *= 2.0f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
m3 = 2.0f * m1;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestScalarDivision)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 / 0.5f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
m3 = m1;
|
||||
m3 /= 0.5f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestNegation)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
EXPECT_THAT(-(-m1), IsClose(m1));
|
||||
EXPECT_THAT(-AZ::Matrix3x4::CreateZero(), IsClose(AZ::Matrix3x4::CreateZero()));
|
||||
|
||||
AZ::Matrix3x4 m2 = -m1;
|
||||
EXPECT_THAT(m2.GetRow(0), IsClose(AZ::Vector4(-1.0f, -2.0f, -3.0f, -4.0f)));
|
||||
EXPECT_THAT(m2.GetRow(1), IsClose(AZ::Vector4(-5.0f, -6.0f, -7.0f, -8.0f)));
|
||||
EXPECT_THAT(m2.GetRow(2), IsClose(AZ::Vector4(-9.0f, -10.0f, -11.0f, -12.0f)));
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 + (-m1);
|
||||
EXPECT_THAT(m3, IsClose(AZ::Matrix3x4::CreateZero()));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, MultiplyByVector3)
|
||||
@@ -652,6 +767,34 @@ namespace UnitTest
|
||||
EXPECT_THAT(scaledMatrix.RetrieveScale(), IsClose(AZ::Vector3::CreateOne()));
|
||||
}
|
||||
|
||||
TEST_P(Matrix3x4ScaleFixture, ScaleSq)
|
||||
{
|
||||
const AZ::Matrix3x4 orthogonalMatrix = GetParam();
|
||||
EXPECT_THAT(orthogonalMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
|
||||
AZ::Matrix3x4 unscaledMatrix = orthogonalMatrix;
|
||||
unscaledMatrix.ExtractScale();
|
||||
EXPECT_THAT(unscaledMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
|
||||
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
|
||||
AZ::Matrix3x4 scaledMatrix = orthogonalMatrix;
|
||||
scaledMatrix.MultiplyByScale(scale);
|
||||
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(scale * scale));
|
||||
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(scaledMatrix.RetrieveScale() * scaledMatrix.RetrieveScale()));
|
||||
scaledMatrix.ExtractScale();
|
||||
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
|
||||
}
|
||||
|
||||
TEST_P(Matrix3x4ScaleFixture, GetReciprocalScaled)
|
||||
{
|
||||
const AZ::Matrix3x4 orthogonalMatrix = GetParam();
|
||||
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
|
||||
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
|
||||
AZ::Matrix3x4 scaledMatrix = orthogonalMatrix;
|
||||
scaledMatrix.MultiplyByScale(scale);
|
||||
AZ::Matrix3x4 reciprocalScaledMatrix = orthogonalMatrix;
|
||||
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
|
||||
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MATH_Matrix3x4, Matrix3x4ScaleFixture, ::testing::ValuesIn(MathTestData::OrthogonalMatrix3x4s));
|
||||
|
||||
TEST(MATH_Matrix3x4, IsOrthogonal)
|
||||
|
||||
@@ -246,16 +246,16 @@ namespace UnitTest
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
Matrix4x4 m3 = m1 * m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(3).IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
|
||||
Matrix4x4 m4 = m1;
|
||||
m4 *= m2;
|
||||
AZ_TEST_ASSERT(m4.GetRow(0).IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(1).IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(2).IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(3).IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
|
||||
EXPECT_THAT(m4.GetRow(0), IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
|
||||
EXPECT_THAT(m4.GetRow(1), IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
|
||||
EXPECT_THAT(m4.GetRow(2), IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
|
||||
EXPECT_THAT(m4.GetRow(3), IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestVectorMultiplication)
|
||||
@@ -265,18 +265,148 @@ namespace UnitTest
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
AZ_TEST_ASSERT((m1 * Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(18.0f, 46.0f, 74.0f)));
|
||||
AZ_TEST_ASSERT((m1 * Vector4(1.0f, 2.0f, 3.0f, 4.0f)).IsClose(Vector4(30.0f, 70.0f, 110.0f, 150.0f)));
|
||||
AZ_TEST_ASSERT(m1.TransposedMultiply3x3(Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(38.0f, 44.0f, 50.0f)));
|
||||
AZ_TEST_ASSERT(m1.Multiply3x3(Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(14.0f, 38.0f, 62.0f)));
|
||||
EXPECT_THAT((m1 * Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(18.0f, 46.0f, 74.0f)));
|
||||
EXPECT_THAT((m1 * Vector4(1.0f, 2.0f, 3.0f, 4.0f)), IsClose(Vector4(30.0f, 70.0f, 110.0f, 150.0f)));
|
||||
EXPECT_THAT(m1.TransposedMultiply3x3(Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(38.0f, 44.0f, 50.0f)));
|
||||
EXPECT_THAT(m1.Multiply3x3(Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(14.0f, 38.0f, 62.0f)));
|
||||
Vector3 v1(1.0f, 2.0f, 3.0f);
|
||||
AZ_TEST_ASSERT((v1 * m1).IsClose(Vector3(51.0f, 58.0f, 65.0f)));
|
||||
EXPECT_THAT((v1 * m1), IsClose(Vector3(51.0f, 58.0f, 65.0f)));
|
||||
v1 *= m1;
|
||||
AZ_TEST_ASSERT(v1.IsClose(Vector3(51.0f, 58.0f, 65.0f)));
|
||||
EXPECT_THAT(v1, IsClose(Vector3(51.0f, 58.0f, 65.0f)));
|
||||
Vector4 v2(1.0f, 2.0f, 3.0f, 4.0f);
|
||||
AZ_TEST_ASSERT((v2 * m1).IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
|
||||
EXPECT_THAT((v2 * m1), IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
|
||||
v2 *= m1;
|
||||
AZ_TEST_ASSERT(v2.IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
|
||||
EXPECT_THAT(v2, IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestSum)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
Matrix4x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
|
||||
Matrix4x4 m3 = m1 + m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(32.0f, 34.0f, 36.0f, 38.0f)));
|
||||
|
||||
m3 = m1;
|
||||
m3 += m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(32.0f, 34.0f, 36.0f, 38.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestDifference)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
Matrix4x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
|
||||
Matrix4x4 m3 = m1 - m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
m3 = m1;
|
||||
m3 -= m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestScalarMultiplication)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
Matrix4x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
|
||||
Matrix4x4 m3 = m1 * 2.0f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
m3 = m1;
|
||||
m3 *= 2.0f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
m3 = 2.0f * m1;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestScalarDivision)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
Matrix4x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
|
||||
Matrix4x4 m3 = m1 / 0.5f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
m3 = m1;
|
||||
m3 /= 0.5f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestNegation)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
EXPECT_THAT(-(-m1), IsClose(m1));
|
||||
EXPECT_THAT(-Matrix4x4::CreateZero(), IsClose(Matrix4x4::CreateZero()));
|
||||
|
||||
Matrix4x4 m2 = -m1;
|
||||
EXPECT_THAT(m2.GetRow(0), IsClose(Vector4(-1.0f, -2.0f, -3.0f, -4.0f)));
|
||||
EXPECT_THAT(m2.GetRow(1), IsClose(Vector4(-5.0f, -6.0f, -7.0f, -8.0f)));
|
||||
EXPECT_THAT(m2.GetRow(2), IsClose(Vector4(-9.0f, -10.0f, -11.0f, -12.0f)));
|
||||
EXPECT_THAT(m2.GetRow(3), IsClose(Vector4(-13.0f, -14.0f, -15.0f, -16.0f)));
|
||||
|
||||
Matrix4x4 m3 = m1 + (-m1);
|
||||
EXPECT_THAT(m3, IsClose(Matrix4x4::CreateZero()));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestTranspose)
|
||||
@@ -368,4 +498,36 @@ namespace UnitTest
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
AZ_TEST_ASSERT(m1.GetDiagonal() == Vector4(1.0f, 6.0f, 11.0f, 16.0f));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestScaleAccess)
|
||||
{
|
||||
Matrix4x4 m1 = Matrix4x4::CreateRotationX(DegToRad(40.0f)) * Matrix4x4::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
EXPECT_THAT(m1.ExtractScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3::CreateOne()));
|
||||
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(3.0f, 4.0f, 5.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestScaleSqAccess)
|
||||
{
|
||||
Matrix4x4 m1 = Matrix4x4::CreateRotationX(DegToRad(40.0f)) * Matrix4x4::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(4.0f, 9.0f, 16.0f)));
|
||||
m1.ExtractScale();
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3::CreateOne()));
|
||||
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(9.0f, 16.0f, 25.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestReciprocalScaled)
|
||||
{
|
||||
Matrix4x4 orthogonalMatrix = Matrix4x4::CreateRotationX(DegToRad(40.0f));
|
||||
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
|
||||
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
|
||||
AZ::Matrix4x4 scaledMatrix = orthogonalMatrix;
|
||||
scaledMatrix.MultiplyByScale(scale);
|
||||
AZ::Matrix4x4 reciprocalScaledMatrix = orthogonalMatrix;
|
||||
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
|
||||
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace JsonSerializationTests
|
||||
EXPECT_EQ(42, value);
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_PointerInstance_ValueLoadedCorrectly)
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_ToPointerInstance_ValueLoadedCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
@@ -126,6 +126,51 @@ namespace JsonSerializationTests
|
||||
EXPECT_EQ(42, value);
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_ToNullPointer_ValueLoadedCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value json;
|
||||
json.Set(42);
|
||||
int* ptrValue = nullptr;
|
||||
|
||||
ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
ASSERT_NE(nullptr, ptrValue);
|
||||
EXPECT_EQ(42, *ptrValue);
|
||||
|
||||
azfree(ptrValue, AZ::SystemAllocator, sizeof(int), alignof(int));
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_DefaultToNullPointer_ValueLoadedCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value json(rapidjson::kObjectType);
|
||||
int* ptrValue = nullptr;
|
||||
|
||||
ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
ASSERT_NE(nullptr, ptrValue);
|
||||
|
||||
azfree(ptrValue, AZ::SystemAllocator, sizeof(int), alignof(int));
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_NullDeletesObject_ValueLoadedCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value json(rapidjson::kNullType);
|
||||
int* ptrValue = reinterpret_cast<int*>(azmalloc(sizeof(int), alignof(int), AZ::SystemAllocator));
|
||||
|
||||
ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
ASSERT_EQ(nullptr, ptrValue);
|
||||
}
|
||||
|
||||
//
|
||||
// ContinueStoring
|
||||
//
|
||||
@@ -156,6 +201,64 @@ namespace JsonSerializationTests
|
||||
Expect_DocStrEq("42");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToFullDefaultedInstance_ValueStoredCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int value = 42;
|
||||
int* ptrValue = &value;
|
||||
int value2 = 42;
|
||||
int* defaultPtrValue = &value2;
|
||||
|
||||
ResultCode result =
|
||||
ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext, Flags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("{}");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptr_ValueStoredCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int* ptrValue = nullptr;
|
||||
|
||||
ResultCode result = ContinueStoring(
|
||||
*m_jsonDocument, &ptrValue, nullptr, azrtti_typeid<int>(), *m_jsonSerializationContext, Flags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("null");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptrWithValueDefault_ValueStoredCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int* ptrValue = nullptr;
|
||||
int value2 = 42;
|
||||
int* defaultPtrValue = &value2;
|
||||
|
||||
ResultCode result =
|
||||
ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext, Flags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("null");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptrWithNullPtrDefault_NullPtrIsStored)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int* ptrValue = nullptr;
|
||||
int* defaultPtrValue = nullptr;
|
||||
|
||||
ResultCode result =
|
||||
ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext, Flags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("null");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_ReplaceDefault_ValueStoredCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
@@ -32,11 +32,6 @@ namespace JsonSerializationTests
|
||||
return AZStd::make_shared<AZ::JsonSmartPointerSerializer>();
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
return AZStd::make_shared<SmartPointer>();
|
||||
}
|
||||
|
||||
void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context) override
|
||||
{
|
||||
context->RegisterGenericType<SmartPointer>();
|
||||
@@ -51,6 +46,13 @@ namespace JsonSerializationTests
|
||||
using SmartPointer = T<SimpleClass>;
|
||||
using Base = SmartPointerBaseTestDescription<SmartPointer>;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew SimpleClass());
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
@@ -106,21 +108,6 @@ namespace JsonSerializationTests
|
||||
}
|
||||
};
|
||||
|
||||
template<template<typename...> class T>
|
||||
class SmartPointerSimpleClassWithInstanceTestDescription :
|
||||
public SmartPointerSimpleClassTestDescription<T>
|
||||
{
|
||||
public:
|
||||
using SmartPointer = typename SmartPointerSimpleClassTestDescription<T>::SmartPointer;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew SimpleClass());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<template<typename...> class T>
|
||||
class SmartPointerSimpleDerivedClassTestDescription :
|
||||
public SmartPointerBaseTestDescription<T<BaseClass>>
|
||||
@@ -129,6 +116,13 @@ namespace JsonSerializationTests
|
||||
using SmartPointer = T<BaseClass>;
|
||||
using Base = SmartPointerBaseTestDescription<SmartPointer>;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew BaseClass());
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
|
||||
{
|
||||
auto* instance = aznew SimpleInheritence();
|
||||
@@ -272,6 +266,13 @@ namespace JsonSerializationTests
|
||||
using SmartPointer = T<BaseClass2>;
|
||||
using Base = SmartPointerBaseTestDescription<SmartPointer>;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew BaseClass2());
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
|
||||
{
|
||||
auto* instance = aznew MultipleInheritence();
|
||||
@@ -424,9 +425,6 @@ namespace JsonSerializationTests
|
||||
SmartPointerSimpleClassTestDescription<AZStd::unique_ptr>,
|
||||
SmartPointerSimpleClassTestDescription<AZStd::shared_ptr>,
|
||||
SmartPointerSimpleClassTestDescription<AZStd::intrusive_ptr>,
|
||||
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::unique_ptr>,
|
||||
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::shared_ptr>,
|
||||
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::intrusive_ptr>,
|
||||
// Simple derived class, include single inheritance.
|
||||
SmartPointerSimpleDerivedClassTestDescription<AZStd::unique_ptr>,
|
||||
SmartPointerSimpleDerivedClassTestDescription<AZStd::shared_ptr>,
|
||||
@@ -551,6 +549,37 @@ namespace JsonSerializationTests
|
||||
EXPECT_EQ(nullptr, *instance);
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Load_DefaultInstanceToNullptr_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
SmartPointer instance;
|
||||
AZStd::shared_ptr<SmartPointer> compare = m_description.CreateDefaultInstance();
|
||||
m_jsonDocument->SetObject();
|
||||
|
||||
JSR::ResultCode result =
|
||||
m_serializer.Load(&instance, azrtti_typeid<SmartPointer>(), *m_jsonDocument, *m_jsonDeserializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
|
||||
EXPECT_NE(nullptr, instance);
|
||||
EXPECT_TRUE(m_description.AreEqual(instance, *compare));
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Load_DefaultObjectDoesNotUpdateInstance_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateFullySetInstance();
|
||||
AZStd::shared_ptr<SmartPointer> compare = m_description.CreateFullySetInstance();
|
||||
m_jsonDocument->SetObject();
|
||||
|
||||
JSR::ResultCode result =
|
||||
m_serializer.Load(instance.get(), azrtti_typeid<SmartPointer>(), *m_jsonDocument, *m_jsonDeserializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
|
||||
EXPECT_TRUE(m_description.AreEqual(*instance, *compare));
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Load_InstanceBeingReplacedWithDifferentType_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
@@ -720,13 +749,66 @@ namespace JsonSerializationTests
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateFullySetInstance();
|
||||
SmartPointer nullPtr;
|
||||
JSR::ResultCode result = m_serializer.Store(*m_jsonDocument, instance.get(), &nullPtr,
|
||||
SmartPointer defaultInstance;
|
||||
JSR::ResultCode result = m_serializer.Store(
|
||||
*m_jsonDocument, instance.get(), &defaultInstance,
|
||||
azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::Success, result.GetOutcome());
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ValuePointerIsNullPtr_ReturnsSuccessAndStoresNull)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
SmartPointer instance;
|
||||
AZStd::shared_ptr<SmartPointer> defaultInstance = m_description.CreateFullySetInstance();
|
||||
JSR::ResultCode result = m_serializer.Store(
|
||||
*m_jsonDocument, &instance, defaultInstance.get(), azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::Success, result.GetOutcome());
|
||||
EXPECT_TRUE(m_jsonDocument->IsNull());
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ValueAndDefaultPointersAreNullPtr_ReturnsSuccessAndStoresNull)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
SmartPointer instance;
|
||||
SmartPointer defaultInstance;
|
||||
JSR::ResultCode result =
|
||||
m_serializer.Store(*m_jsonDocument, &instance, &defaultInstance, azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
EXPECT_TRUE(m_jsonDocument->IsNull());
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ValueAndDefaultPointersAreBothDefault_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateDefaultInstance();
|
||||
AZStd::shared_ptr<SmartPointer> defaultInstance = m_description.CreateDefaultInstance();
|
||||
JSR::ResultCode result =
|
||||
m_serializer.Store(*m_jsonDocument, instance.get(), defaultInstance.get(), azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
Expect_ExplicitDefault(*m_jsonDocument);
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ValueHasDefaultValuesAndDefaultHasNullPointer_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateDefaultInstance();
|
||||
SmartPointer defaultInstance;
|
||||
JSR::ResultCode result = m_serializer.Store(
|
||||
*m_jsonDocument, instance.get(), &defaultInstance, azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
Expect_ExplicitDefault(*m_jsonDocument);
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_DefaultPointerIsOtherClass_CompletesButDoesNotReturnDefaults)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
@@ -749,7 +831,7 @@ namespace JsonSerializationTests
|
||||
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_SaveAnClassThatIsNotReflected_ReturnsUnknown)
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ClassThatIsNotReflected_ReturnsUnknown)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace AzFramework::ProjectManager
|
||||
}
|
||||
AZ::IO::FixedMaxPath pythonPath = engineRootPath / "python";
|
||||
pythonPath /= AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL;
|
||||
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s %s%s --executable_path=%s --parent_pid=%" PRId64, pythonPath.Native().c_str(),
|
||||
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s %s%s --executable_path=%s --parent_pid=%" PRIu32, pythonPath.Native().c_str(),
|
||||
debugOption.c_str(), (projectManagerPath / projectsScript).c_str(), executablePath.c_str(), AZ::Platform::GetCurrentProcessId());
|
||||
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Scene::UnsetSubsystem(const T& system)
|
||||
bool Scene::UnsetSubsystem([[maybe_unused]] const T& system)
|
||||
{
|
||||
const AZ::TypeId& targetType = azrtti_typeid<T>();
|
||||
const size_t systemKeysCount = m_systemKeys.size();
|
||||
|
||||
@@ -12,14 +12,150 @@
|
||||
|
||||
#include "CameraInput.h"
|
||||
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <AzCore/Math/Plane.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void CameraSystem::HandleEvents(const InputEvent& event)
|
||||
AZ_CVAR(
|
||||
float, ed_cameraSystemDefaultPlaneHeight, 34.0f, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"The default height of the ground plane to do intersection tests against when orbiting");
|
||||
AZ_CVAR(float, ed_cameraSystemBoostMultiplier, 3.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemTranslateSpeed, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemOrbitDollyScrollSpeed, 0.02f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemOrbitDollyCursorSpeed, 0.01f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemScrollTranslateSpeed, 0.02f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemDefaultOrbitDistance, 60.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemMaxOrbitDistance, 100.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemLookSmoothness, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemTranslateSmoothness, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemRotateSpeed, 0.005f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemPanSpeed, 0.01f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(bool, ed_cameraSystemPanInvertX, true, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(bool, ed_cameraSystemPanInvertY, true, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateForwardKey, "keyboard_key_alphanumeric_W", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateBackwardKey, "keyboard_key_alphanumeric_S", nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateLeftKey, "keyboard_key_alphanumeric_A", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateRightKey, "keyboard_key_alphanumeric_D", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemTranslateUpKey, "keyboard_key_alphanumeric_E", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateDownKey, "keyboard_key_alphanumeric_Q", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateBoostKey, "keyboard_key_modifier_shift_l", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitKey, "keyboard_key_modifier_alt_l", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemFreeLookButton, "mouse_button_right", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemFreePanButton, "mouse_button_middle", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitLookButton, "mouse_button_left", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitDollyButton, "mouse_button_right", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitPanButton, "mouse_button_middle", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
|
||||
static InputChannelId CameraTranslateForwardId;
|
||||
static InputChannelId CameraTranslateBackwardId;
|
||||
static InputChannelId CameraTranslateLeftId;
|
||||
static InputChannelId CameraTranslateRightId;
|
||||
static InputChannelId CameraTranslateDownId;
|
||||
static InputChannelId CameraTranslateUpId;
|
||||
static InputChannelId CameraTranslateBoostId;
|
||||
static InputChannelId CameraOrbitId;
|
||||
|
||||
// externed elsewhere
|
||||
InputChannelId CameraFreeLookButton;
|
||||
InputChannelId CameraFreePanButton;
|
||||
InputChannelId CameraOrbitLookButton;
|
||||
InputChannelId CameraOrbitDollyButton;
|
||||
InputChannelId CameraOrbitPanButton;
|
||||
|
||||
void ReloadCameraKeyBindings()
|
||||
{
|
||||
const AZ::CVarFixedString& forward = ed_cameraSystemTranslateForwardKey;
|
||||
CameraTranslateForwardId = InputChannelId(forward.c_str());
|
||||
const AZ::CVarFixedString& backward = ed_cameraSystemTranslateBackwardKey;
|
||||
CameraTranslateBackwardId = InputChannelId(backward.c_str());
|
||||
const AZ::CVarFixedString& left = ed_cameraSystemTranslateLeftKey;
|
||||
CameraTranslateLeftId = InputChannelId(left.c_str());
|
||||
const AZ::CVarFixedString& right = ed_cameraSystemTranslateRightKey;
|
||||
CameraTranslateRightId = InputChannelId(right.c_str());
|
||||
const AZ::CVarFixedString& down = ed_cameraSystemTranslateDownKey;
|
||||
CameraTranslateDownId = InputChannelId(down.c_str());
|
||||
const AZ::CVarFixedString& up = ed_cameraSystemTranslateUpKey;
|
||||
CameraTranslateUpId = InputChannelId(up.c_str());
|
||||
const AZ::CVarFixedString& boost = ed_cameraSystemTranslateBoostKey;
|
||||
CameraTranslateBoostId = InputChannelId(boost.c_str());
|
||||
const AZ::CVarFixedString& orbit = ed_cameraSystemOrbitKey;
|
||||
CameraOrbitId = InputChannelId(orbit.c_str());
|
||||
const AZ::CVarFixedString& freeLook = ed_cameraSystemFreeLookButton;
|
||||
CameraFreeLookButton = InputChannelId(freeLook.c_str());
|
||||
const AZ::CVarFixedString& freePan = ed_cameraSystemFreePanButton;
|
||||
CameraFreePanButton = InputChannelId(freePan.c_str());
|
||||
const AZ::CVarFixedString& orbitLook = ed_cameraSystemOrbitLookButton;
|
||||
CameraOrbitLookButton = InputChannelId(orbitLook.c_str());
|
||||
const AZ::CVarFixedString& orbitDolly = ed_cameraSystemOrbitDollyButton;
|
||||
CameraOrbitDollyButton = InputChannelId(orbitDolly.c_str());
|
||||
const AZ::CVarFixedString& orbitPan = ed_cameraSystemOrbitPanButton;
|
||||
CameraOrbitPanButton = InputChannelId(orbitPan.c_str());
|
||||
}
|
||||
|
||||
static void ReloadCameraKeyBindingsConsole(const AZ::ConsoleCommandContainer&)
|
||||
{
|
||||
ReloadCameraKeyBindings();
|
||||
}
|
||||
|
||||
AZ_CONSOLEFREEFUNC(ReloadCameraKeyBindingsConsole, AZ::ConsoleFunctorFlags::Null, "Reload keybindings for the modern camera system");
|
||||
|
||||
// Based on paper by David Eberly - https://www.geometrictools.com/Documentation/EulerAngles.pdf
|
||||
AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation)
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
// 2.4 Factor as RzRyRx
|
||||
if (orientation.GetElement(2, 0) < 1.0f)
|
||||
{
|
||||
if (orientation.GetElement(2, 0) > -1.0f)
|
||||
{
|
||||
x = std::atan2(orientation.GetElement(2, 1), orientation.GetElement(2, 2));
|
||||
y = std::asin(-orientation.GetElement(2, 0));
|
||||
z = std::atan2(orientation.GetElement(1, 0), orientation.GetElement(0, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0.0f;
|
||||
y = AZ::Constants::Pi * 0.5f;
|
||||
z = -std::atan2(-orientation.GetElement(2, 1), orientation.GetElement(1, 1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0.0f;
|
||||
y = -AZ::Constants::Pi * 0.5f;
|
||||
z = std::atan2(-orientation.GetElement(1, 2), orientation.GetElement(1, 1));
|
||||
}
|
||||
|
||||
return {x, y, z};
|
||||
}
|
||||
|
||||
void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform)
|
||||
{
|
||||
const auto eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(transform));
|
||||
|
||||
camera.m_lookAt = transform.GetTranslation();
|
||||
camera.m_pitch = eulerAngles.GetX();
|
||||
camera.m_yaw = eulerAngles.GetZ();
|
||||
}
|
||||
|
||||
bool CameraSystem::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto& cursor_motion = AZStd::get_if<CursorMotionEvent>(&event))
|
||||
{
|
||||
@@ -30,10 +166,10 @@ namespace AzFramework
|
||||
m_scrollDelta = scroll->m_delta;
|
||||
}
|
||||
|
||||
m_cameras.HandleEvents(event);
|
||||
return m_cameras.HandleEvents(event);
|
||||
}
|
||||
|
||||
Camera CameraSystem::StepCamera(const Camera& targetCamera, float deltaTime)
|
||||
Camera CameraSystem::StepCamera(const Camera& targetCamera, const float deltaTime)
|
||||
{
|
||||
const auto cursorDelta = m_currentCursorPosition.has_value() && m_lastCursorPosition.has_value()
|
||||
? m_currentCursorPosition.value() - m_lastCursorPosition.value()
|
||||
@@ -51,36 +187,41 @@ namespace AzFramework
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void Cameras::AddCamera(AZStd::shared_ptr<CameraInput> camera_input)
|
||||
void Cameras::AddCamera(AZStd::shared_ptr<CameraInput> cameraInput)
|
||||
{
|
||||
m_idleCameraInputs.push_back(AZStd::move(camera_input));
|
||||
m_idleCameraInputs.push_back(AZStd::move(cameraInput));
|
||||
}
|
||||
|
||||
void Cameras::HandleEvents(const InputEvent& event)
|
||||
bool Cameras::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
for (auto& camera_input : m_activeCameraInputs)
|
||||
bool handling = false;
|
||||
for (auto& cameraInput : m_activeCameraInputs)
|
||||
{
|
||||
camera_input->HandleEvents(event);
|
||||
cameraInput->HandleEvents(event);
|
||||
handling = !cameraInput->Idle() || handling;
|
||||
}
|
||||
|
||||
for (auto& camera_input : m_idleCameraInputs)
|
||||
for (auto& cameraInput : m_idleCameraInputs)
|
||||
{
|
||||
camera_input->HandleEvents(event);
|
||||
cameraInput->HandleEvents(event);
|
||||
}
|
||||
|
||||
return handling;
|
||||
}
|
||||
|
||||
Camera Cameras::StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, const float deltaTime)
|
||||
Camera Cameras::StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime)
|
||||
{
|
||||
for (int i = 0; i < m_idleCameraInputs.size();)
|
||||
{
|
||||
auto& camera_input = m_idleCameraInputs[i];
|
||||
const bool can_begin = camera_input->Beginning() &&
|
||||
auto& cameraInput = m_idleCameraInputs[i];
|
||||
const bool canBegin = cameraInput->Beginning() &&
|
||||
std::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(),
|
||||
[](const auto& input) { return !input->Exclusive(); }) &&
|
||||
(!camera_input->Exclusive() || (camera_input->Exclusive() && m_activeCameraInputs.empty()));
|
||||
if (can_begin)
|
||||
(!cameraInput->Exclusive() || (cameraInput->Exclusive() && m_activeCameraInputs.empty()));
|
||||
|
||||
if (canBegin)
|
||||
{
|
||||
m_activeCameraInputs.push_back(camera_input);
|
||||
m_activeCameraInputs.push_back(cameraInput);
|
||||
using AZStd::swap;
|
||||
swap(m_idleCameraInputs[i], m_idleCameraInputs[m_idleCameraInputs.size() - 1]);
|
||||
m_idleCameraInputs.pop_back();
|
||||
@@ -93,25 +234,25 @@ namespace AzFramework
|
||||
|
||||
// accumulate
|
||||
Camera nextCamera = targetCamera;
|
||||
for (auto& camera_input : m_activeCameraInputs)
|
||||
for (auto& cameraInput : m_activeCameraInputs)
|
||||
{
|
||||
nextCamera = camera_input->StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
|
||||
nextCamera = cameraInput->StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_activeCameraInputs.size();)
|
||||
{
|
||||
auto& camera_input = m_activeCameraInputs[i];
|
||||
if (camera_input->Ending())
|
||||
auto& cameraInput = m_activeCameraInputs[i];
|
||||
if (cameraInput->Ending())
|
||||
{
|
||||
camera_input->ClearActivation();
|
||||
m_idleCameraInputs.push_back(camera_input);
|
||||
cameraInput->ClearActivation();
|
||||
m_idleCameraInputs.push_back(cameraInput);
|
||||
using AZStd::swap;
|
||||
swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
|
||||
m_activeCameraInputs.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
camera_input->ContinueActivation();
|
||||
cameraInput->ContinueActivation();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -134,7 +275,7 @@ namespace AzFramework
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == m_channelId)
|
||||
if (input->m_channelId == m_rotateChannelId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
@@ -154,14 +295,14 @@ namespace AzFramework
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
nextCamera.m_pitch += float(cursorDelta.m_y) * m_props.m_rotateSpeed;
|
||||
nextCamera.m_yaw += float(cursorDelta.m_x) * m_props.m_rotateSpeed;
|
||||
nextCamera.m_pitch -= float(cursorDelta.m_y) * ed_cameraSystemRotateSpeed;
|
||||
nextCamera.m_yaw -= float(cursorDelta.m_x) * ed_cameraSystemRotateSpeed;
|
||||
|
||||
auto clamp_rotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoOverPi, AZ::Constants::TwoOverPi); };
|
||||
const auto clampRotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); };
|
||||
|
||||
nextCamera.m_yaw = clamp_rotation(nextCamera.m_yaw);
|
||||
nextCamera.m_yaw = clampRotation(nextCamera.m_yaw);
|
||||
// clamp pitch to be +-90 degrees
|
||||
nextCamera.m_pitch = AZ::GetClamp(nextCamera.m_pitch, -AZ::Constants::Pi * 0.5f, AZ::Constants::Pi * 0.5f);
|
||||
nextCamera.m_pitch = AZ::GetClamp(nextCamera.m_pitch, -AZ::Constants::HalfPi, AZ::Constants::HalfPi);
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
@@ -170,7 +311,7 @@ namespace AzFramework
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceMouse::Button::Middle)
|
||||
if (input->m_channelId == m_panChannelId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
@@ -190,51 +331,50 @@ namespace AzFramework
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
const auto pan_axes = m_panAxesFn(nextCamera);
|
||||
const auto panAxes = m_panAxesFn(nextCamera);
|
||||
|
||||
const auto delta_pan_x = float(cursorDelta.m_x) * pan_axes.m_horizontalAxis * m_props.m_panSpeed;
|
||||
const auto delta_pan_y = float(cursorDelta.m_y) * pan_axes.m_verticalAxis * m_props.m_panSpeed;
|
||||
const auto deltaPanX = float(cursorDelta.m_x) * panAxes.m_horizontalAxis * ed_cameraSystemPanSpeed;
|
||||
const auto deltaPanY = float(cursorDelta.m_y) * panAxes.m_verticalAxis * ed_cameraSystemPanSpeed;
|
||||
|
||||
const auto inv = [](const bool invert) {
|
||||
constexpr float Dir[] = {1.0f, -1.0f};
|
||||
return Dir[static_cast<int>(invert)];
|
||||
};
|
||||
|
||||
nextCamera.m_lookAt += delta_pan_x * inv(m_props.m_panInvertX);
|
||||
nextCamera.m_lookAt += delta_pan_y * -inv(m_props.m_panInvertY);
|
||||
nextCamera.m_lookAt += deltaPanX * inv(ed_cameraSystemPanInvertX);
|
||||
nextCamera.m_lookAt += deltaPanY * -inv(ed_cameraSystemPanInvertY);
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
TranslateCameraInput::TranslationType TranslateCameraInput::translationFromKey(InputChannelId channelId)
|
||||
{
|
||||
// note: remove hard-coded InputDevice keys
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericW)
|
||||
if (channelId == CameraTranslateForwardId)
|
||||
{
|
||||
return TranslationType::Forward;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericS)
|
||||
if (channelId == CameraTranslateBackwardId)
|
||||
{
|
||||
return TranslationType::Backward;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericA)
|
||||
if (channelId == CameraTranslateLeftId)
|
||||
{
|
||||
return TranslationType::Left;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericD)
|
||||
if (channelId == CameraTranslateRightId)
|
||||
{
|
||||
return TranslationType::Right;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericQ)
|
||||
if (channelId == CameraTranslateDownId)
|
||||
{
|
||||
return TranslationType::Down;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericE)
|
||||
if (channelId == CameraTranslateUpId)
|
||||
{
|
||||
return TranslationType::Up;
|
||||
}
|
||||
@@ -259,19 +399,19 @@ namespace AzFramework
|
||||
BeginActivation();
|
||||
}
|
||||
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierShiftL)
|
||||
if (input->m_channelId == CameraTranslateBoostId)
|
||||
{
|
||||
m_boost = true;
|
||||
}
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
{
|
||||
m_translation ^= translationFromKey(input->m_channelId);
|
||||
m_translation &= ~(translationFromKey(input->m_channelId));
|
||||
if (m_translation == TranslationType::Nil)
|
||||
{
|
||||
EndActivation();
|
||||
}
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierShiftL)
|
||||
if (input->m_channelId == CameraTranslateBoostId)
|
||||
{
|
||||
m_boost = false;
|
||||
}
|
||||
@@ -285,13 +425,13 @@ namespace AzFramework
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
const auto translation_basis = m_translationAxesFn(nextCamera);
|
||||
const auto axisX = translation_basis.GetBasisX();
|
||||
const auto axisY = translation_basis.GetBasisY();
|
||||
const auto axisZ = translation_basis.GetBasisZ();
|
||||
const auto translationBasis = m_translationAxesFn(nextCamera);
|
||||
const auto axisX = translationBasis.GetBasisX();
|
||||
const auto axisY = translationBasis.GetBasisY();
|
||||
const auto axisZ = translationBasis.GetBasisZ();
|
||||
|
||||
const float speed = [boost = m_boost, props = m_props]() {
|
||||
return props.m_translateSpeed * (boost ? props.m_boostMultiplier : 1.0f);
|
||||
const float speed = [boost = m_boost]() {
|
||||
return ed_cameraSystemTranslateSpeed * (boost ? ed_cameraSystemBoostMultiplier : 1.0f);
|
||||
}();
|
||||
|
||||
if ((m_translation & TranslationType::Forward) == TranslationType::Forward)
|
||||
@@ -342,12 +482,8 @@ namespace AzFramework
|
||||
{
|
||||
if (const auto* input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierAltL)
|
||||
if (input->m_channelId == CameraOrbitId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Updated)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
BeginActivation();
|
||||
@@ -358,7 +494,7 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
|
||||
if (Active())
|
||||
{
|
||||
m_orbitCameras.HandleEvents(event);
|
||||
@@ -366,29 +502,29 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
Camera OrbitCameraInput::StepCamera(
|
||||
const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, float deltaTime)
|
||||
const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
if (Beginning())
|
||||
{
|
||||
float hit_distance = 0.0f;
|
||||
if (AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateZero())
|
||||
.CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY() * m_props.m_maxOrbitDistance, hit_distance))
|
||||
if (AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateAxisZ(ed_cameraSystemDefaultPlaneHeight))
|
||||
.CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY(), hit_distance))
|
||||
{
|
||||
hit_distance = AZStd::min<float>(hit_distance, ed_cameraSystemMaxOrbitDistance);
|
||||
nextCamera.m_lookDist = -hit_distance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * hit_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextCamera.m_lookDist = -m_props.m_defaultOrbitDistance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * m_props.m_defaultOrbitDistance;
|
||||
nextCamera.m_lookDist = -ed_cameraSystemMaxOrbitDistance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * ed_cameraSystemMaxOrbitDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if (Active())
|
||||
{
|
||||
// todo: need to return nested cameras to idle state when ending
|
||||
nextCamera = m_orbitCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
|
||||
}
|
||||
|
||||
@@ -413,10 +549,10 @@ namespace AzFramework
|
||||
|
||||
Camera OrbitDollyScrollCameraInput::StepCamera(
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta,
|
||||
[[maybe_unused]] float deltaTime)
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + scrollDelta * m_props.m_dollySpeed, 0.0f);
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + scrollDelta * ed_cameraSystemOrbitDollyScrollSpeed, 0.0f);
|
||||
EndActivation();
|
||||
return nextCamera;
|
||||
}
|
||||
@@ -425,7 +561,7 @@ namespace AzFramework
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceMouse::Button::Right)
|
||||
if (input->m_channelId == m_dollyChannelId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
@@ -444,7 +580,7 @@ namespace AzFramework
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + float(cursorDelta.m_y) * m_props.m_dollySpeed, 0.0f);
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + float(cursorDelta.m_y) * ed_cameraSystemOrbitDollyCursorSpeed, 0.0f);
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
@@ -457,7 +593,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
Camera ScrollTranslationCameraInput::StepCamera(
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, float scrollDelta,
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta,
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
@@ -465,38 +601,39 @@ namespace AzFramework
|
||||
const auto translation_basis = LookTranslation(nextCamera);
|
||||
const auto axisY = translation_basis.GetBasisY();
|
||||
|
||||
nextCamera.m_lookAt += axisY * scrollDelta * m_props.m_translateSpeed;
|
||||
nextCamera.m_lookAt += axisY * scrollDelta * ed_cameraSystemScrollTranslateSpeed;
|
||||
|
||||
EndActivation();
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const SmoothProps& props, const float deltaTime)
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const float deltaTime)
|
||||
{
|
||||
const auto clamp_rotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); };
|
||||
|
||||
// keep yaw in 0 - 360 range
|
||||
float target_yaw = clamp_rotation(targetCamera.m_yaw);
|
||||
const float current_yaw = clamp_rotation(currentCamera.m_yaw);
|
||||
float targetYaw = clamp_rotation(targetCamera.m_yaw);
|
||||
const float currentYaw = clamp_rotation(currentCamera.m_yaw);
|
||||
|
||||
auto sign = [](const float value) { return static_cast<float>((0.0f < value) - (value < 0.0f)); };
|
||||
// return the sign of the float input (-1, 0, 1)
|
||||
const auto sign = [](const float value) { return aznumeric_cast<float>((0.0f < value) - (value < 0.0f)); };
|
||||
|
||||
// ensure smooth transition when moving across 0 - 360 boundary
|
||||
const float yaw_delta = target_yaw - current_yaw;
|
||||
if (std::abs(yaw_delta) >= AZ::Constants::Pi)
|
||||
const float yawDelta = targetYaw - currentYaw;
|
||||
if (std::abs(yawDelta) >= AZ::Constants::Pi)
|
||||
{
|
||||
target_yaw -= AZ::Constants::TwoPi * sign(yaw_delta);
|
||||
targetYaw -= AZ::Constants::TwoPi * sign(yawDelta);
|
||||
}
|
||||
|
||||
Camera camera;
|
||||
// note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent
|
||||
// note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent
|
||||
// article by Scott Lembcke: https://www.gamasutra.com/blogs/ScottLembcke/20180404/316046/Improved_Lerp_Smoothing.php
|
||||
const float lookRate = std::exp2(props.m_lookSmoothness);
|
||||
const float lookRate = std::exp2(ed_cameraSystemLookSmoothness);
|
||||
const float lookT = std::exp2(-lookRate * deltaTime);
|
||||
camera.m_pitch = AZ::Lerp(targetCamera.m_pitch, currentCamera.m_pitch, lookT);
|
||||
camera.m_yaw = AZ::Lerp(target_yaw, current_yaw, lookT);
|
||||
const float moveRate = std::exp2(props.m_moveSmoothness);
|
||||
camera.m_yaw = AZ::Lerp(targetYaw, currentYaw, lookT);
|
||||
const float moveRate = std::exp2(ed_cameraSystemTranslateSmoothness);
|
||||
const float moveT = std::exp2(-moveRate * deltaTime);
|
||||
camera.m_lookDist = AZ::Lerp(targetCamera.m_lookDist, currentCamera.m_lookDist, moveT);
|
||||
camera.m_lookAt = targetCamera.m_lookAt.Lerp(currentCamera.m_lookAt, moveT);
|
||||
@@ -508,20 +645,24 @@ namespace AzFramework
|
||||
const auto& inputChannelId = inputChannel.GetInputChannelId();
|
||||
const auto& inputDeviceId = inputChannel.GetInputDevice().GetInputDeviceId();
|
||||
|
||||
if (inputChannelId == InputDeviceMouse::SystemCursorPosition)
|
||||
const bool wasMouseButton =
|
||||
AZStd::any_of(InputDeviceMouse::Button::All.begin(), InputDeviceMouse::Button::All.end(), [inputChannelId](const auto& button) {
|
||||
return button == inputChannelId;
|
||||
});
|
||||
|
||||
if (inputChannelId == InputDeviceMouse::Movement::X || inputChannelId == InputDeviceMouse::Movement::Y)
|
||||
{
|
||||
AZ::Vector2 systemCursorPositionNormalized = AZ::Vector2::CreateZero();
|
||||
InputSystemCursorRequestBus::EventResult(
|
||||
systemCursorPositionNormalized, inputDeviceId, &InputSystemCursorRequestBus::Events::GetSystemCursorPositionNormalized);
|
||||
const auto* position = inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
|
||||
AZ_Assert(position, "Expected PositionData2D but found nullptr");
|
||||
|
||||
return CursorMotionEvent{ScreenPoint(
|
||||
systemCursorPositionNormalized.GetX() * windowSize.m_width, systemCursorPositionNormalized.GetY() * windowSize.m_height)};
|
||||
position->m_normalizedPosition.GetX() * windowSize.m_width, position->m_normalizedPosition.GetY() * windowSize.m_height)};
|
||||
}
|
||||
else if (inputChannelId == InputDeviceMouse::Movement::Z)
|
||||
{
|
||||
return ScrollEvent{inputChannel.GetValue()};
|
||||
}
|
||||
else if (InputDeviceMouse::IsMouseDevice(inputDeviceId) || InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId))
|
||||
else if (wasMouseButton || InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId))
|
||||
{
|
||||
return DiscreteInputEvent{inputChannelId, inputChannel.GetState()};
|
||||
}
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
#include <AzCore/std/containers/variant.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzFramework/Input/Channels/InputChannel.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct WindowSize;
|
||||
//! Update camera key bindings that can be overridden with AZ console vars (invoke from console to update)
|
||||
void ReloadCameraKeyBindings();
|
||||
|
||||
//! Return Euler angles (pitch, roll, yaw) for the incoming orientation.
|
||||
AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation);
|
||||
|
||||
struct Camera
|
||||
{
|
||||
@@ -51,8 +54,8 @@ namespace AzFramework
|
||||
|
||||
inline AZ::Transform Camera::Transform() const
|
||||
{
|
||||
return AZ::Transform::CreateTranslation(m_lookAt) * AZ::Transform::CreateRotationX(m_pitch) *
|
||||
AZ::Transform::CreateRotationZ(m_yaw) * AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisZ(m_lookDist));
|
||||
return AZ::Transform::CreateTranslation(m_lookAt) * AZ::Transform::CreateRotationZ(m_yaw) *
|
||||
AZ::Transform::CreateRotationX(m_pitch) * AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(m_lookDist));
|
||||
}
|
||||
|
||||
inline AZ::Matrix3x3 Camera::Rotation() const
|
||||
@@ -65,6 +68,8 @@ namespace AzFramework
|
||||
return Transform().GetTranslation();
|
||||
}
|
||||
|
||||
void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform);
|
||||
|
||||
struct CursorMotionEvent
|
||||
{
|
||||
ScreenPoint m_position;
|
||||
@@ -159,19 +164,13 @@ namespace AzFramework
|
||||
Activation m_activation = Activation::Idle;
|
||||
};
|
||||
|
||||
struct SmoothProps
|
||||
{
|
||||
float m_lookSmoothness = 5.0f;
|
||||
float m_moveSmoothness = 5.0f;
|
||||
};
|
||||
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const SmoothProps& props, float deltaTime);
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, float deltaTime);
|
||||
|
||||
class Cameras
|
||||
{
|
||||
public:
|
||||
void AddCamera(AZStd::shared_ptr<CameraInput> cameraInput);
|
||||
void HandleEvents(const InputEvent& event);
|
||||
bool HandleEvents(const InputEvent& event);
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime);
|
||||
void Reset();
|
||||
|
||||
@@ -183,7 +182,7 @@ namespace AzFramework
|
||||
class CameraSystem
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event);
|
||||
bool HandleEvents(const InputEvent& event);
|
||||
Camera StepCamera(const Camera& targetCamera, float deltaTime);
|
||||
|
||||
Cameras m_cameras;
|
||||
@@ -197,19 +196,16 @@ namespace AzFramework
|
||||
class RotateCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
explicit RotateCameraInput(const InputChannelId channelId)
|
||||
: m_channelId(channelId)
|
||||
explicit RotateCameraInput(const InputChannelId rotateChannelId)
|
||||
: m_rotateChannelId(rotateChannelId)
|
||||
{
|
||||
}
|
||||
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
InputChannelId m_channelId;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_rotateSpeed = 0.005f;
|
||||
} m_props;
|
||||
private:
|
||||
InputChannelId m_rotateChannelId;
|
||||
};
|
||||
|
||||
struct PanAxes
|
||||
@@ -242,22 +238,17 @@ namespace AzFramework
|
||||
class PanCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
explicit PanCameraInput(PanAxesFn panAxesFn)
|
||||
PanCameraInput(const InputChannelId panChannelId, PanAxesFn panAxesFn)
|
||||
: m_panAxesFn(AZStd::move(panAxesFn))
|
||||
, m_panChannelId(panChannelId)
|
||||
{
|
||||
}
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_panSpeed = 0.01f;
|
||||
bool m_panInvertX = true;
|
||||
bool m_panInvertY = true;
|
||||
} m_props;
|
||||
|
||||
private:
|
||||
PanAxesFn m_panAxesFn;
|
||||
InputChannelId m_panChannelId;
|
||||
};
|
||||
|
||||
using TranslationAxesFn = AZStd::function<AZ::Matrix3x3(const Camera& camera)>;
|
||||
@@ -298,17 +289,11 @@ namespace AzFramework
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
void ResetImpl() override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_translateSpeed = 10.0f;
|
||||
float m_boostMultiplier = 3.0f;
|
||||
} m_props;
|
||||
|
||||
private:
|
||||
enum class TranslationType
|
||||
{
|
||||
// clang-format off
|
||||
Nil = 0,
|
||||
Nil = 0,
|
||||
Forward = 1 << 0,
|
||||
Backward = 1 << 1,
|
||||
Left = 1 << 2,
|
||||
@@ -354,6 +339,11 @@ namespace AzFramework
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend TranslationType operator~(const TranslationType lhs)
|
||||
{
|
||||
return static_cast<TranslationType>(~static_cast<std::underlying_type_t<TranslationType>>(lhs));
|
||||
}
|
||||
|
||||
static TranslationType translationFromKey(InputChannelId channelId);
|
||||
|
||||
TranslationType m_translation = TranslationType::Nil;
|
||||
@@ -366,23 +356,19 @@ namespace AzFramework
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_dollySpeed = 0.2f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
class OrbitDollyCursorMoveCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
explicit OrbitDollyCursorMoveCameraInput(const InputChannelId dollyChannelId)
|
||||
: m_dollyChannelId(dollyChannelId) {}
|
||||
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_dollySpeed = 0.1f;
|
||||
} m_props;
|
||||
private:
|
||||
InputChannelId m_dollyChannelId;
|
||||
};
|
||||
|
||||
class ScrollTranslationCameraInput : public CameraInput
|
||||
@@ -390,11 +376,6 @@ namespace AzFramework
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_translateSpeed = 0.2f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
class OrbitCameraInput : public CameraInput
|
||||
@@ -408,13 +389,10 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
Cameras m_orbitCameras;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_defaultOrbitDistance = 15.0f;
|
||||
float m_maxOrbitDistance = 100.0f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
struct WindowSize;
|
||||
|
||||
//! Map from a generic InputChannel event to a camera specific InputEvent.
|
||||
InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize);
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -14,7 +14,6 @@ set(FILES
|
||||
AzFrameworkModule.h
|
||||
AzFrameworkModule.cpp
|
||||
API/ApplicationAPI.h
|
||||
API/AtomActiveInterface.h
|
||||
Application/Application.cpp
|
||||
Application/Application.h
|
||||
Archive/Archive.cpp
|
||||
|
||||
-1
@@ -16,7 +16,6 @@
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
|
||||
#include <AzFramework/API/AtomActiveInterface.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
namespace AzQtComponents
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
struct BehaviorParameter;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -40,6 +46,8 @@ namespace AzToolsFramework
|
||||
};
|
||||
using GlobalFunctionCollection = AZStd::vector<GlobalFunction>;
|
||||
virtual void GetGlobalFunctionList(GlobalFunctionCollection& globalFunctionCollection) const = 0;
|
||||
|
||||
virtual AZStd::string FetchPythonTypeName(const AZ::BehaviorParameter& param) = 0;
|
||||
};
|
||||
|
||||
//! Interface to signal the phases for the Python virtual machine
|
||||
|
||||
+4
-9
@@ -10,8 +10,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/FolderThumbnail.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <QPixmap>
|
||||
@@ -50,8 +50,8 @@ namespace AzToolsFramework
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// FolderThumbnail
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static constexpr const char* FolderIconPath = "Icons/AssetBrowser/Folder_16.svg";
|
||||
static constexpr const char* GemIconPath = "Icons/AssetBrowser/GemFolder_16.svg";
|
||||
static constexpr const char* FolderIconPath = "Assets/Editor/Icons/AssetBrowser/Folder_16.svg";
|
||||
static constexpr const char* GemIconPath = "Assets/Editor/Icons/AssetBrowser/GemFolder_16.svg";
|
||||
|
||||
FolderThumbnail::FolderThumbnail(SharedThumbnailKey key)
|
||||
: Thumbnail(key)
|
||||
@@ -62,13 +62,8 @@ namespace AzToolsFramework
|
||||
auto folderKey = azrtti_cast<const FolderThumbnailKey*>(m_key.data());
|
||||
AZ_Assert(folderKey, "Incorrect key type, excpected FolderThumbnailKey");
|
||||
|
||||
const char* engineRoot = nullptr;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot);
|
||||
AZ_Assert(engineRoot, "Engine Root not initialized");
|
||||
const char* folderIcon = folderKey->IsGem() ? GemIconPath : FolderIconPath;
|
||||
AZStd::string absoluteIconPath;
|
||||
AZ::StringFunc::Path::Join(engineRoot, folderIcon, absoluteIconPath);
|
||||
|
||||
auto absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / folderIcon;
|
||||
m_pixmap.load(absoluteIconPath.c_str());
|
||||
m_state = m_pixmap.isNull() ? State::Failed : State::Ready;
|
||||
}
|
||||
|
||||
+6
-23
@@ -17,7 +17,7 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Asset/AssetBundleManifest.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
@@ -250,7 +250,7 @@ namespace AzToolsFramework
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
AZ_Assert(fileIO != nullptr, "AZ::IO::FileIOBase must be ready for use.\n");
|
||||
|
||||
AZStd::string bundleFilePath = assetBundleSettings.m_bundleFilePath;
|
||||
AZ::IO::Path bundleFilePath = AZ::IO::Path(AZStd::string_view{ AZ::Utils::GetEnginePath() }) / assetBundleSettings.m_bundleFilePath;
|
||||
|
||||
AzFramework::PlatformId platformId = static_cast<AzFramework::PlatformId>(AzFramework::PlatformHelper::GetPlatformIndexFromName(assetBundleSettings.m_platform.c_str()));
|
||||
|
||||
@@ -259,22 +259,13 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* appRoot = nullptr;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot);
|
||||
|
||||
if (AzFramework::StringFunc::Path::IsRelative(bundleFilePath.c_str()))
|
||||
{
|
||||
AzFramework::StringFunc::Path::ConstructFull(appRoot, bundleFilePath.c_str(), bundleFilePath, true);
|
||||
}
|
||||
|
||||
AZ::u64 maxSizeInBytes = static_cast<AZ::u64>(assetBundleSettings.m_maxBundleSizeInMB * NumOfBytesInMB);
|
||||
AZ::u64 assetCatalogFileSizeBuffer = static_cast<AZ::u64>(AssetCatalogFileSizeBufferPercentage * assetBundleSettings.m_maxBundleSizeInMB * NumOfBytesInMB) / 100;
|
||||
AZ::u64 bundleSize = 0;
|
||||
AZ::u64 totalFileSize = 0;
|
||||
int bundleIndex = 0;
|
||||
|
||||
AZStd::string bundleFullPath = bundleFilePath;
|
||||
AZStd::string tempBundleFilePath = bundleFullPath + "_temp";
|
||||
AZStd::string tempBundleFilePath = bundleFilePath.Native() + "_temp";
|
||||
|
||||
AZStd::vector<AZStd::string> dependentBundleNames;
|
||||
AZStd::vector<AZStd::string> levelDirs;
|
||||
@@ -301,7 +292,7 @@ namespace AzToolsFramework
|
||||
if (fileIO->Exists(bundleFilePath.c_str()))
|
||||
{
|
||||
// This will delete both the parent bundle as well as all the dependent bundles mentioned in the manifest file of the parent bundle.
|
||||
if (!DeleteBundleFiles(bundleFilePath))
|
||||
if (!DeleteBundleFiles(bundleFilePath.Native()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -390,7 +381,7 @@ namespace AzToolsFramework
|
||||
// we need to find a bundle which does not exist on disk;
|
||||
bundleIndex++;
|
||||
numOfTries--;
|
||||
dependentBundleFileName = CreateAssetBundleFileName(bundleFilePath, bundleIndex);
|
||||
dependentBundleFileName = CreateAssetBundleFileName(bundleFilePath.Native(), bundleIndex);
|
||||
AzFramework::StringFunc::Path::ReplaceFullName(tempBundleFilePath, (dependentBundleFileName + tempBundleFileSuffix).c_str());
|
||||
} while (numOfTries && fileIO->Exists(tempBundleFilePath.c_str()));
|
||||
|
||||
@@ -463,15 +454,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
|
||||
AZStd::string assetFileInfoListPath = assetBundleSettings.m_assetFileInfoListPath;
|
||||
|
||||
const char* appRoot = nullptr;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot);
|
||||
|
||||
if (AzFramework::StringFunc::Path::IsRelative(assetFileInfoListPath.c_str()))
|
||||
{
|
||||
AzFramework::StringFunc::Path::ConstructFull(appRoot, assetFileInfoListPath.c_str(), assetFileInfoListPath, true);
|
||||
}
|
||||
AZ::IO::Path assetFileInfoListPath = AZ::IO::Path{ AZStd::string_view{AZ::Utils::GetEnginePath()} } / assetBundleSettings.m_assetFileInfoListPath;
|
||||
|
||||
if (!fileIO->Exists(assetFileInfoListPath.c_str()))
|
||||
{
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiSystemComponent.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerComponent.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserComponent.h>
|
||||
#include <AzToolsFramework/MaterialBrowser/MaterialBrowserComponent.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -93,7 +92,6 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::SliceDependencyBrowserComponent::CreateDescriptor(),
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerComponent::CreateDescriptor(),
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserComponent::CreateDescriptor(),
|
||||
AzToolsFramework::MaterialBrowser::MaterialBrowserComponent::CreateDescriptor(),
|
||||
AzToolsFramework::EditorInteractionSystemComponent::CreateDescriptor(),
|
||||
AzToolsFramework::Components::EditorComponentAPIComponent::CreateDescriptor(),
|
||||
AzToolsFramework::Components::EditorLevelComponentAPIComponent::CreateDescriptor(),
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Data
|
||||
{
|
||||
struct AssetId;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace MaterialBrowser
|
||||
{
|
||||
class MaterialBrowserRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
|
||||
// Only a single handler is allowed
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
virtual bool HasRecord(const AZ::Data::AssetId& assetId) = 0;
|
||||
virtual bool IsMultiMaterial(const AZ::Data::AssetId& assetId) = 0;
|
||||
};
|
||||
|
||||
using MaterialBrowserRequestBus = AZ::EBus<MaterialBrowserRequests>;
|
||||
} // namespace MaterialBrowser
|
||||
} // namespace AzToolsFramework
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <AzToolsFramework/MaterialBrowser/MaterialBrowserComponent.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/FolderThumbnail.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.h>
|
||||
#include <AzToolsFramework/MaterialBrowser/MaterialThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/SourceControlThumbnail.h>
|
||||
|
||||
#include <QApplication>
|
||||
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QBrush::d': class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush'
|
||||
#include <QStyle>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace MaterialBrowser
|
||||
{
|
||||
MaterialBrowserComponent::MaterialBrowserComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void MaterialBrowserComponent::Activate()
|
||||
{
|
||||
using namespace Thumbnailer;
|
||||
using namespace AssetBrowser;
|
||||
const char* contextName = "MaterialBrowser";
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterContext, contextName);
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(FolderThumbnailCache), contextName);
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SourceThumbnailCache), contextName);
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(MaterialThumbnailCache), contextName);
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SourceControlThumbnailCache), contextName);
|
||||
}
|
||||
|
||||
void MaterialBrowserComponent::Deactivate()
|
||||
{
|
||||
}
|
||||
|
||||
void MaterialBrowserComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<MaterialBrowserComponent, AZ::Component>();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialBrowserComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
}
|
||||
} // namespace MaterialBrowser
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user