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

Conflicts:
	projects/vs2013/LumixEngine.sln
	projects/vs2013/engine/engine.vcxproj.filters
	src/engine/engine.h
	src/graphics/render_scene.cpp
This commit is contained in:
tluqo 2014-08-20 21:15:13 +02:00
commit 56161eee27
99 changed files with 5505 additions and 3658 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 KiB

After

Width:  |  Height:  |  Size: 1 MiB

View file

@ -29,8 +29,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "script", "script\script.vcx
{A0A17BB4-760B-4E34-B1B0-3E43E5F2778A} = {A0A17BB4-760B-4E34-B1B0-3E43E5F2778A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtEditor", "..\..\qteditor\QtEditor\QtEditor.vcxproj", "{9776D012-8010-39DD-9E1F-2C1A1DB433C3}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtEditor", "..\..\qteditor\QtEditor\QtEditor.vcxproj", "{D04C721A-BACC-3CE7-B285-D5A7D567F8BA}"
ProjectSection(ProjectDependencies) = postProject
{E56A8C15-C73D-43E4-8D7C-04BBFC062ACC} = {E56A8C15-C73D-43E4-8D7C-04BBFC062ACC}
{E1A0C677-DE71-4AD8-B802-AA7A3332D822} = {E1A0C677-DE71-4AD8-B802-AA7A3332D822}
{4D15098E-177F-44EE-BF3C-FF0298E1BA33} = {4D15098E-177F-44EE-BF3C-FF0298E1BA33}
{A0A17BB4-760B-4E34-B1B0-3E43E5F2778A} = {A0A17BB4-760B-4E34-B1B0-3E43E5F2778A}
@ -64,6 +65,7 @@ Global
{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}.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
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Debug|Win32.ActiveCfg = Debug|Win32
{B9B67659-001C-4E9A-823D-49C7EF3F49C2}.Debug|Win32.Build.0 = Debug|Win32
@ -77,12 +79,12 @@ Global
{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
{9776D012-8010-39DD-9E1F-2C1A1DB433C3}.Debug|Win32.ActiveCfg = Debug|Win32
{9776D012-8010-39DD-9E1F-2C1A1DB433C3}.Debug|Win32.Build.0 = Debug|Win32
{9776D012-8010-39DD-9E1F-2C1A1DB433C3}.Debug|x64.ActiveCfg = Debug|Win32
{9776D012-8010-39DD-9E1F-2C1A1DB433C3}.Release|Win32.ActiveCfg = Release|Win32
{9776D012-8010-39DD-9E1F-2C1A1DB433C3}.Release|Win32.Build.0 = Release|Win32
{9776D012-8010-39DD-9E1F-2C1A1DB433C3}.Release|x64.ActiveCfg = Release|Win32
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

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)'=='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|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|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>
@ -122,7 +122,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>
</SDLCheck>
<PreprocessorDefinitions>MEM_TRACK;BUILDING_CORE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>NDEBUG;MEM_TRACK;BUILDING_CORE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>..\..\..\src;</AdditionalIncludeDirectories>
</ClCompile>

View file

@ -66,23 +66,23 @@
</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>
<TargetExt>.dll</TargetExt>
</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>
<TargetExt>.dll</TargetExt>
</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>
<TargetExt>.dll</TargetExt>
</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>
<TargetExt>.dll</TargetExt>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@ -130,7 +130,7 @@
</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\external\physx\include;..\..\..\src;..\..\..\external\glew\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>WIN32;BUILDING_ENGINE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>NDEBUG;WIN32;BUILDING_ENGINE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -164,11 +164,10 @@
<ClCompile Include="..\..\..\src\animation\animation.cpp" />
<ClCompile Include="..\..\..\src\animation\animation_system.cpp" />
<ClCompile Include="..\..\..\src\core\new.cpp" />
<ClCompile Include="..\..\..\src\editor\editor_client.cpp" />
<ClCompile Include="..\..\..\src\editor\editor_icon.cpp" />
<ClCompile Include="..\..\..\src\editor\editor_server.cpp" />
<ClCompile Include="..\..\..\src\editor\entity_template_system.cpp" />
<ClCompile Include="..\..\..\src\editor\world_editor.cpp" />
<ClCompile Include="..\..\..\src\editor\gizmo.cpp" />
<ClCompile Include="..\..\..\src\editor\server_message_types.cpp" />
<ClCompile Include="..\..\..\src\engine\engine.cpp" />
<ClCompile Include="..\..\..\src\engine\iplugin.cpp" />
<ClCompile Include="..\..\..\src\engine\plugin_manager.cpp" />
@ -196,13 +195,12 @@
<ItemGroup>
<ClInclude Include="..\..\..\src\animation\animation.h" />
<ClInclude Include="..\..\..\src\animation\animation_system.h" />
<ClInclude Include="..\..\..\src\editor\client_message_types.h" />
<ClInclude Include="..\..\..\src\editor\editor_client.h" />
<ClInclude Include="..\..\..\src\editor\ieditor_command.h" />
<ClInclude Include="..\..\..\src\editor\editor_icon.h" />
<ClInclude Include="..\..\..\src\editor\editor_server.h" />
<ClInclude Include="..\..\..\src\editor\entity_template_system.h" />
<ClInclude Include="..\..\..\src\editor\world_editor.h" />
<ClInclude Include="..\..\..\src\editor\gizmo.h" />
<ClInclude Include="..\..\..\src\editor\property_descriptor.h" />
<ClInclude Include="..\..\..\src\editor\server_message_types.h" />
<ClInclude Include="..\..\..\src\engine\engine.h" />
<ClInclude Include="..\..\..\src\engine\iplugin.h" />
<ClInclude Include="..\..\..\src\engine\plugin_manager.h" />

View file

@ -63,21 +63,12 @@
<ClCompile Include="..\..\..\src\engine\plugin_manager.cpp">
<Filter>engine</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\editor\editor_client.cpp">
<Filter>editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\editor\editor_icon.cpp">
<Filter>editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\editor\editor_server.cpp">
<Filter>editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\editor\gizmo.cpp">
<Filter>editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\editor\server_message_types.cpp">
<Filter>editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\universe\component.cpp">
<Filter>universe</Filter>
</ClCompile>
@ -106,6 +97,12 @@
<ClCompile Include="..\..\..\src\graphics\terrain.cpp">
<Filter>graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\editor\world_editor.cpp">
<Filter>editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\editor\entity_template_system.cpp">
<Filter>editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\graphics\culling_system.cpp">
<Filter>graphics</Filter>
</ClCompile>
@ -165,27 +162,15 @@
<ClInclude Include="..\..\..\src\engine\plugin_manager.h">
<Filter>engine</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\client_message_types.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\editor_client.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\editor_icon.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\editor_server.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\gizmo.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\property_descriptor.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\server_message_types.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\universe\component.h">
<Filter>universe</Filter>
</ClInclude>
@ -216,5 +201,14 @@
<ClInclude Include="..\..\..\src\graphics\terrain.h">
<Filter>graphics</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\world_editor.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\entity_template_system.h">
<Filter>editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\editor\ieditor_command.h">
<Filter>editor</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -117,7 +117,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src</AdditionalIncludeDirectories>
<PreprocessorDefinitions>BUILDING_SCRIPT;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>NDEBUG;BUILDING_SCRIPT;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -27,7 +27,8 @@ SOURCES += main.cpp\
materialmanager.cpp \
profilerui.cpp \
profilergraph.cpp \
pc/file_system_watcher.cpp
pc/file_system_watcher.cpp \
entity_template_list.cpp
HEADERS += mainwindow.h \
sceneview.h \
@ -43,7 +44,8 @@ HEADERS += mainwindow.h \
renderdevicewidget.h \
profilerui.h \
profilergraph.h \
file_system_watcher.h
file_system_watcher.h \
entity_template_list.h
FORMS += mainwindow.ui \
logwidget.ui \
@ -54,7 +56,8 @@ FORMS += mainwindow.ui \
fileserverwidget.ui \
materialmanager.ui \
profilerui.ui \
profilergraph.ui
profilergraph.ui \
entity_template_list.ui
win32
{

View file

@ -4,8 +4,7 @@
#include "core/crc32.h"
#include "core/resource.h"
#include "core/resource_manager.h"
#include "editor/editor_client.h"
#include "editor/editor_server.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include <qfilesystemmodel.h>
#include <qlistwidget.h>
@ -33,7 +32,6 @@ 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_client = NULL;
m_server = NULL;
m_ui->setupUi(this);
m_model = new QFileSystemModel;
@ -73,35 +71,22 @@ void AssetBrowser::emitFileChanged(const char* path)
void AssetBrowser::handleDoubleClick(const QFileInfo& file_info)
{
ASSERT(m_client);
const QString& suffix = file_info.suffix();
QString file =file_info.filePath().toLower();
if(suffix == "unv")
{
m_client->loadUniverse(file.toLatin1().data());
m_server->loadUniverse(file.toLatin1().data());
}
else if(suffix == "msh")
{
m_client->addEntity();
m_client->addComponent(crc32("renderable"));
QString base_path = m_client->getBasePath();
if(file.startsWith(base_path))
{
file.remove(0, base_path.length());
}
m_client->setComponentProperty("renderable", "source", file.toLatin1().data(), file.length());
m_client->requestProperties(crc32("renderable"));
m_server->addEntity();
m_server->addComponent(crc32("renderable"));
m_server->setProperty("renderable", "source", file.toLatin1().data(), file.length());
}
else if(suffix == "ani")
{
m_client->addComponent(crc32("animable"));
QString base_path = m_client->getBasePath();
if(file.startsWith(base_path))
{
file.remove(0, base_path.length());
}
m_client->setComponentProperty("animable", "preview", file.toLatin1().data(), file.length());
m_client->requestProperties(crc32("animable"));
m_server->addComponent(crc32("animable"));
m_server->setProperty("animable", "preview", file.toLatin1().data(), file.length());
}
}

View file

@ -4,8 +4,7 @@
namespace Lumix
{
class EditorClient;
class EditorServer;
class WorldEditor;
}
namespace Ui
@ -20,8 +19,7 @@ class AssetBrowser : public QDockWidget
public:
explicit AssetBrowser(QWidget* parent = NULL);
~AssetBrowser();
void setEditorClient(Lumix::EditorClient& client) { m_client = &client; }
void setEditorServer(Lumix::EditorServer& server) { m_server = &server; }
void setWorldEditor(Lumix::WorldEditor& server) { m_server = &server; }
void emitFileChanged(const char* path);
private:
@ -46,7 +44,6 @@ private slots:
Ui::AssetBrowser* m_ui;
class QFileSystemModel* m_model;
class FileSystemWatcher* m_watcher;
Lumix::EditorClient* m_client;
Lumix::EditorServer* m_server;
Lumix::WorldEditor* m_server;
QString m_base_path;
};

View file

@ -0,0 +1,56 @@
#include "entity_template_list.h"
#include "ui_entity_template_list.h"
#include "editor/entity_template_system.h"
#include "editor/world_editor.h"
EntityTemplateList::EntityTemplateList()
: QDockWidget(NULL)
, m_ui(new Ui::EntityTemplateList)
{
m_ui->setupUi(this);
m_editor = NULL;
}
EntityTemplateList::~EntityTemplateList()
{
if (m_editor)
{
m_editor->getEntityTemplateSystem().updated().unbind<EntityTemplateList, &EntityTemplateList::onSystemUpdated>(this);
}
delete m_ui;
}
void EntityTemplateList::setWorldEditor(Lumix::WorldEditor& editor)
{
m_editor = &editor;
m_editor->getEntityTemplateSystem().updated().bind<EntityTemplateList, &EntityTemplateList::onSystemUpdated>(this);
onSystemUpdated();
}
void EntityTemplateList::onSystemUpdated()
{
Lumix::Array<Lumix::string>& template_names = m_editor->getEntityTemplateSystem().getTemplateNames();
m_ui->templateList->clear();
for (int i = 0, c = template_names.size(); i < c; ++i)
{
m_ui->templateList->insertItem(i, template_names[i].c_str());
}
}
void EntityTemplateList::on_templateList_doubleClicked(const QModelIndex &index)
{
m_editor->getEntityTemplateSystem().createInstance(m_ui->templateList->item(index.row())->text().toLatin1().data());
}
void EntityTemplateList::instantiateTemplate()
{
if (m_ui->templateList->currentIndex().row() >= 0)
{
m_editor->getEntityTemplateSystem().createInstance(m_ui->templateList->item(m_ui->templateList->currentIndex().row())->text().toLatin1().data());
}
}

View file

@ -0,0 +1,36 @@
#pragma once
#include <QDockWidget>
namespace Ui
{
class EntityTemplateList;
}
namespace Lumix
{
class WorldEditor;
}
class EntityTemplateList : public QDockWidget
{
Q_OBJECT
public:
explicit EntityTemplateList();
~EntityTemplateList();
void setWorldEditor(Lumix::WorldEditor& editor);
void instantiateTemplate();
private:
void onSystemUpdated();
private slots:
void on_templateList_doubleClicked(const QModelIndex& index);
private:
Ui::EntityTemplateList* m_ui;
Lumix::WorldEditor* m_editor;
};

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EntityTemplateList</class>
<widget class="QDockWidget" name="EntityTemplateList">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Entity templates</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="QListWidget" name="templateList"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -5,7 +5,7 @@
#include "core/fs/file_system.h"
#include "core/fs/tcp_file_server.h"
#include "core/fs/file_events_device.h"
#include "editor/editor_server.h"
#include "editor/world_editor.h"
namespace
{
@ -120,14 +120,14 @@ void FileServerWidget::emitFileEvent(const Lumix::FS::Event& event, qint64 time)
}
void FileServerWidget::setEditorServer(Lumix::EditorServer& server)
void FileServerWidget::setWorldEditor(Lumix::WorldEditor& server)
{
m_server = &server;
Lumix::FS::FileEventsDevice& dev = m_watcher->getFileEventDevice();
Lumix::FS::FileSystem& fs = m_server->getEngine().getFileSystem();
fs.mount(&dev);
fs.setDefaultDevice("memory:events:tcp");
fs.setDefaultDevice("memory:events:disk");
}

View file

@ -6,7 +6,7 @@
namespace Lumix
{
class EditorServer;
class WorldEditor;
}
namespace Ui
@ -22,7 +22,7 @@ public:
explicit FileServerWidget(QWidget* parent = NULL);
~FileServerWidget();
void setEditorServer(Lumix::EditorServer& server);
void setWorldEditor(Lumix::WorldEditor& server);
void fsEventCb(const Lumix::FS::Event& event, int32_t param);
void emitFileEvent(const Lumix::FS::Event& event, qint64 time);
@ -44,7 +44,7 @@ private:
void filterTable();
Ui::FileServerWidget* m_ui;
Lumix::EditorServer* m_server;
Lumix::WorldEditor* m_server;
class FileServerWatcher* m_watcher;
};

View file

@ -1,7 +1,7 @@
#include "gameview.h"
#include "ui_gameview.h"
#include <QMouseEvent>
#include "editor/editor_client.h"
#include "editor/world_editor.h"
#include "graphics/pipeline.h"
GameView::GameView(QWidget* parent) :
@ -10,7 +10,6 @@ GameView::GameView(QWidget* parent) :
{
m_ui->setupUi(this);
m_pipeline = NULL;
m_client = NULL;
}
GameView::~GameView()
@ -38,6 +37,6 @@ void GameView::resizeEvent(QResizeEvent* event)
void GameView::on_playButton_clicked()
{
m_client->toggleGameMode();
m_server->toggleGameMode();
}

View file

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

View file

