mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 05:03:31 +02:00
separate new shape types from legacy
This commit is contained in:
parent
0b78156956
commit
28a3c3f469
6 changed files with 67 additions and 59 deletions
|
@ -760,19 +760,19 @@ void SkeletonModel::buildShapes() {
|
||||||
Shape::Type type = joint.shapeType;
|
Shape::Type type = joint.shapeType;
|
||||||
int parentIndex = joint.parentIndex;
|
int parentIndex = joint.parentIndex;
|
||||||
if (parentIndex == -1 || radius < EPSILON) {
|
if (parentIndex == -1 || radius < EPSILON) {
|
||||||
type = SHAPE_TYPE_UNKNOWN;
|
type = INVALID_SHAPE;
|
||||||
} else if (type == SHAPE_TYPE_CAPSULE && halfHeight < EPSILON) {
|
} else if (type == CAPSULE_SHAPE && halfHeight < EPSILON) {
|
||||||
// this shape is forced to be a sphere
|
// this shape is forced to be a sphere
|
||||||
type = SHAPE_TYPE_SPHERE;
|
type = SPHERE_SHAPE;
|
||||||
}
|
}
|
||||||
Shape* shape = NULL;
|
Shape* shape = NULL;
|
||||||
if (type == SHAPE_TYPE_SPHERE) {
|
if (type == SPHERE_SHAPE) {
|
||||||
shape = new VerletSphereShape(radius, &(points[i]));
|
shape = new VerletSphereShape(radius, &(points[i]));
|
||||||
shape->setEntity(this);
|
shape->setEntity(this);
|
||||||
float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume());
|
float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume());
|
||||||
points[i].setMass(mass);
|
points[i].setMass(mass);
|
||||||
totalMass += mass;
|
totalMass += mass;
|
||||||
} else if (type == SHAPE_TYPE_CAPSULE) {
|
} else if (type == CAPSULE_SHAPE) {
|
||||||
assert(parentIndex != -1);
|
assert(parentIndex != -1);
|
||||||
shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i]));
|
shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i]));
|
||||||
shape->setEntity(this);
|
shape->setEntity(this);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <GeometryUtil.h>
|
#include <GeometryUtil.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <OctalCode.h>
|
#include <OctalCode.h>
|
||||||
|
#include <Shape.h>
|
||||||
|
|
||||||
#include "FBXReader.h"
|
#include "FBXReader.h"
|
||||||
|
|
||||||
|
@ -1999,7 +2000,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
||||||
joint.inverseBindRotation = joint.inverseDefaultRotation;
|
joint.inverseBindRotation = joint.inverseDefaultRotation;
|
||||||
joint.name = model.name;
|
joint.name = model.name;
|
||||||
joint.shapePosition = glm::vec3(0.0f);
|
joint.shapePosition = glm::vec3(0.0f);
|
||||||
joint.shapeType = SHAPE_TYPE_UNKNOWN;
|
joint.shapeType = INVALID_SHAPE;
|
||||||
|
|
||||||
foreach (const QString& childID, childMap.values(modelID)) {
|
foreach (const QString& childID, childMap.values(modelID)) {
|
||||||
QString type = typeFlags.value(childID);
|
QString type = typeFlags.value(childID);
|
||||||
|
@ -2421,10 +2422,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
||||||
if (collideLikeCapsule) {
|
if (collideLikeCapsule) {
|
||||||
joint.shapeRotation = rotationBetween(defaultCapsuleAxis, jointShapeInfo.boneBegin);
|
joint.shapeRotation = rotationBetween(defaultCapsuleAxis, jointShapeInfo.boneBegin);
|
||||||
joint.shapePosition = 0.5f * jointShapeInfo.boneBegin;
|
joint.shapePosition = 0.5f * jointShapeInfo.boneBegin;
|
||||||
joint.shapeType = SHAPE_TYPE_CAPSULE;
|
joint.shapeType = CAPSULE_SHAPE;
|
||||||
} else {
|
} else {
|
||||||
// collide the joint like a sphere
|
// collide the joint like a sphere
|
||||||
joint.shapeType = SHAPE_TYPE_SPHERE;
|
joint.shapeType = SPHERE_SHAPE;
|
||||||
if (jointShapeInfo.numVertices > 0) {
|
if (jointShapeInfo.numVertices > 0) {
|
||||||
jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices;
|
jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices;
|
||||||
joint.shapePosition = jointShapeInfo.averageVertex;
|
joint.shapePosition = jointShapeInfo.averageVertex;
|
||||||
|
@ -2444,8 +2445,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
||||||
if (distanceFromEnd > joint.distanceToParent && distanceFromBegin > joint.distanceToParent) {
|
if (distanceFromEnd > joint.distanceToParent && distanceFromBegin > joint.distanceToParent) {
|
||||||
// The shape is further from both joint endpoints than the endpoints are from each other
|
// The shape is further from both joint endpoints than the endpoints are from each other
|
||||||
// which probably means the model has a bad transform somewhere. We disable this shape
|
// which probably means the model has a bad transform somewhere. We disable this shape
|
||||||
// by setting its type to SHAPE_TYPE_UNKNOWN.
|
// by setting its type to INVALID_SHAPE.
|
||||||
joint.shapeType = SHAPE_TYPE_UNKNOWN;
|
joint.shapeType = INVALID_SHAPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,13 @@
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
#include <Extents.h>
|
|
||||||
#include <Transform.h>
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
|
||||||
|
#include <Extents.h>
|
||||||
|
#include <Transform.h>
|
||||||
|
#include <ShapeInfo.h>
|
||||||
|
|
||||||
#include <model/Geometry.h>
|
#include <model/Geometry.h>
|
||||||
#include <model/Material.h>
|
#include <model/Material.h>
|
||||||
|
|
||||||
|
@ -58,12 +59,6 @@ public:
|
||||||
QVector<glm::vec3> normals;
|
QVector<glm::vec3> normals;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ShapeType {
|
|
||||||
SHAPE_TYPE_SPHERE = 0,
|
|
||||||
SHAPE_TYPE_CAPSULE = 1,
|
|
||||||
SHAPE_TYPE_UNKNOWN = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A single joint (transformation node) extracted from an FBX document.
|
/// A single joint (transformation node) extracted from an FBX document.
|
||||||
class FBXJoint {
|
class FBXJoint {
|
||||||
public:
|
public:
|
||||||
|
@ -88,7 +83,7 @@ public:
|
||||||
QString name;
|
QString name;
|
||||||
glm::vec3 shapePosition; // in joint frame
|
glm::vec3 shapePosition; // in joint frame
|
||||||
glm::quat shapeRotation; // in joint frame
|
glm::quat shapeRotation; // in joint frame
|
||||||
ShapeType shapeType;
|
quint8 shapeType;
|
||||||
bool isSkeletonJoint;
|
bool isSkeletonJoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <Shape.h> // for FOO_SHAPE types
|
#include <ShapeInfo.h>
|
||||||
#include <SharedUtil.h> // for MILLIMETERS_PER_METER
|
#include <SharedUtil.h> // for MILLIMETERS_PER_METER
|
||||||
|
|
||||||
#include "ShapeInfoUtil.h"
|
#include "ShapeInfoUtil.h"
|
||||||
|
@ -18,16 +18,16 @@
|
||||||
int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) {
|
int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) {
|
||||||
int bulletShapeType = INVALID_SHAPE_PROXYTYPE;
|
int bulletShapeType = INVALID_SHAPE_PROXYTYPE;
|
||||||
switch(shapeInfoType) {
|
switch(shapeInfoType) {
|
||||||
case BOX_SHAPE:
|
case SHAPE_TYPE_BOX:
|
||||||
bulletShapeType = BOX_SHAPE_PROXYTYPE;
|
bulletShapeType = BOX_SHAPE_PROXYTYPE;
|
||||||
break;
|
break;
|
||||||
case SPHERE_SHAPE:
|
case SHAPE_TYPE_SPHERE:
|
||||||
bulletShapeType = SPHERE_SHAPE_PROXYTYPE;
|
bulletShapeType = SPHERE_SHAPE_PROXYTYPE;
|
||||||
break;
|
break;
|
||||||
case CAPSULE_SHAPE:
|
case SHAPE_TYPE_CAPSULE:
|
||||||
bulletShapeType = CAPSULE_SHAPE_PROXYTYPE;
|
bulletShapeType = CAPSULE_SHAPE_PROXYTYPE;
|
||||||
break;
|
break;
|
||||||
case CYLINDER_SHAPE:
|
case SHAPE_TYPE_CYLINDER:
|
||||||
bulletShapeType = CYLINDER_SHAPE_PROXYTYPE;
|
bulletShapeType = CYLINDER_SHAPE_PROXYTYPE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -35,19 +35,19 @@ int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) {
|
int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) {
|
||||||
int shapeInfoType = INVALID_SHAPE;
|
int shapeInfoType = SHAPE_TYPE_NONE;
|
||||||
switch(bulletShapeType) {
|
switch(bulletShapeType) {
|
||||||
case BOX_SHAPE_PROXYTYPE:
|
case BOX_SHAPE_PROXYTYPE:
|
||||||
shapeInfoType = BOX_SHAPE;
|
shapeInfoType = SHAPE_TYPE_BOX;
|
||||||
break;
|
break;
|
||||||
case SPHERE_SHAPE_PROXYTYPE:
|
case SPHERE_SHAPE_PROXYTYPE:
|
||||||
shapeInfoType = SPHERE_SHAPE;
|
shapeInfoType = SHAPE_TYPE_SPHERE;
|
||||||
break;
|
break;
|
||||||
case CAPSULE_SHAPE_PROXYTYPE:
|
case CAPSULE_SHAPE_PROXYTYPE:
|
||||||
shapeInfoType = CAPSULE_SHAPE;
|
shapeInfoType = SHAPE_TYPE_CAPSULE;
|
||||||
break;
|
break;
|
||||||
case CYLINDER_SHAPE_PROXYTYPE:
|
case CYLINDER_SHAPE_PROXYTYPE:
|
||||||
shapeInfoType = CYLINDER_SHAPE;
|
shapeInfoType = SHAPE_TYPE_CYLINDER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return shapeInfoType;
|
return shapeInfoType;
|
||||||
|
@ -57,24 +57,24 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf
|
||||||
if (shape) {
|
if (shape) {
|
||||||
int type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType());
|
int type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType());
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case BOX_SHAPE: {
|
case SHAPE_TYPE_BOX: {
|
||||||
const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
|
const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
|
||||||
info.setBox(bulletToGLM(boxShape->getHalfExtentsWithMargin()));
|
info.setBox(bulletToGLM(boxShape->getHalfExtentsWithMargin()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPHERE_SHAPE: {
|
case SHAPE_TYPE_SPHERE: {
|
||||||
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
|
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
|
||||||
info.setSphere(sphereShape->getRadius());
|
info.setSphere(sphereShape->getRadius());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CYLINDER_SHAPE: {
|
case SHAPE_TYPE_CYLINDER: {
|
||||||
// NOTE: we only support cylinders along yAxis
|
// NOTE: we only support cylinders along yAxis
|
||||||
const btCylinderShape* cylinderShape = static_cast<const btCylinderShape*>(shape);
|
const btCylinderShape* cylinderShape = static_cast<const btCylinderShape*>(shape);
|
||||||
btVector3 halfExtents = cylinderShape->getHalfExtentsWithMargin();
|
btVector3 halfExtents = cylinderShape->getHalfExtentsWithMargin();
|
||||||
info.setCylinder(halfExtents.getX(), halfExtents.getY());
|
info.setCylinder(halfExtents.getX(), halfExtents.getY());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CAPSULE_SHAPE: {
|
case SHAPE_TYPE_CAPSULE: {
|
||||||
// NOTE: we only support capsules along yAxis
|
// NOTE: we only support capsules along yAxis
|
||||||
const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
|
const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
|
||||||
info.setCapsule(capsuleShape->getRadius(), capsuleShape->getHalfHeight());
|
info.setCapsule(capsuleShape->getRadius(), capsuleShape->getHalfHeight());
|
||||||
|
@ -93,23 +93,23 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
||||||
btCollisionShape* shape = NULL;
|
btCollisionShape* shape = NULL;
|
||||||
const QVector<glm::vec3>& data = info.getData();
|
const QVector<glm::vec3>& data = info.getData();
|
||||||
switch(info.getType()) {
|
switch(info.getType()) {
|
||||||
case BOX_SHAPE: {
|
case SHAPE_TYPE_BOX: {
|
||||||
// data[0] is halfExtents
|
// data[0] is halfExtents
|
||||||
shape = new btBoxShape(glmToBullet(data[0]));
|
shape = new btBoxShape(glmToBullet(data[0]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPHERE_SHAPE: {
|
case SHAPE_TYPE_SPHERE: {
|
||||||
float radius = data[0].z;
|
float radius = data[0].z;
|
||||||
shape = new btSphereShape(radius);
|
shape = new btSphereShape(radius);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CYLINDER_SHAPE: {
|
case SHAPE_TYPE_CYLINDER: {
|
||||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||||
// data[0] = btVector3(radius, halfHeight, unused)
|
// data[0] = btVector3(radius, halfHeight, unused)
|
||||||
shape = new btCylinderShape(glmToBullet(data[0]));
|
shape = new btCylinderShape(glmToBullet(data[0]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CAPSULE_SHAPE: {
|
case SHAPE_TYPE_CAPSULE: {
|
||||||
float radius = data[0].x;
|
float radius = data[0].x;
|
||||||
float height = 2.0f * data[0].y;
|
float height = 2.0f * data[0].y;
|
||||||
shape = new btCapsuleShape(radius, height);
|
shape = new btCapsuleShape(radius, height);
|
||||||
|
|
|
@ -17,26 +17,26 @@
|
||||||
#include "ShapeInfo.h"
|
#include "ShapeInfo.h"
|
||||||
|
|
||||||
void ShapeInfo::clear() {
|
void ShapeInfo::clear() {
|
||||||
_type = INVALID_SHAPE;
|
_type = SHAPE_TYPE_NONE;
|
||||||
_data.clear();
|
_data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
||||||
_type = BOX_SHAPE;
|
_type = SHAPE_TYPE_BOX;
|
||||||
_data.clear();
|
_data.clear();
|
||||||
// _data[0] = < halfX, halfY, halfZ >
|
// _data[0] = < halfX, halfY, halfZ >
|
||||||
_data.push_back(halfExtents);
|
_data.push_back(halfExtents);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setSphere(float radius) {
|
void ShapeInfo::setSphere(float radius) {
|
||||||
_type = SPHERE_SHAPE;
|
_type = SHAPE_TYPE_SPHERE;
|
||||||
_data.clear();
|
_data.clear();
|
||||||
// _data[0] = < radius, radius, radius >
|
// _data[0] = < radius, radius, radius >
|
||||||
_data.push_back(glm::vec3(radius));
|
_data.push_back(glm::vec3(radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setCylinder(float radius, float halfHeight) {
|
void ShapeInfo::setCylinder(float radius, float halfHeight) {
|
||||||
_type = CYLINDER_SHAPE;
|
_type = SHAPE_TYPE_CYLINDER;
|
||||||
_data.clear();
|
_data.clear();
|
||||||
// _data[0] = < radius, halfHeight, radius >
|
// _data[0] = < radius, halfHeight, radius >
|
||||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||||
|
@ -44,7 +44,7 @@ void ShapeInfo::setCylinder(float radius, float halfHeight) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setCapsule(float radius, float halfHeight) {
|
void ShapeInfo::setCapsule(float radius, float halfHeight) {
|
||||||
_type = CAPSULE_SHAPE;
|
_type = SHAPE_TYPE_CAPSULE;
|
||||||
_data.clear();
|
_data.clear();
|
||||||
// _data[0] = < radius, halfHeight, radius >
|
// _data[0] = < radius, halfHeight, radius >
|
||||||
_data.push_back(glm::vec3(radius, halfHeight, radius));
|
_data.push_back(glm::vec3(radius, halfHeight, radius));
|
||||||
|
@ -52,10 +52,10 @@ void ShapeInfo::setCapsule(float radius, float halfHeight) {
|
||||||
|
|
||||||
glm::vec3 ShapeInfo::getBoundingBoxDiagonal() const {
|
glm::vec3 ShapeInfo::getBoundingBoxDiagonal() const {
|
||||||
switch(_type) {
|
switch(_type) {
|
||||||
case BOX_SHAPE:
|
case SHAPE_TYPE_BOX:
|
||||||
case SPHERE_SHAPE:
|
case SHAPE_TYPE_SPHERE:
|
||||||
case CYLINDER_SHAPE:
|
case SHAPE_TYPE_CYLINDER:
|
||||||
case CAPSULE_SHAPE:
|
case SHAPE_TYPE_CAPSULE:
|
||||||
return 2.0f * _data[0];
|
return 2.0f * _data[0];
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -67,22 +67,22 @@ float ShapeInfo::computeVolume() const {
|
||||||
const float DEFAULT_VOLUME = 1.0f;
|
const float DEFAULT_VOLUME = 1.0f;
|
||||||
float volume = DEFAULT_VOLUME;
|
float volume = DEFAULT_VOLUME;
|
||||||
switch(_type) {
|
switch(_type) {
|
||||||
case BOX_SHAPE: {
|
case SHAPE_TYPE_BOX: {
|
||||||
// factor of 8.0 because the components of _data[0] are all halfExtents
|
// factor of 8.0 because the components of _data[0] are all halfExtents
|
||||||
volume = 8.0f * _data[0].x * _data[0].y * _data[0].z;
|
volume = 8.0f * _data[0].x * _data[0].y * _data[0].z;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPHERE_SHAPE: {
|
case SHAPE_TYPE_SPHERE: {
|
||||||
float radius = _data[0].x;
|
float radius = _data[0].x;
|
||||||
volume = 4.0f * PI * radius * radius * radius / 3.0f;
|
volume = 4.0f * PI * radius * radius * radius / 3.0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CYLINDER_SHAPE: {
|
case SHAPE_TYPE_CYLINDER: {
|
||||||
float radius = _data[0].x;
|
float radius = _data[0].x;
|
||||||
volume = PI * radius * radius * 2.0f * _data[0].y;
|
volume = PI * radius * radius * 2.0f * _data[0].y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CAPSULE_SHAPE: {
|
case SHAPE_TYPE_CAPSULE: {
|
||||||
float radius = _data[0].x;
|
float radius = _data[0].x;
|
||||||
volume = PI * radius * radius * (2.0f * _data[0].y + 4.0f * radius / 3.0f);
|
volume = PI * radius * radius * (2.0f * _data[0].y + 4.0f * radius / 3.0f);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,9 +17,21 @@
|
||||||
|
|
||||||
#include "Shape.h"
|
#include "Shape.h"
|
||||||
|
|
||||||
|
enum ShapeType {
|
||||||
|
SHAPE_TYPE_NONE,
|
||||||
|
SHAPE_TYPE_BOX,
|
||||||
|
SHAPE_TYPE_SPHERE,
|
||||||
|
SHAPE_TYPE_ELLIPSOID,
|
||||||
|
SHAPE_TYPE_CYLINDER,
|
||||||
|
SHAPE_TYPE_CAPSULE,
|
||||||
|
SHAPE_TYPE_CONVEX_HULL,
|
||||||
|
SHAPE_TYPE_PLANE,
|
||||||
|
SHAPE_TYPE_COMPOUND
|
||||||
|
};
|
||||||
|
|
||||||
class ShapeInfo {
|
class ShapeInfo {
|
||||||
public:
|
public:
|
||||||
ShapeInfo() : _type(INVALID_SHAPE) {}
|
ShapeInfo() : _type(SHAPE_TYPE_NONE) {}
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue