Created
May 2, 2017 14:23
FoliageComponent Source
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by Victor Holt on 5/1/2017. | |
// | |
#include <cor-game/components/FoliageComponent.h> | |
#include <cor-game/GameEngine.h> | |
#include <cor-game/terrain/Grid.h> | |
#include <cor-game/terrain/GridCell.h> | |
#include <gs-common/helpers/NumberHelper.hpp> | |
#include <gs-common/helpers/MathHelper.h> | |
#include <gs-common/core/SenchaThreadManager.h> | |
#include <gs-common/core/SenchaThread.h> | |
#include <gs-script/engine/AppSettings.h> | |
using namespace Urho3D; | |
using namespace Sencha; | |
class FoliageThread : public SenchaThread | |
{ | |
URHO3D_OBJECT(SenchaThread, Object); | |
public: | |
FoliageThread(Context* context) : SenchaThread(context) {} | |
protected: | |
virtual void OnProcess() override { | |
FoliageComponent* component = reinterpret_cast<FoliageComponent*>(methodArgs_["FoliageComponent"].GetVoidPtr()); | |
} | |
}; | |
FoliageComponent::FoliageComponent(Context* context) | |
: Component(context) | |
{ | |
SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(FoliageComponent, HandleUpdateEvent)); | |
isProcessing_ = false; | |
isLoaded_ = false; | |
isInView_ = false; | |
} | |
void FoliageComponent::RegisterObject(Context* context) | |
{ | |
context->RegisterFactory<FoliageComponent>(); | |
} | |
void FoliageComponent::HandleUpdateEvent(StringHash eventType, VariantMap& eventData) | |
{ | |
GameEngine* gameEngine = GetSubsystem<GameEngine>(); | |
if (!gameEngine->GetInit()) return; | |
if (!isProcessing_) { | |
Node* cameraNode = gameEngine->GetActiveCameraNode(); | |
Camera* camera = cameraNode->GetComponent<Camera>(); | |
Graphics* graphics = GetSubsystem<Graphics>(); | |
UI* ui = GetSubsystem<UI>(); | |
IntVector2 pos = ui->GetCursorPosition(); | |
Ray cameraRay = camera->GetScreenRay((float) pos.x_ / graphics->GetWidth(), | |
(float) pos.y_ / graphics->GetHeight()); | |
Vector3 cameraPos = cameraNode->GetWorldPosition(); | |
if (boundingBox_.IsInside(cameraPos) == INSIDE || cameraRay.HitDistance(boundingBox_) < GetSubsystem<Grid>()->GetFoilageDrawDistance()) { | |
Load(); | |
} else { | |
Unload(); | |
} | |
} | |
} | |
void FoliageComponent::Initialize(GridCell* gridCell, const String& name, Model* model, uint32_t maxFoliageNodes) | |
{ | |
gridCell_ = gridCell; | |
name_ = name; | |
// Create the mesh. | |
foliageMesh_ = new CustomMesh(GetContext(), false); | |
float lengthX = 1.0f; | |
float lengthY = 1.0f; | |
float lengthZ = 1.0f; | |
foliageMesh_->AddFace( | |
Vector3(0.0f, 0.0f, lengthZ), | |
Vector3(lengthX, lengthY, lengthZ), | |
Vector3(0.0f, lengthY, lengthZ), | |
MeshUVType::UV_XY | |
); | |
foliageMesh_->AddFace( | |
Vector3(0.0f, 0.0f, lengthZ), | |
Vector3(lengthX, 0.0f, lengthZ), | |
Vector3(lengthX, lengthY, lengthZ), | |
MeshUVType::UV_XY | |
); | |
foliageMesh_->Commit(); | |
maxFoliageNodes_ = maxFoliageNodes; | |
Grid* grid = GetSubsystem<Grid>(); | |
float cellSize = grid->GetCellSize(); | |
float cellSizeHalf = cellSize / 2.0f; | |
Vector3 scale = grid->GetTerrainScale(); | |
Vector3 cellMin = Vector3(-cellSizeHalf * scale.x_, 0.0f, -cellSizeHalf * scale.z_); | |
Vector3 cellMax = Vector3(cellSize * scale.x_, 0.0f, cellSize * scale.z_); | |
foliageNode_ = node_->CreateChild("Foilage"); | |
modelGroup_ = foliageNode_->CreateComponent<StaticModelGroup>(); | |
modelGroup_->SetDrawDistance(grid->GetFoilageDrawDistance()); | |
modelGroup_->SetModel(foliageMesh_->GetModel()); | |
modelGroup_->SetCastShadows(false); | |
modelGroup_->SetOccludee(true); | |
modelGroup_->SetMaterial(GetSubsystem<ResourceCache>()->GetResource<Material>("CorMod/gfx/materials/Foliage.xml")); | |
Vector3 worldNodePos = gridCell_->GetTerrainNode()->GetWorldPosition(); | |
boundingBox_ = BoundingBox(Vector3(cellMin.x_, -1000.0f, cellMin.z_) + worldNodePos, Vector3(cellMax.x_, 1000.0f, cellMax.z_) + worldNodePos); | |
VectorBuffer buffer; | |
buffer.WriteUInt(maxFoliageNodes); | |
for (uint32_t i = 0; i < maxFoliageNodes_; i++) { | |
Vector3 nodePos = Vector3(NumberHelper::RandomFloat(cellMin.x_, cellMax.x_), 0.0f, NumberHelper::RandomFloat(cellMin.z_, cellMax.z_)); | |
nodePos += worldNodePos; | |
nodePos.y_ = gridCell->GetTerrain()->GetHeight(Vector3(nodePos.x_, 0.0f, nodePos.z_)); | |
Quaternion rot = Quaternion(0.0f, Random(360.0f), 0.0f); | |
float foilageScale = 0.5f + Random(2.0f); | |
buffer.WriteVector3(nodePos); | |
buffer.WriteQuaternion(rot); | |
buffer.WriteFloat(foilageScale); | |
} | |
modelGroup_->SetEnabled(false); | |
Save(buffer); | |
// Create our loading thread. | |
SenchaThreadManager* threadManager = GetSubsystem<SenchaThreadManager>(); | |
loadThread_ = threadManager->CreateThread([&]() { | |
while (!loadThread_->GetIsAborted()) { | |
if (!isProcessing_ || !GetSubsystem<GameEngine>()->GetInit() || GetSubsystem<GameEngine>()->GetNumFoliageLoads() > 3) { | |
loadThread_->Sleep(100); | |
continue; | |
} | |
GetSubsystem<GameEngine>()->IncFoliageLoads(); | |
MutexLock lock(foliageLock_); | |
if (isInView_) { | |
if (!modelGroup_->IsEnabled()) { | |
File file(GetContext(), filePath_); | |
VectorBuffer buffer(file.ReadBuffer()); | |
uint32_t maxFoliageNodes = buffer.ReadUInt(); | |
file.Close(); | |
for (uint32_t i = 0; i < maxFoliageNodes_; i++) { | |
Vector3 nodePos = buffer.ReadVector3(); | |
Quaternion rot = buffer.ReadQuaternion(); | |
float foilageScale = buffer.ReadFloat(); | |
Node* node = new Node(GetContext()); | |
node->SetName("Vegetation"); | |
node->SetPosition(nodePos); | |
node->SetRotation(rot); | |
node->SetScale(foilageScale); | |
instancedNodes_.Push(node); | |
modelGroup_->AddInstanceNode(node); | |
} | |
modelGroup_->SetEnabled(true); | |
isLoaded_ = true; | |
GetSubsystem<GameEngine>()->DecFoliageLoads(); | |
} | |
} else { | |
modelGroup_->RemoveAllInstanceNodes(); | |
for (auto node : instancedNodes_) { | |
delete node; | |
} | |
instancedNodes_.Clear(); | |
isLoaded_ = false; | |
GetSubsystem<GameEngine>()->DecFoliageLoads(); | |
} | |
isProcessing_ = false; | |
loadThread_->Sleep(100); | |
} | |
}, true); | |
} | |
void FoliageComponent::Save(VectorBuffer& data) | |
{ | |
AppSettings* settings = GetSubsystem<AppSettings>(); | |
String relFileName; | |
String cacheFileName = settings->GetCacheDirPath(); | |
cacheFileName.Append("/"); | |
settings->GetRelativeModPath("gfx/map", "", relFileName); | |
relFileName.Replace('/', '_'); | |
relFileName.Append('_'); | |
filePath_ = cacheFileName; | |
filePath_.Append(relFileName); | |
filePath_.Append(name_); | |
filePath_.Append(".dat"); | |
File file(GetContext(), filePath_, FILE_WRITE); | |
file.WriteBuffer(data.GetBuffer()); | |
file.Close(); | |
} | |
void FoliageComponent::Load() | |
{ | |
if (isLoaded_) return; | |
isProcessing_ = true; | |
isInView_ = true; | |
} | |
void FoliageComponent::Unload() | |
{ | |
if (!isLoaded_) return; | |
isProcessing_ = true; | |
modelGroup_->SetEnabled(false); | |
isInView_ = false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment