Grass independant on the ground texture - closes #1024
This commit is contained in:
parent
03747c71fe
commit
8d4f290819
7 changed files with 171 additions and 112 deletions
|
@ -64,7 +64,7 @@ struct PaintTerrainCommand LUMIX_FINAL : public Lumix::IEditorCommand
|
|||
|
||||
|
||||
PaintTerrainCommand(Lumix::WorldEditor& editor,
|
||||
TerrainEditor::Type type,
|
||||
TerrainEditor::ActionType action_type,
|
||||
int texture_idx,
|
||||
const Lumix::Vec3& hit_pos,
|
||||
Lumix::BinaryArray& mask,
|
||||
|
@ -80,8 +80,9 @@ struct PaintTerrainCommand LUMIX_FINAL : public Lumix::IEditorCommand
|
|||
, m_new_data(editor.getAllocator())
|
||||
, m_old_data(editor.getAllocator())
|
||||
, m_items(editor.getAllocator())
|
||||
, m_type(type)
|
||||
, m_action_type(action_type)
|
||||
, m_texture_idx(texture_idx)
|
||||
, m_grass_idx(texture_idx)
|
||||
, m_mask(editor.getAllocator())
|
||||
, m_flat_height(flat_height)
|
||||
{
|
||||
|
@ -109,8 +110,9 @@ struct PaintTerrainCommand LUMIX_FINAL : public Lumix::IEditorCommand
|
|||
|
||||
void serialize(Lumix::JsonSerializer& serializer) override
|
||||
{
|
||||
serializer.serialize("type", (int)m_type);
|
||||
serializer.serialize("type", (int)m_action_type);
|
||||
serializer.serialize("texture_idx", m_texture_idx);
|
||||
serializer.serialize("grass_idx", m_grass_idx);
|
||||
serializer.beginArray("items");
|
||||
for (int i = 0; i < m_items.size(); ++i)
|
||||
{
|
||||
|
@ -135,10 +137,11 @@ struct PaintTerrainCommand LUMIX_FINAL : public Lumix::IEditorCommand
|
|||
void deserialize(Lumix::JsonSerializer& serializer) override
|
||||
{
|
||||
m_items.clear();
|
||||
int type;
|
||||
serializer.deserialize("type", type, 0);
|
||||
m_type = (TerrainEditor::Type)type;
|
||||
int action_type;
|
||||
serializer.deserialize("type", action_type, 0);
|
||||
m_action_type = (TerrainEditor::ActionType)action_type;
|
||||
serializer.deserialize("texture_idx", m_texture_idx, 0);
|
||||
serializer.deserialize("grass_idx", m_grass_idx, 0);
|
||||
serializer.deserializeArrayBegin("items");
|
||||
while (!serializer.isArrayEnd())
|
||||
{
|
||||
|
@ -195,7 +198,7 @@ struct PaintTerrainCommand LUMIX_FINAL : public Lumix::IEditorCommand
|
|||
return false;
|
||||
}
|
||||
PaintTerrainCommand& my_command = static_cast<PaintTerrainCommand&>(command);
|
||||
if (m_terrain == my_command.m_terrain && m_type == my_command.m_type &&
|
||||
if (m_terrain == my_command.m_terrain && m_action_type == my_command.m_action_type &&
|
||||
m_texture_idx == my_command.m_texture_idx)
|
||||
{
|
||||
my_command.m_items.push(m_items.back());
|
||||
|
@ -236,8 +239,10 @@ private:
|
|||
Lumix::Texture* getDestinationTexture()
|
||||
{
|
||||
const char* uniform_name = "";
|
||||
switch (m_type)
|
||||
switch (m_action_type)
|
||||
{
|
||||
case TerrainEditor::REMOVE_GRASS:
|
||||
case TerrainEditor::ADD_GRASS:
|
||||
case TerrainEditor::LAYER:
|
||||
uniform_name = SPLATMAP_UNIFORM;
|
||||
break;
|
||||
|
@ -365,6 +370,46 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void rasterGrassItem(Lumix::Texture* texture, Lumix::Array<Lumix::uint8>& data, Item& item, TerrainEditor::ActionType action_type)
|
||||
{
|
||||
int texture_width = texture->width;
|
||||
Rectangle r = item.getBoundingRectangle(texture_width, texture->height);
|
||||
|
||||
if (texture->bytes_per_pixel != 4)
|
||||
{
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
float fx = 0;
|
||||
float fstepx = 1.0f / (r.m_to_x - r.m_from_x);
|
||||
float fstepy = 1.0f / (r.m_to_y - r.m_from_y);
|
||||
for (int i = r.m_from_x, end = r.m_to_x; i < end; ++i, fx += fstepx)
|
||||
{
|
||||
float fy = 0;
|
||||
for (int j = r.m_from_y, end2 = r.m_to_y; j < end2; ++j, fy += fstepy)
|
||||
{
|
||||
if (isMasked(fx, fy))
|
||||
{
|
||||
int offset = 4 * (i - m_x + (j - m_y) * m_width) + 2;
|
||||
float attenuation = getAttenuation(item, i, j);
|
||||
int add = int(attenuation * item.m_amount * 255);
|
||||
if (add > 0)
|
||||
{
|
||||
if (m_action_type == TerrainEditor::REMOVE_GRASS)
|
||||
{
|
||||
data[offset] &= ~(1 << m_grass_idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
data[offset] |= 1 << m_grass_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rasterSmoothHeightItem(Lumix::Texture* texture, Lumix::Array<Lumix::uint8>& data, Item& item)
|
||||
{
|
||||
|
@ -415,22 +460,27 @@ private:
|
|||
|
||||
void rasterItem(Lumix::Texture* texture, Lumix::Array<Lumix::uint8>& data, Item& item)
|
||||
{
|
||||
if (m_type == TerrainEditor::COLOR)
|
||||
if (m_action_type == TerrainEditor::COLOR)
|
||||
{
|
||||
rasterColorItem(texture, data, item);
|
||||
return;
|
||||
}
|
||||
else if (m_type == TerrainEditor::LAYER)
|
||||
else if (m_action_type == TerrainEditor::LAYER)
|
||||
{
|
||||
rasterLayerItem(texture, data, item);
|
||||
return;
|
||||
}
|
||||
else if (m_type == TerrainEditor::SMOOTH_HEIGHT)
|
||||
else if (m_action_type == TerrainEditor::ADD_GRASS || m_action_type == TerrainEditor::REMOVE_GRASS)
|
||||
{
|
||||
rasterGrassItem(texture, data, item, m_action_type);
|
||||
return;
|
||||
}
|
||||
else if (m_action_type == TerrainEditor::SMOOTH_HEIGHT)
|
||||
{
|
||||
rasterSmoothHeightItem(texture, data, item);
|
||||
return;
|
||||
}
|
||||
else if (m_type == TerrainEditor::FLAT_HEIGHT)
|
||||
else if (m_action_type == TerrainEditor::FLAT_HEIGHT)
|
||||
{
|
||||
rasterFlatHeightItem(texture, data, item);
|
||||
return;
|
||||
|
@ -454,7 +504,7 @@ private:
|
|||
|
||||
int add = int(attenuation * amount);
|
||||
Lumix::uint16 x = ((Lumix::uint16*)texture->getData())[(i + j * texture_width)];
|
||||
x += m_type == TerrainEditor::RAISE_HEIGHT ? Lumix::Math::minimum(add, 0xFFFF - x)
|
||||
x += m_action_type == TerrainEditor::RAISE_HEIGHT ? Lumix::Math::minimum(add, 0xFFFF - x)
|
||||
: Lumix::Math::maximum(-add, -x);
|
||||
((Lumix::uint16*)&data[0])[offset] = x;
|
||||
}
|
||||
|
@ -525,7 +575,8 @@ private:
|
|||
texture->onDataUpdated(m_x, m_y, m_width, m_height);
|
||||
static_cast<Lumix::RenderScene*>(m_terrain.scene)->forceGrassUpdate(m_terrain.handle);
|
||||
|
||||
if (m_type != TerrainEditor::LAYER && m_type != TerrainEditor::COLOR)
|
||||
if (m_action_type != TerrainEditor::LAYER && m_action_type != TerrainEditor::COLOR &&
|
||||
m_action_type != TerrainEditor::ADD_GRASS && m_action_type != TerrainEditor::REMOVE_GRASS)
|
||||
{
|
||||
Lumix::IScene* scene = m_world_editor.getUniverse()->getScene(Lumix::crc32("physics"));
|
||||
if (!scene) return;
|
||||
|
@ -616,11 +667,12 @@ private:
|
|||
Lumix::Array<Lumix::uint8> m_new_data;
|
||||
Lumix::Array<Lumix::uint8> m_old_data;
|
||||
int m_texture_idx;
|
||||
int m_grass_idx;
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_x;
|
||||
int m_y;
|
||||
TerrainEditor::Type m_type;
|
||||
TerrainEditor::ActionType m_action_type;
|
||||
Lumix::Array<Item> m_items;
|
||||
Lumix::ComponentUID m_terrain;
|
||||
Lumix::WorldEditor& m_world_editor;
|
||||
|
@ -694,6 +746,11 @@ TerrainEditor::TerrainEditor(Lumix::WorldEditor& editor, StudioApp& app)
|
|||
app.addAction(m_smooth_terrain_action);
|
||||
app.addAction(m_lower_terrain_action);
|
||||
|
||||
m_remove_grass_action =
|
||||
LUMIX_NEW(editor.getAllocator(), Action)("Remove grass from terrain", "removeGrassFromTerrain");
|
||||
m_remove_grass_action->is_global = false;
|
||||
app.addAction(m_remove_grass_action);
|
||||
|
||||
m_remove_entity_action =
|
||||
LUMIX_NEW(editor.getAllocator(), Action)("Remove entities from terrain", "removeEntitiesFromTerrain");
|
||||
m_remove_entity_action->is_global = false;
|
||||
|
@ -702,8 +759,9 @@ TerrainEditor::TerrainEditor(Lumix::WorldEditor& editor, StudioApp& app)
|
|||
editor.addPlugin(*this);
|
||||
m_terrain_brush_size = 10;
|
||||
m_terrain_brush_strength = 0.1f;
|
||||
m_type = RAISE_HEIGHT;
|
||||
m_action_type = RAISE_HEIGHT;
|
||||
m_texture_idx = 0;
|
||||
m_grass_idx = 0;
|
||||
m_is_align_with_normal = false;
|
||||
m_is_rotate_x = false;
|
||||
m_is_rotate_y = false;
|
||||
|
@ -758,7 +816,7 @@ void TerrainEditor::drawCursor(Lumix::RenderScene& scene, Lumix::ComponentHandle
|
|||
{
|
||||
PROFILE_FUNCTION();
|
||||
static const int SLICE_COUNT = 30;
|
||||
if (m_type == TerrainEditor::FLAT_HEIGHT && ImGui::GetIO().KeyCtrl)
|
||||
if (m_action_type == TerrainEditor::FLAT_HEIGHT && ImGui::GetIO().KeyCtrl)
|
||||
{
|
||||
scene.addDebugCross(center, 1.0f, 0xff0000ff, 0);
|
||||
return;
|
||||
|
@ -790,34 +848,46 @@ void TerrainEditor::drawCursor(Lumix::RenderScene& scene, Lumix::ComponentHandle
|
|||
|
||||
void TerrainEditor::detectModifiers()
|
||||
{
|
||||
bool is_height_tool = m_type == LOWER_HEIGHT || m_type == RAISE_HEIGHT ||
|
||||
m_type == SMOOTH_HEIGHT;
|
||||
bool is_height_tool = m_action_type == LOWER_HEIGHT || m_action_type == RAISE_HEIGHT ||
|
||||
m_action_type == SMOOTH_HEIGHT;
|
||||
if (is_height_tool)
|
||||
{
|
||||
if (m_lower_terrain_action->isActive())
|
||||
{
|
||||
m_type = LOWER_HEIGHT;
|
||||
m_action_type = LOWER_HEIGHT;
|
||||
}
|
||||
else if (m_smooth_terrain_action->isActive())
|
||||
{
|
||||
m_type = SMOOTH_HEIGHT;
|
||||
m_action_type = SMOOTH_HEIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = RAISE_HEIGHT;
|
||||
m_action_type = RAISE_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_entity_tool = m_type == ENTITY || m_type == REMOVE_ENTITY;
|
||||
if (m_action_type == ADD_GRASS || m_action_type == REMOVE_GRASS)
|
||||
{
|
||||
if (m_remove_grass_action->isActive())
|
||||
{
|
||||
m_action_type = REMOVE_GRASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_action_type = ADD_GRASS;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_entity_tool = m_action_type == ENTITY || m_action_type == REMOVE_ENTITY;
|
||||
if (is_entity_tool)
|
||||
{
|
||||
if (m_remove_entity_action->isActive())
|
||||
{
|
||||
m_type = REMOVE_ENTITY;
|
||||
m_action_type = REMOVE_ENTITY;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = ENTITY;
|
||||
m_action_type = ENTITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -857,14 +927,14 @@ bool TerrainEditor::onEntityMouseDown(const Lumix::WorldEditor::RayHit& hit, int
|
|||
if (selected_entities.size() != 1) return false;
|
||||
bool is_terrain = m_world_editor.getUniverse()->hasComponent(selected_entities[0], TERRAIN_TYPE);
|
||||
if (!is_terrain) return false;
|
||||
if (m_type == NOT_SET || !m_component.isValid()) return false;
|
||||
if (m_action_type == NOT_SET || !m_component.isValid()) return false;
|
||||
|
||||
detectModifiers();
|
||||
|
||||
if (selected_entities[0] == hit.entity && m_component.isValid())
|
||||
{
|
||||
Lumix::Vec3 hit_pos = hit.pos;
|
||||
switch (m_type)
|
||||
switch (m_action_type)
|
||||
{
|
||||
case FLAT_HEIGHT:
|
||||
if (ImGui::GetIO().KeyCtrl)
|
||||
|
@ -873,14 +943,16 @@ bool TerrainEditor::onEntityMouseDown(const Lumix::WorldEditor::RayHit& hit, int
|
|||
}
|
||||
else
|
||||
{
|
||||
paint(hit.pos, m_type, false);
|
||||
paint(hit.pos, m_action_type, false);
|
||||
}
|
||||
break;
|
||||
case RAISE_HEIGHT:
|
||||
case LOWER_HEIGHT:
|
||||
case SMOOTH_HEIGHT:
|
||||
case REMOVE_GRASS:
|
||||
case ADD_GRASS:
|
||||
case COLOR:
|
||||
case LAYER: paint(hit.pos, m_type, false); break;
|
||||
case LAYER: paint(hit.pos, m_action_type, false); break;
|
||||
case ENTITY: paintEntities(hit.pos); break;
|
||||
case REMOVE_ENTITY: removeEntities(hit.pos); break;
|
||||
default: ASSERT(false); break;
|
||||
|
@ -1166,14 +1238,16 @@ void TerrainEditor::onMouseMove(int x, int y, int, int)
|
|||
bool is_terrain = m_world_editor.getUniverse()->hasComponent(hit.m_entity, TERRAIN_TYPE);
|
||||
if (!is_terrain) return;
|
||||
|
||||
switch (m_type)
|
||||
switch (m_action_type)
|
||||
{
|
||||
case FLAT_HEIGHT:
|
||||
case RAISE_HEIGHT:
|
||||
case LOWER_HEIGHT:
|
||||
case SMOOTH_HEIGHT:
|
||||
case REMOVE_GRASS:
|
||||
case ADD_GRASS:
|
||||
case COLOR:
|
||||
case LAYER: paint(hit.m_origin + hit.m_dir * hit.m_t, m_type, true); break;
|
||||
case LAYER: paint(hit.m_origin + hit.m_dir * hit.m_t, m_action_type, true); break;
|
||||
case ENTITY: paintEntities(hit.m_origin + hit.m_dir * hit.m_t); break;
|
||||
case REMOVE_ENTITY: removeEntities(hit.m_origin + hit.m_dir * hit.m_t); break;
|
||||
default: ASSERT(false); break;
|
||||
|
@ -1220,7 +1294,8 @@ void TerrainEditor::onGUI()
|
|||
HEIGHT,
|
||||
LAYER,
|
||||
ENTITY,
|
||||
COLOR
|
||||
COLOR,
|
||||
GRASS
|
||||
};
|
||||
|
||||
bool is_grass_enabled = scene->isGrassEnabled();
|
||||
|
@ -1228,9 +1303,9 @@ void TerrainEditor::onGUI()
|
|||
if (ImGui::Checkbox("Enable grass", &is_grass_enabled)) scene->enableGrass(is_grass_enabled);
|
||||
|
||||
if (ImGui::Combo(
|
||||
"Brush type", &m_current_brush, "Height\0Layer\0Entity\0Color\0"))
|
||||
"Brush type", &m_current_brush, "Height\0Layer\0Entity\0Color\0Grass\0"))
|
||||
{
|
||||
m_type = m_current_brush == HEIGHT ? TerrainEditor::RAISE_HEIGHT : m_type;
|
||||
m_action_type = m_current_brush == HEIGHT ? TerrainEditor::RAISE_HEIGHT : m_action_type;
|
||||
}
|
||||
|
||||
switch (m_current_brush)
|
||||
|
@ -1239,8 +1314,9 @@ void TerrainEditor::onGUI()
|
|||
if (ImGui::Button("Save heightmap"))
|
||||
getMaterial()->getTextureByUniform(HEIGHTMAP_UNIFORM)->save();
|
||||
break;
|
||||
case GRASS:
|
||||
case LAYER:
|
||||
if (ImGui::Button("Save layermap"))
|
||||
if (ImGui::Button("Save layermap and grassmap"))
|
||||
getMaterial()->getTextureByUniform(SPLATMAP_UNIFORM)->save();
|
||||
break;
|
||||
case COLOR:
|
||||
|
@ -1249,7 +1325,7 @@ void TerrainEditor::onGUI()
|
|||
break;
|
||||
}
|
||||
|
||||
if (m_current_brush == LAYER || m_current_brush == COLOR)
|
||||
if (m_current_brush == LAYER || m_current_brush == GRASS || m_current_brush == COLOR)
|
||||
{
|
||||
if (m_brush_texture)
|
||||
{
|
||||
|
@ -1308,28 +1384,42 @@ void TerrainEditor::onGUI()
|
|||
{
|
||||
case HEIGHT:
|
||||
{
|
||||
bool is_flat_tool = m_type == TerrainEditor::FLAT_HEIGHT;
|
||||
bool is_flat_tool = m_action_type == TerrainEditor::FLAT_HEIGHT;
|
||||
if (ImGui::Checkbox("Flat", &is_flat_tool))
|
||||
{
|
||||
m_type = is_flat_tool ? TerrainEditor::FLAT_HEIGHT : TerrainEditor::RAISE_HEIGHT;
|
||||
m_action_type = is_flat_tool ? TerrainEditor::FLAT_HEIGHT : TerrainEditor::RAISE_HEIGHT;
|
||||
}
|
||||
|
||||
if (m_type == TerrainEditor::FLAT_HEIGHT)
|
||||
if (m_action_type == TerrainEditor::FLAT_HEIGHT)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("- Press Ctrl to pick height");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GRASS:
|
||||
{
|
||||
m_action_type = TerrainEditor::ADD_GRASS;
|
||||
int type_count = scene->getGrassCount(m_component.handle);
|
||||
for (int i = 0; i < type_count; ++i)
|
||||
{
|
||||
if (i % 4 != 0) ImGui::SameLine();
|
||||
if (ImGui::RadioButton(Lumix::StaticString<20>("", i, "###rb", i), m_grass_idx == i))
|
||||
{
|
||||
m_grass_idx = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COLOR:
|
||||
{
|
||||
m_type = TerrainEditor::COLOR;
|
||||
m_action_type = TerrainEditor::COLOR;
|
||||
ImGui::ColorPicker(&m_color.x, false);
|
||||
break;
|
||||
}
|
||||
case LAYER:
|
||||
{
|
||||
m_type = TerrainEditor::LAYER;
|
||||
m_action_type = TerrainEditor::LAYER;
|
||||
Lumix::Texture* tex = getMaterial()->getTextureByUniform(TEX_COLOR_UNIFORM);
|
||||
if (tex)
|
||||
{
|
||||
|
@ -1346,7 +1436,7 @@ void TerrainEditor::onGUI()
|
|||
}
|
||||
case ENTITY:
|
||||
{
|
||||
m_type = TerrainEditor::ENTITY;
|
||||
m_action_type = TerrainEditor::ENTITY;
|
||||
auto& template_system = m_world_editor.getEntityTemplateSystem();
|
||||
auto& template_names = template_system.getTemplateNames();
|
||||
if (template_names.empty())
|
||||
|
@ -1433,7 +1523,7 @@ void TerrainEditor::onGUI()
|
|||
}
|
||||
|
||||
if(!m_component.isValid()) return;
|
||||
if(m_type == NOT_SET) return;
|
||||
if(m_action_type == NOT_SET) return;
|
||||
if(!m_is_enabled) return;
|
||||
|
||||
float mouse_x = m_world_editor.getMouseX();
|
||||
|
@ -1460,11 +1550,11 @@ void TerrainEditor::onGUI()
|
|||
}
|
||||
|
||||
|
||||
void TerrainEditor::paint(const Lumix::Vec3& hit_pos, Type type, bool old_stroke)
|
||||
void TerrainEditor::paint(const Lumix::Vec3& hit_pos, ActionType action_type, bool old_stroke)
|
||||
{
|
||||
PaintTerrainCommand* command = LUMIX_NEW(m_world_editor.getAllocator(), PaintTerrainCommand)(m_world_editor,
|
||||
type,
|
||||
m_texture_idx,
|
||||
action_type,
|
||||
action_type == ADD_GRASS || action_type == REMOVE_GRASS ? m_grass_idx : m_texture_idx,
|
||||
hit_pos,
|
||||
m_brush_mask,
|
||||
m_terrain_brush_size,
|
||||
|
|
|
@ -19,7 +19,7 @@ class Texture;
|
|||
class TerrainEditor LUMIX_FINAL : public Lumix::WorldEditor::Plugin
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
enum ActionType
|
||||
{
|
||||
RAISE_HEIGHT,
|
||||
LOWER_HEIGHT,
|
||||
|
@ -29,6 +29,8 @@ public:
|
|||
ENTITY,
|
||||
REMOVE_ENTITY,
|
||||
COLOR,
|
||||
ADD_GRASS,
|
||||
REMOVE_GRASS,
|
||||
NOT_SET
|
||||
};
|
||||
|
||||
|
@ -46,7 +48,7 @@ private:
|
|||
void detectModifiers();
|
||||
void drawCursor(Lumix::RenderScene& scene, Lumix::ComponentHandle cmp, const Lumix::Vec3& center);
|
||||
Lumix::Material* getMaterial();
|
||||
void paint(const Lumix::Vec3& hit, TerrainEditor::Type type, bool new_stroke);
|
||||
void paint(const Lumix::Vec3& hit, TerrainEditor::ActionType action_type, bool new_stroke);
|
||||
|
||||
static void getProjections(const Lumix::Vec3& axis,
|
||||
const Lumix::Vec3 vertices[8],
|
||||
|
@ -64,11 +66,12 @@ private:
|
|||
|
||||
private:
|
||||
Lumix::WorldEditor& m_world_editor;
|
||||
Type m_type;
|
||||
ActionType m_action_type;
|
||||
Lumix::ComponentUID m_component;
|
||||
float m_terrain_brush_strength;
|
||||
float m_terrain_brush_size;
|
||||
int m_texture_idx;
|
||||
int m_grass_idx;
|
||||
Lumix::uint16 m_flat_height;
|
||||
Lumix::Vec3 m_color;
|
||||
int m_current_brush;
|
||||
|
@ -80,6 +83,7 @@ private:
|
|||
Action* m_lower_terrain_action;
|
||||
Action* m_smooth_terrain_action;
|
||||
Action* m_remove_entity_action;
|
||||
Action* m_remove_grass_action;
|
||||
Lumix::BinaryArray m_brush_mask;
|
||||
Lumix::Texture* m_brush_texture;
|
||||
Lumix::Vec2 m_size_spread;
|
||||
|
|
|
@ -2441,18 +2441,6 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void setGrassGround(ComponentHandle cmp, int index, int ground) override
|
||||
{
|
||||
m_terrains[{cmp.index}]->setGrassTypeGround(index, ground);
|
||||
}
|
||||
|
||||
|
||||
int getGrassGround(ComponentHandle cmp, int index) override
|
||||
{
|
||||
return m_terrains[{cmp.index}]->getGrassTypeGround(index);
|
||||
}
|
||||
|
||||
|
||||
void setGrassPath(ComponentHandle cmp, int index, const Path& path) override
|
||||
{
|
||||
m_terrains[{cmp.index}]->setGrassTypePath(index, path);
|
||||
|
|
|
@ -55,6 +55,7 @@ enum class RenderSceneVersion : int32
|
|||
DECAL,
|
||||
PARTICLE_EMITTER_SUBIMAGE_MODULE,
|
||||
PARTICLE_EMITTER_LOCAL_SPACE,
|
||||
NEW_GRASS,
|
||||
|
||||
LATEST,
|
||||
INVALID = -1,
|
||||
|
@ -383,8 +384,6 @@ public:
|
|||
virtual void enableGrass(bool enabled) = 0;
|
||||
virtual void setGrassPath(ComponentHandle cmp, int index, const Path& path) = 0;
|
||||
virtual Path getGrassPath(ComponentHandle cmp, int index) = 0;
|
||||
virtual void setGrassGround(ComponentHandle cmp, int index, int ground) = 0;
|
||||
virtual int getGrassGround(ComponentHandle cmp, int index) = 0;
|
||||
virtual void setGrassDensity(ComponentHandle cmp, int index, int density) = 0;
|
||||
virtual int getGrassDensity(ComponentHandle cmp, int index) = 0;
|
||||
virtual int getGrassCount(ComponentHandle cmp) = 0;
|
||||
|
|
|
@ -407,10 +407,6 @@ static void registerProperties(IAllocator& allocator)
|
|||
"Mesh", &RenderScene::getGrassPath, &RenderScene::setGrassPath, "Mesh (*.msh)", MODEL_TYPE));
|
||||
grass->addChild(LUMIX_NEW(allocator, DecimalPropertyDescriptor<RenderScene>)(
|
||||
"Distance", &RenderScene::getGrassDistance, &RenderScene::setGrassDistance, 1.0f, FLT_MAX, 1.0f));
|
||||
auto ground = LUMIX_NEW(allocator, IntPropertyDescriptor<RenderScene>)(
|
||||
"Ground", &RenderScene::getGrassGround, &RenderScene::setGrassGround);
|
||||
ground->setLimit(0, 4);
|
||||
grass->addChild(ground);
|
||||
grass->addChild(LUMIX_NEW(allocator, IntPropertyDescriptor<RenderScene>)(
|
||||
"Density", &RenderScene::getGrassDensity, &RenderScene::setGrassDensity));
|
||||
PropertyRegister::add("terrain", grass);
|
||||
|
|
|
@ -229,13 +229,13 @@ Terrain::~Terrain()
|
|||
}
|
||||
|
||||
|
||||
Terrain::GrassType::GrassType(Terrain& terrain)
|
||||
Terrain::GrassType::GrassType(Terrain& terrain, int idx)
|
||||
: m_terrain(terrain)
|
||||
{
|
||||
m_grass_model = nullptr;
|
||||
m_ground = 0;
|
||||
m_density = 10;
|
||||
m_distance = 50;
|
||||
m_idx = idx;
|
||||
}
|
||||
|
||||
|
||||
|
@ -249,11 +249,11 @@ void Terrain::addGrassType(int index)
|
|||
{
|
||||
if(index < 0)
|
||||
{
|
||||
m_grass_types.push(LUMIX_NEW(m_allocator, GrassType)(*this));
|
||||
m_grass_types.push(LUMIX_NEW(m_allocator, GrassType)(*this, m_grass_types.size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_grass_types.insert(index, LUMIX_NEW(m_allocator, GrassType)(*this));
|
||||
m_grass_types.insert(index, LUMIX_NEW(m_allocator, GrassType)(*this, index));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,23 +301,6 @@ float Terrain::getGrassTypeDistance(int index) const
|
|||
}
|
||||
|
||||
|
||||
void Terrain::setGrassTypeGround(int index, int ground)
|
||||
{
|
||||
Lumix::Texture* tex = getMaterial()->getTextureByUniform(TEX_COLOR_UNIFORM);
|
||||
if(tex) ground = Math::clamp(ground, 0, tex->layers - 1);
|
||||
forceGrassUpdate();
|
||||
GrassType& type = *m_grass_types[index];
|
||||
type.m_ground = ground;
|
||||
}
|
||||
|
||||
|
||||
int Terrain::getGrassTypeGround(int index) const
|
||||
{
|
||||
GrassType& type = *m_grass_types[index];
|
||||
return type.m_ground;
|
||||
}
|
||||
|
||||
|
||||
AABB Terrain::getAABB() const
|
||||
{
|
||||
Vec3 min(0, 0, 0);
|
||||
|
@ -421,8 +404,8 @@ void Terrain::generateGrassTypeQuad(GrassPatch& patch, const Matrix& terrain_mat
|
|||
int tx = int(base_tx + tx_step * dx);
|
||||
uint32 pixel_value = splat_data[tx];
|
||||
|
||||
int ground_index = pixel_value & 0xff;
|
||||
if (ground_index != patch.m_type->m_ground) continue;
|
||||
int ground_mask = (pixel_value >> 16) & 0xff;
|
||||
if ((ground_mask & (1 << patch.m_type->m_idx)) == 0) continue;
|
||||
|
||||
float density = ((pixel_value >> 8) & 0xff) * DIV255;
|
||||
if (density < 0.25f) continue;
|
||||
|
@ -621,7 +604,11 @@ void Terrain::deserialize(InputBlob& serializer,
|
|||
for(int i = 0; i < count; ++i)
|
||||
{
|
||||
serializer.readString(path, MAX_PATH_LENGTH);
|
||||
serializer.read(m_grass_types[i]->m_ground);
|
||||
if (version <= (int)RenderSceneVersion::NEW_GRASS)
|
||||
{
|
||||
int dummy;
|
||||
serializer.read(dummy);
|
||||
}
|
||||
serializer.read(m_grass_types[i]->m_density);
|
||||
if (version > (int)RenderSceneVersion::GRASS_TYPE_DISTANCE)
|
||||
{
|
||||
|
@ -646,7 +633,6 @@ void Terrain::serialize(OutputBlob& serializer)
|
|||
{
|
||||
GrassType& type = *m_grass_types[i];
|
||||
serializer.writeString(type.m_grass_model ? type.m_grass_model->getPath().c_str() : "");
|
||||
serializer.write(type.m_ground);
|
||||
serializer.write(type.m_density);
|
||||
serializer.write(type.m_distance);
|
||||
}
|
||||
|
|
|
@ -34,19 +34,18 @@ class Universe;
|
|||
class Terrain
|
||||
{
|
||||
public:
|
||||
class GrassType
|
||||
struct GrassType
|
||||
{
|
||||
public:
|
||||
explicit GrassType(Terrain& terrain);
|
||||
~GrassType();
|
||||
GrassType(Terrain& terrain, int idx);
|
||||
~GrassType();
|
||||
|
||||
void grassLoaded(Resource::State, Resource::State, Resource&);
|
||||
void grassLoaded(Resource::State, Resource::State, Resource&);
|
||||
|
||||
Model* m_grass_model;
|
||||
Terrain& m_terrain;
|
||||
int32 m_ground;
|
||||
int32 m_density;
|
||||
float m_distance;
|
||||
Model* m_grass_model;
|
||||
Terrain& m_terrain;
|
||||
int32 m_density;
|
||||
float m_distance;
|
||||
int m_idx;
|
||||
};
|
||||
|
||||
struct GrassPatch
|
||||
|
@ -64,16 +63,15 @@ class Terrain
|
|||
GrassType* m_type;
|
||||
};
|
||||
|
||||
class GrassQuad
|
||||
struct GrassQuad
|
||||
{
|
||||
public:
|
||||
explicit GrassQuad(IAllocator& allocator)
|
||||
: m_patches(allocator)
|
||||
{}
|
||||
explicit GrassQuad(IAllocator& allocator)
|
||||
: m_patches(allocator)
|
||||
{}
|
||||
|
||||
Array<GrassPatch> m_patches;
|
||||
Vec3 pos;
|
||||
float radius;
|
||||
Array<GrassPatch> m_patches;
|
||||
Vec3 pos;
|
||||
float radius;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -99,7 +97,6 @@ class Terrain
|
|||
AABB getAABB() const;
|
||||
int getWidth() const { return m_width; }
|
||||
int getHeight() const { return m_height; }
|
||||
int getGrassTypeGround(int index) const;
|
||||
int getGrassTypeDensity(int index) const;
|
||||
float getGrassTypeDistance(int index) const;
|
||||
int getGrassTypeCount() const { return m_grass_types.size(); }
|
||||
|
@ -109,7 +106,6 @@ class Terrain
|
|||
void setXZScale(float scale) { m_scale.x = scale; m_scale.z = scale; }
|
||||
void setYScale(float scale) { m_scale.y = scale; }
|
||||
void setGrassTypePath(int index, const Path& path);
|
||||
void setGrassTypeGround(int index, int ground);
|
||||
void setGrassTypeDensity(int index, int density);
|
||||
void setGrassTypeDistance(int index, float value);
|
||||
void setMaterial(Material* material);
|
||||
|
|
Loading…
Reference in a new issue