terrain editor - WIP

This commit is contained in:
Mikulas Florek 2014-08-02 01:56:37 +02:00
parent e0e0611d9f
commit 30296d20ae
10 changed files with 193 additions and 111 deletions

View file

@ -444,22 +444,33 @@ void PropertyView::on_editScriptClicked()
void PropertyView::addTerrainCustomProperties() void PropertyView::addTerrainCustomProperties()
{ {
/*QTreeWidgetItem* tools_item = new QTreeWidgetItem(QStringList() << "Tools"); QSlider* slider = new QSlider(Qt::Orientation::Horizontal);
m_ui->propertyList->topLevelItem(0)->insertChild(0, tools_item); QTreeWidgetItem* item = new QTreeWidgetItem(QStringList() << "Brush size");
QWidget* widget = new QWidget(); m_ui->propertyList->topLevelItem(0)->insertChild(0, item);
QHBoxLayout* layout = new QHBoxLayout(widget); m_ui->propertyList->setItemWidget(item, 1, slider);
layout->setContentsMargins(0, 0, 0, 0); slider->setMinimum(1);
QPushButton* compile_button = new QPushButton("Play/Pause", widget); slider->setMaximum(100);
QSlider* slider = new QSlider(Qt::Orientation::Horizontal, widget); connect(slider, &QSlider::valueChanged, this, &PropertyView::on_terrainBrushSizeChanged);
slider->setObjectName("animation_frame_slider");
slider->setMinimum(0); slider = new QSlider(Qt::Orientation::Horizontal);
int frame_count = static_cast<Lumix::AnimationSystem*>(cmp.system)->getFrameCount(cmp); item = new QTreeWidgetItem(QStringList() << "Brush strength");
slider->setMaximum(frame_count); m_ui->propertyList->topLevelItem(0)->insertChild(1, item);
layout->addWidget(compile_button); m_ui->propertyList->setItemWidget(item, 1, slider);
layout->addWidget(slider); slider->setMinimum(-100);
m_ui->propertyList->setItemWidget(tools_item, 1, widget); slider->setMaximum(100);
connect(compile_button, &QPushButton::clicked, this, &PropertyView::on_animablePlayPause); connect(slider, &QSlider::valueChanged, this, &PropertyView::on_terrainBrushStrengthChanged);
connect(slider, &QSlider::valueChanged, this, &PropertyView::on_animableTimeSet);*/ }
void PropertyView::on_terrainBrushStrengthChanged(int value)
{
m_server->setTerrainBrushStrength(value / 50000.0f);
}
void PropertyView::on_terrainBrushSizeChanged(int value)
{
m_server->setTerrainBrushSize(value);
} }
@ -596,23 +607,6 @@ void PropertyView::updateValues()
Lumix::Component animable = m_selected_entity.getComponent(crc32("animable")); Lumix::Component animable = m_selected_entity.getComponent(crc32("animable"));
if (animable.isValid()) if (animable.isValid())
{ {
#if 0
QTreeWidgetItem* tools_item = new QTreeWidgetItem(QStringList() << "Tools");
m_ui->propertyList->topLevelItem(0)->insertChild(0, tools_item);
QWidget* widget = new QWidget();
QHBoxLayout* layout = new QHBoxLayout(widget);
layout->setContentsMargins(0, 0, 0, 0);
QPushButton* compile_button = new QPushButton("Play/Pause", widget);
QSlider* slider = new QSlider(Qt::Orientation::Horizontal, widget);
slider->s
slider->setMinimum(0);
slider->setMaximum(100);
layout->addWidget(compile_button);
layout->addWidget(slider);
m_ui->propertyList->setItemWidget(tools_item, 1, widget);
connect(compile_button, &QPushButton::clicked, this, &PropertyView::on_animablePlayPause);
connect(slider, &QSlider::valueChanged, this, &PropertyView::on_animableTimeSet);
#endif
int frame_count = static_cast<Lumix::AnimationSystem*>(animable.system)->getFrameCount(animable); int frame_count = static_cast<Lumix::AnimationSystem*>(animable.system)->getFrameCount(animable);
m_ui->propertyList->findChild<QSlider*>("animation_frame_slider")->setMaximum(frame_count); m_ui->propertyList->findChild<QSlider*>("animation_frame_slider")->setMaximum(frame_count);
} }