@ -5,11 +5,11 @@
#include "core/profiler.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "editor/editor_client.h"
#include "editor/editor_server.h"
#include "editor/world_editor.h"
#include "editor/gizmo.h"
#include "engine/engine.h"
#include "engine/plugin_manager.h"
#include <graphics/gl_ext.h>
#include "graphics/irender_device.h"
#include "graphics/pipeline.h"
#include "graphics/renderer.h"
@ -20,6 +20,7 @@
#include "wgl_render_device.h"
#include "materialmanager.h"
class App
{
public:
@ -29,20 +30,20 @@ class App
m_edit_render_device = NULL;
m_qt_app = NULL;
m_main_window = NULL;
m_world_editor = NULL;
}
~App()
{
delete m_main_window;
delete m_qt_app;
m_client.destroy();
m_server.destroy();
Lumix::WorldEditor::destroy(m_world_editor);
}
void onUniverseCreated()
{
m_edit_render_device->getPipeline().setScene(m_server.getEngine().getRenderScene());
m_game_render_device->getPipeline().setScene(m_server.getEngine().getRenderScene());
m_edit_render_device->getPipeline().setScene(m_world_editor->getEngine().getRenderScene());
m_game_render_device->getPipeline().setScene(m_world_editor->getEngine().getRenderScene());
}
void onUniverseDestroyed()
@ -60,18 +61,20 @@ class App
HGLRC createGLContext(HWND hwnd[], int count)
{
ASSERT(count > 0);
QWidget* widget = new QWidget();
HWND gl_hwnd = (HWND)widget->winId();
HDC hdc;
hdc = GetDC(hwnd[0]);
hdc = GetDC(gl_hwnd);
ASSERT(hdc != NULL);
if (hdc == NULL)
{
Lumix::g_log_error.log("renderer") << "Could not get the device context";
return NULL;
}
PIXELFORMATDESCRIPTOR pfd =
{
BOOL success;
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
@ -90,44 +93,27 @@ class App
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
};
int pixelformat = ChoosePixelFormat(hdc, &pfd);
if (pixelformat == 0)
{
delete widget;
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not choose a pixel format";
return NULL;
}
BOOL success = SetPixelFormat(hdc, pixelformat, &pfd);
success = SetPixelFormat(hdc, pixelformat, &pfd);
if (success == FALSE)
{
delete widget;
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not set a pixel format";
return NULL;
}
for (int i = 1; i < count; ++i)
{
if (hwnd[i])
{
HDC hdc2 = GetDC(hwnd[i]);
if (hdc2 == NULL)
{
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not get the device context";
return NULL;
}
BOOL success = SetPixelFormat(hdc2, pixelformat, &pfd);
if (success == FALSE)
{
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not set a pixel format";
return NULL;
}
}
}
HGLRC hglrc = wglCreateContext(hdc);
if (hglrc == NULL)
{
delete widget;
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not create an opengl context";
return NULL;
@ -135,22 +121,91 @@ class App
success = wglMakeCurrent(hdc, hglrc);
if (success == FALSE)
{
delete widget;
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not make the opengl context current rendering context";
return NULL;
}
{
UINT numFormats;
int atrribs[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, 4,
0
};
PFNWGLCHOOSEPIXELFORMATARBPROC foo;
foo = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
if (!foo)
{
delete widget;
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not get function wglChoosePixelFormatARB";
return NULL;
}
success = foo(hdc, atrribs, NULL, 1, &pixelformat, &numFormats);
}
wglDeleteContext(hglrc);
hglrc = NULL;
delete widget;
for (int i = 0; i < count; ++i)
{
if (hwnd[i])
{
hdc = GetDC(hwnd[i]);
ChoosePixelFormat(hdc, &pfd);
if (hdc == NULL)
{
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not get the device context";
return NULL;
}
SetPixelFormat(hdc, pixelformat, &pfd);
if (!hglrc)
{
hglrc = wglCreateContext(hdc);
if (hglrc == NULL)
{
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not create an opengl context";
return NULL;
}
success = wglMakeCurrent(hdc, hglrc);
if (success == FALSE)
{
ASSERT(false);
Lumix::g_log_error.log("renderer") << "Could not make the opengl context current rendering context";
return NULL;
}
}
}
}
return hglrc;
}
void renderPhysics()
{
Lumix::PhysicsSystem* system = static_cast<Lumix::PhysicsSystem*>(m_server.getEngine().getPluginManager().getPlugin("physics"));
Lumix::PhysicsSystem* system = static_cast<Lumix::PhysicsSystem*>(m_world_editor->getEngine().getPluginManager().getPlugin("physics"));
if(system && system->getScene())
{
system->getScene()->render();
}
}
void init(int argc, char* argv[])
{
m_qt_app = new QApplication(argc, argv);
@ -163,34 +218,31 @@ 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};
HGLRC hglrc = createGLContext(hwnds, 2);
HWND hwnds[] = { hwnd, game_hwnd, (HWND)m_main_window->getMaterialManager()->getPreview()->winId() };
HGLRC hglrc = createGLContext(hwnds, 3);
bool server_created = m_server.create(QDir::currentPath().toLocal8Bit().data(), m_client);
ASSERT(server_created);
m_server.tick();
bool client_created = m_client.create(m_server.getEngine().getBasePath(), m_server);
ASSERT(client_created);
m_world_editor = Lumix::WorldEditor::create(QDir::currentPath().toLocal8Bit().data());
ASSERT(m_world_editor);
m_world_editor->tick();
m_main_window->setEditorClient(m_client);
m_main_window->setEditorServer(m_server);
m_main_window->getSceneView()->setServer(&m_server);
m_main_window->setWorldEditor(*m_world_editor);
m_main_window->getSceneView()->setWorldEditor(m_world_editor);
m_edit_render_device = new WGLRenderDevice(m_server.getEngine(), "pipelines/main.json");
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_server.getEngine().getRenderScene()); /// TODO manage scene properly
m_server.setEditViewRenderDevice(*m_edit_render_device);
m_edit_render_device->getPipeline().setScene(m_world_editor->getEngine().getRenderScene()); /// TODO manage scene properly
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_server.getEngine(), "pipelines/game_view.json");
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_server.getEngine().getRenderScene()); /// TODO manage scene properly
m_server.getEngine().getRenderer().setRenderDevice(*m_game_render_device);
m_game_render_device->getPipeline().setScene(m_world_editor->getEngine().getRenderScene()); /// TODO manage scene properly
m_world_editor->getEngine().getRenderer().setRenderDevice(*m_game_render_device);
m_server.universeCreated().bind<App, &App::onUniverseCreated>(this);
m_server.universeDestroyed().bind<App, &App::onUniverseDestroyed>(this);
m_world_editor->universeCreated().bind<App, &App::onUniverseCreated>(this);
m_world_editor->universeDestroyed().bind<App, &App::onUniverseDestroyed>(this);
m_main_window->getSceneView()->setPipeline(m_edit_render_device->getPipeline());
m_main_window->getGameView()->setPipeline(m_game_render_device->getPipeline());
@ -208,10 +260,10 @@ class App
{
PROFILE_FUNCTION();
m_edit_render_device->beginFrame();
m_server.render(*m_edit_render_device);
m_server.renderIcons(*m_edit_render_device);
m_server.getGizmo().updateScale(m_server.getEditCamera());
m_server.getGizmo().render(m_server.getEngine().getRenderer(), *m_edit_render_device);
m_world_editor->render(*m_edit_render_device);
m_world_editor->renderIcons(*m_edit_render_device);
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();
@ -238,19 +290,19 @@ class App
}
if (keys['W'] >> 7)
{
m_client.navigate(1, 0, speed);
m_world_editor->navigate(1, 0, speed);
}
else if (keys['S'] >> 7)
{
m_client.navigate(-1, 0, speed);
m_world_editor->navigate(-1, 0, speed);
}
if (keys['A'] >> 7)
{
m_client.navigate(0, -1, speed);
m_world_editor->navigate(0, -1, speed);
}
else if (keys['D'] >> 7)
{
m_client.navigate(0, 1, speed);
m_world_editor->navigate(0, 1, speed);
}
}
}
@ -263,8 +315,8 @@ class App
{
PROFILE_BLOCK("tick");
renderEditView();
m_server.getEngine().getRenderer().renderGame();
m_server.tick();
m_world_editor->getEngine().getRenderer().renderGame();
m_world_editor->tick();
handleEvents();
}
Lumix::g_profiler.frame();
@ -275,8 +327,7 @@ class App
WGLRenderDevice* m_edit_render_device;
WGLRenderDevice* m_game_render_device;
MainWindow* m_main_window;
Lumix::EditorServer m_server;
Lumix::EditorClient m_client;
Lumix::WorldEditor* m_world_editor;
QApplication* m_qt_app;
};

View file

@ -1,10 +1,9 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <qfiledialog.h>
#include <qsettings.h>
#include "assetbrowser.h"
#include "editor/editor_client.h"
#include "editor/editor_server.h"
#include "editor/entity_template_system.h"
#include "editor/world_editor.h"
#include "entity_template_list.h"
#include "fileserverwidget.h"
#include "gameview.h"
#include "log_widget.h"
@ -13,13 +12,15 @@
#include "scripts/scriptcompilerwidget.h"
#include "materialmanager.h"
#include "profilerui.h"
#include <qfiledialog.h>
#include <qinputdialog.h>
#include <qsettings.h>
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
m_ui(new Ui::MainWindow)
{
m_client = NULL;
m_ui->setupUi(this);
m_ui->centralWidget->hide();
setDockOptions(AllowNestedDocks | AnimatedDocks | AllowTabbedDocks);
@ -33,6 +34,7 @@ MainWindow::MainWindow(QWidget* parent) :
m_file_server_ui = new FileServerWidget;
m_material_manager_ui = new MaterialManager;
m_profiler_ui = new ProfilerUI;
m_entity_template_list_ui = new EntityTemplateList;
QSettings settings("Lumix", "QtEditor");
restoreGeometry(settings.value("mainWindowGeometry").toByteArray());
@ -46,6 +48,7 @@ MainWindow::MainWindow(QWidget* parent) :
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);
m_property_view->setScriptCompiler(m_script_compiler_ui->getCompiler());
@ -73,27 +76,20 @@ MainWindow::~MainWindow()
delete m_file_server_ui;
delete m_material_manager_ui;
delete m_profiler_ui;
delete m_entity_template_list_ui;
}
void MainWindow::setEditorServer(Lumix::EditorServer& server)
void MainWindow::setWorldEditor(Lumix::WorldEditor& editor)
{
m_file_server_ui->setEditorServer(server);
m_asset_browser->setEditorServer(server);
m_material_manager_ui->setEditorServer(server);
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);
}
void MainWindow::setEditorClient(Lumix::EditorClient& client)
{
m_client = &client;
m_property_view->setEditorClient(client);
m_scene_view->setEditorClient(client);
m_asset_browser->setEditorClient(client);
m_game_view->setEditorClient(client);
m_material_manager_ui->setEditorClient(client);
}
GameView* MainWindow::getGameView() const
{
return m_game_view;
@ -111,43 +107,28 @@ void MainWindow::on_actionLog_triggered()
m_log->show();
}
void MainWindow::on_actionOpen_triggered()
{
QByteArray path = QFileDialog::getOpenFileName(NULL, QString(), QString(), "universe (*.unv)").toLocal8Bit();
int len = (int)strlen(m_client->getBasePath());
if (!path.isEmpty())
{
if (strncmp(path.data(), m_client->getBasePath(), len) == 0)
{
m_client->loadUniverse(path.data() + len);
}
else
{
m_client->loadUniverse(path.data());
}
m_world_editor->loadUniverse(path.data());
}
}
void MainWindow::on_actionSave_As_triggered()
{
QByteArray path = QFileDialog::getSaveFileName().toLocal8Bit();
int len = (int)strlen(m_client->getBasePath());
if (!path.isEmpty())
{
if (strncmp(path.data(), m_client->getBasePath(), len) == 0)
{
m_client->saveUniverse(path.data() + len);
}
else
{
m_client->saveUniverse(path.data());
}
m_world_editor->saveUniverse(path.data());
}
}
void MainWindow::on_actionCreate_triggered()
{
m_client->addEntity();
m_world_editor->addEntity();
}
void MainWindow::on_actionProperties_triggered()
@ -192,20 +173,75 @@ void MainWindow::on_actionProfiler_triggered()
void MainWindow::on_actionMaterial_manager_triggered()
{
m_material_manager_ui->show();
m_material_manager_ui->show();
}
void MainWindow::on_actionPolygon_Mode_changed()
{
m_client->setWireframe(m_ui->actionPolygon_Mode->isChecked());
m_world_editor->setWireframe(m_ui->actionPolygon_Mode->isChecked());
}
void MainWindow::on_actionGame_mode_triggered()
{
m_client->toggleGameMode();
m_world_editor->toggleGameMode();
}
void MainWindow::on_actionLook_at_selected_entity_triggered()
{
m_client->lookAtSelected();
m_world_editor->lookAtSelected();
}
void MainWindow::on_actionNew_triggered()
{
m_world_editor->newUniverse();
}
void MainWindow::on_actionSave_triggered()
{
if (m_world_editor->getUniversePath()[0] == '\0')
{
on_actionSave_As_triggered();
}
else
{
m_world_editor->saveUniverse(m_world_editor->getUniversePath());
}
}
void MainWindow::on_actionSnap_to_terrain_triggered()
{
m_world_editor->snapToTerrain();
}
void MainWindow::on_actionSave_as_template_triggered()
{
if (m_world_editor->getSelectedEntity().isValid())
{
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());
}
}
}
void MainWindow::on_actionEntity_templates_triggered()
{
m_entity_template_list_ui->show();
}
void MainWindow::on_actionInstantiate_template_triggered()
{
m_entity_template_list_ui->instantiateTemplate();
}
void MainWindow::on_actionUndo_triggered()
{
m_world_editor->undo();
}
void MainWindow::on_actionRedo_triggered()
{
m_world_editor->redo();
}

View file

@ -4,8 +4,7 @@
namespace Lumix
{
class EditorClient;
class EditorServer;
class WorldEditor;
}
namespace Ui
@ -21,8 +20,7 @@ public:
explicit MainWindow(QWidget* parent = NULL);
~MainWindow();
void setEditorClient(Lumix::EditorClient& client);
void setEditorServer(Lumix::EditorServer& server);
void setWorldEditor(Lumix::WorldEditor& world_editor);
class SceneView* getSceneView() const;
class GameView* getGameView() const;
class MaterialManager* getMaterialManager() const { return m_material_manager_ui; }
@ -40,20 +38,26 @@ private slots:
void on_actionAsset_Browser_triggered();
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();
void on_actionNew_triggered();
void on_actionSave_triggered();
void on_actionSnap_to_terrain_triggered();
void on_actionSave_as_template_triggered();
void on_actionEntity_templates_triggered();
void on_actionProfiler_triggered();
void on_actionInstantiate_template_triggered();
void on_actionMaterial_manager_triggered();
void on_actionUndo_triggered();
void on_actionPolygon_Mode_changed();
void on_actionGame_mode_triggered();
void on_actionLook_at_selected_entity_triggered();
void on_actionRedo_triggered();
private:
Ui::MainWindow* m_ui;
Lumix::EditorClient* m_client;
Lumix::WorldEditor* m_world_editor;
class LogWidget* m_log;
class PropertyView* m_property_view;
class SceneView* m_scene_view;
@ -63,5 +67,6 @@ private:
class FileServerWidget* m_file_server_ui;
class MaterialManager* m_material_manager_ui;
class ProfilerUI* m_profiler_ui;
class EntityTemplateList* m_entity_template_list_ui;
};

View file

@ -52,6 +52,7 @@
<string>Windows</string>
</property>
<addaction name="actionAsset_Browser"/>
<addaction name="actionEntity_templates"/>
<addaction name="actionFile_server"/>
<addaction name="actionGame_view"/>
<addaction name="actionLog"/>
@ -81,14 +82,25 @@
</property>
<addaction name="actionGame_mode"/>
<addaction name="actionCompile_scripts"/>
<addaction name="actionSnap_to_terrain"/>
</widget>
<widget class="QMenu" name="menuEntity">
<property name="title">
<string>Entity</string>
</property>
<addaction name="actionCreate"/>
<addaction name="actionSave_as_template"/>
<addaction name="actionInstantiate_template"/>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
<string>Edit</string>
</property>
<addaction name="actionUndo"/>
<addaction name="actionRedo"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
<addaction name="menuView"/>
<addaction name="menuTools"/>
<addaction name="menuEntity"/>
@ -218,6 +230,48 @@
<string>Ctrl+Tab</string>
</property>
</action>
<action name="actionSnap_to_terrain">
<property name="text">
<string>Snap to terrain</string>
</property>
<property name="shortcut">
<string>Ctrl+T</string>
</property>
</action>
<action name="actionSave_as_template">
<property name="text">
<string>Create template</string>
</property>
</action>
<action name="actionEntity_templates">
<property name="text">
<string>Entity templates</string>
</property>
</action>
<action name="actionInstantiate_template">
<property name="text">
<string>Instantiate template</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="actionUndo">
<property name="text">
<string>Undo</string>
</property>
<property name="shortcut">
<string>Ctrl+Z</string>
</property>
</action>
<action name="actionRedo">
<property name="text">
<string>Redo</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+Z</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>

View file

