Merge remote-tracking branch 'remotes/origin/master' into clipper2

Conflicts:
	src/engine/engine.cpp
	src/engine/engine.h
	src/graphics/render_scene.cpp
This commit is contained in:
tluqo 2014-09-29 21:24:10 +02:00
commit 4a4c3c1ce8
90 changed files with 6331 additions and 3106 deletions

View file

@ -37,6 +37,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtEditor", "..\..\qteditor\
{A0A17BB4-760B-4E34-B1B0-3E43E5F2778A} = {A0A17BB4-760B-4E34-B1B0-3E43E5F2778A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "animation", "animation\animation.vcxproj", "{63F2E301-5062-4910-87FB-0243772F6852}"
ProjectSection(ProjectDependencies) = postProject
{E1A0C677-DE71-4AD8-B802-AA7A3332D822} = {E1A0C677-DE71-4AD8-B802-AA7A3332D822}
{A0A17BB4-760B-4E34-B1B0-3E43E5F2778A} = {A0A17BB4-760B-4E34-B1B0-3E43E5F2778A}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -64,27 +70,41 @@ Global
{4D15098E-177F-44EE-BF3C-FF0298E1BA33}.Debug|Win32.ActiveCfg = Debug|Win32
{4D15098E-177F-44EE-BF3C-FF0298E1BA33}.Debug|Win32.Build.0 = Debug|Win32
{4D15098E-177F-44EE-BF3C-FF0298E1BA33}.Debug|x64.ActiveCfg = Debug|x64
{4D15098E-177F-44EE-BF3C-FF0298E1BA33}.Debug|x64.Build.0 = Debug|x64
{4D15098E-177F-44EE-BF3C-FF0298E1BA33}.Release|Win32.ActiveCfg = Release|Win32
{4D15098E-177F-44EE-BF3C-FF0298E1BA33}.Release|Win32.Build.0 = Release|Win32
{4D15098E-177F-44EE-BF3C-FF0298E1BA33}.Release|x64.ActiveCfg = Release|x64
{4D15098E-177F-44EE-BF3C-FF0298E1BA33}.Release|x64.Build.0 = Release|x64
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Debug|Win32.ActiveCfg = Debug|Win32
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Debug|Win32.Build.0 = Debug|Win32
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Debug|x64.ActiveCfg = Debug|Win32
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Debug|x64.ActiveCfg = Debug|x64
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Debug|x64.Build.0 = Debug|x64
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Release|Win32.ActiveCfg = Release|Win32
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Release|Win32.Build.0 = Release|Win32
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Release|x64.ActiveCfg = Release|Win32
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Release|x64.ActiveCfg = Release|x64
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Release|x64.Build.0 = Release|x64
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Debug|Win32.ActiveCfg = Debug|Win32
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Debug|Win32.Build.0 = Debug|Win32
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Debug|x64.ActiveCfg = Debug|Win32
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Debug|x64.ActiveCfg = Debug|x64
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Debug|x64.Build.0 = Debug|x64
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Release|Win32.ActiveCfg = Release|Win32
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Release|Win32.Build.0 = Release|Win32
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Release|x64.ActiveCfg = Release|x64
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}.Release|x64.Build.0 = Release|x64
{D04C721A-BACC-3CE7-B285-D5A7D567F8BA}.Debug|Win32.ActiveCfg = Debug|Win32
{D04C721A-BACC-3CE7-B285-D5A7D567F8BA}.Debug|Win32.Build.0 = Debug|Win32
{D04C721A-BACC-3CE7-B285-D5A7D567F8BA}.Debug|x64.ActiveCfg = Debug|Win32
{D04C721A-BACC-3CE7-B285-D5A7D567F8BA}.Release|Win32.ActiveCfg = Release|Win32
{D04C721A-BACC-3CE7-B285-D5A7D567F8BA}.Release|Win32.Build.0 = Release|Win32
{D04C721A-BACC-3CE7-B285-D5A7D567F8BA}.Release|x64.ActiveCfg = Release|Win32
{63F2E301-5062-4910-87FB-0243772F6852}.Debug|Win32.ActiveCfg = Debug|Win32
{63F2E301-5062-4910-87FB-0243772F6852}.Debug|Win32.Build.0 = Debug|Win32
{63F2E301-5062-4910-87FB-0243772F6852}.Debug|x64.ActiveCfg = Debug|x64
{63F2E301-5062-4910-87FB-0243772F6852}.Debug|x64.Build.0 = Debug|x64
{63F2E301-5062-4910-87FB-0243772F6852}.Release|Win32.ActiveCfg = Release|Win32
{63F2E301-5062-4910-87FB-0243772F6852}.Release|Win32.Build.0 = Release|Win32
{63F2E301-5062-4910-87FB-0243772F6852}.Release|x64.ActiveCfg = Release|x64
{63F2E301-5062-4910-87FB-0243772F6852}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{63F2E301-5062-4910-87FB-0243772F6852}</ProjectGuid>
<RootNamespace>animation</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(SolutionDir)..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)..\..\bin\$(Platform)_$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(SolutionDir)..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)..\..\bin\$(Platform)_$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(SolutionDir)..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)..\..\bin\$(Platform)_$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(SolutionDir)..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)..\..\bin\$(Platform)_$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src</AdditionalIncludeDirectories>
<PreprocessorDefinitions>BUILDING_ANIMATION;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\bin\$(Platform)_$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src</AdditionalIncludeDirectories>
<PreprocessorDefinitions>BUILDING_ANIMATION;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\bin\$(Platform)_$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src</AdditionalIncludeDirectories>
<PreprocessorDefinitions>BUILDING_ANIMATION;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\bin\$(Platform)_$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src</AdditionalIncludeDirectories>
<PreprocessorDefinitions>BUILDING_ANIMATION;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\bin\$(Platform)_$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\animation\animation.cpp" />
<ClCompile Include="..\..\..\src\animation\animation_system.cpp" />
<ClCompile Include="..\..\..\src\core\new.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\animation\animation.h" />
<ClInclude Include="..\..\..\src\animation\animation_system.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\..\src\animation\animation.cpp" />
<ClCompile Include="..\..\..\src\animation\animation_system.cpp" />
<ClCompile Include="..\..\..\src\core\new.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\animation\animation.h" />
<ClInclude Include="..\..\..\src\animation\animation_system.h" />
</ItemGroup>
</Project>

View file

@ -161,8 +161,6 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\animation\animation.cpp" />
<ClCompile Include="..\..\..\src\animation\animation_system.cpp" />
<ClCompile Include="..\..\..\src\core\new.cpp" />
<ClCompile Include="..\..\..\src\editor\editor_icon.cpp" />
<ClCompile Include="..\..\..\src\editor\entity_template_system.cpp" />
@ -193,8 +191,6 @@
<ClCompile Include="..\..\..\src\universe\universe.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\animation\animation.h" />
<ClInclude Include="..\..\..\src\animation\animation_system.h" />
<ClInclude Include="..\..\..\src\editor\ieditor_command.h" />
<ClInclude Include="..\..\..\src\editor\editor_icon.h" />
<ClInclude Include="..\..\..\src\editor\entity_template_system.h" />

View file

@ -13,17 +13,8 @@
<Filter Include="graphics">
<UniqueIdentifier>{4958eded-acc7-41f8-ac9b-6f6bc47bd0ae}</UniqueIdentifier>
</Filter>
<Filter Include="animation">
<UniqueIdentifier>{240998ba-942c-45cf-a31c-06007274bd82}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\animation\animation.cpp">
<Filter>animation</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\animation\animation_system.cpp">
<Filter>animation</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\graphics\frame_buffer.cpp">
<Filter>graphics</Filter>
</ClCompile>
@ -108,12 +99,6 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\animation\animation.h">
<Filter>animation</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\animation\animation_system.h">
<Filter>animation</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\graphics\frame_buffer.h">
<Filter>graphics</Filter>
</ClInclude>

View file

@ -66,20 +66,20 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)\..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)\..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)\..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)\..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>

View file

@ -5,10 +5,18 @@
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\core\new.cpp" />
@ -16,6 +24,7 @@
<ClCompile Include="..\..\..\src\unit_tests\core\ut_fixed_lock_free_queue.cpp" />
<ClCompile Include="..\..\..\src\unit_tests\core\ut_hash_map.cpp">
<PreprocessToFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</PreprocessToFile>
<PreprocessToFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</PreprocessToFile>
</ClCompile>
<ClCompile Include="..\..\..\src\unit_tests\core\ut_mtjd_framework.cpp" />
<ClCompile Include="..\..\..\src\unit_tests\core\ut_path.cpp" />
@ -47,6 +56,12 @@
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
@ -54,26 +69,49 @@
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\..\..\bin\$(Platform)_$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\..\..\tmp\$(Platform)_$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
@ -86,7 +124,23 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>animation.lib;core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\bin\$(Platform)_$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\external\glew\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>animation.lib;core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\bin\$(Platform)_$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
@ -106,7 +160,27 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>animation.lib;core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\bin\$(Platform)_$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\external\glew\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>animation.lib;core.lib;engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\bin\$(Platform)_$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>

View file

@ -24,11 +24,13 @@ SOURCES += main.cpp\
scripts/scriptcompiler.cpp \
scripts/scriptcompilerwidget.cpp \
fileserverwidget.cpp \
materialmanager.cpp \
profilerui.cpp \
profilergraph.cpp \
pc/file_system_watcher.cpp \
entity_template_list.cpp
entity_template_list.cpp \
notifications.cpp \
insert_mesh_command.cpp \
entity_list.cpp
HEADERS += mainwindow.h \
sceneview.h \
@ -39,13 +41,15 @@ HEADERS += mainwindow.h \
scripts/scriptcompiler.h \
scripts/scriptcompilerwidget.h \
fileserverwidget.h \
materialmanager.h \
wgl_render_device.h \
renderdevicewidget.h \
profilerui.h \
profilergraph.h \
file_system_watcher.h \
entity_template_list.h
entity_template_list.h \
notifications.h \
insert_mesh_command.h \
entity_list.h
FORMS += mainwindow.ui \
logwidget.ui \
@ -54,15 +58,15 @@ FORMS += mainwindow.ui \
assetbrowser.ui \
scripts/scriptcompilerwidget.ui \
fileserverwidget.ui \
materialmanager.ui \
profilerui.ui \
profilergraph.ui \
entity_template_list.ui
entity_template_list.ui \
entity_list.ui
win32
{
INCLUDEPATH = ../../src \
../../external/glew/include
Release:LIBS = -L../../bin/Win32_Release -lcore -lengine -lopengl32 -lphysics
Debug:LIBS = -L../../bin/Win32_Debug -lcore -lengine -lopengl32 -lphysics
Release:LIBS = -L../../bin/Win32_Release -lcore -lengine -lopengl32 -lphysics -lanimation
Debug:LIBS = -L../../bin/Win32_Debug -lcore -lengine -lopengl32 -lphysics -lanimation
}

View file

@ -6,6 +6,7 @@
#include "core/resource_manager.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "insert_mesh_command.h"
#include <qfilesystemmodel.h>
#include <qlistwidget.h>
#include <qmenu.h>
@ -21,7 +22,7 @@ struct ProcessInfo
void getDefaultFilters(QStringList& filters)
{
filters << "*.msh" << "*.unv" << "*.ani" << "*.blend" << "*.tga" << "*.mat";
filters << "*.msh" << "*.unv" << "*.ani" << "*.blend" << "*.tga" << "*.mat" << "*.dds";
}
@ -32,7 +33,7 @@ AssetBrowser::AssetBrowser(QWidget* parent) :
m_watcher = FileSystemWatcher::create(QDir::currentPath().toLatin1().data());
m_watcher->getCallback().bind<AssetBrowser, &AssetBrowser::onFileSystemWatcherCallback>(this);
m_base_path = QDir::currentPath();
m_server = NULL;
m_editor = NULL;
m_ui->setupUi(this);
m_model = new QFileSystemModel;
m_model->setRootPath(QDir::currentPath());
@ -48,6 +49,7 @@ AssetBrowser::AssetBrowser(QWidget* parent) :
m_ui->treeView->hideColumn(4);
m_ui->listWidget->hide();
connect(this, SIGNAL(fileChanged(const QString&)), this, SLOT(onFileChanged(const QString&)));
connect(m_ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &AssetBrowser::onTreeViewSelectionChanged);
}
AssetBrowser::~AssetBrowser()
@ -57,6 +59,18 @@ AssetBrowser::~AssetBrowser()
}
void AssetBrowser::onTreeViewSelectionChanged(const QModelIndex&, const QModelIndex&)
{
/*if (current.isValid())
{
const QFileInfo& file_info = m_model->fileInfo(current);
QByteArray byte_array = file_info.filePath().toLower().toLatin1();
const char* filename = byte_array.data();
emit fileSelected(filename);
}*/
}
void AssetBrowser::onFileSystemWatcherCallback(const char* path)
{
emitFileChanged(path);
@ -72,21 +86,21 @@ void AssetBrowser::emitFileChanged(const char* path)
void AssetBrowser::handleDoubleClick(const QFileInfo& file_info)
{
const QString& suffix = file_info.suffix();
QString file =file_info.filePath().toLower();
QString file = file_info.filePath().toLower();
if(suffix == "unv")
{
m_server->loadUniverse(file.toLatin1().data());
m_editor->loadUniverse(file.toLatin1().data());
}
else if(suffix == "msh")
{
m_server->addEntity();
m_server->addComponent(crc32("renderable"));
m_server->setProperty("renderable", "source", file.toLatin1().data(), file.length());
InsertMeshCommand* command = new InsertMeshCommand(*m_editor, m_editor->getCameraRaycastHit(), file.toLatin1().data());
m_editor->executeCommand(command);
}
else if(suffix == "ani")
{
m_server->addComponent(crc32("animable"));
m_server->setProperty("animable", "preview", file.toLatin1().data(), file.length());
m_editor->addComponent(crc32("animable"));
m_editor->setProperty(crc32("animable"), -1, *m_editor->getProperty("animable", "preview"), file.toLatin1().data(), file.length());
}
}
@ -108,9 +122,9 @@ void AssetBrowser::onFileChanged(const QString& path)
exportAnimation(result_file_info);
exportModel(result_file_info);
}
else if(m_server)
else if(m_editor)
{
m_server->getEngine().getResourceManager().reload(path.toLatin1().data());
m_editor->getEngine().getResourceManager().reload(path.toLatin1().data());
}
}
@ -245,3 +259,14 @@ void AssetBrowser::on_filterComboBox_currentTextChanged(const QString&)
}
m_model->setNameFilters(filters);
}
void AssetBrowser::on_treeView_clicked(const QModelIndex &index)
{
if (index.isValid())
{
const QFileInfo& file_info = m_model->fileInfo(index);
QByteArray byte_array = file_info.filePath().toLower().toLatin1();
const char* filename = byte_array.data();
emit fileSelected(filename);
}
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <QDockWidget>
#include <qdockwidget.h>
#include <qitemselectionmodel.h>
namespace Lumix
{
@ -19,7 +20,7 @@ class AssetBrowser : public QDockWidget
public:
explicit AssetBrowser(QWidget* parent = NULL);
~AssetBrowser();
void setWorldEditor(Lumix::WorldEditor& server) { m_server = &server; }
void setWorldEditor(Lumix::WorldEditor& editor) { m_editor = &editor; }
void emitFileChanged(const char* path);
private:
@ -27,9 +28,11 @@ private:
void exportAnimation(const QFileInfo& file_info);
void exportModel(const QFileInfo& file_info);
void onFileSystemWatcherCallback(const char* path);
void onTreeViewSelectionChanged(const QModelIndex& current, const QModelIndex& previous);
signals:
void fileChanged(const QString& string);
void fileSelected(const char* path);
private slots:
void on_treeView_doubleClicked(const QModelIndex &index);
@ -40,10 +43,12 @@ private slots:
void on_exportFinished(int);
void on_filterComboBox_currentTextChanged(const QString &arg1);
private:
void on_treeView_clicked(const QModelIndex &index);
private:
Ui::AssetBrowser* m_ui;
class QFileSystemModel* m_model;
class FileSystemWatcher* m_watcher;
Lumix::WorldEditor* m_server;
Lumix::WorldEditor* m_editor;
QString m_base_path;
};

View file

@ -0,0 +1,287 @@
#include "entity_list.h"
#include "ui_entity_list.h"
#include "core/crc32.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "universe/entity.h"
static const char* component_map[] =
{
"Animable", "animable",
"Camera", "camera",
"Directional light", "light",
"Mesh", "renderable",
"Physics Box", "box_rigid_actor",
"Physics Controller", "physical_controller",
"Physics Mesh", "mesh_rigid_actor",
"Physics Heightfield", "physical_heightfield",
"Script", "script",
"Terrain", "terrain"
};
class EntityListFilter : public QSortFilterProxyModel
{
public:
EntityListFilter(QWidget* parent) : QSortFilterProxyModel(parent), m_component(0) {}
void filterComponent(uint32_t component) { m_component = component; }
void setUniverse(Lumix::Universe* universe) { m_universe = universe; invalidate(); }
void setWorldEditor(Lumix::WorldEditor& editor)
{
editor.entityNameSet().bind<EntityListFilter, &EntityListFilter::onEntityNameSet>(this);
}
protected:
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
{
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
if (m_component == 0)
{
return sourceModel()->data(index).toString().contains(filterRegExp());
}
int entity_index = sourceModel()->data(index, Qt::UserRole).toInt();
return Lumix::Entity(m_universe, entity_index).getComponent(m_component).isValid() && sourceModel()->data(index).toString().contains(filterRegExp());
}
void onEntityNameSet(const Lumix::Entity&, const char*)
{
invalidate();
}
private:
uint32_t m_component;
Lumix::Universe* m_universe;
};
class EntityListModel : public QAbstractItemModel
{
public:
EntityListModel(QWidget* parent, EntityListFilter* filter)
: QAbstractItemModel(parent)
{
m_universe = NULL;
m_filter = filter;
}
virtual QVariant headerData(int section, Qt::Orientation, int role = Qt::DisplayRole) const override
{
if(role == Qt::DisplayRole)
{
switch(section)
{
case 0:
return "ID";
break;
default:
ASSERT(false);
return QVariant();
}
}
return QVariant();
}
virtual QModelIndex index(int row, int column, const QModelIndex&) const override
{
return createIndex(row, column);
}
virtual QModelIndex parent(const QModelIndex&) const override
{
return QModelIndex();
}
virtual int rowCount(const QModelIndex& parent_index) const override
{
return parent_index.isValid() ? 0 : m_entities.size();
}
virtual int columnCount(const QModelIndex&) const override
{
return 1;
}
virtual QVariant data(const QModelIndex& index, int role) const override
{
if (index.row() < m_entities.size())
{
if (index.isValid() && role == Qt::DisplayRole)
{
const char* name = m_entities[index.row()].getName();
return name && name[0] != '\0' ? QVariant(name) : QVariant(m_entities[index.row()].index);
}
else if (index.isValid() && role == Qt::UserRole)
{
return m_entities[index.row()].index;
}
}
return QVariant();
}
void setUniverse(Lumix::Universe* universe)
{
m_filter->setUniverse(universe);
if(m_universe)
{
m_universe->entityCreated().unbind<EntityListModel, &EntityListModel::onEntityCreated>(this);
m_universe->entityDestroyed().unbind<EntityListModel, &EntityListModel::onEntityDestroyed>(this);
}
m_entities.clear();
m_universe = universe;
if(m_universe)
{
m_universe->entityCreated().bind<EntityListModel, &EntityListModel::onEntityCreated>(this);
m_universe->entityDestroyed().bind<EntityListModel, &EntityListModel::onEntityDestroyed>(this);
Lumix::Entity e = m_universe->getFirstEntity();
while(e.isValid())
{
m_entities.push(e);
e = m_universe->getNextEntity(e);
}
}
if(m_universe)
{
emit dataChanged(createIndex(0, 0), createIndex(m_entities.size(), 0));
}
}
private:
void onEntityCreated(const Lumix::Entity& entity)
{
m_entities.push(entity);
emit dataChanged(createIndex(0, 0), createIndex(m_entities.size() - 1, 0));
m_filter->invalidate();
}
void onEntityDestroyed(const Lumix::Entity& entity)
{
m_entities.eraseItem(entity);
emit dataChanged(createIndex(0, 0), createIndex(m_entities.size() - 1, 0));
m_filter->invalidate();
}
private:
Lumix::Universe* m_universe;
Lumix::Array<Lumix::Entity> m_entities;
EntityListFilter* m_filter;
};
EntityList::EntityList(QWidget *parent)
: QDockWidget(parent)
, m_ui(new Ui::EntityList)
{
m_universe = NULL;
m_ui->setupUi(this);
m_filter = new EntityListFilter(this);
m_model = new EntityListModel(this, m_filter);
m_filter->setDynamicSortFilter(true);
m_filter->setSourceModel(m_model);
m_ui->entityList->setModel(m_filter);
}
EntityList::~EntityList()
{
m_editor->universeCreated().unbind<EntityList, &EntityList::onUniverseCreated>(this);
m_editor->universeDestroyed().unbind<EntityList, &EntityList::onUniverseDestroyed>(this);
m_editor->universeLoaded().unbind<EntityList, &EntityList::onUniverseLoaded>(this);
m_editor->entitySelected().unbind<EntityList, &EntityList::onEntitySelected>(this);
delete m_ui;
}
void EntityList::setWorldEditor(Lumix::WorldEditor& editor)
{
m_editor = &editor;
editor.universeCreated().bind<EntityList, &EntityList::onUniverseCreated>(this);
editor.universeDestroyed().bind<EntityList, &EntityList::onUniverseDestroyed>(this);
editor.universeLoaded().bind<EntityList, &EntityList::onUniverseLoaded>(this);
m_universe = editor.getEngine().getUniverse();
m_model->setUniverse(m_universe);
m_filter->setSourceModel(m_model);
m_filter->setWorldEditor(editor);
m_ui->comboBox->clear();
m_ui->comboBox->addItem("All");
for (int i = 0; i < sizeof(component_map) / sizeof(component_map[0]); i += 2)
{
m_ui->comboBox->addItem(component_map[i]);
}
editor.entitySelected().bind<EntityList, &EntityList::onEntitySelected>(this);
}
void EntityList::onEntitySelected(const Lumix::Array<Lumix::Entity>& entities)
{
m_ui->entityList->selectionModel()->clear();
for(int j = entities.size() - 1; j >= 0; --j)
{
for (int i = 0, c = m_filter->rowCount(); i < c; ++i)
{
if (m_filter->data(m_filter->index(i, 0), Qt::UserRole).toInt() == entities[j].index)
{
m_ui->entityList->selectionModel()->select(m_filter->index(i, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
break;
}
}
}
}
void EntityList::onUniverseCreated()
{
m_universe = m_editor->getEngine().getUniverse();
m_model->setUniverse(m_universe);
}
void EntityList::onUniverseLoaded()
{
m_universe = m_editor->getEngine().getUniverse();
m_model->setUniverse(m_universe);
m_filter->invalidate();
}
void EntityList::onUniverseDestroyed()
{
m_model->setUniverse(NULL);
m_universe = NULL;
}
void EntityList::on_entityList_clicked(const QModelIndex &index)
{
m_editor->selectEntities(&Lumix::Entity(m_universe, m_filter->data(index, Qt::UserRole).toInt()), 1);
}
void EntityList::on_comboBox_activated(const QString &arg1)
{
for (int i = 0; i < sizeof(component_map) / sizeof(component_map[0]); i += 2)
{
if (arg1 == component_map[i])
{
m_filter->filterComponent(crc32(component_map[i + 1]));
m_filter->invalidate();
return;
}
}
m_filter->filterComponent(0);
m_filter->invalidate();
}
void EntityList::on_nameFilterEdit_textChanged(const QString &arg1)
{
QRegExp regExp(arg1);
m_filter->setFilterRegExp(regExp);
}

View file

@ -0,0 +1,52 @@
#pragma once
#include <QDockWidget>
#include <qsortfilterproxymodel.h>
#include "core/array.h"
#include "universe/entity.h"
namespace Ui
{
class EntityList;
}
namespace Lumix
{
struct Entity;
class Universe;
class WorldEditor;
}
class EntityListModel;
class EntityListFilter;
class EntityList : public QDockWidget
{
Q_OBJECT
public:
explicit EntityList(QWidget* parent);
~EntityList();
void setWorldEditor(Lumix::WorldEditor& editor);
private slots:
void on_entityList_clicked(const QModelIndex& index);
void on_comboBox_activated(const QString& arg1);
void on_nameFilterEdit_textChanged(const QString &arg1);
private:
void onUniverseCreated();
void onUniverseDestroyed();
void onUniverseLoaded();
void onEntitySelected(const Lumix::Array<Lumix::Entity>& entity);
private:
Ui::EntityList* m_ui;
Lumix::WorldEditor* m_editor;
Lumix::Universe* m_universe;
EntityListModel* m_model;
EntityListFilter* m_filter;
};

View file

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EntityList</class>
<widget class="QDockWidget" name="EntityList">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>389</width>
<height>422</height>
</rect>
</property>
<property name="windowTitle">
<string>Entity list</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string>All</string>
</property>
</item>
<item>
<property name="text">
<string>Animable</string>
</property>
</item>
<item>
<property name="text">
<string>Camera</string>
</property>
</item>
<item>
<property name="text">
<string>Mesh</string>
</property>
</item>
<item>
<property name="text">
<string>Physics Box</string>
</property>
</item>
<item>
<property name="text">
<string>Physics Mesh</string>
</property>
</item>
<item>
<property name="text">
<string>Physics Heightfield</string>
</property>
</item>
<item>
<property name="text">
<string>Script</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLineEdit" name="nameFilterEdit"/>
</item>
<item>
<widget class="QListView" name="entityList">
<property name="modelColumn">
<number>0</number>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -43,14 +43,23 @@ void EntityTemplateList::onSystemUpdated()
void EntityTemplateList::on_templateList_doubleClicked(const QModelIndex &index)
{
m_editor->getEntityTemplateSystem().createInstance(m_ui->templateList->item(index.row())->text().toLatin1().data());
Lumix::Vec3 pos = m_editor->getCameraRaycastHit();
m_editor->getEntityTemplateSystem().createInstance(m_ui->templateList->item(index.row())->text().toLatin1().data(), pos);
}
void EntityTemplateList::instantiateTemplate()
{
instantiateTemplateAt(m_editor->getCameraRaycastHit());
}
void EntityTemplateList::instantiateTemplateAt(const Lumix::Vec3& pos)
{
if (m_ui->templateList->currentIndex().row() >= 0)
{
m_editor->getEntityTemplateSystem().createInstance(m_ui->templateList->item(m_ui->templateList->currentIndex().row())->text().toLatin1().data());
m_editor->getEntityTemplateSystem().createInstance(m_ui->templateList->item(m_ui->templateList->currentIndex().row())->text().toLatin1().data(), pos);
}
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <QDockWidget>
#include "core/vec3.h"
namespace Ui
{
@ -22,6 +23,7 @@ class EntityTemplateList : public QDockWidget
void setWorldEditor(Lumix::WorldEditor& editor);
void instantiateTemplate();
void instantiateTemplateAt(const Lumix::Vec3& position);
private:
void onSystemUpdated();

View file

@ -37,6 +37,6 @@ void GameView::resizeEvent(QResizeEvent* event)
void GameView::on_playButton_clicked()
{
m_server->toggleGameMode();
m_editor->toggleGameMode();
}

View file

@ -25,6 +25,7 @@ public:
QWidget* getContentWidget() const;
void setPipeline(Lumix::PipelineInstance& pipeline) { m_pipeline = &pipeline; }
void setWorldEditor(Lumix::WorldEditor& editor) { m_editor = &editor; }
private slots:
void on_playButton_clicked();
@ -35,6 +36,6 @@ private:
private:
Ui::GameView* m_ui;
Lumix::PipelineInstance* m_pipeline;
Lumix::WorldEditor* m_server;
Lumix::WorldEditor* m_editor;
};

View file

@ -0,0 +1,68 @@
#include "insert_mesh_command.h"
#include "core/crc32.h"
#include "engine/engine.h"
#include "graphics/render_scene.h"
static const uint32_t RENDERABLE_HASH = crc32("renderable");
InsertMeshCommand::InsertMeshCommand(Lumix::WorldEditor& editor, const Lumix::Vec3& position, const Lumix::Path& mesh_path)
: m_mesh_path(mesh_path)
, m_position(position)
, m_editor(editor)
{
}
void InsertMeshCommand::execute()
{
Lumix::Engine& engine = m_editor.getEngine();
m_entity = engine.getUniverse()->createEntity();
m_entity.setPosition(m_position);
const Lumix::Array<Lumix::IScene*>& scenes = engine.getScenes();
Lumix::Component cmp;
Lumix::IScene* scene = NULL;
for (int i = 0; i < scenes.size(); ++i)
{
cmp = scenes[i]->createComponent(RENDERABLE_HASH, m_entity);
if (cmp.isValid())
{
scene = scenes[i];
break;
}
}
if (cmp.isValid())
{
char rel_path[LUMIX_MAX_PATH];
m_editor.getRelativePath(rel_path, LUMIX_MAX_PATH, m_mesh_path.c_str());
static_cast<Lumix::RenderScene*>(scene)->setRenderablePath(cmp, Lumix::string(rel_path));
}
}
void InsertMeshCommand::undo()
{
const Lumix::Entity::ComponentList& cmps = m_entity.getComponents();
for (int i = 0; i < cmps.size(); ++i)
{
cmps[i].scene->destroyComponent(cmps[i]);
}
m_editor.getEngine().getUniverse()->destroyEntity(m_entity);
m_entity = Lumix::Entity::INVALID;
}
uint32_t InsertMeshCommand::getType()
{
static const uint32_t type = crc32("insert_mesh");
return type;
}
bool InsertMeshCommand::merge(IEditorCommand&)
{
return false;
}

View file

@ -0,0 +1,25 @@
#pragma once
#include "core/path.h"
#include "editor/ieditor_command.h"
#include "editor/world_editor.h"
class InsertMeshCommand : public Lumix::IEditorCommand
{
public:
InsertMeshCommand(Lumix::WorldEditor& editor, const Lumix::Vec3& position, const Lumix::Path& mesh_path);
virtual void execute() override;
virtual void undo() override;
virtual uint32_t getType() override;
virtual bool merge(IEditorCommand&);
const Lumix::Entity& getEntity() const { return m_entity; }
private:
Lumix::Vec3 m_position;
Lumix::Path m_mesh_path;
Lumix::Entity m_entity;
Lumix::WorldEditor& m_editor;
};

View file

@ -18,7 +18,6 @@
#include "sceneview.h"
#include "gameview.h"
#include "wgl_render_device.h"
#include "materialmanager.h"
class App
@ -42,8 +41,8 @@ class App
void onUniverseCreated()
{
m_edit_render_device->getPipeline().setScene(m_world_editor->getEngine().getRenderScene());
m_game_render_device->getPipeline().setScene(m_world_editor->getEngine().getRenderScene());
m_edit_render_device->getPipeline().setScene((Lumix::RenderScene*)m_world_editor->getEngine().getScene(crc32("renderer")));
m_game_render_device->getPipeline().setScene((Lumix::RenderScene*)m_world_editor->getEngine().getScene(crc32("renderer")));
}
void onUniverseDestroyed()
@ -198,10 +197,10 @@ class App
void renderPhysics()
{
Lumix::PhysicsSystem* system = static_cast<Lumix::PhysicsSystem*>(m_world_editor->getEngine().getPluginManager().getPlugin("physics"));
if(system && system->getScene())
Lumix::PhysicsScene* scene = static_cast<Lumix::PhysicsScene*>(m_world_editor->getEngine().getScene(crc32("physics")));
if(scene)
{
system->getScene()->render();
scene->render();
}
}
@ -218,8 +217,8 @@ class App
HWND hwnd = (HWND)m_main_window->getSceneView()->getViewWidget()->winId();
HWND game_hwnd = (HWND)m_main_window->getGameView()->getContentWidget()->winId();
HWND hwnds[] = { hwnd, game_hwnd, (HWND)m_main_window->getMaterialManager()->getPreview()->winId() };
HGLRC hglrc = createGLContext(hwnds, 3);
HWND hwnds[] = { hwnd, game_hwnd };
HGLRC hglrc = createGLContext(hwnds, 2);
m_world_editor = Lumix::WorldEditor::create(QDir::currentPath().toLocal8Bit().data());
ASSERT(m_world_editor);
@ -231,14 +230,14 @@ class App
m_edit_render_device = new WGLRenderDevice(m_world_editor->getEngine(), "pipelines/main.json");
m_edit_render_device->m_hdc = GetDC(hwnd);
m_edit_render_device->m_opengl_context = hglrc;
m_edit_render_device->getPipeline().setScene(m_world_editor->getEngine().getRenderScene()); /// TODO manage scene properly
m_edit_render_device->getPipeline().setScene((Lumix::RenderScene*)m_world_editor->getEngine().getScene(crc32("renderer")));
m_world_editor->setEditViewRenderDevice(*m_edit_render_device);
m_edit_render_device->getPipeline().addCustomCommandHandler("render_physics").bind<App, &App::renderPhysics>(this);
m_game_render_device = new WGLRenderDevice(m_world_editor->getEngine(), "pipelines/game_view.json");
m_game_render_device->m_hdc = GetDC(game_hwnd);
m_game_render_device->m_opengl_context = hglrc;
m_game_render_device->getPipeline().setScene(m_world_editor->getEngine().getRenderScene()); /// TODO manage scene properly
m_game_render_device->getPipeline().setScene((Lumix::RenderScene*)m_world_editor->getEngine().getScene(crc32("renderer")));
m_world_editor->getEngine().getRenderer().setRenderDevice(*m_game_render_device);
m_world_editor->universeCreated().bind<App, &App::onUniverseCreated>(this);
@ -248,6 +247,7 @@ class App
m_main_window->getGameView()->setPipeline(m_game_render_device->getPipeline());
}
void shutdown()
{
delete m_game_render_device;
@ -256,6 +256,7 @@ class App
m_edit_render_device = NULL;
}
void renderEditView()
{
PROFILE_FUNCTION();
@ -265,10 +266,9 @@ class App
m_world_editor->getGizmo().updateScale(m_world_editor->getEditCamera());
m_world_editor->getGizmo().render(m_world_editor->getEngine().getRenderer(), *m_edit_render_device);
m_edit_render_device->endFrame();
m_main_window->getMaterialManager()->updatePreview();
}
void handleEvents()
{
PROFILE_FUNCTION();
@ -308,12 +308,14 @@ class App
}
}
void run()
{
while (m_main_window->isVisible())
{
{
PROFILE_BLOCK("tick");
m_main_window->update();
renderEditView();
m_world_editor->getEngine().getRenderer().renderGame();
m_world_editor->tick();

View file

@ -3,17 +3,20 @@
#include "assetbrowser.h"
#include "editor/entity_template_system.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "entity_list.h"
#include "entity_template_list.h"
#include "fileserverwidget.h"
#include "gameview.h"
#include "log_widget.h"
#include "notifications.h"
#include "property_view.h"
#include "sceneview.h"
#include "scripts/scriptcompilerwidget.h"
#include "materialmanager.h"
#include "profilerui.h"
#include <qfiledialog.h>
#include <qinputdialog.h>
#include <qevent.h>
#include <qsettings.h>
@ -32,9 +35,10 @@ MainWindow::MainWindow(QWidget* parent) :
m_asset_browser = new AssetBrowser;
m_script_compiler_ui = new ScriptCompilerWidget;
m_file_server_ui = new FileServerWidget;
m_material_manager_ui = new MaterialManager;
m_profiler_ui = new ProfilerUI;
m_entity_template_list_ui = new EntityTemplateList;
m_notifications = Notifications::create(*this);
m_entity_list = new EntityList(NULL);
QSettings settings("Lumix", "QtEditor");
restoreGeometry(settings.value("mainWindowGeometry").toByteArray());
@ -46,16 +50,30 @@ MainWindow::MainWindow(QWidget* parent) :
addDockWidget(static_cast<Qt::DockWidgetArea>(1), m_property_view);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), m_scene_view);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), m_asset_browser);
addDockWidget(static_cast<Qt::DockWidgetArea>(8), m_material_manager_ui);
addDockWidget(static_cast<Qt::DockWidgetArea>(1), m_profiler_ui);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), m_entity_template_list_ui);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), m_entity_list);
m_property_view->setScriptCompiler(m_script_compiler_ui->getCompiler());
m_property_view->setAssetBrowser(*m_asset_browser);
m_property_view->setEntityTemplateList(m_entity_template_list_ui);
restoreState(settings.value("mainWindowState").toByteArray());
}
void MainWindow::resizeEvent(QResizeEvent* event)
{
m_resized.invoke(event->size());
}
void MainWindow::update()
{
m_notifications->update(m_world_editor->getEngine().getLastTimeDelta());
}
void MainWindow::closeEvent(QCloseEvent *event)
{
QSettings settings("Lumix", "QtEditor");
@ -74,9 +92,9 @@ MainWindow::~MainWindow()
delete m_asset_browser;
delete m_script_compiler_ui;
delete m_file_server_ui;
delete m_material_manager_ui;
delete m_profiler_ui;
delete m_entity_template_list_ui;
Notifications::destroy(m_notifications);
}
@ -85,9 +103,10 @@ void MainWindow::setWorldEditor(Lumix::WorldEditor& editor)
m_world_editor = &editor;
m_file_server_ui->setWorldEditor(editor);
m_asset_browser->setWorldEditor(editor);
m_material_manager_ui->setWorldEditor(editor);
m_property_view->setWorldEditor(editor);
m_entity_template_list_ui->setWorldEditor(editor);
m_game_view->setWorldEditor(editor);
m_entity_list->setWorldEditor(editor);
}
GameView* MainWindow::getGameView() const
@ -171,11 +190,6 @@ void MainWindow::on_actionProfiler_triggered()
m_profiler_ui->show();
}
void MainWindow::on_actionMaterial_manager_triggered()
{
m_material_manager_ui->show();
}
void MainWindow::on_actionPolygon_Mode_changed()
{
m_world_editor->setWireframe(m_ui->actionPolygon_Mode->isChecked());
@ -215,13 +229,13 @@ void MainWindow::on_actionSnap_to_terrain_triggered()
void MainWindow::on_actionSave_as_template_triggered()
{
if (m_world_editor->getSelectedEntity().isValid())
if (m_world_editor->getSelectedEntities().size() == 1)
{
bool ok = false;
QString text = QInputDialog::getText(this, tr("Entity template"), tr("Template name:"), QLineEdit::Normal, tr(""), &ok);
if (ok)
{
m_world_editor->getEntityTemplateSystem().createTemplateFromEntity(text.toLatin1().data(), m_world_editor->getSelectedEntity());
m_world_editor->getEntityTemplateSystem().createTemplateFromEntity(text.toLatin1().data(), m_world_editor->getSelectedEntities()[0]);
}
}
}
@ -245,3 +259,16 @@ void MainWindow::on_actionRedo_triggered()
{
m_world_editor->redo();
}
void MainWindow::on_actionRemove_triggered()
{
if (!m_world_editor->getSelectedEntities().empty())
{
m_world_editor->destroyEntities(&m_world_editor->getSelectedEntities()[0], m_world_editor->getSelectedEntities().size());
}
}
void MainWindow::on_actionEntity_list_triggered()
{
m_entity_list->show();
}

View file

@ -1,6 +1,8 @@
#pragma once
#include <QMainWindow>
#include "core/delegate_list.h"
namespace Lumix
{
@ -20,10 +22,11 @@ public:
explicit MainWindow(QWidget* parent = NULL);
~MainWindow();
void update();
void setWorldEditor(Lumix::WorldEditor& world_editor);
class SceneView* getSceneView() const;
class GameView* getGameView() const;
class MaterialManager* getMaterialManager() const { return m_material_manager_ui; }
Lumix::DelegateList<void(const QSize&)>& resized() { return m_resized; }
private slots:
void on_actionLog_triggered();
@ -39,7 +42,6 @@ private slots:
void on_actionScene_View_triggered();
virtual void closeEvent(QCloseEvent* event) override;
void on_actionProfiler_triggered();
void on_actionMaterial_manager_triggered();
void on_actionPolygon_Mode_changed();
void on_actionGame_mode_triggered();
void on_actionLook_at_selected_entity_triggered();
@ -48,12 +50,16 @@ private slots:
void on_actionSnap_to_terrain_triggered();
void on_actionSave_as_template_triggered();
void on_actionEntity_templates_triggered();
void on_actionInstantiate_template_triggered();
void on_actionUndo_triggered();
void on_actionRedo_triggered();
void on_actionInstantiate_template_triggered();
void on_actionRemove_triggered();
void on_actionUndo_triggered();
void on_actionEntity_list_triggered();
void on_actionRedo_triggered();
private:
virtual void resizeEvent(QResizeEvent* event) override;
private:
Ui::MainWindow* m_ui;
@ -65,8 +71,10 @@ private:
class AssetBrowser* m_asset_browser;
class ScriptCompilerWidget* m_script_compiler_ui;
class FileServerWidget* m_file_server_ui;
class MaterialManager* m_material_manager_ui;
class ProfilerUI* m_profiler_ui;
class EntityTemplateList* m_entity_template_list_ui;
class Notifications* m_notifications;
class EntityList* m_entity_list;
Lumix::DelegateList<void(const QSize&)> m_resized;
};

View file

@ -52,11 +52,11 @@
<string>Windows</string>
</property>
<addaction name="actionAsset_Browser"/>
<addaction name="actionEntity_list"/>
<addaction name="actionEntity_templates"/>
<addaction name="actionFile_server"/>
<addaction name="actionGame_view"/>
<addaction name="actionLog"/>
<addaction name="actionMaterial_manager"/>
<addaction name="actionProfiler"/>
<addaction name="actionProperties"/>
<addaction name="actionScene_View"/>
@ -89,6 +89,7 @@
<string>Entity</string>
</property>
<addaction name="actionCreate"/>
<addaction name="actionRemove"/>
<addaction name="actionSave_as_template"/>
<addaction name="actionInstantiate_template"/>
</widget>
@ -272,6 +273,19 @@
<string>Ctrl+Shift+Z</string>
</property>
</action>
<action name="actionRemove">
<property name="text">
<string>Remove</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</action>
<action name="actionEntity_list">
<property name="text">
<string>Entity list</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>

View file

@ -1,372 +0,0 @@
#include "materialmanager.h"
#include "ui_materialmanager.h"
#include <qboxlayout.h>
#include <qcheckbox.h>
#include <qfilesystemmodel.h>
#include <qformlayout.h>
#include <qlineedit.h>
#include <qpainter.h>
#include <qpushbutton.h>
#include "core/crc32.h"
#include "core/FS/file_system.h"
#include "core/json_serializer.h"
#include "core/log.h"
#include "core/profiler.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "graphics/material.h"
#include "graphics/model.h"
#include "graphics/pipeline.h"
#include "graphics/renderer.h"
#include "graphics/render_scene.h"
#include "graphics/shader.h"
#include "graphics/texture.h"
#include "universe/universe.h"
#include "wgl_render_device.h"
class MaterialManagerUI
{
public:
Lumix::Engine* m_engine;
Lumix::Universe* m_universe;
Lumix::RenderScene* m_render_scene;
WGLRenderDevice* m_render_device;
Lumix::Model* m_selected_object_model;
QFileSystemModel* m_fs_model;
Lumix::Material* m_material;
Lumix::WorldEditor* m_world_editor;
};
MaterialManager::MaterialManager(QWidget *parent)
: QDockWidget(parent)
, m_ui(new Ui::MaterialManager)
{
m_impl = new MaterialManagerUI();
m_impl->m_selected_object_model = NULL;
m_impl->m_world_editor = NULL;
m_ui->setupUi(this);
m_impl->m_fs_model = new QFileSystemModel();
m_impl->m_fs_model->setRootPath(QDir::currentPath());
QStringList filters;
filters << "*.mat";
m_impl->m_fs_model->setNameFilters(filters);
m_impl->m_fs_model->setNameFilterDisables(false);
m_ui->fileTreeView->setModel(m_impl->m_fs_model);
m_ui->fileTreeView->setRootIndex(m_impl->m_fs_model->index(QDir::currentPath()));
m_impl->m_engine = NULL;
m_impl->m_universe = NULL;
m_impl->m_render_scene = NULL;
}
void MaterialManager::updatePreview()
{
PROFILE_FUNCTION();
m_impl->m_render_device->beginFrame();
m_impl->m_engine->getRenderer().render(*m_impl->m_render_device);
m_impl->m_render_device->endFrame();
m_impl->m_render_scene->update(0.01f); TODO("time");
}
void MaterialManager::fillObjectMaterials()
{
m_ui->objectMaterialList->clear();
if(m_impl->m_selected_object_model)
{
for(int i = 0; i < m_impl->m_selected_object_model->getMeshCount(); ++i)
{
const char* path = m_impl->m_selected_object_model->getMesh(i).getMaterial()->getPath().c_str();
m_ui->objectMaterialList->addItem(path);
}
}
}
QWidget* MaterialManager::getPreview() const
{
return m_ui->previewWidget;
}
void MaterialManager::onEntitySelected(Lumix::Entity& entity)
{
if (entity.isValid())
{
Lumix::Component cmp = entity.getComponent(crc32("renderable"));
if (cmp.isValid())
{
m_impl->m_selected_object_model = static_cast<Lumix::RenderScene*>(cmp.system)->getModel(cmp);
fillObjectMaterials();
}
}
}
void MaterialManager::setWorldEditor(Lumix::WorldEditor& editor)
{
ASSERT(m_impl->m_engine == NULL);
m_impl->m_world_editor = &editor;
HWND hwnd = (HWND)m_ui->previewWidget->winId();
editor.entitySelected().bind<MaterialManager, &MaterialManager::onEntitySelected>(this);
m_impl->m_engine = &editor.getEngine();
m_impl->m_universe = new Lumix::Universe();
m_impl->m_universe->create();
m_impl->m_render_scene = Lumix::RenderScene::createInstance(editor.getEngine(), *m_impl->m_universe);
m_impl->m_render_device = new WGLRenderDevice(editor.getEngine(), "pipelines/main.json");
m_impl->m_render_device->m_hdc = GetDC(hwnd);
m_impl->m_render_device->m_opengl_context = wglGetCurrentContext();
m_impl->m_render_device->getPipeline().setScene(m_impl->m_render_scene);
const Lumix::Entity& camera_entity = m_impl->m_universe->createEntity();
Lumix::Component cmp = m_impl->m_render_scene->createComponent(crc32("camera"), camera_entity);
m_impl->m_render_scene->setCameraSlot(cmp, Lumix::string("editor"));
Lumix::Entity light_entity = m_impl->m_universe->createEntity();
light_entity.setRotation(Lumix::Quat(Lumix::Vec3(0, 1, 0), 3.14159265f));
m_impl->m_render_scene->createComponent(crc32("light"), light_entity);
Lumix::Entity model_entity = m_impl->m_universe->createEntity();
model_entity.setPosition(0, 0, -5);
Lumix::Component cmp2 = m_impl->m_render_scene->createComponent(crc32("renderable"), model_entity);
m_impl->m_render_scene->setRenderablePath(cmp2, Lumix::string("models/editor/material_sphere.msh"));
m_ui->previewWidget->setAttribute(Qt::WA_NoSystemBackground);
m_ui->previewWidget->setAutoFillBackground(false);
m_ui->previewWidget->setAttribute(Qt::WA_OpaquePaintEvent);
m_ui->previewWidget->setAttribute(Qt::WA_TranslucentBackground);
m_ui->previewWidget->setAttribute(Qt::WA_PaintOnScreen);
m_ui->previewWidget->m_render_device = m_impl->m_render_device;
m_ui->previewWidget->m_engine = m_impl->m_engine;
}
MaterialManager::~MaterialManager()
{
Lumix::RenderScene::destroyInstance(m_impl->m_render_scene);
m_impl->m_universe->destroy();
delete m_impl->m_render_device;
delete m_impl->m_universe;
delete m_impl;
delete m_ui;
}
class ICppObjectProperty
{
public:
enum Type
{
BOOL,
SHADER,
UNKNOWN
};
public:
Type getType() const { return m_type; }
const char* getName() const { return m_name.c_str(); }
template <class T>
static Type getType();
template <> static Type getType<bool>() { return BOOL; }
template <> static Type getType<Lumix::Shader*>() { return SHADER; }
protected:
Type m_type;
Lumix::string m_name;
};
template <typename V, class T>
class CppObjectProperty : public ICppObjectProperty
{
public:
typedef V (T::*Getter)() const;
typedef void (T::*Setter)(V);
public:
CppObjectProperty(const char* name, Getter getter, Setter setter)
{
m_name = name;
m_type = ICppObjectProperty::getType<V>();
m_getter = getter;
m_setter = setter;
}
V get(const T& t)
{
return (t.*m_getter)();
}
void set(T& t, const V& v)
{
(t.*m_setter)(v);
}
private:
Getter m_getter;
Setter m_setter;
};
void MaterialManager::onBoolPropertyStateChanged(int)
{
QCheckBox* obj = qobject_cast<QCheckBox*>(QObject::sender());
if(obj)
{
CppObjectProperty<bool, Lumix::Material>* prop = static_cast<CppObjectProperty<bool, Lumix::Material>*>(obj->property("cpp_property").value<void*>());
prop->set(*m_impl->m_material, obj->isChecked());
}
}
void MaterialManager::onTextureChanged()
{
QLineEdit* edit = qobject_cast<QLineEdit*>(QObject::sender());
if(edit)
{
int i = edit->property("texture_index").toInt();
m_impl->m_material->setTexture(i, static_cast<Lumix::Texture*>(m_impl->m_engine->getResourceManager().get(Lumix::ResourceManager::TEXTURE)->load(edit->text().toLatin1().data())));
}
}
void MaterialManager::onShaderChanged()
{
QLineEdit* edit = static_cast<QLineEdit*>(QObject::sender());
m_impl->m_material->setShader(static_cast<Lumix::Shader*>(m_impl->m_engine->getResourceManager().get(Lumix::ResourceManager::SHADER)->load(edit->text().toLatin1().data())));
}
void MaterialManager::onTextureAdded()
{
m_impl->m_material->addTexture(static_cast<Lumix::Texture*>(m_impl->m_engine->getResourceManager().get(Lumix::ResourceManager::TEXTURE)->load("textures/default.dds")));
selectMaterial(m_impl->m_material->getPath().c_str());
}
void MaterialManager::selectMaterial(const char* path)
{
char rel_path[LUMIX_MAX_PATH];
m_impl->m_world_editor->getRelativePath(rel_path, LUMIX_MAX_PATH, path);
Lumix::Material* material = static_cast<Lumix::Material*>(m_impl->m_engine->getResourceManager().get(Lumix::ResourceManager::MATERIAL)->load(rel_path));
material->getObserverCb().bind<MaterialManager, &MaterialManager::onMaterialLoaded>(this);
m_impl->m_material = material;
if(material->isReady())
{
onMaterialLoaded(Lumix::Resource::State::READY, Lumix::Resource::State::READY);
}
}
void MaterialManager::onMaterialLoaded(Lumix::Resource::State, Lumix::Resource::State)
{
ICppObjectProperty* properties[] =
{
new CppObjectProperty<bool, Lumix::Material>("Z test", &Lumix::Material::isZTest, &Lumix::Material::enableZTest),
new CppObjectProperty<bool, Lumix::Material>("Alpha to coverage", &Lumix::Material::isAlphaToCoverage, &Lumix::Material::enableAlphaToCoverage),
new CppObjectProperty<bool, Lumix::Material>("Backface culling", &Lumix::Material::isBackfaceCulling, &Lumix::Material::enableBackfaceCulling),
new CppObjectProperty<Lumix::Shader*, Lumix::Material>("Shader", &Lumix::Material::getShader, &Lumix::Material::setShader)
};
Lumix::Model* model = static_cast<Lumix::Model*>(m_impl->m_engine->getResourceManager().get(Lumix::ResourceManager::MODEL)->get("models/editor/material_sphere.msh"));
Lumix::Material* material = m_impl->m_material;
material->getObserverCb().unbind<MaterialManager, &MaterialManager::onMaterialLoaded>(this);
model->getMesh(0).setMaterial(material);
QFormLayout* layout = m_ui->materialPropertiesLayout;
QLayoutItem* item;
while((item = layout->takeAt(0)) != NULL)
{
delete item->widget();
delete item;
}
for(int i = 0; i < sizeof(properties) / sizeof(ICppObjectProperty*); ++i)
{
switch(properties[i]->getType())
{
case ICppObjectProperty::BOOL:
{
QCheckBox* checkbox = new QCheckBox();
checkbox->setProperty("cpp_property", QVariant::fromValue((void*)properties[i]));
checkbox->setChecked(static_cast<CppObjectProperty<bool, Lumix::Material>*>(properties[i])->get(*material));
layout->addRow(properties[i]->getName(), checkbox);
connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(onBoolPropertyStateChanged(int)));
}
break;
case ICppObjectProperty::SHADER:
{
QLineEdit* edit = new QLineEdit();
Lumix::Shader* shader = static_cast<CppObjectProperty<Lumix::Shader*, Lumix::Material>*>(properties[i])->get(*material);
if(shader)
{
edit->setText(shader->getPath().c_str());
}
connect(edit, SIGNAL(editingFinished()), this, SLOT(onShaderChanged()));
layout->addRow(properties[i]->getName(), edit);
}
break;
default:
ASSERT(false);
break;
}
}
for(int i = 0; i < material->getTextureCount(); ++i)
{
QLineEdit* edit = new QLineEdit;
QBoxLayout* inner_layout = new QBoxLayout(QBoxLayout::Direction::LeftToRight);
QPushButton* button = new QPushButton();
button->setText("Remove");
inner_layout->addWidget(edit);
inner_layout->addWidget(button);
edit->setText(material->getTexture(i)->getPath().c_str());
edit->setProperty("texture_index", i);
layout->addRow("Texture", inner_layout);
connect(edit, SIGNAL(editingFinished()), this, SLOT(onTextureChanged()));
connect(button, SIGNAL(clicked()), this, SLOT(onTextureRemoved()));
button->setProperty("texture_id", i);
}
QPushButton* button = new QPushButton();
button->setText("Add Texture");
connect(button, SIGNAL(clicked()), this, SLOT(onTextureAdded()));
layout->addRow("", button);
}
void MaterialManager::onTextureRemoved()
{
QPushButton* button = static_cast<QPushButton*>(QObject::sender());
int i = button->property("texture_id").toInt();
m_impl->m_material->removeTexture(i);
selectMaterial(m_impl->m_material->getPath().c_str());
}
void MaterialManager::on_objectMaterialList_doubleClicked(const QModelIndex &index)
{
QListWidgetItem* item = m_ui->objectMaterialList->item(index.row());
selectMaterial(item->text().toLatin1().data());
}
void MaterialManager::on_saveMaterialButton_clicked()
{
Lumix::FS::FileSystem& fs = m_impl->m_engine->getFileSystem();
// use temporary because otherwise the material is reloaded during saving
char tmp_path[LUMIX_MAX_PATH];
strcpy(tmp_path, m_impl->m_material->getPath().c_str());
strcat(tmp_path, ".tmp");
Lumix::FS::IFile* file = fs.open(fs.getDefaultDevice(), tmp_path, Lumix::FS::Mode::CREATE | Lumix::FS::Mode::WRITE);
if(file)
{
Lumix::JsonSerializer serializer(*file, Lumix::JsonSerializer::AccessMode::WRITE, m_impl->m_material->getPath().c_str());
m_impl->m_material->save(serializer);
fs.close(file);
QFile::remove(m_impl->m_material->getPath().c_str());
QFile::rename(tmp_path, m_impl->m_material->getPath().c_str());
}
else
{
Lumix::g_log_error.log("Material manager") << "Could not save file " << m_impl->m_material->getPath().c_str();
}
}
void MaterialManager::on_fileTreeView_doubleClicked(const QModelIndex &index)
{
QString file_path = m_impl->m_fs_model->fileInfo(index).filePath().toLower();
selectMaterial(file_path.toLatin1().data());
}

