Grass independant on the ground texture - closes #1024

This commit is contained in:
Mikulas Florek 2016-10-21 11:43:07 +02:00
parent 03747c71fe
commit 8d4f290819
7 changed files with 171 additions and 112 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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);