@ -12,9 +12,7 @@
#include "core/json_serializer.h"
#include "core/log.h"
#include "core/profiler.h"
#include "editor/editor_server.h"
#include "editor/editor_client.h"
#include "editor/server_message_types.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "graphics/material.h"
#include "graphics/model.h"
@ -37,6 +35,7 @@ class MaterialManagerUI
Lumix::Model* m_selected_object_model;
QFileSystemModel* m_fs_model;
Lumix::Material* m_material;
Lumix::WorldEditor* m_world_editor;
};
@ -46,6 +45,7 @@ MaterialManager::MaterialManager(QWidget *parent)
{
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());
@ -53,8 +53,8 @@ MaterialManager::MaterialManager(QWidget *parent)
filters << "*.mat";
m_impl->m_fs_model->setNameFilters(filters);
m_impl->m_fs_model->setNameFilterDisables(false);
m_ui->fileListView->setModel(m_impl->m_fs_model);
m_ui->fileListView->setRootIndex(m_impl->m_fs_model->index(QDir::currentPath()));
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;
@ -82,36 +82,38 @@ void MaterialManager::fillObjectMaterials()
}
}
void MaterialManager::onPropertyList(Lumix::PropertyListEvent& event)
QWidget* MaterialManager::getPreview() const
{
if (event.type_hash == crc32("renderable"))
return m_ui->previewWidget;
}
void MaterialManager::onEntitySelected(Lumix::Entity& entity)
{
if (entity.isValid())
{
for (int i = 0; i < event.properties.size(); ++i)
Lumix::Component cmp = entity.getComponent(crc32("renderable"));
if (cmp.isValid())
{
if (event.properties[i].name_hash == crc32("source"))
{
m_impl->m_selected_object_model = static_cast<Lumix::Model*>(m_impl->m_engine->getResourceManager().get(Lumix::ResourceManager::MODEL)->get((char*)event.properties[i].data));
fillObjectMaterials();
}
m_impl->m_selected_object_model = static_cast<Lumix::RenderScene*>(cmp.system)->getModel(cmp);
fillObjectMaterials();
}
}
}
void MaterialManager::setEditorClient(Lumix::EditorClient& client)
{
client.propertyListReceived().bind<MaterialManager, &MaterialManager::onPropertyList>(this);
}
void MaterialManager::setEditorServer(Lumix::EditorServer& server)
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();
m_impl->m_engine = &server.getEngine();
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(server.getEngine(), *m_impl->m_universe);
m_impl->m_render_device = new WGLRenderDevice(server.getEngine(), "pipelines/main.json");
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);
@ -136,41 +138,6 @@ void MaterialManager::setEditorServer(Lumix::EditorServer& server)
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;
/// TODO refactor (EditorServer::create)
HDC hdc;
hdc = GetDC(hwnd);
ASSERT(hdc != NULL);
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // 32-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pixelformat = ChoosePixelFormat(hdc, &pfd);
if (pixelformat == 0)
{
ASSERT(false);
}
BOOL success = SetPixelFormat(hdc, pixelformat, &pfd);
if (success == FALSE)
{
ASSERT(false);
}
}
MaterialManager::~MaterialManager()
@ -276,7 +243,9 @@ void MaterialManager::onTextureAdded()
void MaterialManager::selectMaterial(const char* path)
{
Lumix::Material* material = static_cast<Lumix::Material*>(m_impl->m_engine->getResourceManager().get(Lumix::ResourceManager::MATERIAL)->load(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())
@ -290,6 +259,7 @@ void MaterialManager::onMaterialLoaded(Lumix::Resource::State, Lumix::Resource::
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)
};
@ -366,12 +336,6 @@ void MaterialManager::onTextureRemoved()
selectMaterial(m_impl->m_material->getPath().c_str());
}
void MaterialManager::on_fileListView_doubleClicked(const QModelIndex &index)
{
QString file_path = m_impl->m_fs_model->fileInfo(index).filePath().toLower();
selectMaterial(file_path.toLatin1().data());
}
void MaterialManager::on_objectMaterialList_doubleClicked(const QModelIndex &index)
{
QListWidgetItem* item = m_ui->objectMaterialList->item(index.row());
@ -400,3 +364,9 @@ void MaterialManager::on_saveMaterialButton_clicked()
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

@ -10,8 +10,8 @@ namespace Ui
namespace Lumix
{
class EditorServer;
class EditorClient;
class WorldEditor;
struct Entity;
class Event;
struct PropertyListEvent;
}
@ -23,18 +23,17 @@ class MaterialManager : public QDockWidget
public:
explicit MaterialManager(QWidget* parent = NULL);
~MaterialManager();
void setEditorServer(Lumix::EditorServer& server);
void setEditorClient(Lumix::EditorClient& client);
void setWorldEditor(Lumix::WorldEditor& server);
void updatePreview();
QWidget* getPreview() const;
private:
void onPropertyList(Lumix::PropertyListEvent& event);
void fillObjectMaterials();
void selectMaterial(const char* path);
void onMaterialLoaded(Lumix::Resource::State, Lumix::Resource::State);
void onEntitySelected(Lumix::Entity& entity);
private slots:
void on_fileListView_doubleClicked(const QModelIndex& index);
void on_objectMaterialList_doubleClicked(const QModelIndex& index);
void on_saveMaterialButton_clicked();
void onBoolPropertyStateChanged(int state);
@ -42,6 +41,7 @@ class MaterialManager : public QDockWidget
void onTextureChanged();
void onTextureRemoved();
void onTextureAdded();
void on_fileTreeView_doubleClicked(const QModelIndex &index);
private:
Ui::MaterialManager* m_ui;

View file

@ -22,7 +22,7 @@
</property>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -42,7 +42,7 @@
<number>0</number>
</property>
<item>
<widget class="QListView" name="fileListView"/>
<widget class="QTreeView" name="fileTreeView"/>
</item>
</layout>
</widget>

View file

@ -42,6 +42,7 @@ class FileSystemWatcherPC : public FileSystemWatcher
{
switch(info->Action)
{
case FILE_ACTION_RENAMED_NEW_NAME:
case FILE_ACTION_ADDED:
case FILE_ACTION_MODIFIED:
{
@ -51,6 +52,7 @@ class FileSystemWatcherPC : public FileSystemWatcher
// watcher->m_asset_browser->emitFileChanged(tmp);
}
break;
case FILE_ACTION_RENAMED_OLD_NAME:
case FILE_ACTION_REMOVED:
//do not do anything
break;
@ -76,14 +78,20 @@ class FileSystemWatcherPC : public FileSystemWatcher
{
switch(info->Action)
{
case FILE_ACTION_RENAMED_NEW_NAME:
case FILE_ACTION_ADDED:
case FILE_ACTION_MODIFIED:
{
char tmp[MAX_PATH];
wcharToCharArray(info->FileName, tmp, info->FileNameLength);
watcher->m_callback.invoke(tmp);
// watcher->m_asset_browser->emitFileChanged(tmp);
}
break;
case FILE_ACTION_RENAMED_OLD_NAME:
case FILE_ACTION_REMOVED:
//do not do anything
break;
default:
ASSERT(false);
break;

View file

@ -39,6 +39,36 @@ void ProfilerGraph::mouseMoveEvent(QMouseEvent* event)
}
}
void ProfilerGraph::getRootPath(QPainterPath& path, float max)
{
ProfileModel::Block* root = m_model->getRoot();
int w = width();
int h = height();
path.moveTo(0, height());
if (max > 0)
{
for (int i = 0; i < root->m_frames.size(); ++i)
{
float l = i * w / (float)m_model->getRoot()->m_frames.size();
float time = 0;
ProfileModel::Block* block = root;
while (block)
{
time += block->m_frames[i];
block = block->m_next;
}
float t = (h - 1) * (1.0f - time / max);
path.lineTo(l, t);
}
}
path.lineTo(width(), height());
path.closeSubpath();
}
void ProfilerGraph::getBlockPath(ProfileModel::Block* block, QPainterPath& path, float max)
{
@ -49,12 +79,11 @@ void ProfilerGraph::getBlockPath(ProfileModel::Block* block, QPainterPath& path,
if(max > 0)
{
int i = m_model->getRoot()->m_frames.size() - block->m_frames.size();
for(auto iter = block->m_frames.begin(), end = block->m_frames.end(); iter != end; ++iter)
for (int i = 0; i < block->m_frames.size(); ++i)
{
float l = i * w / (float)m_model->getRoot()->m_frames.size();
++i;
float t = (h - 1) * (1.0f - *iter / max);
float time = block->m_frames[i];
float t = (h - 1) * (1.0f - time / max);
path.lineTo(l, t);
}
}
@ -80,15 +109,22 @@ void ProfilerGraph::paintEvent(QPaintEvent*)
gradient.setSpread(QGradient::Spread::ReflectSpread);
float max = 0;
for(auto iter = root->m_frames.begin(), end = root->m_frames.end(); iter != end; ++iter)
for (int i = 0; i < root->m_frames.size(); ++i)
{
max = max < *iter ? *iter : max;
ProfileModel::Block* block = root;
float time = 0;
while (block)
{
time += block->m_frames[i];
block = block->m_next;
}
max = max < time ? time : max;
}
QPainterPath path;
getBlockPath(root, path, max);
getRootPath(path, max);
painter.fillPath(path, gradient);
if(m_block && m_block != root)
if(m_block)
{
QPainterPath detail_path;
getBlockPath(m_block, detail_path, max);

View file

@ -25,6 +25,7 @@ class ProfilerGraph : public QWidget
private:
void getBlockPath(ProfileModel::Block* block, QPainterPath& path, float max);
void getRootPath(QPainterPath& path, float max);
signals:
void frameSet();

View file

@ -3,72 +3,79 @@
#include <qpainter.h>
#include <qpixmap.h>
static const int MAX_FRAMES = 200;
ProfileModel::Block::Block()
{
m_frames.reserve(MAX_FRAMES);
for(int i = 0; i < MAX_FRAMES; ++i)
{
m_frames.push_back(0);
}
m_hit_counts.reserve(MAX_FRAMES);
for (int i = 0; i < MAX_FRAMES; ++i)
{
m_hit_counts.push_back(0);
}
}
ProfileModel::ProfileModel()
{
Lumix::g_profiler.getFrameListeners().bind<ProfileModel, &ProfileModel::onFrame>(this);
m_root = NULL;
m_frame = 0;
m_frame = -1;
}
void ProfileModel::cloneBlock(Block* my_block, Lumix::Profiler::Block* remote_block)
{
ASSERT(my_block->m_name == remote_block->m_name);
my_block->m_frames.push_back(remote_block->getLength());
if(my_block->m_frames.size() > 200)
my_block->m_hit_counts.push_back(remote_block->getHitCount());
if (my_block->m_frames.size() > MAX_FRAMES)
{
my_block->m_frames.pop_front();
}
if(!my_block->m_first_child && remote_block->m_first_child)
if (my_block->m_hit_counts.size() > MAX_FRAMES)
{
my_block->m_hit_counts.pop_front();
}
if (!my_block->m_first_child && remote_block->m_first_child)
{
Lumix::Profiler::Block* remote_child = remote_block->m_first_child;
Block* last_new_child = NULL;
while(remote_child)
{
Block* my_child = new Block;
my_child->m_function = remote_child->m_function;
my_child->m_name = remote_child->m_name;
my_child->m_parent = my_block;
my_child->m_next = NULL;
my_child->m_first_child = NULL;
if(last_new_child)
{
last_new_child->m_next = my_child;
}
else
{
my_block->m_first_child = my_child;
}
last_new_child = my_child;
cloneBlock(my_child, remote_child);
remote_child = remote_child->m_next;
}
Block* my_child = new Block;
my_child->m_function = remote_child->m_function;
my_child->m_name = remote_child->m_name;
my_child->m_parent = my_block;
my_child->m_next = NULL;
my_child->m_first_child = NULL;
my_block->m_first_child = my_child;
cloneBlock(my_child, remote_child);
}
else if(my_block->m_first_child)
{
Lumix::Profiler::Block* remote_child = remote_block->m_first_child;
Block* my_child = my_block->m_first_child;
while(remote_child)
{
if(my_child->m_name != remote_child->m_name && my_child->m_function != remote_child->m_function)
{
Block* new_child = new Block;
new_child->m_function = remote_child->m_function;
new_child->m_name = remote_child->m_name;
new_child->m_parent = my_block;
new_child->m_next = my_child;
new_child->m_first_child = NULL;
my_child = new_child;
if(my_child == my_block->m_first_child)
{
my_block->m_first_child = new_child;
}
}
cloneBlock(my_child, remote_child);
remote_child = remote_child->m_next;
my_child = my_child->m_next;
}
cloneBlock(my_child, remote_child);
}
if (!my_block->m_next && remote_block->m_next)
{
Lumix::Profiler::Block* remote_next = remote_block->m_next;
Block* my_next = new Block;
my_next->m_function = remote_next->m_function;
my_next->m_name = remote_next->m_name;
my_next->m_parent = my_block->m_parent;
my_next->m_next = NULL;
my_next->m_first_child = NULL;
my_block->m_next = my_next;
cloneBlock(my_next, remote_next);
}
else if (my_block->m_next)
{
cloneBlock(my_block->m_next, remote_block->m_next);
}
}
@ -114,6 +121,9 @@ QVariant ProfileModel::headerData(int section, Qt::Orientation, int role) const
return "Name";
case Values::LENGTH:
return "Length (ms)";
case Values::HIT_COUNT:
return "Hit count";
break;
default:
ASSERT(false);
return QVariant();
@ -131,22 +141,21 @@ QModelIndex ProfileModel::index(int row, int column, const QModelIndex& parent)
Block* block = NULL;
if(parent.internalPointer() != NULL)
{
block = static_cast<Block*>(parent.internalPointer());
block = static_cast<Block*>(parent.internalPointer())->m_first_child;
}
else
{
return createIndex(0, column, m_root);
block = m_root;
}
int index = row;
Block* child = block->m_first_child;
while(child && index > 0)
while (block && index > 0)
{
child = child->m_next;
block = block->m_next;
--index;
}
return createIndex(row, column, child);
return createIndex(row, column, block);
}
QModelIndex ProfileModel::parent(const QModelIndex& index) const
@ -183,7 +192,14 @@ int ProfileModel::rowCount(const QModelIndex& parent_index) const
if (!parent_index.isValid() || !parent_index.internalPointer())
{
return 1;
int count = 0;
Block* root = m_root;
while (root)
{
++count;
root = root->m_next;
}
return count;
}
else
{
@ -225,9 +241,10 @@ QVariant ProfileModel::data(const QModelIndex& index, int role) const
case Values::NAME:
return block->m_name;
case Values::LENGTH:
{
return m_frame >= 0 && m_frame < block->m_frames.size() ? block->m_frames[m_frame] : 0;
}
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::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;
default:
ASSERT(false);
return QVariant();

View file

@ -38,17 +38,21 @@ class ProfileModel : public QAbstractItemModel
NAME,
FUNCTION,
LENGTH,
HIT_COUNT,
COUNT
};
struct Block
{
Block();
const char* m_name;
const char* m_function;
Block* m_parent;
Block* m_first_child;
Block* m_next;
QList<float> m_frames;
QList<int> m_hit_counts;
};
public:

File diff suppressed because it is too large Load diff

View file

@ -4,12 +4,13 @@
#include <QDockWidget>
#include "core/array.h"
#include "core/string.h"
#include "universe/entity.h"
namespace Lumix
{
class EditorClient;
struct EntityPositionEvent;
struct EntitySelectedEvent;
struct Component;
class WorldEditor;
struct Entity;
class Event;
class Path;
struct PropertyListEvent;
@ -52,8 +53,7 @@ public:
public:
explicit PropertyView(QWidget* parent = NULL);
~PropertyView();
void setEditorClient(Lumix::EditorClient& client);
Lumix::EditorClient* getEditorClient();
void setWorldEditor(Lumix::WorldEditor& server);
void setScriptCompiler(ScriptCompiler* compiler);
private slots:
@ -65,24 +65,45 @@ private slots:
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);
private:
void clear();
void onPropertyList(Lumix::PropertyListEvent& event);
void onEntitySelected(Lumix::EntitySelectedEvent& event);
void onEntityPosition(Lumix::EntityPositionEvent& e);
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, void* data, int32_t data_size);
void onPropertyValue(Property* property, const void* data, int32_t data_size);
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();
private:
Ui::PropertyView* m_ui;
Lumix::EditorClient* m_client;
Lumix::Array<Property*> m_properties;
ScriptCompiler* m_compiler;
int m_selected_entity_index;
Lumix::Entity m_selected_entity;
Lumix::WorldEditor* m_world_editor;
bool m_is_updating_values;
class TerrainEditor* m_terrain_editor;
};

View file

@ -84,6 +84,9 @@
</item>
<item>
<widget class="QTreeWidget" name="propertyList">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="headerHidden">
<bool>false</bool>
</property>

View file

@ -1,6 +1,5 @@
#include "sceneview.h"
#include "editor/editor_client.h"
#include "editor/editor_server.h"
#include "editor/world_editor.h"
#include <qapplication.h>
#include <QDoubleSpinBox>
#include <QDragEnterEvent>
@ -16,11 +15,12 @@ class ViewWidget : public QWidget
ViewWidget(QWidget* parent)
: QWidget(parent)
{
setMouseTracking(true);
}
virtual void mousePressEvent(QMouseEvent* event) override
{
m_client->mouseDown(event->x(), event->y(), event->button() == Qt::LeftButton ? 0 : 2);
m_world_editor->onMouseDown(event->x(), event->y(), event->button() == Qt::RightButton ? Lumix::MouseButton::RIGHT : Lumix::MouseButton::LEFT);
m_last_x = event->x();
m_last_y = event->y();
setFocus();
@ -29,19 +29,19 @@ class ViewWidget : public QWidget
virtual void mouseMoveEvent(QMouseEvent* event) override
{
int flags = 0;
flags |= Qt::ControlModifier & QApplication::keyboardModifiers() ? (int)Lumix::EditorServer::MouseFlags::CONTROL : 0;
flags |= Qt::AltModifier & QApplication::keyboardModifiers() ? (int)Lumix::EditorServer::MouseFlags::ALT : 0;
m_client->mouseMove(event->x(), event->y(), event->x() - m_last_x, event->y() - m_last_y, flags);
flags |= Qt::ControlModifier & QApplication::keyboardModifiers() ? (int)Lumix::WorldEditor::MouseFlags::CONTROL : 0;
flags |= Qt::AltModifier & QApplication::keyboardModifiers() ? (int)Lumix::WorldEditor::MouseFlags::ALT : 0;
m_world_editor->onMouseMove(event->x(), event->y(), event->x() - m_last_x, event->y() - m_last_y, flags);
m_last_x = event->x();
m_last_y = event->y();
}
virtual void mouseReleaseEvent(QMouseEvent* event) override
{
m_client->mouseUp(event->x(), event->y(), event->button() == Qt::LeftButton ? 0 : 2);
m_world_editor->onMouseUp(event->x(), event->y(), event->button() == Qt::RightButton ? Lumix::MouseButton::RIGHT : Lumix::MouseButton::LEFT);
}
Lumix::EditorClient* m_client;
Lumix::WorldEditor* m_world_editor;
int m_last_x;
int m_last_y;
};
@ -69,10 +69,10 @@ SceneView::SceneView(QWidget* parent) :
}
void SceneView::setEditorClient(Lumix::EditorClient& client)
void SceneView::setWorldEditor(Lumix::WorldEditor* world_editor)
{
m_client = &client;
static_cast<ViewWidget*>(m_view)->m_client = &client;
static_cast<ViewWidget*>(m_view)->m_world_editor = world_editor;
m_world_editor = world_editor;
}
@ -98,14 +98,12 @@ void SceneView::dropEvent(QDropEvent *event)
QString file = list[0].toLocalFile();
if(file.endsWith(".msh"))
{
m_client->addEntity();
m_client->addComponent(crc32("renderable"));
QString base_path = m_client->getBasePath();
if(file.startsWith(base_path))
{
file.remove(0, base_path.length());
}
m_client->setComponentProperty("renderable", "source", file.toLatin1().data(), file.length());
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());
}
}
}

View file

@ -5,8 +5,7 @@
namespace Lumix
{
class EditorClient;
class EditorServer;
class WorldEditor;
class PipelineInstance;
}
@ -17,8 +16,7 @@ class SceneView : public QDockWidget
Q_OBJECT
public:
explicit SceneView(QWidget* parent = NULL);
void setEditorClient(Lumix::EditorClient& client);
void setServer(Lumix::EditorServer* server) { m_server = server; }
void setWorldEditor(Lumix::WorldEditor* server);
void setPipeline(Lumix::PipelineInstance& pipeline) { m_pipeline = &pipeline; }
QWidget* getViewWidget() { return m_view; }
float getNavivationSpeed() const;
@ -29,8 +27,7 @@ private:
virtual void dropEvent(QDropEvent *event) override;
private:
Lumix::EditorClient* m_client;
Lumix::EditorServer* m_server;
Lumix::WorldEditor* m_world_editor;
Lumix::PipelineInstance* m_pipeline;
QWidget* m_view;
QDoubleSpinBox* m_speed_input;

View file

@ -0,0 +1,21 @@
<ui version="4.0">
<author/>
<comment/>
<exportmacro/>
<class>TerrainEditor</class>
<widget name="TerrainEditor" class="QWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
</widget>
<pixmapfunction/>
<connections/>
</ui>

BIN
qteditor/QtEditor/vc120.pdb Normal file

Binary file not shown.

View file