View file

@ -1,50 +0,0 @@
#pragma once
#include <QDockWidget>
#include "core/resource.h"
namespace Ui
{
class MaterialManager;
}
namespace Lumix
{
class WorldEditor;
struct Entity;
class Event;
struct PropertyListEvent;
}
class MaterialManager : public QDockWidget
{
Q_OBJECT
public:
explicit MaterialManager(QWidget* parent = NULL);
~MaterialManager();
void setWorldEditor(Lumix::WorldEditor& server);
void updatePreview();
QWidget* getPreview() const;
private:
void fillObjectMaterials();
void selectMaterial(const char* path);
void onMaterialLoaded(Lumix::Resource::State, Lumix::Resource::State);
void onEntitySelected(Lumix::Entity& entity);
private slots:
void on_objectMaterialList_doubleClicked(const QModelIndex& index);
void on_saveMaterialButton_clicked();
void onBoolPropertyStateChanged(int state);
void onShaderChanged();
void onTextureChanged();
void onTextureRemoved();
void onTextureAdded();
void on_fileTreeView_doubleClicked(const QModelIndex &index);
private:
Ui::MaterialManager* m_ui;
class MaterialManagerUI* m_impl;
};

View file

@ -1,114 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MaterialManager</class>
<widget class="QDockWidget" name="MaterialManager">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>680</width>
<height>422</height>
</rect>
</property>
<property name="windowTitle">
<string>Material manager</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Files</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTreeView" name="fileTreeView"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Object</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="objectMaterialList"/>
</item>
</layout>
</widget>
</widget>
<widget class="RenderDeviceWidget" name="previewWidget" native="true"/>
<widget class="QWidget" name="materialProperties" native="true">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QFormLayout" name="materialPropertiesLayout"/>
</item>
<item>
<widget class="QPushButton" name="saveMaterialButton">
<property name="text">
<string>Save material</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>RenderDeviceWidget</class>
<extends>QWidget</extends>
<header>renderdevicewidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,128 @@
#include "notifications.h"
#include "core/log.h"
#include "mainwindow.h"
#include <qlabel.h>
static const float DISPLAY_TIME = 2.0f;
static const int NOTIFICATION_WIDTH = 200;
static const int WIDGET_SPACING = 5;
class NotificationsImpl : public Notifications
{
public:
NotificationsImpl(MainWindow& main_window)
: m_main_window(main_window)
{
//Lumix::g_log_info.getCallback().bind<NotificationsImpl, &NotificationsImpl::onLogInfo>(this);
Lumix::g_log_warning.getCallback().bind<NotificationsImpl, &NotificationsImpl::onLogWarning>(this);
Lumix::g_log_error.getCallback().bind<NotificationsImpl, &NotificationsImpl::onLogError>(this);
m_main_window.resized().bind<NotificationsImpl, &NotificationsImpl::onMainWindowResized>(this);
}
~NotificationsImpl()
{
//Lumix::g_log_info.getCallback().unbind<NotificationsImpl, &NotificationsImpl::onLogInfo>(this);
Lumix::g_log_warning.getCallback().unbind<NotificationsImpl, &NotificationsImpl::onLogWarning>(this);
Lumix::g_log_error.getCallback().unbind<NotificationsImpl, &NotificationsImpl::onLogError>(this);
m_main_window.resized().unbind<NotificationsImpl, &NotificationsImpl::onMainWindowResized>(this);
}
void onMainWindowResized(const QSize&)
{
updateLayout();
}
void updateLayout()
{
int y = m_main_window.height() - WIDGET_SPACING;
for (int i = m_items.size() - 1; i >= 0; --i)
{
QWidget* widget = m_items[i].m_widget;
y -= widget->height() + WIDGET_SPACING;
widget->move(m_main_window.width() - NOTIFICATION_WIDTH - WIDGET_SPACING, y);
}
}
void onLogInfo(const char*, const char* message)
{
showNotification(message);
}
void onLogWarning(const char*, const char* message)
{
showNotification(message);
}
void onLogError(const char*, const char* message)
{
showNotification(message);
}
virtual void update(float time_delta) override
{
if (!m_items.empty())
{
m_items[0].m_time -= time_delta;
if (m_items[0].m_time < 0)
{
delete m_items[0].m_widget;
m_items.erase(0);
updateLayout();
}
}
}
virtual void showNotification(const char* text) override
{
QWidget* widget = new QWidget(&m_main_window);
widget->setObjectName("notification");
QLabel* label = new QLabel(widget);
label->setMinimumWidth(NOTIFICATION_WIDTH);
label->setWordWrap(true);
label->setContentsMargins(2, 2, 2, 2);
label->setText(text);
widget->adjustSize();
widget->show();
widget->raise();
Notification n;
n.m_widget = widget;
n.m_time = DISPLAY_TIME;
m_items.push(n);
updateLayout();
}
private:
class Notification
{
public:
QWidget* m_widget;
float m_time;
};
private:
MainWindow& m_main_window;
Lumix::Array<Notification> m_items;
};
Notifications* Notifications::create(MainWindow& main_window)
{
return new NotificationsImpl(main_window);
}
void Notifications::destroy(Notifications* notifications)
{
delete notifications;
}

View file

@ -0,0 +1,15 @@
#pragma once
class Notifications
{
public:
static Notifications* create(class MainWindow& main_window);
static void destroy(Notifications* notifications);
virtual void update(float time_delta) = 0;
virtual void showNotification(const char* text) = 0;
protected:
Notifications() {}
virtual ~Notifications() {}
};

View file

@ -20,7 +20,8 @@ ProfileModel::Block::Block()
}
ProfileModel::ProfileModel()
ProfileModel::ProfileModel(QWidget* parent)
: QAbstractItemModel(parent)
{
Lumix::g_profiler.getFrameListeners().bind<ProfileModel, &ProfileModel::onFrame>(this);
m_root = NULL;
@ -121,6 +122,8 @@ QVariant ProfileModel::headerData(int section, Qt::Orientation, int role) const
return "Name";
case Values::LENGTH:
return "Length (ms)";
case Values::LENGTH_EXCLUSIVE:
return "Length exclusive (ms)";
case Values::HIT_COUNT:
return "Hit count";
break;
@ -222,6 +225,7 @@ int ProfileModel::columnCount(const QModelIndex&) const
return (int)Values::COUNT;
}
QVariant ProfileModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || !index.internalPointer())
@ -242,6 +246,32 @@ QVariant ProfileModel::data(const QModelIndex& index, int role) const
return block->m_name;
case Values::LENGTH:
return m_frame >= 0 && m_frame < block->m_frames.size() ? block->m_frames[m_frame] : (block->m_frames.isEmpty() ? 0 : block->m_frames.back());
case Values::LENGTH_EXCLUSIVE:
{
if (m_frame >= 0 && m_frame < block->m_frames.size())
{
float length = block->m_frames[m_frame];
Block* child = block->m_first_child;
while (child)
{
length -= m_frame < child->m_frames.size() ? child->m_frames[m_frame] : (child->m_frames.isEmpty() ? 0 : child->m_frames.back());
child = child->m_next;
}
return length;
}
else
{
float length = block->m_frames.isEmpty() ? 0 : block->m_frames.back();
Block* child = block->m_first_child;
while (child)
{
length -= child->m_frames.isEmpty() ? 0 : child->m_frames.back();
child = child->m_next;
}
return length;
}
}
break;
case Values::HIT_COUNT:
return m_frame >= 0 && m_frame < block->m_hit_counts.size() ? block->m_hit_counts[m_frame] : (block->m_hit_counts.isEmpty() ? 0 : block->m_hit_counts.back());
break;
@ -256,9 +286,11 @@ ProfilerUI::ProfilerUI(QWidget* parent)
: QDockWidget(parent)
, m_ui(new Ui::ProfilerUI)
{
m_model = new ProfileModel;
m_sortable_model = new QSortFilterProxyModel(this);
m_model = new ProfileModel(this);
m_sortable_model->setSourceModel(m_model);
m_ui->setupUi(this);
m_ui->profileTreeView->setModel(m_model);
m_ui->profileTreeView->setModel(m_sortable_model);
m_ui->profileTreeView->header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
m_ui->profileTreeView->header()->setSectionResizeMode(1, QHeaderView::ResizeMode::ResizeToContents);
m_ui->profileTreeView->header()->setSectionResizeMode(2, QHeaderView::ResizeMode::ResizeToContents);
@ -277,14 +309,14 @@ void ProfilerUI::on_dataChanged()
ProfilerUI::~ProfilerUI()
{
delete m_ui;
delete m_model;
}
void ProfilerUI::on_recordCheckBox_stateChanged(int)
{
Lumix::g_profiler.toggleRecording();
m_ui->profileTreeView->setModel(NULL);
m_ui->profileTreeView->setModel(m_model);
m_sortable_model->setSourceModel(m_model);
m_ui->profileTreeView->setModel(m_sortable_model);
m_ui->profileTreeView->update();
}

View file

@ -1,7 +1,8 @@
#pragma once
#include <QAbstractItemModel>
#include <QDockWidget>
#include <qabstractitemmodel.h>
#include <QSortFilterProxyModel>
#include "core/profiler.h"
namespace Ui
@ -11,6 +12,7 @@ class ProfilerUI;
class ProfileModel;
class ProfilerUI : public QDockWidget
{
Q_OBJECT
@ -28,8 +30,10 @@ private slots:
private:
Ui::ProfilerUI* m_ui;
ProfileModel* m_model;
QSortFilterProxyModel* m_sortable_model;
};
class ProfileModel : public QAbstractItemModel
{
public:
@ -38,6 +42,7 @@ class ProfileModel : public QAbstractItemModel
NAME,
FUNCTION,
LENGTH,
LENGTH_EXCLUSIVE,
HIT_COUNT,
COUNT
};
@ -56,7 +61,7 @@ class ProfileModel : public QAbstractItemModel
};
public:
ProfileModel();
ProfileModel(QWidget* parent);
Block* getRoot() { return m_root; }
void setFrame(int frame) { m_frame = frame; }

View file

@ -76,14 +76,23 @@
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>true</bool>
</attribute>
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="headerDefaultSectionSize">
<number>200</number>
</attribute>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>true</bool>
</attribute>
<attribute name="headerStretchLastSection">
<bool>false</bool>
<bool>true</bool>
</attribute>
</widget>
<widget class="ProfilerGraph" name="graphView" native="true"/>

File diff suppressed because it is too large Load diff

View file

@ -4,16 +4,17 @@
#include <QDockWidget>
#include "core/array.h"
#include "core/string.h"
#include "core/resource.h"
#include "universe/entity.h"
namespace Lumix
{
struct Component;
class WorldEditor;
struct Entity;
class Event;
class Path;
struct PropertyListEvent;
class Resource;
class WorldEditor;
}
namespace Ui
@ -21,89 +22,98 @@ namespace Ui
class PropertyView;
}
class AssetBrowser;
class QTreeWidgetItem;
class ScriptCompiler;
class PropertyViewObject : public QObject
{
Q_OBJECT
public:
typedef PropertyViewObject* (*Creator)(PropertyViewObject*, Lumix::Resource*);
public:
PropertyViewObject(PropertyViewObject* parent, const char* name)
: m_name(name)
, m_parent(parent)
{ }
virtual ~PropertyViewObject();
const char* getName() const { return m_name.c_str(); }
PropertyViewObject** getMembers() { return m_members.empty() ? NULL : &m_members[0]; }
int getMemberCount() const { return m_members.size(); }
void addMember(PropertyViewObject* member) { m_members.push(member); }
void removeMember(PropertyViewObject* member) { m_members.eraseItem(member); }
PropertyViewObject* getParent() const { return m_parent; }
virtual void createEditor(class PropertyView& view, QTreeWidgetItem* item) = 0;
virtual bool isEditable() const = 0;
private:
Lumix::string m_name;
Lumix::Array<PropertyViewObject*> m_members;
PropertyViewObject* m_parent;
};
class PropertyView : public QDockWidget
{
Q_OBJECT
public:
class Property
{
public:
enum Type
{
FILE,
STRING,
DECIMAL,
VEC3,
BOOL
};
Type m_type;
uint32_t m_component;
Lumix::string m_name;
Lumix::string m_file_type;
Lumix::string m_component_name;
uint32_t m_name_hash;
QTreeWidgetItem* m_tree_item;
};
public:
explicit PropertyView(QWidget* parent = NULL);
~PropertyView();
void setWorldEditor(Lumix::WorldEditor& server);
void setWorldEditor(Lumix::WorldEditor& editor);
Lumix::WorldEditor* getWorldEditor();
void setScriptCompiler(ScriptCompiler* compiler);
void setAssetBrowser(AssetBrowser& asset_browser);
void addResourcePlugin(PropertyViewObject::Creator plugin);
Lumix::Resource* getSelectedResource() const { return m_selected_resource; }
void setSelectedResourceFilename(const char* filename);
void setSelectedResource(Lumix::Resource* resource);
void setObject(PropertyViewObject* object);
PropertyViewObject* getObject();
void addTerrainCustomProperties(QTreeWidgetItem& item, const Lumix::Component& terrain_component);
void refresh();
void setEntityTemplateList(class EntityTemplateList* list) { m_entity_template_list = list; }
private slots:
void on_addComponentButton_clicked();
void on_checkboxStateChanged();
void on_doubleSpinBoxValueChanged();
void on_vec3ValueChanged();
void on_lineEditEditingFinished();
void on_browseFilesClicked();
void on_compileScriptClicked();
void on_editScriptClicked();
void on_animablePlayPause();
void on_animableTimeSet(int value);
void on_terrainBrushSizeChanged(int value);
void on_terrainBrushStrengthChanged(int value);
void on_TerrainHeightTypeClicked();
void on_TerrainTextureTypeClicked();
void on_terrainBrushTextureChanged(int value);
void on_TerrainHeightSaveClicked();
void on_TerrainSplatSaveClicked();
void on_positionX_valueChanged(double arg1);
void on_positionY_valueChanged(double arg1);
void on_positionZ_valueChanged(double arg1);
void on_propertyList_customContextMenuRequested(const QPoint &pos);
void on_positionX_valueChanged(double arg1);
void on_positionY_valueChanged(double arg1);
void on_positionZ_valueChanged(double arg1);
void on_propertyList_customContextMenuRequested(const QPoint &pos);
void on_nameEdit_editingFinished();
private:
void createObjectEditor(QTreeWidgetItem* item, PropertyViewObject* object);
void clear();
void onUniverseCreated();
void onUniverseDestroyed();
void onEntitySelected(Lumix::Entity& e);
void onEntityPosition(Lumix::Entity& e);
void addProperty(const char* component, const char* name, const char* label, Property::Type type, const char* file_type);
void onPropertyValue(Property* property, const void* data, int32_t data_size);
void onEntitySelected(const Lumix::Array<Lumix::Entity>& e);
void onEntityPosition(const Lumix::Entity& e);
void addScriptCustomProperties();
void addAnimableCustomProperties(const Lumix::Component& cmp);
void addTerrainCustomProperties(const Lumix::Component& terrain_component);
void onScriptCompiled(const Lumix::Path& path, uint32_t status);
void setScriptStatus(uint32_t status);
void updateValues();
void updateSelectedEntityPosition();
void onSelectedResourceLoaded(Lumix::Resource::State old_state, Lumix::Resource::State new_state);
private:
Ui::PropertyView* m_ui;
Lumix::Array<Property*> m_properties;
ScriptCompiler* m_compiler;
Lumix::Entity m_selected_entity;
Lumix::WorldEditor* m_world_editor;
bool m_is_updating_values;
class TerrainEditor* m_terrain_editor;
AssetBrowser* m_asset_browser;
Lumix::Resource* m_selected_resource;
Lumix::Array<PropertyViewObject::Creator> m_resource_plugins;
PropertyViewObject* m_object;
class EntityTemplateList* m_entity_template_list;
};