View file

@ -67,6 +67,8 @@ private slots:
void on_editScriptClicked(); void on_editScriptClicked();
void on_animablePlayPause(); void on_animablePlayPause();
void on_animableTimeSet(int value); void on_animableTimeSet(int value);
void on_terrainBrushSizeChanged(int value);
void on_terrainBrushStrengthChanged(int value);
private: private:
void clear(); void clear();

View file

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TerrainEditor</class>
<widget class="QWidget" name="TerrainEditor">
<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>
<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="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>+</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Brush size</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="brushSizeSlider">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>-</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -17,6 +17,8 @@
#include "core/map.h" #include "core/map.h"
#include "core/matrix.h" #include "core/matrix.h"
#include "core/profiler.h" #include "core/profiler.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "editor/editor_icon.h" #include "editor/editor_icon.h"
#include "editor/gizmo.h" #include "editor/gizmo.h"
#include "editor/property_descriptor.h" #include "editor/property_descriptor.h"
@ -24,9 +26,11 @@
#include "engine/iplugin.h" #include "engine/iplugin.h"
#include "engine/plugin_manager.h" #include "engine/plugin_manager.h"
#include "graphics/irender_device.h" #include "graphics/irender_device.h"
#include "graphics/material.h"
#include "graphics/model.h" #include "graphics/model.h"
#include "graphics/pipeline.h" #include "graphics/pipeline.h"
#include "graphics/renderer.h" #include "graphics/renderer.h"
#include "graphics/texture.h"
#include "core/input_system.h" #include "core/input_system.h"
#include "core/MT/mutex.h" #include "core/MT/mutex.h"
#include "script/script_system.h" #include "script/script_system.h"
@ -185,18 +189,138 @@ struct WorldEditorImpl : public WorldEditor
} }
else if (hit.m_is_hit) else if (hit.m_is_hit)
{ {
selectEntity(hit.m_component.entity); onEntityMouseDown(hit, x, y);
m_mouse_mode = MouseMode::TRANSFORM;
m_gizmo.startTransform(m_camera.getComponent(CAMERA_HASH), x, y, Gizmo::TransformMode::CAMERA_XZ);
} }
} }
} }
void addTerrainLevel(Component terrain, const RayCastModelHit& hit, float rel_amount, float radius)
{
string material_path;
static_cast<RenderScene*>(terrain.system)->getTerrainMaterial(hit.m_component, material_path);
Material* material = static_cast<Material*>(m_engine.getResourceManager().get(ResourceManager::MATERIAL)->get(material_path));
Vec3 hit_pos = hit.m_origin + hit.m_dir * hit.m_t;
Texture* heightmap = material->getTexture(0);
heightmap = heightmap;
Matrix entity_mtx = hit.m_component.entity.getMatrix();
entity_mtx.fastInverse();
Vec3 local_pos = entity_mtx.multiplyPosition(hit_pos);
int w = heightmap->getWidth();
if (heightmap->getBytesPerPixel() == 4)
{
int from_x = Math::maxValue((int)(local_pos.x - radius), 0);
int to_x = Math::minValue((int)(local_pos.x + radius), heightmap->getWidth());
int from_z = Math::maxValue((int)(local_pos.z - radius), 0);
int to_z = Math::minValue((int)(local_pos.z + radius), heightmap->getHeight());
float amount = rel_amount * 255;
for (int i = from_x, end = to_x; i < end; ++i)
{
for (int j = from_z, end2 = to_z; j < end2; ++j)
{
float dist = sqrt((local_pos.x - i) * (local_pos.x - i) + (local_pos.z - j) * (local_pos.z - j));
float add_rel = 1.0f - Math::minValue(dist / radius, 1.0f);
uint8_t add = (uint8_t)(add_rel * amount);
add = Math::minValue(add, (uint8_t)(255 - heightmap->getData()[4 * (i + j * w)]));
heightmap->getData()[4 * (i + j * w)] += add;
heightmap->getData()[4 * (i + j * w) + 1] += add;
heightmap->getData()[4 * (i + j * w) + 2] += add;
heightmap->getData()[4 * (i + j * w) + 3] += add;
}
}
}
else if (heightmap->getBytesPerPixel() == 2)
{
uint16_t* data = reinterpret_cast<uint16_t*>(heightmap->getData());
int from_x = Math::maxValue((int)(local_pos.x - radius), 0);
int to_x = Math::minValue((int)(local_pos.x + radius), heightmap->getWidth());
int from_z = Math::maxValue((int)(local_pos.z - radius), 0);
int to_z = Math::minValue((int)(local_pos.z + radius), heightmap->getHeight());
float amount = rel_amount * (256 * 256 - 1);
for (int i = from_x, end = to_x; i < end; ++i)
{
for (int j = from_z, end2 = to_z; j < end2; ++j)
{
float dist = sqrt((local_pos.x - i) * (local_pos.x - i) + (local_pos.z - j) * (local_pos.z - j));
float add_rel = 1.0f - Math::minValue(dist / radius, 1.0f);
uint16_t add = (uint16_t)(add_rel * amount);
if (rel_amount > 0)
{
add = Math::minValue(add, (uint16_t)((256 * 256 - 1) - data[i + j * w]));
}
else if ((uint16_t)(data[i + j * w] + add) > data[i + j * w])
{
add = (uint16_t)0 - data[i + j * w];
}
data[i + j * w] = data[i + j * w] + add;
}
}
}
else
{
ASSERT(false);
}
heightmap->onDataUpdated();
}
void onEntityMouseDown(const RayCastModelHit& hit, int x, int y)
{
Entity entity = hit.m_component.entity;
if (m_selected_entity == entity)
{
Component terrain = entity.getComponent(TERRAIN_HASH);
if (terrain.isValid())
{
Vec3 hit_pos = hit.m_origin + hit.m_dir * hit.m_t;
m_mouse_mode = MouseMode::CUSTOM;
addTerrainLevel(terrain, hit, m_terrain_brush_strength, (float)m_terrain_brush_size);
}
}
else
{
selectEntity(entity);
m_mouse_mode = MouseMode::TRANSFORM;
m_gizmo.startTransform(m_camera.getComponent(CAMERA_HASH), x, y, Gizmo::TransformMode::CAMERA_XZ);
}
}
virtual void setTerrainBrushStrength(float value) override
{
m_terrain_brush_strength = value;
}
virtual void setTerrainBrushSize(int value) override
{
m_terrain_brush_size = value;
}
virtual void onMouseMove(int x, int y, int relx, int rely, int mouse_flags) override virtual void onMouseMove(int x, int y, int relx, int rely, int mouse_flags) override
{ {
switch (m_mouse_mode) switch (m_mouse_mode)
{ {
case MouseMode::CUSTOM:
{
Component terrain = m_selected_entity.getComponent(TERRAIN_HASH);
Component camera_cmp = m_camera.getComponent(CAMERA_HASH);
RenderScene* scene = static_cast<RenderScene*>(camera_cmp.system);
Vec3 origin, dir;
scene->getRay(camera_cmp, (float)x, (float)y, origin, dir);
RayCastModelHit hit = scene->castRay(origin, dir);
if (hit.m_is_hit)
{
addTerrainLevel(terrain, hit, m_terrain_brush_strength, (float)m_terrain_brush_size);
}
}
break;
case MouseMode::NAVIGATE: case MouseMode::NAVIGATE:
rotateCamera(relx, rely); rotateCamera(relx, rely);
break; break;
@ -506,6 +630,8 @@ struct WorldEditorImpl : public WorldEditor
m_selected_entity = Entity::INVALID; m_selected_entity = Entity::INVALID;
m_edit_view_render_device = NULL; m_edit_view_render_device = NULL;
m_universe_path = ""; m_universe_path = "";
m_terrain_brush_size = 10;
m_terrain_brush_strength = 0.01f;
} }
@ -722,7 +848,8 @@ struct WorldEditorImpl : public WorldEditor
NONE, NONE,
SELECT, SELECT,
NAVIGATE, NAVIGATE,
TRANSFORM TRANSFORM,
CUSTOM
}; };
}; };
@ -750,6 +877,8 @@ struct WorldEditorImpl : public WorldEditor
bool m_toggle_game_mode_requested; bool m_toggle_game_mode_requested;
Path m_universe_path; Path m_universe_path;
Path m_base_path; Path m_base_path;
int m_terrain_brush_size;
float m_terrain_brush_strength;
}; };