@ -33,15 +33,13 @@ public:
virtual void beginFrame() override
{
PROFILE_FUNCTION();
BOOL b = wglMakeCurrent(m_hdc, m_opengl_context);
ASSERT(b);
wglMakeCurrent(m_hdc, m_opengl_context);
}
virtual void endFrame() override
{
PROFILE_FUNCTION();
BOOL b = wglSwapLayerBuffers(m_hdc, WGL_SWAP_MAIN_PLANE);
ASSERT(b);
wglSwapLayerBuffers(m_hdc, WGL_SWAP_MAIN_PLANE);
}
virtual Lumix::PipelineInstance& getPipeline()

View file

@ -40,6 +40,7 @@ Animation::Animation(const Path& path, ResourceManager& resource_manager)
{
m_rotations = NULL;
m_positions = NULL;
m_bones = NULL;
m_frame_count = 0;
}
@ -48,6 +49,7 @@ Animation::~Animation()
{
LUMIX_DELETE_ARRAY(m_positions);
LUMIX_DELETE_ARRAY(m_rotations);
LUMIX_DELETE_ARRAY(m_bones);
}
@ -70,13 +72,20 @@ void Animation::getPose(float time, Pose& pose, Model& model) const
{
for(int i = 0; i < m_bone_count; ++i)
{
lerp(m_positions[off + i], m_positions[off2 + i], &pos[i], t);
nlerp(m_rotations[off + i], m_rotations[off2 + i], &rot[i], t);
int parent = model.getBone(i).parent_idx;
if (parent >= 0)
Model::BoneMap::iterator iter = model.getBoneIndex(m_bones[i]);
if (iter.isValid())
{
pos[i] = rot[parent] * pos[i] + pos[parent];
rot[i] = rot[i] * rot[parent];
int model_bone_index = iter.value();
lerp(m_positions[off + i], m_positions[off2 + i], &pos[model_bone_index], t);
nlerp(m_rotations[off + i], m_rotations[off2 + i], &rot[model_bone_index], t);
/*int parent = model.getBone(model_bone_index).parent_idx;
ASSERT(parent < model_bone_index);
if (parent >= 0)
{
pos[model_bone_index] = rot[parent] * pos[model_bone_index] + pos[parent];
rot[model_bone_index] = rot[model_bone_index] * rot[parent];
}*/
}
}
}
@ -84,16 +93,24 @@ void Animation::getPose(float time, Pose& pose, Model& model) const
{
for(int i = 0; i < m_bone_count; ++i)
{
pos[i] = m_positions[off + i];
rot[i] = m_rotations[off + i];
int parent = model.getBone(i).parent_idx;
if (parent >= 0)
Model::BoneMap::iterator iter = model.getBoneIndex(m_bones[i]);
if (iter.isValid())
{
pos[i] = rot[parent] * pos[i] + pos[parent];
rot[i] = rot[i] * rot[parent];
int model_bone_index = iter.value();
pos[model_bone_index] = m_positions[off + i];
rot[model_bone_index] = m_rotations[off + i];
/*int parent = model.getBone(model_bone_index).parent_idx;
ASSERT(parent < model_bone_index);
if (parent >= 0)
{
pos[model_bone_index] = rot[parent] * pos[model_bone_index] + pos[parent];
rot[model_bone_index] = rot[model_bone_index] * rot[parent];
}*/
}
}
}
pose.setIsRelative();
pose.computeAbsolute(model);
}
}
@ -128,9 +145,11 @@ void Animation::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
m_positions = LUMIX_NEW_ARRAY(Vec3, m_frame_count * m_bone_count);
m_rotations = LUMIX_NEW_ARRAY(Quat, m_frame_count * m_bone_count);
m_bones = LUMIX_NEW_ARRAY(uint32_t, m_bone_count);
file->read(&m_positions[0], sizeof(Vec3)* m_bone_count * m_frame_count);
file->read(&m_rotations[0], sizeof(Quat)* m_bone_count * m_frame_count);
file->read(m_bones, sizeof(m_bones[0]) * m_bone_count);
m_size = file->size();
decrementDepCount();
}

View file

@ -51,6 +51,7 @@ class Animation : public Resource
int m_bone_count;
Vec3* m_positions;
Quat* m_rotations;
uint32_t* m_bones;
};

View file

@ -3,7 +3,7 @@
#include "core/crc32.h"
#include "core/json_serializer.h"
#include "core/resource_manager.h"
#include "editor/editor_server.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "graphics/renderer.h"
#include "universe/universe.h"
@ -15,214 +15,278 @@ namespace Lumix
static const uint32_t ANIMABLE_HASH = crc32("animable");
struct AnimationSystemImpl
struct AnimationSystemImpl : public AnimationSystem
{
public:
AnimationSystemImpl(Engine& engine) : m_engine(engine) {}
struct Animable
{
bool m_manual;
bool m_is_free;
Component m_renderable;
float m_time;
class Animation* m_animation;
};
void onCreateUniverse(Universe& universe)
{
ASSERT(!m_universe);
m_universe = &universe;
m_universe->componentCreated().bind<AnimationSystemImpl, &AnimationSystemImpl::onComponentCreated>(this);
}
void onDestroyUniverse(Universe&)
{
ASSERT(m_universe);
m_animables.clear();
m_universe->componentCreated().unbind<AnimationSystemImpl, &AnimationSystemImpl::onComponentCreated>(this);
m_universe = 0;
}
virtual Component createComponent(uint32_t component_type, const Entity& entity) override
{
if (component_type == ANIMABLE_HASH)
{
return createAnimable(entity);
}
return Component::INVALID;
}
virtual void destroyComponent(const Component& component) override
{
m_animables[component.index].m_is_free = true;
m_universe->removeComponent(component);
m_universe->componentDestroyed().invoke(component);
}
virtual void serialize(ISerializer& serializer) override
{
serializer.serialize("count", m_animables.size());
serializer.beginArray("animables");
for (int i = 0; i < m_animables.size(); ++i)
{
serializer.serializeArrayItem(m_animables[i].m_manual);
serializer.serializeArrayItem(m_animables[i].m_renderable.entity.index);
serializer.serializeArrayItem(m_animables[i].m_time);
serializer.serializeArrayItem(m_animables[i].m_is_free);
}
serializer.endArray();
}
virtual void deserialize(ISerializer& serializer) override
{
int count;
serializer.deserialize("count", count);
serializer.deserializeArrayBegin("animables");
m_animables.resize(count);
for (int i = 0; i < count; ++i)
{
serializer.deserializeArrayItem(m_animables[i].m_manual);
int entity_index;
serializer.deserializeArrayItem(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)
{
if (cmps[j].type == RENDERABLE_HASH)
{
m_animables[i].m_renderable = cmps[j];
break;
}
}
serializer.deserializeArrayItem(m_animables[i].m_time);
serializer.deserializeArrayItem(m_animables[i].m_is_free);
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
}
virtual bool isManual(Component cmp) override
{
return m_animables[cmp.index].m_manual;
}
virtual void setManual(Component cmp, bool is_manual) override
{
m_animables[cmp.index].m_manual = is_manual;
}
virtual void getPreview(Component cmp, string& path) override
{
path = m_animables[cmp.index].m_animation ? m_animables[cmp.index].m_animation->getPath().c_str() : "";
}
virtual void setPreview(Component cmp, const string& path) override
{
playAnimation(cmp, path.c_str());
}
virtual void playAnimation(const Component& cmp, const char* path) override
{
m_animables[cmp.index].m_animation = loadAnimation(path);
m_animables[cmp.index].m_time = 0;
m_animables[cmp.index].m_manual = false;
}
virtual void setAnimationFrame(const Component& cmp, int frame) override
{
if (m_animables[cmp.index].m_animation)
{
m_animables[cmp.index].m_time = m_animables[cmp.index].m_animation->getLength() * frame / m_animables[cmp.index].m_animation->getFrameCount();
}
}
virtual int getFrameCount(const Component& cmp) const override
{
if (m_animables[cmp.index].m_animation)
{
return m_animables[cmp.index].m_animation->getFrameCount();
}
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];
if (!animable.m_is_free && animable.m_animation && animable.m_animation->isReady())
{
RenderScene* scene = static_cast<RenderScene*>(animable.m_renderable.system);
animable.m_animation->getPose(animable.m_time, scene->getPose(animable.m_renderable), *scene->getModel(animable.m_renderable));
if (!animable.m_manual)
{
float t = animable.m_time + time_delta;
float l = animable.m_animation->getLength();
while (t > l)
{
t -= l;
}
animable.m_time = t;
}
}
}
}
virtual const char* getName() const override
{
return "animation";
}
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));
return true;
}
virtual void destroy() override
{
}
Array<Animable> m_animables;
Universe* m_universe;
Engine& m_engine;
void onComponentCreated(Component& component);
Engine* m_engine;
private:
void operator=(const AnimationSystemImpl&);
};
bool AnimationSystem::create(Engine& engine)
AnimationSystem* AnimationSystem::createInstance()
{
m_impl = LUMIX_NEW(AnimationSystemImpl)(engine);
m_impl->m_universe = 0;
if(engine.getEditorServer())
{
engine.getEditorServer()->registerCreator(ANIMABLE_HASH, *this);
}
engine.getEditorServer()->registerProperty("animable", LUMIX_NEW(PropertyDescriptor<AnimationSystem>)(crc32("preview"), &AnimationSystem::getPreview, &AnimationSystem::setPreview, IPropertyDescriptor::FILE));
return true;
return LUMIX_NEW(AnimationSystemImpl);
}
void AnimationSystem::destroy()
{
LUMIX_DELETE(m_impl);
m_impl = 0;
}
void AnimationSystem::onCreateUniverse(Universe& universe)
{
ASSERT(!m_impl->m_universe);
m_impl->m_universe = &universe;
m_impl->m_universe->componentCreated().bind<AnimationSystemImpl, &AnimationSystemImpl::onComponentCreated>(m_impl);
}
void AnimationSystem::onDestroyUniverse(Universe&)
{
ASSERT(m_impl->m_universe);
m_impl->m_animables.clear();
m_impl->m_universe->componentCreated().unbind<AnimationSystemImpl, &AnimationSystemImpl::onComponentCreated>(m_impl);
m_impl->m_universe = 0;
}
Component AnimationSystem::createComponent(uint32_t component_type, const Entity& entity)
{
if(component_type == ANIMABLE_HASH)
{
return createAnimable(entity);
}
return Component::INVALID;
}
void AnimationSystem::serialize(ISerializer& serializer)
{
serializer.serialize("count", m_impl->m_animables.size());
serializer.beginArray("animables");
for(int i = 0; i < m_impl->m_animables.size(); ++i)
{
serializer.serializeArrayItem(m_impl->m_animables[i].m_manual);
serializer.serializeArrayItem(m_impl->m_animables[i].m_renderable.entity.index);
serializer.serializeArrayItem(m_impl->m_animables[i].m_time);
}
serializer.endArray();
}
void AnimationSystem::deserialize(ISerializer& serializer)
{
int count;
serializer.deserialize("count", count);
serializer.deserializeArrayBegin("animables");
m_impl->m_animables.resize(count);
for(int i = 0; i < count; ++i)
{
serializer.deserializeArrayItem(m_impl->m_animables[i].m_manual);
int entity_index;
serializer.deserializeArrayItem(entity_index);
Entity e(m_impl->m_universe, entity_index);
const Entity::ComponentList& cmps = e.getComponents();
m_impl->m_animables[i].m_renderable = Component::INVALID;
for(int j = 0; j < cmps.size(); ++j)
{
if(cmps[j].type == RENDERABLE_HASH)
{
m_impl->m_animables[i].m_renderable = cmps[j];
break;
}
}
serializer.deserializeArrayItem(m_impl->m_animables[i].m_time);
m_impl->m_universe->addComponent(e, ANIMABLE_HASH, this, i);
}
serializer.deserializeArrayEnd();
}
void AnimationSystemImpl::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 AnimationSystem::createAnimable(const Entity& entity)
{
AnimationSystemImpl::Animable& animable = m_impl->m_animables.pushEmpty();
animable.m_manual = true;
animable.m_time = 0;
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_impl->m_universe->addComponent(entity, ANIMABLE_HASH, this, m_impl->m_animables.size() - 1);
m_impl->m_universe->componentCreated().invoke(cmp);
return cmp;
}
Animation* AnimationSystem::loadAnimation(const char* path)
{
ResourceManager& rm = m_impl->m_engine.getResourceManager();
return static_cast<Animation*>(rm.get(ResourceManager::ANIMATION)->load(path));
}
void AnimationSystem::getPreview(Component cmp, string& path)
{
path = m_impl->m_animables[cmp.index].m_animation ? m_impl->m_animables[cmp.index].m_animation->getPath().c_str() : "";
}
void AnimationSystem::setPreview(Component cmp, const string& path)
{
playAnimation(cmp, path.c_str());
}
void AnimationSystem::playAnimation(const Component& cmp, const char* path)
{
m_impl->m_animables[cmp.index].m_animation = loadAnimation(path);
m_impl->m_animables[cmp.index].m_time = 0;
m_impl->m_animables[cmp.index].m_manual = false;
}
void AnimationSystem::setAnimationTime(const Component& cmp, float time)
{
m_impl->m_animables[cmp.index].m_time = time;
}
void AnimationSystem::update(float time_delta)
{
if(m_impl->m_animables.empty())
return;
for(int i = 0, c = m_impl->m_animables.size(); i < c; ++i)
{
AnimationSystemImpl::Animable& animable = m_impl->m_animables[i];
if(!animable.m_manual && animable.m_animation->isReady())
{
RenderScene* scene = static_cast<RenderScene*>(animable.m_renderable.system);
animable.m_animation->getPose(animable.m_time, scene->getPose(animable.m_renderable), *scene->getModel(animable.m_renderable));
float t = animable.m_time + time_delta;
float l = animable.m_animation->getLength();
while(t > l)
{
t -= l;
}
animable.m_time = t;
}
}
}
} // ~namespace Lumix

View file

@ -22,27 +22,17 @@ namespace Lumix
class LUMIX_ENGINE_API AnimationSystem : public IPlugin
{
public:
AnimationSystem() { m_impl = 0; }
static AnimationSystem* createInstance();
virtual bool create(Engine&) override;
virtual void update(float time_delta) 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 Component createComponent(uint32_t, const Entity&) override;
virtual const char* getName() const override { return "animation"; }
virtual void setFrame(Component cmp, int frame) = 0;
virtual bool isManual(Component cmp) = 0;
virtual void setManual(Component cmp, bool is_manual) = 0;
virtual void getPreview(Component cmp, string& path) = 0;
virtual void setPreview(Component cmp, const string& path) = 0;
void getPreview(Component cmp, string& path);
void setPreview(Component cmp, const string& path);
void destroy();
Component createAnimable(const Entity& entity);
void playAnimation(const Component& cmp, const char* path);
void setAnimationTime(const Component& cmp, float time);
Animation* loadAnimation(const char* path);
private:
struct AnimationSystemImpl* m_impl;
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;
};

View file

@ -362,6 +362,7 @@ public:
T& back()
{
ASSERT(m_size > 0);
return m_data[m_size - 1];
}

View file

@ -10,13 +10,28 @@ namespace Lumix
}
void Blob::rewindForRead()
{
m_pos = 0;
if (!m_buffer.empty())
{
m_data = &m_buffer[0];
m_size = m_buffer.size();
}
}
void Blob::write(const void* data, int32_t size)
{
if(m_size + (int)size > m_buffer.size())
{
m_buffer.resize(m_size + size);
m_data = &m_buffer[0];
}
if (size)
{
memcpy(&m_buffer[0] + m_size, data, size);
}
memcpy(&m_buffer[0] + m_size, data, size);
m_size += size;
}

View file

@ -28,7 +28,7 @@ namespace Lumix
template <class T>
void read(T& value) { read(&value, sizeof(T)); }
void rewindForRead() { m_pos = 0; m_data = &m_buffer[0]; m_size = m_buffer.size(); }
void rewindForRead();
private:

View file

@ -409,6 +409,7 @@ namespace Lumix
void destruct(node_type* n)
{
(void)n; /// to avoid a bug in VS 2013 - n is unused warning
n->~node_type();
}

View file

@ -280,8 +280,14 @@ void JsonSerializer::deserializeArrayBegin()
void JsonSerializer::deserializeRawString(char* buffer, int max_length)
{
buffer[0] = m_buffer;
m_file.read(buffer + 1, max_length);
strncpy(buffer, m_token, max_length);
size_t token_length = strlen(m_token);
if (token_length + 2 <= max_length)
{
buffer[token_length] = '\n';
buffer[token_length + 1] = m_buffer;
m_file.read(buffer + token_length + 2, max_length - token_length - 2);
}
}

View file

@ -75,6 +75,12 @@ namespace Lumix
virtual void nextArrayItem() override;
virtual bool isObjectEnd() const override;
size_t getRestOfFileSize()
{
const size_t NEW_LINE_AND_M_BUFFER_SIZE = sizeof('\n') + sizeof(m_buffer);
return m_file.size() - m_file.pos() + NEW_LINE_AND_M_BUFFER_SIZE + strlen(m_token);
}
private:
void deserializeLabel(const char* label);
void deserializeToken();

View file

@ -60,6 +60,12 @@ namespace Lumix
return *this;
}
LogProxy& LogProxy::operator <<(float message)
{
m_message.cat(message);
return *this;
}
LogProxy& LogProxy::operator <<(uint32_t message)
{
m_message.cat(message);

View file

@ -19,6 +19,7 @@ namespace Lumix
~LogProxy();
LogProxy& operator <<(const char* message);
LogProxy& operator <<(float message);
LogProxy& operator <<(int32_t message);
LogProxy& operator <<(uint32_t message);
LogProxy& operator <<(const Path& path);

View file

@ -30,7 +30,11 @@ const uint32_t LUMIX_MAX_PATH = 260;
#ifndef ASSERT
#ifdef _WIN32
#define ASSERT(x) { const volatile bool lumix_assert_b____ = !(x); if(lumix_assert_b____) __debugbreak(); }
#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
@ -75,6 +79,8 @@ const uint32_t LUMIX_MAX_PATH = 260;
#define LUMIX_SCRIPT_API __declspec(dllimport)
#endif
#define LUMIX_RESTRICT __restrict
#include "core/new.h"
#include "core/new_macros.h"

View file

@ -32,7 +32,7 @@ namespace Lumix
bool operator == (const char* rhs) const { Path path(rhs); return m_id == path.m_id; }
bool operator == (uint32_t rhs) const { return m_id == rhs; }
bool isValid() { return NULL != m_path; }
bool isValid() const { return m_path[0] != '\0'; }
private:
char m_path[LUMIX_MAX_PATH];

View file

@ -50,6 +50,21 @@ namespace Lumix
}
}
}
static void getExtension(char* extension, int /*max_length*/, const char* src)
{
for (int i = strlen(src) - 1; i >= 0; --i)
{
if (src[i] == '.')
{
++i;
strcpy(extension, src + i);
break;
}
}
}
private:
PathUtils();
~PathUtils();

