void Brush_ConstructCuboid(Brush& brush, const AABB& bounds, const std::string& shader, const TextureProjection& projection) { const unsigned char box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } }; Vector3 mins(bounds.origin - bounds.extents); Vector3 maxs(bounds.origin + bounds.extents); brush.clear(); brush.reserve(6); { for(int i=0; i < 3; ++i) { Vector3 planepts1(maxs); Vector3 planepts2(maxs); planepts2[box[i][0]] = mins[box[i][0]]; planepts1[box[i][1]] = mins[box[i][1]]; brush.addPlane(maxs, planepts1, planepts2, shader, projection); } } { for(int i=0; i < 3; ++i) { Vector3 planepts1(mins); Vector3 planepts2(mins); planepts1[box[i][0]] = maxs[box[i][0]]; planepts2[box[i][1]] = maxs[box[i][1]]; brush.addPlane(mins, planepts1, planepts2, shader, projection); } } }
void Cone::generate (Brush& brush, const AABB& bounds, std::size_t sides, const TextureProjection& projection, const std::string& shader) { if (sides < _minSides) { gtkutil::errorDialog(_("Too few sides for constructing the prism, minimum is 3")); return; } if (sides > _maxSides) { gtkutil::errorDialog(_("Too many sides for constructing the prism, maximum is 32")); return; } brush.clear(); brush.reserve(sides + 1); Vector3 mins(bounds.origin - bounds.extents); Vector3 maxs(bounds.origin + bounds.extents); float radius = maxExtent(bounds.extents); const Vector3& mid = bounds.origin; Vector3 planepts[3]; planepts[0][0] = mins[0]; planepts[0][1] = mins[1]; planepts[0][2] = mins[2]; planepts[1][0] = maxs[0]; planepts[1][1] = mins[1]; planepts[1][2] = mins[2]; planepts[2][0] = maxs[0]; planepts[2][1] = maxs[1]; planepts[2][2] = mins[2]; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); for (std::size_t i = 0; i < sides; ++i) { double sv = sin(i * 3.14159265 * 2 / sides); double cv = cos(i * 3.14159265 * 2 / sides); planepts[0][0] = static_cast<float> (floor(mid[0] + radius * cv + 0.5)); planepts[0][1] = static_cast<float> (floor(mid[1] + radius * sv + 0.5)); planepts[0][2] = mins[2]; planepts[1][0] = mid[0]; planepts[1][1] = mid[1]; planepts[1][2] = maxs[2]; planepts[2][0] = static_cast<float> (floor(planepts[0][0] - radius * sv + 0.5)); planepts[2][1] = static_cast<float> (floor(planepts[0][1] + radius * cv + 0.5)); planepts[2][2] = maxs[2]; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); } }
void Brush_ConstructSphere(Brush& brush, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection) { if(sides < c_brushSphere_minSides) { globalErrorStream() << c_brushSphere_name << ": sides " << Unsigned(sides) << ": too few sides, minimum is " << Unsigned(c_brushSphere_minSides) << "\n"; return; } if(sides > c_brushSphere_maxSides) { globalErrorStream() << c_brushSphere_name << ": sides " << Unsigned(sides) << ": too many sides, maximum is " << Unsigned(c_brushSphere_maxSides) << "\n"; return; } brush.undoSave(); brush.clear(); brush.reserve(sides*sides); float radius = max_extent(bounds.extents); const Vector3& mid = bounds.origin; Vector3 planepts[3]; double dt = 2 * c_pi / sides; double dp = c_pi / sides; for(std::size_t i=0; i < sides; i++) { for(std::size_t j=0;j < sides-1; j++) { double t = i * dt; double p = float(j * dp - c_pi / 2); planepts[0] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t, p), radius)); planepts[1] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t, p + dp), radius)); planepts[2] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t + dt, p + dp), radius)); brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); } } { double p = (sides - 1) * dp - c_pi / 2; for(std::size_t i = 0; i < sides; i++) { double t = i * dt; planepts[0] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t, p), radius)); planepts[1] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t + dt, p + dp), radius)); planepts[2] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t + dt, p), radius)); brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); } } }
void Brush_ConstructCone(Brush& brush, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection) { if(sides < c_brushCone_minSides) { globalErrorStream() << c_brushCone_name << ": sides " << Unsigned(sides) << ": too few sides, minimum is " << Unsigned(c_brushCone_minSides) << "\n"; return; } if(sides > c_brushCone_maxSides) { globalErrorStream() << c_brushCone_name << ": sides " << Unsigned(sides) << ": too many sides, maximum is " << Unsigned(c_brushCone_maxSides) << "\n"; return; } brush.undoSave(); brush.clear(); brush.reserve(sides+1); Vector3 mins(vector3_subtracted(bounds.origin, bounds.extents)); Vector3 maxs(vector3_added(bounds.origin, bounds.extents)); float radius = max_extent(bounds.extents); const Vector3& mid = bounds.origin; Vector3 planepts[3]; planepts[0][0] = mins[0];planepts[0][1] = mins[1];planepts[0][2] = mins[2]; planepts[1][0] = maxs[0];planepts[1][1] = mins[1];planepts[1][2] = mins[2]; planepts[2][0] = maxs[0];planepts[2][1] = maxs[1];planepts[2][2] = mins[2]; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); for (std::size_t i=0 ; i<sides ; ++i) { double sv = sin (i*3.14159265*2/sides); double cv = cos (i*3.14159265*2/sides); planepts[0][0] = static_cast<float>(floor(mid[0]+radius*cv+0.5)); planepts[0][1] = static_cast<float>(floor(mid[1]+radius*sv+0.5)); planepts[0][2] = mins[2]; planepts[1][0] = mid[0]; planepts[1][1] = mid[1]; planepts[1][2] = maxs[2]; planepts[2][0] = static_cast<float>(floor(planepts[0][0] - radius * sv + 0.5)); planepts[2][1] = static_cast<float>(floor(planepts[0][1] + radius * cv + 0.5)); planepts[2][2] = maxs[2]; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); } }
void Sphere::generate (Brush& brush, const AABB& bounds, std::size_t sides, const TextureProjection& projection, const std::string& shader) { if (sides < _minSides) { gtkutil::errorDialog(_("Too few sides for constructing the sphere, minimum is 3")); return; } if (sides > _maxSides) { gtkutil::errorDialog(_("Too many sides for constructing the sphere, maximum is 31")); return; } brush.clear(); brush.reserve(sides * sides); float radius = maxExtent(bounds.extents); const Vector3& mid = bounds.origin; Vector3 planepts[3]; double dt = 2 * c_pi / sides; double dp = c_pi / sides; for (std::size_t i = 0; i < sides; i++) { for (std::size_t j = 0; j < sides - 1; j++) { double t = i * dt; double p = float(j * dp - c_pi / 2); planepts[0] = mid + vector3_for_spherical(t, p) * radius; planepts[1] = mid + vector3_for_spherical(t, p + dp) * radius; planepts[2] = mid + vector3_for_spherical(t + dt, p + dp) * radius; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); } } { double p = (sides - 1) * dp - c_pi / 2; for (std::size_t i = 0; i < sides; i++) { double t = i * dt; planepts[0] = mid + vector3_for_spherical(t, p) * radius; planepts[1] = mid + vector3_for_spherical(t + dt, p + dp) * radius; planepts[2] = mid + vector3_for_spherical(t + dt, p) * radius; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); } } }
void Brush_ConstructPrism(Brush& brush, const AABB& bounds, std::size_t sides, int axis, const std::string& shader, const TextureProjection& projection) { if(sides < c_brushPrism_minSides) { globalErrorStream() << c_brushPrism_name << ": sides " << sides << ": too few sides, minimum is " << c_brushPrism_minSides << "\n"; return; } if(sides > c_brushPrism_maxSides) { globalErrorStream() << c_brushPrism_name << ": sides " << sides << ": too many sides, maximum is " << c_brushPrism_maxSides << "\n"; return; } brush.clear(); brush.reserve(sides+2); Vector3 mins(bounds.origin - bounds.extents); Vector3 maxs(bounds.origin + bounds.extents); float radius = max_extent_2d(bounds.extents, axis); const Vector3& mid = bounds.origin; Vector3 planepts[3]; planepts[2][(axis+1)%3] = mins[(axis+1)%3]; planepts[2][(axis+2)%3] = mins[(axis+2)%3]; planepts[2][axis] = maxs[axis]; planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; planepts[1][(axis+2)%3] = mins[(axis+2)%3]; planepts[1][axis] = maxs[axis]; planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; planepts[0][axis] = maxs[axis]; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); planepts[0][(axis+1)%3] = mins[(axis+1)%3]; planepts[0][(axis+2)%3] = mins[(axis+2)%3]; planepts[0][axis] = mins[axis]; planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; planepts[1][(axis+2)%3] = mins[(axis+2)%3]; planepts[1][axis] = mins[axis]; planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; planepts[2][axis] = mins[axis]; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); for (std::size_t i=0 ; i<sides ; ++i) { double sv = sin (i*3.14159265*2/sides); double cv = cos (i*3.14159265*2/sides); planepts[0][(axis+1)%3] = static_cast<float>(floor(mid[(axis+1)%3]+radius*cv+0.5)); planepts[0][(axis+2)%3] = static_cast<float>(floor(mid[(axis+2)%3]+radius*sv+0.5)); planepts[0][axis] = mins[axis]; planepts[1][(axis+1)%3] = planepts[0][(axis+1)%3]; planepts[1][(axis+2)%3] = planepts[0][(axis+2)%3]; planepts[1][axis] = maxs[axis]; planepts[2][(axis+1)%3] = static_cast<float>(floor(planepts[0][(axis+1)%3] - radius*sv + 0.5)); planepts[2][(axis+2)%3] = static_cast<float>(floor(planepts[0][(axis+2)%3] + radius*cv + 0.5)); planepts[2][axis] = maxs[axis]; brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection); } }
void BrushByPlaneClipper::visit(const scene::INodePtr& node) const { // Don't clip invisible nodes if (!node->visible()) { return; } // Try to cast the instance onto a brush Brush* brush = Node_getBrush(node); // Return if not brush if (brush == NULL) { return; } Plane3 plane(_p0, _p1, _p2); if (!plane.isValid()) { return; } // greebo: Analyse the brush to find out which shader is the most used one getMostUsedTexturing(brush); BrushSplitType split = Brush_classifyPlane(*brush, _split == eFront ? -plane : plane); if (split.counts[ePlaneBack] && split.counts[ePlaneFront]) { // the plane intersects this brush if (_split == eFrontAndBack) { scene::INodePtr brushNode = GlobalBrushCreator().createBrush(); assert(brushNode != NULL); Brush* fragment = Node_getBrush(brushNode); assert(fragment != NULL); fragment->copy(*brush); FacePtr newFace = fragment->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split != eFront) { newFace->flipWinding(); } fragment->removeEmptyFaces(); ASSERT_MESSAGE(!fragment->empty(), "brush left with no faces after split"); // Mark this brush for insertion _insertList.insert(InsertMap::value_type(brushNode, node->getParent())); } FacePtr newFace = brush->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split == eFront) { newFace->flipWinding(); } brush->removeEmptyFaces(); ASSERT_MESSAGE(!brush->empty(), "brush left with no faces after split"); } // the plane does not intersect this brush else if (_split != eFrontAndBack && split.counts[ePlaneBack] != 0) { // the brush is "behind" the plane _deleteList.insert(node); } }
void BrushByPlaneClipper::split(const BrushPtrVector& brushes) { Plane3 plane(_p0, _p1, _p2); if (!plane.isValid()) { return; } for (BrushPtrVector::const_iterator i = brushes.begin(); i != brushes.end(); ++i) { const BrushNodePtr& node = *i; // Don't clip invisible nodes if (!node->visible()) { continue; } Brush& brush = node->getBrush(); scene::INodePtr parent = node->getParent(); if (!parent) { continue; } // greebo: Analyse the brush to find out which shader is the most used one getMostUsedTexturing(brush); BrushSplitType split = Brush_classifyPlane(brush, _split == eFront ? -plane : plane); if (split.counts[ePlaneBack] && split.counts[ePlaneFront]) { // the plane intersects this brush if (_split == eFrontAndBack) { scene::INodePtr fragmentNode = GlobalBrushCreator().createBrush(); assert(fragmentNode != NULL); // Put the fragment in the same layer as the brush it was clipped from // Do this before adding the fragment to the parent, since there is an // update algorithm setting the visibility of the fragment right there. scene::assignNodeToLayers(fragmentNode, node->getLayers()); // greebo: For copying the texture scale the new node needs to be inserted in the scene // otherwise the shaders cannot be captured and the scale is off // Insert the child into the designated parent scene::addNodeToContainer(fragmentNode, parent); // Select the child Node_setSelected(fragmentNode, true); Brush* fragment = Node_getBrush(fragmentNode); assert(fragment != NULL); fragment->copy(brush); FacePtr newFace = fragment->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split != eFront) { newFace->flipWinding(); } fragment->removeEmptyFaces(); ASSERT_MESSAGE(!fragment->empty(), "brush left with no faces after split"); } FacePtr newFace = brush.addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split == eFront) { newFace->flipWinding(); } brush.removeEmptyFaces(); ASSERT_MESSAGE(!brush.empty(), "brush left with no faces after split"); } // the plane does not intersect this brush else if (_split != eFrontAndBack && split.counts[ePlaneBack] != 0) { // the brush is "behind" the plane // Remove the node from the scene scene::removeNodeFromParent(node); } } }