View file

@ -65,6 +65,8 @@ namespace Lumix
virtual void setWireframe(bool is_wireframe) = 0; virtual void setWireframe(bool is_wireframe) = 0;
virtual void lookAtSelected() = 0; virtual void lookAtSelected() = 0;
virtual const char* getBasePath() = 0; virtual const char* getBasePath() = 0;
virtual void setTerrainBrushSize(int value) = 0;
virtual void setTerrainBrushStrength(float value) = 0;
virtual Entity getSelectedEntity() const = 0; virtual Entity getSelectedEntity() const = 0;
virtual const IPropertyDescriptor& getPropertyDescriptor(uint32_t type, uint32_t name_hash) = 0; virtual const IPropertyDescriptor& getPropertyDescriptor(uint32_t type, uint32_t name_hash) = 0;
virtual DelegateList<void(Entity&)>& entitySelected() = 0; virtual DelegateList<void(Entity&)>& entitySelected() = 0;

View file

@ -304,12 +304,11 @@ namespace Lumix
if (Math::getRayAABBIntersection(rel_origin, rel_dir, m_root->m_min, size, start)) if (Math::getRayAABBIntersection(rel_origin, rel_dir, m_root->m_min, size, start))
{ {
Vec3 p = 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 int hx = (int)(p.x / 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 hz = (int)(p.z / m_xz_scale);
while (hx >= 0 && hz >= 0 && hx < m_width - 1 && hz < m_height - 1)
{ {
float t; 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 x = hx * m_xz_scale;
float z = hz * m_xz_scale; float z = hz * m_xz_scale;
Vec3 p0(x, getHeight(hx, hz), z); Vec3 p0(x, getHeight(hx, hz), z);
@ -332,7 +331,9 @@ namespace Lumix
hit.m_t = t; hit.m_t = t;
return hit; return hit;
} }
p += dir; p += rel_dir;
hx = (int)(p.x / m_xz_scale);
hz = (int)(p.z / m_xz_scale);
} }
} }
} }