View file

@ -1,4 +1,5 @@
#include "profiler.h"
#include "core/log.h"
namespace Lumix
@ -57,22 +58,20 @@ namespace Lumix
}
if (!m_current_block)
{
if (m_root_block)
Block* root = m_root_block;
while (root && (root->m_name != name || root->m_function != function))
{
if (m_root_block->m_name == name && m_root_block->m_function == function)
{
m_current_block = m_root_block;
}
else
{
ASSERT(false); // there can be only one root
}
root = root->m_next;
}
if (root)
{
m_current_block = root;
}
else
{
Block* root = LUMIX_NEW(Block);
root->m_parent = NULL;
root->m_next = NULL;
root->m_next = m_root_block;
root->m_first_child = NULL;
root->m_name = name;
root->m_function = function;
@ -111,7 +110,8 @@ namespace Lumix
return;
}
ASSERT(m_current_block);
m_current_block->m_hits.back().m_length = 1000.0f * (m_timer->getTimeSinceStart() - m_current_block->m_hits.back().m_start);
float now = m_timer->getTimeSinceStart();
m_current_block->m_hits.back().m_length = 1000.0f * (now - m_current_block->m_hits.back().m_start);
m_current_block = m_current_block->m_parent;
}

View file

@ -53,6 +53,7 @@ namespace Lumix
~Block();
void frame();
float getLength();
int getHitCount() const { return m_hits.size(); }
public:
Block* m_parent;

View file

@ -165,6 +165,15 @@ class base_string
return *this;
}
template<>
base_string<T, Allocator>& cat<float>(float value)
{
char tmp[40];
toCString(value, tmp, 30, 10);
*this += tmp;
return *this;
}
template<>
base_string<T, Allocator>& cat<char*>(char* value)
{

View file

@ -1,37 +0,0 @@
#pragma once
namespace Lumix
{
struct ClientMessageType
{
enum
{
POINTER_DOWN = 1,
POINTER_MOVE,
POINTER_UP,
PROPERTY_SET,
MOVE_CAMERA, // 5
SAVE,
LOAD,
ADD_COMPONENT = 8,
GET_PROPERTIES = 9,
REMOVE_COMPONENT = 10,
ADD_ENTITY, // 11
TOGGLE_GAME_MODE, // 12
GET_POSITION, // 13
SET_POSITION, // 14
REMOVE_ENTITY, // 15
SET_EDIT_MODE, // 16
EDIT_SCRIPT, // 17
SET_WIREFRAME, // 18
NEW_UNIVERSE = 19, // 19
LOOK_AT_SELECTED = 20, // 20
STOP_GAME_MODE, // 21
};
};
} // ~namespace Lumix

View file

@ -1,236 +0,0 @@
#include "editor_client.h"
#include "core/array.h"
#include "core/blob.h"
#include "core/crc32.h"
#include "core/fifo_allocator.h"
#include "core/mt/lock_free_queue.h"
#include "core/mt/mutex.h"
#include "core/mt/task.h"
#include "core/net/tcp_connector.h"
#include "core/net/tcp_stream.h"
#include "core/path.h"
#include "core/profiler.h"
#include "editor/client_message_types.h"
#include "editor/editor_server.h"
#include "editor/server_message_types.h"
#include "universe/universe.h"
namespace Lumix
{
struct EditorClientImpl
{
EditorClientImpl(EditorServer& server)
: m_server(server)
{}
void sendMessage(uint32_t type, const void* data, int32_t size);
void onMessage(const uint8_t* data, int size);
Path m_base_path;
EditorServer& m_server;
DelegateList<void(EntityPositionEvent&)> m_entity_position_changed;
DelegateList<void(EntitySelectedEvent&)> m_entity_selected;
DelegateList <void(LogEvent&)> m_message_logged;
DelegateList <void(PropertyListEvent&)> m_property_list_received;
};
bool EditorClient::create(const char* base_path, EditorServer& server)
{
m_impl = LUMIX_NEW(EditorClientImpl)(server);
m_impl->m_base_path = base_path;
return true;
}
void EditorClient::destroy()
{
if (m_impl)
{
LUMIX_DELETE(m_impl);
m_impl = NULL;
}
}
void EditorClient::onMessage(const uint8_t* data, int size)
{
if(m_impl)
{
m_impl->onMessage(data, size);
}
}
void EditorClientImpl::onMessage(const uint8_t* data, int size)
{
Blob stream;
stream.create(data, size);
int32_t message_type;
stream.read(message_type);
switch(message_type)
{
case ServerMessageType::ENTITY_POSITION:
{
EntityPositionEvent msg;
msg.read(stream);
m_entity_position_changed.invoke(msg);
}
break;
case ServerMessageType::ENTITY_SELECTED:
{
EntitySelectedEvent msg;
msg.read(stream);
m_entity_selected.invoke(msg);
}
break;
case ServerMessageType::PROPERTY_LIST:
{
PropertyListEvent msg;
msg.read(stream);
m_property_list_received.invoke(msg);
}
break;
case ServerMessageType::LOG_MESSAGE:
{
LogEvent msg;
msg.read(stream);
m_message_logged.invoke(msg);
}
break;
default:
break;
}
}
EditorClient::PropertyListCallback& EditorClient::propertyListReceived()
{
return m_impl->m_property_list_received;
}
EditorClient::EntitySelectedCallback& EditorClient::entitySelected()
{
return m_impl->m_entity_selected;
}
EditorClient::EntityPositionCallback& EditorClient::entityPositionReceived()
{
return m_impl->m_entity_position_changed;
}
void EditorClientImpl::sendMessage(uint32_t type, const void* data, int32_t size)
{
Blob stream;
stream.write(&type, sizeof(type));
if (data)
{
stream.write(data, size);
}
m_server.onMessage(stream.getBuffer(), stream.getBufferSize());
}
const char* EditorClient::getBasePath() const
{
return m_impl->m_base_path.c_str();
}
void EditorClient::lookAtSelected()
{
m_impl->sendMessage((uint32_t)ClientMessageType::LOOK_AT_SELECTED, NULL, 0);
}
void EditorClient::addComponent(uint32_t type)
{
m_impl->sendMessage((uint32_t)ClientMessageType::ADD_COMPONENT, &type, sizeof(type));
}
void EditorClient::toggleGameMode()
{
m_impl->sendMessage((uint32_t)ClientMessageType::TOGGLE_GAME_MODE, NULL, 0);
}
void EditorClient::addEntity()
{
m_impl->sendMessage((uint32_t)ClientMessageType::ADD_ENTITY, NULL, 0);
}
void EditorClient::mouseDown(int x, int y, int button)
{
int data[3] = {x, y, button};
m_impl->sendMessage(ClientMessageType::POINTER_DOWN, data, 12);
}
void EditorClient::mouseUp(int x, int y, int button)
{
int data[3] = {x, y, button};
m_impl->sendMessage(ClientMessageType::POINTER_UP, data, 12);
}
void EditorClient::mouseMove(int x, int y, int dx, int dy, int flags)
{
int data[] = {x, y, dx, dy, flags};
m_impl->sendMessage(ClientMessageType::POINTER_MOVE, data, 20);
}
void EditorClient::loadUniverse(const char* path)
{
m_impl->sendMessage(ClientMessageType::LOAD, path, (int32_t)strlen(path)+1);
}
void EditorClient::setWireframe(bool is_wireframe)
{
int32_t data = is_wireframe;
m_impl->sendMessage(ClientMessageType::SET_WIREFRAME, &data, sizeof(data));
}
void EditorClient::setEntityPosition(int32_t entity, const Vec3& position)
{
uint8_t data[sizeof(entity) + sizeof(position)];
*(int32_t*)data = entity;
*(Vec3*)(data + sizeof(entity)) = position;
m_impl->sendMessage(ClientMessageType::SET_POSITION, data, sizeof(entity) + sizeof(position));
}
void EditorClient::saveUniverse(const char* path)
{
m_impl->sendMessage(ClientMessageType::SAVE, path, (int32_t)strlen(path)+1);
}
void EditorClient::navigate(float forward, float right, float speed)
{
uint8_t data[12];
*(float*)data = forward;
*(float*)(data + 4) = right;
*(float*)(data + 8) = speed;
m_impl->sendMessage(ClientMessageType::MOVE_CAMERA, data, 12);
}
void EditorClient::setComponentProperty(const char* component, const char* property, const void* value, int32_t length)
{
static Blob stream;
stream.clearBuffer();
uint32_t tmp = crc32(component);
stream.write(&tmp, sizeof(tmp));
tmp = crc32(property);
stream.write(&tmp, sizeof(tmp));
stream.write(&length, sizeof(length));
stream.write(value, length);
m_impl->sendMessage(ClientMessageType::PROPERTY_SET, stream.getBuffer(), stream.getBufferSize());
}
void EditorClient::requestProperties(uint32_t type_crc)
{
m_impl->sendMessage(ClientMessageType::GET_PROPERTIES, &type_crc, sizeof(type_crc));
}
} // ~namespace Lumix

View file

@ -1,54 +0,0 @@
#pragma once
#include "core/lumix.h"
#include "core/delegate_list.h"
namespace Lumix
{
class EditorServer;
struct Entity;
struct EntityPositionEvent;
struct EntitySelectedEvent;
struct PropertyListEvent;
struct ServerMessage;
struct Vec3;
class LUMIX_ENGINE_API EditorClient
{
public:
typedef DelegateList<void(PropertyListEvent&)> PropertyListCallback;
typedef DelegateList<void(EntitySelectedEvent&)> EntitySelectedCallback;
typedef DelegateList<void(EntityPositionEvent&)> EntityPositionCallback;
public:
EditorClient() { m_impl = NULL; }
bool create(const char* base_path, EditorServer& server);
void destroy();
void onMessage(const uint8_t* data, int size);
void addEntity();
void toggleGameMode();
void lookAtSelected();
void addComponent(uint32_t type);
void mouseDown(int x, int y, int button);
void mouseUp(int x, int y, int button);
void mouseMove(int x, int y, int dx, int dy, int flags);
void requestProperties(uint32_t type_crc);
void setComponentProperty(const char* component, const char* property, const void* value, int32_t length);
void navigate(float forward, float right, float speed);
void loadUniverse(const char* path);
void saveUniverse(const char* path);
void setEntityPosition(int32_t entity, const Vec3& position);
void setWireframe(bool is_wireframe);
const char* getBasePath() const;
PropertyListCallback& propertyListReceived();
EntitySelectedCallback& entitySelected();
EntityPositionCallback& entityPositionReceived();
private:
struct EditorClientImpl* m_impl;
};
} // ~namespace Lumix

File diff suppressed because it is too large Load diff

View file

@ -1,54 +0,0 @@
#pragma once
#include "core/lumix.h"
#include "core/delegate_list.h"
#include "editor/property_descriptor.h"
namespace Lumix
{
class EditorClient;
class Engine;
class IPlugin;
class IRenderDevice;
namespace FS
{
class TCPFileServer;
}
class LUMIX_ENGINE_API EditorServer
{
public:
enum class MouseFlags : int
{
ALT = 1,
CONTROL = 2
};
public:
EditorServer() { m_impl = 0; }
bool create(const char* base_path, EditorClient& client);
void destroy();
void onMessage(const uint8_t* data, int32_t size);
void tick();
void registerCreator(uint32_t type, IPlugin& creator);
void registerProperty(const char* component_type, IPropertyDescriptor* descriptor);
Engine& getEngine();
void render(IRenderDevice& render_device);
void renderIcons(IRenderDevice& render_device);
Component getEditCamera() const;
class Gizmo& getGizmo();
class FS::TCPFileServer& getTCPFileServer();
void setEditViewRenderDevice(IRenderDevice& render_device);
DelegateList<void ()>& universeCreated();
DelegateList<void ()>& universeDestroyed();
private:
struct EditorServerImpl* m_impl;
};
}

View file

@ -0,0 +1,211 @@
#include "entity_template_system.h"
#include "core/array.h"
#include "core/crc32.h"
#include "core/iserializer.h"
#include "core/map.h"
#include "core/string.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "universe/entity.h"
#include "universe/universe.h"
namespace Lumix
{
class EntityTemplateSystemImpl : public EntityTemplateSystem
{
public:
EntityTemplateSystemImpl(WorldEditor& editor)
: m_editor(editor)
{
m_universe = editor.getEngine().getUniverse();
editor.universeCreated().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
editor.universeDestroyed().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
}
~EntityTemplateSystemImpl()
{
m_editor.universeCreated().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
m_editor.universeDestroyed().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
}
void onUniverseCreated()
{
m_instances.clear();
m_template_names.clear();
m_universe = m_editor.getEngine().getUniverse();
}
void onUniverseDestroyed()
{
m_instances.clear();
m_template_names.clear();
m_universe = NULL;
}
virtual void createTemplateFromEntity(const char* name, const Entity& entity) override
{
uint32_t name_hash = crc32(name);
if (m_instances.find(name_hash) == m_instances.end())
{
m_template_names.push(string(name));
m_instances[name_hash].push(entity);
m_updated.invoke();
}
else
{
ASSERT(false);
}
}
virtual uint32_t getTemplate(const Entity& entity) override
{
for (auto iter = m_instances.begin(), end = m_instances.end(); iter != end; ++iter)
{
Array<Entity>& entities = iter.second();
for (int i = 0, c = entities.size(); i < c; ++i)
{
if (entities[i] == entity)
{
return iter.first();
}
}
}
return 0;
}
virtual const Array<Entity>& getInstances(uint32_t template_name_hash) override
{
return m_instances[template_name_hash];
}
virtual Entity createInstance(const char* name) 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;
}
}
virtual void serialize(ISerializer& serializer) override
{
serializer.serialize("templates_count", (int32_t)m_template_names.size());
serializer.beginArray("template_names");
for (int i = 0, c = m_template_names.size(); i < c; ++i)
{
serializer.serializeArrayItem(m_template_names[i].c_str());
}
serializer.endArray();
serializer.serialize("instance_count", (int32_t)m_instances.size());
serializer.beginArray("instances");
for (auto i = m_instances.begin(), end = m_instances.end(); i != end; ++i)
{
serializer.serializeArrayItem(i.first());
serializer.serializeArrayItem((int32_t)i.second().size());
for (int j = 0, c = i.second().size(); j < c; ++j)
{
serializer.serializeArrayItem(i.second()[j].index);
}
}
serializer.endArray();
}
virtual void deserialize(ISerializer& serializer) override
{
m_template_names.clear();
m_instances.clear();
int32_t count;
serializer.deserialize("templates_count", count);
serializer.deserializeArrayBegin("template_names");
for (int i = 0; i < count; ++i)
{
const int MAX_NAME_LENGTH = 50;
char name[MAX_NAME_LENGTH];
serializer.deserializeArrayItem(name, MAX_NAME_LENGTH);
m_template_names.push(string(name));
}
serializer.deserializeArrayEnd();
serializer.deserialize("instance_count", count);
serializer.deserializeArrayBegin("instances");
for (int i = 0; i < count; ++i)
{
uint32_t hash;
serializer.deserializeArrayItem(hash);
int32_t instances_per_template;
serializer.deserializeArrayItem(instances_per_template);
m_instances.insert(hash, Array<Entity>());
Array<Entity>& entities = m_instances[hash];
for (int j = 0; j < instances_per_template; ++j)
{
int32_t entity_index;
serializer.deserializeArrayItem(entity_index);
entities.push(Entity(m_universe, entity_index));
}
}
serializer.deserializeArrayEnd();
m_updated.invoke();
}
virtual Array<string>& getTemplateNames() override
{
return m_template_names;
}
virtual DelegateList<void()>& updated() override
{
return m_updated;
}
private:
Map<uint32_t, Array<Entity> > m_instances;
Array<string> m_template_names;
Universe* m_universe;
WorldEditor& m_editor;
DelegateList<void()> m_updated;
}; // class EntityTemplateSystemImpl
EntityTemplateSystem* EntityTemplateSystem::create(WorldEditor& editor)
{
return LUMIX_NEW(EntityTemplateSystemImpl)(editor);
}
void EntityTemplateSystem::destroy(EntityTemplateSystem* system)
{
LUMIX_DELETE(system);
}
} // namespace Lumix

View file

@ -0,0 +1,35 @@
#pragma once
#include "core/lumix.h"
#include "core/delegate_list.h"
#include "core/string.h"
#include "universe/entity.h"
namespace Lumix
{
class ISerializer;
class WorldEditor;
class LUMIX_ENGINE_API EntityTemplateSystem
{
public:
static EntityTemplateSystem* create(WorldEditor& editor);
static void destroy(EntityTemplateSystem* system);
virtual ~EntityTemplateSystem() {}
virtual void serialize(ISerializer& serializer) = 0;
virtual void deserialize(ISerializer& serializer) = 0;
virtual void createTemplateFromEntity(const char* name, const Entity& entity) = 0;
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 DelegateList<void()>& updated() = 0;
};
} // namespace Lumix

View file

