#include "LBBCBillboardKMeansClusterData.h" namespace LBBC { BillboardKMeansClusterData::BillboardKMeansClusterData() { } BillboardKMeansClusterData::~BillboardKMeansClusterData() { } void BillboardKMeansClusterData::readBillboardClusterData(TiXmlNode *billboardNode, int iBillboardGroup) { TiXmlNode *coord4dNode = billboardNode->FirstChild("coord4d"); Ogre::Vector3 normal; normal[0] = Ogre::StringConverter::parseReal(coord4dNode->ToElement()->Attribute("nx")); normal[1] = Ogre::StringConverter::parseReal(coord4dNode->ToElement()->Attribute("ny")); normal[2] = Ogre::StringConverter::parseReal(coord4dNode->ToElement()->Attribute("nz")); this->setNormal(normal); TiXmlNode *topLeftNode = billboardNode->FirstChild("topLeft"); Ogre::Vector3 topLeft; topLeft[0] = Ogre::StringConverter::parseReal(topLeftNode->ToElement()->Attribute("x")); topLeft[1] = Ogre::StringConverter::parseReal(topLeftNode->ToElement()->Attribute("y")); topLeft[2] = Ogre::StringConverter::parseReal(topLeftNode->ToElement()->Attribute("z")); this->setQuadTopLeftCorner(topLeft); TiXmlNode *topRightNode = billboardNode->FirstChild("topRight"); Ogre::Vector3 topRight; topRight[0] = Ogre::StringConverter::parseReal(topRightNode->ToElement()->Attribute("x")); topRight[1] = Ogre::StringConverter::parseReal(topRightNode->ToElement()->Attribute("y")); topRight[2] = Ogre::StringConverter::parseReal(topRightNode->ToElement()->Attribute("z")); this->setQuadTopRightCorner(topRight); TiXmlNode *bottomRightNode = billboardNode->FirstChild("bottomRight"); Ogre::Vector3 bottomRight; bottomRight[0] = Ogre::StringConverter::parseReal(bottomRightNode->ToElement()->Attribute("x")); bottomRight[1] = Ogre::StringConverter::parseReal(bottomRightNode->ToElement()->Attribute("y")); bottomRight[2] = Ogre::StringConverter::parseReal(bottomRightNode->ToElement()->Attribute("z")); this->setQuadBottomRightCorner(bottomRight); TiXmlNode *bottomLeftNode = billboardNode->FirstChild("bottomLeft"); Ogre::Vector3 bottomLeft; bottomLeft[0] = Ogre::StringConverter::parseReal(bottomLeftNode->ToElement()->Attribute("x")); bottomLeft[1] = Ogre::StringConverter::parseReal(bottomLeftNode->ToElement()->Attribute("y")); bottomLeft[2] = Ogre::StringConverter::parseReal(bottomLeftNode->ToElement()->Attribute("z")); this->setQuadBottomLeftCorner(bottomLeft); TiXmlNode *axisXNode = billboardNode->FirstChild("axisX"); Ogre::Vector3 axisX; axisX[0] = Ogre::StringConverter::parseReal(axisXNode->ToElement()->Attribute("x")); axisX[1] = Ogre::StringConverter::parseReal(axisXNode->ToElement()->Attribute("y")); axisX[2] = Ogre::StringConverter::parseReal(axisXNode->ToElement()->Attribute("z")); this->setAxisX(axisX); TiXmlNode *axisYNode = billboardNode->FirstChild("axisY"); Ogre::Vector3 axisY; axisY[0] = Ogre::StringConverter::parseReal(axisYNode->ToElement()->Attribute("x")); axisY[1] = Ogre::StringConverter::parseReal(axisYNode->ToElement()->Attribute("y")); axisY[2] = Ogre::StringConverter::parseReal(axisYNode->ToElement()->Attribute("z")); this->setAxisY(axisY); TiXmlNode *axisZNode = billboardNode->FirstChild("axisZ"); Ogre::Vector3 axisZ; axisZ[0] = Ogre::StringConverter::parseReal(axisZNode->ToElement()->Attribute("x")); axisZ[1] = Ogre::StringConverter::parseReal(axisZNode->ToElement()->Attribute("y")); axisZ[2] = Ogre::StringConverter::parseReal(axisZNode->ToElement()->Attribute("z")); this->setAxisZ(axisZ); if (iBillboardGroup >= 0) { TiXmlNode *uvMapMinNode = billboardNode->FirstChild("uvMapMin"); Ogre::Vector2 uvMapMin; uvMapMin[0] = Ogre::StringConverter::parseReal(uvMapMinNode->ToElement()->Attribute("x")); uvMapMin[1] = Ogre::StringConverter::parseReal(uvMapMinNode->ToElement()->Attribute("y")); this->addBillboardUVMapMin(uvMapMin); TiXmlNode *uvMapMaxNode = billboardNode->FirstChild("uvMapMax"); Ogre::Vector2 uvMapMax; uvMapMax[0] = Ogre::StringConverter::parseReal(uvMapMaxNode->ToElement()->Attribute("x")); uvMapMax[1] = Ogre::StringConverter::parseReal(uvMapMaxNode->ToElement()->Attribute("y")); this->addBillboardUVMapMax(uvMapMax); } } void BillboardKMeansClusterData::writeBillboardClusterData(TiXmlNode *parentNode, int iBillboardGroup) { BBC::EntityClusterPtr entityCluster = getEntityCluster(); Ogre::Vector3 normal = getNormal(); normal.normalise(); float d = 0; for (unsigned int iLeaf = 0; iLeaf < entityCluster->getNumEntitiesClusterData(); iLeaf++) { LeafKMeansClusterData *leafKMeansClusterData = (LeafKMeansClusterData*)entityCluster->getEntityClusterData(iLeaf).get(); Leaf *leaf = (Leaf*)leafKMeansClusterData->getEntity().get(); d = d + leaf->getPosition().dotProduct(normal); } d = - d / entityCluster->getNumEntitiesClusterData(); TiXmlNode *billboardNode; TiXmlNode *coord4dNode; TiXmlNode *uvMapMin; TiXmlNode *uvMapMax; TiXmlNode *quadTopRightCornerNode; TiXmlNode *quadTopLeftCornerNode; TiXmlNode *quadBottomRightCornerNode; TiXmlNode *quadBottomLeftCornerNode; TiXmlNode *axisYNode; TiXmlNode *axisZNode; TiXmlNode *leavesNode; TiXmlNode *leafNode; billboardNode = parentNode->ToElement()->InsertEndChild(TiXmlElement("billboard"))->ToElement(); coord4dNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("coord4d"))->ToElement(); Ogre::String sNX = Ogre::StringConverter::toString(normal.x); coord4dNode->ToElement()->SetAttribute("nx",sNX.c_str()); Ogre::String sNY = Ogre::StringConverter::toString(normal.y); coord4dNode->ToElement()->SetAttribute("ny",sNY.c_str()); Ogre::String sNZ = Ogre::StringConverter::toString(normal.z); coord4dNode->ToElement()->SetAttribute("nz",sNZ.c_str()); Ogre::String sD = Ogre::StringConverter::toString(d); coord4dNode->ToElement()->SetAttribute("d",sD.c_str()); quadTopLeftCornerNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("topLeft"))->ToElement(); Ogre::String sTLX = Ogre::StringConverter::toString(getQuadTopLeftCorner().x); quadTopLeftCornerNode->ToElement()->SetAttribute("x",sTLX.c_str()); Ogre::String sTLY = Ogre::StringConverter::toString(getQuadTopLeftCorner().y); quadTopLeftCornerNode->ToElement()->SetAttribute("y",sTLY.c_str()); Ogre::String sTLZ = Ogre::StringConverter::toString(getQuadTopLeftCorner().z); quadTopLeftCornerNode->ToElement()->SetAttribute("z",sTLZ.c_str()); quadTopRightCornerNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("topRight"))->ToElement(); Ogre::String sTRX = Ogre::StringConverter::toString(getQuadTopRightCorner().x); quadTopRightCornerNode->ToElement()->SetAttribute("x",sTRX.c_str()); Ogre::String sTRY = Ogre::StringConverter::toString(getQuadTopRightCorner().y); quadTopRightCornerNode->ToElement()->SetAttribute("y",sTRY.c_str()); Ogre::String sTRZ = Ogre::StringConverter::toString(getQuadTopRightCorner().z); quadTopRightCornerNode->ToElement()->SetAttribute("z",sTRZ.c_str()); quadBottomRightCornerNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("bottomRight"))->ToElement(); Ogre::String sBRX = Ogre::StringConverter::toString(getQuadBottomRightCorner().x); quadBottomRightCornerNode->ToElement()->SetAttribute("x",sBRX.c_str()); Ogre::String sBRY = Ogre::StringConverter::toString(getQuadBottomRightCorner().y); quadBottomRightCornerNode->ToElement()->SetAttribute("y",sBRY.c_str()); Ogre::String sBRZ = Ogre::StringConverter::toString(getQuadBottomRightCorner().z); quadBottomRightCornerNode->ToElement()->SetAttribute("z",sBRZ.c_str()); quadBottomLeftCornerNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("bottomLeft"))->ToElement(); Ogre::String sBLX = Ogre::StringConverter::toString(getQuadBottomLeftCorner().x); quadBottomLeftCornerNode->ToElement()->SetAttribute("x",sBLX.c_str()); Ogre::String sBLY = Ogre::StringConverter::toString(getQuadBottomLeftCorner().y); quadBottomLeftCornerNode->ToElement()->SetAttribute("y",sBLY.c_str()); Ogre::String sBLZ = Ogre::StringConverter::toString(getQuadBottomLeftCorner().z); quadBottomLeftCornerNode->ToElement()->SetAttribute("z",sBLZ.c_str()); axisYNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("axisX"))->ToElement(); Ogre::String sAXX = Ogre::StringConverter::toString(getAxisX().x); axisYNode->ToElement()->SetAttribute("x",sAXX.c_str()); Ogre::String sAXY = Ogre::StringConverter::toString(getAxisX().y); axisYNode->ToElement()->SetAttribute("y",sAXY.c_str()); Ogre::String sAXZ = Ogre::StringConverter::toString(getAxisX().z); axisYNode->ToElement()->SetAttribute("z",sAXZ.c_str()); axisYNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("axisY"))->ToElement(); Ogre::String sAYX = Ogre::StringConverter::toString(getAxisY().x); axisYNode->ToElement()->SetAttribute("x",sAYX.c_str()); Ogre::String sAYY = Ogre::StringConverter::toString(getAxisY().y); axisYNode->ToElement()->SetAttribute("y",sAYY.c_str()); Ogre::String sAYZ = Ogre::StringConverter::toString(getAxisY().z); axisYNode->ToElement()->SetAttribute("z",sAYZ.c_str()); axisZNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("axisZ"))->ToElement(); Ogre::String sAZX = Ogre::StringConverter::toString(getAxisZ().x); axisZNode->ToElement()->SetAttribute("x",sAZX.c_str()); Ogre::String sAZY = Ogre::StringConverter::toString(getAxisZ().y); axisZNode->ToElement()->SetAttribute("y",sAZY.c_str()); Ogre::String sAZZ = Ogre::StringConverter::toString(getAxisZ().z); axisZNode->ToElement()->SetAttribute("z",sAZZ.c_str()); if (iBillboardGroup >= 0) { uvMapMin = billboardNode->ToElement()->InsertEndChild(TiXmlElement("uvMapMin"))->ToElement(); Ogre::String sUvMapMinX = Ogre::StringConverter::toString(this->getBillboardUVMapMin(0).x); uvMapMin->ToElement()->SetAttribute("x",sUvMapMinX.c_str()); Ogre::String sUvMapMinY = Ogre::StringConverter::toString(this->getBillboardUVMapMin(0).y); uvMapMin->ToElement()->SetAttribute("y",sUvMapMinY.c_str()); uvMapMax = billboardNode->ToElement()->InsertEndChild(TiXmlElement("uvMapMax"))->ToElement(); Ogre::String suvMapMaxX = Ogre::StringConverter::toString(this->getBillboardUVMapMax(0).x); uvMapMax->ToElement()->SetAttribute("x",suvMapMaxX.c_str()); Ogre::String suvMapMaxY = Ogre::StringConverter::toString(this->getBillboardUVMapMax(0).y); uvMapMax->ToElement()->SetAttribute("y",suvMapMaxY.c_str()); } leavesNode = billboardNode->ToElement()->InsertEndChild(TiXmlElement("leaves"))->ToElement(); Ogre::String sLeaves = Ogre::StringConverter::toString(entityCluster->getNumEntitiesClusterData()); leavesNode->ToElement()->SetAttribute("count",sLeaves.c_str()); for (unsigned int iLeaf = 0; iLeaf < entityCluster->getNumEntitiesClusterData(); iLeaf++) { LeafKMeansClusterData *leafKMeansClusterData = (LeafKMeansClusterData*)entityCluster->getEntityClusterData(iLeaf).get(); Leaf *leaf = (Leaf*)leafKMeansClusterData->getEntity().get(); leafNode = leavesNode->ToElement()->InsertEndChild(TiXmlElement("leaf"))->ToElement(); Ogre::String sLeaf = Ogre::StringConverter::toString(leaf->getEntityHandle()); leafNode->ToElement()->SetAttribute("id",sLeaf.c_str()); } } void BillboardKMeansClusterData::generateBillboardBoundingQuad() { Ogre::Vector3 normal = getNormal(); Ogre::Vector3 planePosition; float d = getD(); normal.normalise(); if ((abs(normal[0] > abs(normal[1])) && (abs(normal[0] > abs(normal[2]))))) { planePosition[0] = -d / normal[0]; planePosition[1] = 0; planePosition[2] = 0; } else if ((abs(normal[1] > abs(normal[0])) && (abs(normal[1] > abs(normal[2]))))) { planePosition[0] = 0; planePosition[1] = -d / normal[1]; planePosition[2] = 0; } else { planePosition[0] = 0; planePosition[1] = 0; planePosition[2] = -d / normal[2]; } mAxisX = normal.perpendicular(); mAxisX.normalise(); mAxisY = normal.crossProduct(mAxisX); mAxisY.normalise(); mAxisZ = normal; Ogre::Matrix4 coordPlane; Ogre::Matrix4 constCoord; Ogre::Matrix4 invMCoordPlane; coordPlane[0][0] = mAxisX.x; coordPlane[0][1] = mAxisX.y; coordPlane[0][2] = mAxisX.z; coordPlane[0][3] = 0.0f; coordPlane[1][0] = mAxisY.x; coordPlane[1][1] = mAxisY.y; coordPlane[1][2] = mAxisY.z; coordPlane[1][3] = 0.0f; coordPlane[2][0] = mAxisZ.x; coordPlane[2][1] = mAxisZ.y; coordPlane[2][2] = mAxisZ.z; coordPlane[2][3] = 0.0f; coordPlane[3][0] = planePosition.x; coordPlane[3][1] = planePosition.y; coordPlane[3][2] = planePosition.z; coordPlane[3][3] = 1.0f; invMCoordPlane = coordPlane.inverse(); constCoord[0][0] = 1.0f; constCoord[0][1] = 0.0f; constCoord[0][2] = 0.0f; constCoord[0][3] = 0.0f; constCoord[1][0] = 0.0f; constCoord[1][1] = 1.0f; constCoord[1][2] = 0.0f; constCoord[1][3] = 0.0f; constCoord[2][0] = 0.0f; constCoord[2][1] = 0.0f; constCoord[2][2] = 0.0f; constCoord[2][3] = 0.0f; constCoord[3][0] = 0.0f; constCoord[3][1] = 0.0f; constCoord[3][2] = 0.0f; constCoord[3][3] = 1.0f; float xMax = -FLT_MAX; float xMin = FLT_MAX; float yMax = -FLT_MAX; float yMin = FLT_MAX; Ogre::Vector3 vXmax; Ogre::Vector3 vXmin; Ogre::Vector3 vYmax; Ogre::Vector3 vYmin; BBC::EntityClusterPtr entityCluster = getEntityCluster(); BBC::EntityPtr entity = entityCluster->getEntity(); for (unsigned int iVertex = 0; iVertex < entity->getSubEntity(0)->getNumVertices(); iVertex++) { Ogre::Vector3 position = entity->getSubEntity(0)->getPosition(iVertex); Ogre::Vector4 projPointP1d4 = Ogre::Vector4(position.x,position.y,position.z,1.0f) * invMCoordPlane * constCoord * coordPlane; // The point projected in the plane Ogre::Vector3 projPointP1(projPointP1d4.x,projPointP1d4.y,projPointP1d4.z); float v1 = normal.dotProduct(planePosition); float v2 = normal.dotProduct(position); float t = v1 - v2; projPointP1 = position + (normal * t); float x1 = mAxisX.dotProduct(projPointP1 - planePosition); float y1 = mAxisY.dotProduct(projPointP1 - planePosition); float z1 = mAxisZ.dotProduct(projPointP1 - planePosition); if (x1 > xMax) { xMax = x1; vXmax = projPointP1; } if (x1 < xMin) { xMin = x1; vXmin = projPointP1; } if (y1 > yMax) { yMax = y1; vYmax = projPointP1; } if (y1 < yMin) { yMin = y1; vYmin = projPointP1; } } for (unsigned int iLeaf = 0; iLeaf < entityCluster->getNumEntitiesClusterData(); iLeaf++) { LeafKMeansClusterData *leafKMeansClusterData = (LeafKMeansClusterData*)entityCluster->getEntityClusterData(iLeaf).get(); Leaf *leaf = (Leaf*)leafKMeansClusterData->getEntity().get(); Ogre::Vector3 position = leaf->getPosition(); Ogre::Vector4 projPointP1d4 = Ogre::Vector4(position.x,position.y,position.z,1.0f) * invMCoordPlane * constCoord * coordPlane; // The point projected in the plane Ogre::Vector3 projPointP1(projPointP1d4.x,projPointP1d4.y,projPointP1d4.z); leaf->setPosition(projPointP1); } Ogre::Vector3 aP; Ogre::Vector3 bP; Ogre::Vector3 pP; Ogre::Vector3 abV; Ogre::Vector3 apV; Ogre::Vector3 dProdV; float aLength; float abLength; float dist; Ogre::Vector3 intersectP; aP = vYmin; bP = vYmin + mAxisX; pP = vXmin; abV = bP - aP; apV = pP - aP; dProdV = abV.crossProduct(apV); aLength = dProdV.length(); abLength = abV.length(); dist = aLength / abLength; mBillboardCorners[QUAD_TOP_LEFT] = pP + (mAxisY * (-dist)); aP = vYmax; bP = vYmax + mAxisX; pP = vXmax; abV = bP - aP; apV = pP - aP; dProdV = abV.crossProduct(apV); aLength = dProdV.length(); abLength = abV.length(); dist = aLength / abLength; mBillboardCorners[QUAD_BOTTOM_RIGHT] = pP + (mAxisY * dist); aP = vXmax; bP = vXmax + mAxisY; pP = vYmin; abV = bP - aP; apV = pP - aP; dProdV = abV.crossProduct(apV); aLength = dProdV.length(); abLength = abV.length(); dist = aLength / abLength; mBillboardCorners[QUAD_BOTTOM_LEFT] = pP + (mAxisX * dist); Ogre::Vector3 vDirWidth = mBillboardCorners[QUAD_BOTTOM_LEFT] - mBillboardCorners[QUAD_BOTTOM_RIGHT]; float distWidth = vDirWidth.length(); mBillboardCorners[QUAD_TOP_RIGHT] = mBillboardCorners[QUAD_TOP_LEFT] + (mAxisY * distWidth); } }