View file

@ -6,17 +6,29 @@
<rect>
<x>0</x>
<y>0</y>
<width>380</width>
<width>356</width>
<height>446</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Properties</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>9</number>
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
@ -32,50 +44,126 @@
</property>
<item>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="horizontalSpacing">
<number>2</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Position</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="positionX">
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-999999.000000000000000</double>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
<item row="0" column="1">
<widget class="QWidget" name="widget_4" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QDoubleSpinBox" name="positionX">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-999999.000000000000000</double>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="positionY">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-999999.000000000000000</double>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="positionZ">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-999999.000000000000000</double>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="positionY">
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-999999.000000000000000</double>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
<item row="1" column="1">
<widget class="QLineEdit" name="nameEdit"/>
</item>
<item>
<widget class="QDoubleSpinBox" name="positionZ">
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-999999.000000000000000</double>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
@ -84,6 +172,12 @@
</item>
<item>
<widget class="QTreeWidget" name="propertyList">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
@ -104,6 +198,12 @@
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>

View file

@ -1,19 +1,26 @@
#include "sceneview.h"
#include "editor/world_editor.h"
#include "core/crc32.h"
#include "editor/ieditor_command.h"
#include "engine/engine.h"
#include "engine/iplugin.h"
#include "graphics/pipeline.h"
#include "graphics/render_scene.h"
#include "insert_mesh_command.h"
#include <qapplication.h>
#include <QDoubleSpinBox>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QMouseEvent>
#include <QVBoxLayout>
#include "core/crc32.h"
#include "graphics/pipeline.h"
class ViewWidget : public QWidget
{
public:
ViewWidget(QWidget* parent)
ViewWidget(SceneView& view, QWidget* parent)
: QWidget(parent)
, m_view(view)
{
setMouseTracking(true);
}
@ -26,6 +33,16 @@ class ViewWidget : public QWidget
setFocus();
}
virtual void wheelEvent(QWheelEvent* event) override
{
float speed = m_view.getNavivationSpeed();
if (QApplication::keyboardModifiers() & Qt::ShiftModifier)
{
speed *= 10;
}
m_world_editor->navigate(event->delta() * 0.1f, 0, speed);
}
virtual void mouseMoveEvent(QMouseEvent* event) override
{
int flags = 0;
@ -44,6 +61,7 @@ class ViewWidget : public QWidget
Lumix::WorldEditor* m_world_editor;
int m_last_x;
int m_last_y;
SceneView& m_view;
};
SceneView::SceneView(QWidget* parent) :
@ -53,7 +71,7 @@ SceneView::SceneView(QWidget* parent) :
QWidget* root = new QWidget();
QVBoxLayout* vertical_layout = new QVBoxLayout(root);
QHBoxLayout* horizontal_layout = new QHBoxLayout(root);
m_view = new ViewWidget(root);
m_view = new ViewWidget(*this, root);
m_speed_input = new QDoubleSpinBox(root);
m_speed_input->setSingleStep(0.1f);
m_speed_input->setValue(0.1f);
@ -98,12 +116,24 @@ void SceneView::dropEvent(QDropEvent *event)
QString file = list[0].toLocalFile();
if(file.endsWith(".msh"))
{
m_world_editor->addEntityAt(event->pos().x(), event->pos().y());
m_world_editor->addComponent(crc32("renderable"));
char rel_path[LUMIX_MAX_PATH];
m_world_editor->getRelativePath(rel_path, LUMIX_MAX_PATH, file.toLatin1().data());
m_world_editor->setProperty("renderable", "source", rel_path, strlen(rel_path));
m_world_editor->selectEntity(m_world_editor->getSelectedEntity());
Lumix::Vec3 position;
Lumix::RenderScene* scene = static_cast<Lumix::RenderScene*>(m_world_editor->getEditCamera().scene);
Lumix::Vec3 origin;
Lumix::Vec3 dir;
scene->getRay(m_world_editor->getEditCamera(), event->pos().x(), event->pos().y(), origin, dir);
Lumix::RayCastModelHit hit = scene->castRay(origin, dir, Lumix::Component::INVALID);
if (hit.m_is_hit)
{
position = hit.m_origin + hit.m_dir * hit.m_t;
}
else
{
position.set(0, 0, 0);
}
InsertMeshCommand* command = new InsertMeshCommand(*static_cast<ViewWidget&>(*m_view).m_world_editor, position, file.toLatin1().data());
m_world_editor->executeCommand(command);
m_world_editor->selectEntities(&command->getEntity(), 1);
}
}
}

View file

@ -16,7 +16,7 @@ class SceneView : public QDockWidget
Q_OBJECT
public:
explicit SceneView(QWidget* parent = NULL);
void setWorldEditor(Lumix::WorldEditor* server);
void setWorldEditor(Lumix::WorldEditor* editor);
void setPipeline(Lumix::PipelineInstance& pipeline) { m_pipeline = &pipeline; }
QWidget* getViewWidget() { return m_view; }
float getNavivationSpeed() const;

View file

@ -18,7 +18,7 @@ struct Quat;
struct Vec3;
class LUMIX_ENGINE_API AnimationManager : public ResourceManagerBase
class LUMIX_ANIMATION_API AnimationManager : public ResourceManagerBase
{
public:
AnimationManager() : ResourceManagerBase() {}
@ -30,7 +30,7 @@ protected:
};
class Animation : public Resource
class LUMIX_ANIMATION_API Animation : public Resource
{
public:
Animation(const Path& path, ResourceManager& resource_manager);

View file

@ -8,16 +8,23 @@
#include "graphics/renderer.h"
#include "universe/universe.h"
namespace Lumix
{
extern "C" IPlugin* createPlugin()
{
return AnimationSystem::createInstance();
}
static const uint32_t RENDERABLE_HASH = crc32("renderable");
static const uint32_t ANIMABLE_HASH = crc32("animable");
struct AnimationSystemImpl : public AnimationSystem
class AnimationSceneImpl : public AnimationScene
{
public:
private:
struct Animable
{
bool m_manual;
@ -27,28 +34,25 @@ namespace Lumix
class Animation* m_animation;
};
void onCreateUniverse(Universe& universe)
public:
AnimationSceneImpl(AnimationSystem& anim_system, Engine& engine, Universe& universe)
: m_universe(universe)
, m_engine(engine)
, m_anim_system(anim_system)
{
ASSERT(!m_universe);
m_universe = &universe;
m_universe->componentCreated().bind<AnimationSystemImpl, &AnimationSystemImpl::onComponentCreated>(this);
m_universe.componentCreated().bind<AnimationSceneImpl, &AnimationSceneImpl::onComponentCreated>(this);
}
void onDestroyUniverse(Universe&)
~AnimationSceneImpl()
{
ASSERT(m_universe);
m_animables.clear();
m_universe->componentCreated().unbind<AnimationSystemImpl, &AnimationSystemImpl::onComponentCreated>(this);
m_universe = 0;
m_universe.componentCreated().unbind<AnimationSceneImpl, &AnimationSceneImpl::onComponentCreated>(this);
}
virtual Component createComponent(uint32_t component_type, const Entity& entity) override
virtual Component createComponent(uint32_t type, const Entity& entity) override
{
if (component_type == ANIMABLE_HASH)
if (type == ANIMABLE_HASH)
{
return createAnimable(entity);
}
@ -56,12 +60,11 @@ namespace Lumix
}
virtual void destroyComponent(const Component& component) override
virtual void destroyComponent(const Component& component)
{
m_animables[component.index].m_is_free = true;
m_universe->removeComponent(component);
m_universe->componentDestroyed().invoke(component);
m_universe.destroyComponent(component);
m_universe.componentDestroyed().invoke(component);
}
@ -91,7 +94,7 @@ namespace Lumix
serializer.deserializeArrayItem(m_animables[i].m_manual);
int entity_index;
serializer.deserializeArrayItem(entity_index);
Entity e(m_universe, entity_index);
Entity e(&m_universe, entity_index);
const Entity::ComponentList& cmps = e.getComponents();
m_animables[i].m_renderable = Component::INVALID;
for (int j = 0; j < cmps.size(); ++j)
@ -104,70 +107,12 @@ namespace Lumix
}
serializer.deserializeArrayItem(m_animables[i].m_time);
serializer.deserializeArrayItem(m_animables[i].m_is_free);
m_universe->addComponent(e, ANIMABLE_HASH, this, i);
m_universe.addComponent(e, ANIMABLE_HASH, this, i);
}
serializer.deserializeArrayEnd();
}
void onComponentCreated(Component& cmp)
{
if (cmp.type == RENDERABLE_HASH)
{
const Entity::ComponentList& cmps = cmp.entity.getComponents();
for (int i = 0; i < cmps.size(); ++i)
{
if (cmps[i].type == ANIMABLE_HASH)
{
m_animables[cmps[i].index].m_renderable = cmp;
break;
}
}
}
}
Component createAnimable(const Entity& entity)
{
Animable* src = NULL;
for (int i = 0, c = m_animables.size(); i < c; ++i)
{
if (m_animables[i].m_is_free)
{
src = &m_animables[i];
break;
}
}
Animable& animable = src ? *src : m_animables.pushEmpty();
animable.m_manual = true;
animable.m_time = 0;
animable.m_is_free = false;
animable.m_renderable = Component::INVALID;
animable.m_animation = NULL;
const Entity::ComponentList& cmps = entity.getComponents();
for (int i = 0; i < cmps.size(); ++i)
{
if (cmps[i].type == RENDERABLE_HASH)
{
animable.m_renderable = cmps[i];
break;
}
}
Component cmp = m_universe->addComponent(entity, ANIMABLE_HASH, this, m_animables.size() - 1);
m_universe->componentCreated().invoke(cmp);
return cmp;
}
Animation* loadAnimation(const char* path)
{
ResourceManager& rm = m_engine->getResourceManager();
return static_cast<Animation*>(rm.get(ResourceManager::ANIMATION)->load(path));
}
virtual void setFrame(Component cmp, int frame) override
{
m_animables[cmp.index].m_time = m_animables[cmp.index].m_animation->getLength() * frame / 30.0f; /// TODO get rid of the constant
@ -224,16 +169,17 @@ namespace Lumix
return -1;
}
virtual void update(float time_delta) override
{
if (m_animables.empty())
return;
for (int i = 0, c = m_animables.size(); i < c; ++i)
{
AnimationSystemImpl::Animable& animable = m_animables[i];
Animable& animable = m_animables[i];
if (!animable.m_is_free && animable.m_animation && animable.m_animation->isReady())
{
RenderScene* scene = static_cast<RenderScene*>(animable.m_renderable.system);
RenderScene* scene = static_cast<RenderScene*>(animable.m_renderable.scene);
animable.m_animation->getPose(animable.m_time, scene->getPose(animable.m_renderable), *scene->getModel(animable.m_renderable));
if (!animable.m_manual)
{
@ -250,6 +196,89 @@ namespace Lumix
}
private:
Animation* loadAnimation(const char* path)
{
ResourceManager& rm = m_engine.getResourceManager();
return static_cast<Animation*>(rm.get(ResourceManager::ANIMATION)->load(path));
}
void onComponentCreated(const Component& cmp)
{
if (cmp.type == RENDERABLE_HASH)
{
const Entity::ComponentList& cmps = cmp.entity.getComponents();
for (int i = 0; i < cmps.size(); ++i)
{
if (cmps[i].type == ANIMABLE_HASH)
{
m_animables[cmps[i].index].m_renderable = cmp;
break;
}
}
}
}
Component createAnimable(const Entity& entity)
{
Animable* src = NULL;
for (int i = 0, c = m_animables.size(); i < c; ++i)
{
if (m_animables[i].m_is_free)
{
src = &m_animables[i];
break;
}
}
Animable& animable = src ? *src : m_animables.pushEmpty();
animable.m_manual = true;
animable.m_time = 0;
animable.m_is_free = false;
animable.m_renderable = Component::INVALID;
animable.m_animation = NULL;
const Entity::ComponentList& cmps = entity.getComponents();
for (int i = 0; i < cmps.size(); ++i)
{
if (cmps[i].type == RENDERABLE_HASH)
{
animable.m_renderable = cmps[i];
break;
}
}
Component cmp = m_universe.addComponent(entity, ANIMABLE_HASH, this, m_animables.size() - 1);
m_universe.componentCreated().invoke(cmp);
return cmp;
}
virtual IPlugin& getPlugin() const override
{
return m_anim_system;
}
private:
Universe& m_universe;
AnimationSystem& m_anim_system;
Engine& m_engine;
Array<Animable> m_animables;
};
struct AnimationSystemImpl : public AnimationSystem
{
public:
virtual IScene* createScene(Universe& universe) override
{
ASSERT(m_engine);
return LUMIX_NEW(AnimationSceneImpl)(*this, *m_engine, universe);
}
virtual const char* getName() const override
{
return "animation";
@ -259,23 +288,19 @@ namespace Lumix
virtual bool create(Engine& engine) override
{
m_engine = &engine;
m_universe = 0;
if (engine.getWorldEditor())
{
engine.getWorldEditor()->registerCreator(ANIMABLE_HASH, *this);
}
engine.getWorldEditor()->registerProperty("animable", LUMIX_NEW(PropertyDescriptor<AnimationSystem>)(crc32("preview"), &AnimationSystem::getPreview, &AnimationSystem::setPreview, IPropertyDescriptor::FILE));
engine.getWorldEditor()->registerProperty("animable", LUMIX_NEW(FilePropertyDescriptor<AnimationSceneImpl>)("preview", &AnimationSceneImpl::getPreview, &AnimationSceneImpl::setPreview, "Animation (*.ani)"));
m_animation_manager.create(ResourceManager::ANIMATION, engine.getResourceManager());
return true;
}
virtual void destroy() override
{
m_engine->getResourceManager().get(ResourceManager::ANIMATION)->releaseAll();
}
Array<Animable> m_animables;
Universe* m_universe;
Engine* m_engine;
AnimationManager m_animation_manager;
private:
void operator=(const AnimationSystemImpl&);

View file

@ -19,11 +19,9 @@ namespace Lumix
class ISerializer;
class Universe;
class LUMIX_ENGINE_API AnimationSystem : public IPlugin
class LUMIX_ANIMATION_API AnimationScene : public IScene
{
public:
static AnimationSystem* createInstance();
virtual void setFrame(Component cmp, int frame) = 0;
virtual bool isManual(Component cmp) = 0;
virtual void setManual(Component cmp, bool is_manual) = 0;
@ -33,7 +31,20 @@ namespace Lumix
virtual void playAnimation(const Component& cmp, const char* path) = 0;
virtual void setAnimationFrame(const Component& cmp, int frame) = 0;
virtual int getFrameCount(const Component& cmp) const = 0;
virtual void update(float time_delta) = 0;
};
class LUMIX_ANIMATION_API AnimationSystem : public IPlugin
{
public:
static AnimationSystem* createInstance();
};
extern "C"
{
LUMIX_ANIMATION_API IPlugin* createPlugin();
}
}// ~ namespace Lumix

View file

@ -86,6 +86,18 @@ class Array<T, Allocator, false>
}
}
void eraseItem(const T& item)
{
for (int i = 0; i < m_size; ++i)
{
if (m_data[i] == item)
{
erase(i);
return;
}
}
}
void erase(int index)
{
if(index >= 0 && index < m_size)
@ -293,6 +305,26 @@ public:
m_allocator.deallocate(m_data);
}
void swap(Array<T, Allocator, true>& rhs)
{
int i = rhs.m_capacity;
rhs.m_capacity = m_capacity;
m_capacity = i;
i = m_size;
m_size = rhs.m_size;
rhs.m_size = i;
T* p = rhs.m_data;
rhs.m_data = m_data;
m_data = p;
Allocator a = rhs.m_allocator;
rhs.m_allocator = m_allocator;
m_allocator = a;
}
void eraseFast(int index)
{
if (index >= 0 && index < m_size)
@ -326,6 +358,32 @@ public:
}
}
void eraseItem(const T& item)
{
for (int i = 0; i < m_size; ++i)
{
if (m_data[i] == item)
{
erase(i);
return;
}
}
}
void insert(int index, const T& value)
{
if (m_size == m_capacity)
{
grow();
}
memmove(m_data + index + 1, m_data + index, m_size - index);
m_data[index] = value;
++m_size;
}
void push(const T& value)
{
if (m_size == m_capacity)

View file

@ -482,7 +482,10 @@ namespace Lumix
node_type* next = n->m_next;
destruct(n);
construct(n, next ? *next : m_sentinel);
destruct(next);
if (next)
{
destruct(next);
}
m_allocator.deallocate(next);
}
else

View file