@ -7,6 +7,7 @@
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "editor/gizmo.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "graphics/irender_device.h"
#include "graphics/model.h"
@ -18,7 +19,8 @@ namespace Lumix
{
Gizmo::Gizmo()
Gizmo::Gizmo(WorldEditor& editor)
: m_editor(editor)
{
m_model = NULL;
m_selected_entity.index = -1;
@ -178,8 +180,9 @@ void Gizmo::transform(Component camera, TransformOperation operation, int x, int
{
angle = (relx + rely) / 100.0f;
}
m_selected_entity.setRotation(m_selected_entity.getRotation() * Quat(axis, angle));
m_selected_entity.setPosition(pos);
Quat new_rot = m_selected_entity.getRotation() * Quat(axis, angle);
new_rot.normalize();
m_editor.setEntityPositionAndRotaion(m_selected_entity, pos, new_rot);
}
else
{
@ -188,7 +191,7 @@ void Gizmo::transform(Component camera, TransformOperation operation, int x, int
m_transform_point = intersection;
Vec3 pos = m_selected_entity.getPosition();
pos += delta;
m_selected_entity.setPosition(pos);
m_editor.setEntityPosition(m_selected_entity, pos);
}
}
}

View file

@ -16,6 +16,7 @@ class IRenderDevice;
struct Matrix;
class Renderer;
class Universe;
class WorldEditor;
class LUMIX_ENGINE_API Gizmo
@ -73,7 +74,7 @@ class LUMIX_ENGINE_API Gizmo
};
public:
Gizmo();
Gizmo(WorldEditor& editor);
~Gizmo();
void create(Renderer& renderer);
@ -93,6 +94,7 @@ class LUMIX_ENGINE_API Gizmo
Vec3 getMousePlaneIntersection(Component camera, int x, int y);
private:
WorldEditor& m_editor;
Renderer* m_renderer;
Entity m_selected_entity;
Universe* m_universe;

View file

@ -0,0 +1,18 @@
#pragma once
namespace Lumix
{
class IEditorCommand
{
public:
virtual void execute() = 0;
virtual void undo() = 0;
virtual uint32_t getType() = 0;
virtual bool merge(IEditorCommand& command) = 0;
};
} // namespace Lumix

View file

@ -89,8 +89,7 @@ class PropertyDescriptor : public IPropertyDescriptor
template <class S>
void PropertyDescriptor<S>::set(Component cmp, Blob& stream) const
{
int len;
stream.read(&len, sizeof(len));
int len = stream.getBufferSize();
switch(m_type)
{
case DECIMAL:
@ -151,7 +150,6 @@ void PropertyDescriptor<S>::get(Component cmp, Blob& stream) const
string value;
(static_cast<S*>(cmp.system)->*m_getter)(cmp, value);
len = value.length() + 1;
stream.write(&len, sizeof(len));
stream.write(value.c_str(), len);
}
break;
@ -160,7 +158,6 @@ void PropertyDescriptor<S>::get(Component cmp, Blob& stream) const
float f;
(static_cast<S*>(cmp.system)->*m_decimal_getter)(cmp, f);
len = sizeof(f);
stream.write(&len, sizeof(len));
stream.write(&f, len);
}
break;
@ -169,7 +166,6 @@ void PropertyDescriptor<S>::get(Component cmp, Blob& stream) const
int32_t i;
(static_cast<S*>(cmp.system)->*m_integer_getter)(cmp, i);
len = sizeof(i);
stream.write(&len, sizeof(len));
stream.write(&i, len);
}
break;
@ -178,7 +174,6 @@ void PropertyDescriptor<S>::get(Component cmp, Blob& stream) const
bool b;
(static_cast<S*>(cmp.system)->*m_bool_getter)(cmp, b);
len = sizeof(b);
stream.write(&len, sizeof(len));
stream.write(&b, len);
}
break;
@ -187,7 +182,6 @@ void PropertyDescriptor<S>::get(Component cmp, Blob& stream) const
Vec3 v;
(static_cast<S*>(cmp.system)->*m_vec3_getter)(cmp, v);
len = sizeof(v);
stream.write(&len, sizeof(len));
stream.write(&v, len);
}
break;

View file

@ -1,77 +0,0 @@
#include "server_message_types.h"
#include "core/blob.h"
namespace Lumix
{
void EntityPositionEvent::read(Blob& stream)
{
stream.read(&index, sizeof(index));
stream.read(&x, sizeof(x));
stream.read(&y, sizeof(y));
stream.read(&z, sizeof(z));
}
void EntitySelectedEvent::read(Blob& stream)
{
stream.read(&index, sizeof(index));
int32_t count;
stream.read(&count, sizeof(count));
components.resize(count);
for(int i = 0; i < count; ++i)
{
stream.read(&components[i], sizeof(components[i]));
}
}
void LogEvent::read(Blob& stream)
{
stream.read(&type, sizeof(type));
int32_t len;
stream.read(&len, sizeof(len));
char tmp[255];
if(len < 255)
{
stream.read(tmp, len);
tmp[len] = 0;
}
system = tmp;
stream.read(&len, sizeof(len));
if(len < 255)
{
stream.read(tmp, len);
tmp[len] = 0;
message = tmp;
}
else
{
char* buf = LUMIX_NEW_ARRAY(char, len+1);
stream.read(buf, len);
buf[len] = 0;
message = buf;
LUMIX_DELETE_ARRAY(buf);
}
}
void PropertyListEvent::read(Blob& stream)
{
int32_t count;
stream.read(&count, sizeof(count));
properties.resize(count);
stream.read(&type_hash, sizeof(type_hash));
for(int i = 0; i < count; ++i)
{
stream.read(&properties[i].name_hash, sizeof(properties[i].name_hash));
stream.read(&properties[i].data_size, sizeof(properties[i].data_size));
properties[i].data = LUMIX_NEW_ARRAY(uint8_t, properties[i].data_size);
stream.read(properties[i].data, properties[i].data_size);
}
}
} // ~namespace Lumix

View file

@ -1,76 +0,0 @@
#pragma once
#include "core/map.h"
#include "core/array.h"
#include "core/string.h"
namespace Lumix
{
class Blob;
struct ServerMessageType
{
enum Value
{
ENTITY_SELECTED = 1,
PROPERTY_LIST = 2,
ENTITY_POSITION = 3,
LOG_MESSAGE = 4,
};
};
struct LUMIX_ENGINE_API EntityPositionEvent
{
void read(Blob& stream);
int32_t index;
float x;
float y;
float z;
};
struct LUMIX_ENGINE_API EntitySelectedEvent
{
void read(Blob& stream);
int32_t index;
Array<uint32_t> components;
};
struct LUMIX_ENGINE_API LogEvent
{
void read(Blob& stream);
int32_t type;
string message;
string system;
};
struct LUMIX_ENGINE_API PropertyListEvent
{
struct Property
{
Property() { data = NULL; }
~Property() { LUMIX_DELETE_ARRAY(data); }
uint32_t name_hash;
void* data;
int32_t data_size;
};
void read(Blob& stream);
uint32_t type_hash;
Array<Property> properties;
};
} // ~namespace Lumix

1457
src/editor/world_editor.cpp Normal file

File diff suppressed because it is too large Load diff

106
src/editor/world_editor.h Normal file
View file

@ -0,0 +1,106 @@
#pragma once
#include "core/lumix.h"
#include "core/delegate_list.h"
#include "editor/property_descriptor.h"
namespace Lumix
{
class Engine;
class EntityTemplateSystem;
class IPlugin;
class IRenderDevice;
class Path;
class RayCastModelHit;
namespace FS
{
class TCPFileServer;
}
struct MouseButton
{
enum Value
{
LEFT,
MIDDLE,
RIGHT
};
};
class LUMIX_ENGINE_API WorldEditor
{
public:
enum class MouseFlags : int
{
ALT = 1,
CONTROL = 2
};
class Plugin
{
public:
virtual ~Plugin() {}
virtual void tick() = 0;
virtual bool onEntityMouseDown(const RayCastModelHit& hit, int x, int y) = 0;
virtual void onMouseMove(int x, int y, int rel_x, int rel_y, int mouse_flags) = 0;
virtual void onMouseUp(int x, int y, MouseButton::Value button) = 0;
};
public:
static WorldEditor* create(const char* base_path);
static void destroy(WorldEditor* server);
virtual void tick() = 0;
virtual void registerCreator(uint32_t type, IPlugin& creator) = 0;
virtual void registerProperty(const char* component_type, IPropertyDescriptor* descriptor) = 0;
virtual Engine& getEngine() = 0;
virtual void render(IRenderDevice& render_device) = 0;
virtual void renderIcons(IRenderDevice& render_device) = 0;
virtual Component getEditCamera() const = 0;
virtual class Gizmo& getGizmo() = 0;
virtual class FS::TCPFileServer& getTCPFileServer() = 0;
virtual void setEditViewRenderDevice(IRenderDevice& render_device) = 0;
virtual void undo() = 0;
virtual void redo() = 0;
virtual void loadUniverse(const Path& path) = 0;
virtual void saveUniverse(const Path& path) = 0;
virtual void newUniverse() = 0;
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 Entity addEntity() = 0;
virtual void selectEntity(Entity e) = 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 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 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;
virtual float getMouseX() const = 0;
virtual float getMouseY() const = 0;
virtual void setWireframe(bool is_wireframe) = 0;
virtual void lookAtSelected() = 0;
virtual const char* getBasePath() = 0;
virtual Entity getSelectedEntity() const = 0;
virtual const IPropertyDescriptor& getPropertyDescriptor(uint32_t type, uint32_t name_hash) = 0;
virtual DelegateList<void(Entity&)>& entitySelected() = 0;
virtual DelegateList<void()>& universeCreated() = 0;
virtual DelegateList<void()>& universeDestroyed() = 0;
virtual void addPlugin(Plugin* plugin) = 0;
virtual void getRelativePath(char* relative_path, int max_length, const Path& source) = 0;
virtual EntityTemplateSystem& getEntityTemplateSystem() = 0;
protected:
virtual ~WorldEditor() {}
};
}

View file

@ -56,7 +56,7 @@ namespace Lumix
// CullingSystem* m_culling_system;
string m_base_path;
EditorServer* m_editor_server;
WorldEditor* m_editor_server;
PluginManager m_plugin_manager;
Universe* m_universe;
RenderScene* m_render_scene;
@ -113,7 +113,7 @@ namespace Lumix
{
return false;
}
AnimationSystem* anim_system = LUMIX_NEW(AnimationSystem)();
AnimationSystem* anim_system = AnimationSystem::createInstance();
if(!anim_system->create(owner))
{
LUMIX_DELETE(anim_system);
@ -128,7 +128,7 @@ namespace Lumix
}
bool Engine::create(const char* base_path, FS::FileSystem* file_system, EditorServer* editor_server)
bool Engine::create(const char* base_path, FS::FileSystem* file_system, WorldEditor* editor_server)
{
g_log_info.getCallback().bind<showLogInVS>();
g_log_warning.getCallback().bind<showLogInVS>();
@ -222,7 +222,7 @@ namespace Lumix
}
}
EditorServer* Engine::getEditorServer() const
WorldEditor* Engine::getWorldEditor() const
{
return m_impl->m_editor_server;
}

View file

@ -8,6 +8,7 @@ namespace Lumix
class FileSystem;
}
class WorldEditor;
namespace MTJD
{
class Manager;
@ -31,13 +32,13 @@ namespace Lumix
Engine() { m_impl = NULL; }
~Engine() { ASSERT(m_impl == NULL); }
bool create(const char* base_path, FS::FileSystem* fs, EditorServer* editor_server);
bool create(const char* base_path, FS::FileSystem* fs, WorldEditor* editor_server);
void destroy();
Universe* createUniverse();
void destroyUniverse();
EditorServer* getEditorServer() const;
WorldEditor* getWorldEditor() const;
FS::FileSystem& getFileSystem();
Renderer& getRenderer();
InputSystem& getInputSystem();

View file

@ -25,6 +25,7 @@ namespace Lumix
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*) {};
};

View file

