Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5,100 changes: 5,100 additions & 0 deletions bin/World/PortsmouthHarbour/pontoon.ini

Large diffs are not rendered by default.

1,894 changes: 1,894 additions & 0 deletions bin/World/SwinomishChannelSouth/pontoon.ini

Large diffs are not rendered by default.

Binary file added bin/media/pontoon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 48 additions & 1 deletion doc/WorldFileSpec.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@ <h3>Introduction:</h3>
</p>

<p>
For small details such as harbours and marinas, 3d models can be loaded into the world model. See the detail below in the landobject.ini
For small details such as harbours, 3d models can be loaded into the world model. See the detail below in the landobject.ini
for how land objects can be set to appear in the radar, and act as physical models that the own ship can interact with.
</p>

<p>
In addition, floating pontoons can be defined by a series of coordinates, which can be useful to model marinas.
</p>

<p>
A variety of formats can be used for the height maps. The simplest is a greyscale png image, with black representing the deepest point, and
white representing the highest point. A standard greyscale png can represent 255 shades from black to white, so if you need finer elevation
Expand Down Expand Up @@ -94,6 +98,7 @@ <h4>Configuration:</h4>
<li>light.ini:&nbsp;Specifies navigation lights in world (floating or land based)</li>
<li>tide.ini:&nbsp;Defines the tides</li>
<li>tidalstream.ini:&nbsp;Defines the tidal stream (optional)</li>
<li>pontoon.ini:&nbsp;Defines floating pontoons (optional)</li>
<!--<li>RadarReflector.ini:&nbsp;Defines location of fixed radar reflecting objects (Optional)</li>-->
<!--<li>Description.ini:&nbsp;A brief description of the world model (Optional)</li>-->
<!--<li>Thumb.bmp:&nbsp;A thumbnail image (Optional)</li>-->
Expand Down Expand Up @@ -497,6 +502,48 @@ <h5>Example tidalstream.ini:</h5>
</pre>
</p>

<h5>pontoon.ini</h5>

<p>This is an optional file, and defines floating pontoons (like in a marina), using a series of location coordinates.
</p>

<p>There is one general variables, <i>number</i> to set the number of pontoons.</p>