@ -282,7 +282,7 @@ void JsonSerializer::deserializeRawString(char* buffer, int max_length)
{
strncpy(buffer, m_token, max_length);
size_t token_length = strlen(m_token);
if (token_length + 2 <= max_length)
if (token_length + 2 <= (size_t)max_length)
{
buffer[token_length] = '\n';
buffer[token_length + 1] = m_buffer;

View file

@ -29,54 +29,60 @@
const uint32_t LUMIX_MAX_PATH = 260;
#ifndef ASSERT
#ifdef _WIN32
#ifdef NDEBUG
#define ASSERT(x) { false ? (void)(x) : 0; }
#else
#define ASSERT(x) { const volatile bool lumix_assert_b____ = !(x); if(lumix_assert_b____) __debugbreak(); }
#endif
#else
#define ASSERT(x) assert(x)
#endif
#ifdef _WIN32
#ifdef NDEBUG
#define ASSERT(x) { false ? (void)(x) : 0; }
#else
#define ASSERT(x) { const volatile bool lumix_assert_b____ = !(x); if(lumix_assert_b____) __debugbreak(); }
#endif
#else
#define ASSERT(x) assert(x)
#endif
#endif
#ifndef NULL
#define NULL nullptr
#define NULL nullptr
#endif
#define LUMIX_FORCE_INLINE __forceinline
#ifdef BUILDING_CORE
#define LUMIX_CORE_API __declspec(dllexport)
#define LUMIX_CORE_API __declspec(dllexport)
#else
#define LUMIX_CORE_API __declspec(dllimport)
#define LUMIX_CORE_API __declspec(dllimport)
#endif
#ifdef BUILDING_PHYSICS
#define LUMIX_PHYSICS_API __declspec(dllexport)
#define LUMIX_PHYSICS_API __declspec(dllexport)
#else
#define LUMIX_PHYSICS_API __declspec(dllimport)
#define LUMIX_PHYSICS_API __declspec(dllimport)
#endif
#ifdef BUILDING_NAVIGATION
#define LUMIX_NAVIGATION_API __declspec(dllexport)
#define LUMIX_NAVIGATION_API __declspec(dllexport)
#else
#define LUMIX_NAVIGATION_API __declspec(dllimport)
#define LUMIX_NAVIGATION_API __declspec(dllimport)
#endif
#ifdef BUILDING_ENGINE
#define LUMIX_ENGINE_API __declspec(dllexport)
#define LUMIX_ENGINE_API __declspec(dllexport)
#else
#define LUMIX_ENGINE_API __declspec(dllimport)
#define LUMIX_ENGINE_API __declspec(dllimport)
#endif
#ifdef BUILDING_SCRIPT
#define LUMIX_SCRIPT_API __declspec(dllexport)
#define LUMIX_SCRIPT_API __declspec(dllexport)
#else
#define LUMIX_SCRIPT_API __declspec(dllimport)
#define LUMIX_SCRIPT_API __declspec(dllimport)
#endif
#ifdef BUILDING_ANIMATION
#define LUMIX_ANIMATION_API __declspec(dllexport)
#else
#define LUMIX_ANIMATION_API __declspec(dllimport)
#endif
#define LUMIX_RESTRICT __restrict
@ -85,4 +91,5 @@ const uint32_t LUMIX_MAX_PATH = 260;
#include "core/new_macros.h"
#pragma warning(disable : 4251)
#pragma warning(disable : 4512)
#pragma warning(disable : 4996)

View file

@ -36,6 +36,16 @@ class Map
this->node = node;
}
Value& value()
{
return node->value;
}
Key& key()
{
return node->key;
}
Value& second()
{
return node->value;
@ -189,6 +199,11 @@ class Map
m_root = deleteNode(key, m_root);
}
void erase(iterator& iter)
{
m_root = deleteNode(iter.key(), m_root);
}
private:
void clearNode(Node* node)
{

View file

@ -93,8 +93,7 @@ void EditorIcon::render(Renderer* renderer, IRenderDevice& render_device)
Component camera = m_scene->getCameraInSlot("editor");
Lumix::Matrix mtx = camera.entity.getMatrix();
float fov;
static_cast<RenderScene*>(camera.system)->getCameraFOV(camera, fov);
float fov = static_cast<RenderScene*>(camera.scene)->getCameraFOV(camera);
float scale = tan(fov * Math::PI / 180 * 0.5f) * (m_entity.getPosition() - mtx.getTranslation()).length() / 20;
mtx.setTranslation(m_entity.getPosition());

View file

@ -4,25 +4,105 @@
#include "core/iserializer.h"
#include "core/map.h"
#include "core/string.h"
#include "editor/ieditor_command.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "engine/iplugin.h"
#include "graphics/render_scene.h"
#include "universe/entity.h"
#include "universe/universe.h"
static const uint32_t RENDERABLE_HASH = crc32("renderable");
static const uint32_t CAMERA_HASH = crc32("camera");
static const uint32_t LIGHT_HASH = crc32("light");
static const uint32_t SCRIPT_HASH = crc32("script");
static const uint32_t ANIMABLE_HASH = crc32("animable");
static const uint32_t TERRAIN_HASH = crc32("terrain");
namespace Lumix
{
class EntityTemplateSystemImpl : public EntityTemplateSystem
{
private:
class CreateInstanceCommand : public IEditorCommand
{
public:
CreateInstanceCommand(EntityTemplateSystemImpl& entity_system, const char* template_name, const Vec3& position)
: m_entity_system(entity_system)
, m_template_name_hash(crc32(template_name))
, m_position(position)
{
}
virtual void execute() override
{
Map<uint32_t, Array<Entity> >::iterator iter = m_entity_system.m_instances.find(m_template_name_hash);
if (iter != m_entity_system.m_instances.end())
{
m_entity = m_entity_system.m_editor.getEngine().getUniverse()->createEntity();
m_entity.setPosition(m_position);
m_entity_system.m_instances[m_template_name_hash].push(m_entity);
Entity template_entity = iter.second()[0];
const Entity::ComponentList& template_cmps = template_entity.getComponents();
for (int i = 0; i < template_cmps.size(); ++i)
{
m_entity_system.m_editor.cloneComponent(template_cmps[i], m_entity);
}
}
else
{
ASSERT(false);
}
}
virtual void undo() override
{
const Entity::ComponentList& cmps = m_entity.getComponents();
for (int i = 0; i < cmps.size(); ++i)
{
cmps[i].scene->destroyComponent(cmps[i]);
}
m_entity_system.m_universe->destroyEntity(m_entity);
m_entity = Entity::INVALID;
}
virtual bool merge(IEditorCommand&) override
{
return false;
}
virtual uint32_t getType() override
{
static const uint32_t hash = crc32("create_entity_template_instance");
return hash;
}
const Entity& getEntity() const { return m_entity; }
private:
EntityTemplateSystemImpl& m_entity_system;
uint32_t m_template_name_hash;
Entity m_entity;
Vec3 m_position;
};
public:
EntityTemplateSystemImpl(WorldEditor& editor)
: m_editor(editor)
, m_universe(NULL)
{
m_universe = editor.getEngine().getUniverse();
editor.universeCreated().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
editor.universeDestroyed().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
setUniverse(editor.getEngine().getUniverse());
}
@ -30,6 +110,21 @@ namespace Lumix
{
m_editor.universeCreated().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
m_editor.universeDestroyed().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
setUniverse(NULL);
}
void setUniverse(Universe* universe)
{
if (m_universe)
{
m_universe->entityDestroyed().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onEntityDestroyed>(this);
}
m_universe = universe;
if (m_universe)
{
m_universe->entityDestroyed().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onEntityDestroyed>(this);
}
}
@ -37,7 +132,7 @@ namespace Lumix
{
m_instances.clear();
m_template_names.clear();
m_universe = m_editor.getEngine().getUniverse();
setUniverse(m_editor.getEngine().getUniverse());
}
@ -45,7 +140,30 @@ namespace Lumix
{
m_instances.clear();
m_template_names.clear();
m_universe = NULL;
setUniverse(NULL);
}
void onEntityDestroyed(const Entity& entity)
{
uint32_t tpl = getTemplate(entity);
if (tpl != 0)
{
Array<Entity>& instances = m_instances[tpl];
instances.eraseItemFast(entity);
if (instances.empty())
{
m_instances.erase(tpl);
for (int i = 0; i < m_template_names.size(); ++i)
{
if (crc32(m_template_names[i].c_str()) == tpl)
{
m_template_names.eraseFast(i);
break;
}
}
}
}
}
@ -88,27 +206,11 @@ namespace Lumix
}
virtual Entity createInstance(const char* name) override
virtual Entity createInstance(const char* name, const Vec3& position) override
{
uint32_t name_hash = crc32(name);
Map<uint32_t, Array<Entity> >::iterator iter = m_instances.find(name_hash);
if (iter == m_instances.end())
{
ASSERT(false);
return Entity::INVALID;
}
else
{
Entity entity = m_editor.addEntity();
m_instances[name_hash].push(entity);
Entity template_entity = iter.second()[0];
const Entity::ComponentList& template_cmps = template_entity.getComponents();
for (int i = 0; i < template_cmps.size(); ++i)
{
m_editor.cloneComponent(template_cmps[i], entity);
}
return entity;
}
CreateInstanceCommand* command = LUMIX_NEW(CreateInstanceCommand)(*this, name, position);
m_editor.executeCommand(command);
return command->getEntity();
}

View file

@ -26,7 +26,7 @@ namespace Lumix
virtual uint32_t getTemplate(const Entity& entity) = 0;
virtual const Array<Entity>& getInstances(uint32_t template_name_hash) = 0;
virtual class Array<string>& getTemplateNames() = 0;
virtual Entity createInstance(const char* name) = 0;
virtual Entity createInstance(const char* name, const Vec3& position) = 0;
virtual DelegateList<void()>& updated() = 0;
};

View file

@ -23,7 +23,6 @@ Gizmo::Gizmo(WorldEditor& editor)
: m_editor(editor)
{
m_model = NULL;
m_selected_entity.index = -1;
}
@ -46,35 +45,22 @@ void Gizmo::create(Renderer& renderer)
}
void Gizmo::hide()
{
//ASSERT(false);
}
void Gizmo::show()
{
//ASSERT(false);
}
void Gizmo::getMatrix(Matrix& mtx)
{
m_selected_entity.getMatrix(mtx);
m_editor.getSelectedEntities()[0].getMatrix(mtx);
}
void Gizmo::updateScale(Component camera)
{
if (m_selected_entity.isValid())
if (!m_editor.getSelectedEntities().empty())
{
Matrix camera_mtx;
camera.entity.getMatrix(camera_mtx);
Matrix mtx;
getMatrix(mtx);
Vec3 pos = mtx.getTranslation();
float fov;
static_cast<RenderScene*>(camera.system)->getCameraFOV(camera, fov);
float fov = static_cast<RenderScene*>(camera.scene)->getCameraFOV(camera);
float scale = tanf(fov * Math::PI / 180 * 0.5f) * (mtx.getTranslation() - camera_mtx.getTranslation()).length() * 2;
scale /= 20 * mtx.getXVector().length();
m_scale = scale;
@ -82,20 +68,6 @@ void Gizmo::updateScale(Component camera)
}
void Gizmo::setEntity(Entity entity)
{
m_selected_entity = entity;
if(m_selected_entity.index != -1)
{
show();
}
else
{
hide();
}
}
void Gizmo::setUniverse(Universe* universe)
{
m_universe = universe;
@ -104,9 +76,11 @@ void Gizmo::setUniverse(Universe* universe)
RayCastModelHit Gizmo::castRay(const Vec3& origin, const Vec3& dir)
{
if (m_selected_entity.isValid())
if (!m_editor.getSelectedEntities().empty())
{
return m_model->castRay(origin, dir, m_selected_entity.getMatrix(), m_scale);
Matrix mtx;
getMatrix(mtx);
return m_model->castRay(origin, dir, mtx, m_scale);
}
RayCastModelHit hit;
hit.m_is_hit = false;
@ -116,11 +90,13 @@ RayCastModelHit Gizmo::castRay(const Vec3& origin, const Vec3& dir)
void Gizmo::render(Renderer& renderer, IRenderDevice& render_device)
{
if(m_selected_entity.isValid())
if(!m_editor.getSelectedEntities().empty())
{
Matrix scale_mtx = Matrix::IDENTITY;
scale_mtx.m11 = scale_mtx.m22 = scale_mtx.m33 = m_scale;
Matrix mtx = m_selected_entity.getMatrix() * scale_mtx;
Matrix gizmo_mtx;
getMatrix(gizmo_mtx);
Matrix mtx = gizmo_mtx * scale_mtx;
renderer.renderModel(*m_model, mtx, render_device.getPipeline());
}
}
@ -136,13 +112,15 @@ void Gizmo::startTransform(Component camera, int x, int y, TransformMode mode)
void Gizmo::transform(Component camera, TransformOperation operation, int x, int y, int relx, int rely, int flags)
{
if(m_selected_entity.index != -1)
if(operation == TransformOperation::ROTATE && m_transform_mode != TransformMode::CAMERA_XZ)
{
if(operation == TransformOperation::ROTATE && m_transform_mode != TransformMode::CAMERA_XZ)
Array<Vec3> new_positions;
Array<Quat> new_rotations;
for(int i = 0, c = m_editor.getSelectedEntities().size(); i < c; ++i)
{
Vec3 pos = m_selected_entity.getPosition();
Vec3 pos = m_editor.getSelectedEntities()[i].getPosition();
Matrix emtx;
m_selected_entity.getMatrix(emtx);
m_editor.getSelectedEntities()[i].getMatrix(emtx);
Vec3 axis;
switch(m_transform_mode)
{
@ -180,19 +158,26 @@ void Gizmo::transform(Component camera, TransformOperation operation, int x, int
{
angle = (relx + rely) / 100.0f;
}
Quat new_rot = m_selected_entity.getRotation() * Quat(axis, angle);
Quat new_rot = m_editor.getSelectedEntities()[i].getRotation() * Quat(axis, angle);
new_rot.normalize();
m_editor.setEntityPositionAndRotaion(m_selected_entity, pos, new_rot);
new_rotations.push(new_rot);
new_positions.push(pos);
}
else
m_editor.setEntityPositionAndRotaion(m_editor.getSelectedEntities(), new_positions, new_rotations);
}
else
{
Vec3 intersection = getMousePlaneIntersection(camera, x, y);
Vec3 delta = intersection - m_transform_point;
Array<Vec3> new_positions;
for(int i = 0, ci = m_editor.getSelectedEntities().size(); i < ci; ++i)
{
Vec3 intersection = getMousePlaneIntersection(camera, x, y);
Vec3 delta = intersection - m_transform_point;
m_transform_point = intersection;
Vec3 pos = m_selected_entity.getPosition();
Vec3 pos = m_editor.getSelectedEntities()[i].getPosition();
pos += delta;
m_editor.setEntityPosition(m_selected_entity, pos);
new_positions.push(pos);
}
m_editor.setEntitiesPositions(m_editor.getSelectedEntities(), new_positions);
m_transform_point = intersection;
}
}
@ -200,18 +185,20 @@ void Gizmo::transform(Component camera, TransformOperation operation, int x, int
Vec3 Gizmo::getMousePlaneIntersection(Component camera, int x, int y)
{
Vec3 origin, dir;
RenderScene* scene = static_cast<RenderScene*>(camera.system);
RenderScene* scene = static_cast<RenderScene*>(camera.scene);
scene->getRay(camera, (float)x, (float)y, origin, dir);
dir.normalize();
Matrix camera_mtx;
camera.entity.getMatrix(camera_mtx);
Matrix gizmo_mtx;
getMatrix(gizmo_mtx);
if(m_transform_mode == TransformMode::CAMERA_XZ)
{
Vec3 a = crossProduct(Vec3(0, 1, 0), camera_mtx.getXVector());
Vec3 b = crossProduct(Vec3(0, 1, 0), camera_mtx.getZVector());
Vec3 plane_normal = crossProduct(a, b);
float t;
if (Math::getRayPlaneIntersecion(origin, dir, m_selected_entity.getPosition(), plane_normal, t))
if (Math::getRayPlaneIntersecion(origin, dir, gizmo_mtx.getTranslation(), plane_normal, t))
{
return origin + dir * t;
}
@ -221,16 +208,16 @@ Vec3 Gizmo::getMousePlaneIntersection(Component camera, int x, int y)
switch(m_transform_mode)
{
case TransformMode::X:
axis = m_selected_entity.getMatrix().getXVector();
axis = gizmo_mtx.getXVector();
break;
case TransformMode::Y:
axis = m_selected_entity.getMatrix().getYVector();
axis = gizmo_mtx.getYVector();
break;
case TransformMode::Z:
axis = m_selected_entity.getMatrix().getZVector();
axis = gizmo_mtx.getZVector();
break;
}
Vec3 pos = m_selected_entity.getPosition();
Vec3 pos = gizmo_mtx.getTranslation();
Vec3 normal = crossProduct(crossProduct(dir, axis), dir);
float d = dotProduct(origin - pos, normal) / dotProduct(axis, normal);
return axis * d + pos;

View file

@ -79,10 +79,7 @@ class LUMIX_ENGINE_API Gizmo
void create(Renderer& renderer);
void destroy();
void hide();
void show();
void updateScale(Component camera);
void setEntity(Entity entity);
void setUniverse(Universe* universe);
void startTransform(Component camera, int x, int y, TransformMode mode);
void transform(Component camera, TransformOperation operation, int x, int y, int relx, int rely, int flags);
@ -96,7 +93,6 @@ class LUMIX_ENGINE_API Gizmo
private:
WorldEditor& m_editor;
Renderer* m_renderer;
Entity m_selected_entity;
Universe* m_universe;
TransformMode m_transform_mode;
Vec3 m_transform_point;

View file

@ -2,6 +2,7 @@
#include "universe\universe.h"
#include "core/blob.h"
#include "core/crc32.h"
#include "core/delegate.h"
#include "core/string.h"
@ -24,172 +25,597 @@ class IPropertyDescriptor
BOOL,
VEC3,
INTEGER,
STRING
STRING,
ARRAY
};
public:
virtual ~IPropertyDescriptor() {}
virtual void set(Component cmp, Blob& stream) const = 0;
virtual void get(Component cmp, Blob& stream) const = 0;
virtual void set(Component cmp, int index, Blob& stream) const = 0;
virtual void get(Component cmp, int index, Blob& stream) const = 0;
uint32_t getNameHash() const { return m_name_hash; }
Type getType() const { return m_type; }
uint32_t getNameHash() const { return m_name_hash; }
const char* getName() const { return m_name.c_str(); }
void setName(const char* name) { m_name = name; m_name_hash = crc32(name); }
void addChild(IPropertyDescriptor* child) { m_children.push(child); }
const Array<IPropertyDescriptor*>& getChildren() const { return m_children; }
Array<IPropertyDescriptor*>& getChildren() { return m_children; }
protected:
uint32_t m_name_hash;
string m_name;
Type m_type;
Array<IPropertyDescriptor*> m_children;
};
class IIntPropertyDescriptor : public IPropertyDescriptor
{
public:
IIntPropertyDescriptor()
{
m_min = INT_MIN;
m_max = INT_MAX;
}
void setLimit(int min, int max) { m_min = min; m_max = max; }
int getMin() const { return m_min; }
int getMax() const { return m_max; }
private:
int m_min;
int m_max;
};
template <class S>
class PropertyDescriptor : public IPropertyDescriptor
class IntArrayObjectDescriptor : public IIntPropertyDescriptor
{
public:
typedef int (S::*IntegerGetter)(Component, int);
typedef void (S::*IntegerSetter)(Component, int, int);
public:
IntArrayObjectDescriptor(const char* name, IntegerGetter _getter, IntegerSetter _setter)
{
setName(name);
m_integer_getter = _getter;
m_integer_setter = _setter;
m_type = INTEGER;
}
virtual void set(Component cmp, int index, Blob& stream) const override
{
int32_t i;
stream.read(&i, sizeof(i));
(static_cast<S*>(cmp.scene)->*m_integer_setter)(cmp, index, i);
}
virtual void get(Component cmp, int index, Blob& stream) const override
{
int32_t i = (static_cast<S*>(cmp.scene)->*m_integer_getter)(cmp, index);
int len = sizeof(i);
stream.write(&i, len);
}
virtual void set(Component, Blob&) const {};
virtual void get(Component, Blob&) const {};
private:
IntegerGetter m_integer_getter;
IntegerSetter m_integer_setter;
};
template <class S>
class BoolArrayObjectDescriptor : public IPropertyDescriptor
{
public:
typedef void (S::*Getter)(Component, int, int&);
typedef void (S::*Setter)(Component, int, const int&);
public:
BoolArrayObjectDescriptor(const char* name, Getter _getter, Setter _setter)
{
setName(name);
m_getter = _getter;
m_setter = _setter;
m_type = BOOL;
}
virtual void set(Component cmp, int index, Blob& stream) const override
{
bool b;
stream.read(&b, sizeof(b));
(static_cast<S*>(cmp.scene)->*m_setter)(cmp, index, b);
}
virtual void get(Component cmp, int index, Blob& stream) const override
{
bool b;
(static_cast<S*>(cmp.scene)->*m_getter)(cmp, index, b);
stream.write(&b, sizeof(b));
}
virtual void set(Component, Blob&) const { ASSERT(false); };
virtual void get(Component, Blob&) const { ASSERT(false); };
private:
Getter m_getter;
Setter m_setter;
};
template <class S>
class DecimalArrayObjectDescriptor : public IPropertyDescriptor
{
public:
typedef float (S::*Getter)(Component, int);
typedef void (S::*Setter)(Component, int, float);
public:
DecimalArrayObjectDescriptor(const char* name, Getter _getter, Setter _setter)
{
setName(name);
m_getter = _getter;
m_setter = _setter;
m_type = DECIMAL;
}
virtual void set(Component cmp, int index, Blob& stream) const override
{
float f;
stream.read(&f, sizeof(f));
(static_cast<S*>(cmp.scene)->*m_setter)(cmp, index, f);
}
virtual void get(Component cmp, int index, Blob& stream) const override
{
float f = (static_cast<S*>(cmp.scene)->*m_getter)(cmp, index);
stream.write(&f, sizeof(f));
}
virtual void set(Component, Blob&) const { ASSERT(false); };
virtual void get(Component, Blob&) const { ASSERT(false); };
private:
Getter m_getter;
Setter m_setter;
};
template <class S>
class StringArrayObjectDescriptor : public IPropertyDescriptor
{
public:
typedef void (S::*Getter)(Component, int, string&);
typedef void (S::*Setter)(Component, int, const string&);
public:
StringArrayObjectDescriptor(const char* name, Getter _getter, Setter _setter)
{
setName(name);
m_getter = _getter;
m_setter = _setter;
m_type = STRING;
}
virtual void set(Component cmp, int index, Blob& stream) const override
{
char tmp[300];
char* c = tmp;
do
{
stream.read(c, 1);
++c;
}
while (*(c - 1) && (c - 1) - tmp < 300);
string s((char*)tmp);
(static_cast<S*>(cmp.scene)->*m_setter)(cmp, index, s);
}
virtual void get(Component cmp, int index, Blob& stream) const override
{
string value;
(static_cast<S*>(cmp.scene)->*m_getter)(cmp, index, value);
int len = value.length() + 1;
stream.write(value.c_str(), len);
}
virtual void set(Component, Blob&) const { ASSERT(false); };
virtual void get(Component, Blob&) const { ASSERT(false); };
private:
Getter m_getter;
Setter m_setter;
};
template <class S>
class FileArrayObjectDescriptor : public StringArrayObjectDescriptor<S>, public IFilePropertyDescriptor
{
public:
FileArrayObjectDescriptor(const char* name, Getter getter, Setter setter, const char* file_type)
: StringArrayObjectDescriptor(name, getter, setter)
, m_file_type(file_type)
{
m_type = IPropertyDescriptor::FILE;
}
virtual const char* getFileType() override
{
return m_file_type.c_str();
}
private:
string m_file_type;
};
template <class S>
class Vec3ArrayObjectDescriptor : public IPropertyDescriptor
{
public:
typedef Vec3 (S::*Getter)(Component, int);
typedef void (S::*Setter)(Component, int, const Vec3&);
public:
Vec3ArrayObjectDescriptor(const char* name, Getter _getter, Setter _setter) { setName(name); m_vec3_getter = _getter; m_vec3_setter = _setter; m_type = VEC3; }
virtual void set(Component cmp, int index, Blob& stream) const override
{
Vec3 v;
stream.read(&v, sizeof(v));
(static_cast<S*>(cmp.scene)->*m_vec3_setter)(cmp, index, v);
}
virtual void get(Component cmp, int index, Blob& stream) const override
{
Vec3 v = (static_cast<S*>(cmp.scene)->*m_vec3_getter)(cmp, index);
len = sizeof(v);
stream.write(&v, len);
}
virtual void set(Component, Blob&) const {};
virtual void get(Component, Blob&) const {};
private:
Getter m_getter;
Setter m_setter;
};
class IArrayDescriptor : public IPropertyDescriptor
{
public:
virtual void removeArrayItem(Component cmp, int index) const = 0;
virtual void addArrayItem(Component cmp, int index) const = 0;
virtual int getCount(Component cmp) const = 0;
};
template <class S>
class ArrayDescriptor : public IArrayDescriptor
{
public:
typedef int (S::*Counter)(Component);
typedef void (S::*Adder)(Component, int);
typedef void (S::*Remover)(Component, int);
public:
ArrayDescriptor(const char* name, Counter counter, Adder adder, Remover remover) { setName(name); m_type = ARRAY; m_counter = counter; m_adder = adder; m_remover = remover; }
~ArrayDescriptor()
{
for(int i = 0; i < m_children.size(); ++i)
{
LUMIX_DELETE(m_children[i]);
}
}
virtual void set(Component cmp, Blob& stream) const override
{
int count;
stream.read(count);
while (getCount(cmp) < count)
{
addArrayItem(cmp, -1);
}
while (getCount(cmp) > count)
{
removeArrayItem(cmp, getCount(cmp) - 1);
}
for (int i = 0; i < count; ++i)
{
for (int j = 0, cj = getChildren().size(); j < cj; ++j)
{
getChildren()[j]->set(cmp, i, stream);
}
}
}
virtual void get(Component cmp, Blob& stream) const override
{
int count = getCount(cmp);
stream.write(count);
for (int i = 0; i < count; ++i)
{
for (int j = 0, cj = getChildren().size(); j < cj; ++j)
{
getChildren()[j]->get(cmp, i, stream);
}
}
}
virtual void set(Component, int, Blob&) const override { ASSERT(false); };
virtual void get(Component, int, Blob&) const override { ASSERT(false); };
virtual int getCount(Component cmp) const override { return (static_cast<S*>(cmp.scene)->*m_counter)(cmp); }
virtual void addArrayItem(Component cmp, int index) const override { (static_cast<S*>(cmp.scene)->*m_adder)(cmp, index); }
virtual void removeArrayItem(Component cmp, int index) const override { (static_cast<S*>(cmp.scene)->*m_remover)(cmp, index); }
private:
Counter m_counter;
Adder m_adder;
Remover m_remover;
};
template <class S>
class IntPropertyDescriptor : public IIntPropertyDescriptor
{
public:
typedef int (S::*IntegerGetter)(Component);
typedef void (S::*IntegerSetter)(Component, int);
public:
IntPropertyDescriptor(const char* name, IntegerGetter _getter, IntegerSetter _setter) { setName(name); m_integer_getter = _getter; m_integer_setter = _setter; m_type = INTEGER; }
virtual void set(Component cmp, Blob& stream) const override
{
int32_t i;
stream.read(&i, sizeof(i));
(static_cast<S*>(cmp.scene)->*m_integer_setter)(cmp, i);
}
virtual void get(Component cmp, Blob& stream) const override
{
int32_t i = (static_cast<S*>(cmp.scene)->*m_integer_getter)(cmp);
len = sizeof(i);
stream.write(&i, len);
}
virtual void set(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); set(cmp, stream); };
virtual void get(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); get(cmp, stream); };
private:
IntegerGetter m_integer_getter;
IntegerSetter m_integer_setter;
};
template <class S>
class StringPropertyDescriptor : public IPropertyDescriptor
{
public:
typedef void (S::*Getter)(Component, string&);
typedef void (S::*Setter)(Component, const string&);
typedef void (S::*BoolGetter)(Component, bool&);
typedef void (S::*BoolSetter)(Component, const bool&);
typedef void (S::*DecimalGetter)(Component, float&);
typedef void (S::*DecimalSetter)(Component, const float&);
typedef void (S::*IntegerGetter)(Component, int&);
typedef void (S::*IntegerSetter)(Component, const int&);
typedef void (S::*Vec3Getter)(Component, Vec3&);
typedef void (S::*Vec3Setter)(Component, const Vec3&);
public:
PropertyDescriptor(uint32_t _name_hash, Getter _getter, Setter _setter, Type _type) { m_name_hash = _name_hash; m_getter = _getter; m_setter = _setter; m_type = _type; }
PropertyDescriptor(uint32_t _name_hash, BoolGetter _getter, BoolSetter _setter) { m_name_hash = _name_hash; m_bool_getter = _getter; m_bool_setter = _setter; m_type = BOOL; }
PropertyDescriptor(uint32_t _name_hash, DecimalGetter _getter, DecimalSetter _setter) { m_name_hash = _name_hash; m_decimal_getter = _getter; m_decimal_setter = _setter; m_type = DECIMAL; }
PropertyDescriptor(uint32_t _name_hash, IntegerGetter _getter, IntegerSetter _setter) { m_name_hash = _name_hash; m_integer_getter = _getter; m_integer_setter = _setter; m_type = INTEGER; }
PropertyDescriptor(uint32_t _name_hash, Vec3Getter _getter, Vec3Setter _setter) { m_name_hash = _name_hash; m_vec3_getter = _getter; m_vec3_setter = _setter; m_type = VEC3; }
virtual void set(Component cmp, Blob& stream) const override;
virtual void get(Component cmp, Blob& stream) const override;
StringPropertyDescriptor(const char* name, Getter getter, Setter setter)
{
setName(name);
m_getter = getter;
m_setter = setter;
m_type = IPropertyDescriptor::STRING;
}
virtual void set(Component cmp, Blob& stream) const override
{
char tmp[300];
char* c = tmp;
do
{
stream.read(c, 1);
++c;
}
while (*(c - 1) && (c - 1) - tmp < 300);
string s((char*)tmp);
(static_cast<S*>(cmp.scene)->*m_setter)(cmp, s);
}
virtual void get(Component cmp, Blob& stream) const override
{
string value;
(static_cast<S*>(cmp.scene)->*m_getter)(cmp, value);
int len = value.length() + 1;
stream.write(value.c_str(), len);
}
virtual void set(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); set(cmp, stream); };
virtual void get(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); get(cmp, stream); };
private:
union
{
Getter m_getter;
BoolGetter m_bool_getter;
DecimalGetter m_decimal_getter;
IntegerGetter m_integer_getter;
Vec3Getter m_vec3_getter;
};
union
{
Setter m_setter;
BoolSetter m_bool_setter;
DecimalSetter m_decimal_setter;
IntegerSetter m_integer_setter;
Vec3Setter m_vec3_setter;
};
Getter m_getter;
Setter m_setter;
};
template <class S>
void PropertyDescriptor<S>::set(Component cmp, Blob& stream) const
class BoolPropertyDescriptor : public IPropertyDescriptor
{
int len = stream.getBufferSize();
switch(m_type)
{
case DECIMAL:
{
float f;
stream.read(&f, sizeof(f));
(static_cast<S*>(cmp.system)->*m_decimal_setter)(cmp, f);
}
break;
case INTEGER:
{
int32_t i;
stream.read(&i, sizeof(i));
(static_cast<S*>(cmp.system)->*m_integer_setter)(cmp, i);
}
break;
case BOOL:
{
bool b;
stream.read(&b, sizeof(b));
(static_cast<S*>(cmp.system)->*m_bool_setter)(cmp, b);
}
break;
case STRING:
case FILE:
{
char tmp[301];
ASSERT(len < 300);
stream.read(tmp, len);
tmp[len] = '\0';
string s((char*)tmp);
(static_cast<S*>(cmp.system)->*m_setter)(cmp, s);
}
break;
case VEC3:
{
Vec3 v;
stream.read(&v, sizeof(v));
(static_cast<S*>(cmp.system)->*m_vec3_setter)(cmp, v);
}
break;
default:
ASSERT(false);
break;
}
}
public:
typedef void (S::*Getter)(Component, bool&);
typedef void (S::*Setter)(Component, const bool&);
public:
BoolPropertyDescriptor(const char* name, Getter getter, Setter setter)
{
setName(name);
m_getter = getter;
m_setter = setter;
m_type = IPropertyDescriptor::BOOL;
}
virtual void set(Component cmp, Blob& stream) const override
{
bool b;
stream.read(&b, sizeof(b));
(static_cast<S*>(cmp.scene)->*m_setter)(cmp, b);
}
virtual void get(Component cmp, Blob& stream) const override
{
bool b;
(static_cast<S*>(cmp.scene)->*m_getter)(cmp, b);
int len = sizeof(b);
stream.write(&b, len);
}
virtual void set(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); set(cmp, stream); };
virtual void get(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); get(cmp, stream); };
private:
Getter m_getter;
Setter m_setter;
};
template <class S>
void PropertyDescriptor<S>::get(Component cmp, Blob& stream) const
class Vec3PropertyDescriptor : public IPropertyDescriptor
{
int len = 4;
switch(m_type)
{
case STRING:
case FILE:
{
string value;
(static_cast<S*>(cmp.system)->*m_getter)(cmp, value);
len = value.length() + 1;
stream.write(value.c_str(), len);
}
break;
case DECIMAL:
{
float f;
(static_cast<S*>(cmp.system)->*m_decimal_getter)(cmp, f);
len = sizeof(f);
stream.write(&f, len);
}
break;
case INTEGER:
{
int32_t i;
(static_cast<S*>(cmp.system)->*m_integer_getter)(cmp, i);
len = sizeof(i);
stream.write(&i, len);
}
break;
case BOOL:
{
bool b;
(static_cast<S*>(cmp.system)->*m_bool_getter)(cmp, b);
len = sizeof(b);
stream.write(&b, len);
}
break;
case VEC3:
{
Vec3 v;
(static_cast<S*>(cmp.system)->*m_vec3_getter)(cmp, v);
len = sizeof(v);
stream.write(&v, len);
}
break;
default:
ASSERT(false);
break;
}
}
public:
typedef Vec3 (S::*Getter)(Component);
typedef void (S::*Setter)(Component, const Vec3&);
public:
Vec3PropertyDescriptor(const char* name, Getter getter, Setter setter)
{
setName(name);
m_getter = getter;
m_setter = setter;
m_type = IPropertyDescriptor::VEC3;
}
virtual void set(Component cmp, Blob& stream) const override
{
Vec3 v;
stream.read(&v, sizeof(v));
(static_cast<S*>(cmp.scene)->*m_setter)(cmp, v);
}
virtual void get(Component cmp, Blob& stream) const override
{
Vec3 v = (static_cast<S*>(cmp.scene)->*m_getter)(cmp);
int len = sizeof(v);
stream.write(&v, len);
}
virtual void set(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); set(cmp, stream); };
virtual void get(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); get(cmp, stream); };
private:
Getter m_getter;
Setter m_setter;
};
class IFilePropertyDescriptor
{
public:
virtual const char* getFileType() = 0;
};
template <class T>
class FilePropertyDescriptor : public StringPropertyDescriptor<T>, public IFilePropertyDescriptor
{
public:
FilePropertyDescriptor(const char* name, Getter getter, Setter setter, const char* file_type)
: StringPropertyDescriptor(name, getter, setter)
, m_file_type(file_type)
{
m_type = IPropertyDescriptor::FILE;
}
virtual const char* getFileType() override
{
return m_file_type.c_str();
}
private:
string m_file_type;
};
template <class S>
class DecimalPropertyDescriptor : public IPropertyDescriptor
{
public:
typedef float (S::*Getter)(Component);
typedef void (S::*Setter)(Component, float);
public:
DecimalPropertyDescriptor(const char* name, Getter _getter, Setter _setter) { setName(name); m_getter = _getter; m_setter = _setter; m_type = DECIMAL; }
virtual void set(Component cmp, Blob& stream) const override
{
float f;
stream.read(&f, sizeof(f));
(static_cast<S*>(cmp.scene)->*m_setter)(cmp, f);
}
virtual void get(Component cmp, Blob& stream) const override
{
float f = (static_cast<S*>(cmp.scene)->*m_getter)(cmp);
int len = sizeof(f);
stream.write(&f, len);
}
virtual void set(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); set(cmp, stream); };
virtual void get(Component cmp, int index, Blob& stream) const override { ASSERT(index == -1); get(cmp, stream);};
private:
Getter m_getter;
Setter m_setter;
};
} // !namespace Lumix

File diff suppressed because it is too large Load diff

View file

@ -51,11 +51,12 @@ namespace Lumix
public:
static WorldEditor* create(const char* base_path);
static void destroy(WorldEditor* server);
static void destroy(WorldEditor* editor);
virtual void tick() = 0;
virtual void registerCreator(uint32_t type, IPlugin& creator) = 0;
virtual void registerProperty(const char* component_type, IPropertyDescriptor* descriptor) = 0;
virtual IPropertyDescriptor* getProperty(const char* component_type, const char* property_name) = 0;
virtual void executeCommand(class IEditorCommand* command) = 0;
virtual Engine& getEngine() = 0;
virtual void render(IRenderDevice& render_device) = 0;
virtual void renderIcons(IRenderDevice& render_device) = 0;
@ -71,16 +72,20 @@ namespace Lumix
virtual Path getUniversePath() const = 0;
virtual void addComponent(uint32_t type_crc) = 0;
virtual void cloneComponent(const Component& src, Entity& entity) = 0;
virtual void removeComponent(const Component& crc) = 0;
virtual void destroyComponent(const Component& crc) = 0;
virtual Entity addEntity() = 0;
virtual void selectEntity(Entity e) = 0;
virtual void destroyEntities(const Entity* entities, int count) = 0;
virtual void selectEntities(const Entity* entities, int count) = 0;
virtual Entity addEntityAt(int camera_x, int camera_y) = 0;
virtual void setEntityPosition(const Entity& entity, const Vec3& position) = 0;
virtual void setEntityPositionAndRotaion(const Entity& entity, const Vec3& position, const Quat& rotation) = 0;
virtual void setEntitiesPositions(const Array<Entity>& entity, const Array<Vec3>& position) = 0;
virtual void setEntityPositionAndRotaion(const Array<Entity>& entity, const Array<Vec3>& position, const Array<Quat>& rotation) = 0;
virtual void setEntityName(const Entity& entity, const char* name) = 0;
virtual void snapToTerrain() = 0;
virtual void toggleGameMode() = 0;
virtual void navigate(float forward, float right, float speed) = 0;
virtual void setProperty(const char* component, const char* property, const void* data, int size) = 0;
virtual void setProperty(uint32_t component, int index, IPropertyDescriptor& property, const void* data, int size) = 0;
virtual void addArrayPropertyItem(const Component& cmp, IArrayDescriptor& property) = 0;
virtual void removeArrayPropertyItem(const Component& cmp, int index, IArrayDescriptor& property) = 0;
virtual void onMouseDown(int x, int y, MouseButton::Value button) = 0;
virtual void onMouseMove(int x, int y, int relx, int rely, int mouse_flags) = 0;
virtual void onMouseUp(int x, int y, MouseButton::Value button) = 0;
@ -89,14 +94,18 @@ namespace Lumix
virtual void setWireframe(bool is_wireframe) = 0;
virtual void lookAtSelected() = 0;
virtual const char* getBasePath() = 0;
virtual Entity getSelectedEntity() const = 0;
virtual const Array<Entity>& getSelectedEntities() const = 0;
virtual const IPropertyDescriptor& getPropertyDescriptor(uint32_t type, uint32_t name_hash) = 0;
virtual DelegateList<void(Entity&)>& entitySelected() = 0;
virtual Array<IPropertyDescriptor*>& getPropertyDescriptors(uint32_t type) = 0;
virtual DelegateList<void(const Array<Entity>&)>& entitySelected() = 0;
virtual DelegateList<void()>& universeCreated() = 0;
virtual DelegateList<void()>& universeDestroyed() = 0;
virtual DelegateList<void()>& universeLoaded() = 0;
virtual DelegateList<void(const Entity&, const char*)>& entityNameSet() = 0;
virtual void addPlugin(Plugin* plugin) = 0;
virtual void getRelativePath(char* relative_path, int max_length, const Path& source) = 0;
virtual EntityTemplateSystem& getEntityTemplateSystem() = 0;
virtual Vec3 getCameraRaycastHit() = 0;
protected:
virtual ~WorldEditor() {}

View file