@ -28,8 +28,8 @@ FrameBuffer::FrameBuffer(int width, int height, int render_buffers, const char*
glBindTexture(GL_TEXTURE_2D, m_textures[DEPTH]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_textures[DEPTH], 0);

View file

@ -1,4 +1,5 @@
#include "graphics/geometry.h"
#include "core/profiler.h"
#include "graphics/gl_ext.h"
#include "graphics/shader.h"
@ -34,11 +35,16 @@ void VertexDef::parse(const char* data, int size)
break;
case 'i':
++i;
if(data[i] == '4')
if (data[i] == '4')
{
m_attributes[index] = VertexAttributeDef::INT4;
m_vertex_size += 4 * sizeof(int);
}
else if (data[i] == '1')
{
m_attributes[index] = VertexAttributeDef::INT1;
m_vertex_size += sizeof(int);
}
else
{
ASSERT(false);
@ -83,6 +89,9 @@ int VertexDef::getPositionOffset() const
case VertexAttributeDef::INT4:
offset += 4 * sizeof(int);
break;
case VertexAttributeDef::INT1:
offset += sizeof(int);
break;
case VertexAttributeDef::POSITION:
return offset;
break;
@ -103,6 +112,7 @@ int VertexDef::getPositionOffset() const
void VertexDef::begin(Shader& shader)
{
PROFILE_FUNCTION();
int offset = 0;
int shader_attrib_idx = 0;
for(int i = 0; i < m_attribute_count; ++i)
@ -142,6 +152,12 @@ void VertexDef::begin(Shader& shader)
offset += sizeof(GLint) * 4;
++shader_attrib_idx;
break;
case VertexAttributeDef::INT1:
glEnableVertexAttribArray(shader.getAttribId(shader_attrib_idx));
glVertexAttribPointer(shader.getAttribId(shader_attrib_idx), 1, GL_INT, GL_FALSE, m_vertex_size, (GLvoid*)offset);
offset += sizeof(GLint) * 1;
++shader_attrib_idx;
break;
default:
ASSERT(false);
break;
@ -153,6 +169,7 @@ void VertexDef::begin(Shader& shader)
void VertexDef::end(Shader& shader)
{
PROFILE_FUNCTION();
int shader_attrib_idx = 0;
for(int i = 0; i < m_attribute_count; ++i)
{
@ -167,6 +184,7 @@ void VertexDef::end(Shader& shader)
case VertexAttributeDef::TEXTURE_COORDS:
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
break;
case VertexAttributeDef::INT1:
case VertexAttributeDef::INT4:
case VertexAttributeDef::FLOAT4:
case VertexAttributeDef::FLOAT2:
@ -199,6 +217,7 @@ 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);
@ -221,6 +240,48 @@ Geometry::~Geometry()
}
void Geometry::copy(const Geometry& source, int times, VertexCallback& vertex_callback, IndexCallback& index_callback)
{
ASSERT(!source.m_indices.empty());
m_vertex_definition = source.m_vertex_definition;
glBindBuffer(GL_ARRAY_BUFFER, source.m_id);
uint8_t* data = (uint8_t*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
Array<uint8_t> data_copy;
int vertex_size = m_vertex_definition.getVertexSize();
int one_size = vertex_size * source.getVertices().size();
data_copy.resize(one_size * times);
for (int i = 0; i < times; ++i)
{
memcpy(&data_copy[i * one_size], data, one_size);
}
vertex_callback.invoke(data_copy);
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, source.m_indices_id);
data = (uint8_t*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
Array<int> indices_data_copy;
int indices_count = source.getIndices().size();
indices_data_copy.resize(indices_count * times);
for (int i = 0; i < times; ++i)
{
memcpy(&indices_data_copy[i * indices_count], data, sizeof(int) * indices_count);
}
index_callback.invoke(indices_data_copy);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_id);
glBufferData(GL_ARRAY_BUFFER, data_copy.size() * sizeof(data_copy[0]), &data_copy[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_data_copy.size() * sizeof(indices_data_copy[0]), &indices_data_copy[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void Geometry::copy(const uint8_t* data, int size, const Array<int32_t>& indices, VertexDef vertex_definition)
{
m_vertex_definition = vertex_definition;
@ -236,7 +297,6 @@ void Geometry::copy(const uint8_t* data, int size, const Array<int32_t>& indices
{
m_indices[i] = indices[i];
}
m_indices_count = indices.size();
glBindBuffer(GL_ARRAY_BUFFER, m_id);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

View file

@ -1,5 +1,6 @@
#pragma once
#include "core/array.h"
#include "core/delegate.h"
#include "core/vec3.h"
#include "graphics/gl_ext.h"
@ -18,6 +19,7 @@ struct VertexAttributeDef
FLOAT4,
FLOAT2,
INT4,
INT1,
POSITION,
NORMAL,
TEXTURE_COORDS,
@ -34,6 +36,7 @@ struct VertexDef
int getPositionOffset() const;
void begin(Shader& shader);
void end(Shader& shader);
VertexAttributeDef::Type getAttributeType(int i) const { return i < m_attribute_count ? m_attributes[i] : VertexAttributeDef::NONE; }
private:
VertexAttributeDef::Type m_attributes[16];
@ -45,15 +48,21 @@ struct VertexDef
class Geometry
{
public:
typedef Delegate<void(Array<uint8_t>&)> VertexCallback;
typedef Delegate<void(Array<int>&)> IndexCallback;
public:
Geometry();
~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; }
private:
GLuint m_id;
@ -61,7 +70,6 @@ class Geometry
VertexDef m_vertex_definition;
Array<Vec3> m_vertices;
Array<int32_t> m_indices;
int m_indices_count;
};

View file

@ -4,3 +4,4 @@
#define GLEW_STATIC
#include <gl/glew.h>
#include <gl/GL.h>
#include <gl/wglew.h>

View file

@ -4,6 +4,7 @@
#include "core/json_serializer.h"
#include "core/log.h"
#include "core/path_utils.h"
#include "core/profiler.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "core/timer.h"
@ -48,6 +49,7 @@ void Material::apply(Renderer& renderer, PipelineInstance& pipeline)
{
m_textures[i]->apply(i);
}
renderer.enableAlphaToCoverage(m_is_alpha_to_coverage);
renderer.enableZTest(m_is_z_test);
for (int i = 0, c = m_uniforms.size(); i < c; ++i)
{
@ -226,6 +228,7 @@ void Material::setShader(Shader* shader)
void Material::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
{
PROFILE_FUNCTION();
if(success)
{
JsonSerializer serializer(*file, JsonSerializer::READ, m_path.c_str());
@ -241,7 +244,7 @@ void Material::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
{
deserializeUniforms(serializer);
}
else if (strcmp(label, "texture") == 0 || strcmp(label, "heightmap") == 0)
else if (strcmp(label, "texture") == 0 || strcmp(label, "heightmap") == 0 || strcmp(label, "splatmap") == 0)
{
serializer.deserialize(path, MAX_PATH);
if (path[0] != '\0')
@ -251,6 +254,7 @@ void Material::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
texture_path += path;
Texture* texture = static_cast<Texture*>(m_resource_manager.get(ResourceManager::TEXTURE)->load(texture_path.c_str()));
bool is_heightmap = label[0] == 'h';
bool is_splatmap = label[0] == 's';
if (is_heightmap)
{
if (!m_textures.empty())
@ -260,9 +264,12 @@ void Material::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
fs.close(file);
return;
}
}
if (is_heightmap || is_splatmap)
{
if (texture->isReady() && !texture->getData())
{
g_log_error.log("Renderer") << "Heightmap " << m_path.c_str() << " can not be used as an ordinary texture";
g_log_error.log("Renderer") << (is_heightmap ? "Heightmap " : "Splatmap ") << m_path.c_str() << " can not be used as an ordinary texture";
onFailure();
fs.close(file);
return;
@ -273,6 +280,10 @@ void Material::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
addDependency(*texture);
}
}
else if (strcmp(label, "alpha_to_coverage") == 0)
{
serializer.deserialize(m_is_alpha_to_coverage);
}
else if (strcmp(label, "shader") == 0)
{
serializer.deserialize(path, MAX_PATH);

View file

@ -37,6 +37,8 @@ public:
void enableZTest(bool enable) { m_is_z_test = enable; }
bool isBackfaceCulling() const { return m_is_backface_culling; }
void enableBackfaceCulling(bool enable) { m_is_backface_culling = enable; }
bool isAlphaToCoverage() const { return m_is_alpha_to_coverage; }
void enableAlphaToCoverage(bool enable) { m_is_alpha_to_coverage = enable; }
void setShader(Shader* shader);
Shader* getShader() const { return m_shader; }
@ -54,6 +56,7 @@ private:
, m_is_z_test(true)
, m_is_backface_culling(true)
, m_depth_func(DepthFunc::LESS)
, m_is_alpha_to_coverage(false)
{ }
~Material();
@ -94,6 +97,7 @@ private:
Array<Uniform> m_uniforms;
bool m_is_z_test;
bool m_is_backface_culling;
bool m_is_alpha_to_coverage;
DepthFunc m_depth_func;
};

View file

@ -6,6 +6,7 @@
#include "core/fs/ifile.h"
#include "core/log.h"
#include "core/path_utils.h"
#include "core/profiler.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "core/vec3.h"
@ -190,6 +191,7 @@ bool Model::parseBones(FS::IFile* file)
file->read(tmp, len);
tmp[len] = 0;
b.name = tmp;
m_bone_map.insert(crc32(b.name.c_str()), m_bones.size() - 1);
file->read(&len, sizeof(len));
if (len >= MAX_PATH)
{
@ -294,6 +296,7 @@ bool Model::parseMeshes(FS::IFile* file)
void Model::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
{
PROFILE_FUNCTION();
if(success)
{
VertexDef vertex_definition;

View file

@ -4,6 +4,7 @@
#include "core/array.h"
#include "core/crc32.h"
#include "core/delegate_list.h"
#include "core/hash_map.h"
#include "core/matrix.h"
#include "core/quat.h"
#include "core/string.h"
@ -58,6 +59,8 @@ class Mesh
class Model : public Resource
{
public:
typedef HashMap<uint32_t, int> BoneMap;
struct Bone
{
string name;
@ -83,6 +86,7 @@ class Model : public Resource
int getMeshCount() const { return m_meshes.size(); }
int getBoneCount() const { return m_bones.size(); }
const Bone& getBone(int i) const { return m_bones[i]; }
BoneMap::iterator getBoneIndex(uint32_t hash) { return m_bone_map.find(hash); }
void getPose(Pose& pose);
float getBoundingRadius() const { return m_bounding_radius; }
RayCastModelHit castRay(const Vec3& origin, const Vec3& dir, const Matrix& model_transform, float scale);
@ -103,6 +107,7 @@ class Model : public Resource
Array<Mesh> m_meshes;
Array<Bone> m_bones;
float m_bounding_radius;
BoneMap m_bone_map; // maps bone name hash to bone index in m_bones
};

View file

@ -7,6 +7,7 @@
#include "core/json_serializer.h"
#include "core/log.h"
#include "core/map.h"
#include "core/profiler.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "core/string.h"
@ -546,8 +547,38 @@ struct PipelineInstanceImpl : public PipelineInstance
glEnd();
}
void renderGrass(int64_t layer_mask)
{
PROFILE_FUNCTION();
if (m_active_camera.isValid())
{
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)
{
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();
}
shader->setUniform("grass_matrices", m_grass_infos[i].m_matrices, m_grass_infos[i].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);
}
}
}
void renderTerrains(int64_t layer_mask)
{
PROFILE_FUNCTION();
if (m_active_camera.isValid())
{
m_terrain_infos.clear();
@ -560,6 +591,7 @@ struct PipelineInstanceImpl : public PipelineInstance
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]);
@ -580,20 +612,22 @@ struct PipelineInstanceImpl : public PipelineInstance
void renderModels(int64_t layer_mask)
{
PROFILE_FUNCTION();
ASSERT(m_renderer != NULL);
static Array<RenderableInfo> infos;
infos.clear();
m_scene->getRenderableInfos(infos, layer_mask);
int count = infos.size();
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;
for (int i = 0; i < count; ++i)
{
glPushMatrix();
Matrix world_matrix = infos[i].m_model ? infos[i].m_model->getMatrix() : *infos[i].m_matrix;
world_matrix.multiply3x3(infos[i].m_scale);
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);
Mesh& mesh = *infos[i].m_mesh;
Mesh& mesh = *m_renderable_infos[i].m_mesh;
Material& material = *mesh.getMaterial();
if (last_material != &material)
{
@ -607,12 +641,13 @@ struct PipelineInstanceImpl : public PipelineInstance
last_material = &material;
}
static Matrix bone_mtx[64];
if (infos[i].m_pose)
if (m_renderable_infos[i].m_pose)
{
const Pose& pose = *infos[i].m_pose;
const Model& model = *infos[i].m_model->getModel();
const Pose& pose = *m_renderable_infos[i].m_pose;
const Model& model = *m_renderable_infos[i].m_model->getModel();
Vec3* poss = pose.getPositions();
Quat* rots = pose.getRotations();
ASSERT(pose.getCount() <= 64);
for (int bone_index = 0, bone_count = pose.getCount(); bone_index < bone_count; ++bone_index)
{
rots[bone_index].toMatrix(bone_mtx[bone_index]);
@ -622,11 +657,11 @@ struct PipelineInstanceImpl : public PipelineInstance
material.getShader()->setUniform("bone_matrices", bone_mtx, pose.getCount());
}
infos[i].m_geometry->draw(mesh.getStart(), mesh.getCount(), *material.getShader());
m_renderable_infos[i].m_geometry->draw(mesh.getStart(), mesh.getCount(), *material.getShader());
glPopMatrix();
}
renderTerrains(layer_mask);
renderGrass(layer_mask);
}
virtual void resize(int w, int h) override
@ -673,6 +708,8 @@ struct PipelineInstanceImpl : public PipelineInstance
Map<uint32_t, CustomCommandHandler> m_custom_commands_handlers;
Component m_active_camera;
Array<TerrainInfo> m_terrain_infos;
Array<GrassInfo> m_grass_infos;
Array<RenderableInfo> m_renderable_infos;
private:
void operator=(const PipelineInstanceImpl&);

View file

@ -2,6 +2,7 @@
#include "core/matrix.h"
#include "core/quat.h"
#include "core/vec3.h"
#include "graphics/model.h"
namespace Lumix
@ -13,6 +14,7 @@ Pose::Pose()
m_positions = 0;
m_rotations = 0;
m_count = 0;
m_is_absolute = false;
}
@ -25,6 +27,7 @@ Pose::~Pose()
void Pose::resize(int count)
{
m_is_absolute = false;
LUMIX_DELETE_ARRAY(m_positions);
LUMIX_DELETE_ARRAY(m_rotations);
m_count = count;
@ -40,6 +43,40 @@ void Pose::resize(int count)
}
}
void Pose::computeAbsolute(Model& model, int i, bool* valid)
{
if (!valid[i])
{
int parent = model.getBone(i).parent_idx;
if (parent >= 0)
{
if (!valid[parent])
{
computeAbsolute(model, parent, valid);
}
m_positions[i] = m_rotations[parent] * m_positions[i] + m_positions[parent];
m_rotations[i] = m_rotations[i] * m_rotations[parent];
}
valid[i] = true;
}
}
void Pose::computeAbsolute(Model& model)
{
/// TODO remove recursion
if(!m_is_absolute)
{
ASSERT(m_count < 256);
bool valid[256];
memset(valid, 0, sizeof(bool) * m_count);
for (int i = 0; i < m_count; ++i)
{
computeAbsolute(model, i, valid);
}
m_is_absolute = true;
}
}
void Pose::setMatrices(Matrix* mtx) const
{

View file

@ -9,6 +9,7 @@ namespace Lumix
struct Matrix;
class Model;
struct Quat;
struct Vec3;
@ -24,12 +25,16 @@ class Pose
int getCount() const { return m_count; }
Vec3* getPositions() const { return m_positions; }
Quat* getRotations() const { return m_rotations; }
void computeAbsolute(Model& model);
void setIsRelative() { m_is_absolute = false; }
private:
Pose(const Pose&) {}
void operator =(const Pose&) {}
void computeAbsolute(Model& model, int i, bool* valid);
private:
bool m_is_absolute;
int32_t m_count;
Vec3* m_positions;
Quat* m_rotations;

View file

@ -8,14 +8,15 @@
namespace Lumix
{
struct RayCastModelHit
class RayCastModelHit
{
bool m_is_hit;
float m_t;
Vec3 m_origin;
Vec3 m_dir;
class Mesh* m_mesh;
Component m_component;
public:
bool m_is_hit;
float m_t;
Vec3 m_origin;
Vec3 m_dir;
class Mesh* m_mesh;
Component m_component;
};
} // ~ namespace Lumix

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,15 @@ namespace Lumix
float m_scale;
};
struct GrassInfo
{
Geometry* m_geometry;
Mesh* m_mesh;
const Matrix* m_matrices;
int m_matrix_count;
int m_mesh_copy_count;
};
struct DebugLine
{
Vec3 m_from;
@ -59,7 +68,8 @@ namespace Lumix
virtual void serialize(ISerializer& serializer) = 0;
virtual void deserialize(ISerializer& serializer) = 0;
virtual Component createComponent(uint32_t type, const Entity& entity) = 0;
virtual RayCastModelHit castRay(const Vec3& origin, const Vec3& dir) = 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;
virtual void update(float dt) = 0;
@ -93,6 +103,8 @@ namespace Lumix
virtual void setRenderablePath(Component cmp, const string& path) = 0;
virtual void setRenderableScale(Component cmp, const 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 void setTerrainMaterial(Component cmp, const string& path) = 0;
virtual void getTerrainMaterial(Component cmp, string& path) = 0;
@ -100,6 +112,9 @@ namespace Lumix
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 void setTerrainBrush(Component cmp, const Vec3& position, float size) = 0;
protected:
virtual ~RenderScene() {}

View file

@ -26,9 +26,9 @@ namespace Lumix
{
static const uint32_t light_hash = crc32("light");
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 RENDERABLE_HASH = crc32("renderable");
static const uint32_t CAMERA_HASH = crc32("camera");
struct RendererImpl : public Renderer
@ -110,11 +110,33 @@ 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)
{
glEnable(GL_MULTISAMPLE);
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
else
{
glDisable(GL_MULTISAMPLE);
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
}
virtual void enableZTest(bool enable) override
{
if (enable)

View file

@ -35,6 +35,7 @@ class LUMIX_ENGINE_API Renderer : public IPlugin
virtual void render(IRenderDevice& device) = 0;
virtual void renderGame() = 0;
virtual void enableAlphaToCoverage(bool enable) = 0;
virtual void enableZTest(bool enable) = 0;
virtual void setRenderDevice(IRenderDevice& device) = 0;
virtual void setEditorWireframe(bool is_wireframe) = 0;

View file

@ -4,6 +4,7 @@
#include "core/json_serializer.h"
#include "core/log.h"
#include "core/matrix.h"
#include "core/profiler.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "core/vec3.h"
@ -39,6 +40,7 @@ void Shader::apply()
void Shader::setUniform(const char* name, int value)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0)
{
@ -51,6 +53,7 @@ void Shader::setUniform(const char* name, int value)
void Shader::setUniform(const char* name, const Vec3& value)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0)
{
@ -63,6 +66,7 @@ void Shader::setUniform(const char* name, const Vec3& value)
void Shader::setUniform(const char* name, GLfloat value)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0)
{
@ -75,6 +79,7 @@ void Shader::setUniform(const char* name, GLfloat value)
void Shader::setUniform(const char* name, const Matrix& mtx)
{
PROFILE_FUNCTION();
GLint loc = glGetUniformLocation(m_program_id, name);
if(loc >= 0)
{
@ -86,6 +91,7 @@ void Shader::setUniform(const char* name, const Matrix& mtx)
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
{
@ -140,7 +146,7 @@ void Shader::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
}
serializer.deserializeObjectEnd();
int32_t size = (int32_t)file->size() - file->pos() + 1;
int32_t size = serializer.getRestOfFileSize();
ShaderManager* manager = static_cast<ShaderManager*>(getResourceManager().get(ResourceManager::SHADER));
char* buf = reinterpret_cast<char*>(manager->getBuffer(size + 1));
serializer.deserializeRawString(buf, size);

View file

@ -1,5 +1,6 @@
#include "terrain.h"
#include "core/iserializer.h"
#include "core/log.h"
#include "core/math_utils.h"
#include "core/profiler.h"
#include "core/resource_manager.h"
@ -11,12 +12,14 @@
#include "graphics/render_scene.h"
#include "graphics/shader.h"
#include "graphics/texture.h"
#include <cfloat>
namespace Lumix
{
static const int GRID_SIZE = 16;
static const int COPY_COUNT = 50;
static const uint32_t TERRAIN_HASH = crc32("terrain");
struct Sample
@ -144,7 +147,7 @@ namespace Lumix
};
Terrain::Terrain(const Entity& entity)
Terrain::Terrain(const Entity& entity, RenderScene& scene)
: m_mesh(NULL)
, m_material(NULL)
, m_root(NULL)
@ -154,6 +157,12 @@ 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();
}
@ -163,6 +172,213 @@ namespace Lumix
setMaterial(NULL);
LUMIX_DELETE(m_mesh);
LUMIX_DELETE(m_root);
if (m_grass_model)
{
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]);
}
}
}
Path Terrain::getGrassPath()
{
if (m_grass_model)
{
return m_grass_model->getPath();
}
return "";
}
void Terrain::setGrassPath(const Path& path)
{
if (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;
}
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);
}
}
void Terrain::updateGrass(const Vec3& camera_position)
{
PROFILE_FUNCTION();
if (m_free_grass_quads.size() + m_grass_quads.size() < GRASS_QUADS_HEIGHT * GRASS_QUADS_WIDTH)
{
int new_count = GRASS_QUADS_HEIGHT * GRASS_QUADS_WIDTH - m_grass_quads.size();
for (int i = 0; i < new_count; ++i)
{
m_free_grass_quads.push(LUMIX_NEW(GrassQuad));
}
}
if ((m_last_camera_position - camera_position).length() > 1)
{
Matrix mtx = m_entity.getMatrix();
Matrix inv_mtx = m_entity.getMatrix();
inv_mtx.fastInverse();
Vec3 local_camera_position = inv_mtx.multiplyPosition(camera_position);
float cx = (int)(local_camera_position.x / (GRASS_QUAD_SIZE)) * (float)GRASS_QUAD_SIZE;
float cz = (int)(local_camera_position.z / (GRASS_QUAD_SIZE)) * (float)GRASS_QUAD_SIZE;
float from_quad_x = cx - (GRASS_QUADS_WIDTH >> 1) * GRASS_QUAD_SIZE;
float from_quad_z = cz - (GRASS_QUADS_HEIGHT >> 1) * GRASS_QUAD_SIZE;
float to_quad_x = cx + (GRASS_QUADS_WIDTH >> 1) * GRASS_QUAD_SIZE;
float to_quad_z = cz + (GRASS_QUADS_WIDTH >> 1) * GRASS_QUAD_SIZE;
float old_bounds[4] = { FLT_MAX, FLT_MIN, FLT_MAX, FLT_MIN };
for (int i = m_grass_quads.size() - 1; i >= 0; --i)
{
GrassQuad* quad = m_grass_quads[i];
old_bounds[0] = Math::minValue(old_bounds[0], quad->m_x);
old_bounds[1] = Math::maxValue(old_bounds[1], quad->m_x);
old_bounds[2] = Math::minValue(old_bounds[2], quad->m_z);
old_bounds[3] = Math::maxValue(old_bounds[3], quad->m_z);
if (quad->m_x < from_quad_x || quad->m_x > to_quad_x || quad->m_z < from_quad_z || quad->m_z > to_quad_z)
{
m_free_grass_quads.push(m_grass_quads[i]);
m_grass_quads.eraseFast(i);
}
}
from_quad_x = Math::maxValue(0.0f, from_quad_x);
from_quad_z = Math::maxValue(0.0f, from_quad_z);
for (float quad_z = from_quad_z; quad_z <= to_quad_z; quad_z += GRASS_QUAD_SIZE)
{
for (float quad_x = from_quad_x; quad_x <= to_quad_x; quad_x += GRASS_QUAD_SIZE)
{
if (quad_x < old_bounds[0] || quad_x > old_bounds[1] || quad_z < old_bounds[2] || quad_z > old_bounds[3])
{
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;
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 (float dz = 0; dz < GRASS_QUAD_SIZE; dz += 0.333f)
{
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;
}
}
}
}
}
m_last_camera_position = camera_position;
}
}
void Terrain::grassVertexCopyCallback(Array<uint8_t>& data)
{
bool has_matrix_index_attribute = m_grass_model->getGeometry()->getVertexDefinition().getAttributeType(3) == VertexAttributeDef::INT1;
if (has_matrix_index_attribute)
{
int vertex_size = m_grass_model->getGeometry()->getVertexDefinition().getVertexSize();
int one_size = vertex_size * m_grass_model->getGeometry()->getVertices().size();
const int i1_offset = 3 * sizeof(float) + 3 * sizeof(float) + 2 * sizeof(float);
for (int i = 0; i < COPY_COUNT; ++i)
{
for (int j = 0; j < m_grass_model->getGeometry()->getVertices().size(); ++j)
{
data[i * one_size + j * vertex_size + i1_offset] = (uint8_t)i;
}
}
}
else
{
g_log_error.log("renderer") << "Mesh " << m_grass_model->getPath().c_str() << " is not a grass mesh - wrong format";
}
}
void Terrain::grassIndexCopyCallback(Array<int>& data)
{
int indices_count = m_grass_model->getGeometry()->getIndices().size();
int index_offset = m_grass_model->getGeometry()->getVertices().size();
for (int i = 0; i < COPY_COUNT; ++i)
{
for (int j = 0, c = indices_count; j < c; ++j)
{
data[i * indices_count + j] += index_offset * i;
}
}
}
void Terrain::grassLoaded(Resource::State, Resource::State)
{
if (m_grass_model->isReady())
{
LUMIX_DELETE(m_grass_geometry);
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);
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");
}
}
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)
{
for (int k = 0, kc = m_grass_quads[i]->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_matrix_count = COPY_COUNT;
info.m_mesh_copy_count = COPY_COUNT;
}
if (m_grass_quads[i]->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_mesh_copy_count = COPY_COUNT;
}
}
}
}
@ -202,6 +418,8 @@ 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);
universe.addComponent(m_entity, TERRAIN_HASH, &scene, index);
}
@ -213,6 +431,7 @@ namespace Lumix
serializer.serializeArrayItem(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() : "");
}
@ -221,9 +440,37 @@ namespace Lumix
if (m_root)
{
m_material->apply(renderer, pipeline);
Matrix world_matrix;
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", camera_pos);
m_root->render(m_mesh, m_geometry, camera_pos, *pipeline.getScene());
m_mesh->getMaterial()->getShader()->setUniform("camera_pos", rel_cam_pos);
m_root->render(m_mesh, m_geometry, rel_cam_pos, *pipeline.getScene());
}
}
float Terrain::getHeight(float x, float z)
{
int int_x = (int)x;
int int_z = (int)z;
float dec_x = x - int_x;
float dec_z = z - int_z;
if (dec_x > dec_z)
{
float h0 = getHeight(int_x, int_z);
float h1 = getHeight(int_x + 1, int_z);
float h2 = getHeight(int_x + 1, int_z + 1);
return h0 + (h1 - h0) * dec_x + (h2 - h1) * dec_z;
}
else
{
float h0 = getHeight(int_x, int_z);
float h1 = getHeight(int_x + 1, int_z + 1);
float h2 = getHeight(int_x, int_z + 1);
return h0 + (h2 - h0) * dec_z + (h1 - h2) * dec_x;
}
}
@ -231,10 +478,10 @@ namespace Lumix
float Terrain::getHeight(int x, int z)
{
Texture* t = m_material->getTexture(0);
int idx = x + z * m_width;
int idx = Math::clamp(x, 0, m_width) + Math::clamp(z, 0, m_height) * m_width;
if (t->getBytesPerPixel() == 2)
{
return ((m_y_scale / (256.0f * 256.0f)) * ((uint16_t*)t->getData())[idx]);
return ((m_y_scale / (256.0f * 256.0f - 1)) * ((uint16_t*)t->getData())[idx]);
}
else if(t->getBytesPerPixel() == 4)
{
@ -242,7 +489,7 @@ namespace Lumix
}
else
{
ASSERT(false); TODO("todo");
ASSERT(false);
}
return 0;
}
@ -304,12 +551,11 @@ namespace Lumix
if (Math::getRayAABBIntersection(rel_origin, rel_dir, m_root->m_min, size, start))
{
Vec3 p = start;
while (p.x >= m_root->m_min.x && p.x <= m_root->m_min.x + m_root->m_size * m_xz_scale
&& p.z >= m_root->m_min.z && p.z <= m_root->m_min.z + m_root->m_size * m_xz_scale)
int hx = (int)(p.x / m_xz_scale);
int hz = (int)(p.z / m_xz_scale);
while (hx >= 0 && hz >= 0 && hx < m_width - 1 && hz < m_height - 1 && p.y > m_root->m_min.y && p.y < m_root->m_min.y + m_root->m_size)
{
float t;
int hx = (int)(p.x / m_xz_scale);
int hz = (int)(p.z / m_xz_scale);
float x = hx * m_xz_scale;
float z = hz * m_xz_scale;
Vec3 p0(x, getHeight(hx, hz), z);
@ -332,7 +578,9 @@ namespace Lumix
hit.m_t = t;
return hit;
}
p += dir;
p += rel_dir;
hx = (int)(p.x / m_xz_scale);
hz = (int)(p.z / m_xz_scale);
}
}
}

