# HG changeset patch # User Extrawurst # Date 1291408681 -3600 # Node ID c03a41d47b603bb07c74c29f40848ed4cd2427ed # Parent 8697699b2c5aba5f33f2fc0e9e3ec94d84ab6b26 - finished all constraints properties - implemented cpAssertWarn the mixin way diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/chipmunk.d --- a/trunk/chipmunkd/chipmunk.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/chipmunk.d Fri Dec 03 21:38:01 2010 +0100 @@ -2,60 +2,47 @@ // written in the D programming language module chipmunkd.chipmunk; -//#ifndef CHIPMUNK_HEADER -//#define CHIPMUNK_HEADER -// -//#ifdef __cplusplus -//extern "C" { -//#endif -// -//void cpMessage(const char *message, const char *condition, const char *file, int line, int isError); -//#ifdef NDEBUG -// #define cpAssertWarn(condition, message) -//#else -// #define cpAssertWarn(condition, message) if(!(condition)) cpMessage(message, #condition, __FILE__, __LINE__, 0) -//#endif + +import std.stdio; +import std.string:format; +import std.conv:to; + +void +cpMessage(string message, string condition, string file, int line, bool isError) +{ + stderr.writeln(.format("%s:%s", isError ? "Aborting due to Chipmunk error" : "Chipmunk warning", message)); + stderr.writeln(.format("\tFailed condition: %s", condition)); + stderr.writeln(.format("\tSource: %s(%s)", file, line)); + + if(isError) {debug{assert(false);}else{asm{int 3;}}} +} debug { - //TODO: - //void cpAssertWarn(bool condition, string message){if(condition) cpMessage(message,condition,__FILE__,__LINE__, 0);} - void cpAssertWarn(bool condition, string message){} + template cpAssertWarn(string _condition, string message,string _f = __FILE__,int _l=__LINE__) + { + enum cpAssertWarn = "if(!("~_condition~"))"~ + "cpMessage(\""~message~"\",\""~_condition~"\",r\""~_f~"\","~to!string(_l)~",false);"; + } } else { - void cpAssertWarn(bool condition, string message){} + template cpAssertWarn(string _condition, string message,string _f = __FILE__,int _l=__LINE__) + { + enum cpAssertWarn = ""; + } } -// +//TODO //#ifdef NDEBUG // #define cpAssert(condition, message) //#else // #define cpAssert(condition, message) if(!(condition)) cpMessage(message, #condition, __FILE__, __LINE__, 1) //#endif // + import chipmunkd.chipmunk_types_h; import core.stdc.stdlib; -// -//#ifndef INFINITY -// #ifdef _MSC_VER -// union MSVC_EVIL_FLOAT_HACK -// { -// unsigned __int8 Bytes[4]; -// float Value; -// }; -// static union MSVC_EVIL_FLOAT_HACK INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}}; -// #define INFINITY (INFINITY_HACK.Value) -// #endif -// -// #ifdef __GNUC__ -// #define INFINITY (__builtin_inf()) -// #endif -// -// #ifndef INFINITY -// #define INFINITY (1e1000) -// #endif -//#endif enum INFINITY = cpFloat.infinity; @@ -92,17 +79,6 @@ enum cpHashValue CP_HASH_COEF = cast(cpHashValue)(3344921057uL); // ulong to uint ?? static cpHashValue CP_HASH_PAIR(T)(T A, T B) {return (cast(cpHashValue)(A)*CP_HASH_COEF ^ cast(cpHashValue)(B)*CP_HASH_COEF);} -void -cpMessage(string message, string condition, string file, int line, int isError) -{ - //TODO: - //fprintf(stderr, (isError ? "Aborting due to Chipmunk error: %s\n" : "Chipmunk warning: %s\n"), message); - //fprintf(stderr, "\tFailed condition: %s\n", condition); - //fprintf(stderr, "\tSource:%s:%d\n", file, line); - - if(isError) abort(); -} - extern const char *cpVersionString; void cpInitChipmunk() { @@ -166,9 +142,3 @@ { return m*(width*width + height*height)/12.0f; } - -//#ifdef __cplusplus -//} -//#endif -// -//#endif diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpConstraint.d --- a/trunk/chipmunkd/constraints/cpConstraint.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpConstraint.d Fri Dec 03 21:38:01 2010 +0100 @@ -58,9 +58,6 @@ "assert("~constraint~".klass == "~_struct~"GetClass(), \"Constraint is not a "~_struct~"\");"; } -//#define cpConstraintCheckCast(constraint, struct) \ -// cpAssert(constraint->klass == struct##GetClass(), "Constraint is not a "#struct); - template CP_DefineConstraintGetter(string _struct,string type,string member,string name) { enum CP_DefineConstraintGetter = @@ -71,13 +68,6 @@ "}"; } -//#define CP_DefineConstraintGetter(struct, type, member, name) \ -//static inline type \ -//struct##Get##name(const cpConstraint *constraint){ \ -// cpConstraintCheckCast(constraint, struct); \ -// return ((struct *)constraint)->member; \ -//} \ - template CP_DefineConstraintSetter(string _struct,string type,string member,string name) { enum CP_DefineConstraintSetter = @@ -88,14 +78,6 @@ "}"; } -//#define CP_DefineConstraintSetter(struct, type, member, name) \ -//static inline void \ -//struct##Set##name(cpConstraint *constraint, type value){ \ -// cpConstraintCheckCast(constraint, struct); \ -// cpConstraintActivateBodies(constraint); \ -// ((struct *)constraint)->member = value; \ -//} \ - template CP_DefineConstraintProperty(string _struct,string type,string member,string name) { enum CP_DefineConstraintProperty = @@ -103,10 +85,6 @@ } -//#define CP_DefineConstraintProperty(struct, type, member, name) \ -//CP_DefineConstraintGetter(struct, type, member, name) \ -//CP_DefineConstraintSetter(struct, type, member, name) -//TODO: //// Built in Joint types public import chipmunkd.constraints.cpPinJoint; public import chipmunkd.constraints.cpSlideJoint; diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpDampedRotarySpring.d --- a/trunk/chipmunkd/constraints/cpDampedRotarySpring.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpDampedRotarySpring.d Fri Dec 03 21:38:01 2010 +0100 @@ -26,11 +26,11 @@ //cpDampedRotarySpring *cpDampedRotarySpringAlloc(void); //cpDampedRotarySpring *cpDampedRotarySpringInit(cpDampedRotarySpring *joint, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping); //cpConstraint *cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping); -//TODO -//CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, restAngle, RestAngle); -//CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, stiffness, Stiffness); -//CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, damping, Damping); -//CP_DefineConstraintProperty(cpDampedRotarySpring, cpDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc); + +mixin(CP_DefineConstraintProperty!("cpDampedRotarySpring", "cpFloat", "restAngle", "RestAngle")); +mixin(CP_DefineConstraintProperty!("cpDampedRotarySpring", "cpFloat", "stiffness", "Stiffness")); +mixin(CP_DefineConstraintProperty!("cpDampedRotarySpring", "cpFloat", "damping", "Damping")); +mixin(CP_DefineConstraintProperty!("cpDampedRotarySpring", "cpDampedRotarySpringTorqueFunc", "springTorqueFunc", "SpringTorqueFunc")); // cpDampedRotarySpring.c --------------------------------- diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpGearJoint.d --- a/trunk/chipmunkd/constraints/cpGearJoint.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpGearJoint.d Fri Dec 03 21:38:01 2010 +0100 @@ -22,9 +22,9 @@ //cpGearJoint *cpGearJointAlloc(void); //cpGearJoint *cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio); //cpConstraint *cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio); -//TODO -//CP_DefineConstraintProperty(cpGearJoint, cpFloat, phase, Phase); -//CP_DefineConstraintGetter(cpGearJoint, cpFloat, ratio, Ratio); + +mixin(CP_DefineConstraintProperty!("cpGearJoint", "cpFloat", "phase", "Phase")); +mixin(CP_DefineConstraintGetter!("cpGearJoint", "cpFloat", "ratio", "Ratio")); //void cpGearJointSetRatio(cpConstraint *constraint, cpFloat value); // cpGearJoint.c --------------------------------- diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpGrooveJoint.d --- a/trunk/chipmunkd/constraints/cpGrooveJoint.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpGrooveJoint.d Fri Dec 03 21:38:01 2010 +0100 @@ -26,13 +26,12 @@ //cpGrooveJoint *cpGrooveJointAlloc(void); //cpGrooveJoint *cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2); //cpConstraint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2); -// -//TODO -//CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_a, GrooveA); + +mixin(CP_DefineConstraintGetter!("cpGrooveJoint", "cpVect", "grv_a", "GrooveA")); //void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value); -//CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_b, GrooveB); +mixin(CP_DefineConstraintGetter!("cpGrooveJoint", "cpVect", "grv_b", "GrooveB")); //void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value); -//CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2); +mixin(CP_DefineConstraintProperty!("cpGrooveJoint", "cpVect", "anchr2", "Anchr2")); // cpGrooveJoint.c --------------------------------- diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpPivotJoint.d --- a/trunk/chipmunkd/constraints/cpPivotJoint.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpPivotJoint.d Fri Dec 03 21:38:01 2010 +0100 @@ -24,9 +24,9 @@ //cpPivotJoint *cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2); //cpConstraint *cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot); //cpConstraint *cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2); -//TODO -//CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr1, Anchr1); -//CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr2, Anchr2); + +mixin(CP_DefineConstraintProperty!("cpPivotJoint", "cpVect", "anchr1", "Anchr1")); +mixin(CP_DefineConstraintProperty!("cpPivotJoint", "cpVect", "anchr2", "Anchr2")); static void preStep(cpPivotJoint *joint, cpFloat dt, cpFloat dt_inv) diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpRatchetJoint.d --- a/trunk/chipmunkd/constraints/cpRatchetJoint.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpRatchetJoint.d Fri Dec 03 21:38:01 2010 +0100 @@ -21,10 +21,10 @@ //cpRatchetJoint *cpRatchetJointAlloc(void); //cpRatchetJoint *cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet); //cpConstraint *cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet); -//TODO -//CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, angle, Angle); -//CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, phase, Phase); -//CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, ratchet, Ratchet); + +mixin(CP_DefineConstraintProperty!("cpRatchetJoint", "cpFloat", "angle", "Angle")); +mixin(CP_DefineConstraintProperty!("cpRatchetJoint", "cpFloat", "phase", "Phase")); +mixin(CP_DefineConstraintProperty!("cpRatchetJoint", "cpFloat", "ratchet", "Ratchet")); // cpRatchetJoint.c --------------------------------- diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpRotaryLimitJoint.d --- a/trunk/chipmunkd/constraints/cpRotaryLimitJoint.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpRotaryLimitJoint.d Fri Dec 03 21:38:01 2010 +0100 @@ -21,9 +21,9 @@ //cpRotaryLimitJoint *cpRotaryLimitJointAlloc(void); //cpRotaryLimitJoint *cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max); //cpConstraint *cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max); -//TODO -//CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, min, Min); -//CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, max, Max); + +mixin(CP_DefineConstraintProperty!("cpRotaryLimitJoint", "cpFloat", "min", "Min")); +mixin(CP_DefineConstraintProperty!("cpRotaryLimitJoint", "cpFloat", "max", "Max")); // cpRotaryLimitJoint.c --------------------------------- diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpSimpleMotor.d --- a/trunk/chipmunkd/constraints/cpSimpleMotor.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpSimpleMotor.d Fri Dec 03 21:38:01 2010 +0100 @@ -20,7 +20,7 @@ //cpSimpleMotor *cpSimpleMotorAlloc(void); //cpSimpleMotor *cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate); //cpConstraint *cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate); -// + mixin(CP_DefineConstraintProperty!("cpSimpleMotor", "cpFloat", "rate", "Rate")); // cpRotaryLimitJoint.c --------------------------------- diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/constraints/cpSlideJoint.d --- a/trunk/chipmunkd/constraints/cpSlideJoint.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/constraints/cpSlideJoint.d Fri Dec 03 21:38:01 2010 +0100 @@ -24,11 +24,11 @@ //cpSlideJoint *cpSlideJointAlloc(void); //cpSlideJoint *cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max); //cpConstraint *cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max); -//TODO -//CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr1, Anchr1); -//CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr2, Anchr2); -//CP_DefineConstraintProperty(cpSlideJoint, cpFloat, min, Min); -//CP_DefineConstraintProperty(cpSlideJoint, cpFloat, max, Max); + +mixin(CP_DefineConstraintProperty!("cpSlideJoint", "cpVect", "anchr1", "Anchr1")); +mixin(CP_DefineConstraintProperty!("cpSlideJoint", "cpVect", "anchr2", "Anchr2")); +mixin(CP_DefineConstraintProperty!("cpSlideJoint", "cpFloat", "min", "Min")); +mixin(CP_DefineConstraintProperty!("cpSlideJoint", "cpFloat", "max", "Max")); // cpSlideJoint.c --------------------------------- diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/cpArbiter.d --- a/trunk/chipmunkd/cpArbiter.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/cpArbiter.d Fri Dec 03 21:38:01 2010 +0100 @@ -107,7 +107,7 @@ (*a) = arb.private_a, (*b) = arb.private_b; } } -//#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b); + template CP_ARBITER_GET_SHAPES(string arb,string a,string b) { enum CP_ARBITER_GET_SHAPES = "cpShape* "~a~", "~b~";"~ diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/cpBody.d --- a/trunk/chipmunkd/cpBody.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/cpBody.d Fri Dec 03 21:38:01 2010 +0100 @@ -112,7 +112,7 @@ return (_body.space is null); } - +//TODO //#define CP_DefineBodyGetter(type, member, name) \ //static inline type cpBodyGet##name(const cpBody *body){return body.member;} // @@ -363,5 +363,5 @@ if(cpBodyIsSleeping(_body)) return; assert(!cpBodyIsStatic(_body) && !cpBodyIsRogue(_body), "Rogue and static bodies cannot be put to sleep."); - cpSpaceSleepBody(_body.space, _body); //TODO + cpSpaceSleepBody(_body.space, _body); } diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/cpShape.d --- a/trunk/chipmunkd/cpShape.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/cpShape.d Fri Dec 03 21:38:01 2010 +0100 @@ -98,7 +98,8 @@ // //// Test if a point lies within a shape. //cpBool cpShapePointQuery(cpShape *shape, cpVect p); -// + +//TODO //#define CP_DeclareShapeGetter(struct, type, name) type struct##Get##name(cpShape *shape) // @@ -242,11 +243,11 @@ void cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info) { - writefln("Segment Query:\n"); - writefln("\tt: %s\n", info.t); + writefln("Segment Query:"); + writefln("\tt: %s", info.t); // writefln("\tdist: %f\n", info.dist); // writefln("\tpoint: %s\n", cpvstr(info.point)); - //writefln("\tn: %s\n", cpvstr(info.n)); //TODO: + writefln("\tn: %s", cpvstr(info.n)); } cpCircleShape * diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/cpSpace.d --- a/trunk/chipmunkd/cpSpace.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/cpSpace.d Fri Dec 03 21:38:01 2010 +0100 @@ -502,7 +502,7 @@ cpBody * cpSpaceAddBody(cpSpace *space, cpBody *_body) { - cpAssertWarn(_body.m != INFINITY, "Did you really mean to add an infinite mass body to the space?"); + mixin(cpAssertWarn!("_body.m != INFINITY", "Did you really mean to add an infinite mass body to the space?",__FILE__,__LINE__)); assert(!_body.space, "Cannot add a body to a more than one space or to the same space twice."); // cpAssertSpaceUnlocked(space); This should be safe as long as it's not from an integration callback @@ -558,8 +558,8 @@ cpBodyActivate(_body); cpAssertSpaceUnlocked(space); - cpAssertWarn(cpHashSetFind(space.activeShapes.handleSet, shape.hashid, shape) !is null, - "Cannot remove a shape that was never added to the space. (Removed twice maybe?)"); + mixin(cpAssertWarn!("cpHashSetFind(space.activeShapes.handleSet, shape.hashid, shape) !is null", + "Cannot remove a shape that was never added to the space. (Removed twice maybe?)",__FILE__,__LINE__)); cpBodyRemoveShape(_body, shape); @@ -571,8 +571,8 @@ void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape) { - cpAssertWarn(cpHashSetFind(space.staticShapes.handleSet, shape.hashid, shape) !is null, - "Cannot remove a static or sleeping shape that was never added to the space. (Removed twice maybe?)"); + mixin(cpAssertWarn!("cpHashSetFind(space.staticShapes.handleSet, shape.hashid, shape) !is null", + "Cannot remove a static or sleeping shape that was never added to the space. (Removed twice maybe?)",__FILE__,__LINE__)); cpAssertSpaceUnlocked(space); removalContext context = {space, shape}; @@ -585,8 +585,8 @@ void cpSpaceRemoveBody(cpSpace *space, cpBody *_body) { - cpAssertWarn(_body.space == space, - "Cannot remove a body that was never added to the space. (Removed twice maybe?)"); + mixin(cpAssertWarn!("_body.space == space", + "Cannot remove a body that was never added to the space. (Removed twice maybe?)")); cpAssertSpaceUnlocked(space); cpBodyActivate(_body); @@ -597,8 +597,8 @@ void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint) { - cpAssertWarn(cpArrayContains(space.constraints, constraint), - "Cannot remove a constraint that was never added to the space. (Removed twice maybe?)"); + mixin(cpAssertWarn!("cpArrayContains(space.constraints, constraint)", + "Cannot remove a constraint that was never added to the space. (Removed twice maybe?)",__FILE__,__LINE__)); // cpAssertSpaceUnlocked(space); Should be safe as long as its not from a constraint callback. cpBodyActivate(constraint.a); diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/cpSpaceStep.d --- a/trunk/chipmunkd/cpSpaceStep.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/cpSpaceStep.d Fri Dec 03 21:38:01 2010 +0100 @@ -108,7 +108,7 @@ } cpContactBufferHeader *head = space.contactBuffersHead; - return &(cast(cpContactBuffer *)head).contacts[head.numContacts]; //TODO: check if this works + return &(cast(cpContactBuffer *)head).contacts[head.numContacts]; } static void diff -r 8697699b2c5a -r c03a41d47b60 trunk/chipmunkd/cpVect.d --- a/trunk/chipmunkd/cpVect.d Fri Dec 03 01:01:39 2010 +0100 +++ b/trunk/chipmunkd/cpVect.d Fri Dec 03 21:38:01 2010 +0100 @@ -44,10 +44,10 @@ return cpfatan2(v.y, v.x); } -//char* -//cpvstr(const cpVect v) -//{ -// static char str[256]; -// sprintf(str, "(% .3f, % .3f)", v.x, v.y); -// return str; -//} \ No newline at end of file +import std.string:format; + +string +cpvstr(const cpVect v) +{ + return .format("(%s,%s)",v.x, v.y); +} \ No newline at end of file