@ -1,8 +1,6 @@
#include "core/lumix.h"
#include "engine/engine.h"
#include "animation/animation.h"
#include "animation/animation_system.h"
#include "core/crc32.h"
#include "core/input_system.h"
@ -34,38 +32,285 @@
namespace Lumix
{
struct EngineImpl
class EngineImpl : public Engine
{
EngineImpl(Engine& engine) : m_owner(engine) {}
~EngineImpl();
bool create(const char* base_path, Engine& owner);
public:
EngineImpl(const char* base_path, FS::FileSystem* file_system, WorldEditor* world_editor)
{
m_editor = world_editor;
if (NULL == file_system)
{
m_file_system = FS::FileSystem::create();
Renderer* m_renderer;
FS::FileSystem* m_file_system;
FS::MemoryFileDevice* m_mem_file_device;
FS::DiskFileDevice* m_disk_file_device;
m_mem_file_device = LUMIX_NEW(FS::MemoryFileDevice);
m_disk_file_device = LUMIX_NEW(FS::DiskFileDevice);
ResourceManager m_resource_manager;
MaterialManager m_material_manager;
ModelManager m_model_manager;
ShaderManager m_shader_manager;
TextureManager m_texture_manager;
PipelineManager m_pipeline_manager;
AnimationManager m_animation_manager;
m_file_system->mount(m_mem_file_device);
m_file_system->mount(m_disk_file_device);
m_file_system->setDefaultDevice("memory:disk");
m_file_system->setSaveGameDevice("memory:disk");
}
else
{
m_file_system = file_system;
m_mem_file_device = NULL;
m_disk_file_device = NULL;
}
MTJD::Manager m_mtjd_manager;
// CullingSystem* m_culling_system;
string m_base_path;
WorldEditor* m_editor_server;
PluginManager m_plugin_manager;
Universe* m_universe;
RenderScene* m_render_scene;
InputSystem m_input_system;
Engine& m_owner;
Timer* m_timer;
Timer* m_fps_timer;
int m_fps_frame;
float m_fps;
m_resource_manager.create(*m_file_system);
m_material_manager.create(ResourceManager::MATERIAL, m_resource_manager);
m_model_manager.create(ResourceManager::MODEL, m_resource_manager);
m_shader_manager.create(ResourceManager::SHADER, m_resource_manager);
m_texture_manager.create(ResourceManager::TEXTURE, m_resource_manager);
m_pipeline_manager.create(ResourceManager::PIPELINE, m_resource_manager);
m_timer = Timer::create();
m_fps_timer = Timer::create();
m_fps_frame = 0;
m_universe = 0;
m_base_path = base_path;
}
bool create()
{
if (!m_plugin_manager.create(*this))
{
return false;
}
m_renderer = Renderer::createInstance();
if (!m_renderer)
{
return false;
}
if (!m_renderer->create(*this))
{
Renderer::destroyInstance(*m_renderer);
return false;
}
m_plugin_manager.addPlugin(m_renderer);
if (!m_input_system.create())
{
return false;
}
return true;
}
virtual ~EngineImpl()
{
m_resource_manager.get(ResourceManager::TEXTURE)->releaseAll();
m_resource_manager.get(ResourceManager::MATERIAL)->releaseAll();
m_resource_manager.get(ResourceManager::SHADER)->releaseAll();
m_resource_manager.get(ResourceManager::MODEL)->releaseAll();
m_resource_manager.get(ResourceManager::PIPELINE)->releaseAll();
Timer::destroy(m_timer);
Timer::destroy(m_fps_timer);
m_plugin_manager.destroy();
m_input_system.destroy();
m_material_manager.destroy();
if (m_disk_file_device)
{
FS::FileSystem::destroy(m_file_system);
LUMIX_DELETE(m_mem_file_device);
LUMIX_DELETE(m_disk_file_device);
}
}
virtual Universe* createUniverse() override
{
m_universe = LUMIX_NEW(Universe)();
const Array<IPlugin*>& plugins = m_plugin_manager.getPlugins();
for (int i = 0; i < plugins.size(); ++i)
{
IScene* scene = plugins[i]->createScene(*m_universe);
if (scene)
{
m_scenes.push(scene);
}
}
return m_universe;
}
virtual IScene* getScene(uint32_t type) const override
{
for (int i = 0; i < m_scenes.size(); ++i)
{
if (crc32(m_scenes[i]->getPlugin().getName()) == type)
{
return m_scenes[i];
}
}
return NULL;
}
virtual const Array<IScene*>& getScenes() const override
{
return m_scenes;
}
// m_impl->m_culling_system = CullingSystem::create(m_impl->m_mtjd_manager);
virtual void destroyUniverse() override
{
ASSERT(m_universe);
if (m_universe)
{
for (int i = 0; i < m_scenes.size(); ++i)
{
LUMIX_DELETE(m_scenes[i]);
}
m_scenes.clear();
LUMIX_DELETE(m_universe);
m_universe = NULL;
}
}
virtual WorldEditor* getWorldEditor() const override
{
return m_editor;
}
virtual PluginManager& getPluginManager() override
{
return m_plugin_manager;
}
virtual FS::FileSystem& getFileSystem() override
{
return *m_file_system;
}
virtual Renderer& getRenderer() override
{
return *m_renderer;
}
virtual void update(bool is_game_running) override
{
if (is_game_running)
{
++m_fps_frame;
if (m_fps_frame == 30)
{
m_fps = 30.0f / m_fps_timer->tick();
m_fps_frame = 0;
}
}
float dt = m_timer->tick();
m_last_time_delta = dt;
for (int i = 0; i < m_scenes.size(); ++i)
{
m_scenes[i]->update(dt);
}
if (is_game_running)
{
m_plugin_manager.update(dt);
m_input_system.update(dt);
}
}
virtual IPlugin* loadPlugin(const char* name) override
{
return m_plugin_manager.load(name);
}
virtual InputSystem& getInputSystem() override
{
return m_input_system;
}
virtual const char* getBasePath() const override
{
return m_base_path.c_str();
}
virtual Universe* getUniverse() const override
{
return m_universe;
}
virtual ResourceManager& getResourceManager() override
{
return m_resource_manager;
}
virtual float getFPS() const override
{
return m_fps;
}
virtual void serialize(ISerializer& serializer) override
{
m_universe->serialize(serializer);
m_renderer->serialize(serializer);
m_plugin_manager.serialize(serializer);
for (int i = 0; i < m_scenes.size(); ++i)
{
m_scenes[i]->serialize(serializer);
}
}
virtual void deserialize(ISerializer& serializer) override
{
m_universe->deserialize(serializer);
m_renderer->deserialize(serializer);
m_plugin_manager.deserialize(serializer);
for (int i = 0; i < m_scenes.size(); ++i)
{
m_scenes[i]->deserialize(serializer);
}
}
virtual float getLastTimeDelta() override
{
return m_last_time_delta;
}
private:
Renderer* m_renderer;
FS::FileSystem* m_file_system;
FS::MemoryFileDevice* m_mem_file_device;
FS::DiskFileDevice* m_disk_file_device;
ResourceManager m_resource_manager;
MaterialManager m_material_manager;
ModelManager m_model_manager;
ShaderManager m_shader_manager;
TextureManager m_texture_manager;
PipelineManager m_pipeline_manager;
string m_base_path;
WorldEditor* m_editor;
PluginManager m_plugin_manager;
Universe* m_universe;
Array<IScene*> m_scenes;
InputSystem m_input_system;
Timer* m_timer;
Timer* m_fps_timer;
int m_fps_frame;
float m_fps;
float m_last_time_delta;
private:
void operator=(const EngineImpl&);
@ -79,262 +324,25 @@ namespace Lumix
}
EngineImpl::~EngineImpl()
{
m_resource_manager.get(ResourceManager::TEXTURE)->releaseAll();
m_resource_manager.get(ResourceManager::MATERIAL)->releaseAll();
m_resource_manager.get(ResourceManager::SHADER)->releaseAll();
m_resource_manager.get(ResourceManager::ANIMATION)->releaseAll();
m_resource_manager.get(ResourceManager::MODEL)->releaseAll();
m_resource_manager.get(ResourceManager::PIPELINE)->releaseAll();
}
bool EngineImpl::create(const char* base_path, Engine& owner)
{
m_timer = Timer::create();
m_fps_timer = Timer::create();
m_fps_frame = 0;
m_universe = 0;
m_base_path = base_path;
m_render_scene = NULL;
m_renderer = Renderer::createInstance();
if(!m_renderer)
{
return false;
}
if(!m_renderer->create(owner))
{
Renderer::destroyInstance(*m_renderer);
return false;
}
if(!m_plugin_manager.create(owner))
{
return false;
}
AnimationSystem* anim_system = AnimationSystem::createInstance();
if(!anim_system->create(owner))
{
LUMIX_DELETE(anim_system);
return false;
}
m_plugin_manager.addPlugin(anim_system);
if(!m_input_system.create())
{
return false;
}
return true;
}
bool Engine::create(const char* base_path, FS::FileSystem* file_system, WorldEditor* editor_server)
Engine* Engine::create(const char* base_path, FS::FileSystem* file_system, WorldEditor* editor)
{
g_log_info.getCallback().bind<showLogInVS>();
g_log_warning.getCallback().bind<showLogInVS>();
g_log_error.getCallback().bind<showLogInVS>();
m_impl = LUMIX_NEW(EngineImpl)(*this);
m_impl->m_editor_server = editor_server;
if(NULL == file_system)
EngineImpl* engine = LUMIX_NEW(EngineImpl)(base_path, file_system, editor);
if (!engine->create())
{
m_impl->m_file_system = FS::FileSystem::create();
m_impl->m_mem_file_device = LUMIX_NEW(FS::MemoryFileDevice);
m_impl->m_disk_file_device = LUMIX_NEW(FS::DiskFileDevice);
m_impl->m_file_system->mount(m_impl->m_mem_file_device);
m_impl->m_file_system->mount(m_impl->m_disk_file_device);
m_impl->m_file_system->setDefaultDevice("memory:disk");
m_impl->m_file_system->setSaveGameDevice("memory:disk");
LUMIX_DELETE(engine);
return NULL;
}
else
{
m_impl->m_file_system = file_system;
m_impl->m_mem_file_device = NULL;
m_impl->m_disk_file_device = NULL;
}
if(!m_impl->create(base_path, *this))
{
LUMIX_DELETE(m_impl);
m_impl = NULL;
return false;
}
m_impl->m_resource_manager.create(*m_impl->m_file_system);
m_impl->m_material_manager.create(ResourceManager::MATERIAL, m_impl->m_resource_manager);
m_impl->m_model_manager.create(ResourceManager::MODEL, m_impl->m_resource_manager);
m_impl->m_shader_manager.create(ResourceManager::SHADER, m_impl->m_resource_manager);
m_impl->m_texture_manager.create(ResourceManager::TEXTURE, m_impl->m_resource_manager);
m_impl->m_pipeline_manager.create(ResourceManager::PIPELINE, m_impl->m_resource_manager);
m_impl->m_animation_manager.create(ResourceManager::ANIMATION, m_impl->m_resource_manager);
// m_impl->m_culling_system = CullingSystem::create(m_impl->m_mtjd_manager);
return true;
return engine;
}
void Engine::destroy()
void Engine::destroy(Engine* engine)
{
Timer::destroy(m_impl->m_timer);
Timer::destroy(m_impl->m_fps_timer);
m_impl->m_plugin_manager.destroy();
Renderer::destroyInstance(*m_impl->m_renderer);
// CullingSystem::destroy(*m_impl->m_culling_system);
m_impl->m_input_system.destroy();
m_impl->m_material_manager.destroy();
if(m_impl->m_disk_file_device)
{
FS::FileSystem::destroy(m_impl->m_file_system);
LUMIX_DELETE(m_impl->m_mem_file_device);
LUMIX_DELETE(m_impl->m_disk_file_device);
}
LUMIX_DELETE(m_impl);
m_impl = 0;
}
Universe* Engine::createUniverse()
{
m_impl->m_universe = LUMIX_NEW(Universe)();
m_impl->m_render_scene = RenderScene::createInstance(*this, *m_impl->m_universe);
m_impl->m_plugin_manager.onCreateUniverse(*m_impl->m_universe);
m_impl->m_universe->create();
return m_impl->m_universe;
}
void Engine::destroyUniverse()
{
ASSERT(m_impl->m_universe);
if (m_impl->m_universe)
{
m_impl->m_plugin_manager.onDestroyUniverse(*m_impl->m_universe);
m_impl->m_universe->destroy();
RenderScene::destroyInstance(m_impl->m_render_scene);
m_impl->m_render_scene = NULL;
LUMIX_DELETE(m_impl->m_universe);
m_impl->m_universe = 0;
}
}
WorldEditor* Engine::getWorldEditor() const
{
return m_impl->m_editor_server;
}
PluginManager& Engine::getPluginManager()
{
return m_impl->m_plugin_manager;
}
FS::FileSystem& Engine::getFileSystem()
{
return *m_impl->m_file_system;
}
Renderer& Engine::getRenderer()
{
return *m_impl->m_renderer;
}
void Engine::update(bool is_game_running)
{
if (is_game_running)
{
++m_impl->m_fps_frame;
if (m_impl->m_fps_frame == 30)
{
m_impl->m_fps = 30.0f / m_impl->m_fps_timer->tick();
m_impl->m_fps_frame = 0;
}
}
float dt = m_impl->m_timer->tick();
m_impl->m_render_scene->update(dt);
if (is_game_running)
{
m_impl->m_plugin_manager.update(dt);
m_impl->m_input_system.update(dt);
}
}
IPlugin* Engine::loadPlugin(const char* name)
{
return m_impl->m_plugin_manager.load(name);
}
InputSystem& Engine::getInputSystem()
{
return m_impl->m_input_system;
}
const char* Engine::getBasePath() const
{
return m_impl->m_base_path.c_str();
}
Universe* Engine::getUniverse() const
{
return m_impl->m_universe;
}
RenderScene* Engine::getRenderScene() const
{
return m_impl->m_render_scene;
}
MTJD::Manager& Engine::getMTJDManager() const
{
return m_impl->m_mtjd_manager;
}
//CullingSystem& Engine::getCullingSystem() const
//{
// return *m_impl->m_culling_system;
//}
ResourceManager& Engine::getResourceManager() const
{
return m_impl->m_resource_manager;
}
float Engine::getFPS() const
{
return m_impl->m_fps;
}
void Engine::serialize(ISerializer& serializer)
{
m_impl->m_universe->serialize(serializer);
m_impl->m_renderer->serialize(serializer);
m_impl->m_render_scene->serialize(serializer);
m_impl->m_plugin_manager.serialize(serializer);
}
void Engine::deserialize(ISerializer& serializer)
{
m_impl->m_universe->deserialize(serializer);
m_impl->m_renderer->deserialize(serializer);
m_impl->m_render_scene->deserialize(serializer);
m_impl->m_plugin_manager.deserialize(serializer);
LUMIX_DELETE(engine);
}

View file

@ -1,6 +1,10 @@
#pragma once
#include "core/lumix.h"
#include "core/array.h"
namespace Lumix
{
namespace FS
@ -18,10 +22,10 @@ namespace Lumix
class EditorServer;
class InputSystem;
class IPlugin;
class IScene;
class ISerializer;
class PluginManager;
class Renderer;
class RenderScene;
class ResourceManager;
class Universe;
@ -29,36 +33,37 @@ namespace Lumix
class LUMIX_ENGINE_API Engine
{
public:
Engine() { m_impl = NULL; }
~Engine() { ASSERT(m_impl == NULL); }
virtual ~Engine() {}
bool create(const char* base_path, FS::FileSystem* fs, WorldEditor* editor_server);
void destroy();
static Engine* create(const char* base_path, FS::FileSystem* fs, WorldEditor* editor);
static void destroy(Engine* engine);
Universe* createUniverse();
void destroyUniverse();
virtual Universe* createUniverse() = 0;
virtual void destroyUniverse() = 0;
WorldEditor* getWorldEditor() const;
FS::FileSystem& getFileSystem();
Renderer& getRenderer();
InputSystem& getInputSystem();
PluginManager& getPluginManager();
IPlugin* loadPlugin(const char* name);
Universe* getUniverse() const;
RenderScene* getRenderScene() const;
virtual WorldEditor* getWorldEditor() const = 0;
virtual FS::FileSystem& getFileSystem() = 0;
virtual Renderer& getRenderer() = 0;
virtual InputSystem& getInputSystem() = 0;
virtual PluginManager& getPluginManager() = 0;
virtual IPlugin* loadPlugin(const char* name) = 0;
virtual Universe* getUniverse() const = 0;
virtual const Array<IScene*>& getScenes() const = 0;
virtual IScene* getScene(uint32_t type) const = 0;
MTJD::Manager& getMTJDManager() const;
// CullingSystem& getCullingSystem() const;
ResourceManager& getResourceManager() const;
virtual ResourceManager& getResourceManager() = 0;
const char* getBasePath() const;
void update(bool is_game_running);
void serialize(ISerializer& serializer);
void deserialize(ISerializer& serializer);
float getFPS() const;
virtual const char* getBasePath() const = 0;
virtual void update(bool is_game_running) = 0;
virtual void serialize(ISerializer& serializer) = 0;
virtual void deserialize(ISerializer& serializer) = 0;
virtual float getFPS() const = 0;
virtual float getLastTimeDelta() = 0;
private:
struct EngineImpl* m_impl;
protected:
Engine() {}
};

View file

@ -8,10 +8,25 @@
namespace Lumix
{
class Engine;
class IPlugin;
class ISerializer;
class Universe;
class LUMIX_ENGINE_API IScene abstract
{
public:
virtual ~IScene() {}
virtual Component createComponent(uint32_t, const Entity&) = 0;
virtual void destroyComponent(const Component& component) = 0;
virtual void serialize(ISerializer& serializer) = 0;
virtual void deserialize(ISerializer& serializer) = 0;
virtual IPlugin& getPlugin() const = 0;
virtual void update(float time_delta) = 0;
};
class LUMIX_ENGINE_API IPlugin abstract
{
public:
@ -19,15 +34,13 @@ namespace Lumix
virtual bool create(Engine& engine) = 0;
virtual void destroy() = 0;
virtual void onCreateUniverse(Universe&) {}
virtual void onDestroyUniverse(Universe&) {}
virtual void serialize(ISerializer&) {}
virtual void deserialize(ISerializer&) {}
virtual void update(float) {}
virtual Component createComponent(uint32_t, const Entity&) = 0;
virtual void destroyComponent(const Component& component) = 0;
virtual const char* getName() const = 0;
virtual void sendMessage(const char*) {};
virtual IScene* createScene(Universe&) { return NULL; }
};

View file

@ -45,24 +45,9 @@ namespace Lumix
}
}
void PluginManager::onDestroyUniverse(Universe& universe)
const Array<IPlugin*>& PluginManager::getPlugins() const
{
PluginManagerImpl::PluginList& plugins = m_impl->m_plugins;
for(int i = 0, c = plugins.size(); i < c; ++i)
{
plugins[i]->onDestroyUniverse(universe);
}
}
void PluginManager::onCreateUniverse(Universe& universe)
{
PluginManagerImpl::PluginList& plugins = m_impl->m_plugins;
for(int i = 0, c = plugins.size(); i < c; ++i)
{
plugins[i]->onCreateUniverse(universe);
}
return m_impl->m_plugins;
}
IPlugin* PluginManager::getPlugin(const char* name)

View file

@ -2,6 +2,7 @@
#include "core/lumix.h"
#include "core/array.h"
namespace Lumix
@ -24,9 +25,8 @@ namespace Lumix
void update(float dt);
void serialize(ISerializer& serializer);
void deserialize(ISerializer& serializer);
void onDestroyUniverse(Universe& universe);
void onCreateUniverse(Universe& universe);
IPlugin* getPlugin(const char* name);
const Array<IPlugin*>& getPlugins() const;
private:
struct PluginManagerImpl* m_impl;

View file

@ -110,7 +110,7 @@ int VertexDef::getPositionOffset() const
}
void VertexDef::begin(Shader& shader)
void VertexDef::begin(Shader& shader) const
{
PROFILE_FUNCTION();
int offset = 0;
@ -167,7 +167,7 @@ void VertexDef::begin(Shader& shader)
}
void VertexDef::end(Shader& shader)
void VertexDef::end(Shader& shader) const
{
PROFILE_FUNCTION();
int shader_attrib_idx = 0;
@ -215,17 +215,6 @@ float Geometry::getBoundingRadius() const
}
void Geometry::draw(int start, int count, Shader& shader)
{
PROFILE_FUNCTION();
glBindBuffer(GL_ARRAY_BUFFER, m_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices_id);
m_vertex_definition.begin(shader);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, (void*)(start * sizeof(GLint)));
m_vertex_definition.end(shader);
}
Geometry::Geometry()
{
glGenBuffers(1, &m_id);

View file

@ -34,8 +34,8 @@ struct VertexDef
void parse(const char* data, int size);
int getVertexSize() const { return m_vertex_size; }
int getPositionOffset() const;
void begin(Shader& shader);
void end(Shader& shader);
void begin(Shader& shader) const;
void end(Shader& shader) const;
VertexAttributeDef::Type getAttributeType(int i) const { return i < m_attribute_count ? m_attributes[i] : VertexAttributeDef::NONE; }
private:
@ -58,11 +58,12 @@ class Geometry
void copy(const uint8_t* data, int size, const Array<int32_t>& indices, VertexDef vertex_definition);
void copy(const Geometry& source, int times, VertexCallback& vertex_callback, IndexCallback& index_callback);
void draw(int start, int count, Shader& shader);
const Array<Vec3>& getVertices() const { return m_vertices; }
const Array<int32_t>& getIndices() const { return m_indices; }
float getBoundingRadius() const;
const VertexDef& getVertexDefinition() const { return m_vertex_definition; }
GLuint getID() const { return m_id; }
GLuint getIndicesID() const { return m_indices_id; }
private:
GLuint m_id;

View file

@ -1,4 +1,5 @@
#include "graphics/material.h"
#include "core/crc32.h"
#include "core/fs/file_system.h"
#include "core/fs/ifile.h"
#include "core/json_serializer.h"
@ -18,16 +19,21 @@
namespace Lumix
{
static const uint32_t SHADOWMAP_HASH = crc32("shadowmap");
Material::~Material()
{
ASSERT(isEmpty());
}
void Material::apply(Renderer& renderer, PipelineInstance& pipeline)
void Material::apply(Renderer& renderer, PipelineInstance& pipeline) const
{
PROFILE_FUNCTION();
if(getState() == State::READY)
{
m_shader->apply();
renderer.applyShader(*m_shader);
switch (m_depth_func)
{
case DepthFunc::LEQUAL:
@ -57,16 +63,16 @@ void Material::apply(Renderer& renderer, PipelineInstance& pipeline)
switch (uniform.m_type)
{
case Uniform::FLOAT:
m_shader->setUniform(uniform.m_name, uniform.m_float);
renderer.setUniform(*m_shader, uniform.m_name, uniform.m_name_hash, uniform.m_float);
break;
case Uniform::INT:
m_shader->setUniform(uniform.m_name, uniform.m_int);
renderer.setUniform(*m_shader, uniform.m_name, uniform.m_name_hash, uniform.m_int);
break;
case Uniform::MATRIX:
m_shader->setUniform(uniform.m_name, uniform.m_matrix);
renderer.setUniform(*m_shader, uniform.m_name, uniform.m_name_hash, uniform.m_matrix);
break;
case Uniform::TIME:
m_shader->setUniform(uniform.m_name, pipeline.getScene()->getTimer()->getTimeSinceStart());
renderer.setUniform(*m_shader, uniform.m_name, uniform.m_name_hash, pipeline.getScene()->getTimer()->getTimeSinceStart());
break;
default:
ASSERT(false);
@ -79,7 +85,7 @@ void Material::apply(Renderer& renderer, PipelineInstance& pipeline)
glActiveTexture(GL_TEXTURE0 + m_textures.size());
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pipeline.getShadowmapFramebuffer()->getDepthTexture());
m_shader->setUniform("shadowmap", m_textures.size());
renderer.setUniform(*m_shader, "shadowmap", SHADOWMAP_HASH, m_textures.size());
}
}
@ -123,6 +129,9 @@ bool Material::save(ISerializer& serializer)
PathUtils::getFilename(path, LUMIX_MAX_PATH, m_textures[i]->getPath().c_str());
serializer.serialize("texture", path);
}
serializer.serialize("alpha_to_coverage", m_is_alpha_to_coverage);
serializer.serialize("backface_culling", m_is_backface_culling);
serializer.serialize("z_test", m_is_z_test);
serializer.endObject();
return false;
}
@ -142,6 +151,7 @@ void Material::deserializeUniforms(ISerializer& serializer)
if (strcmp(label, "name") == 0)
{
serializer.deserialize(uniform.m_name, Uniform::MAX_NAME_LENGTH);
uniform.m_name_hash = crc32(uniform.m_name);
}
else if (strcmp(label, "int_value") == 0)
{

View file

@ -32,7 +32,7 @@ public:
};
public:
void apply(Renderer& renderer, PipelineInstance& pipeline);
void apply(Renderer& renderer, PipelineInstance& pipeline) const;
bool isZTest() const { return m_is_z_test; }
void enableZTest(bool enable) { m_is_z_test = enable; }
bool isBackfaceCulling() const { return m_is_backface_culling; }
@ -48,6 +48,7 @@ public:
void addTexture(Texture* texture);
void setTexture(int i, Texture* texture);
void removeTexture(int i);
bool save(ISerializer& serializer);
private:
Material(const Path& path, ResourceManager& resource_manager)
@ -61,7 +62,6 @@ private:
~Material();
bool save(ISerializer& serializer);
virtual void doUnload(void) override;
virtual FS::ReadCallback getReadCallback() override;
@ -79,6 +79,7 @@ private:
};
static const int MAX_NAME_LENGTH = 30;
char m_name[MAX_NAME_LENGTH + 1];
uint32_t m_name_hash;
Type m_type;
union
{

View file

@ -318,7 +318,7 @@ void Model::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
}
else
{
g_log_info.log("renderer") << "Error loading model " << m_path.c_str();
g_log_warning.log("renderer") << "Error loading model " << m_path.c_str();
onFailure();
}

View file

@ -39,19 +39,23 @@ class Mesh
m_start = start;
m_count = count;
m_name_hash = crc32(name);
m_name = name;
}
Material* getMaterial() const { return m_material; }
void setMaterial(Material* material) { m_material = material; }
int getCount() const { return m_count; }
int getTriangleCount() const { return m_count / 3; }
int getStart() const { return m_start; }
uint32_t getNameHash() const { return m_name_hash; }
const char* getName() const { return m_name.c_str(); }
private:
int32_t m_start;
int32_t m_count;
uint32_t m_name_hash;
Material* m_material;
string m_name;
};

View file

@ -24,6 +24,7 @@ class ModelInstance
Matrix& getMatrix() { return m_matrix; }
Model* getModel() const { return m_model; }
Pose& getPose() { return m_pose; }
const Pose& getPose() const { return m_pose; }
void setMatrix(const Matrix& mtx);
private:

View file

@ -29,6 +29,17 @@ namespace Lumix
struct PipelineImpl;
struct PipelineInstanceImpl;
static const uint32_t SHADOW_MATRIX0_HASH = crc32("shadowmap_matrix0");
static const uint32_t SHADOW_MATRIX1_HASH = crc32("shadowmap_matrix1");
static const uint32_t SHADOW_MATRIX2_HASH = crc32("shadowmap_matrix2");
static const uint32_t SHADOW_MATRIX3_HASH = crc32("shadowmap_matrix3");
static const uint32_t LIGHT_DIR_HASH = crc32("light_dir");
static const uint32_t TERRAIN_SCALE_HASH = crc32("terrain_scale");
static const uint32_t BONE_MATRICES_HASH = crc32("bone_matrices");
static const uint32_t CAMERA_POS_HASH = crc32("camera_pos");
struct Command
{
virtual ~Command() {}
@ -276,7 +287,7 @@ struct PipelineImpl : public Pipeline
}
else
{
g_log_error.log("renderer") << "Unknown pipeline command " << tmp;
g_log_error.log("renderer") << "Unknown pipeline command \"" << tmp << "\" in pipeline " << getPath().c_str();
}
}
serializer.deserializeArrayEnd();
@ -440,6 +451,7 @@ struct PipelineInstanceImpl : public PipelineInstance
void renderShadowmap(Component camera, int64_t layer_mask)
{
PROFILE_FUNCTION();
ASSERT(m_renderer != NULL);
Component light_cmp = m_scene->getLight(0);
if (!light_cmp.isValid() || !camera.isValid())
@ -482,6 +494,7 @@ struct PipelineInstanceImpl : public PipelineInstance
);
m_shadow_modelviewprojection[split_index] = biasMatrix * (projection_matrix * modelview_matrix);
renderTerrains(layer_mask);
renderModels(layer_mask);
}
glMatrixMode(GL_PROJECTION);
@ -526,15 +539,7 @@ struct PipelineInstanceImpl : public PipelineInstance
void renderDebugLines()
{
// cleanup
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
for (int i = 0; i < 16; ++i)
{
glActiveTexture(GL_TEXTURE0 + i);
glDisable(GL_TEXTURE_2D);
}
glActiveTexture(GL_TEXTURE0);
m_renderer->cleanup();
const Array<DebugLine>& lines = m_scene->getDebugLines();
glBegin(GL_LINES);
@ -552,26 +557,29 @@ struct PipelineInstanceImpl : public PipelineInstance
PROFILE_FUNCTION();
if (m_active_camera.isValid())
{
Material* last_material = NULL;
const Material* last_material = NULL;
m_grass_infos.clear();
m_scene->getGrassInfos(m_grass_infos, layer_mask);
for (int i = 0; i < m_grass_infos.size(); ++i)
{
Shader* shader = m_grass_infos[i].m_mesh->getMaterial()->getShader();
if (m_grass_infos[i].m_mesh->getMaterial() != last_material)
const GrassInfo& info = m_grass_infos[i];
const Mesh& mesh = *info.m_mesh;
const Material& material = *mesh.getMaterial();
Shader* shader = material.getShader();
if (&material != last_material)
{
m_grass_infos[i].m_mesh->getMaterial()->apply(*m_renderer, *this);
shader->setUniform("shadowmap_matrix0", m_shadow_modelviewprojection[0]);
shader->setUniform("shadowmap_matrix1", m_shadow_modelviewprojection[1]);
shader->setUniform("shadowmap_matrix2", m_shadow_modelviewprojection[2]);
shader->setUniform("shadowmap_matrix3", m_shadow_modelviewprojection[3]);
shader->setUniform("light_dir", m_light_dir);
last_material = m_grass_infos[i].m_mesh->getMaterial();
material.apply(*m_renderer, *this);
m_renderer->setUniform(*shader, "shadowmap_matrix0", SHADOW_MATRIX0_HASH, m_shadow_modelviewprojection[0]);
m_renderer->setUniform(*shader, "shadowmap_matrix1", SHADOW_MATRIX1_HASH, m_shadow_modelviewprojection[1]);
m_renderer->setUniform(*shader, "shadowmap_matrix2", SHADOW_MATRIX2_HASH, m_shadow_modelviewprojection[2]);
m_renderer->setUniform(*shader, "shadowmap_matrix3", SHADOW_MATRIX3_HASH, m_shadow_modelviewprojection[3]);
m_renderer->setUniform(*shader, "light_dir", LIGHT_DIR_HASH, m_light_dir);
m_renderer->setUniform(*shader, "camera_pos", CAMERA_POS_HASH, m_active_camera.entity.getPosition());
last_material = &material;
}
shader->setUniform("grass_matrices", m_grass_infos[i].m_matrices, m_grass_infos[i].m_matrix_count);
m_renderer->setFixedCachedUniform(*shader, (int)Shader::FixedCachedUniforms::GRASS_MATRICES, info.m_matrices, info.m_matrix_count);
Mesh& mesh = *m_grass_infos[i].m_mesh;
m_grass_infos[i].m_geometry->draw(mesh.getStart(), mesh.getCount() / m_grass_infos[i].m_mesh_copy_count * m_grass_infos[i].m_matrix_count, *shader);
m_renderer->renderGeometry(*info.m_geometry, mesh.getStart(), mesh.getCount() / info.m_mesh_copy_count * info.m_matrix_count, *shader);
}
}
}
@ -586,65 +594,79 @@ struct PipelineInstanceImpl : public PipelineInstance
Vec3 camera_position = m_active_camera.entity.getPosition();
for (int i = 0; i < m_terrain_infos.size(); ++i)
{
if (m_terrain_infos[i].m_material && m_terrain_infos[i].m_material->getShader())
if (m_terrain_infos[i].m_material && m_terrain_infos[i].m_material->isReady())
{
Matrix world_matrix;
m_terrain_infos[i].m_entity.getMatrix(world_matrix);
Shader* shader = m_terrain_infos[i].m_material->getShader();
m_terrain_infos[i].m_material->apply(*m_renderer, *this);
shader->setUniform("world_matrix", world_matrix);
shader->setUniform("shadowmap_matrix0", m_shadow_modelviewprojection[0]);
shader->setUniform("shadowmap_matrix1", m_shadow_modelviewprojection[1]);
shader->setUniform("shadowmap_matrix2", m_shadow_modelviewprojection[2]);
shader->setUniform("shadowmap_matrix3", m_shadow_modelviewprojection[3]);
shader->setUniform("light_dir", m_light_dir);
m_renderer->setFixedCachedUniform(*shader, (int)Shader::FixedCachedUniforms::WORLD_MATRIX, world_matrix);
m_renderer->setUniform(*shader, "shadowmap_matrix0", SHADOW_MATRIX0_HASH, m_shadow_modelviewprojection[0]);
m_renderer->setUniform(*shader, "shadowmap_matrix1", SHADOW_MATRIX1_HASH, m_shadow_modelviewprojection[1]);
m_renderer->setUniform(*shader, "shadowmap_matrix2", SHADOW_MATRIX2_HASH, m_shadow_modelviewprojection[2]);
m_renderer->setUniform(*shader, "shadowmap_matrix3", SHADOW_MATRIX3_HASH, m_shadow_modelviewprojection[3]);
m_renderer->setUniform(*shader, "light_dir", LIGHT_DIR_HASH, m_light_dir);
Vec3 scale;
scale.x = m_terrain_infos[i].m_xz_scale;
scale.y = m_terrain_infos[i].m_y_scale;
scale.z = scale.x;
m_terrain_infos[i].m_material->getShader()->setUniform("terrain_scale", scale);
m_renderer->setUniform(*shader, "terrain_scale", TERRAIN_SCALE_HASH, scale);
m_scene->renderTerrain(m_terrain_infos[i], *m_renderer, *this, camera_position);
}
}
}
}
void sortRenderables(Array<RenderableInfo>& infos)
{
PROFILE_FUNCTION();
if (!infos.empty())
{
qsort(&infos[0], infos.size(), sizeof(RenderableInfo), [](const void* a, const void* b) -> int
{
const RenderableInfo* info1 = static_cast<const RenderableInfo*>(a);
const RenderableInfo* info2 = static_cast<const RenderableInfo*>(b);
return (int)(info1->m_mesh - info2->m_mesh);
});
}
}
void renderModels(int64_t layer_mask)
{
PROFILE_FUNCTION();
ASSERT(m_renderer != NULL);
renderTerrains(layer_mask);
m_renderable_infos.clear();
m_scene->getRenderableInfos(m_renderable_infos, layer_mask);
int count = m_renderable_infos.size();
Material* last_material = NULL;
const Material* last_material = NULL;
sortRenderables(m_renderable_infos);
for (int i = 0; i < count; ++i)
{
glPushMatrix();
Matrix world_matrix = m_renderable_infos[i].m_model ? m_renderable_infos[i].m_model->getMatrix() : *m_renderable_infos[i].m_matrix;
world_matrix.multiply3x3(m_renderable_infos[i].m_scale);
glMultMatrixf(&world_matrix.m11);
const RenderableInfo& info = m_renderable_infos[i];
const Matrix& world_matrix = info.m_model->getMatrix();
const Mesh& mesh = *info.m_mesh;
const Material& material = *mesh.getMaterial();
Shader& shader = *material.getShader();
Mesh& mesh = *m_renderable_infos[i].m_mesh;
Material& material = *mesh.getMaterial();
if (last_material != &material)
{
material.apply(*m_renderer, *this);
material.getShader()->setUniform("world_matrix", world_matrix);
material.getShader()->setUniform("shadowmap_matrix0", m_shadow_modelviewprojection[0]);
material.getShader()->setUniform("shadowmap_matrix1", m_shadow_modelviewprojection[1]);
material.getShader()->setUniform("shadowmap_matrix2", m_shadow_modelviewprojection[2]);
material.getShader()->setUniform("shadowmap_matrix3", m_shadow_modelviewprojection[3]);
material.getShader()->setUniform("light_dir", m_light_dir);
m_renderer->setUniform(shader, "shadowmap_matrix0", SHADOW_MATRIX0_HASH, m_shadow_modelviewprojection[0]);
m_renderer->setUniform(shader, "shadowmap_matrix1", SHADOW_MATRIX1_HASH, m_shadow_modelviewprojection[1]);
m_renderer->setUniform(shader, "shadowmap_matrix2", SHADOW_MATRIX2_HASH, m_shadow_modelviewprojection[2]);
m_renderer->setUniform(shader, "shadowmap_matrix3", SHADOW_MATRIX3_HASH, m_shadow_modelviewprojection[3]);
m_renderer->setUniform(shader, "light_dir", LIGHT_DIR_HASH, m_light_dir);
last_material = &material;
}
m_renderer->setFixedCachedUniform(shader, (int)Shader::FixedCachedUniforms::WORLD_MATRIX, world_matrix);
static Matrix bone_mtx[64];
if (m_renderable_infos[i].m_pose)
if (info.m_pose->getCount() > 0)
{
const Pose& pose = *m_renderable_infos[i].m_pose;
const Model& model = *m_renderable_infos[i].m_model->getModel();
const Pose& pose = *info.m_pose;
const Model& model = *info.m_model->getModel();
Vec3* poss = pose.getPositions();
Quat* rots = pose.getRotations();
ASSERT(pose.getCount() <= 64);
@ -654,14 +676,11 @@ struct PipelineInstanceImpl : public PipelineInstance
bone_mtx[bone_index].translate(poss[bone_index]);
bone_mtx[bone_index] = bone_mtx[bone_index] * model.getBone(bone_index).inv_bind_matrix;
}
material.getShader()->setUniform("bone_matrices", bone_mtx, pose.getCount());
m_renderer->setUniform(shader, "bone_matrices", BONE_MATRICES_HASH, bone_mtx, pose.getCount());
}
m_renderable_infos[i].m_geometry->draw(mesh.getStart(), mesh.getCount(), *material.getShader());
glPopMatrix();
m_renderer->renderGeometry(*m_renderable_infos[i].m_geometry, mesh.getStart(), mesh.getCount(), *material.getShader());
}
renderGrass(layer_mask);
}
virtual void resize(int w, int h) override
@ -789,7 +808,10 @@ void RenderModelsCommand::deserialize(PipelineImpl&, ISerializer& serializer)
void RenderModelsCommand::execute(PipelineInstanceImpl& pipeline)
{
pipeline.renderTerrains(m_layer_mask);
pipeline.renderModels(m_layer_mask);
pipeline.renderGrass(m_layer_mask);
}

View file