View file

@ -26,7 +26,21 @@ struct TerrainQuad;
class Terrain
{
public:
Terrain(const Entity& entity);
class GrassQuad
{
public:
Array<Matrix> m_matrices;
float m_x;
float m_z;
};
public:
static const int GRASS_QUADS_WIDTH = 5;
static const int GRASS_QUADS_HEIGHT = 5;
static const int GRASS_QUAD_SIZE = 10;
public:
Terrain(const Entity& entity, RenderScene& scene);
~Terrain();
void render(Renderer& renderer, PipelineInstance& pipeline, const Vec3& camera_pos);
@ -40,12 +54,21 @@ 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 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; }
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);
private:
Mesh* m_mesh;
@ -58,6 +81,15 @@ 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<GrassQuad*> m_free_grass_quads;
Array<GrassQuad*> m_grass_quads;
Vec3 m_last_camera_position;
Vec3 m_brush_position;
float m_brush_size;
};

File diff suppressed because it is too large Load diff

View file

@ -26,14 +26,18 @@ class LUMIX_ENGINE_API Texture : public Resource
int getHeight() const { return m_height; }
int getBytesPerPixel() const { return m_BPP; }
const uint8_t* getData() const { return m_data.empty() ? NULL : &m_data[0]; }
uint8_t* getData() { return m_data.empty() ? NULL : &m_data[0]; }
void addDataReference();
void removeDataReference();
void onDataUpdated();
void save();
private:
void loaded(FS::IFile* file, bool success, FS::FileSystem& fs);
bool loadDDS(FS::IFile& file);
bool loadTGA(FS::IFile& file);
bool loadRaw(FS::IFile& file);
void saveTGA();
virtual void doUnload(void) override;
virtual FS::ReadCallback getReadCallback() override;
@ -45,6 +49,7 @@ class LUMIX_ENGINE_API Texture : public Resource
int m_BPP;
int m_data_reference;
Array<uint8_t> m_data;
bool m_is_cubemap;
};

View file

@ -220,6 +220,7 @@ struct PhysicsSceneImpl : public PhysicsScene
m_actors.push(actor);
actor->m_source = "";
actor->m_entity = entity;
actor->m_physx_actor = NULL;
Component cmp = m_universe->addComponent(entity, MESH_ACTOR_HASH, this, m_actors.size() - 1);
m_universe->componentCreated().invoke(cmp);
@ -295,7 +296,7 @@ struct PhysicsSceneImpl : public PhysicsScene
{
bool is_dynamic = false;
getIsDynamic(cmp, is_dynamic);
if (m_actors[cmp.index]->m_source == str && is_dynamic == !m_actors[cmp.index]->m_physx_actor->isRigidStatic())
if (m_actors[cmp.index]->m_source == str && (!m_actors[cmp.index]->m_physx_actor || is_dynamic == !m_actors[cmp.index]->m_physx_actor->isRigidStatic()))
{
return;
}
@ -308,7 +309,7 @@ struct PhysicsSceneImpl : public PhysicsScene
cmp.entity.getMatrix(mtx);
matrix2Transform(mtx, transform);
if (m_actors[cmp.index])
if (m_actors[cmp.index] && m_actors[cmp.index]->m_physx_actor)
{
m_scene->removeActor(*m_actors[cmp.index]->m_physx_actor);
m_actors[cmp.index]->m_physx_actor->release();
@ -539,15 +540,16 @@ struct PhysicsSceneImpl : public PhysicsScene
if (bytes_per_pixel == 2)
{
PROFILE_BLOCK("copyData");
const uint16_t* data = (const uint16_t*)terrain->m_heightmap->getData();
const uint16_t* LUMIX_RESTRICT data = (const uint16_t*)terrain->m_heightmap->getData();
for (int j = 0; j < height; ++j)
{
int idx = j * width;
for (int i = 0; i < width; ++i)
{
int idx = i + j * width;
int idx2 = j + i * height;
heights[idx].height = data[idx2];
heights[idx].materialIndex0 = heights[idx].materialIndex1 = 0;
++idx;
}
}
}
@ -569,42 +571,45 @@ struct PhysicsSceneImpl : public PhysicsScene
//terrain->m_heightmap->removeDataReference();
physx::PxHeightFieldDesc hfDesc;
hfDesc.format = physx::PxHeightFieldFormat::eS16_TM;
hfDesc.nbColumns = width;
hfDesc.nbRows = height;
hfDesc.samples.data = &heights[0];
hfDesc.samples.stride = sizeof(physx::PxHeightFieldSample);
hfDesc.thickness = -1;
{ // PROFILE_BLOCK scope
PROFILE_BLOCK("PhysX");
physx::PxHeightFieldDesc hfDesc;
hfDesc.format = physx::PxHeightFieldFormat::eS16_TM;
hfDesc.nbColumns = width;
hfDesc.nbRows = height;
hfDesc.samples.data = &heights[0];
hfDesc.samples.stride = sizeof(physx::PxHeightFieldSample);
hfDesc.thickness = -1;
physx::PxHeightField* heightfield = m_system->m_impl->m_physics->createHeightField(hfDesc);
float height_scale = bytes_per_pixel == 2 ? 1 / (256 * 256.0f) : 1 / 255.0f;
physx::PxHeightFieldGeometry hfGeom(heightfield, physx::PxMeshGeometryFlags(), height_scale * terrain->m_y_scale, terrain->m_xz_scale, terrain->m_xz_scale);
if (terrain->m_actor)
{
physx::PxRigidActor* actor = terrain->m_actor;
m_scene->removeActor(*actor);
actor->release();
terrain->m_actor = NULL;
}
physx::PxHeightField* heightfield = m_system->m_impl->m_physics->createHeightField(hfDesc);
float height_scale = bytes_per_pixel == 2 ? 1 / (256 * 256.0f - 1) : 1 / 255.0f;
physx::PxHeightFieldGeometry hfGeom(heightfield, physx::PxMeshGeometryFlags(), height_scale * terrain->m_y_scale, terrain->m_xz_scale, terrain->m_xz_scale);
if (terrain->m_actor)
{
physx::PxRigidActor* actor = terrain->m_actor;
m_scene->removeActor(*actor);
actor->release();
terrain->m_actor = NULL;
}
physx::PxTransform transform;
Matrix mtx;
terrain->m_entity.getMatrix(mtx);
matrix2Transform(mtx, transform);
physx::PxTransform transform;
Matrix mtx;
terrain->m_entity.getMatrix(mtx);
matrix2Transform(mtx, transform);
physx::PxRigidActor* actor;
actor = PxCreateStatic(*m_system->m_impl->m_physics, transform, hfGeom, *m_default_material);
if (actor)
{
actor->setActorFlag(physx::PxActorFlag::eVISUALIZATION, width <= 1024);
actor->userData = (void*)terrain->m_entity.index;
m_scene->addActor(*actor);
terrain->m_actor = actor;
}
else
{
g_log_error.log("PhysX") << "Could not create PhysX heightfield " << terrain->m_heightmap->getPath().c_str();
physx::PxRigidActor* actor;
actor = PxCreateStatic(*m_system->m_impl->m_physics, transform, hfGeom, *m_default_material);
if (actor)
{
actor->setActorFlag(physx::PxActorFlag::eVISUALIZATION, width <= 1024);
actor->userData = (void*)terrain->m_entity.index;
m_scene->addActor(*actor);
terrain->m_actor = actor;
}
else
{
g_log_error.log("PhysX") << "Could not create PhysX heightfield " << terrain->m_heightmap->getPath().c_str();
}
}
}
@ -984,12 +989,12 @@ PhysicsScene* PhysicsScene::create(PhysicsSystem& system, Universe& universe, En
return NULL;
}
//impl->m_scene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);
/*impl->m_scene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);
impl->m_scene->setVisualizationParameter(physx::PxVisualizationParameter::eSCALE, 1.0);
impl->m_scene->setVisualizationParameter(physx::PxVisualizationParameter::eACTOR_AXES, 1.0f);
impl->m_scene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_AABBS, 1.0f);
impl->m_scene->setVisualizationParameter(physx::PxVisualizationParameter::eWORLD_AXES, 1.0f);
impl->m_scene->setVisualizationParameter(physx::PxVisualizationParameter::eCONTACT_POINT, 1.0f);
impl->m_scene->setVisualizationParameter(physx::PxVisualizationParameter::eCONTACT_POINT, 1.0f);*/
impl->m_system = &system;
impl->m_default_material = impl->m_system->m_impl->m_physics->createMaterial(0.5,0.5,0.5);
return impl;

View file

@ -5,7 +5,7 @@
#include "cooking/PxCooking.h"
#include "core/crc32.h"
#include "core/log.h"
#include "editor/editor_server.h"
#include "editor/world_editor.h"
#include "editor/property_descriptor.h"
#include "engine/engine.h"
#include "physics/physics_scene.h"
@ -68,6 +68,12 @@ void PhysicsSystem::sendMessage(const char* message)
}
void PhysicsSystem::destroyComponent(const Component& component)
{
ASSERT(false);
}
Component PhysicsSystem::createComponent(uint32_t component_type, const Entity& entity)
{
if (component_type == HEIGHTFIELD_HASH)
@ -121,16 +127,16 @@ class AssertNullAllocator : public physx::PxAllocatorCallback
bool PhysicsSystem::create(Engine& engine)
{
engine.getEditorServer()->registerProperty("box_rigid_actor", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("dynamic"), &PhysicsScene::getIsDynamic, &PhysicsScene::setIsDynamic));
engine.getEditorServer()->registerProperty("box_rigid_actor", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("size"), &PhysicsScene::getHalfExtents, &PhysicsScene::setHalfExtents));
engine.getEditorServer()->registerProperty("mesh_rigid_actor", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("source"), &PhysicsScene::getShapeSource, &PhysicsScene::setShapeSource, IPropertyDescriptor::FILE));
engine.getEditorServer()->registerProperty("physical_heightfield", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("heightmap"), &PhysicsScene::getHeightmap, &PhysicsScene::setHeightmap, IPropertyDescriptor::FILE));
engine.getEditorServer()->registerProperty("physical_heightfield", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("xz_scale"), &PhysicsScene::getHeightmapXZScale, &PhysicsScene::setHeightmapXZScale));
engine.getEditorServer()->registerProperty("physical_heightfield", LUMIX_NEW(PropertyDescriptor<PhysicsScene>)(crc32("y_scale"), &PhysicsScene::getHeightmapYScale, &PhysicsScene::setHeightmapYScale));
engine.getEditorServer()->registerCreator(HEIGHTFIELD_HASH, *this);
engine.getEditorServer()->registerCreator(BOX_ACTOR_HASH, *this);
engine.getEditorServer()->registerCreator(MESH_ACTOR_HASH, *this);
engine.getEditorServer()->registerCreator(CONTROLLER_HASH, *this);
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);
m_impl = LUMIX_NEW(PhysicsSystemImpl);
m_impl->m_allocator = LUMIX_NEW(AssertNullAllocator)();

View file

@ -24,6 +24,7 @@ class LUMIX_PHYSICS_API PhysicsSystem : public IPlugin
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;

View file

@ -6,7 +6,7 @@
#include "core/json_serializer.h"
#include "core/log.h"
#include "core/array.h"
#include "editor/editor_server.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "universe/universe.h"
#include "base_script.h"
@ -263,8 +263,8 @@ namespace Lumix
virtual bool create(Engine& engine) override
{
m_engine = &engine;
engine.getEditorServer()->registerProperty("script", LUMIX_NEW(PropertyDescriptor<ScriptSystem>)(crc32("source"), &ScriptSystem::getScriptPath, &ScriptSystem::setScriptPath, IPropertyDescriptor::FILE));
engine.getEditorServer()->registerCreator(SCRIPT_HASH, *this);
engine.getWorldEditor()->registerProperty("script", LUMIX_NEW(PropertyDescriptor<ScriptSystem>)(crc32("source"), &ScriptSystem::getScriptPath, &ScriptSystem::setScriptPath, IPropertyDescriptor::FILE));
engine.getWorldEditor()->registerCreator(SCRIPT_HASH, *this);
return true;
}
@ -275,6 +275,12 @@ namespace Lumix
}
virtual void destroyComponent(const Component&) override
{
ASSERT(false);
}
virtual Component createComponent(uint32_t type, const Entity& entity) override
{
if (type == SCRIPT_HASH)

View file

@ -34,18 +34,16 @@ Universe::Universe()
}
Entity Universe::createEntity()
{
if(m_free_slots.empty())
{
m_positions.push(Vec3(0, 0, 0));
m_rotations.push(Quat(0, 0, 0, 1));
m_component_list.pushEmpty();
return Entity(this, m_positions.size() - 1);
Entity e(this, m_positions.size() - 1);
m_entity_created.invoke(e);
return e;
}
else
{
@ -54,6 +52,7 @@ Entity Universe::createEntity()
m_positions[e.index].set(0, 0, 0);
m_rotations[e.index].set(0, 0, 0, 1);
m_component_list[e.index].clear();
m_entity_created.invoke(e);
return e;
}
}

View file

@ -44,14 +44,14 @@ class LUMIX_ENGINE_API Universe final
int getEntityCount() const { return m_positions.size(); }
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(Component&)>& componentDestroyed() { return m_component_destroyed; }
DelegateList<void(const Component&)>& componentDestroyed() { return m_component_destroyed; }
void serialize(ISerializer& serializer);
void deserialize(ISerializer& serializer);
private:
void onEvent(Event& event);
@ -61,9 +61,10 @@ class LUMIX_ENGINE_API Universe final
Array<int> m_free_slots;
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(Component&)> m_component_destroyed;
DelegateList<void(const Component&)> m_component_destroyed;
};