View file

@ -449,6 +449,24 @@ void Texture::apply(int unit)
} }
void Texture::onDataUpdated()
{
glBindTexture(GL_TEXTURE_2D, m_id);
if (m_BPP == 4)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &m_data[0]);
}
else if (m_BPP == 2)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, m_width, m_height, 0, GL_RED, GL_UNSIGNED_SHORT, &m_data[0]);
}
else
{
ASSERT(false);
}
}
bool Texture::loadRaw(FS::IFile& file) bool Texture::loadRaw(FS::IFile& file)
{ {
PROFILE_FUNCTION(); PROFILE_FUNCTION();

View file

@ -26,8 +26,10 @@ class LUMIX_ENGINE_API Texture : public Resource
int getHeight() const { return m_height; } int getHeight() const { return m_height; }
int getBytesPerPixel() const { return m_BPP; } int getBytesPerPixel() const { return m_BPP; }
const uint8_t* getData() const { return m_data.empty() ? NULL : &m_data[0]; } 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 addDataReference();
void removeDataReference(); void removeDataReference();
void onDataUpdated();
private: private:
void loaded(FS::IFile* file, bool success, FS::FileSystem& fs); void loaded(FS::IFile* file, bool success, FS::FileSystem& fs);

View file

@ -582,7 +582,7 @@ struct PhysicsSceneImpl : public PhysicsScene
hfDesc.thickness = -1; hfDesc.thickness = -1;
physx::PxHeightField* heightfield = m_system->m_impl->m_physics->createHeightField(hfDesc); 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; 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); physx::PxHeightFieldGeometry hfGeom(heightfield, physx::PxMeshGeometryFlags(), height_scale * terrain->m_y_scale, terrain->m_xz_scale, terrain->m_xz_scale);
if (terrain->m_actor) if (terrain->m_actor)
{ {