@ -63,7 +63,6 @@ void Pose::computeAbsolute(Model& model, int i, bool* valid)
void Pose::computeAbsolute(Model& model)
{
/// TODO remove recursion
if(!m_is_absolute)
{
ASSERT(m_count < 256);

View file

@ -14,7 +14,7 @@ struct Quat;
struct Vec3;
class Pose
class LUMIX_ENGINE_API Pose
{
public:
Pose();

View file

@ -44,11 +44,11 @@ namespace Lumix
{
Renderable() {}
bool m_is_free;
int64_t m_layer_mask;
ModelInstance m_model;
Entity m_entity;
int64_t m_layer_mask;
float m_scale;
bool m_is_free;
private:
Renderable(const Renderable&) {}
@ -64,6 +64,7 @@ namespace Lumix
Type m_type;
Entity m_entity;
bool m_is_free;
};
struct Camera
@ -78,15 +79,17 @@ namespace Lumix
float m_width;
float m_height;
bool m_is_active;
bool m_is_free;
char m_slot[MAX_SLOT_LENGTH + 1];
};
class RenderSceneImpl : public RenderScene
{
public:
RenderSceneImpl(Engine& engine, Universe& universe)
RenderSceneImpl(Renderer& renderer, Engine& engine, Universe& universe)
: m_engine(engine)
, m_universe(universe)
, m_renderer(renderer)
{
m_universe.entityMoved().bind<RenderSceneImpl, &RenderSceneImpl::onEntityMoved>(this);
m_timer = Timer::create();
@ -110,6 +113,11 @@ namespace Lumix
CullingSystem::destroy(*m_culling_system);
}
virtual IPlugin& getPlugin() const override
{
return m_renderer;
}
virtual void getRay(Component camera, float x, float y, Vec3& origin, Vec3& dir) override
{
Vec3 camera_pos = camera.entity.getPosition();
@ -145,7 +153,7 @@ namespace Lumix
float height = m_cameras[cmp.index].m_height;
float near_plane = m_cameras[cmp.index].m_near;
float far_plane = m_cameras[cmp.index].m_far;
m_engine.getRenderer().setProjection(width, height, fov, near_plane, far_plane, mtx);
m_renderer.setProjection(width, height, fov, near_plane, far_plane, mtx);
m_camera_frustum.compute(
mtx.getTranslation(),
@ -250,6 +258,7 @@ namespace Lumix
serializer.beginArray("cameras");
for (int i = 0; i < m_cameras.size(); ++i)
{
serializer.serializeArrayItem(m_cameras[i].m_is_free);
serializer.serializeArrayItem(m_cameras[i].m_far);
serializer.serializeArrayItem(m_cameras[i].m_near);
serializer.serializeArrayItem(m_cameras[i].m_fov);
@ -270,6 +279,7 @@ namespace Lumix
{
serializer.serializeArrayItem(m_lights[i].m_entity.index);
serializer.serializeArrayItem((int32_t)m_lights[i].m_type);
serializer.serializeArrayItem(m_lights[i].m_is_free);
}
serializer.endArray();
}
@ -280,22 +290,25 @@ namespace Lumix
serializer.beginArray("renderables");
for (int i = 0; i < m_renderables.size(); ++i)
{
serializer.serializeArrayItem(m_renderables[i]->m_entity.index);
serializer.serializeArrayItem(m_renderables[i]->m_layer_mask);
serializer.serializeArrayItem(m_renderables[i]->m_is_free);
if (m_renderables[i]->m_model.getModel())
if(!m_renderables[i]->m_is_free)
{
serializer.serializeArrayItem(m_renderables[i]->m_model.getModel()->getPath().c_str());
}
else
{
serializer.serializeArrayItem("");
}
serializer.serializeArrayItem(m_renderables[i]->m_scale);
Matrix mtx = m_renderables[i]->m_model.getMatrix();
for (int j = 0; j < 16; ++j)
{
serializer.serializeArrayItem((&mtx.m11)[j]);
serializer.serializeArrayItem(m_renderables[i]->m_entity.index);
serializer.serializeArrayItem(m_renderables[i]->m_layer_mask);
if (m_renderables[i]->m_model.getModel())
{
serializer.serializeArrayItem(m_renderables[i]->m_model.getModel()->getPath().c_str());
}
else
{
serializer.serializeArrayItem("");
}
serializer.serializeArrayItem(m_renderables[i]->m_scale);
Matrix mtx = m_renderables[i]->m_model.getMatrix();
for (int j = 0; j < 16; ++j)
{
serializer.serializeArrayItem((&mtx.m11)[j]);
}
}
}
serializer.endArray();
@ -307,7 +320,15 @@ namespace Lumix
serializer.beginArray("terrains");
for (int i = 0; i < m_terrains.size(); ++i)
{
m_terrains[i]->serialize(serializer);
if(m_terrains[i])
{
serializer.serializeArrayItem(true);
m_terrains[i]->serialize(serializer);
}
else
{
serializer.serializeArrayItem(false);
}
}
serializer.endArray();
}
@ -328,6 +349,7 @@ namespace Lumix
m_cameras.resize(size);
for (int i = 0; i < size; ++i)
{
serializer.deserializeArrayItem(m_cameras[i].m_is_free);
serializer.deserializeArrayItem(m_cameras[i].m_far);
serializer.deserializeArrayItem(m_cameras[i].m_near);
serializer.deserializeArrayItem(m_cameras[i].m_fov);
@ -338,7 +360,10 @@ namespace Lumix
serializer.deserializeArrayItem(m_cameras[i].m_entity.index);
m_cameras[i].m_entity.universe = &m_universe;
serializer.deserializeArrayItem(m_cameras[i].m_slot, Camera::MAX_SLOT_LENGTH);
m_universe.addComponent(m_cameras[i].m_entity, CAMERA_HASH, this, i);
if(!m_cameras[i].m_is_free)
{
m_universe.addComponent(m_cameras[i].m_entity, CAMERA_HASH, this, i);
}
}
serializer.deserializeArrayEnd();
}
@ -360,21 +385,22 @@ namespace Lumix
}
for (int i = 0; i < size; ++i)
{
serializer.deserializeArrayItem(m_renderables[i]->m_entity.index);
m_renderables[i]->m_entity.universe = &m_universe;
serializer.deserializeArrayItem(m_renderables[i]->m_layer_mask);
serializer.deserializeArrayItem(m_renderables[i]->m_is_free);
char path[LUMIX_MAX_PATH];
serializer.deserializeArrayItem(path, LUMIX_MAX_PATH);
serializer.deserializeArrayItem(m_renderables[i]->m_scale);
m_renderables[i]->m_model.setModel(static_cast<Model*>(m_engine.getResourceManager().get(ResourceManager::MODEL)->load(path)));
for (int j = 0; j < 16; ++j)
if(!m_renderables[i]->m_is_free)
{
serializer.deserializeArrayItem((&m_renderables[i]->m_model.getMatrix().m11)[j]);
serializer.deserializeArrayItem(m_renderables[i]->m_entity.index);
m_renderables[i]->m_entity.universe = &m_universe;
serializer.deserializeArrayItem(m_renderables[i]->m_layer_mask);
char path[LUMIX_MAX_PATH];
serializer.deserializeArrayItem(path, LUMIX_MAX_PATH);
serializer.deserializeArrayItem(m_renderables[i]->m_scale);
m_renderables[i]->m_model.setModel(static_cast<Model*>(m_engine.getResourceManager().get(ResourceManager::MODEL)->load(path)));
for (int j = 0; j < 16; ++j)
{
serializer.deserializeArrayItem((&m_renderables[i]->m_model.getMatrix().m11)[j]);
}
m_universe.addComponent(m_renderables[i]->m_entity, RENDERABLE_HASH, this, i);
}
m_culling_system->addStatic(Sphere(m_renderables[i]->m_entity.getPosition(), 1.0f), i);
m_universe.addComponent(m_renderables[i]->m_entity, RENDERABLE_HASH, this, i);
}
serializer.deserializeArrayEnd();
}
@ -390,7 +416,11 @@ namespace Lumix
serializer.deserializeArrayItem(m_lights[i].m_entity.index);
m_lights[i].m_entity.universe = &m_universe;
serializer.deserializeArrayItem((int32_t&)m_lights[i].m_type);
m_universe.addComponent(m_lights[i].m_entity, LIGHT_HASH, this, i);
serializer.deserializeArrayItem(m_lights[i].m_is_free);
if(!m_lights[i].m_is_free)
{
m_universe.addComponent(m_lights[i].m_entity, LIGHT_HASH, this, i);
}
}
serializer.deserializeArrayEnd();
}
@ -403,17 +433,23 @@ namespace Lumix
for (int i = size; i < m_terrains.size(); ++i)
{
LUMIX_DELETE(m_terrains[i]);
m_terrains[i] = NULL;
}
int old_size = m_terrains.size();
m_terrains.resize(size);
for (int i = old_size; i < size; ++i)
{
m_terrains[i] = LUMIX_NEW(Terrain)(Entity::INVALID, *this);
}
for (int i = 0; i < size; ++i)
{
Terrain* terrain = m_terrains[i];
terrain->deserialize(serializer, m_universe, *this, i);
bool exists;
serializer.deserializeArrayItem(exists);
if(exists)
{
m_terrains[i] = LUMIX_NEW(Terrain)(Entity::INVALID, *this);
Terrain* terrain = m_terrains[i];
terrain->deserialize(serializer, m_universe, *this, i);
}
else
{
m_terrains[i] = NULL;
}
}
serializer.deserializeArrayEnd();
}
@ -433,7 +469,26 @@ namespace Lumix
{
m_renderables[component.index]->m_model.setModel(NULL);
m_renderables[component.index]->m_is_free = true;
m_universe.removeComponent(component);
m_universe.destroyComponent(component);
m_universe.componentDestroyed().invoke(component);
}
else if (component.type == LIGHT_HASH)
{
m_lights[component.index].m_is_free = true;
m_universe.destroyComponent(component);
m_universe.componentDestroyed().invoke(component);
}
else if (component.type == CAMERA_HASH)
{
m_cameras[component.index].m_is_free = true;
m_universe.destroyComponent(component);
m_universe.componentDestroyed().invoke(component);
}
else if(component.type == TERRAIN_HASH)
{
LUMIX_DELETE(m_terrains[component.index]);
m_terrains[component.index] = NULL;
m_universe.destroyComponent(component);
m_universe.componentDestroyed().invoke(component);
}
else
@ -457,6 +512,7 @@ namespace Lumix
else if (type == CAMERA_HASH)
{
Camera& camera = m_cameras.pushEmpty();
camera.m_is_free = false;
camera.m_is_active = false;
camera.m_entity = entity;
camera.m_fov = 60;
@ -505,15 +561,15 @@ namespace Lumix
Light& light = m_lights.pushEmpty();
light.m_type = Light::Type::DIRECTIONAL;
light.m_entity = entity;
light.m_is_free = false;
Component cmp = m_universe.addComponent(entity, type, this, m_lights.size() - 1);
m_universe.componentCreated().invoke(cmp);
return cmp;
}
ASSERT(false);
return Component::INVALID;
}
void onEntityMoved(Entity& entity)
void onEntityMoved(const Entity& entity)
{
const Entity::ComponentList& cmps = entity.getComponents();
for (int i = 0; i < cmps.size(); ++i)
@ -540,6 +596,12 @@ namespace Lumix
}
virtual float getTerrainHeightAt(Component cmp, float x, float z) override
{
return m_terrains[cmp.index]->getHeight(x, z);
}
virtual void setTerrainMaterial(Component cmp, const string& path) override
{
Material* material = static_cast<Material*>(m_engine.getResourceManager().get(ResourceManager::MATERIAL)->load(path.c_str()));
@ -547,6 +609,12 @@ namespace Lumix
}
virtual Material* getTerrainMaterial(Component cmp) override
{
return m_terrains[cmp.index]->getMaterial();
}
virtual void getTerrainMaterial(Component cmp, string& path) override
{
if (m_terrains[cmp.index]->getMaterial())
@ -560,25 +628,25 @@ namespace Lumix
}
virtual void setTerrainXZScale(Component cmp, const float& scale) override
virtual void setTerrainXZScale(Component cmp, float scale) override
{
m_terrains[cmp.index]->setXZScale(scale);
}
virtual void getTerrainXZScale(Component cmp, float& scale) override
virtual float getTerrainXZScale(Component cmp) override
{
scale = m_terrains[cmp.index]->getXZScale();
return m_terrains[cmp.index]->getXZScale();
}
virtual void setTerrainYScale(Component cmp, const float& scale) override
virtual void setTerrainYScale(Component cmp, float scale) override
{
m_terrains[cmp.index]->setYScale(scale);
}
virtual void getTerrainYScale(Component cmp, float& scale)
virtual float getTerrainYScale(Component cmp)
{
scale = m_terrains[cmp.index]->getYScale();
return m_terrains[cmp.index]->getYScale();
}
@ -611,7 +679,7 @@ namespace Lumix
m_renderables[cmp.index]->m_layer_mask = ((int64_t)1 << (int64_t)layer);
}
virtual void setRenderableScale(Component cmp, const float& scale) override
virtual void setRenderableScale(Component cmp, float scale) override
{
m_renderables[cmp.index]->m_scale = scale;
}
@ -645,7 +713,7 @@ namespace Lumix
infos.reserve(m_terrains.size());
for (int i = 0; i < m_terrains.size(); ++i)
{
if ((m_terrains[i]->getLayerMask() & layer_mask) != 0)
if (m_terrains[i] && (m_terrains[i]->getLayerMask() & layer_mask) != 0)
{
TerrainInfo& info = infos.pushEmpty();
info.m_entity = m_terrains[i]->getEntity();
@ -663,7 +731,7 @@ namespace Lumix
PROFILE_FUNCTION();
for (int i = 0; i < m_terrains.size(); ++i)
{
if ((m_terrains[i]->getLayerMask() & layer_mask) != 0)
if (m_terrains[i] && (m_terrains[i]->getLayerMask() & layer_mask) != 0)
{
m_terrains[i]->getGrassInfos(infos, m_applied_camera.entity.getPosition());
}
@ -671,15 +739,57 @@ namespace Lumix
}
virtual void setTerrainGrass(Component cmp, const string& path) override
virtual void setGrassDensity(Component cmp, int index, int density) override
{
m_terrains[cmp.index]->setGrassPath(path.c_str());
m_terrains[cmp.index]->setGrassTypeDensity(index, density);
}
virtual int getGrassDensity(Component cmp, int index) override
{
return m_terrains[cmp.index]->getGrassTypeDensity(index);
}
virtual void getTerrainGrass(Component cmp, string& path) override
virtual void setGrassGround(Component cmp, int index, int ground) override
{
path = m_terrains[cmp.index]->getGrassPath().c_str();
m_terrains[cmp.index]->setGrassTypeGround(index, ground);
}
virtual int getGrassGround(Component cmp, int index) override
{
return m_terrains[cmp.index]->getGrassTypeGround(index);
}
virtual void setGrass(Component cmp, int index, const string& path) override
{
m_terrains[cmp.index]->setGrassTypePath(index, path.c_str());
}
virtual void getGrass(Component cmp, int index, string& path) override
{
path = m_terrains[cmp.index]->getGrassTypePath(index).c_str();
}
virtual int getGrassCount(Component cmp) override
{
return m_terrains[cmp.index]->getGrassTypeCount();
}
virtual void addGrass(Component cmp, int index) override
{
m_terrains[cmp.index]->addGrassType(index);
}
virtual void removeGrass(Component cmp, int index) override
{
m_terrains[cmp.index]->removeGrassType(index);
}
@ -693,6 +803,7 @@ namespace Lumix
m_culling_system->cullToFrustumAsync(m_camera_frustum);
infos.reserve(m_renderables.size() * 2);
for (int i = 0, c = m_renderables.size(); i < c; ++i)
//const CullingSystem::InputSpheres& spheres = m_culling_system->getSpheres();
@ -712,20 +823,23 @@ namespace Lumix
infos.reserve(m_renderables.size() * 2);
for (int i = 0; i < m_renderables.size(); ++i)
{
if (!m_renderables[i]->m_is_free)
const Renderable* LUMIX_RESTRICT renderable = m_renderables[i];
if (!renderable->m_is_free)
{
bool is_model_ready = m_renderables[i]->m_model.getModel() && m_renderables[i]->m_model.getModel()->isReady();
if (is_model_ready && (m_renderables[i]->m_layer_mask & layer_mask) != 0 && results[i] > -1)
const ModelInstance& model_instance = renderable->m_model;
const Model* model = model_instance.getModel();
bool is_model_ready = model && model->isReady();
if (is_model_ready && (renderable->m_layer_mask & layer_mask) != 0 && results[i] > -1)
{
for (int j = 0, c = m_renderables[i]->m_model.getModel()->getMeshCount(); j < c; ++j)
for (int j = 0, c = renderable->m_model.getModel()->getMeshCount(); j < c; ++j)
{
RenderableInfo& info = infos.pushEmpty();
info.m_scale = m_renderables[i]->m_scale;
info.m_geometry = m_renderables[i]->m_model.getModel()->getGeometry();
info.m_mesh = &m_renderables[i]->m_model.getModel()->getMesh(j);
info.m_pose = &m_renderables[i]->m_model.getPose();
info.m_model = &m_renderables[i]->m_model;
info.m_matrix = &m_renderables[i]->m_model.getMatrix();
info.m_scale = renderable->m_scale;
info.m_geometry = model->getGeometry();
info.m_mesh = &model->getMesh(j);
info.m_pose = &model_instance.getPose();
info.m_model = &model_instance;
info.m_matrix = &model_instance.getMatrix();
}
}
}
@ -742,44 +856,44 @@ namespace Lumix
slot = m_cameras[camera.index].m_slot;
}
virtual void getCameraFOV(Component camera, float& fov) override
virtual float getCameraFOV(Component camera) override
{
fov = m_cameras[camera.index].m_fov;
return m_cameras[camera.index].m_fov;
}
virtual void setCameraFOV(Component camera, const float& fov) override
virtual void setCameraFOV(Component camera, float fov) override
{
m_cameras[camera.index].m_fov = fov;
}
virtual void setCameraNearPlane(Component camera, const float& near_plane) override
virtual void setCameraNearPlane(Component camera, float near_plane) override
{
m_cameras[camera.index].m_near = near_plane;
}
virtual void getCameraNearPlane(Component camera, float& near_plane) override
virtual float getCameraNearPlane(Component camera) override
{
near_plane = m_cameras[camera.index].m_near;
return m_cameras[camera.index].m_near;
}
virtual void setCameraFarPlane(Component camera, const float& far_plane) override
virtual void setCameraFarPlane(Component camera, float far_plane) override
{
m_cameras[camera.index].m_far = far_plane;
}
virtual void getCameraFarPlane(Component camera, float& far_plane) override
virtual float getCameraFarPlane(Component camera) override
{
far_plane = m_cameras[camera.index].m_far;
return m_cameras[camera.index].m_far;
}
virtual void getCameraWidth(Component camera, float& width) override
virtual float getCameraWidth(Component camera) override
{
width = m_cameras[camera.index].m_width;
return m_cameras[camera.index].m_width;
}
virtual void getCameraHeight(Component camera, float& height) override
virtual float getCameraHeight(Component camera) override
{
height = m_cameras[camera.index].m_height;
return m_cameras[camera.index].m_height;
}
virtual void setCameraSize(Component camera, int w, int h) override
@ -882,11 +996,14 @@ namespace Lumix
}
for (int i = 0; i < m_terrains.size(); ++i)
{
RayCastModelHit terrain_hit = m_terrains[i]->castRay(origin, dir);
if (terrain_hit.m_is_hit && ignore_terrain != m_terrains[i] && (!hit.m_is_hit || terrain_hit.m_t < hit.m_t))
if(m_terrains[i])
{
terrain_hit.m_component = Component(m_terrains[i]->getEntity(), TERRAIN_HASH, this, i);
hit = terrain_hit;
RayCastModelHit terrain_hit = m_terrains[i]->castRay(origin, dir);
if (terrain_hit.m_is_hit && ignore_terrain != m_terrains[i] && (!hit.m_is_hit || terrain_hit.m_t < hit.m_t))
{
terrain_hit.m_component = Component(m_terrains[i]->getEntity(), TERRAIN_HASH, this, i);
hit = terrain_hit;
}
}
}
return hit;
@ -894,7 +1011,7 @@ namespace Lumix
virtual Component getLight(int index) override
{
if (index >= m_lights.size())
if (index >= m_lights.size() || m_lights[index].m_is_free)
{
return Component::INVALID;
}
@ -905,7 +1022,7 @@ namespace Lumix
{
for (int i = 0, c = m_cameras.size(); i < c; ++i)
{
if (strcmp(m_cameras[i].m_slot, slot) == 0)
if (!m_cameras[i].m_is_free && strcmp(m_cameras[i].m_slot, slot) == 0)
{
return Component(m_cameras[i].m_entity, CAMERA_HASH, this, i);
}
@ -946,6 +1063,7 @@ namespace Lumix
Array<Camera> m_cameras;
Array<Terrain*> m_terrains;
Universe& m_universe;
Renderer& m_renderer;
Engine& m_engine;
Array<DebugLine> m_debug_lines;
Timer* m_timer;
@ -955,9 +1073,9 @@ namespace Lumix
};
RenderScene* RenderScene::createInstance(Engine& engine, Universe& universe)
RenderScene* RenderScene::createInstance(Renderer& renderer, Engine& engine, Universe& universe)
{
return LUMIX_NEW(RenderSceneImpl)(engine, universe);
return LUMIX_NEW(RenderSceneImpl)(renderer, engine, universe);
}

View file

@ -3,6 +3,7 @@
#include "core/lumix.h"
#include "core/array.h"
#include "core/string.h"
#include "engine/iplugin.h"
#include "graphics/ray_cast_model_hit.h"
#include "universe/component.h"
@ -35,7 +36,7 @@ namespace Lumix
struct RenderableInfo
{
Geometry* m_geometry;
Mesh* m_mesh;
const Mesh* m_mesh;
const Pose* m_pose;
const ModelInstance* m_model;
const Matrix* m_matrix;
@ -59,16 +60,12 @@ namespace Lumix
float m_life;
};
class LUMIX_ENGINE_API RenderScene
class LUMIX_ENGINE_API RenderScene : public IScene
{
public:
static RenderScene* createInstance(Engine& engine, Universe& universe);
static RenderScene* createInstance(Renderer& renderer, Engine& engine, Universe& universe);
static void destroyInstance(RenderScene* scene);
virtual void serialize(ISerializer& serializer) = 0;
virtual void deserialize(ISerializer& serializer) = 0;
virtual Component createComponent(uint32_t type, const Entity& entity) = 0;
virtual void destroyComponent(const Component& component) = 0;
virtual RayCastModelHit castRay(const Vec3& origin, const Vec3& dir, const Component& ignore) = 0;
virtual void getRay(Component camera, float x, float y, Vec3& origin, Vec3& dir) = 0;
virtual void applyCamera(Component camera) = 0;
@ -86,14 +83,14 @@ namespace Lumix
virtual void addDebugCircle(const Vec3& center, float radius, const Vec3& color, float life) = 0;
virtual const Array<DebugLine>& getDebugLines() const = 0;
virtual Component getCameraInSlot(const char* slot) = 0;
virtual void getCameraFOV(Component camera, float& fov) = 0;
virtual void setCameraFOV(Component camera, const float& fov) = 0;
virtual void setCameraFarPlane(Component camera, const float& far) = 0;
virtual void setCameraNearPlane(Component camera, const float& near) = 0;
virtual void getCameraFarPlane(Component camera, float& far) = 0;
virtual void getCameraNearPlane(Component camera, float& near) = 0;
virtual void getCameraWidth(Component camera, float& width) = 0;
virtual void getCameraHeight(Component camera, float& height) = 0;
virtual float getCameraFOV(Component camera) = 0;
virtual void setCameraFOV(Component camera, float fov) = 0;
virtual void setCameraFarPlane(Component camera, float far) = 0;
virtual void setCameraNearPlane(Component camera, float near) = 0;
virtual float getCameraFarPlane(Component camera) = 0;
virtual float getCameraNearPlane(Component camera) = 0;
virtual float getCameraWidth(Component camera) = 0;
virtual float getCameraHeight(Component camera) = 0;
virtual void setCameraSlot(Component camera, const string& slot) = 0;
virtual void getCameraSlot(Component camera, string& slot) = 0;
virtual void setCameraSize(Component camera, int w, int h) = 0;
@ -101,21 +98,31 @@ namespace Lumix
virtual void getRenderablePath(Component cmp, string& path) = 0;
virtual void setRenderableLayer(Component cmp, const int32_t& layer) = 0;
virtual void setRenderablePath(Component cmp, const string& path) = 0;
virtual void setRenderableScale(Component cmp, const float& scale) = 0;
virtual void setRenderableScale(Component cmp, float scale) = 0;
virtual void getRenderableInfos(Array<RenderableInfo>& infos, int64_t layer_mask) = 0;
virtual void getGrassInfos(Array<GrassInfo>& infos, int64_t layer_mask) = 0;
virtual void getTerrainInfos(Array<TerrainInfo>& infos, int64_t layer_mask) = 0;
virtual float getTerrainHeightAt(Component cmp, float x, float z) = 0;
virtual void setTerrainMaterial(Component cmp, const string& path) = 0;
virtual void getTerrainMaterial(Component cmp, string& path) = 0;
virtual void setTerrainXZScale(Component cmp, const float& scale) = 0;
virtual void getTerrainXZScale(Component cmp, float& scale) = 0;
virtual void setTerrainYScale(Component cmp, const float& scale) = 0;
virtual void getTerrainYScale(Component cmp, float& scale) = 0;
virtual void setTerrainGrass(Component cmp, const string& path) = 0;
virtual void getTerrainGrass(Component cmp, string& path) = 0;
virtual Material* getTerrainMaterial(Component cmp) = 0;
virtual void setTerrainXZScale(Component cmp, float scale) = 0;
virtual float getTerrainXZScale(Component cmp) = 0;
virtual void setTerrainYScale(Component cmp, float scale) = 0;
virtual float getTerrainYScale(Component cmp) = 0;
virtual void setTerrainBrush(Component cmp, const Vec3& position, float size) = 0;
virtual void setGrass(Component cmp, int index, const string& path) = 0;
virtual void getGrass(Component cmp, int index, string& path) = 0;
virtual void setGrassGround(Component cmp, int index, int ground) = 0;
virtual int getGrassGround(Component cmp, int index) = 0;
virtual void setGrassDensity(Component cmp, int index, int density) = 0;
virtual int getGrassDensity(Component cmp, int index) = 0;
virtual int getGrassCount(Component cmp) = 0;
virtual void addGrass(Component cmp, int index) = 0;
virtual void removeGrass(Component cmp, int index) = 0;
protected:
virtual ~RenderScene() {}
};

View file

@ -8,6 +8,7 @@
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "core/vec4.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "graphics/geometry.h"
#include "graphics/gl_ext.h"
@ -33,12 +34,18 @@ static const uint32_t CAMERA_HASH = crc32("camera");
struct RendererImpl : public Renderer
{
RendererImpl()
{
m_last_bind_geometry = NULL;
m_last_program_id = 0xffffFFFF;
m_is_editor_wireframe = false;
}
virtual IScene* createScene(Universe& universe)
{
return RenderScene::createInstance(*this, *m_engine, universe);
}
virtual void setProjection(float width, float height, float fov, float near_plane, float far_plane, const Matrix& mtx) override
{
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
@ -72,14 +79,21 @@ struct RendererImpl : public Renderer
virtual void render(IRenderDevice& device) override
{
PROFILE_FUNCTION();
// init
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
// render
device.getPipeline().render();
// cleanup
cleanup();
}
virtual void cleanup() override
{
if(m_last_bind_geometry)
{
m_last_bind_geometry->getVertexDefinition().end(*m_last_bind_geometry_shader);
}
m_last_bind_geometry = NULL;
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
for(int i = 0; i < 16; ++i)
@ -90,8 +104,208 @@ struct RendererImpl : public Renderer
glActiveTexture(GL_TEXTURE0);
}
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, int value) override
{
PROFILE_FUNCTION();
GLint loc = shader.getUniformLocation(name, name_hash);
if (loc >= 0)
{
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniform1i(loc, value);
}
}
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, const Vec3& value) override
{
PROFILE_FUNCTION();
GLint loc = shader.getUniformLocation(name, name_hash);
if (loc >= 0)
{
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniform3f(loc, value.x, value.y, value.z);
}
}
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, float value) override
{
PROFILE_FUNCTION();
GLint loc = shader.getUniformLocation(name, name_hash);
if (loc >= 0)
{
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniform1f(loc, value);
}
}
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, const Matrix& mtx) override
{
PROFILE_FUNCTION();
GLint loc = shader.getUniformLocation(name, name_hash);
if (loc >= 0)
{
//glProgramUniformMatrix4fv(shader.getProgramId(), loc, 1, false, &mtx.m11);
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniformMatrix4fv(loc, 1, false, &mtx.m11);
}
}
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, const Matrix* matrices, int count) override
{
PROFILE_FUNCTION();
GLint loc = shader.getUniformLocation(name, name_hash);
if (loc >= 0)
{
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniformMatrix4fv(loc, count, false, (float*)matrices);
}
}
virtual void setFixedCachedUniform(Shader& shader, int name, const Vec3& value) override
{
PROFILE_FUNCTION();
GLint loc = shader.getFixedCachedUniformLocation((Shader::FixedCachedUniforms)name);
if (loc >= 0)
{
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniform3f(loc, value.x, value.y, value.z);
}
}
virtual void setFixedCachedUniform(Shader& shader, int name, float value) override
{
PROFILE_FUNCTION();
GLint loc = shader.getFixedCachedUniformLocation((Shader::FixedCachedUniforms)name);
if (loc >= 0)
{
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniform1f(loc, value);
}
}
virtual void setFixedCachedUniform(Shader& shader, int name, const Matrix& mtx) override
{
PROFILE_FUNCTION();
GLint loc = shader.getFixedCachedUniformLocation((Shader::FixedCachedUniforms)name);
if (loc >= 0)
{
//glProgramUniformMatrix4fv(shader.getProgramId(), loc, 1, false, &mtx.m11);
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniformMatrix4fv(loc, 1, false, &mtx.m11);
}
}
virtual void setFixedCachedUniform(Shader& shader, int name, const Matrix* matrices, int count) override
{
PROFILE_FUNCTION();
GLint loc = shader.getFixedCachedUniformLocation((Shader::FixedCachedUniforms)name);
if (loc >= 0)
{
if (m_last_program_id != shader.getProgramId())
{
glUseProgram(shader.getProgramId());
m_last_program_id = shader.getProgramId();
}
glUniformMatrix4fv(loc, count, false, (float*)matrices);
}
}
virtual void applyShader(const Shader& shader) override
{
GLuint id = shader.getProgramId();
m_last_program_id = id;
glUseProgram(id);
}
virtual void renderGeometry(Geometry& geometry, int start, int count, Shader& shader) override
{
PROFILE_FUNCTION();
if (m_last_bind_geometry != &geometry)
{
if (m_last_bind_geometry)
{
m_last_bind_geometry->getVertexDefinition().end(shader);
}
glBindBuffer(GL_ARRAY_BUFFER, geometry.getID());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry.getIndicesID());
m_last_bind_geometry = &geometry;
m_last_bind_geometry_shader = &shader;
geometry.getVertexDefinition().begin(shader);
}
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, (void*)(start * sizeof(GLint)));
}
void registerPropertyDescriptors(WorldEditor& editor)
{
editor.registerProperty("camera", LUMIX_NEW(StringPropertyDescriptor<RenderScene>)("slot", &RenderScene::getCameraSlot, &RenderScene::setCameraSlot));
editor.registerProperty("camera", LUMIX_NEW(DecimalPropertyDescriptor<RenderScene>)("fov", &RenderScene::getCameraFOV, &RenderScene::setCameraFOV));
editor.registerProperty("camera", LUMIX_NEW(DecimalPropertyDescriptor<RenderScene>)("near", &RenderScene::getCameraNearPlane, &RenderScene::setCameraNearPlane));
editor.registerProperty("camera", LUMIX_NEW(DecimalPropertyDescriptor<RenderScene>)("far", &RenderScene::getCameraFarPlane, &RenderScene::setCameraFarPlane));
editor.registerProperty("renderable", LUMIX_NEW(FilePropertyDescriptor<RenderScene>)("source", &RenderScene::getRenderablePath, &RenderScene::setRenderablePath, "Mesh (*.msh)"));
editor.registerProperty("terrain", LUMIX_NEW(FilePropertyDescriptor<RenderScene>)("material", &RenderScene::getTerrainMaterial, &RenderScene::setTerrainMaterial, "Material (*.mat)"));
editor.registerProperty("terrain", LUMIX_NEW(DecimalPropertyDescriptor<RenderScene>)("xz_scale", &RenderScene::getTerrainXZScale, &RenderScene::setTerrainXZScale));
editor.registerProperty("terrain", LUMIX_NEW(DecimalPropertyDescriptor<RenderScene>)("y_scale", &RenderScene::getTerrainYScale, &RenderScene::setTerrainYScale));
auto grass = LUMIX_NEW(ArrayDescriptor<RenderScene>)("grass", &RenderScene::getGrassCount, &RenderScene::addGrass, &RenderScene::removeGrass);
grass->addChild(LUMIX_NEW(FileArrayObjectDescriptor<RenderScene>)("mesh", &RenderScene::getGrass, &RenderScene::setGrass, "Mesh (*.msh)"));
auto ground = LUMIX_NEW(IntArrayObjectDescriptor<RenderScene>)("ground", &RenderScene::getGrassGround, &RenderScene::setGrassGround);
ground->setLimit(0, 4);
grass->addChild(ground);
grass->addChild(LUMIX_NEW(IntArrayObjectDescriptor<RenderScene>)("density", &RenderScene::getGrassDensity, &RenderScene::setGrassDensity));
editor.registerProperty("terrain", grass);
}
virtual bool create(Engine& engine) override
{
registerPropertyDescriptors(*engine.getWorldEditor());
m_engine = &engine;
glewExperimental = GL_TRUE;
GLenum err = glewInit();
@ -110,18 +324,6 @@ struct RendererImpl : public Renderer
}
virtual void destroyComponent(const Component& component) override
{
static_cast<RenderScene*>(component.system)->destroyComponent(component);
}
virtual Component createComponent(uint32_t, const Entity&) override
{
return Component::INVALID;
}
virtual void enableAlphaToCoverage(bool enable) override
{
if (enable)
@ -166,7 +368,7 @@ struct RendererImpl : public Renderer
{
const Mesh& mesh = model.getMesh(i);
mesh.getMaterial()->apply(*this, pipeline);
model.getGeometry()->draw(mesh.getStart(), mesh.getCount(), *mesh.getMaterial()->getShader());
renderGeometry(*model.getGeometry(), mesh.getStart(), mesh.getCount(), *mesh.getMaterial()->getShader());
}
glPopMatrix();
}
@ -190,9 +392,11 @@ struct RendererImpl : public Renderer
}
Engine* m_engine;
Array<Model*> m_models;
IRenderDevice* m_render_device;
bool m_is_editor_wireframe;
Geometry* m_last_bind_geometry;
Shader* m_last_bind_geometry_shader;
GLuint m_last_program_id;
};

View file

@ -40,6 +40,19 @@ class LUMIX_ENGINE_API Renderer : public IPlugin
virtual void setRenderDevice(IRenderDevice& device) = 0;
virtual void setEditorWireframe(bool is_wireframe) = 0;
virtual bool isEditorWireframe() const = 0;
virtual void cleanup() = 0;
virtual void renderGeometry(Geometry& geometry, int start, int count, Shader& shader) = 0;
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, int value) = 0;
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, const Vec3& value) = 0;
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, float value) = 0;
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, const Matrix& mtx) = 0;
virtual void setUniform(Shader& shader, const char* name, const uint32_t name_hash, const Matrix* matrices, int count) = 0;
virtual void setFixedCachedUniform(Shader& shader, int name, const Vec3& value) = 0;
virtual void setFixedCachedUniform(Shader& shader, int name, float value) = 0;
virtual void setFixedCachedUniform(Shader& shader, int name, const Matrix& mtx) = 0;
virtual void setFixedCachedUniform(Shader& shader, int name, const Matrix* matrices, int count) = 0;
virtual void applyShader(const Shader& shader) = 0;
virtual void setProjection(float width, float height, float fov, float near_plane, float far_plane, const Matrix& mtx) = 0;
virtual Engine& getEngine() = 0;

View file

