49 #include <RTShaderSystem/OgreRTShaderSystem.h>
50 #include <Overlay/OgreFontManager.h>
52 #ifdef USE_ANGELSCRIPT
54 #endif // USE_ANGELSCRIPT
68 TerrainObjectManager::TerrainObjectManager(
Terrain* terrainManager) :
69 terrainManager(terrainManager)
84 for (
auto geom : m_paged_geometry)
86 delete geom->getPageLoader();
98 Ogre::ColourValue background_color(Ogre::ColourValue::White);
99 Ogre::ColourValue grid_color(0.2f, 0.2f, 0.2f, 1.0f);
101 Ogre::ManualObject* mo =
new Ogre::ManualObject(
"ReferenceGrid");
103 mo->begin(
"BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_LIST);
105 const float step = 1.0f;
106 const size_t count = 50;
107 unsigned int halfCount = count / 2;
108 const float half = (step * count) / 2;
111 for (
size_t i=0; i < count+1; i++)
114 c = Ogre::ColourValue(1.f, 0.f, 0.f, 1.f);
118 mo->position(-half,
y, -half+(step*i));
119 mo->colour(background_color);
120 mo->position(0,
y, -half+(step*i));
122 mo->position(0,
y, -half+(step*i));
124 mo->position(half,
y, -half+(step*i));
125 mo->colour(background_color);
128 c = Ogre::ColourValue(0,0,1,1.0f);
132 mo->position(-half+(step*i),
y, -half);
133 mo->colour(background_color);
134 mo->position(-half+(step*i),
y, 0);
136 mo->position(-half+(step*i),
y, 0);
138 mo->position(-half+(step*i),
y, half);
139 mo->colour(background_color);
143 mo->setCastShadows(
false);
145 n->setPosition(position);
159 DataStreamPtr stream_ptr = ResourceGroupManager::getSingleton().openResource(
180 if (tobj->grid_enabled)
276 float yawfrom,
float yawto,
277 float scalefrom,
float scaleto,
278 char* ColorMap,
char* DensityMap,
char* treemesh,
char* treeCollmesh,
279 float gridspacing,
float highdens,
280 int minDist,
int maxDist,
int mapsizex,
int mapsizez)
285 LOG(
"tree ColorMap map zero!");
288 if (
strnlen(DensityMap, 3) == 0)
290 LOG(
"tree DensityMap zero!");
293 Forests::DensityMap *densityMap = Forests::DensityMap::load(DensityMap, Forests::CHANNEL_COLOR);
296 LOG(
"could not load densityMap: "+String(DensityMap));
299 densityMap->setFilter(Forests::MAPFILTER_BILINEAR);
302 PagedGeometry* geom =
new PagedGeometry();
305 geom->setPageSize(50);
307 Ogre::TRect<Ogre::Real> bounds = TBounds(0, 0, mapsizex, mapsizez);
308 geom->setBounds(bounds);
315 geom->addDetailLevel<BatchPage>(min, min / 2);
321 if (max / 10 > min / 2)
323 geom->addDetailLevel<ImpostorPage>(max, max / 10);
326 TreeLoader2D *treeLoader =
new TreeLoader2D(geom, TBounds(0, 0, mapsizex, mapsizez));
327 treeLoader->setMinimumScale(scalefrom);
328 treeLoader->setMaximumScale(scaleto);
329 geom->setPageLoader(treeLoader);
331 if (String(ColorMap) !=
"none")
333 treeLoader->setColorMap(ColorMap);
341 for (
float x=0;
x < mapsizex;
x += gridspacing)
343 for (
float z=0;
z < mapsizez;
z += gridspacing)
345 float density = densityMap->_getDensityAt_Unfiltered(
x,
z, bounds);
346 if (density < 0.8f)
continue;
347 float nx =
x + gridspacing * 0.5f;
348 float nz =
z + gridspacing * 0.5f;
349 float yaw = Math::RangeRandom(yawfrom, yawto);
350 float scale = Math::RangeRandom(scalefrom, scaleto);
351 Vector3 pos = Vector3(nx, 0, nz);
352 treeLoader->addTree(curTree, pos, Degree(yaw), (Ogre::Real)scale);
353 if (strlen(treeCollmesh))
365 if (gridspacing < 0 && gridspacing != 0)
367 gridsize = -gridspacing;
371 for (
float x=0;
x < mapsizex;
x += gridsize)
373 for (
float z=0;
z < mapsizez;
z += gridsize)
375 if (highdens < 0) hd = Math::RangeRandom(0, -highdens);
376 float density = densityMap->_getDensityAt_Unfiltered(
x,
z, bounds);
379 while(numTreesToPlace-->0)
381 nx = Math::RangeRandom(
x,
x + gridsize);
382 nz = Math::RangeRandom(
z,
z + gridsize);
383 float yaw = Math::RangeRandom(yawfrom, yawto);
384 float scale = Math::RangeRandom(scalefrom, scaleto);
385 Vector3 pos = Vector3(nx, 0, nz);
386 treeLoader->addTree(curTree, pos, Degree(yaw), (Ogre::Real)scale);
387 if (strlen(treeCollmesh))
396 m_paged_geometry.push_back(geom);
401 float SwaySpeed,
float SwayLength,
float SwayDistribution,
float Density,
402 float minx,
float miny,
float minH,
float maxx,
float maxy,
float maxH,
403 char* grassmat,
char* colorMapFilename,
char* densityMapFilename,
404 int growtechnique,
int techn,
int range,
405 int mapsizex,
int mapsizez)
417 GrassLoader *grassLoader =
new GrassLoader(grass);
418 grass->setPageLoader(grassLoader);
422 grassLoader->setRenderQueueGroup(RENDER_QUEUE_MAIN-1);
424 GrassLayer* grassLayer = grassLoader->addLayer(grassmat);
425 grassLayer->setHeightRange(minH, maxH);
426 grassLayer->setLightingEnabled(
true);
428 grassLayer->setAnimationEnabled((SwaySpeed>0));
429 grassLayer->setSwaySpeed(SwaySpeed);
430 grassLayer->setSwayLength(SwayLength);
431 grassLayer->setSwayDistribution(SwayDistribution);
435 grassLayer->setRenderTechnique(
static_cast<GrassTechnique
>(techn-10),
true);
437 grassLayer->setRenderTechnique(
static_cast<GrassTechnique
>(techn),
false);
439 grassLayer->setMapBounds(TBounds(0, 0, mapsizex, mapsizez));
441 if (strcmp(colorMapFilename,
"none") != 0)
443 grassLayer->setColorMap(colorMapFilename);
444 grassLayer->setColorMapFilter(MAPFILTER_BILINEAR);
447 if (strcmp(densityMapFilename,
"none") != 0)
449 grassLayer->setDensityMap(densityMapFilename);
450 grassLayer->setDensityMapFilter(MAPFILTER_BILINEAR);
453 grassLayer->setMinimumSize(minx, miny);
454 grassLayer->setMaximumSize(maxx, maxy);
457 if (growtechnique == 0)
458 grassLayer->setFadeTechnique(FADETECH_GROW);
459 else if (growtechnique == 1)
460 grassLayer->setFadeTechnique(FADETECH_ALPHAGROW);
461 else if (growtechnique == 2)
462 grassLayer->setFadeTechnique(FADETECH_ALPHA);
464 m_paged_geometry.push_back(grass);
468 LOG(
"error loading grass!");
480 dst->position = position;
481 dst->rotation = rotation;
482 dst->special_object_type = type;
484 dst->tobj_cache_id = tobj_cache_id;
497 LOG(
fmt::format(
"[RoR] `moveObjectVisuals()`: instance name '{}' not found!", instancename));
509 LOG(
fmt::format(
"[RoR] `destroyObject()`: instance name '{}' not found!", instancename));
519 ROR_ASSERT(!object->static_collision_tris.size());
520 ROR_ASSERT(!object->static_collision_boxes.size());
531 for (Ogre::MovableObject* mova : object->static_object_node->getAttachedObjects())
538 for (
int tri : object->static_collision_tris)
542 for (
int box : object->static_collision_boxes)
564 return search_res->second.get();
568 const std::string filename = odef_name +
".odef";
569 std::string group_name;
572 group_name = Ogre::ResourceGroupManager::getSingleton().findGroupContainingResource(filename);
576 LOG(
fmt::format(
"[ODEF] Could not find {} in any resource group", filename));
583 Ogre::DataStreamPtr ds = ResourceGroupManager::getSingleton().openResource(filename, group_name);
587 std::shared_ptr<ODefDocument> odef = parser.
Finalize();
595 LOG(
fmt::format(
"[ODEF] An exception occurred when loading or parsing {}", filename));
600 bool TerrainObjectManager::LoadTerrainObject(
const Ogre::String& name,
const Ogre::Vector3& pos,
const Ogre::Vector3& rot,
const Ogre::String& instancename,
const Ogre::String& type,
float rendering_distance ,
bool enable_collisions ,
int scripthandler ,
bool uniquifyMaterial )
605 for (
int x = 0;
x < 500;
x += 50)
607 for (
int z = 0;
z < 500;
z += 50)
609 const String notype =
"";
610 LoadTerrainObject(name, pos + Vector3(
x, 0.0f,
z), rot, name, notype, 0, enable_collisions, scripthandler, uniquifyMaterial);
616 const std::string odefname = name +
".odef";
639 mo->
getEntity()->setRenderingDistance(rendering_distance);
655 tenode->setPosition(pos);
656 Quaternion rotation = Quaternion(Degree(rot.x), Vector3::UNIT_X) * Quaternion(Degree(rot.y), Vector3::UNIT_Y) * Quaternion(Degree(rot.z), Vector3::UNIT_Z);
657 tenode->rotate(rotation);
658 tenode->pitch(Degree(-90));
659 tenode->setVisible(
true);
663 object->instance_name = instancename;
665 object->position = pos;
666 object->rotation = rot;
667 object->initial_position = pos;
668 object->initial_rotation = rot;
669 object->static_object_node = tenode;
670 object->enable_collisions = enable_collisions;
671 object->script_handler = scripthandler;
675 if (mo && uniquifyMaterial && !instancename.empty())
677 for (
unsigned int i = 0; i < mo->
getEntity()->getNumSubEntities(); i++)
679 SubEntity* se = mo->
getEntity()->getSubEntity(i);
680 String matname = se->getMaterialName();
681 String newmatname = matname +
"/" + instancename;
682 se->getMaterial()->clone(newmatname);
683 se->setMaterialName(newmatname);
690 loc.
position = Vector3(pos.x, pos.y, pos.z);
698 tenode->pitch(Degree(90));
704 for (std::string& snd_name : odef->
sounds)
718 bool race_event = !
object->instance_name.compare(0, 10,
"checkpoint") ||
719 !
object->instance_name.compare(0, 4,
"race");
723 String type =
"checkpoint";
724 auto res = StringUtil::split(object->instance_name,
"|");
725 if ((res.size() == 4 && res[2] ==
"0") || !object->instance_name.compare(0, 4,
"race"))
729 int race_id = res.size() > 1 ? StringConverter::parseInt(res[1], -1) : -1;
732 else if (object->type !=
"" && object->type !=
"-")
735 if (object->type ==
"station" || object->type ==
"hotel" || object->type ==
"village" ||
736 object->type ==
"observatory" || object->type ==
"farm" || object->type ==
"ship" || object->type ==
"sign")
738 caption =
object->instance_name +
" " +
object->type;
749 LOG(
"[ODEF] Skipping collision mesh with empty name. Object: " + odefname);
756 cmesh.
mesh_name, pos, tenode->getOrientation(),
757 cmesh.
scale, gm, &(object->static_collision_tris));
770 pParticleSys->setCastShadows(
false);
774 #ifdef USE_ANGELSCRIPT
775 unsigned short affCount = pParticleSys->getNumAffectors();
776 ParticleAffector* pAff;
777 for (
unsigned short i = 0; i < affCount; ++i)
779 pAff = pParticleSys->getAffector(i);
780 if (pAff->getType() ==
"ExtinguishableFire")
785 #endif // USE_ANGELSCRIPT
787 SceneNode* sn = tenode->createChildSceneNode();
788 sn->attachObject(pParticleSys);
789 sn->pitch(Degree(90));
793 peo.
psys = pParticleSys;
807 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(odef->
mat_name_generate,
"generatedMaterialShaders");
808 Ogre::RTShader::ShaderGenerator::getSingleton().createShaderBasedTechnique(*mat, Ogre::MaterialManager::DEFAULT_SCHEME_NAME, Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
809 Ogre::RTShader::ShaderGenerator::getSingleton().invalidateMaterial(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME, String(odef->
mat_name_generate));
816 AnimationStateSet *s = mo->
getEntity()->getAllAnimationStates();
817 String anim_name_str(anim.
name);
818 if (!s->hasAnimationState(anim_name_str))
820 LOG(
"[ODEF] animation '" + anim_name_str +
"' for mesh: '" + odef->
header.
mesh_name +
"' in odef file '" + name +
".odef' not found!");
839 LOG(
"[ODEF] animation '" + anim_name_str +
"' for mesh: '" + odef->
header.
mesh_name +
"' in odef file '" + name +
".odef' not found!");
842 ao.
anim->setEnabled(
true);
851 String matName = mo->
getEntity()->getSubEntity(0)->getMaterialName();
852 MaterialPtr m = MaterialManager::getSingleton().getByName(matName);
855 LOG(
"[ODEF] problem with drawTextOnMeshTexture command: mesh material not found: "+odefname+
" : "+matName);
858 String texName = m->getTechnique(0)->getPass(0)->getTextureUnitState(0)->getTextureName();
859 Texture* background = (Texture *)TextureManager::getSingleton().getByName(texName).get();
862 LOG(
"[ODEF] problem with drawTextOnMeshTexture command: mesh texture not found: "+odefname+
" : "+texName);
866 static int textureNumber = 0;
868 char tmpTextName[256] =
"", tmpMatName[256] =
"";
869 sprintf(tmpTextName,
"TextOnTexture_%d_Texture", textureNumber);
870 sprintf(tmpMatName,
"TextOnTexture_%d_Material", textureNumber);
871 TexturePtr texture = TextureManager::getSingleton().createManual(tmpTextName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, (Ogre::uint)background->getWidth(), (Ogre::uint)background->getHeight(), MIP_UNLIMITED, PF_X8R8G8B8, Ogre::TU_STATIC | Ogre::TU_AUTOMIPMAP);
872 if (texture.get() == 0)
874 LOG(
"[ODEF] problem with drawTextOnMeshTexture command: could not create texture: "+odefname+
" : "+tmpTextName);
881 if (!strncmp(text_buf.
GetBuffer(),
"{{argument1}}", 13))
884 text_buf << instancename;
888 char *text_pointer = text_buf.
GetBuffer();
889 while (*text_pointer!=0) {
if (*text_pointer==
'_') *text_pointer=
' ';text_pointer++;};
891 String font_name_str(tex_print.
font_name);
892 Ogre::Font* font = (Ogre::Font *)FontManager::getSingleton().getByName(font_name_str).get();
895 LOG(
"[ODEF] problem with drawTextOnMeshTexture command: font not found: "+odefname+
" : "+font_name_str);
900 texture->getBuffer()->blit(background->getBuffer());
902 float x = background->getWidth() * tex_print.
x;
903 float y = background->getHeight() * tex_print.
y;
904 float w = background->getWidth() * tex_print.
w;
905 float h = background->getHeight() * tex_print.
h;
907 ColourValue color(tex_print.
r, tex_print.
g, tex_print.
b, tex_print.
a);
908 Ogre::Box box = Ogre::Box((
size_t)
x, (
size_t)
y, (
size_t)(
x+
w), (
size_t)(
y+h));
914 m->clone(tmpMatName);
915 MaterialPtr mNew = MaterialManager::getSingleton().getByName(tmpMatName);
916 mNew->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(tmpTextName);
918 mo->
getEntity()->setMaterialName(String(tmpMatName));
925 spotLight->setType(Light::LT_SPOTLIGHT);
926 spotLight->setPosition(spotl.
pos);
927 spotLight->setDirection(spotl.
dir);
928 spotLight->setAttenuation(spotl.
range, 1.0, 0.3, 0.0);
929 spotLight->setDiffuseColour(spotl.
color);
930 spotLight->setSpecularColour(spotl.
color);
934 lflare->createBillboard(spotl.
pos, spotl.
color);
935 lflare->setMaterialName(
"tracks/flare");
938 float fsize = Math::Clamp(spotl.
range / 10, 0.2f, 2.0f);
939 lflare->setDefaultDimensions(fsize, fsize);
941 SceneNode *sn = tenode->createChildSceneNode();
942 sn->attachObject(spotLight);
943 sn->attachObject(lflare);
950 pointlight->setType(Light::LT_POINT);
951 pointlight->setPosition(plight.
pos);
952 pointlight->setDirection(plight.
dir);
953 pointlight->setAttenuation(plight.
range, 1.0, 0.3, 0.0);
954 pointlight->setDiffuseColour(plight.
color);
955 pointlight->setSpecularColour(plight.
color);
958 lflare->createBillboard(plight.
pos, plight.
color);
959 lflare->setMaterialName(
"tracks/flare");
962 float fsize = Math::Clamp(plight.
range / 10, 0.2f, 2.0f);
963 lflare->setDefaultDimensions(fsize, fsize);
965 SceneNode *sn = tenode->createChildSceneNode();
966 sn->attachObject(pointlight);
967 sn->attachObject(lflare);
989 std::vector<AnimatedObject>::iterator it;
993 if (it->anim && it->speedfactor != 0)
995 Real time = dt * it->speedfactor;
996 it->anim->addTime(time);
1023 if (object->tobj_cache_id == -1 || object->tobj_cache_id >= (
int)
m_tobj_cache.size())
1026 fmt::format(
"Assuming no 'rot_yxz' when spawning preselected actor '{}' - TOBJ document not found", object->getName()));
1054 object->actor_instance_id);
1099 for (
auto geom : m_paged_geometry)
1138 obj->static_collision_boxes.push_back(boxnum);
1162 [needle_instance_name](
TerrainEditorObjectPtr& obj) { return obj->instance_name == needle_instance_name; });