/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "scene3d/mitem.h" #include "binding_helpers.h" using namespace GS; using namespace GS::S3D; using namespace GS::Script; //------------------------------------------------------------------------------ #define __SQ_TEST_ITEM_PHYSIC if (!item->physic_item) return sq_throwerror(vm, "No physic interface."); SQInteger ItemSetSelfMask(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(item, MItem, typetag_Item) __SQ_GETINT(mask) __SQ_GETEND __SQ_TEST_ITEM_PHYSIC item->physic_item->SetSelfMask(mask); __SQ_RETURN } SQInteger ItemCollisionActivate(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(item, MItem, typetag_Item) __SQ_GETBOOL(active) __SQ_GETEND __SQ_TEST_ITEM_PHYSIC item->physic_item->SetActive(asbool(active)); __SQ_RETURN } SQInteger ItemSetCollisionMask(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(item, MItem, typetag_Item) __SQ_GETINT(mask) __SQ_GETEND __SQ_TEST_ITEM_PHYSIC item->physic_item->SetCollisionMask(mask); __SQ_RETURN } SQInteger ItemGetShapeFromIndex(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(item, MItem, typetag_Item) __SQ_GETINT(idx) __SQ_GETEND __SQ_TEST_ITEM_PHYSIC if (idx < (SQInteger)item->physic_item_desc.shape_list.GetCount()) __SQ_RETURNSAFEPTR(item->physic_item_desc.shape_list[idx], typetag_ColShape) __SQ_RETURNNULL } SQInteger ItemAddCollisionShape(HSQUIRRELVM vm) { __SQ_GETSINGLESAFEPTR(item, MItem, typetag_Item) __SQ_TEST_ITEM_PHYSIC PhysicShape *shape = new PhysicShape; if (!shape) return sq_throwerror(vm, "Failed to allocate collision shape."); item->physic_item_desc.shape_list.Add(shape); __SQ_RETURNSAFEPTR(shape, typetag_ColShape) } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ SQInteger ShapeSetMesh(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETSTRING(path) bool r = path ? shape->Set(PhysicShape::TypeMesh, path) : false; __SQ_GETEND __SQ_RETURNBOOL(r) } SQInteger ShapeSetConvex(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETSTRING(path) bool r = path ? shape->Set(PhysicShape::TypeConvex, path) : false; __SQ_GETEND __SQ_RETURNBOOL(r) } SQInteger ShapeSetSphere(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETFLOAT(radius) __SQ_GETEND __SQ_RETURNBOOL(shape->Set(PhysicShape::TypeSphere, Vector4(radius, 0, 0))) } SQInteger ShapeSetBox(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETVECTOR(scale) __SQ_GETEND __SQ_RETURNBOOL(shape->Set(PhysicShape::TypeBox, scale)) } SQInteger ShapeSetCapsule(HSQUIRRELVM vm) { __SQ_GETSTART(3) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETFLOAT(radius) __SQ_GETFLOAT(length) __SQ_GETEND __SQ_RETURNBOOL(shape->Set(PhysicShape::TypeCapsule, Vector4(radius, length, 0.0))) } SQInteger ShapeSetCylinder(HSQUIRRELVM vm) { __SQ_GETSTART(3) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETFLOAT(radius) __SQ_GETFLOAT(length) __SQ_GETEND __SQ_RETURNBOOL(shape->Set(PhysicShape::TypeCylinder, Vector4(radius, length, 0.0))) } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ SQInteger ShapeGetItem(HSQUIRRELVM vm) { __SQ_GETSINGLESAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_RETURNSAFEPTR(NULL, typetag_Item); } SQInteger ShapeGetPosition(HSQUIRRELVM vm) { __SQ_GETSINGLESAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_RETURNVECTOR(shape->position) } SQInteger ShapeSetPosition(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETVECTOR(p) __SQ_GETEND shape->position = p; __SQ_RETURN } SQInteger ShapeGetRotation(HSQUIRRELVM vm) { __SQ_GETSINGLESAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_RETURNVECTOR(shape->rotation) } SQInteger ShapeSetRotation(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETVECTOR(e) __SQ_GETEND shape->rotation = e; __SQ_RETURN } SQInteger ShapeSetRestitution(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETFLOAT(r) __SQ_GETEND shape->restitution = r; __SQ_RETURN } SQInteger ShapeSetFriction(HSQUIRRELVM vm) { __SQ_GETSTART(3) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETFLOAT(df) __SQ_GETFLOAT(sf) __SQ_GETEND shape->dynamic_friction = df; shape->static_friction = sf; __SQ_RETURN } SQInteger ShapeGetMass(HSQUIRRELVM vm) { __SQ_GETSINGLESAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_RETURNFLOAT(shape->mass) } SQInteger ShapeSetMass(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETSAFEPTR(shape, PhysicShape, typetag_ColShape) __SQ_GETFLOAT(mass) __SQ_GETEND shape->mass = mass; __SQ_RETURN } //------------------------------------------------------------------------------ // //poly poly intersection //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Gather up one-dimensional extents of the projection of the polygon // onto this axis. void gatherPolygonProjectionExtents(GS::Array poly, GS::Vector4 v, float &outMin, float &outMax) { // Initialize extents to a single point, the first vertex outMin = outMax = v.Dot(poly[0]); // Now scan all the rest, growing extents to include them for (uint i = 1; i < poly.GetCount(); ++i) { float d = v.Dot(poly[i]); if (d < outMin) outMin = d; else if (d > outMax) outMax = d; } } // Helper routine: test if two convex polygons overlap, using only the edges of // the first polygon (polygon "a") to build the list of candidate separating axes. bool findSeparatingAxis(GS::Array poly_a, GS::Array poly_b) { // Iterate over all the edges uint prev = poly_a.GetCount() - 1; for (uint cur = 0; cur < poly_a.GetCount(); ++cur) { // Get edge vector. (Assume operator- is overloaded) GS::Vector4 edge = poly_a[cur] - poly_a[prev]; edge.y = 0; edge.Normalize(); // Rotate vector 90 degrees (doesn't matter which way) to get // candidate separating axis. GS::Vector4 v(edge.z, 0, -edge.x); // Gather extents of both polygons projected onto this axis float result_poly_a_min, result_poly_a_max; gatherPolygonProjectionExtents(poly_a, v, result_poly_a_min, result_poly_a_max); float result_poly_b_min, result_poly_b_max; gatherPolygonProjectionExtents(poly_b, v, result_poly_b_min, result_poly_b_max); // Is this a separating axis? if (result_poly_a_max < result_poly_b_min) return true; if (result_poly_b_max < result_poly_a_min) return true; // Next edge, please prev = cur; } // Failed to find a separating axis return false; } // Here is our high level entry point. It tests whether two polygons intersect. The // polygons must be convex, and they must not be degenerate. bool convexPolygonOverlap(GS::Array poly_a, GS::Array poly_b) //poly[a, b, c, d] { // First, use all of A's edges to get candidate separating axes if (findSeparatingAxis(poly_a, poly_b)) return false; // Now swap roles, and use B's edges if (findSeparatingAxis(poly_b, poly_a)) return false; // No separating axis found. They must overlap return true; } SQInteger convexPolygonOverlapBind(HSQUIRRELVM vm) { __SQ_GETSTART(2) GS::Array poly_a(4); sq_pushnull(vm);//null iterator for (int i = 0; i < 4; ++i) { sq_next(vm, __SQ_STACKPOS - 1); GetVector(vm, -1, poly_a[i]); sq_pop(vm, 2); } sq_pop(vm, 1); //pops the null iterator __SQ_GETUPDATESTACK GS::Array poly_b(4); sq_pushnull(vm);//null iterator for (int i = 0; i < 4; ++i) { sq_next(vm, __SQ_STACKPOS - 1); GetVector(vm, -1, poly_b[i]); sq_pop(vm, 2); } sq_pop(vm, 1); //pops the null iterator __SQ_GETEND __SQ_RETURNBOOL(convexPolygonOverlap(poly_a, poly_b)); } //------------------------------------------------------------ bool PointInPoly2D(GS::Vector4 point, GS::Array poly) // poly = [Vector(), Vector(), Vector(), Vector()] //------------------------------------------------------------ { bool oddNodes = false; float x2 = poly[3].x; float z2 = poly[3].z; float x1, z1; // vertex a x1 = poly[0].x; z1 = poly[0].z; if (((z1 < point.z) && (z2 >= point.z)) || (z1 >= point.z) && (z2 < point.z)) { if ((point.z - z1) / (z2 - z1) * (x2 - x1) < (point.x - x1)) oddNodes = !oddNodes; } x2 = x1; z2 = z1; // vertex b x1 = poly[1].x; z1 = poly[1].z; if (((z1 < point.z) && (z2 >= point.z)) || (z1 >= point.z) && (z2 < point.z)) { if ((point.z - z1) / (z2 - z1) * (x2 - x1) < (point.x - x1)) oddNodes = !oddNodes; } x2 = x1; z2 = z1; // vertex c x1 = poly[2].x; z1 = poly[2].z; if (((z1 < point.z) && (z2 >= point.z)) || (z1 >= point.z) && (z2 < point.z)) { if ((point.z - z1) / (z2 - z1) * (x2 - x1) < (point.x - x1)) oddNodes = !oddNodes; } x2 = x1; z2 = z1; // vertex d x1 = poly[3].x; z1 = poly[3].z; if (((z1 < point.z) && (z2 >= point.z)) || (z1 >= point.z) && (z2 < point.z)) { if ((point.z - z1) / (z2 - z1) * (x2 - x1) < (point.x - x1)) oddNodes = !oddNodes; } return oddNodes; } SQInteger PointInPoly2DBind(HSQUIRRELVM vm) { __SQ_GETSTART(2) __SQ_GETVECTOR(p); GS::Array poly_a(4); sq_pushnull(vm);//null iterator for (int i = 0; i < 4; ++i) { sq_next(vm, __SQ_STACKPOS - 1); GetVector(vm, -1, poly_a[i]); sq_pop(vm, 2); } sq_pop(vm, 1); //pops the null iterator __SQ_GETUPDATESTACK __SQ_GETEND __SQ_RETURNBOOL(PointInPoly2D(p, poly_a)); } //---------------------------------------------------------- void RegisterCollisionBinding(HSQUIRRELVM vm) //---------------------------------------------------------- { /*# Func: convexPolygonOverlapBind Proto: void:array polyA, array polyB Desc: return if the 2 poly overlap #*/ sq_register(vm, convexPolygonOverlapBind, "convexPolygonOverlapBind", _SC(".aa")); /*# Func: convexPolygonOverlapBind Proto: void:Vector p, array polyA Desc: return if the 2 poly overlap #*/ sq_register(vm, PointInPoly2DBind, "PointInPoly2DBind", _SC(".xa")); /*# Topic: Collision Type: ColShape #*/ /*# Section: CollisionShapeType Desc: Collision Shape Type functions #*/ /*# Func: ShapeSetMesh Proto: bool:ColShape shape,string path Desc: Set the shape as a collision mesh. #*/ sq_register(vm, ShapeSetMesh, "ShapeSetMesh", _SC(".xs")); /*# Func: ShapeSetConvex Proto: bool:ColShape shape,string path Desc: Set the shape as a convex collision. #*/ sq_register(vm, ShapeSetConvex, "ShapeSetConvex", _SC(".xs")); /*# Func: ShapeSetSphere Proto: bool:ColShape shape,float radius Desc: Set the shape as a sphere. #*/ sq_register(vm, ShapeSetSphere, "ShapeSetSphere", _SC(".xn")); /*# Func: ShapeSetBox Proto: bool:ColShape shape,Vector dimensions Desc: Set the shape as a box collision shape. #*/ sq_register(vm, ShapeSetBox, "ShapeSetBox", _SC(".xx")); /*# Func: ShapeSetCapsule Proto: bool:ColShape shape,float radius,float length Desc: Set the shape as a Z-oriented capsule collision shape. #*/ sq_register(vm, ShapeSetCapsule, "ShapeSetCapsule", _SC(".xnn")); /*# Func: ShapeSetCylinder Proto: bool:ColShape shape,float radius,float length Desc: Set the shape as a Z-oriented cylinder collision shape. #*/ sq_register(vm, ShapeSetCylinder, "ShapeSetCylinder", _SC(".xnn")); /*# Section: CollisionShape Desc: Collision Shape functions #*/ /*# Func: ShapeSetPosition Proto: void:ColShape shape,Vector position Desc: Set the collision shape position in item space. #*/ sq_register(vm, ShapeSetPosition, "ShapeSetPosition", _SC(".xx")); /*# Func: ShapeGetPosition Proto: Vector:ColShape shape Desc: Get the collision shape position in item space. #*/ sq_register(vm, ShapeGetPosition, "ShapeGetPosition", _SC(".x")); /*# Func: ShapeSetRotation Proto: void:ColShape shape,Vector position Desc: Set the collision shape position from a Euler triplet in item space. #*/ sq_register(vm, ShapeSetRotation, "ShapeSetRotation", _SC(".xx")); /*# Func: ShapeGetRotation Proto: Vector:ColShape shape Desc: Get the collision shape rotation as an Euler triplet in item space. #*/ sq_register(vm, ShapeGetRotation, "ShapeGetRotation", _SC(".x")); /*# Func: ShapeSetMass Proto: void:ColShape shape,float mass Desc: Set the collision shape mass. Do not forget to update the item collision setup to update changes. #*/ sq_register(vm, ShapeSetMass, "ShapeSetMass", _SC(".xn")); /*# Func: ShapeGetMass Proto: float:ColShape shape Desc: Get the collision shape mass. #*/ sq_register(vm, ShapeGetMass, "ShapeGetMass", _SC(".x")); /*# Func: ShapeSetFriction Proto: void:ColShape shape,float dynamic_friction,float static_friction Desc: Set collision shape dynamic and static friction. #*/ sq_register(vm, ShapeSetFriction, "ShapeSetFriction", _SC(".xnn")); /*# Func: ShapeSetRestitution Proto: void:ColShape shape,float restitution Desc: Set collision shape restitution (1 for a perfect elastic collision). #*/ sq_register(vm, ShapeSetRestitution, "ShapeSetRestitution", _SC(".xn")); /*# Func: ShapeGetItem Proto: Item:ColShape shape Desc: Get the item this collision shape belongs to. #*/ sq_register(vm, ShapeGetItem, "ShapeGetItem", _SC(".x")); /*# Section: CollisionItem Desc: Item functions #*/ /*# Func: ItemAddCollisionShape Proto: ColShape:Item Desc: Add a new collision shape to item. #*/ sq_register(vm, ItemAddCollisionShape, "ItemAddCollisionShape", _SC(".x")); /*# Func: ItemCollisionActivate Proto: void:Item,bool active Desc: Activate or deactivate item collision. #*/ sq_register(vm, ItemCollisionActivate, "ItemCollisionActivate", _SC(".xb")); /*# Func: ItemSetSelfMask Proto: void:Item,int self_mask Desc: Set item self mask, this mask is a bit field. #*/ sq_register(vm, ItemSetSelfMask, "ItemSetSelfMask", _SC(".xi")); /*# Func: ItemSetCollisionMask Proto: void:Item,int collision_mask Desc: Set item collision mask, this mask is a bit field. #*/ sq_register(vm, ItemSetCollisionMask, "ItemSetCollisionMask", _SC(".xi")); /*# Func: ItemGetShapeFromIndex Proto: ColShape:item,int index Desc: Get item collision shape from index. #*/ sq_register(vm, ItemGetShapeFromIndex, "ItemGetShapeFromIndex", _SC(".xi")); // Push defines. sq_pushroottable(vm); /*# Enum: ShapeMask Desc: Shape mask to filter out certain type of shape from intersection tests. Values: CollisionTraceMesh,CollisionTraceSphere,CollisionTraceCuboid,CollisionTraceAll #*/ sq_pushstring(vm, "CollisionTraceMesh", -1); sq_pushinteger(vm, -1); sq_newslot(vm, -3, true); sq_pushstring(vm, "CollisionTraceSphere", -1); sq_pushinteger(vm, -1); sq_newslot(vm, -3, true); sq_pushstring(vm, "CollisionTraceCuboid", -1); sq_pushinteger(vm, -1); sq_newslot(vm, -3, true); sq_pushstring(vm, "CollisionTraceAll", -1); sq_pushinteger(vm, ~0); sq_newslot(vm, -3, true); sq_pop(vm, 1); }