<p>For each pontoon, a series of coordinates is given, defining the end point of each straight section. The number of these points is given by the Nodes(#) parameter. For each node, the position is given in latitude and longitude.</p>

<h5>Example tidalstream.ini:</h5>
<p>
<pre>
Number=3

Nodes(1)=2
Lat(1,1)=48.3922659
Long(1,1)=-122.4968183
Lat(1,2)=48.3922369
Long(1,2)=-122.4965243

Nodes(2)=3
Lat(2,1)=48.3919328
Long(2,1)=-122.4968907
Lat(2,2)=48.3922659
Long(2,2)=-122.4968183
Lat(2,3)=48.3925858
Long(2,3)=-122.4967724

Nodes(3)=5
Lat(3,1)=48.3915730
Long(3,1)=-122.4967124
Lat(3,2)=48.3916300
Long(3,2)=-122.4969726
Lat(3,3)=48.3918882
Long(3,3)=-122.4968375
Lat(3,4)=48.3918302
Long(3,4)=-122.4965865
Lat(3,5)=48.3915730
Long(3,5)=-122.4967124
</pre>
</p>


<!--

Expand Down
73 changes: 66 additions & 7 deletions src/LandObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@

//using namespace irr;

LandObject::LandObject(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 rotation, bool collisionObject, bool radarObject, bool morph, Terrain* terrain, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev)
LandObject::LandObject(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 rotation, bool collisionObject, bool radarObject, bool morph, Terrain* terrain, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev, bool dummyObject, irr::f32 sectionLength)
{

const irr::f32 tallHeightRatio = 5.0; // Minimum ratio of height to max of width, length for an object to be considered 'tall'
const irr::f32 nearlyFlatHeight = 1.0; // Max height in model units for a 'flat' object

this->collisionObject = collisionObject;

device = dev;

std::string basePath = "Models/LandObject/" + name + "/";
Expand All @@ -54,14 +56,35 @@ LandObject::LandObject(const std::string& name, const std::string& internalName,

std::string objectFullPath = basePath + objectFileName;

// Store the vertical position (used later if object is floating)
heightCorrection = location.Y;

// Normally not floating
floating = false;

//Load the mesh
irr::scene::IMesh* objectMesh = smgr->getMesh(objectFullPath.c_str());
irr::scene::IMesh* objectMesh = 0;
if (!dummyObject) {
objectMesh = smgr->getMesh(objectFullPath.c_str());
}

//add to scene node
if (objectMesh==0) {
if (dummyObject || objectMesh==0) {
//Failed to load mesh - load with dummy and continue
dev->getLogger()->log("Failed to load land object model:");
dev->getLogger()->log("Using dummy land object model:");
dev->getLogger()->log(objectFullPath.c_str());
landObject = smgr->addCubeSceneNode(0.1, 0, -1, location);
landObject = smgr->addCubeSceneNode(1, 0, -1, location);
objectMesh = landObject->getMesh();

// Special case, make the object float
if (name == "PONTOON_INTERNAL") {
floating = true;
// Scale the mesh
irr::scene::IMeshManipulator* meshManipulator = smgr->getMeshManipulator();
meshManipulator->scale(objectMesh, irr::core::vector3df(2.0, 1.0, sectionLength));
// Set a simple texture
landObject->setMaterialTexture(0, smgr->getVideoDriver()->getTexture("media/pontoon.png"));
}
} else {
if (morph) {
// Remove nearly flat mesh buffers
Expand All @@ -85,13 +108,16 @@ LandObject::LandObject(const std::string& name, const std::string& internalName,
}

//Set ID as a flag if we should model collisions with this, also used to get radar points
triangleSelectorEnabled = false;
selector = 0;
if (collisionObject || radarObject) {
landObject->setID(IDFlag_IsPickable);

//Add a triangle selector
irr::scene::ITriangleSelector* selector=smgr->createTriangleSelector(objectMesh,landObject);
selector=smgr->createTriangleSelector(objectMesh,landObject);
if(selector) {
landObject->setTriangleSelector(selector);
triangleSelectorEnabled = true;
}
}

Expand All @@ -102,7 +128,9 @@ LandObject::LandObject(const std::string& name, const std::string& internalName,
}
}

landObject->setScale(irr::core::vector3df(objectScale,objectScale,objectScale));
if (!dummyObject) {
landObject->setScale(irr::core::vector3df(objectScale, objectScale, objectScale));
}
landObject->setRotation(irr::core::vector3df(0,rotation,0));
landObject->setMaterialFlag(irr::video::EMF_FOG_ENABLE, true);
landObject->setMaterialFlag(irr::video::EMF_NORMALIZE_NORMALS, true); //Normalise normals on scaled meshes, for correct lighting
Expand Down Expand Up @@ -221,6 +249,7 @@ LandObject::LandObject(const std::string& name, const std::string& internalName,
if (!collisionObject) {
landObject->setID(-1);
landObject->setTriangleSelector(0);
triangleSelectorEnabled = false;
}
//End contact points for radar detection
//======================================
Expand Down Expand Up @@ -274,3 +303,33 @@ irr::scene::ISceneNode* LandObject::getSceneNode() const
{
return (irr::scene::ISceneNode*)landObject;
}

void LandObject::enableTriangleSelector(bool selectorEnabled)
{
//Only re-set if we need to change the state

if (collisionObject && selectorEnabled && !triangleSelectorEnabled) {
landObject->setTriangleSelector(selector);
triangleSelectorEnabled = true;
}

if (!selectorEnabled && triangleSelectorEnabled) {
landObject->setTriangleSelector(0);
triangleSelectorEnabled = false;
}
}

irr::f32 LandObject::getHeightCorrection() const
{
return heightCorrection;
}

bool LandObject::getFloating() const
{
return floating;
}

void LandObject::setPosition(irr::core::vector3df position)
{
landObject->setPosition(position);
}
11 changes: 10 additions & 1 deletion src/LandObject.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,24 @@ class Terrain;
class LandObject
{
public:
LandObject(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 rotation, bool collisionObject, bool radarObject, bool morph, Terrain* terrain, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev);
LandObject(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 rotation, bool collisionObject, bool radarObject, bool morph, Terrain* terrain, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev, bool dummyObject = false, irr::f32 sectionLength = 1.0f);
virtual ~LandObject();
irr::core::vector3df getPosition() const;
void moveNode(irr::f32 deltaX, irr::f32 deltaY, irr::f32 deltaZ);
irr::scene::ISceneNode* getSceneNode() const;
void enableTriangleSelector(bool selectorEnabled);
bool getFloating() const;
irr::f32 getHeightCorrection() const;
void setPosition(irr::core::vector3df position);
protected:
private:
irr::scene::IMeshSceneNode* landObject; //The scene node for the object.
irr::IrrlichtDevice* device;
irr::scene::ITriangleSelector* selector; //The triangle selector for the buoy. We will set and unset this depending on the distance from the ownship for speed
bool triangleSelectorEnabled;
bool collisionObject;
irr::f32 heightCorrection;
bool floating;
irr::f32 findContactYFromRay(irr::core::line3d<irr::f32> ray);
};

Expand Down
74 changes: 72 additions & 2 deletions src/LandObjects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ LandObjects::~LandObjects()

void LandObjects::load(const std::string& worldName, irr::scene::ISceneManager* smgr, SimulationModel* model, Terrain* terrain, irr::IrrlichtDevice* dev)
{
this->model = model;

//get landObject.ini filename
std::string scenarioLandObjectFilename = worldName;
scenarioLandObjectFilename.append("/landobject.ini");
Expand All @@ -52,7 +54,7 @@ void LandObjects::load(const std::string& worldName, irr::scene::ISceneManager*
//Get object position
irr::f32 objectX = model->longToX(IniFile::iniFileTof32(scenarioLandObjectFilename,IniFile::enumerate1("Long",currentObject)));
irr::f32 objectZ = model->latToZ(IniFile::iniFileTof32(scenarioLandObjectFilename,IniFile::enumerate1("Lat",currentObject)));
irr::f32 objectY = IniFile::iniFileTof32(scenarioLandObjectFilename,IniFile::enumerate1("HeightCorrection",currentObject));;
irr::f32 objectY = IniFile::iniFileTof32(scenarioLandObjectFilename,IniFile::enumerate1("HeightCorrection",currentObject));

//Check if we should 'morph' the model to fit the land (mostly for OSM2World models)
bool morph = false;
Expand All @@ -79,10 +81,78 @@ void LandObjects::load(const std::string& worldName, irr::scene::ISceneManager*

//Create land object and load into vector
std::string internalName = "LandObject_";
internalName.append(std::to_string(currentObject-1)); // -1 as we want index from 0
internalName.append(std::to_string(landObjects.size()));
landObjects.push_back(LandObject (objectName.c_str(),internalName,worldName,irr::core::vector3df(objectX,objectY,objectZ),rotation,collisionObject,radarObject,morph,terrain,smgr,dev));

}

// Add 'pontoons' here.
std::string scenarioPontoonFilename = worldName;
scenarioPontoonFilename.append("/pontoon.ini");

//Find number of objects
irr::u32 numberOfPontoons;
numberOfPontoons = IniFile::iniFileTou32(scenarioPontoonFilename, "Number");
for (irr::u32 currentPontoon = 1; currentPontoon <= numberOfPontoons; currentPontoon++) {
irr::u32 numberOfNodes;
numberOfNodes = IniFile::iniFileTou32(scenarioPontoonFilename, IniFile::enumerate1("Nodes", currentPontoon));
for (irr::u32 currentNode = 1; currentNode < numberOfNodes; currentNode++) {
//Get position of this node and next one
irr::f32 node1X = model->longToX(IniFile::iniFileTof32(scenarioPontoonFilename, IniFile::enumerate2("Long", currentPontoon, currentNode)));
irr::f32 node1Z = model->latToZ(IniFile::iniFileTof32(scenarioPontoonFilename, IniFile::enumerate2("Lat", currentPontoon, currentNode)));
irr::f32 node1Y = IniFile::iniFileTof32(scenarioPontoonFilename, IniFile::enumerate2("HeightCorrection", currentPontoon, currentNode));

irr::f32 node2X = model->longToX(IniFile::iniFileTof32(scenarioPontoonFilename, IniFile::enumerate2("Long", currentPontoon, currentNode + 1)));
irr::f32 node2Z = model->latToZ(IniFile::iniFileTof32(scenarioPontoonFilename, IniFile::enumerate2("Lat", currentPontoon, currentNode + 1)));
irr::f32 node2Y = IniFile::iniFileTof32(scenarioPontoonFilename, IniFile::enumerate2("HeightCorrection", currentPontoon, currentNode + 1));

irr::f32 midPointX = (node1X + node2X) / 2.0;
irr::f32 midPointY = (node1Y + node2Y) / 2.0;
irr::f32 midPointZ = (node1Z + node2Z) / 2.0;

// Find length and angle of this section
irr::f32 rotation = atan2(node2X - node1X, node2Z - node1Z) * irr::core::RADTODEG;
irr::f32 sectionLength = pow(pow(node2X - node1X, 2.0) + pow(node2Z - node1Z, 2.0), 0.5);

//Create land object and load into vector
std::string internalName = "LandObject_";
internalName.append(std::to_string(landObjects.size()));

// Set properties
std::string objectName = "PONTOON_INTERNAL"; // This name is used to trigger floating behaviour in 'land object'
bool collisionObject = true;
bool radarObject = false; // We could turn this on, but may use a lot of memory!
bool morph = false;

landObjects.push_back(LandObject(objectName.c_str(), internalName, worldName, irr::core::vector3df(midPointX, midPointY, midPointZ), rotation, collisionObject, radarObject, morph, terrain, smgr, dev, true, sectionLength));

}
}
}

void LandObjects::update(irr::f32 tideHeight, irr::core::vector3df ownShipPosition, irr::f32 ownShipLength)
{
for (std::vector<LandObject>::iterator it = landObjects.begin(); it != landObjects.end(); ++it) {

if (it->getFloating()) {
irr::f32 xPos, yPos, zPos;
irr::core::vector3df pos = it->getPosition();
xPos = pos.X;
//yPos = tideHeight + model->getWaveHeight(pos.X, pos.Z) + it->getHeightCorrection();
yPos = tideHeight + it->getHeightCorrection(); // Don't include wave height for floating pontoons etc.
zPos = pos.Z;
it->setPosition(irr::core::vector3df(xPos, yPos, zPos));
}
//Set or clear triangle selector depending on distance from own ship;
irr::f32 landObjectMaxLength = it->getSceneNode()->getTransformedBoundingBox().getExtent().getLength(); // Max length between corners of the bounding box
if (it->getSceneNode()->getAbsolutePosition().getDistanceFrom(ownShipPosition) < (ownShipLength + landObjectMaxLength)) {
it->enableTriangleSelector(true);
}
else {
it->enableTriangleSelector(false);
}

}
}

irr::u32 LandObjects::getNumber() const
Expand Down
2 changes: 2 additions & 0 deletions src/LandObjects.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ class LandObjects
irr::u32 getNumber() const;
void moveNode(irr::f32 deltaX, irr::f32 deltaY, irr::f32 deltaZ);
irr::scene::ISceneNode* getSceneNode(int number);
void update(irr::f32 tideHeight, irr::core::vector3df ownShipPosition, irr::f32 ownShipLength);

private:
std::vector<LandObject> landObjects;
SimulationModel* model; //Store reference to model
};

#endif
4 changes: 4 additions & 0 deletions src/SimulationModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1902,6 +1902,10 @@ SimulationModel::~SimulationModel()
//update buoys (for lights, floating, and if collision detection is turned on)
buoys.update(deltaTime,scenarioTime,tideHeight,lightLevel,ownShip.getPosition(),ownShip.getLength());

}{ IPROF("Update land objects");
//update land objects (for floating, and if collision detection is turned on)
landObjects.update(tideHeight, ownShip.getPosition(), ownShip.getLength());

}{ IPROF("Update land lights");
//Update land lights
landLights.update(deltaTime,scenarioTime,lightLevel);
Expand Down
Loading