@ -32,75 +32,23 @@ Shader::~Shader()
glDeleteShader(m_fragment_id);
}
void Shader::apply()
{
glUseProgram(m_program_id);
}
void Shader::setUniform(const char* name, int value)
GLint Shader::getUniformLocation(const char* name, uint32_t name_hash)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0)
for (int i = 0, c = m_uniforms.size(); i < c; ++i)
{
//glProgramUniform1i(m_program_id, loc, value);
glUseProgram(m_program_id);
glUniform1i(loc, value);
if (m_uniforms[i].m_name_hash == name_hash)
{
return m_uniforms[i].m_location;
}
}
CachedUniform& unif = m_uniforms.pushEmpty();
unif.m_name_hash = name_hash;
unif.m_location = glGetUniformLocation(m_program_id, name);
return unif.m_location;
}
void Shader::setUniform(const char* name, const Vec3& value)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0)
{
//glProgramUniform3f(m_program_id, loc, value.x, value.y, value.z);
glUseProgram(m_program_id);
glUniform3f(loc, value.x, value.y, value.z);
}
}
void Shader::setUniform(const char* name, GLfloat value)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0)
{
//glProgramUniform1f(m_program_id, loc, value);
glUseProgram(m_program_id);
glUniform1f(loc, value);
}
}
void Shader::setUniform(const char* name, const Matrix& mtx)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0)
{
//glProgramUniformMatrix4fv(m_program_id, loc, 1, false, &mtx.m11);
glUseProgram(m_program_id);
glUniformMatrix4fv(loc, 1, false, &mtx.m11);
}
}
void Shader::setUniform(const char* name, const Matrix* matrices, int count)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0) // this is here because of bug in some gl implementations
{
//glProgramUniformMatrix4fv(m_program_id, loc, count, false, &matrices[0].m11);
glUseProgram(m_program_id);
glUniformMatrix4fv(loc, count, false, &matrices[0].m11);
}
}
GLuint Shader::attach(GLenum type, const char* src, int32_t length)
{
GLuint id = glCreateShader(type);
@ -179,9 +127,11 @@ void Shader::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
{
m_vertex_attributes_ids[i] = glGetAttribLocation(m_program_id, attributes[i]);
}
m_position_attrib_id = glGetAttribLocation(m_program_id, "in_position");
m_normal_attrib_id = glGetAttribLocation(m_program_id, "in_normal");
m_tex_coord_attrib_id = glGetAttribLocation(m_program_id, "in_tex_coord");
m_fixed_cached_uniforms[(int)FixedCachedUniforms::WORLD_MATRIX] = glGetUniformLocation(m_program_id, "world_matrix");
m_fixed_cached_uniforms[(int)FixedCachedUniforms::GRASS_MATRICES] = glGetUniformLocation(m_program_id, "grass_matrices");
m_fixed_cached_uniforms[(int)FixedCachedUniforms::MORPH_CONST] = glGetUniformLocation(m_program_id, "morph_const");
m_fixed_cached_uniforms[(int)FixedCachedUniforms::QUAD_SIZE] = glGetUniformLocation(m_program_id, "quad_size");
m_fixed_cached_uniforms[(int)FixedCachedUniforms::QUAD_MIN] = glGetUniformLocation(m_program_id, "quad_min");
m_size = file->size();
decrementDepCount();
@ -197,6 +147,7 @@ void Shader::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
void Shader::doUnload(void)
{
m_uniforms.clear();
glDeleteProgram(m_program_id);
glDeleteShader(m_vertex_id);
glDeleteShader(m_fragment_id);

View file

@ -16,6 +16,17 @@ struct Matrix;
class LUMIX_ENGINE_API Shader : public Resource
{
public:
enum class FixedCachedUniforms : int
{
WORLD_MATRIX,
GRASS_MATRICES,
MORPH_CONST,
QUAD_SIZE,
QUAD_MIN,
COUNT
};
public:
static const int MAX_ATTRIBUTE_COUNT = 16;
@ -23,17 +34,11 @@ class LUMIX_ENGINE_API Shader : public Resource
Shader(const Path& path, ResourceManager& resource_manager);
~Shader();
void apply();
void setUniform(const char* name, GLint value);
void setUniform(const char* name, const Vec3& value);
void setUniform(const char* name, GLfloat value);
void setUniform(const char* name, const Matrix& mtx);
void setUniform(const char* name, const Matrix* matrices, int count);
GLint getAttribId(int index) const { return m_vertex_attributes_ids[index]; }
GLint getPositionAttribId() const { return m_position_attrib_id; }
GLint getNormalAttribId() const { return m_normal_attrib_id; }
GLint getTexCoordAttribId() const { return m_tex_coord_attrib_id; }
bool isShadowmapRequired() const { return m_is_shadowmap_required; }
LUMIX_FORCE_INLINE GLint getUniformLocation(const char* name, uint32_t name_hash);
GLuint getProgramId() const { return m_program_id; }
GLint getFixedCachedUniformLocation(FixedCachedUniforms name) const { return m_fixed_cached_uniforms[(int)name]; }
private:
GLuint attach(GLenum type, const char* src, int32_t length);
@ -43,15 +48,22 @@ class LUMIX_ENGINE_API Shader : public Resource
virtual void doUnload(void) override;
virtual FS::ReadCallback getReadCallback() override;
private:
class CachedUniform
{
public:
uint32_t m_name_hash;
GLint m_location;
};
private:
GLuint m_program_id;
GLuint m_vertex_id;
GLuint m_fragment_id;
GLint m_vertex_attributes_ids[MAX_ATTRIBUTE_COUNT];
GLint m_position_attrib_id;
GLint m_normal_attrib_id;
GLint m_tex_coord_attrib_id;
bool m_is_shadowmap_required;
Array<CachedUniform> m_uniforms;
GLint m_fixed_cached_uniforms[(int)FixedCachedUniforms::COUNT];
};

View file

@ -10,6 +10,7 @@
#include "graphics/model.h"
#include "graphics/pipeline.h"
#include "graphics/render_scene.h"
#include "graphics/renderer.h"
#include "graphics/shader.h"
#include "graphics/texture.h"
#include <cfloat>
@ -21,6 +22,14 @@ namespace Lumix
static const int GRID_SIZE = 16;
static const int COPY_COUNT = 50;
static const uint32_t TERRAIN_HASH = crc32("terrain");
static const uint32_t MORPH_CONST_HASH = crc32("morph_const");
static const uint32_t QUAD_SIZE_HASH = crc32("quad_size");
static const uint32_t QUAD_MIN_HASH = crc32("quad_min");
static const uint32_t BRUSH_POSITION_HASH = crc32("brush_position");
static const uint32_t BRUSH_SIZE_HASH = crc32("brush_size");
static const uint32_t MAP_SIZE_HASH = crc32("map_size");
static const uint32_t CAMERA_POS_HASH = crc32("camera_pos");
struct Sample
{
@ -116,8 +125,9 @@ namespace Lumix
}
bool render(Mesh* mesh, Geometry& geometry, const Vec3& camera_pos, RenderScene& scene)
bool render(Renderer* renderer, Mesh* mesh, Geometry& geometry, const Vec3& camera_pos, RenderScene& scene)
{
PROFILE_FUNCTION();
float dist = getDistance(camera_pos);
float r = getRadiusOuter(m_size);
if (dist > r && m_lod > 1)
@ -128,12 +138,12 @@ namespace Lumix
Shader& shader = *mesh->getMaterial()->getShader();
for (int i = 0; i < CHILD_COUNT; ++i)
{
if (!m_children[i] || !m_children[i]->render(mesh, geometry, camera_pos, scene))
if (!m_children[i] || !m_children[i]->render(renderer, mesh, geometry, camera_pos, scene))
{
shader.setUniform("morph_const", morph_const);
shader.setUniform("quad_size", m_size);
shader.setUniform("quad_min", m_min);
geometry.draw(mesh->getCount() / 4 * i, mesh->getCount() / 4, shader);
renderer->setFixedCachedUniform(shader, (int)Shader::FixedCachedUniforms::MORPH_CONST, morph_const);
renderer->setFixedCachedUniform(shader, (int)Shader::FixedCachedUniforms::QUAD_SIZE, m_size);
renderer->setFixedCachedUniform(shader, (int)Shader::FixedCachedUniforms::QUAD_MIN, m_min);
renderer->renderGeometry(geometry, mesh->getCount() / 4 * i, mesh->getCount() / 4, shader);
}
}
return true;
@ -157,69 +167,155 @@ namespace Lumix
, m_y_scale(1)
, m_xz_scale(1)
, m_entity(entity)
, m_grass_geometry(NULL)
, m_grass_mesh(NULL)
, m_scene(scene)
, m_grass_model(NULL)
, m_brush_position(0, 0, 0)
, m_brush_size(1)
{
generateGeometry();
}
Terrain::GrassType::~GrassType()
{
if (m_grass_model)
{
m_grass_model->getResourceManager().get(ResourceManager::MODEL)->unload(*m_grass_model);
m_grass_model->getObserverCb().unbind<GrassType, &GrassType::grassLoaded>(this);
LUMIX_DELETE(m_grass_mesh);
LUMIX_DELETE(m_grass_geometry);
}
}
Terrain::~Terrain()
{
setMaterial(NULL);
LUMIX_DELETE(m_mesh);
LUMIX_DELETE(m_root);
if (m_grass_model)
for(int i = 0; i < m_grass_types.size(); ++i)
{
m_grass_model->getResourceManager().get(ResourceManager::MODEL)->unload(*m_grass_model);
m_grass_model->getObserverCb().unbind<Terrain, &Terrain::grassLoaded>(this);
LUMIX_DELETE(m_grass_mesh);
LUMIX_DELETE(m_grass_geometry);
for (int i = 0; i < m_grass_quads.size(); ++i)
{
LUMIX_DELETE(m_grass_quads[i]);
}
for (int i = 0; i < m_free_grass_quads.size(); ++i)
{
LUMIX_DELETE(m_free_grass_quads[i]);
}
LUMIX_DELETE(m_grass_types[i]);
}
for (int i = 0; i < m_grass_quads.size(); ++i)
{
LUMIX_DELETE(m_grass_quads[i]);
}
for (int i = 0; i < m_free_grass_quads.size(); ++i)
{
LUMIX_DELETE(m_free_grass_quads[i]);
}
}
Path Terrain::getGrassPath()
Terrain::GrassType::GrassType(Terrain& terrain)
: m_terrain(terrain)
{
if (m_grass_model)
m_grass_geometry = NULL;
m_grass_mesh = NULL;
m_grass_model = NULL;
m_ground = 0;
m_density = 10;
}
void Terrain::addGrassType(int index)
{
if(index < 0)
{
return m_grass_model->getPath();
m_grass_types.push(LUMIX_NEW(GrassType)(*this));
}
else
{
m_grass_types.insert(index, LUMIX_NEW(GrassType)(*this));
}
}
void Terrain::removeGrassType(int index)
{
forceGrassUpdate();
LUMIX_DELETE(m_grass_types[index]);
m_grass_types.erase(index);
}
void Terrain::setGrassTypeDensity(int index, int density)
{
forceGrassUpdate();
GrassType& type = *m_grass_types[index];
type.m_density = Math::clamp(density, 0, 50);
}
int Terrain::getGrassTypeDensity(int index)
{
GrassType& type = *m_grass_types[index];
return type.m_density;
}
void Terrain::setGrassTypeGround(int index, int ground)
{
ground = Math::clamp(ground, 0, 3);
forceGrassUpdate();
GrassType& type = *m_grass_types[index];
type.m_ground = ground;
}
int Terrain::getGrassTypeGround(int index)
{
GrassType& type = *m_grass_types[index];
return type.m_ground;
}
Path Terrain::getGrassTypePath(int index)
{
GrassType& type = *m_grass_types[index];
if (type.m_grass_model)
{
return type.m_grass_model->getPath();
}
return "";
}
void Terrain::setGrassPath(const Path& path)
void Terrain::setGrassTypePath(int index, const Path& path)
{
if (m_grass_model)
forceGrassUpdate();
GrassType& type = *m_grass_types[index];
if (type.m_grass_model)
{
m_grass_model->getResourceManager().get(ResourceManager::MODEL)->unload(*m_grass_model);
m_grass_model->getObserverCb().unbind<Terrain, &Terrain::grassLoaded>(this);
m_grass_model = NULL;
LUMIX_DELETE(m_grass_mesh);
LUMIX_DELETE(m_grass_geometry);
m_grass_mesh = NULL;
m_grass_geometry = NULL;
type.m_grass_model->getResourceManager().get(ResourceManager::MODEL)->unload(*type.m_grass_model);
type.m_grass_model->getObserverCb().unbind<GrassType, &GrassType::grassLoaded>(&type);
type.m_grass_model = NULL;
LUMIX_DELETE(type.m_grass_mesh);
LUMIX_DELETE(type.m_grass_geometry);
type.m_grass_mesh = NULL;
type.m_grass_geometry = NULL;
}
if (path.isValid())
{
m_grass_model = static_cast<Model*>(m_scene.getEngine().getResourceManager().get(ResourceManager::MODEL)->load(path));
m_grass_model->getObserverCb().bind<Terrain, &Terrain::grassLoaded>(this);
type.m_grass_model = static_cast<Model*>(m_scene.getEngine().getResourceManager().get(ResourceManager::MODEL)->load(path));
type.m_grass_model->getObserverCb().bind<GrassType, &GrassType::grassLoaded>(&type);
if(type.m_grass_model->isReady())
{
type.grassLoaded(Resource::State::READY, Resource::State::READY);
}
}
}
void Terrain::forceGrassUpdate()
{
m_force_grass_update = true;
while(!m_grass_quads.empty())
{
m_free_grass_quads.push(m_grass_quads.back());
m_grass_quads.pop();
}
}
void Terrain::updateGrass(const Vec3& camera_position)
{
PROFILE_FUNCTION();
@ -232,8 +328,9 @@ namespace Lumix
}
}
if ((m_last_camera_position - camera_position).length() > 1)
if ((m_last_camera_position - camera_position).length() > 1 || m_force_grass_update)
{
m_force_grass_update = false;
Matrix mtx = m_entity.getMatrix();
Matrix inv_mtx = m_entity.getMatrix();
inv_mtx.fastInverse();
@ -272,21 +369,41 @@ namespace Lumix
GrassQuad* quad = m_free_grass_quads.back();
m_free_grass_quads.pop();
m_grass_quads.push(quad);
quad->m_matrices.resize(31 * 31);
quad->m_x = quad_x;
quad->m_z = quad_z;
quad->m_patches.clear();
srand((int)quad_x + (int)quad_z * GRASS_QUADS_WIDTH);
int index = 0;
for (float dx = 0; dx < GRASS_QUAD_SIZE; dx += 0.333f)
for(int grass_type_idx = 0; grass_type_idx < m_grass_types.size(); ++grass_type_idx)
{
for (float dz = 0; dz < GRASS_QUAD_SIZE; dz += 0.333f)
GrassPatch& patch = quad->m_patches.pushEmpty();
patch.m_matrices.clear();
patch.m_type = m_grass_types[grass_type_idx];
if(patch.m_type->m_grass_geometry)
{
quad->m_matrices[index] = Matrix::IDENTITY;
float x = quad_x + dx + (rand() % 100 - 50) / 100.0f;
float z = quad_z + dz + (rand() % 100 - 50) / 100.0f;;
quad->m_matrices[index].setTranslation(Vec3(x, getHeight(x / m_xz_scale, z / m_xz_scale), z));
quad->m_matrices[index] = mtx * quad->m_matrices[index];
++index;
int index = 0;
Texture* splat_map = m_material->getTexture(m_material->getTextureCount() - 1);
float step = GRASS_QUAD_SIZE / (float)patch.m_type->m_density;
for (float dx = 0; dx < GRASS_QUAD_SIZE; dx += step)
{
for (float dz = 0; dz < GRASS_QUAD_SIZE; dz += step)
{
uint32_t pixel_value = splat_map->getPixel(splat_map->getWidth() * (quad_x + dx) / m_width, splat_map->getHeight() * (quad_z + dz) / m_height);
uint8_t count = (pixel_value >> (8 * patch.m_type->m_ground)) & 0xff;
float density = count / 255.0f;
if(density > 0.25f)
{
Matrix& grass_mtx = patch.m_matrices.pushEmpty();
grass_mtx = Matrix::IDENTITY;
float x = quad_x + dx + step * (rand() % 100 - 50) / 100.0f;
float z = quad_z + dz + step * (rand() % 100 - 50) / 100.0f;
grass_mtx.setTranslation(Vec3(x, getHeight(x / m_xz_scale, z / m_xz_scale), z));
grass_mtx = mtx * grass_mtx;
grass_mtx.multiply3x3(density + (rand() % 20 - 10) / 100.0f);
}
++index;
}
}
}
}
}
@ -297,7 +414,7 @@ namespace Lumix
}
void Terrain::grassVertexCopyCallback(Array<uint8_t>& data)
void Terrain::GrassType::grassVertexCopyCallback(Array<uint8_t>& data)
{
bool has_matrix_index_attribute = m_grass_model->getGeometry()->getVertexDefinition().getAttributeType(3) == VertexAttributeDef::INT1;
if (has_matrix_index_attribute)
@ -320,7 +437,7 @@ namespace Lumix
}
void Terrain::grassIndexCopyCallback(Array<int>& data)
void Terrain::GrassType::grassIndexCopyCallback(Array<int>& data)
{
int indices_count = m_grass_model->getGeometry()->getIndices().size();
int index_offset = m_grass_model->getGeometry()->getVertices().size();
@ -334,7 +451,7 @@ namespace Lumix
}
void Terrain::grassLoaded(Resource::State, Resource::State)
void Terrain::GrassType::grassLoaded(Resource::State, Resource::State)
{
if (m_grass_model->isReady())
{
@ -343,38 +460,40 @@ namespace Lumix
m_grass_geometry = LUMIX_NEW(Geometry);
Geometry::VertexCallback vertex_callback;
Geometry::IndexCallback index_callback;
vertex_callback.bind<Terrain, &Terrain::grassVertexCopyCallback>(this);
index_callback.bind<Terrain, &Terrain::grassIndexCopyCallback>(this);
vertex_callback.bind<GrassType, &GrassType::grassVertexCopyCallback>(this);
index_callback.bind<GrassType, &GrassType::grassIndexCopyCallback>(this);
m_grass_geometry->copy(*m_grass_model->getGeometry(), COPY_COUNT, vertex_callback, index_callback);
Material* material = m_grass_model->getMesh(0).getMaterial();
m_grass_mesh = LUMIX_NEW(Mesh)(material, 0, m_grass_model->getMesh(0).getCount() * COPY_COUNT, "grass");
m_terrain.forceGrassUpdate();
}
}
void Terrain::getGrassInfos(Array<GrassInfo>& infos, const Vec3& camera_position)
{
if (m_grass_geometry && m_grass_model->isReady() && m_material->isReady())
updateGrass(camera_position);
for (int i = 0; i < m_grass_quads.size(); ++i)
{
updateGrass(camera_position);
for (int i = 0; i < m_grass_quads.size(); ++i)
for(int patch_idx = 0; patch_idx < m_grass_quads[i]->m_patches.size(); ++patch_idx)
{
for (int k = 0, kc = m_grass_quads[i]->m_matrices.size() / COPY_COUNT; k < kc; ++k)
GrassPatch& patch = m_grass_quads[i]->m_patches[patch_idx];
for (int k = 0, kc = patch.m_matrices.size() / COPY_COUNT; k < kc; ++k)
{
GrassInfo& info = infos.pushEmpty();
info.m_geometry = m_grass_geometry;
info.m_matrices = &m_grass_quads[i]->m_matrices[COPY_COUNT * k];
info.m_mesh = m_grass_mesh;
info.m_geometry = patch.m_type->m_grass_geometry;
info.m_matrices = &patch.m_matrices[COPY_COUNT * k];
info.m_mesh = patch.m_type->m_grass_mesh;
info.m_matrix_count = COPY_COUNT;
info.m_mesh_copy_count = COPY_COUNT;
}
if (m_grass_quads[i]->m_matrices.size() % COPY_COUNT != 0)
if (patch.m_matrices.size() % COPY_COUNT != 0)
{
GrassInfo& info = infos.pushEmpty();
info.m_geometry = m_grass_geometry;
info.m_matrices = &m_grass_quads[i]->m_matrices[COPY_COUNT * (m_grass_quads[i]->m_matrices.size() / COPY_COUNT)];
info.m_mesh = m_grass_mesh;
info.m_matrix_count = m_grass_quads[i]->m_matrices.size() % COPY_COUNT;
info.m_geometry = patch.m_type->m_grass_geometry;
info.m_matrices = &patch.m_matrices[COPY_COUNT * (patch.m_matrices.size() / COPY_COUNT)];
info.m_mesh = patch.m_type->m_grass_mesh;
info.m_matrix_count = patch.m_matrices.size() % COPY_COUNT;
info.m_mesh_copy_count = COPY_COUNT;
}
}
@ -418,8 +537,24 @@ namespace Lumix
setMaterial(static_cast<Material*>(scene.getEngine().getResourceManager().get(ResourceManager::MATERIAL)->load(path)));
serializer.deserializeArrayItem(m_xz_scale);
serializer.deserializeArrayItem(m_y_scale);
serializer.deserializeArrayItem(path, LUMIX_MAX_PATH);
setGrassPath(path);
int count;
serializer.deserializeArrayItem(count);
while(m_grass_types.size() > count)
{
removeGrassType(m_grass_types.size() - 1);
}
while(m_grass_types.size() < count)
{
addGrassType(-1);
}
for(int i = 0; i < count; ++i)
{
serializer.deserializeArrayItem(path, LUMIX_MAX_PATH);
serializer.deserializeArrayItem(m_grass_types[i]->m_ground);
serializer.deserializeArrayItem(m_grass_types[i]->m_density);
setGrassTypePath(i, path);
}
universe.addComponent(m_entity, TERRAIN_HASH, &scene, index);
}
@ -428,10 +563,18 @@ namespace Lumix
{
serializer.serializeArrayItem(m_entity.index);
serializer.serializeArrayItem(m_layer_mask);
serializer.serializeArrayItem(m_material->getPath().c_str());
serializer.serializeArrayItem(m_material ? m_material->getPath().c_str() : "");
serializer.serializeArrayItem(m_xz_scale);
serializer.serializeArrayItem(m_y_scale);
serializer.serializeArrayItem(m_grass_model ? m_grass_model->getPath().c_str() : "");
serializer.serializeArrayItem(m_grass_types.size());
for(int i = 0; i < m_grass_types.size(); ++i)
{
GrassType& type = *m_grass_types[i];
serializer.serializeArrayItem(type.m_grass_model ? type.m_grass_model->getPath().c_str() : "");
serializer.serializeArrayItem(type.m_ground);
serializer.serializeArrayItem(type.m_density);
}
}
@ -444,11 +587,12 @@ namespace Lumix
m_entity.getMatrix(world_matrix);
world_matrix.fastInverse();
Vec3 rel_cam_pos = world_matrix.multiplyPosition(camera_pos) / m_xz_scale;
m_mesh->getMaterial()->getShader()->setUniform("brush_position", m_brush_position);
m_mesh->getMaterial()->getShader()->setUniform("brush_size", m_brush_size);
m_mesh->getMaterial()->getShader()->setUniform("map_size", m_root->m_size);
m_mesh->getMaterial()->getShader()->setUniform("camera_pos", rel_cam_pos);
m_root->render(m_mesh, m_geometry, rel_cam_pos, *pipeline.getScene());
Shader& shader = *m_mesh->getMaterial()->getShader();
renderer.setUniform(shader, "brush_position", BRUSH_POSITION_HASH, m_brush_position);
renderer.setUniform(shader, "brush_size", BRUSH_SIZE_HASH, m_brush_size);
renderer.setUniform(shader, "map_size", MAP_SIZE_HASH, m_root->m_size);
renderer.setUniform(shader, "camera_pos", CAMERA_POS_HASH, rel_cam_pos);
m_root->render(&static_cast<Renderer&>(m_scene.getPlugin()), m_mesh, m_geometry, rel_cam_pos, *pipeline.getScene());
}
}
@ -477,8 +621,10 @@ namespace Lumix
float Terrain::getHeight(int x, int z)
{
int texture_x = (int)(x / m_xz_scale);
int texture_y = (int)(z / m_xz_scale);
Texture* t = m_material->getTexture(0);
int idx = Math::clamp(x, 0, m_width) + Math::clamp(z, 0, m_height) * m_width;
int idx = Math::clamp(texture_x, 0, m_width) + Math::clamp(texture_y, 0, m_height) * m_width;
if (t->getBytesPerPixel() == 2)
{
return ((m_y_scale / (256.0f * 256.0f - 1)) * ((uint16_t*)t->getData())[idx]);
@ -494,6 +640,7 @@ namespace Lumix
return 0;
}
bool getRayTriangleIntersection(const Vec3& local_origin, const Vec3& local_dir, const Vec3& p0, const Vec3& p1, const Vec3& p2, float& out)
{
Vec3 normal = crossProduct(p1 - p0, p2 - p0);

View file

@ -26,10 +26,35 @@ struct TerrainQuad;
class Terrain
{
public:
class GrassQuad
class GrassType
{
public:
GrassType(Terrain& terrain);
~GrassType();
void grassLoaded(Resource::State, Resource::State);
void grassVertexCopyCallback(Array<uint8_t>& data);
void grassIndexCopyCallback(Array<int>& data);
Geometry* m_grass_geometry;
Mesh* m_grass_mesh;
Model* m_grass_model;
Terrain& m_terrain;
int m_ground;
int m_density;
};
class GrassPatch
{
public:
Array<Matrix> m_matrices;
GrassType* m_type;
};
class GrassQuad
{
public:
Array<GrassPatch> m_patches;
float m_x;
float m_z;
};
@ -54,21 +79,26 @@ class Terrain
float getYScale() const { return m_y_scale; }
Entity getEntity() const { return m_entity; }
Material* getMaterial() const { return m_material; }
void setGrassPath(const Path& path);
Path getGrassPath();
void setGrassTypePath(int index, const Path& path);
Path getGrassTypePath(int index);
void setGrassTypeGround(int index, int ground);
int getGrassTypeGround(int index);
void setGrassTypeDensity(int index, int density);
int getGrassTypeDensity(int index);
void addGrassType(int index);
void removeGrassType(int index);
int getGrassTypeCount() const { return m_grass_types.size(); }
void setMaterial(Material* material);
void getGrassInfos(Array<GrassInfo>& infos, const Vec3& camera_position);
void setBrush(const Vec3& position, float size) { m_brush_position = position; m_brush_size = size; }
float getHeight(float x, float z);
private:
void updateGrass(const Vec3& camera_position);
void generateGeometry();
void onMaterialLoaded(Resource::State, Resource::State new_state);
float getHeight(int x, int z);
float getHeight(float x, float z);
void grassLoaded(Resource::State, Resource::State);
void grassVertexCopyCallback(Array<uint8_t>& data);
void grassIndexCopyCallback(Array<int>& data);
void forceGrassUpdate();
private:
Mesh* m_mesh;
@ -81,15 +111,14 @@ class Terrain
float m_y_scale;
Entity m_entity;
Material* m_material;
Geometry* m_grass_geometry;
Mesh* m_grass_mesh;
RenderScene& m_scene;
Model* m_grass_model;
Array<GrassType*> m_grass_types;
Array<GrassQuad*> m_free_grass_quads;
Array<GrassQuad*> m_grass_quads;
Vec3 m_last_camera_position;
Vec3 m_brush_position;
float m_brush_size;
bool m_force_grass_update;
};

View file

@ -449,6 +449,43 @@ namespace Lumix
glBindTexture(m_is_cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, m_id);
}
uint32_t Texture::getPixel(float x, float y) const
{
if(m_data.empty() || x >= m_width || y >= m_height || x < 0 || y < 0)
{
return 0;
}
// http://fastcpp.blogspot.sk/2011/06/bilinear-pixel-interpolation-using-sse.html
int px = (int)x;
int py = (int)y;
const uint32_t* p0 = (uint32_t*)&m_data[(px + py * m_width) * 4];
const uint8_t* p1 = (uint8_t*)p0;
const uint8_t* p2 = (uint8_t*)(p0 + 1);
const uint8_t* p3 = (uint8_t*)(p0 + m_width);
const uint8_t* p4 = (uint8_t*)(p0 + 1 + m_width);
float fx = x - px;
float fy = y - py;
float fx1 = 1.0f - fx;
float fy1 = 1.0f - fy;
int w1 = (int)(fx1 * fy1 * 256.0f);
int w2 = (int)(fx * fy1 * 256.0f);
int w3 = (int)(fx1 * fy * 256.0f);
int w4 = (int)(fx * fy * 256.0f);
uint8_t res[4];
res[0] = (uint8_t)((p1[0] * w1 + p2[0] * w2 + p3[0] * w3 + p4[0] * w4) >> 8);
res[1] = (uint8_t)((p1[1] * w1 + p2[1] * w2 + p3[1] * w3 + p4[1] * w4) >> 8);
res[2] = (uint8_t)((p1[2] * w1 + p2[2] * w2 + p3[2] * w3 + p4[2] * w4) >> 8);
res[3] = (uint8_t)((p1[3] * w1 + p2[3] * w2 + p3[3] * w3 + p4[3] * w4) >> 8);
return *(uint32_t*)res;
}
void Texture::saveTGA()
{
@ -670,6 +707,8 @@ bool Texture::loadDDS(FS::IFile& file)
width = hdr.dwWidth;
height = hdr.dwHeight;
m_width = width;
m_height = height;
if ((width & (width - 1)) || (height & (height - 1)))
{
g_log_error.log("renderer") << "Wrong dds format " << m_path.c_str();
@ -863,7 +902,7 @@ void Texture::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
}
if(!loaded)
{
g_log_error.log("renderer") << "Error loading texture " << m_path.c_str();
g_log_warning.log("renderer") << "Error loading texture " << m_path.c_str();
onFailure();
}
else
@ -874,7 +913,7 @@ void Texture::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
}
else
{
g_log_error.log("renderer") << "Error loading texture " << m_path.c_str();
g_log_warning.log("renderer") << "Error loading texture " << m_path.c_str();
onFailure();
}

View file

@ -31,6 +31,7 @@ class LUMIX_ENGINE_API Texture : public Resource
void removeDataReference();
void onDataUpdated();
void save();
uint32_t getPixel(float x, float y) const;
private:
void loaded(FS::IFile* file, bool success, FS::FileSystem& fs);

View file

@ -49,7 +49,7 @@ struct OutputStream : public physx::PxOutputStream
{
if (size + (int)count > capacity)
{
int new_capacity = Math::max(size + (int)count, capacity + 4096);
int new_capacity = Math::maxValue(size + (int)count, capacity + 4096);
uint8_t* new_data = LUMIX_NEW_ARRAY(unsigned char, new_capacity);
memcpy(new_data, data, size);
LUMIX_DELETE_ARRAY(data);
@ -147,7 +147,63 @@ struct PhysicsSceneImpl : public PhysicsScene
}
virtual Component createHeightfield(Entity entity) override
virtual IPlugin& getPlugin() const override
{
return *m_system;
}
virtual Component createComponent(uint32_t component_type, const Entity& entity) override
{
if (component_type == HEIGHTFIELD_HASH)
{
return createHeightfield(entity);
}
else if (component_type == CONTROLLER_HASH)
{
return createController(entity);
}
else if (component_type == BOX_ACTOR_HASH)
{
return createBoxRigidActor(entity);
}
else if (component_type == MESH_ACTOR_HASH)
{
return createMeshRigidActor(entity);
}
return Component::INVALID;
}
virtual void destroyComponent(const Component& cmp) override
{
if(cmp.type == HEIGHTFIELD_HASH)
{
LUMIX_DELETE(m_terrains[cmp.index]);
m_terrains[cmp.index] = NULL;
m_universe->destroyComponent(cmp);
m_universe->componentDestroyed().invoke(cmp);
}
else if(cmp.type == CONTROLLER_HASH)
{
m_controllers[cmp.index].m_is_free = true;
m_universe->destroyComponent(cmp);
m_universe->componentDestroyed().invoke(cmp);
}
else if (cmp.type == MESH_ACTOR_HASH || cmp.type == BOX_ACTOR_HASH)
{
m_actors[cmp.index]->m_entity.index = -1;
m_universe->destroyComponent(cmp);
m_universe->componentDestroyed().invoke(cmp);
}
else
{
ASSERT(false);
}
}
Component createHeightfield(Entity entity)
{
Terrain* terrain = LUMIX_NEW(Terrain);
m_terrains.push(terrain);
@ -161,7 +217,7 @@ struct PhysicsSceneImpl : public PhysicsScene
}
virtual Component createController(Entity entity) override
Component createController(Entity entity)
{
physx::PxCapsuleControllerDesc cDesc;
cDesc.material = m_default_material;
@ -177,6 +233,7 @@ struct PhysicsSceneImpl : public PhysicsScene
PhysicsSceneImpl::Controller c;
c.m_controller = m_system->m_impl->m_controller_manager->createController(*m_system->m_impl->m_physics, m_scene, cDesc);
c.m_entity = entity;
c.m_is_free = false;
m_controllers.push(c);
@ -186,7 +243,7 @@ struct PhysicsSceneImpl : public PhysicsScene
}
virtual Component createBoxRigidActor(Entity entity) override
Component createBoxRigidActor(Entity entity)
{
RigidActor* actor = LUMIX_NEW(RigidActor);
m_actors.push(actor);
@ -214,7 +271,7 @@ struct PhysicsSceneImpl : public PhysicsScene
}
virtual Component createMeshRigidActor(Entity entity) override
Component createMeshRigidActor(Entity entity)
{
RigidActor* actor = LUMIX_NEW(RigidActor);
m_actors.push(actor);
@ -234,13 +291,13 @@ struct PhysicsSceneImpl : public PhysicsScene
}
virtual void getHeightmapXZScale(Component cmp, float& scale) override
virtual float getHeightmapXZScale(Component cmp) override
{
scale = m_terrains[cmp.index]->m_xz_scale;
return m_terrains[cmp.index]->m_xz_scale;
}
virtual void setHeightmapXZScale(Component cmp, const float& scale) override
virtual void setHeightmapXZScale(Component cmp, float scale) override
{
if (scale != m_terrains[cmp.index]->m_xz_scale)
{
@ -250,13 +307,13 @@ struct PhysicsSceneImpl : public PhysicsScene
}
virtual void getHeightmapYScale(Component cmp, float& scale) override
virtual float getHeightmapYScale(Component cmp) override
{
scale = m_terrains[cmp.index]->m_y_scale;
return m_terrains[cmp.index]->m_y_scale;
}
virtual void setHeightmapYScale(Component cmp, const float& scale) override
virtual void setHeightmapYScale(Component cmp, float scale) override
{
if (scale != m_terrains[cmp.index]->m_y_scale)
{
@ -460,9 +517,12 @@ struct PhysicsSceneImpl : public PhysicsScene
physx::PxVec3 g(0, time_delta * -9.8f, 0);
for (int i = 0; i < m_controllers.size(); ++i)
{
const physx::PxExtendedVec3& p = m_controllers[i].m_controller->getPosition();
m_controllers[i].m_controller->move(g, 0.0001f, time_delta, physx::PxControllerFilters());
m_controllers[i].m_entity.setPosition((float)p.x, (float)p.y, (float)p.z);
if(!m_controllers[i].m_is_free)
{
const physx::PxExtendedVec3& p = m_controllers[i].m_controller->getPosition();
m_controllers[i].m_controller->move(g, 0.0001f, time_delta, physx::PxControllerFilters());
m_controllers[i].m_entity.setPosition((float)p.x, (float)p.y, (float)p.z);
}
}
}
@ -500,7 +560,7 @@ struct PhysicsSceneImpl : public PhysicsScene
}
void onEntityMoved(Entity& entity)
void onEntityMoved(const Entity& entity)
{
const Entity::ComponentList& cmps = entity.getComponents();
for (int i = 0, c = cmps.size(); i < c; ++i)
@ -634,8 +694,9 @@ struct PhysicsSceneImpl : public PhysicsScene
}
virtual void getHalfExtents(Component cmp, Vec3& size) override
virtual Vec3 getHalfExtents(Component cmp) override
{
Vec3 size;
physx::PxRigidActor* actor = m_actors[cmp.index]->m_physx_actor;
physx::PxShape* shapes;
if (actor->getNbShapes() == 1 && m_actors[cmp.index]->m_physx_actor->getShapes(&shapes, 1))
@ -645,6 +706,7 @@ struct PhysicsSceneImpl : public PhysicsScene
size.y = half.y;
size.z = half.z;
}
return size;
}
@ -795,7 +857,10 @@ struct PhysicsSceneImpl : public PhysicsScene
serializer.serializeArrayItem(m_actors[i]->m_source);
serializer.serializeArrayItem(isDynamic(i));
serializer.serializeArrayItem(m_actors[i]->m_entity.index);
serializeActor(serializer, i);
if(m_actors[i]->m_entity.index != -1)
{
serializeActor(serializer, i);
}
}
serializer.endArray();
serializer.serialize("count", m_controllers.size());
@ -803,16 +868,25 @@ struct PhysicsSceneImpl : public PhysicsScene
for (int i = 0; i < m_controllers.size(); ++i)
{
serializer.serializeArrayItem(m_controllers[i].m_entity.index);
serializer.serializeArrayItem(m_controllers[i].m_is_free);
}
serializer.endArray();
serializer.serialize("count", m_terrains.size());
serializer.beginArray("terrains");
for (int i = 0; i < m_terrains.size(); ++i)
{
serializer.serializeArrayItem(m_terrains[i]->m_entity.index);
serializer.serializeArrayItem(m_terrains[i]->m_heightmap->getPath().c_str());
serializer.serializeArrayItem(m_terrains[i]->m_xz_scale);
serializer.serializeArrayItem(m_terrains[i]->m_y_scale);
if(m_terrains[i])
{
serializer.serializeArrayItem(true);
serializer.serializeArrayItem(m_terrains[i]->m_entity.index);
serializer.serializeArrayItem(m_terrains[i]->m_heightmap->getPath().c_str());
serializer.serializeArrayItem(m_terrains[i]->m_xz_scale);
serializer.serializeArrayItem(m_terrains[i]->m_y_scale);
}
else
{
serializer.serializeArrayItem(false);
}
}
serializer.endArray();
}
@ -839,8 +913,11 @@ struct PhysicsSceneImpl : public PhysicsScene
m_dynamic_actors.push(m_actors[i]);
}
serializer.deserializeArrayItem(m_actors[i]->m_entity.index);
m_actors[i]->m_entity.universe = m_universe;
deserializeActor(serializer, i);
if(m_actors[i]->m_entity.index != -1)
{
m_actors[i]->m_entity.universe = m_universe;
deserializeActor(serializer, i);
}
}
serializer.deserializeArrayEnd();
}
@ -859,26 +936,32 @@ struct PhysicsSceneImpl : public PhysicsScene
for (int i = 0; i < count; ++i)
{
int index;
bool is_free;
serializer.deserializeArrayItem(index);
serializer.deserializeArrayItem(is_free);
Entity e(m_universe, index);
physx::PxCapsuleControllerDesc cDesc;
cDesc.material = m_default_material;
cDesc.height = 1.8f;
cDesc.radius = 0.25f;
cDesc.slopeLimit = 0.0f;
cDesc.contactOffset = 0.1f;
cDesc.stepOffset = 0.02f;
cDesc.callback = NULL;
cDesc.behaviorCallback = NULL;
Vec3 position = e.getPosition();
cDesc.position.set(position.x, position.y, position.z);
Controller c;
c.m_controller = m_system->m_impl->m_controller_manager->createController(*m_system->m_impl->m_physics, m_scene, cDesc);
c.m_entity = e;
c.m_is_free = is_free;
m_controllers.push(c);
m_universe->addComponent(e, CONTROLLER_HASH, this, i);
if(!is_free)
{
physx::PxCapsuleControllerDesc cDesc;
cDesc.material = m_default_material;
cDesc.height = 1.8f;
cDesc.radius = 0.25f;
cDesc.slopeLimit = 0.0f;
cDesc.contactOffset = 0.1f;
cDesc.stepOffset = 0.02f;
cDesc.callback = NULL;
cDesc.behaviorCallback = NULL;
Vec3 position = e.getPosition();
cDesc.position.set(position.x, position.y, position.z);
c.m_controller = m_system->m_impl->m_controller_manager->createController(*m_system->m_impl->m_physics, m_scene, cDesc);
c.m_entity = e;
m_universe->addComponent(e, CONTROLLER_HASH, this, i);
}
}
serializer.deserializeArrayEnd();
}
@ -891,30 +974,36 @@ struct PhysicsSceneImpl : public PhysicsScene
for (int i = count; i < m_terrains.size(); ++i)
{
LUMIX_DELETE(m_terrains[i]);
m_terrains[i] = NULL;
}
int old_size = m_terrains.size();
m_terrains.resize(count);
for (int i = old_size; i < count; ++i)
{
m_terrains[i] = LUMIX_NEW(Terrain);
}
serializer.deserializeArrayBegin("terrains");
for (int i = 0; i < count; ++i)
{
m_terrains[i]->m_scene = this;
m_terrains[i]->m_entity.universe = m_universe;
serializer.deserializeArrayItem(m_terrains[i]->m_entity.index);
char tmp[LUMIX_MAX_PATH];
serializer.deserializeArrayItem(tmp, LUMIX_MAX_PATH);
serializer.deserializeArrayItem(m_terrains[i]->m_xz_scale);
serializer.deserializeArrayItem(m_terrains[i]->m_y_scale);
Component cmp(m_terrains[i]->m_entity, HEIGHTFIELD_HASH, this, i);
if (m_terrains[i]->m_heightmap == NULL || strcmp(tmp, m_terrains[i]->m_heightmap->getPath().c_str()) != 0)
bool exists;
serializer.deserializeArrayItem(exists);
if(exists)
{
setHeightmap(cmp, string(tmp));
if(!m_terrains[i])
{
m_terrains[i] = LUMIX_NEW(Terrain);
}
m_terrains[i]->m_scene = this;
m_terrains[i]->m_entity.universe = m_universe;
serializer.deserializeArrayItem(m_terrains[i]->m_entity.index);
char tmp[LUMIX_MAX_PATH];
serializer.deserializeArrayItem(tmp, LUMIX_MAX_PATH);
serializer.deserializeArrayItem(m_terrains[i]->m_xz_scale);
serializer.deserializeArrayItem(m_terrains[i]->m_y_scale);
Component cmp(m_terrains[i]->m_entity, HEIGHTFIELD_HASH, this, i);
if (m_terrains[i]->m_heightmap == NULL || strcmp(tmp, m_terrains[i]->m_heightmap->getPath().c_str()) != 0)
{
setHeightmap(cmp, string(tmp));
}
m_universe->addComponent(m_terrains[i]->m_entity, HEIGHTFIELD_HASH, this, i);
}
m_universe->addComponent(m_terrains[i]->m_entity, HEIGHTFIELD_HASH, this, i);
}
serializer.deserializeArrayEnd();
}
@ -944,6 +1033,7 @@ struct PhysicsSceneImpl : public PhysicsScene
{
physx::PxController* m_controller;
Entity m_entity;
bool m_is_free;
};
Universe* m_universe;

View file

@ -4,6 +4,7 @@
#include "core/lumix.h"
#include "core/string.h"
#include "core/vec3.h"
#include "engine/iplugin.h"
#include "universe/universe.h"
@ -22,7 +23,7 @@ struct RaycastHit
};
class LUMIX_PHYSICS_API PhysicsScene
class LUMIX_PHYSICS_API PhysicsScene : public IScene
{
friend class PhysicsSystem;
public:
@ -33,29 +34,22 @@ class LUMIX_PHYSICS_API PhysicsScene
virtual void update(float time_delta) = 0;
virtual void render() = 0;
virtual bool raycast(const Vec3& origin, const Vec3& dir, float distance, RaycastHit& result) = 0;
virtual Component createBoxRigidActor(Entity entity) = 0;
virtual Component createMeshRigidActor(Entity entity) = 0;
virtual Component createController(Entity entity) = 0;
virtual Component createHeightfield(Entity entity) = 0;
virtual PhysicsSystem& getSystem() const = 0;
virtual void getIsDynamic(Component cmp, bool& is) = 0;
virtual void setIsDynamic(Component cmp, const bool& is) = 0;
virtual void getHalfExtents(Component cmp, Vec3& size) = 0;
virtual Vec3 getHalfExtents(Component cmp) = 0;
virtual void setHalfExtents(Component cmp, const Vec3& size) = 0;
virtual void getShapeSource(Component cmp, string& str) = 0;
virtual void setShapeSource(Component cmp, const string& str) = 0;
virtual void getHeightmap(Component cmp, string& str) = 0;
virtual void setHeightmap(Component cmp, const string& str) = 0;
virtual void getHeightmapXZScale(Component cmp, float& scale) = 0;
virtual void setHeightmapXZScale(Component cmp, const float& scale) = 0;
virtual void getHeightmapYScale(Component cmp, float& scale) = 0;
virtual void setHeightmapYScale(Component cmp, const float& scale) = 0;
virtual float getHeightmapXZScale(Component cmp) = 0;
virtual void setHeightmapXZScale(Component cmp, float scale) = 0;
virtual float getHeightmapYScale(Component cmp) = 0;
virtual void setHeightmapYScale(Component cmp, float scale) = 0;
virtual void moveController(Component cmp, const Vec3& v, float dt) = 0;
virtual void serialize(ISerializer& serializer) = 0;
virtual void deserialize(ISerializer& serializer) = 0;
};

View file

@ -33,78 +33,9 @@ struct CustomErrorCallback : public physx::PxErrorCallback
virtual void reportError(physx::PxErrorCode::Enum code, const char* message, const char* file, int line);
};
void PhysicsSystem::onCreateUniverse(Universe& universe)
IScene* PhysicsSystem::createScene(Universe& universe)
{
m_impl->m_scene = PhysicsScene::create(*this, universe, *m_impl->m_engine);
}
void PhysicsSystem::onDestroyUniverse(Universe& universe)
{
PhysicsScene::destroy(m_impl->m_scene);
m_impl->m_scene = NULL;
}
void PhysicsSystem::serialize(ISerializer& serializer)
{
m_impl->m_scene->serialize(serializer);
}
void PhysicsSystem::deserialize(ISerializer& serializer)
{
m_impl->m_scene->deserialize(serializer);
}
void PhysicsSystem::sendMessage(const char* message)
{
if(strcmp("render", message) == 0)
{
m_impl->m_scene->render();
}
}
void PhysicsSystem::destroyComponent(const Component& component)
{
ASSERT(false);
}
Component PhysicsSystem::createComponent(uint32_t component_type, const Entity& entity)
{
if (component_type == HEIGHTFIELD_HASH)
{
return m_impl->m_scene->createHeightfield(entity);
}
else if (component_type == CONTROLLER_HASH)
{
return m_impl->m_scene->createController(entity);
}
else if (component_type == BOX_ACTOR_HASH)
{
return m_impl->m_scene->createBoxRigidActor(entity);
}
else if (component_type == MESH_ACTOR_HASH)
{
return m_impl->m_scene->createMeshRigidActor(entity);
}
return Component::INVALID;
}
void PhysicsSystem::update(float dt)
{
m_impl->m_scene->update(dt);
}
PhysicsScene* PhysicsSystem::getScene() const
{
return m_impl->m_scene;
return PhysicsScene::create(*this, universe, *m_impl->m_engine);
}
@ -127,16 +58,12 @@ class AssertNullAllocator : public physx::PxAllocatorCallback
bool PhysicsSystem::create(Engine& engine)
{
engine.getWorldEditor()->registerProperty("box_rigid_actor", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("dynamic"), &PhysicsScene::getIsDynamic, &PhysicsScene::setIsDynamic));
engine.getWorldEditor()->registerProperty("box_rigid_actor", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("size"), &PhysicsScene::getHalfExtents, &PhysicsScene::setHalfExtents));
engine.getWorldEditor()->registerProperty("mesh_rigid_actor", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("source"), &PhysicsScene::getShapeSource, &PhysicsScene::setShapeSource, IPropertyDescriptor::FILE));
engine.getWorldEditor()->registerProperty("physical_heightfield", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("heightmap"), &PhysicsScene::getHeightmap, &PhysicsScene::setHeightmap, IPropertyDescriptor::FILE));
engine.getWorldEditor()->registerProperty("physical_heightfield", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("xz_scale"), &PhysicsScene::getHeightmapXZScale, &PhysicsScene::setHeightmapXZScale));
engine.getWorldEditor()->registerProperty("physical_heightfield", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("y_scale"), &PhysicsScene::getHeightmapYScale, &PhysicsScene::setHeightmapYScale));
engine.getWorldEditor()->registerCreator(HEIGHTFIELD_HASH, *this);
engine.getWorldEditor()->registerCreator(BOX_ACTOR_HASH, *this);
engine.getWorldEditor()->registerCreator(MESH_ACTOR_HASH, *this);
engine.getWorldEditor()->registerCreator(CONTROLLER_HASH, *this);
engine.getWorldEditor()->registerProperty("box_rigid_actor", LUMIX_NEW(BoolPropertyDescriptor<PhysicsScene>)("dynamic", &PhysicsScene::getIsDynamic, &PhysicsScene::setIsDynamic));
engine.getWorldEditor()->registerProperty("box_rigid_actor", LUMIX_NEW(Vec3PropertyDescriptor<PhysicsScene>)("size", &PhysicsScene::getHalfExtents, &PhysicsScene::setHalfExtents));
engine.getWorldEditor()->registerProperty("mesh_rigid_actor", LUMIX_NEW(FilePropertyDescriptor<PhysicsScene>)("source", &PhysicsScene::getShapeSource, &PhysicsScene::setShapeSource, "Physics (*.pda)"));
engine.getWorldEditor()->registerProperty("physical_heightfield", LUMIX_NEW(FilePropertyDescriptor<PhysicsScene>)("heightmap", &PhysicsScene::getHeightmap, &PhysicsScene::setHeightmap, "Image (*.raw)"));
engine.getWorldEditor()->registerProperty("physical_heightfield", LUMIX_NEW(DecimalPropertyDescriptor<PhysicsScene>)("xz_scale", &PhysicsScene::getHeightmapXZScale, &PhysicsScene::setHeightmapXZScale));
engine.getWorldEditor()->registerProperty("physical_heightfield", LUMIX_NEW(DecimalPropertyDescriptor<PhysicsScene>)("y_scale", &PhysicsScene::getHeightmapYScale, &PhysicsScene::setHeightmapYScale));
m_impl = LUMIX_NEW(PhysicsSystemImpl);
m_impl->m_allocator = LUMIX_NEW(AssertNullAllocator)();

View file

@ -17,17 +17,9 @@ class LUMIX_PHYSICS_API PhysicsSystem : public IPlugin
PhysicsSystem() { m_impl = 0; }
virtual bool create(Engine& engine) override;
virtual IScene* createScene(Universe& universe) override;
virtual void destroy() override;
virtual void onCreateUniverse(Universe& universe) override;
virtual void onDestroyUniverse(Universe& universe) override;
virtual void serialize(ISerializer& serializer) override;
virtual void deserialize(ISerializer& serializer) override;
virtual void update(float dt) override;
virtual Component createComponent(uint32_t component_type, const Entity& entity) override;
virtual void destroyComponent(const Component& component) override;
virtual const char* getName() const override { return "physics"; }
virtual void sendMessage(const char* message) override;
class PhysicsScene* getScene() const;
private:
struct PhysicsSystemImpl* m_impl;

View file

@ -18,7 +18,6 @@ struct PhysicsSystemImpl
physx::PxAllocatorCallback* m_allocator;
physx::PxErrorCallback* m_error_callback;
physx::PxCooking* m_cooking;
class PhysicsScene* m_scene;
class Engine* m_engine;
};

View file

@ -8,7 +8,7 @@ namespace Lumix
{
class ScriptSystem;
class ScriptScene;
class ScriptVisitor;
@ -17,7 +17,7 @@ class BaseScript
public:
virtual ~BaseScript() {}
virtual void create(ScriptSystem& ctx, Entity e) = 0;
virtual void create(ScriptScene& ctx, Entity e) = 0;
virtual void update(float) {}
virtual void visit(ScriptVisitor&) {}
};

View file

@ -21,273 +21,305 @@ namespace Lumix
typedef BaseScript* (*CreateScriptFunction)();
typedef void (*DestroyScriptFunction)(BaseScript* script);
class ScriptSceneImpl : public ScriptScene
{
public:
ScriptSceneImpl(ScriptSystem& system, Engine& engine, Universe& universe)
: m_universe(universe)
, m_engine(engine)
, m_system(system)
{
}
~ScriptSceneImpl()
{
stopAll();
}
virtual IPlugin& getPlugin() const
{
return m_system;
}
void deserialize(ISerializer& serializer) override
{
stopAll();
int count;
serializer.deserialize("count", count);
serializer.deserializeArrayBegin("scripts");
m_script_entities.resize(count);
m_paths.resize(count);
for (int i = 0; i < m_script_entities.size(); ++i)
{
serializer.deserializeArrayItem(m_script_entities[i]);
serializer.deserializeArrayItem(m_paths[i]);
Entity entity(&m_universe, m_script_entities[i]);
if(m_script_entities[i] != -1)
{
m_universe.addComponent(entity, SCRIPT_HASH, this, i);
}
}
serializer.deserializeArrayEnd();
runAll();
}
void update(float dt)
{
for (int i = 0; i < m_running_scripts.size(); ++i)
{
m_running_scripts[i].m_script_object->update(dt);
}
}
void getScriptPath(Component cmp, string& str) override
{
str = m_paths[cmp.index];
}
void setScriptPath(Component cmp, const string& str) override
{
m_paths[cmp.index] = str;
stopScript(cmp.index);
if (!runScript(cmp.index, cmp.entity))
{
g_log_warning.log("script") << "Could not run script " << str;
}
}
void getDll(const char* script_path, char* dll_path, char* full_path, int max_length)
{
copyString(dll_path, max_length, script_path);
int32_t len = (int32_t)strlen(script_path);
if (len > 4)
{
copyString(dll_path + len - 4, 5, ".dll");
}
copyString(full_path, max_length, m_engine.getBasePath());
catCString(full_path, max_length, "\\");
catCString(full_path, max_length, dll_path);
}
void getScriptDefaultPath(Entity e, char* path, char* full_path, int length, const char* ext)
{
char tmp[30];
toCString(e.index, tmp, 30);
copyString(full_path, length, m_engine.getBasePath());
catCString(full_path, length, "\\scripts\\e");
catCString(full_path, length, tmp);
catCString(full_path, length, ".");
catCString(full_path, length, ext);
copyString(path, length, "scripts\\e");
catCString(path, length, tmp);
catCString(path, length, ".");
catCString(path, length, ext);
}
void stopScript(int index)
{
int entity_idx = m_script_entities[index];
for (int i = 0; i < m_running_scripts.size(); ++i)
{
if (m_running_scripts[i].m_entity_idx == entity_idx)
{
DestroyScriptFunction f = (DestroyScriptFunction)GetProcAddress(m_running_scripts[i].m_lib, "destroyScript");
f(m_running_scripts[i].m_script_object);
BOOL b = FreeLibrary(m_running_scripts[i].m_lib);
ASSERT(b == TRUE);
m_running_scripts.eraseFast(i);
return;
}
}
}
bool runScript(int i, Entity entity)
{
char path[LUMIX_MAX_PATH];
char full_path[LUMIX_MAX_PATH];
getDll(m_paths[i].c_str(), path, full_path, LUMIX_MAX_PATH);
HMODULE h = LoadLibrary(full_path);
if (h)
{
CreateScriptFunction f = (CreateScriptFunction)GetProcAddress(h, TEXT("createScript"));
BaseScript* script = f();
if (!f)
{
g_log_warning.log("script") << "failed to create script " << m_paths[i].c_str();
FreeLibrary(h);
}
else
{
RunningScript running_script;
running_script.m_script_object = script;
running_script.m_entity_idx = entity.index;
running_script.m_lib = h;
m_running_scripts.push(running_script);
script->create(*this, entity);
return true;
}
}
return false;
}
Component createScript(Entity entity)
{
char path[LUMIX_MAX_PATH];
char full_path[LUMIX_MAX_PATH];
getScriptDefaultPath(entity, path, full_path, LUMIX_MAX_PATH, "cpp");
m_script_entities.push(entity.index);
m_paths.push(string(path));
Component cmp = m_universe.addComponent(entity, SCRIPT_HASH, this, m_script_entities.size() - 1);
m_universe.componentCreated().invoke(cmp);
runScript(m_paths.size() - 1, entity);
return cmp;
}
void runAll()
{
char path[MAX_PATH];
char full_path[MAX_PATH];
for (int i = 0; i < m_script_entities.size(); ++i)
{
if(m_script_entities[i] != -1)
{
Entity e(&m_universe, m_script_entities[i]);
getDll(m_paths[i].c_str(), path, full_path, MAX_PATH);
HMODULE h = LoadLibrary(full_path);
if (h)
{
CreateScriptFunction f = (CreateScriptFunction)GetProcAddress(h, TEXT("createScript"));
BaseScript* script = f();
if (!f)
{
g_log_warning.log("script") << "failed to create script " << m_paths[i].c_str();
FreeLibrary(h);
}
else
{
RunningScript running_script;
running_script.m_entity_idx = e.index;
running_script.m_lib = h;
running_script.m_script_object = script;
m_running_scripts.push(running_script);
script->create(*this, e);
}
}
else
{
g_log_warning.log("script") << "failed to load script " << m_paths[i].c_str();
}
}
}
}
void stopAll()
{
for (int i = 0; i < m_running_scripts.size(); ++i)
{
DestroyScriptFunction f = (DestroyScriptFunction)GetProcAddress(m_running_scripts[i].m_lib, "destroyScript");
f(m_running_scripts[i].m_script_object);
BOOL b = FreeLibrary(m_running_scripts[i].m_lib);
ASSERT(b == TRUE);
}
m_running_scripts.clear();
}
void serialize(ISerializer& serializer) override
{
serializer.serialize("count", m_script_entities.size());
serializer.beginArray("scripts");
for (int i = 0; i < m_script_entities.size(); ++i)
{
serializer.serializeArrayItem(m_script_entities[i]);
serializer.serializeArrayItem(m_paths[i]);
}
serializer.endArray();
}
virtual Component createComponent(uint32_t type, const Entity& entity)
{
if (type == SCRIPT_HASH)
{
return createScript(entity);
}
return Component::INVALID;
}
virtual void destroyComponent(const Component& cmp)
{
m_script_entities[cmp.index] = -1;
m_universe.destroyComponent(cmp);
m_universe.componentDestroyed().invoke(cmp);
}
struct RunningScript
{
BaseScript* m_script_object;
HMODULE m_lib;
int m_entity_idx;
};
Array<RunningScript> m_running_scripts;
Array<int> m_script_entities;
Array<string> m_paths;
Universe& m_universe;
Engine& m_engine;
ScriptSystem& m_system;
};
struct ScriptSystemImpl : public ScriptSystem
{
struct RunningScript
{
BaseScript* m_script_object;
HMODULE m_lib;
int m_entity_idx;
};
Array<RunningScript> m_running_scripts;
Array<int> m_script_entities;
Array<string> m_paths;
Universe* m_universe;
Engine* m_engine;
ScriptSystemImpl()
{
}
Universe* getUniverse() const override
{
return m_universe;
}
Engine* getEngine() const override
{
return m_engine;
}
void runAll()
virtual IScene* createScene(Universe& universe)
{
char path[MAX_PATH];
char full_path[MAX_PATH];
for(int i = 0; i < m_script_entities.size(); ++i)
{
Entity e(m_universe, m_script_entities[i]);
getDll(m_paths[i].c_str(), path, full_path, MAX_PATH);
HMODULE h = LoadLibrary(full_path);
if(h)
{
CreateScriptFunction f = (CreateScriptFunction)GetProcAddress(h, TEXT("createScript"));
BaseScript* script = f();
if(!f)
{
g_log_warning.log("script") << "failed to create script " << m_paths[i].c_str();
FreeLibrary(h);
}
else
{
RunningScript running_script;
running_script.m_entity_idx = e.index;
running_script.m_lib = h;
running_script.m_script_object = script;
m_running_scripts.push(running_script);
script->create(*this, e);
}
}
else
{
g_log_warning.log("script") << "failed to load script " << m_paths[i].c_str();
}
}
}
void deserialize(ISerializer& serializer) override
{
stopAll();
int count;
serializer.deserialize("count", count);
serializer.deserializeArrayBegin("scripts");
m_script_entities.resize(count);
m_paths.resize(count);
for (int i = 0; i < m_script_entities.size(); ++i)
{
serializer.deserializeArrayItem(m_script_entities[i]);
serializer.deserializeArrayItem(m_paths[i]);
Entity entity(m_universe, m_script_entities[i]);
m_universe->addComponent(entity, SCRIPT_HASH, this, i);
}
serializer.deserializeArrayEnd();
runAll();
}
void serialize(ISerializer& serializer) override
{
serializer.serialize("count", m_script_entities.size());
serializer.beginArray("scripts");
for (int i = 0; i < m_script_entities.size(); ++i)
{
serializer.serializeArrayItem(m_script_entities[i]);
serializer.serializeArrayItem(m_paths[i]);
}
serializer.endArray();
}
void stopAll()
{
for(int i = 0; i < m_running_scripts.size(); ++i)
{
DestroyScriptFunction f = (DestroyScriptFunction)GetProcAddress(m_running_scripts[i].m_lib, "destroyScript");
f(m_running_scripts[i].m_script_object);
BOOL b = FreeLibrary(m_running_scripts[i].m_lib);
ASSERT(b == TRUE);
}
m_running_scripts.clear();
}
void update(float dt) override
{
for(int i = 0; i < m_running_scripts.size(); ++i)
{
m_running_scripts[i].m_script_object->update(dt);
}
}
void getScriptPath(Component cmp, string& str) override
{
str = m_paths[cmp.index];
}
void setScriptPath(Component cmp, const string& str) override
{
m_paths[cmp.index] = str;
stopScript(cmp.index);
if (!runScript(cmp.index, cmp.entity))
{
g_log_warning.log("script") << "Could not run script " << str;
}
}
void getDll(const char* script_path, char* dll_path, char* full_path, int max_length)
{
copyString(dll_path, max_length, script_path);
int32_t len = (int32_t)strlen(script_path);
if(len > 4)
{
copyString(dll_path + len - 4, 5, ".dll");
}
copyString(full_path, max_length, m_engine->getBasePath());
catCString(full_path, max_length, "\\");
catCString(full_path, max_length, dll_path);
}
void getScriptDefaultPath(Entity e, char* path, char* full_path, int length, const char* ext)
{
char tmp[30];
toCString(e.index, tmp, 30);
copyString(full_path, length, m_engine->getBasePath());
catCString(full_path, length, "\\scripts\\e");
catCString(full_path, length, tmp);
catCString(full_path, length, ".");
catCString(full_path, length, ext);
copyString(path, length, "scripts\\e");
catCString(path, length, tmp);
catCString(path, length, ".");
catCString(path, length, ext);
}
void stopScript(int index)
{
int entity_idx = m_script_entities[index];
for (int i = 0; i < m_running_scripts.size(); ++i)
{
if (m_running_scripts[i].m_entity_idx == entity_idx)
{
DestroyScriptFunction f = (DestroyScriptFunction)GetProcAddress(m_running_scripts[i].m_lib, "destroyScript");
f(m_running_scripts[i].m_script_object);
BOOL b = FreeLibrary(m_running_scripts[i].m_lib);
ASSERT(b == TRUE);
m_running_scripts.eraseFast(i);
return;
}
}
}
bool runScript(int i, Entity entity)
{
char path[LUMIX_MAX_PATH];
char full_path[LUMIX_MAX_PATH];
getDll(m_paths[i].c_str(), path, full_path, LUMIX_MAX_PATH);
HMODULE h = LoadLibrary(full_path);
if (h)
{
CreateScriptFunction f = (CreateScriptFunction)GetProcAddress(h, TEXT("createScript"));
BaseScript* script = f();
if (!f)
{
g_log_warning.log("script") << "failed to create script " << m_paths[i].c_str();
FreeLibrary(h);
}
else
{
RunningScript running_script;
running_script.m_script_object = script;
running_script.m_entity_idx = entity.index;
running_script.m_lib = h;
m_running_scripts.push(running_script);
script->create(*this, entity);
return true;
}
}
return false;
}
Component createScript(Entity entity) override
{
char path[LUMIX_MAX_PATH];
char full_path[LUMIX_MAX_PATH];
getScriptDefaultPath(entity, path, full_path, LUMIX_MAX_PATH, "cpp");
m_script_entities.push(entity.index);
m_paths.push(string(path));
Component cmp = m_universe->addComponent(entity, SCRIPT_HASH, this, m_script_entities.size() - 1);
m_universe->componentCreated().invoke(cmp);
runScript(m_paths.size() - 1, entity);
return cmp;
return LUMIX_NEW(ScriptSceneImpl)(*this, *m_engine, universe);
}
virtual bool create(Engine& engine) override
{
m_engine = &engine;
engine.getWorldEditor()->registerProperty("script", LUMIX_NEW(PropertyDescriptor<ScriptSystem>)(crc32("source"), &ScriptSystem::getScriptPath, &ScriptSystem::setScriptPath, IPropertyDescriptor::FILE));
engine.getWorldEditor()->registerCreator(SCRIPT_HASH, *this);
engine.getWorldEditor()->registerProperty("script", LUMIX_NEW(FilePropertyDescriptor<ScriptSceneImpl>)("source", &ScriptSceneImpl::getScriptPath, &ScriptSceneImpl::setScriptPath, "Script (*.cpp)"));
return true;
}
virtual void destroy() override
{
stopAll();
}
virtual void destroyComponent(const Component&) override
{
ASSERT(false);
}
virtual Component createComponent(uint32_t type, const Entity& entity) override
{
if (type == SCRIPT_HASH)
{
return createScript(entity);
}
return Component::INVALID;
}
@ -297,18 +329,6 @@ namespace Lumix
}
virtual void onCreateUniverse(Universe& universe) override
{
m_universe = &universe;
}
virtual void onDestroyUniverse(Universe& universe) override
{
m_universe = NULL;
}
}; // ScriptSystemImpl

View file

@ -14,23 +14,21 @@ namespace Lumix
class Engine;
class InputSystem;
class Navigation;
class Renderer;
class LUMIX_SCRIPT_API ScriptScene : public IScene
{
public:
virtual void getScriptPath(Component cmp, string& str) = 0;
virtual void setScriptPath(Component cmp, const string& str) = 0;
};
class LUMIX_SCRIPT_API ScriptSystem : public IPlugin
{
public:
virtual void update(float time_delta) = 0;
virtual Universe* getUniverse() const = 0;
virtual Component createScript(Entity entity) = 0;
virtual Engine* getEngine() const = 0;
virtual void deserialize(ISerializer& serializer) = 0;
virtual void serialize(ISerializer& serializer) = 0;
virtual void getScriptPath(Component cmp, string& str) = 0;
virtual void setScriptPath(Component cmp, const string& str) = 0;
protected:
ScriptSystem() {}
virtual ~ScriptSystem() {}

View file

@ -8,6 +8,7 @@
namespace Lumix
{
struct Entity;
class IScene;
struct LUMIX_ENGINE_API Component final
@ -16,23 +17,23 @@ namespace Lumix
typedef uint32_t Type;
Component() { index = -1; }
Component(const Entity& _entity, uint32_t _type, void* _system, int _index)
Component(const Entity& _entity, uint32_t _type, IScene* _scene, int _index)
: entity(_entity)
, type(_type)
, system(_system)
, scene(_scene)
, index(_index)
{
}
Entity entity;
Type type;
void* system;
IScene* scene;
int index;
static const Component INVALID;
bool operator ==(const Component& rhs) const { return type == rhs.type && system == rhs.system && index == rhs.index; }
bool operator !=(const Component& rhs) const { return type != rhs.type || system != rhs.system || index != rhs.index; }
bool operator ==(const Component& rhs) const { return type == rhs.type && scene == rhs.scene && index == rhs.index; }
bool operator !=(const Component& rhs) const { return type != rhs.type || scene != rhs.scene || index != rhs.index; }
bool isValid() const { return index >= 0; }
};

View file

@ -1,4 +1,5 @@
#include "universe/entity.h"
#include "core/crc32.h"
#include "universe/universe.h"
namespace Lumix
@ -86,14 +87,14 @@ namespace Lumix
}
void Entity::setPosition(float x, float y, float z)
void Entity::setPosition(float x, float y, float z) const
{
universe->m_positions[index].set(x, y, z);
universe->entityMoved().invoke(*this);
}
void Entity::setPosition(const Vec3& pos)
void Entity::setPosition(const Vec3& pos) const
{
universe->m_positions[index] = pos;
universe->entityMoved().invoke(*this);
@ -112,19 +113,42 @@ namespace Lumix
}
void Entity::setRotation(float x, float y, float z, float w)
void Entity::setRotation(float x, float y, float z, float w) const
{
universe->m_rotations[index].set(x, y, z, w);
universe->entityMoved().invoke(*this);
}
void Entity::setRotation(const Quat& rot)
void Entity::setRotation(const Quat& rot) const
{
universe->m_rotations[index] = rot;
universe->entityMoved().invoke(*this);
}
const char* Entity::getName() const
{
auto iter = universe->m_id_to_name_map.find(index);
return iter == universe->m_id_to_name_map.end() ? "" : iter.value().c_str();
}
void Entity::setName(const char* name)
{
auto iter = universe->m_id_to_name_map.find(index);
if (iter != universe->m_id_to_name_map.end())
{
universe->m_name_to_id_map.erase(crc32(iter.value().c_str()));
universe->m_id_to_name_map.erase(iter);
}
if (name && name[0] != '\0')
{
universe->m_name_to_id_map.insert(crc32(name), index);
universe->m_id_to_name_map.insert(index, string(name));
}
}
} // ~namespace Lumix

View file

@ -22,17 +22,19 @@ namespace Lumix
void getMatrix(Matrix& mtx) const;
void setMatrix(const Vec3& pos, const Quat& rot);
void setMatrix(const Matrix& mtx);
void setPosition(float x, float y, float z);
void setPosition(const Vec3& v);
void setPosition(float x, float y, float z) const;
void setPosition(const Vec3& v) const;
const Vec3& getPosition() const;
const Quat& getRotation() const;
void setRotation(float x, float y, float z, float w);
void setRotation(const Quat& rot);
void setRotation(float x, float y, float z, float w) const;
void setRotation(const Quat& rot) const;
void translate(const Vec3& t);
bool isValid() const { return index >= 0; }
const Component& getComponent(uint32_t type) const;
const ComponentList& getComponents() const;
bool existsInUniverse() const;
const char* getName() const;
void setName(const char* name);
bool operator ==(const Entity& rhs) const;

View file

@ -1,4 +1,5 @@
#include "universe.h"
#include "core/crc32.h"
#include "core/matrix.h"
#include "core/json_serializer.h"
@ -6,31 +7,21 @@
namespace Lumix
{
static const int RESERVED_ENTITIES = 5000;
Universe::~Universe()
{
}
void Universe::destroy()
{
m_free_slots.clear();
m_positions.clear();
m_rotations.clear();
m_component_list.clear();
}
void Universe::create()
{
m_positions.reserve(1000);
m_rotations.reserve(1000);
m_component_list.reserve(1000);
}
Universe::Universe()
{
m_positions.reserve(RESERVED_ENTITIES);
m_rotations.reserve(RESERVED_ENTITIES);
m_component_list.reserve(RESERVED_ENTITIES);
}
@ -69,6 +60,50 @@ void Universe::destroyEntity(Entity& entity)
}
Entity Universe::getFirstEntity()
{
for(int i = 0; i < m_positions.size(); ++i)
{
bool found = false;
for(int j = 0, cj = m_free_slots.size(); j < cj; ++j)
{
if(m_free_slots[j] == i)
{
found = true;
break;
}
}
if(!found)
{
return Entity(this, i);
}
}
return Entity::INVALID;
}
Entity Universe::getNextEntity(Entity entity)
{
for(int i = entity.index + 1; i < m_positions.size(); ++i)
{
bool found = false;
for(int j = 0, cj = m_free_slots.size(); j < cj; ++j)
{
if(m_free_slots[j] == i)
{
found = true;
break;
}
}
if(!found)
{
return Entity(this, i);
}
}
return Entity::INVALID;
}
void Universe::serialize(ISerializer& serializer)
{
serializer.serialize("count", m_positions.size());
@ -89,6 +124,16 @@ void Universe::serialize(ISerializer& serializer)
serializer.serializeArrayItem(m_rotations[i].w);
}
serializer.endArray();
serializer.serialize("name_count", m_id_to_name_map.size());
serializer.beginArray("names");
for (auto iter = m_id_to_name_map.begin(), end = m_id_to_name_map.end(); iter != end; ++iter)
{
serializer.serializeArrayItem(iter.key());
serializer.serializeArrayItem(iter.value().c_str());
}
serializer.endArray();
serializer.serialize("free_slot_count", m_free_slots.size());
serializer.beginArray("free_slots");
for(int i = 0; i < m_free_slots.size(); ++i)
@ -127,6 +172,22 @@ void Universe::deserialize(ISerializer& serializer)
}
serializer.deserializeArrayEnd();
serializer.deserialize("name_count", count);
serializer.deserializeArrayBegin("names");
m_id_to_name_map.clear();
m_name_to_id_map.clear();
for (int i = 0; i < count; ++i)
{
uint32_t key;
static const int MAX_NAME_LENGTH = 50;
char name[MAX_NAME_LENGTH];
serializer.deserializeArrayItem(key);
serializer.deserializeArrayItem(name, MAX_NAME_LENGTH);
m_id_to_name_map.insert(key, string(name));
m_name_to_id_map.insert(crc32(name), key);
}
serializer.deserializeArrayEnd();
serializer.deserialize("free_slot_count", count);
m_free_slots.resize(count);
serializer.deserializeArrayBegin("free_slots");
@ -138,7 +199,7 @@ void Universe::deserialize(ISerializer& serializer)
}
void Universe::removeComponent(const Component& cmp)
void Universe::destroyComponent(const Component& cmp)
{
Entity::ComponentList& cmps = m_component_list[cmp.entity.index];
for (int i = 0, c = cmps.size(); i < c; ++i)
@ -152,12 +213,25 @@ void Universe::removeComponent(const Component& cmp)
}
Component Universe::addComponent(const Entity& entity, uint32_t component_type, void* system, int index)
Component Universe::addComponent(const Entity& entity, uint32_t component_type, IScene* scene, int index)
{
Component cmp(entity, component_type, system, index);
Component cmp(entity, component_type, scene, index);
m_component_list[entity.index].push(cmp);
return cmp;
}
bool Universe::nameExists(const char* name) const
{
for (auto iter = m_id_to_name_map.begin(), end = m_id_to_name_map.end(); iter != end; ++iter)
{
if (iter.value() == name)
{
return true;
}
}
return false;
}
} // !namespace Lumix

View file

@ -4,7 +4,9 @@
#include "core/lumix.h"
#include "core/array.h"
#include "core/delegate_list.h"
#include "core/map.h"
#include "core/quat.h"
#include "core/string.h"
#include "core/vec3.h"
#include "universe/component.h"
#include "universe/entity.h"
@ -32,38 +34,37 @@ class LUMIX_ENGINE_API Universe final
Universe();
~Universe();
void create();
void destroy();
Entity createEntity();
void destroyEntity(Entity& entity);
Vec3 getPosition(int index) { return m_positions[index]; }
Quat getRotation(int index) { return m_rotations[index]; }
Component addComponent(const Entity& entity, uint32_t component_type, void* system, int index);
void removeComponent(const Component& cmp);
int getEntityCount() const { return m_positions.size(); }
Component addComponent(const Entity& entity, uint32_t component_type, IScene* scene, int index);
void destroyComponent(const Component& cmp);
int getEntityCount() const { return m_positions.size() - m_free_slots.size(); }
Entity getFirstEntity();
Entity getNextEntity(Entity entity);
bool nameExists(const char* name) const;
DelegateList<void(Entity&)>& entityMoved() { return m_entity_moved; }
DelegateList<void(Entity&)>& entityCreated() { return m_entity_created; }
DelegateList<void(Entity&)>& entityDestroyed() { return m_entity_destroyed; }
DelegateList<void(Component&)>& componentCreated() { return m_component_created; }
DelegateList<void(const Entity&)>& entityMoved() { return m_entity_moved; }
DelegateList<void(const Entity&)>& entityCreated() { return m_entity_created; }
DelegateList<void(const Entity&)>& entityDestroyed() { return m_entity_destroyed; }
DelegateList<void(const Component&)>& componentCreated() { return m_component_created; }
DelegateList<void(const Component&)>& componentDestroyed() { return m_component_destroyed; }
void serialize(ISerializer& serializer);
void deserialize(ISerializer& serializer);
private:
void onEvent(Event& event);
private:
Array<Vec3> m_positions; //< entity positions
Array<Quat> m_rotations; //< entity rotations
Array<Vec3> m_positions;
Array<Quat> m_rotations;
Array<int> m_free_slots;
Map<uint32_t, uint32_t> m_name_to_id_map;
Map<uint32_t, string> m_id_to_name_map;
ComponentList m_component_list;
DelegateList<void(Entity&)> m_entity_moved;
DelegateList<void(Entity&)> m_entity_created;
DelegateList<void(Entity&)> m_entity_destroyed;
DelegateList<void(Component&)> m_component_created;
DelegateList<void(const Entity&)> m_entity_moved;
DelegateList<void(const Entity&)> m_entity_created;
DelegateList<void(const Entity&)> m_entity_destroyed;
DelegateList<void(const Component&)> m_component_created;
DelegateList<void(const Component&)> m_component_destroyed;
};