diff options
Diffstat (limited to 'tests/manyloc/keineschweine')
49 files changed, 9271 insertions, 0 deletions
diff --git a/tests/manyloc/keineschweine/README.md b/tests/manyloc/keineschweine/README.md new file mode 100644 index 000000000..2a6b78a8e --- /dev/null +++ b/tests/manyloc/keineschweine/README.md @@ -0,0 +1,26 @@ +keineSchweine +======================== +Just a dumb little game + +### Dependencies + +* Nimrod 0.8.15, Until this version is released I'm working off Nimrod HEAD: https://github.com/Araq/Nimrod +* SFML 2.0 (git), https://github.com/LaurentGomila/SFML +* CSFML 2.0 (git), https://github.com/LaurentGomila/CSFML +* Chipmunk 6.1.1 http://chipmunk-physics.net/downloads.php + +### How to build? + +* `git clone --recursive git://github.com/fowlmouth/keineSchweine.git somedir` +* `cd somedir` +* `nimrod c -r nakefile test` or `nimrod c -r keineschweine && ./keineschweine` + +### Download the game data + +You need to download the game data before you can play: +http://dl.dropbox.com/u/37533467/data-08-01-2012.7z + +Unpack it to the root directory. You can use the nakefile to do this easily: + +* `nimrod c -r nakefile` +* `./nakefile download` diff --git a/tests/manyloc/keineschweine/TODO.md b/tests/manyloc/keineschweine/TODO.md new file mode 100644 index 000000000..1145949aa --- /dev/null +++ b/tests/manyloc/keineschweine/TODO.md @@ -0,0 +1,21 @@ +##Main State +* Add GUI: + * Player list + * Chat box + * Escape menu + +##Lobby +* Add GUI: + * options menu + * key configuration + +## Animations +* Need one-shot explosion animations + * Thrusters (maybe a particle system instead) + +## Networking +* zone server should verify users through the dir server or handle its own users +* directory server should handle asset patching + +## Genpacket +* add support for branching types with case diff --git a/tests/manyloc/keineschweine/client_settings.json b/tests/manyloc/keineschweine/client_settings.json new file mode 100644 index 000000000..59facf1ad --- /dev/null +++ b/tests/manyloc/keineschweine/client_settings.json @@ -0,0 +1,10 @@ +{ + "resolution": [800,600,32], + "default-file": "alphazone.json", + "alias": "foo", + "directory-server":{ + "host":"localhost", + "port":8024 + }, + "website":"https://github.com/fowlmouth/keineSchweine" +} diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim new file mode 100644 index 000000000..8226b0b04 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -0,0 +1,1516 @@ +# Copyright (c) 2007 Scott Lembcke +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +when defined(Linux): + const Lib = "libchipmunk.so.6.1.1" +else: + {.error: "Platform unsupported".} +when defined(MoreNimrod): + {.hint: "MoreNimrod defined; some Chipmunk functions replaced in Nimrod".} +{.deadCodeElim: on.} +from math import sqrt, sin, cos, arctan2 +when defined(CpUseFloat): + {.hint: "CpUseFloat defined; using float32 as float".} + type CpFloat* = cfloat +else: + type CpFloat* = cdouble +const + CP_BUFFER_BYTES* = (32 * 1024) + CP_MAX_CONTACTS_PER_ARBITER* = 4 + CpInfinity*: CpFloat = 1.0/0 +{.pragma: pf, pure, final.} +type + Bool32* = cint #replace one day with cint-compatible bool + CpDataPointer* = pointer + TVector* {.final, pure.} = object + x*, y*: CpFloat + TTimestamp* = cuint + TBodyVelocityFunc* = proc(body: PBody, gravity: TVector, + damping: CpFloat; dt: CpFloat){.cdecl.} + TBodyPositionFunc* = proc(body: PBody; dt: CpFloat){.cdecl.} + TComponentNode*{.pf.} = object + root*: PBody + next*: PBody + idleTime*: CpFloat + + THashValue = cuint # uintptr_t + TCollisionType* = cuint #uintptr_t + TGroup * = cuint #uintptr_t + TLayers* = cuint + PArray = ptr TArray + TArray{.pure,final.} = object + PHashSet = ptr THashSet + THashSet{.pf.} = object + PContact* = ptr TContact + TContact*{.pure,final.} = object + PArbiter* = ptr TArbiter + TArbiter*{.pf.} = object + e*: CpFloat + u*: CpFloat + surface_vr*: TVector + a*: PShape + b*: PShape + body_a*: PBody + body_b*: PBody + thread_a*: TArbiterThread + thread_b*: TArbiterThread + numContacts*: cint + contacts*: PContact + stamp*: TTimestamp + handler*: PCollisionHandler + swappedColl*: bool32 + state*: TArbiterState + PCollisionHandler* = ptr TCollisionHandler + TCollisionHandler*{.pf.} = object + a*: TCollisionType + b*: TCollisionType + begin*: TCollisionBeginFunc + preSolve*: TCollisionPreSolveFunc + postSolve*: TCollisionPostSolveFunc + separate*: TCollisionSeparateFunc + data*: pointer + TArbiterState*{.size: sizeof(cint).} = enum + ArbiterStateFirstColl, # Arbiter is active and its not the first collision. + ArbiterStateNormal, # Collision has been explicitly ignored. + # Either by returning false from a begin collision handler or calling cpArbiterIgnore(). + ArbiterStateIgnore, # Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps. + ArbiterStateCached + TArbiterThread*{.pf.} = object + next*: PArbiter # Links to next and previous arbiters in the contact graph. + prev*: PArbiter + + TContactPoint*{.pf.} = object + point*: TVector #/ The position of the contact point. + normal*: TVector #/ The normal of the contact point. + dist*: CpFloat #/ The depth of the contact point. + #/ A struct that wraps up the important collision data for an arbiter. + PContactPointSet* = ptr TContactPointSet + TContactPointSet*{.pf.} = object + count*: cint #/ The number of contact points in the set. + points*: array[0..CP_MAX_CONTACTS_PER_ARBITER - 1, TContactPoint] #/ The array of contact points. + + #/ Collision begin event function callback type. + #/ Returning false from a begin callback causes the collision to be ignored until + #/ the the separate callback is called when the objects stop colliding. + TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): Bool{. + cdecl.} + #/ Collision pre-solve event function callback type. + #/ Returning false from a pre-step callback causes the collision to be ignored until the next step. + TCollisionPreSolveFunc* = proc (arb: PArbiter; space: PSpace; + data: pointer): bool {.cdecl.} + #/ Collision post-solve event function callback type. + TCollisionPostSolveFunc* = proc (arb: PArbiter; space: PSpace; + data: pointer){.cdecl.} + #/ Collision separate event function callback type. + TCollisionSeparateFunc* = proc (arb: PArbiter; space: PSpace; + data: pointer){.cdecl.} + + #/ Chipmunk's axis-aligned 2D bounding box type. (left, bottom, right, top) + PBB* = ptr TBB + TBB* {.pf.} = object + l*, b*, r*, t*: CpFloat + + #/ Spatial index bounding box callback function type. + #/ The spatial index calls this function and passes you a pointer to an object you added + #/ when it needs to get the bounding box associated with that object. + TSpatialIndexBBFunc* = proc (obj: pointer): TBB{.cdecl.} + #/ Spatial index/object iterator callback function type. + TSpatialIndexIteratorFunc* = proc (obj: pointer; data: pointer){.cdecl.} + #/ Spatial query callback function type. + TSpatialIndexQueryFunc* = proc (obj1: pointer; obj2: pointer; data: pointer){. + cdecl.} + #/ Spatial segment query callback function type. + TSpatialIndexSegmentQueryFunc* = proc (obj1: pointer; obj2: pointer; + data: pointer): CpFloat {.cdecl.} + #/ private + PSpatialIndex = ptr TSpatialIndex + TSpatialIndex{.pf.} = object + klass: PSpatialIndexClass + bbfunc: TSpatialIndexBBFunc + staticIndex: PSpatialIndex + dynamicIndex: PSpatialIndex + + TSpatialIndexDestroyImpl* = proc (index: PSpatialIndex){.cdecl.} + TSpatialIndexCountImpl* = proc (index: PSpatialIndex): cint{.cdecl.} + TSpatialIndexEachImpl* = proc (index: PSpatialIndex; + func: TSpatialIndexIteratorFunc; data: pointer){. + cdecl.} + TSpatialIndexContainsImpl* = proc (index: PSpatialIndex; obj: pointer; + hashid: THashValue): Bool32 {.cdecl.} + TSpatialIndexInsertImpl* = proc (index: PSpatialIndex; obj: pointer; + hashid: THashValue){.cdecl.} + TSpatialIndexRemoveImpl* = proc (index: PSpatialIndex; obj: pointer; + hashid: THashValue){.cdecl.} + TSpatialIndexReindexImpl* = proc (index: PSpatialIndex){.cdecl.} + TSpatialIndexReindexObjectImpl* = proc (index: PSpatialIndex; + obj: pointer; hashid: THashValue){.cdecl.} + TSpatialIndexReindexQueryImpl* = proc (index: PSpatialIndex; + func: TSpatialIndexQueryFunc; data: pointer){.cdecl.} + TSpatialIndexPointQueryImpl* = proc (index: PSpatialIndex; point: TVector; + func: TSpatialIndexQueryFunc; + data: pointer){.cdecl.} + TSpatialIndexSegmentQueryImpl* = proc (index: PSpatialIndex; obj: pointer; + a: TVector; b: TVector; t_exit: CpFloat; func: TSpatialIndexSegmentQueryFunc; + data: pointer){.cdecl.} + TSpatialIndexQueryImpl* = proc (index: PSpatialIndex; obj: pointer; + bb: TBB; func: TSpatialIndexQueryFunc; + data: pointer){.cdecl.} + PSpatialIndexClass* = ptr TSpatialIndexClass + TSpatialIndexClass*{.pf.} = object + destroy*: TSpatialIndexDestroyImpl + count*: TSpatialIndexCountImpl + each*: TSpatialIndexEachImpl + contains*: TSpatialIndexContainsImpl + insert*: TSpatialIndexInsertImpl + remove*: TSpatialIndexRemoveImpl + reindex*: TSpatialIndexReindexImpl + reindexObject*: TSpatialIndexReindexObjectImpl + reindexQuery*: TSpatialIndexReindexQueryImpl + pointQuery*: TSpatialIndexPointQueryImpl + segmentQuery*: TSpatialIndexSegmentQueryImpl + query*: TSpatialIndexQueryImpl + + PSpaceHash* = ptr TSpaceHash + TSpaceHash* {.pf.} = object + PBBTree* = ptr TBBTree + TBBTree* {.pf.} = object + PSweep1D* = ptr TSweep1D + TSweep1D* {.pf.} = object + + #/ Bounding box tree velocity callback function. + #/ This function should return an estimate for the object's velocity. + TBBTreeVelocityFunc* = proc (obj: pointer): TVector {.cdecl.} + + PContactBufferHeader* = ptr TContentBufferHeader + TContentBufferHeader* {.pf.} = object + TSpaceArbiterApplyImpulseFunc* = proc (arb: PArbiter){.cdecl.} + + PSpace* = ptr TSpace + TSpace* {.pf.} = object + iterations*: cint + gravity*: TVector + damping*: CpFloat + idleSpeedThreshold*: CpFloat + sleepTimeThreshold*: CpFloat + collisionSlop*: CpFloat + collisionBias*: CpFloat + collisionPersistence*: TTimestamp + enableContactGraph*: cint ##BOOL + data*: pointer + staticBody*: PBody + stamp: TTimestamp + currDT: CpFloat + bodies: PArray + rousedBodies: PArray + sleepingComponents: PArray + staticShapes: PSpatialIndex + activeShapes: PSpatialIndex + arbiters: PArray + contactBuffersHead: PContactBufferHeader + cachedArbiters: PHashSet + pooledArbiters: PArray + constraints: PArray + allocatedBuffers: PArray + locked: cint + collisionHandlers: PHashSet + defaultHandler: TCollisionHandler + postStepCallbacks: PHashSet + arbiterApplyImpulse: TSpaceArbiterApplyImpulseFunc + staticBody2: TBody #_staticBody + PBody* = ptr TBody + TBody*{.pf.} = object + velocityFunc*: TBodyVelocityFunc + positionFunc*: TBodyPositionFunc + m*: CpFloat + mInv*: CpFloat + i*: CpFloat + iInv*: CpFloat + p*: TVector + v*: TVector + f*: TVector + a*: CpFloat + w*: CpFloat + t*: CpFloat + rot*: TVector + data*: pointer + vLimit*: CpFloat + wLimit*: CpFloat + vBias*: TVector + wBias*: CpFloat + space*: PSpace + shapeList*: PShape + arbiterList*: PArbiter + constraintList*: PConstraint + node*: TComponentNode + #/ Body/shape iterator callback function type. + TBodyShapeIteratorFunc* = proc (body: PBody; shape: PShape; + data: pointer) {.cdecl.} + #/ Body/constraint iterator callback function type. + TBodyConstraintIteratorFunc* = proc (body: PBody; + constraint: PConstraint; + data: pointer) {.cdecl.} + #/ Body/arbiter iterator callback function type. + TBodyArbiterIteratorFunc* = proc (body: PBody; arbiter: PArbiter; + data: pointer) {.cdecl.} + + PNearestPointQueryInfo* = ptr TNearestPointQueryInfo + #/ Nearest point query info struct. + TNearestPointQueryInfo*{.pf.} = object + shape: PShape #/ The nearest shape, NULL if no shape was within range. + p: TVector #/ The closest point on the shape's surface. (in world space coordinates) + d: CpFloat #/ The distance to the point. The distance is negative if the point is inside the shape. + + PSegmentQueryInfo* = ptr TSegmentQueryInfo + #/ Segment query info struct. + TSegmentQueryInfo*{.pf.} = object + shape*: PShape #/ The shape that was hit, NULL if no collision occured. + t*: CpFloat #/ The normalized distance along the query segment in the range [0, 1]. + n*: TVector #/ The normal of the surface hit. + TShapeType*{.size: sizeof(cint).} = enum + CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, CP_POLY_SHAPE, CP_NUM_SHAPES + TShapeCacheDataImpl* = proc (shape: PShape; p: TVector; rot: TVector): TBB{.cdecl.} + TShapeDestroyImpl* = proc (shape: PShape){.cdecl.} + TShapePointQueryImpl* = proc (shape: PShape; p: TVector): bool32 {.cdecl.} + TShapeSegmentQueryImpl* = proc (shape: PShape; a: TVector; b: TVector; + info: PSegmentQueryInfo){.cdecl.} + PShapeClass* = ptr TShapeClass + TShapeClass*{.pf.} = object + kind*: TShapeType + cacheData*: TShapeCacheDataImpl + destroy*: TShapeDestroyImpl + pointQuery*: TShapePointQueryImpl + segmentQuery*: TShapeSegmentQueryImpl + PShape* = ptr TShape + TShape*{.pf.} = object + klass: PShapeClass #/ PRIVATE + body*: PBody #/ The rigid body this collision shape is attached to. + bb*: TBB #/ The current bounding box of the shape. + sensor*: Bool32 #/ Sensor flag. + #/ Sensor shapes call collision callbacks but don't produce collisions. + e*: CpFloat #/ Coefficient of restitution. (elasticity) + u*: CpFloat #/ Coefficient of friction. + surface_v*: TVector #/ Surface velocity used when solving for friction. + data*: pointer #/ User definable data pointer. Generally this points to your the game object class so you can access it when given a cpShape reference in a callback. + collision_type*: TCollisionType #/ Collision type of this shape used when picking collision handlers. + group*: TGroup #/ Group of this shape. Shapes in the same group don't collide. + layers*: TLayers #/ Layer bitmask for this shape. Shapes only collide if the bitwise and of their layers is non-zero. + space: PSpace #PRIVATE + next: PShape #PRIVATE + prev: PShape #PRIVATE + hashid: THashValue #PRIVATE + PCircleShape* = ptr TCircleShape + TCircleShape*{.pf.} = object + shape: PShape + c, tc: TVector + r: CpFloat + PPolyShape* = ptr TPolyShape + TPolyShape*{.pf.} = object + shape: PShape + numVerts: cint + verts, tVerts: TVector + planes, tPlanes: PSplittingPlane + PSegmentShape* = ptr TSegmentShape + TSegmentShape*{.pf.} = object + shape: PShape + a, b, n: TVector + ta, tb, tn: TVector + r: CpFloat + aTangent, bTangent: TVector + PSplittingPlane* = ptr TSplittingPlane + TSplittingPlane*{.pf.} = object + n: TVector + d: CpFloat + + #/ Post Step callback function type. + TPostStepFunc* = proc (space: PSpace; obj: pointer; data: pointer){.cdecl.} + #/ Point query callback function type. + TSpacePointQueryFunc* = proc (shape: PShape; data: pointer){.cdecl.} + #/ Segment query callback function type. + TSpaceSegmentQueryFunc* = proc (shape: PShape; t: CpFloat; n: TVector; + data: pointer){.cdecl.} + #/ Rectangle Query callback function type. + TSpaceBBQueryFunc* = proc (shape: PShape; data: pointer){.cdecl.} + #/ Shape query callback function type. + TSpaceShapeQueryFunc* = proc (shape: PShape; points: PContactPointSet; + data: pointer){.cdecl.} + #/ Space/body iterator callback function type. + TSpaceBodyIteratorFunc* = proc (body: PBody; data: pointer){.cdecl.} + #/ Space/body iterator callback function type. + TSpaceShapeIteratorFunc* = proc (shape: PShape; data: pointer){.cdecl.} + #/ Space/constraint iterator callback function type. + TSpaceConstraintIteratorFunc* = proc (constraint: PConstraint; + data: pointer){.cdecl.} + #/ Opaque cpConstraint struct. + PConstraint* = ptr TConstraint + TConstraint*{.pf.} = object + klass: PConstraintClass #/PRIVATE + a*: PBody #/ The first body connected to this constraint. + b*: PBody #/ The second body connected to this constraint. + space: PSpace #/PRIVATE + next_a: PConstraint #/PRIVATE + next_b: PConstraint #/PRIVATE + maxForce*: CpFloat #/ The maximum force that this constraint is allowed to use. Defaults to infinity. + errorBias*: CpFloat #/ The rate at which joint error is corrected. Defaults to pow(1.0 - 0.1, 60.0) meaning that it will correct 10% of the error every 1/60th of a second. + maxBias*: CpFloat #/ The maximum rate at which joint error is corrected. Defaults to infinity. + preSolve*: TConstraintPreSolveFunc #/ Function called before the solver runs. Animate your joint anchors, update your motor torque, etc. + postSolve*: TConstraintPostSolveFunc #/ Function called after the solver runs. Use the applied impulse to perform effects like breakable joints. + data*: CpDataPointer # User definable data pointer. Generally this points to your the game object class so you can access it when given a cpConstraint reference in a callback. + TConstraintPreStepImpl = proc (constraint: PConstraint; dt: CpFloat){.cdecl.} + TConstraintApplyCachedImpulseImpl = proc (constraint: PConstraint; dt_coef: CpFloat){.cdecl.} + TConstraintApplyImpulseImpl = proc (constraint: PConstraint){.cdecl.} + TConstraintGetImpulseImpl = proc (constraint: PConstraint): CpFloat{.cdecl.} + PConstraintClass = ptr TConstraintClass + TConstraintClass{.pf.} = object + preStep*: TConstraintPreStepImpl + applyCachedImpulse*: TConstraintApplyCachedImpulseImpl + applyImpulse*: TConstraintApplyImpulseImpl + getImpulse*: TConstraintGetImpulseImpl + #/ Callback function type that gets called before solving a joint. + TConstraintPreSolveFunc* = proc (constraint: PConstraint; space: PSpace){. + cdecl.} + #/ Callback function type that gets called after solving a joint. + TConstraintPostSolveFunc* = proc (constraint: PConstraint; space: PSpace){. + cdecl.} + +##cp property emulators +template defGetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} = + proc `get procName`*(obj: otype): memberType {.cdecl.} = + return obj.memberName +template defSetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} = + proc `set procName`*(obj: otype, value: memberType) {.cdecl.} = + obj.memberName = value +template defProp(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} = + defGetter(otype, memberType, memberName, procName) + defSetter(otype, memberType, memberName, procName) + + +##cpspace.h +proc allocSpace*(): PSpace {. + importc: "cpSpaceAlloc", dynlib: Lib.} +proc Init*(space: PSpace): PSpace {. + importc: "cpSpaceInit", dynlib: Lib.} +proc newSpace*(): PSpace {. + importc: "cpSpaceNew", dynlib: Lib.} +proc destroy*(space: PSpace) {. + importc: "cpSpaceDestroy", dynlib: Lib.} +proc free*(space: PSpace) {. + importc: "cpSpaceFree", dynlib: Lib.} + +defProp(PSpace, cint, iterations, Iterations) +defProp(PSpace, TVector, gravity, Gravity) +defProp(PSpace, CpFloat, damping, Damping) +defProp(PSpace, CpFloat, idleSpeedThreshold, IdleSpeedThreshold) +defProp(PSpace, CpFloat, sleepTimeThreshold, SleepTimeThreshold) +defProp(PSpace, CpFloat, collisionSlop, CollisionSlop) +defProp(PSpace, CpFloat, collisionBias, CollisionBias) +defProp(PSpace, TTimestamp, collisionPersistence, CollisionPersistence) +defProp(PSpace, Bool32, enableContactGraph, EnableContactGraph) +defProp(PSpace, pointer, data, UserData) +defGetter(PSpace, PBody, staticBody, StaticBody) +defGetter(PSpace, CpFloat, currDt, CurrentTimeStep) + + +#/ returns true from inside a callback and objects cannot be added/removed. +proc isLocked*(space: PSpace): Bool{.inline.} = + result = space.locked.bool + +#/ Set a default collision handler for this space. +#/ The default collision handler is invoked for each colliding pair of shapes +#/ that isn't explicitly handled by a specific collision handler. +#/ You can pass NULL for any function you don't want to implement. +proc setDefaultCollisionHandler*(space: PSpace; begin: TCollisionBeginFunc; + preSolve: TCollisionPreSolveFunc; + postSolve: TCollisionPostSolveFunc; + separate: TCollisionSeparateFunc; + data: pointer){. + cdecl, importc: "cpSpaceSetDefaultCollisionHandler", dynlib: Lib.} +#/ Set a collision handler to be used whenever the two shapes with the given collision types collide. +#/ You can pass NULL for any function you don't want to implement. +proc addCollisionHandler*(space: PSpace; a, b: TCollisionType; + begin: TCollisionBeginFunc; + preSolve: TCollisionPreSolveFunc; + postSolve: TCollisionPostSolveFunc; + separate: TCollisionSeparateFunc; data: pointer){. + cdecl, importc: "cpSpaceAddCollisionHandler", dynlib: Lib.} +#/ Unset a collision handler. +proc removeCollisionHandler*(space: PSpace; a: TCollisionType; + b: TCollisionType){. + cdecl, importc: "cpSpaceRemoveCollisionHandler", dynlib: Lib.} +#/ Add a collision shape to the simulation. +#/ If the shape is attached to a static body, it will be added as a static shape. +proc addShape*(space: PSpace; shape: PShape): PShape{. + cdecl, importc: "cpSpaceAddShape", dynlib: Lib.} +#/ Explicity add a shape as a static shape to the simulation. +proc addStaticShape*(space: PSpace; shape: PShape): PShape{. + cdecl, importc: "cpSpaceAddStaticShape", dynlib: Lib.} +#/ Add a rigid body to the simulation. +proc addBody*(space: PSpace; body: PBody): PBody{. + cdecl, importc: "cpSpaceAddBody", dynlib: Lib.} +#/ Add a constraint to the simulation. +proc addConstraint*(space: PSpace; constraint: PConstraint): PConstraint{. + cdecl, importc: "cpSpaceAddConstraint", dynlib: Lib.} +#/ Remove a collision shape from the simulation. +proc removeShape*(space: PSpace; shape: PShape){. + cdecl, importc: "cpSpaceRemoveShape", dynlib: Lib.} +#/ Remove a collision shape added using cpSpaceAddStaticShape() from the simulation. +proc removeStaticShape*(space: PSpace; shape: PShape){. + cdecl, importc: "cpSpaceRemoveStaticShape", dynlib: Lib.} +#/ Remove a rigid body from the simulation. +proc removeBody*(space: PSpace; body: PBody){. + cdecl, importc: "cpSpaceRemoveBody", dynlib: Lib.} +#/ Remove a constraint from the simulation. +proc RemoveConstraint*(space: PSpace; constraint: PConstraint){. + cdecl, importc: "cpSpaceRemoveConstraint", dynlib: Lib.} +#/ Test if a collision shape has been added to the space. +proc containsShape*(space: PSpace; shape: PShape): Bool{. + cdecl, importc: "cpSpaceContainsShape", dynlib: Lib.} +#/ Test if a rigid body has been added to the space. +proc containsBody*(space: PSpace; body: PBody): Bool{. + cdecl, importc: "cpSpaceContainsBody", dynlib: Lib.} +#/ Test if a constraint has been added to the space. + +proc containsConstraint*(space: PSpace; constraint: PConstraint): Bool{. + cdecl, importc: "cpSpaceContainsConstraint", dynlib: Lib.} +#/ Schedule a post-step callback to be called when cpSpaceStep() finishes. +#/ @c obj is used a key, you can only register one callback per unique value for @c obj +proc addPostStepCallback*(space: PSpace; func: TPostStepFunc; + obj: pointer; data: pointer){. + cdecl, importc: "cpSpaceAddPostStepCallback", dynlib: Lib.} + +#/ Query the space at a point and call @c func for each shape found. +proc pointQuery*(space: PSpace; point: TVector; layers: TLayers; + group: TGroup; func: TSpacePointQueryFunc; data: pointer){. + cdecl, importc: "cpSpacePointQuery", dynlib: Lib.} + +#/ Query the space at a point and return the first shape found. Returns NULL if no shapes were found. +proc pointQueryFirst*(space: PSpace; point: TVector; layers: TLayers; + group: TGroup): PShape{. + cdecl, importc: "cpSpacePointQueryFirst", dynlib: Lib.} + +#/ Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected. +proc segmentQuery*(space: PSpace; start: TVector; to: TVector; + layers: TLayers; group: TGroup; + func: TSpaceSegmentQueryFunc; data: pointer){. + cdecl, importc: "cpSpaceSegmentQuery", dynlib: Lib.} +#/ Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit. +proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector; + layers: TLayers; group: TGroup; + res: PSegmentQueryInfo): PShape{. + cdecl, importc: "cpSpaceSegmentQueryFirst", dynlib: Lib.} + +#/ Perform a fast rectangle query on the space calling @c func for each shape found. +#/ Only the shape's bounding boxes are checked for overlap, not their full shape. +proc BBQuery*(space: PSpace; bb: TBB; layers: TLayers; group: TGroup; + func: TSpaceBBQueryFunc; data: pointer){. + cdecl, importc: "cpSpaceBBQuery", dynlib: Lib.} + +#/ Query a space for any shapes overlapping the given shape and call @c func for each shape found. +proc shapeQuery*(space: PSpace; shape: PShape; func: TSpaceShapeQueryFunc; data: pointer): Bool {. + cdecl, importc: "cpSpaceShapeQuery", dynlib: Lib.} +#/ Call cpBodyActivate() for any shape that is overlaps the given shape. +proc activateShapesTouchingShape*(space: PSpace; shape: PShape){. + cdecl, importc: "cpSpaceActivateShapesTouchingShape", dynlib: Lib.} + +#/ Call @c func for each body in the space. +proc eachBody*(space: PSpace; func: TSpaceBodyIteratorFunc; data: pointer){. + cdecl, importc: "cpSpaceEachBody", dynlib: Lib.} + +#/ Call @c func for each shape in the space. +proc eachShape*(space: PSpace; func: TSpaceShapeIteratorFunc; + data: pointer){. + cdecl, importc: "cpSpaceEachShape", dynlib: Lib.} +#/ Call @c func for each shape in the space. +proc eachConstraint*(space: PSpace; func: TSpaceConstraintIteratorFunc; + data: pointer){. + cdecl, importc: "cpSpaceEachConstraint", dynlib: Lib.} +#/ Update the collision detection info for the static shapes in the space. +proc reindexStatic*(space: PSpace){. + cdecl, importc: "cpSpaceReindexStatic", dynlib: Lib.} +#/ Update the collision detection data for a specific shape in the space. +proc reindexShape*(space: PSpace; shape: PShape){. + cdecl, importc: "cpSpaceReindexShape", dynlib: Lib.} +#/ Update the collision detection data for all shapes attached to a body. +proc reindexShapesForBody*(space: PSpace; body: PBody){. + cdecl, importc: "cpSpaceReindexShapesForBody", dynlib: Lib.} +#/ Switch the space to use a spatial has as it's spatial index. +proc SpaceUseSpatialHash*(space: PSpace; dim: CpFloat; count: cint){. + cdecl, importc: "cpSpaceUseSpatialHash", dynlib: Lib.} +#/ Step the space forward in time by @c dt. +proc step*(space: PSpace; dt: CpFloat) {. + cdecl, importc: "cpSpaceStep", dynlib: Lib.} + + +#/ Convenience constructor for cpVect structs. +proc vector*(x, y: CpFloat): TVector {.inline.} = + result.x = x + result.y = y +proc newVector*(x, y: CpFloat): TVector {.inline.} = + return vector(x, y) +#let VectorZero* = newVector(0.0, 0.0) +var VectorZero* = newVector(0.0, 0.0) + +#/ Vector dot product. +proc dot*(v1, v2: TVector): CpFloat {.inline.} = + result = v1.x * v2.x + v1.y * v2.y + +#/ Returns the length of v. +#proc len*(v: TVector): CpFloat {. +# cdecl, importc: "cpvlength", dynlib: Lib.} +proc len*(v: TVector): CpFloat {.inline.} = + result = v.dot(v).sqrt +#/ Spherical linearly interpolate between v1 and v2. +proc slerp*(v1, v2: TVector; t: CpFloat): TVector {. + cdecl, importc: "cpvslerp", dynlib: Lib.} +#/ Spherical linearly interpolate between v1 towards v2 by no more than angle a radians +proc slerpconst*(v1, v2: TVector; a: CpFloat): TVector {. + cdecl, importc: "cpvslerpconst", dynlib: Lib.} +#/ Returns the unit length vector for the given angle (in radians). +#proc vectorForAngle*(a: CpFloat): TVector {. +# cdecl, importc: "cpvforangle", dynlib: Lib.} +proc vectorForAngle*(a: CpFloat): TVector {.inline.} = + result = newVector(math.cos(a), math.sin(a)) +#/ Returns the angular direction v is pointing in (in radians). +proc toAngle*(v: TVector): CpFloat {.inline.} = + result = math.arctan2(v.y, v.x) +#/ Returns a string representation of v. Intended mostly for debugging purposes and not production use. +#/ @attention The string points to a static local and is reset every time the function is called. +#/ If you want to print more than one vector you will have to split up your printing onto separate lines. +proc `$`*(v: TVector): cstring {.cdecl, importc: "cpvstr", dynlib: Lib.} + + +#/ Check if two vectors are equal. (Be careful when comparing floating point numbers!) +proc `==`*(v1, v2: TVector): bool {.inline.} = + result = v1.x == v2.x and v1.y == v2.y + +#/ Add two vectors +proc `+`*(v1, v2: TVector): TVector {.inline.} = + result = newVector(v1.x + v2.x, v1.y + v2.y) +proc `+=`*(v1: var TVector; v2: TVector) = + v1.x = v1.x + v2.x + v1.y = v1.y + v2.y + +#/ Subtract two vectors. +proc `-`*(v1, v2: TVector): TVector {.inline.} = + result = newVector(v1.x - v2.x, v1.y - v2.y) +proc `-=`*(v1: var TVector; v2: TVector) = + v1.x = v1.x - v2.x + v1.y = v1.y - v2.y + +#/ Negate a vector. +proc `-`*(v: TVector): TVector {.inline.} = + result = newVector(- v.x, - v.y) + +#/ Scalar multiplication. +proc `*`*(v: TVector, s: CpFloat): TVector {.inline.} = + result.x = v.x * s + result.y = v.y * s +proc `*=`*(v: var TVector; s: CpFloat) = + v.x = v.x * s + v.y = v.y * s + +#/ 2D vector cross product analog. +#/ The cross product of 2D vectors results in a 3D vector with only a z component. +#/ This function returns the magnitude of the z value. +proc cross*(v1, v2: TVector): CpFloat {.inline.} = + result = v1.x * v2.y - v1.y * v2.x + +#/ Returns a perpendicular vector. (90 degree rotation) +proc perp*(v: TVector): TVector {.inline.} = + result = newVector(- v.y, v.x) + +#/ Returns a perpendicular vector. (-90 degree rotation) +proc rperp*(v: TVector): TVector {.inline.} = + result = newVector(v.y, - v.x) + +#/ Returns the vector projection of v1 onto v2. +proc project*(v1,v2: TVector): TVector {.inline.} = + result = v2 * (v1.dot(v2) / v2.dot(v2)) + +#/ Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector. + +proc rotate*(v1, v2: TVector): TVector {.inline.} = + result = newVector(v1.x * v2.x - v1.y * v2.y, v1.x * v2.y + v1.y * v2.x) +#/ Inverse of cpvrotate(). +proc unrotate*(v1, v2: TVector): TVector {.inline.} = + result = newVector(v1.x * v2.x + v1.y * v2.y, v1.y * v2.x - v1.x * v2.y) +#/ Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths. +proc lenSq*(v: TVector): CpFloat {.inline.} = + result = v.dot(v) +#/ Linearly interpolate between v1 and v2. +proc lerp*(v1, v2: TVector; t: CpFloat): TVector {.inline.} = + result = (v1 * (1.0 - t)) + (v2 * t) +#/ Returns a normalized copy of v. +proc normalize*(v: TVector): TVector {.inline.} = + result = v * (1.0 / v.len) +#/ Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors. +proc normalizeSafe*(v: TVector): TVector {.inline.} = + result = if v.x == 0.0 and v.y == 0.0: VectorZero else: v.normalize +#/ Clamp v to length len. +proc clamp*(v: TVector; len: CpFloat): TVector {.inline.} = + result = if v.dot(v) > len * len: v.normalize * len else: v +#/ Linearly interpolate between v1 towards v2 by distance d. +proc lerpconst*(v1, v2: TVector; d: CpFloat): TVector {.inline.} = + result = v1 + clamp(v2 - v1, d) #vadd(v1 + vclamp(vsub(v2, v1), d)) +#/ Returns the distance between v1 and v2. +proc dist*(v1, v2: TVector): CpFloat {.inline.} = + result = (v1 - v2).len #vlength(vsub(v1, v2)) +#/ Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances. +proc distsq*(v1, v2: TVector): CpFloat {.inline.} = + result = (v1 - v2).lenSq #vlengthsq(vsub(v1, v2)) +#/ Returns true if the distance between v1 and v2 is less than dist. +proc near*(v1, v2: TVector; dist: CpFloat): Bool{.inline.} = + result = v1.distSq(v2) < dist * dist + + + +##cpBody.h +proc allocBody*(): PBody {.importc: "cpBodyAlloc", dynlib: Lib.} +proc init*(body: PBody; m: CpFloat; i: CpFloat): PBody {. + importc: "cpBodyInit", dynlib: Lib.} +proc newBody*(m: CpFloat; i: CpFloat): PBody {. + importc: "cpBodyNew", dynlib: Lib.} + +proc initStaticBody*(body: PBody): PBody{. + importc: "cpBodyInitStatic", dynlib: Lib.} +#/ Allocate and initialize a static cpBody. +proc newStatic*(): PBody{.importc: "cpBodyNewStatic", dynlib: Lib.} +#/ Destroy a cpBody. +proc destroy*(body: PBody){.importc: "cpBodyDestroy", dynlib: Lib.} +#/ Destroy and free a cpBody. +proc free*(body: PBody){.importc: "cpBodyFree", dynlib: Lib.} + +#/ Wake up a sleeping or idle body. +proc activate*(body: PBody){.importc: "cpBodyActivate", dynlib: Lib.} +#/ Wake up any sleeping or idle bodies touching a static body. +proc activateStatic*(body: PBody; filter: PShape){. + importc: "cpBodyActivateStatic", dynlib: Lib.} +#/ Force a body to fall asleep immediately. +proc Sleep*(body: PBody){.importc: "cpBodySleep", dynlib: Lib.} +#/ Force a body to fall asleep immediately along with other bodies in a group. +proc SleepWithGroup*(body: PBody; group: PBody){. + importc: "cpBodySleepWithGroup", dynlib: Lib.} +#/ Returns true if the body is sleeping. +proc isSleeping*(body: PBody): Bool {.inline.} = + return body.node.root != nil +#/ Returns true if the body is static. +proc isStatic*(body: PBody): bool {.inline.} = + return body.node.idleTime == CpInfinity +#/ Returns true if the body has not been added to a space. +proc isRogue*(body: PBody): Bool {.inline.} = + return body.space == nil + +# #define CP_DefineBodyStructGetter(type, member, name) \ +# static inline type cpBodyGet##name(const cpBody *body){return body->member;} +# #define CP_DefineBodyStructSetter(type, member, name) \ +# static inline void cpBodySet##name(cpBody *body, const type value){ \ +# cpBodyActivate(body); \ +# cpBodyAssertSane(body); \ +# body->member = value; \ +# } +# #define CP_DefineBodyStructProperty(type, member, name) \ +# CP_DefineBodyStructGetter(type, member, name) \ +# CP_DefineBodyStructSetter(type, member, name) + +defGetter(PBody, CpFloat, m, Mass) +#/ Set the mass of a body. +when defined(MoreNimrod): + defSetter(PBody, CpFloat, m, Mass) +else: + proc setMass*(body: PBody; m: CpFloat){. + cdecl, importc: "cpBodySetMass", dynlib: Lib.} + +#/ Get the moment of a body. +defGetter(PBody, CpFloat, i, Moment) +#/ Set the moment of a body. +when defined(MoreNimrod): + defSetter(PBody, CpFloat, i, Moment) +else: + proc SetMoment*(body: PBody; i: CpFloat) {. + cdecl, importc: "cpBodySetMoment", dynlib: Lib.} + +#/ Get the position of a body. +defGetter(PBody, TVector, p, Pos) +#/ Set the position of a body. +when defined(MoreNimrod): + defSetter(PBody, TVector, p, Pos) +else: + proc setPos*(body: PBody; pos: TVector) {. + cdecl, importc: "cpBodySetPos", dynlib: Lib.} + +defProp(PBody, TVector, v, Vel) +defProp(PBody, TVector, f, Force) + +#/ Get the angle of a body. +defGetter(PBody, CpFloat, a, Angle) +#/ Set the angle of a body. +proc setAngle*(body: PBody; a: CpFloat){. + cdecl, importc: "cpBodySetAngle", dynlib: Lib.} + +defProp(PBody, CpFloat, w, AngVel) +defProp(PBody, CpFloat, t, Torque) +defGetter(PBody, TVector, rot, Rot) +defProp(PBody, CpFloat, v_limit, VelLimit) +defProp(PBody, CpFloat, w_limit, AngVelLimit) +defProp(PBody, pointer, data, UserData) + +#/ Default Integration functions. +proc UpdateVelocity*(body: PBody; gravity: TVector; damping: CpFloat; dt: CpFloat){. + cdecl, importc: "cpBodyUpdateVelocity", dynlib: Lib.} +proc UpdatePosition*(body: PBody; dt: CpFloat){. + cdecl, importc: "cpBodyUpdatePosition", dynlib: Lib.} +#/ Convert body relative/local coordinates to absolute/world coordinates. +proc Local2World*(body: PBody; v: TVector): TVector{.inline.} = + result = body.p + v.rotate(body.rot) ##return cpvadd(body.p, cpvrotate(v, body.rot)) +#/ Convert body absolute/world coordinates to relative/local coordinates. +proc world2Local*(body: PBody; v: TVector): TVector{.inline.} = + result = (v - body.p).unrotate(body.rot) +#/ Set the forces and torque or a body to zero. +proc resetForces*(body: PBody){. + cdecl, importc: "cpBodyResetForces", dynlib: Lib.} +#/ Apply an force (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates). +proc applyForce*(body: PBody; f, r: TVector){. + cdecl, importc: "cpBodyApplyForce", dynlib: Lib.} +#/ Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates). +proc applyImpulse*(body: PBody; j, r: TVector){. + cdecl, importc: "cpBodyApplyImpulse", dynlib: Lib.} +#/ Get the velocity on a body (in world units) at a point on the body in world coordinates. + +proc getVelAtWorldPoint*(body: PBody; point: TVector): TVector{. + cdecl, importc: "cpBodyGetVelAtWorldPoint", dynlib: Lib.} +#/ Get the velocity on a body (in world units) at a point on the body in local coordinates. +proc getVelAtLocalPoint*(body: PBody; point: TVector): TVector{. + cdecl, importc: "cpBodyGetVelAtLocalPoint", dynlib: Lib.} +#/ Get the kinetic energy of a body. +# static inline CpFloat cpBodyKineticEnergy(const cpBody *body) +# { +# // Need to do some fudging to avoid NaNs +# cpFloat vsq = cpvdot(body->v, body->v); +# cpFloat wsq = body->w*body->w; +# return (vsq ? vsq*body->m : 0.0f) + (wsq ? wsq*body->i : 0.0f); +# } +proc kineticEnergy*(body: PBOdy): CpFloat = + result = (body.v.dot(body.v) * body.m) + (body.w * body.w * body.i) + +#/ Call @c func once for each shape attached to @c body and added to the space. +proc eachShape*(body: PBody; func: TBodyShapeIteratorFunc; + data: pointer){. + cdecl, importc: "cpBodyEachShape", dynlib: Lib.} +#/ Call @c func once for each constraint attached to @c body and added to the space. +proc eachConstraint*(body: PBody; func: TBodyConstraintIteratorFunc; + data: pointer) {. + cdecl, importc: "cpBodyEachConstraint", dynlib: Lib.} +#/ Call @c func once for each arbiter that is currently active on the body. +proc eachArbiter*(body: PBody; func: TBodyArbiterIteratorFunc; + data: pointer){. + cdecl, importc: "cpBodyEachArbiter", dynlib: Lib.} +#/ Allocate a spatial hash. +proc SpaceHashAlloc*(): PSpaceHash{. + cdecl, importc: "cpSpaceHashAlloc", dynlib: Lib.} +#/ Initialize a spatial hash. +proc SpaceHashInit*(hash: PSpaceHash; celldim: CpFloat; numcells: cint; + bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. + cdecl, importc: "cpSpaceHashInit", dynlib: Lib.} +#/ Allocate and initialize a spatial hash. +proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfunc: TSpatialIndexBBFunc; + staticIndex: PSpatialIndex): PSpatialIndex{. + cdecl, importc: "cpSpaceHashNew", dynlib: Lib.} +#/ Change the cell dimensions and table size of the spatial hash to tune it. +#/ The cell dimensions should roughly match the average size of your objects +#/ and the table size should be ~10 larger than the number of objects inserted. +#/ Some trial and error is required to find the optimum numbers for efficiency. +proc SpaceHashResize*(hash: PSpaceHash; celldim: CpFloat; numcells: cint){. + cdecl, importc: "cpSpaceHashResize", dynlib: Lib.} +#MARK: AABB Tree + + +#/ Allocate a bounding box tree. +proc BBTreeAlloc*(): PBBTree{.cdecl, importc: "cpBBTreeAlloc", dynlib: Lib.} +#/ Initialize a bounding box tree. +proc BBTreeInit*(tree: PBBTree; bbfunc: TSpatialIndexBBFunc; + staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, + importc: "cpBBTreeInit", dynlib: Lib.} +#/ Allocate and initialize a bounding box tree. +proc BBTreeNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. + cdecl, importc: "cpBBTreeNew", dynlib: Lib.} +#/ Perform a static top down optimization of the tree. +proc BBTreeOptimize*(index: PSpatialIndex){. + cdecl, importc: "cpBBTreeOptimize", dynlib: Lib.} +#/ Set the velocity function for the bounding box tree to enable temporal coherence. + +proc BBTreeSetVelocityFunc*(index: PSpatialIndex; func: TBBTreeVelocityFunc){. + cdecl, importc: "cpBBTreeSetVelocityFunc", dynlib: Lib.} +#MARK: Single Axis Sweep + + +#/ Allocate a 1D sort and sweep broadphase. + +proc Sweep1DAlloc*(): ptr TSweep1D{.cdecl, importc: "cpSweep1DAlloc", + dynlib: Lib.} +#/ Initialize a 1D sort and sweep broadphase. + +proc Sweep1DInit*(sweep: ptr TSweep1D; bbfunc: TSpatialIndexBBFunc; + staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, + importc: "cpSweep1DInit", dynlib: Lib.} +#/ Allocate and initialize a 1D sort and sweep broadphase. + +proc Sweep1DNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{. + cdecl, importc: "cpSweep1DNew", dynlib: Lib.} + + + +defProp(PArbiter, CpFloat, e, Elasticity) +defProp(PArbiter, CpFloat, u, Friction) +defProp(PArbiter, TVector, surface_vr, SurfaceVelocity) + +#/ Calculate the total impulse that was applied by this +#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback. +proc totalImpulse*(obj: PArbiter): TVector {.cdecl, importc: "cpArbiterTotalImpulse", dynlib: Lib.} + +#/ Calculate the total impulse including the friction that was applied by this arbiter. +#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback. +proc totalImpulseWithFriction*(obj: PArbiter): TVector {.cdecl, importc: "cpArbiterTotalImpulseWithFriction", dynlib: Lib.} + +#/ Calculate the amount of energy lost in a collision including static, but not dynamic friction. +#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback. +proc totalKE*(obj: PArbiter): CpFloat {.cdecl, importc: "cpArbiterTotalKE", dynlib: Lib.} + + +#/ Causes a collision pair to be ignored as if you returned false from a begin callback. +#/ If called from a pre-step callback, you will still need to return false +#/ if you want it to be ignored in the current step. +proc ignore*(arb: PArbiter) {.cdecl, importc: "cpArbiterIgnore", dynlib: Lib.} + +#/ Return the colliding shapes involved for this arbiter. +#/ The order of their cpSpace.collision_type values will match +#/ the order set when the collision handler was registered. +proc getShapes*(arb: PArbiter, a, b: var PShape) {.inline.} = + if arb.swappedColl.bool: + a = arb.b + b = arb.a + else: + a = arb.a + b = arb.b + +#/ A macro shortcut for defining and retrieving the shapes from an arbiter. +#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b); +template getShapes*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} = + var name1, name2: PShape + getShapes(arb, name1, name2) + + +#/ Return the colliding bodies involved for this arbiter. +#/ The order of the cpSpace.collision_type the bodies are associated with values will match +#/ the order set when the collision handler was registered. +#proc getBodies*(arb: PArbiter, a, b: var PBody) {.inline.} = +# getShapes(arb, shape1, shape2) +# a = shape1.body +# b = shape2.body + +#/ A macro shortcut for defining and retrieving the bodies from an arbiter. +#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b); +template getBodies*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} = + var name1, name2: PBOdy + getBodies(arb, name1, name2) + +proc isFirstContact*(arb: PArbiter): bool {.inline.} = + result = arb.state == ArbiterStateFirstColl + +proc getCount*(arb: PArbiter): cint {.inline.} = + result = arb.numContacts + +#/ Return a contact set from an arbiter. +proc getContactPointSet*(arb: PArbiter): TContactPointSet {. + cdecl, importc: "cpArbiterGetContactPointSet", dynlib: Lib.} +#/ Get the normal of the @c ith contact point. +proc getNormal*(arb: PArbiter; i: cint): TVector {. + cdecl, importc: "cpArbiterGetNormal", dynlib: Lib.} +#/ Get the position of the @c ith contact point. +proc getPoint*(arb: PArbiter; i: cint): TVector {. + cdecl, importc: "cpArbiterGetPoint", dynlib: Lib.} +#/ Get the depth of the @c ith contact point. +proc getDepth*(arb: PArbiter; i: cint): CpFloat {. + cdecl, importc: "cpArbiterGetDepth", dynlib: Lib.} + +##Shapes +template defShapeSetter(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} = + proc `set procName`*(obj: PShape, value: memberType) {.cdecl.} = + if activates and obj.body != nil: obj.body.activate() + obj.memberName = value +template defShapeProp(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} = + defGetter(PShape, memberType, memberName, procName) + defShapeSetter(memberType, memberName, procName, activates) + +#/ Destroy a shape. +proc destroy*(shape: PShape) {. + cdecl, importc: "cpShapeDestroy", dynlib: Lib.} +#/ Destroy and Free a shape. +proc free*(shape: PShape){. + cdecl, importc: "cpShapeFree", dynlib: Lib.} +#/ Update, cache and return the bounding box of a shape based on the body it's attached to. +proc cacheBB*(shape: PShape): TBB{. + cdecl, importc: "cpShapeCacheBB", dynlib: Lib.} +#/ Update, cache and return the bounding box of a shape with an explicit transformation. +proc update*(shape: PShape; pos: TVector; rot: TVector): TBB {. + cdecl, importc: "cpShapeUpdate", dynlib: Lib.} +#/ Test if a point lies within a shape. +proc pointQuery*(shape: PShape; p: TVector): Bool32 {. + cdecl, importc: "cpShapePointQuery", dynlib: Lib.} + +#/ Perform a nearest point query. It finds the closest point on the surface of shape to a specific point. +#/ The value returned is the distance between the points. A negative distance means the point is inside the shape. +proc nearestPointQuery*(shape: PShape; p: TVector; res: PNearestPointQueryInfo): CpFloat {. + cdecl, importc: "cpShapeNearestPointQuery", dynlib: Lib.} +#/ Perform a segment query against a shape. @c info must be a pointer to a valid cpSegmentQueryInfo structure. +proc segmentQuery*(shape: PShape, a, b: TVector, info: PSegmentQueryInfo): bool {. + cdecl, importc: "cpShapeSegmentQuery", dynlib: Lib.} + +#/ Get the hit point for a segment query. +## Possibly change; info to PSegmentQueryInfo +proc queryHitPoint*(start, to: TVector, info: TSegmentQueryInfo): TVector {.inline.} = + result = start.lerp(to, info.t) + +#/ Get the hit distance for a segment query. +proc queryHitDist*(start, to: TVector, info: TSegmentQueryInfo): CpFloat {.inline.} = + result = start.dist(to) * info.t + +defGetter(PShape, PSpace, space, Space) + +defGetter(PShape, PBody, body, Body) +proc setBody*(shape: PShape, value: PBody) {. + cdecl, importc: "cpShapeSetBody", dynlib: Lib.} + + +defGetter(PShape, TBB, bb, BB) +defShapeProp(Bool32, sensor, Sensor, true) +defShapeProp(CpFloat, e, Elasticity, false) +defShapeProp(CpFloat, u, Friction, true) +defShapeProp(TVector, surface_v, SurfaceVelocity, true) +defShapeProp(pointer, data, UserData, false) +defShapeProp(TCollisionType, collision_type, CollisionType, true) +defShapeProp(TGroup, group, Group, true) +defShapeProp(TLayers, layers, Layers, true) + +#/ When initializing a shape, it's hash value comes from a counter. +#/ Because the hash value may affect iteration order, you can reset the shape ID counter +#/ when recreating a space. This will make the simulation be deterministic. +proc resetShapeIdCounter*(): void {.cdecl, importc: "cpResetShapeIdCounter", dynlib: Lib.} +#/ Allocate a circle shape. +proc CircleShapeAlloc*(): PCircleShape {.cdecl, importc: "cpCircleShapeAlloc", dynlib: Lib.} +#/ Initialize a circle shape. +proc init*(circle: PCircleShape, body: PBody, radius: CpFloat, offset: TVector): PCircleShape {. + cdecl, importc: "cpCircleShapeInit", dynlib: Lib.} +#/ Allocate and initialize a circle shape. +proc newCircleShape*(body: PBody, radius: CpFloat, offset: TVector): PShape {. + cdecl, importc: "cpCircleShapeNew", dynlib: Lib.} + +proc getCircleOffset*(shape: PShape): TVector {. + cdecl, importc: "cpCircleShapeGetOffset", dynlib: Lib.} +proc getCircleRadius*(shape: PShape): CpFloat {. + cdecl, importc: "cpCircleShapeGetRadius", dynlib: Lib.} + + +#/ Allocate a polygon shape. +proc allocPolyShape*(): PPolyShape {. + cdecl, importc: "cpPolyShapeAlloc", dynlib: Lib.} +#/ Initialize a polygon shape. +#/ A convex hull will be created from the vertexes. +proc init*(poly: PPolyShape; body: PBody, numVerts: cint; + verts: ptr TVector; offset: TVector): PPolyShape {. + cdecl, importc: "cpPolyShapeInit", dynlib: Lib.} +#/ Allocate and initialize a polygon shape. +#/ A convex hull will be created from the vertexes. +proc newPolyShape*(body: PBody; numVerts: cint; verts: ptr TVector; + offset: TVector): PShape {. + cdecl, importc: "cpPolyShapeNew", dynlib: Lib.} +#/ Initialize a box shaped polygon shape. +proc init*(poly: PPolyShape; body: PBody; width, height: CpFloat): PPolyShape {. + cdecl, importc: "cpBoxShapeInit", dynlib: Lib.} +#/ Initialize an offset box shaped polygon shape. +proc init*(poly: PPolyShape; body: PBody; box: TBB): PPolyShape {. + cdecl, importc: "cpBoxShapeInit2", dynlib: Lib.} +#/ Allocate and initialize a box shaped polygon shape. +proc newBoxShape*(body: PBody; width, height: CpFloat): PShape {. + cdecl, importc: "cpBoxShapeNew", dynlib: Lib.} +#/ Allocate and initialize an offset box shaped polygon shape. +proc newBoxShape*(body: PBody; box: TBB): PShape {. + cdecl, importc: "cpBoxShapeNew2", dynlib: Lib.} + +#/ Check that a set of vertexes is convex and has a clockwise winding. +#/ NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate! +proc validatePoly*(verts: ptr TVector; numVerts: cint): bool {. + cdecl, importc: "cpPolyValidate", dynlib: Lib.} +#/ Get the number of verts in a polygon shape. +proc getNumVerts*(shape: PShape): cint {. + cdecl, importc: "cpPolyShapeGetNumVerts", dynlib: Lib.} +#/ Get the @c ith vertex of a polygon shape. +proc getVert*(shape: PShape; index: cint): TVector {. + cdecl, importc: "cpPolyShapeGetVert", dynlib: Lib.} + +#/ Allocate a segment shape. +proc allocSegmentShape*(): PSegmentShape {. + cdecl, importc: "cpSegmentShapeAlloc", dynlib: Lib.} +#/ Initialize a segment shape. +proc init*(seg: PSegmentShape, body: PBody, a, b: TVector, radius: CpFloat): PSegmentShape {. + cdecl, importc: "cpSegmentShapeInit", dynlib: Lib.} +#/ Allocate and initialize a segment shape. +proc newSegmentShape*(body: PBody, a, b: TVector, radius: CpFloat): PShape {. + cdecl, importc: "cpSegmentShapeNew", dynlib: Lib.} + +proc setSegmentNeighbors*(shape: PShape, prev, next: TVector) {. + cdecl, importc: "cpSegmentShapeSetNeighbors", dynlib: Lib.} +proc getSegmentA*(shape: PShape): TVector {. + cdecl, importc: "cpSegmentShapeGetA", dynlib: Lib.} +proc getSegmentB*(shape: PShape): TVector {. + cdecl, importc: "cpSegmentShapeGetB", dynlib: Lib.} +proc getSegmentNormal*(shape: PShape): TVector {. + cdecl, importc: "cpSegmentShapeGetNormal", dynlib: Lib.} +proc getSegmentRadius*(shape: PShape): CpFloat {. + cdecl, importc: "cpSegmentShapeGetRadius", dynlib: Lib.} + + +#/ Version string. +#var VersionString*{.importc: "cpVersionString", dynlib: Lib.}: cstring +#/ Calculate the moment of inertia for a circle. +#/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0. +when defined(MoreNimrod): + proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {.cdecl.} = + result = m * (0.5 * (r1 * r1 + r2 * r2) + lenSq(offset)) +else: + proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {. + cdecl, importc: "cpMomentForCircle", dynlib: Lib.} + +#/ Calculate area of a hollow circle. +#/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0. +proc AreaForCircle*(r1: CpFloat; r2: CpFloat): CpFloat {. + cdecl, importc: "cpAreaForCircle", dynlib: Lib.} +#/ Calculate the moment of inertia for a line segment. +#/ Beveling radius is not supported. +proc MomentForSegment*(m: CpFloat; a, b: TVector): CpFloat {. + cdecl, importc: "cpMomentForSegment", dynlib: Lib.} +#/ Calculate the area of a fattened (capsule shaped) line segment. +proc AreaForSegment*(a, b: TVector; r: CpFloat): CpFloat {. + cdecl, importc: "cpAreaForSegment", dynlib: Lib.} +#/ Calculate the moment of inertia for a solid polygon shape assuming it's center of gravity is at it's centroid. The offset is added to each vertex. +proc MomentForPoly*(m: CpFloat; numVerts: cint; verts: ptr TVector; offset: TVector): CpFloat {. + cdecl, importc: "cpMomentForPoly", dynlib: Lib.} +#/ Calculate the signed area of a polygon. A Clockwise winding gives positive area. +#/ This is probably backwards from what you expect, but matches Chipmunk's the winding for poly shapes. +proc AreaForPoly*(numVerts: cint; verts: ptr TVector): CpFloat {. + cdecl, importc: "cpAreaForPoly", dynlib: Lib.} +#/ Calculate the natural centroid of a polygon. +proc CentroidForPoly*(numVerts: cint; verts: ptr TVector): TVector {. + cdecl, importc: "cpCentroidForPoly", dynlib: Lib.} +#/ Center the polygon on the origin. (Subtracts the centroid of the polygon from each vertex) +proc RecenterPoly*(numVerts: cint; verts: ptr TVector) {. + cdecl, importc: "cpRecenterPoly", dynlib: Lib.} +#/ Calculate the moment of inertia for a solid box. +proc MomentForBox*(m, width, height: CpFloat): CpFloat {. + cdecl, importc: "cpMomentForBox", dynlib: Lib.} +#/ Calculate the moment of inertia for a solid box. +proc MomentForBox2*(m: CpFloat; box: TBB): CpFloat {. + cdecl, importc: "cpMomentForBox2", dynlib: Lib.} + + + +##constraints +type + #TODO: all these are private + #TODO: defConstraintProp() + PPinJoint = ptr TPinJoint + TPinJoint{.pf.} = object + constraint: PConstraint + anchr1: TVector + anchr2: TVector + dist: CpFloat + r1: TVector + r2: TVector + n: TVector + nMass: CpFloat + jnAcc: CpFloat + jnMax: CpFloat + bias: CpFloat + PSlideJoint = ptr TSlideJoint + TSlideJoint{.pf.} = object + constraint: PConstraint + anchr1: TVector + anchr2: TVector + min: CpFloat + max: CpFloat + r1: TVector + r2: TVector + n: TVector + nMass: CpFloat + jnAcc: CpFloat + jnMax: CpFloat + bias: CpFloat + PPivotJoint = ptr TPivotJoint + TPivotJoint{.pf.} = object + constraint: PConstraint + anchr1: TVector + anchr2: TVector + r1: TVector + r2: TVector + k1: TVector + k2: TVector + jAcc: TVector + jMaxLen: CpFloat + bias: TVector + PGrooveJoint = ptr TGrooveJoint + TGrooveJoint{.pf.} = object + constraint: PConstraint + grv_n: TVector + grv_a: TVector + grv_b: TVector + anchr2: TVector + grv_tn: TVector + clamp: CpFloat + r1: TVector + r2: TVector + k1: TVector + k2: TVector + jAcc: TVector + jMaxLen: CpFloat + bias: TVector + PDampedSpring = ptr TDampedSpring + TDampedSpring{.pf.} = object + constraint: PConstraint + anchr1: TVector + anchr2: TVector + restLength: CpFloat + stiffness: CpFloat + damping: CpFloat + springForceFunc: TDampedSpringForceFunc + target_vrn: CpFloat + v_coef: CpFloat + r1: TVector + r2: TVector + nMass: CpFloat + n: TVector + PDampedRotarySpring = ptr TDampedRotarySpring + TDampedRotarySpring{.pf.} = object + constraint: PConstraint + restAngle: CpFloat + stiffness: CpFloat + damping: CpFloat + springTorqueFunc: TDampedRotarySpringTorqueFunc + target_wrn: CpFloat + w_coef: CpFloat + iSum: CpFloat + PRotaryLimitJoint = ptr TRotaryLimitJoint + TRotaryLimitJoint{.pf.} = object + constraint: PConstraint + min: CpFloat + max: CpFloat + iSum: CpFloat + bias: CpFloat + jAcc: CpFloat + jMax: CpFloat + PRatchetJoint = ptr TRatchetJoint + TRatchetJoint{.pf.} = object + constraint: PConstraint + angle: CpFloat + phase: CpFloat + ratchet: CpFloat + iSum: CpFloat + bias: CpFloat + jAcc: CpFloat + jMax: CpFloat + PGearJoint = ptr TGearJoint + TGearJoint{.pf.} = object + constraint: PConstraint + phase: CpFloat + ratio: CpFloat + ratio_inv: CpFloat + iSum: CpFloat + bias: CpFloat + jAcc: CpFloat + jMax: CpFloat + PSimpleMotor = ptr TSimpleMotor + TSimpleMotor{.pf.} = object + constraint: PConstraint + rate: CpFloat + iSum: CpFloat + jAcc: CpFloat + jMax: CpFloat + TDampedSpringForceFunc* = proc (spring: PConstraint; dist: CpFloat): CpFloat{. + cdecl.} + TDampedRotarySpringTorqueFunc* = proc (spring: PConstraint; + relativeAngle: CpFloat): CpFloat {.cdecl.} +#/ Destroy a constraint. +proc destroy*(constraint: PConstraint){. + cdecl, importc: "cpConstraintDestroy", dynlib: Lib.} +#/ Destroy and free a constraint.111 +proc free*(constraint: PConstraint){. + cdecl, importc: "cpConstraintFree", dynlib: Lib.} + +#/ @private +proc activateBodies(constraint: PConstraint) {.inline.} = + if not constraint.a.isNil: constraint.a.activate() + if not constraint.b.isNil: constraint.b.activate() + +# /// @private +# #define CP_DefineConstraintStructGetter(type, member, name) \ +# static inline type cpConstraint##Get##name(const cpConstraint *constraint){return constraint->member;} +# /// @private +# #define CP_DefineConstraintStructSetter(type, member, name) \ +# static inline void cpConstraint##Set##name(cpConstraint *constraint, type value){ \ +# cpConstraintActivateBodies(constraint); \ +# constraint->member = value; \ +# } +template defConstraintSetter(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = + proc `set name`*(constraint: PConstraint, value: memberType) {.cdecl.} = + activateBodies(constraint) + constraint.member = value +template defConstraintProp(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = + defGetter(PConstraint, memberType, member, name) + defConstraintSetter(memberType, member, name) +# CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space) +defGetter(PConstraint, PSpace, space, Space) +defGetter(PConstraint, PBody, a, A) +defGetter(PConstraint, PBody, a, B) +defGetter(PConstraint, CpFloat, maxForce, MaxForce) +defGetter(PConstraint, CpFloat, errorBias, ErrorBias) +defGetter(PConstraint, CpFloat, maxBias, MaxBias) +defGetter(PConstraint, TConstraintPreSolveFunc, preSolve, PreSolveFunc) +defGetter(PConstraint, TConstraintPostSolveFunc, postSolve, PostSolveFunc) +defGetter(PConstraint, CpDataPointer, data, UserData) +# Get the last impulse applied by this constraint. +proc getImpulse*(constraint: PConstraint): CpFloat {.inline.} = + return constraint.klass.getImpulse(constraint) + +# #define cpConstraintCheckCast(constraint, struct) \ +# cpAssertHard(constraint->CP_PRIVATE(klass) == struct##GetClass(), "Constraint is not a "#struct) +# #define CP_DefineConstraintGetter(struct, type, member, name) \ +# static inline type struct##Get##name(const cpConstraint *constraint){ \ +# cpConstraintCheckCast(constraint, struct); \ +# return ((struct *)constraint)->member; \ +# } +# #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 constraintCheckCast(constraint: PConstraint, ctype: expr): stmt {.immediate.} = + assert(constraint.klass == `ctype getClass`(), "Constraint is the wrong class") +template defCGetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = + proc `get ctype name`*(constraint: PConstraint): memberType {.cdecl.} = + constraintCheckCast(constraint, ctype) + result = cast[`P ctype`](constraint).member +template defCSetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = + proc `set ctype name`*(constraint: PConstraint, value: memberType) {.cdecl.} = + constraintCheckCast(constraint, ctype) + activateBodies(constraint) + cast[`P ctype`](constraint).member = value +template defCProp(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = + defCGetter(ctype, memberType, member, name) + defCSetter(ctype, memberType, member, name) + +proc PinJointGetClass*(): PConstraintClass{. + cdecl, importc: "cpPinJointGetClass", dynlib: Lib.} +#/ @private + +#/ Allocate a pin joint. +proc AllocPinJoint*(): PPinJoint{. + cdecl, importc: "cpPinJointAlloc", dynlib: Lib.} +#/ Initialize a pin joint. +proc PinJointInit*(joint: PPinJoint; a: PBody; b: PBody; anchr1: TVector; + anchr2: TVector): PPinJoint{. + cdecl, importc: "cpPinJointInit", dynlib: Lib.} +#/ Allocate and initialize a pin joint. +proc newPinJoint*(a: PBody; b: PBody; anchr1: TVector; anchr2: TVector): PConstraint{. + cdecl, importc: "cpPinJointNew", dynlib: Lib.} +# CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1) +defCProp(PinJoint, TVector, anchr1, Anchr1) +defCProp(PinJoint, TVector, anchr2, Anchr2) +defCProp(PinJoint, CpFloat, dist, Dist) + +proc SlideJointGetClass*(): PConstraintClass{. + cdecl, importc: "cpSlideJointGetClass", dynlib: Lib.} +#/ Allocate a slide joint. +proc AllocSlideJoint*(): PSlideJoint{. + cdecl, importc: "cpSlideJointAlloc", dynlib: Lib.} +#/ Initialize a slide joint. +proc init*(joint: PSlideJoint; a, b: PBody; anchr1, anchr2: TVector; + min, max: CpFloat): PSlideJoint{. + cdecl, importc: "cpSlideJointInit", dynlib: Lib.} +#/ Allocate and initialize a slide joint. +proc newSlideJoint*(a, b: PBody; anchr1, anchr2: TVector; min, max: CpFloat): PConstraint{. + cdecl, importc: "cpSlideJointNew", dynlib: Lib.} + +defCProp(SlideJoint, TVector, anchr1, Anchr1) +defCProp(SlideJoint, TVector, anchr2, Anchr2) +defCProp(SlideJoint, CpFloat, min, Min) +defCProp(SlideJoint, CpFloat, max, Max) + +proc pivotJointGetClass*(): PConstraintClass {. + cdecl, importc: "cpPivotJointGetClass", dynlib: Lib.} + +#/ Allocate a pivot joint +proc allocPivotJoint*(): PPivotJoint{. + cdecl, importc: "cpPivotJointAlloc", dynlib: Lib.} +#/ Initialize a pivot joint. +proc init*(joint: PPivotJoint; a, b: PBody; anchr1, anchr2: TVector): PPivotJoint{. + cdecl, importc: "cpPivotJointInit", dynlib: Lib.} +#/ Allocate and initialize a pivot joint. +proc newPivotJoint*(a, b: PBody; pivot: TVector): PConstraint{. + cdecl, importc: "cpPivotJointNew", dynlib: Lib.} +#/ Allocate and initialize a pivot joint with specific anchors. +proc newPivotJoint*(a, b: PBody; anchr1, anchr2: TVector): PConstraint{. + cdecl, importc: "cpPivotJointNew2", dynlib: Lib.} + +defCProp(PivotJoint, TVector, anchr1, Anchr1) +defCProp(PivotJoint, TVector, anchr2, Anchr2) + + +proc GrooveJointGetClass*(): PConstraintClass{. + cdecl, importc: "cpGrooveJointGetClass", dynlib: Lib.} +#/ Allocate a groove joint. +proc GrooveJointAlloc*(): ptr TGrooveJoint{. + cdecl, importc: "cpGrooveJointAlloc", dynlib: Lib.} +#/ Initialize a groove joint. +proc Init*(joint: PGrooveJoint; a, b: PBody; groove_a, groove_b, anchr2: TVector): PGrooveJoint{. + cdecl, importc: "cpGrooveJointInit", dynlib: Lib.} +#/ Allocate and initialize a groove joint. +proc newGrooveJoint*(a, b: PBody; groove_a, groove_b, anchr2: TVector): PConstraint{. + cdecl, importc: "cpGrooveJointNew", dynlib: Lib.} + +defCGetter(GrooveJoint, TVector, grv_a, GrooveA) +defCGetter(GrooveJoint, TVector, grv_b, GrooveB) +# /// Set endpoint a of a groove joint's groove +proc SetGrooveA*(constraint: PConstraint, value: TVector) {. + cdecl, importc: "cpGrooveJointSetGrooveA", dynlib: Lib.} +# /// Set endpoint b of a groove joint's groove +proc SetGrooveB*(constraint: PConstraint, value: TVector) {. + cdecl, importc: "cpGrooveJointSetGrooveB", dynlib: Lib.} +defCProp(GrooveJoint, TVector, anchr2, Anchr2) + +proc DampedSpringGetClass*(): PConstraintClass{. + cdecl, importc: "cpDampedSpringGetClass", dynlib: Lib.} +#/ Allocate a damped spring. +proc AllocDampedSpring*(): PDampedSpring{. + cdecl, importc: "cpDampedSpringAlloc", dynlib: Lib.} +#/ Initialize a damped spring. +proc init*(joint: PDampedSpring; a, b: PBody; anchr1, anchr2: TVector; + restLength, stiffness, damping: CpFloat): PDampedSpring{. + cdecl, importc: "cpDampedSpringInit", dynlib: Lib.} +#/ Allocate and initialize a damped spring. +proc newDampedSpring*(a, b: PBody; anchr1, anchr2: TVector; + restLength, stiffness, damping: CpFloat): PConstraint{. + cdecl, importc: "cpDampedSpringNew", dynlib: Lib.} + +# CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1) +defCProp(DampedSpring, TVector, anchr1, Anchr1) +defCProp(DampedSpring, TVector, anchr2, Anchr2) +defCProp(DampedSpring, CpFloat, restLength, RestLength) +defCProp(DampedSpring, CpFloat, stiffness, Stiffness) +defCProp(DampedSpring, CpFloat, damping, Damping) +defCProp(DampedSpring, TDampedSpringForceFunc, springForceFunc, SpringForceFunc) + + +proc DampedRotarySpringGetClass*(): PConstraintClass{. + cdecl, importc: "cpDampedRotarySpringGetClass", dynlib: Lib.} + +#/ Allocate a damped rotary spring. +proc DampedRotarySpringAlloc*(): PDampedRotarySpring{. + cdecl, importc: "cpDampedRotarySpringAlloc", dynlib: Lib.} +#/ Initialize a damped rotary spring. +proc init*(joint: PDampedRotarySpring; a, b: PBody; + restAngle, stiffness, damping: CpFloat): PDampedRotarySpring{. + cdecl, importc: "cpDampedRotarySpringInit", dynlib: Lib.} +#/ Allocate and initialize a damped rotary spring. +proc DampedRotarySpringNew*(a, b: PBody; restAngle, stiffness, damping: CpFloat): PConstraint{. + cdecl, importc: "cpDampedRotarySpringNew", dynlib: Lib.} + +defCProp(DampedRotarySpring, CpFloat, restAngle, RestAngle) +defCProp(DampedRotarySpring, CpFloat, stiffness, Stiffness) +defCProp(DampedRotarySpring, CpFloat, damping, Damping) +defCProp(DampedRotarySpring, TDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc) + + +proc RotaryLimitJointGetClass*(): PConstraintClass{. + cdecl, importc: "cpRotaryLimitJointGetClass", dynlib: Lib.} +#/ Allocate a damped rotary limit joint. +proc allocRotaryLimitJoint*(): PRotaryLimitJoint{. + cdecl, importc: "cpRotaryLimitJointAlloc", dynlib: Lib.} +#/ Initialize a damped rotary limit joint. +proc init*(joint: PRotaryLimitJoint; a, b: PBody; min, max: CpFloat): PRotaryLimitJoint{. + cdecl, importc: "cpRotaryLimitJointInit", dynlib: Lib.} +#/ Allocate and initialize a damped rotary limit joint. +proc newRotaryLimitJoint*(a, b: PBody; min, max: CpFloat): PConstraint{. + cdecl, importc: "cpRotaryLimitJointNew", dynlib: Lib.} + +defCProp(RotaryLimitJoint, CpFloat, min, Min) +defCProp(RotaryLimitJoint, CpFloat, max, Max) + + +proc RatchetJointGetClass*(): PConstraintClass{. + cdecl, importc: "cpRatchetJointGetClass", dynlib: Lib.} +#/ Allocate a ratchet joint. +proc AllocRatchetJoint*(): PRatchetJoint{. + cdecl, importc: "cpRatchetJointAlloc", dynlib: Lib.} +#/ Initialize a ratched joint. +proc init*(joint: PRatchetJoint; a, b: PBody; phase, ratchet: CpFloat): PRatchetJoint{. + cdecl, importc: "cpRatchetJointInit", dynlib: Lib.} +#/ Allocate and initialize a ratchet joint. +proc NewRatchetJoint*(a, b: PBody; phase, ratchet: CpFloat): PConstraint{. + cdecl, importc: "cpRatchetJointNew", dynlib: Lib.} + +defCProp(RatchetJoint, CpFloat, angle, Angle) +defCProp(RatchetJoint, CpFloat, phase, Phase) +defCProp(RatchetJoint, CpFloat, ratchet, Ratchet) + + +proc GearJointGetClass*(): PConstraintClass{.cdecl, + importc: "cpGearJointGetClass", dynlib: Lib.} +#/ Allocate a gear joint. +proc AllocGearJoint*(): PGearJoint{. + cdecl, importc: "cpGearJointAlloc", dynlib: Lib.} +#/ Initialize a gear joint. +proc init*(joint: PGearJoint; a, b: PBody, phase, ratio: CpFloat): PGearJoint{. + cdecl, importc: "cpGearJointInit", dynlib: Lib.} +#/ Allocate and initialize a gear joint. +proc NewGearJoint*(a, b: PBody; phase, ratio: CpFloat): PConstraint{. + cdecl, importc: "cpGearJointNew", dynlib: Lib.} + +defCProp(GearJoint, CpFloat, phase, Phase) +defCGetter(GearJoint, CpFloat, ratio, Ratio) +#/ Set the ratio of a gear joint. +proc GearJointSetRatio*(constraint: PConstraint; value: CpFloat){. + cdecl, importc: "cpGearJointSetRatio", dynlib: Lib.} + + +proc SimpleMotorGetClass*(): PConstraintClass{. + cdecl, importc: "cpSimpleMotorGetClass", dynlib: Lib.} +#/ Allocate a simple motor. +proc AllocSimpleMotor*(): PSimpleMotor{. + cdecl, importc: "cpSimpleMotorAlloc", dynlib: Lib.} +#/ initialize a simple motor. +proc init*(joint: PSimpleMotor; a, b: PBody; + rate: CpFloat): PSimpleMotor{. + cdecl, importc: "cpSimpleMotorInit", dynlib: Lib.} +#/ Allocate and initialize a simple motor. +proc newSimpleMotor*(a, b: PBody; rate: CpFloat): PConstraint{. + cdecl, importc: "cpSimpleMotorNew", dynlib: Lib.} + +defCProp(SimpleMotor, CpFloat, rate, Rate) + + + diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim new file mode 100644 index 000000000..ad43c69b7 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim @@ -0,0 +1,614 @@ +discard """Copyright (c) 2002-2012 Lee Salzman + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" +when defined(Linux): + const Lib = "libenet.so.1(|.0.3)" +else: + {.error: "Your platform has not been accounted for."} +{.deadCodeElim: ON.} +const + ENET_VERSION_MAJOR* = 1 + ENET_VERSION_MINOR* = 3 + ENET_VERSION_PATCH* = 3 +template ENET_VERSION_CREATE(major, minor, patch: expr): expr = + (((major) shl 16) or ((minor) shl 8) or (patch)) + +const + ENET_VERSION* = ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, + ENET_VERSION_PATCH) +type + TVersion* = cuint + TSocketType*{.size: sizeof(cint).} = enum + ENET_SOCKET_TYPE_STREAM = 1, ENET_SOCKET_TYPE_DATAGRAM = 2 + TSocketWait*{.size: sizeof(cint).} = enum + ENET_SOCKET_WAIT_NONE = 0, ENET_SOCKET_WAIT_SEND = (1 shl 0), + ENET_SOCKET_WAIT_RECEIVE = (1 shl 1) + TSocketOption*{.size: sizeof(cint).} = enum + ENET_SOCKOPT_NONBLOCK = 1, ENET_SOCKOPT_BROADCAST = 2, + ENET_SOCKOPT_RCVBUF = 3, ENET_SOCKOPT_SNDBUF = 4, + ENET_SOCKOPT_REUSEADDR = 5 +const + ENET_HOST_ANY* = 0 + ENET_HOST_BROADCAST* = 0xFFFFFFFF + ENET_PORT_ANY* = 0 + + ENET_PROTOCOL_MINIMUM_MTU* = 576 + ENET_PROTOCOL_MAXIMUM_MTU* = 4096 + ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS* = 32 + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE* = 4096 + ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE* = 32768 + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT* = 1 + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT* = 255 + ENET_PROTOCOL_MAXIMUM_PEER_ID* = 0x00000FFF +type + PAddress* = ptr TAddress + TAddress*{.pure, final.} = object + host*: cuint + port*: cushort + + TPacketFlag*{.size: sizeof(cint).} = enum + FlagReliable = (1 shl 0), + FlagUnsequenced = (1 shl 1), + NoAllocate = (1 shl 2), + UnreliableFragment = (1 shl 3) + + TENetListNode*{.pure, final.} = object + next*: ptr T_ENetListNode + previous*: ptr T_ENetListNode + + PENetListIterator* = ptr TENetListNode + TENetList*{.pure, final.} = object + sentinel*: TENetListNode + + T_ENetPacket*{.pure, final.} = object + TPacketFreeCallback* = proc (a2: ptr T_ENetPacket){.cdecl.} + + PPacket* = ptr TPacket + TPacket*{.pure, final.} = object + referenceCount: csize + flags*: cint + data*: cstring#ptr cuchar + dataLength*: csize + freeCallback*: TPacketFreeCallback + + PAcknowledgement* = ptr TAcknowledgement + TAcknowledgement*{.pure, final.} = object + acknowledgementList*: TEnetListNode + sentTime*: cuint + command*: TEnetProtocol + + POutgoingCommand* = ptr TOutgoingCommand + TOutgoingCommand*{.pure, final.} = object + outgoingCommandList*: TEnetListNode + reliableSequenceNumber*: cushort + unreliableSequenceNumber*: cushort + sentTime*: cuint + roundTripTimeout*: cuint + roundTripTimeoutLimit*: cuint + fragmentOffset*: cuint + fragmentLength*: cushort + sendAttempts*: cushort + command*: TEnetProtocol + packet*: PPacket + + PIncomingCommand* = ptr TIncomingCommand + TIncomingCommand*{.pure, final.} = object + incomingCommandList*: TEnetListNode + reliableSequenceNumber*: cushort + unreliableSequenceNumber*: cushort + command*: TEnetProtocol + fragmentCount*: cuint + fragmentsRemaining*: cuint + fragments*: ptr cuint + packet*: ptr TPacket + + TPeerState*{.size: sizeof(cint).} = enum + ENET_PEER_STATE_DISCONNECTED = 0, ENET_PEER_STATE_CONNECTING = 1, + ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, + ENET_PEER_STATE_CONNECTION_PENDING = 3, + ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, ENET_PEER_STATE_CONNECTED = 5, + ENET_PEER_STATE_DISCONNECT_LATER = 6, ENET_PEER_STATE_DISCONNECTING = 7, + ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, ENET_PEER_STATE_ZOMBIE = 9 + + TENetProtocolCommand*{.size: sizeof(cint).} = enum + ENET_PROTOCOL_COMMAND_NONE = 0, ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, + ENET_PROTOCOL_COMMAND_CONNECT = 2, + ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, + ENET_PROTOCOL_COMMAND_DISCONNECT = 4, ENET_PROTOCOL_COMMAND_PING = 5, + ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, + ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, + ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, + ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, + ENET_PROTOCOL_COMMAND_COUNT = 13, ENET_PROTOCOL_COMMAND_MASK = 0x0000000F + TENetProtocolFlag*{.size: sizeof(cint).} = enum + ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12, + ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 shl 6), + ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 shl 7), + ENET_PROTOCOL_HEADER_SESSION_MASK = (3 shl 12), + ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 shl 14), + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 shl 15), + ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED.cint or + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME.cint + + TENetProtocolHeader*{.pure, final.} = object + peerID*: cushort + sentTime*: cushort + + TENetProtocolCommandHeader*{.pure, final.} = object + command*: cuchar + channelID*: cuchar + reliableSequenceNumber*: cushort + + TENetProtocolAcknowledge*{.pure, final.} = object + header*: TENetProtocolCommandHeader + receivedReliableSequenceNumber*: cushort + receivedSentTime*: cushort + + TENetProtocolConnect*{.pure, final.} = object + header*: TENetProtocolCommandHeader + outgoingPeerID*: cushort + incomingSessionID*: cuchar + outgoingSessionID*: cuchar + mtu*: cuint + windowSize*: cuint + channelCount*: cuint + incomingBandwidth*: cuint + outgoingBandwidth*: cuint + packetThrottleInterval*: cuint + packetThrottleAcceleration*: cuint + packetThrottleDeceleration*: cuint + connectID*: cuint + data*: cuint + + TENetProtocolVerifyConnect*{.pure, final.} = object + header*: TENetProtocolCommandHeader + outgoingPeerID*: cushort + incomingSessionID*: cuchar + outgoingSessionID*: cuchar + mtu*: cuint + windowSize*: cuint + channelCount*: cuint + incomingBandwidth*: cuint + outgoingBandwidth*: cuint + packetThrottleInterval*: cuint + packetThrottleAcceleration*: cuint + packetThrottleDeceleration*: cuint + connectID*: cuint + + TENetProtocolBandwidthLimit*{.pure, final.} = object + header*: TENetProtocolCommandHeader + incomingBandwidth*: cuint + outgoingBandwidth*: cuint + + TENetProtocolThrottleConfigure*{.pure, final.} = object + header*: TENetProtocolCommandHeader + packetThrottleInterval*: cuint + packetThrottleAcceleration*: cuint + packetThrottleDeceleration*: cuint + + TENetProtocolDisconnect*{.pure, final.} = object + header*: TENetProtocolCommandHeader + data*: cuint + + TENetProtocolPing*{.pure, final.} = object + header*: TENetProtocolCommandHeader + + TENetProtocolSendReliable*{.pure, final.} = object + header*: TENetProtocolCommandHeader + dataLength*: cushort + + TENetProtocolSendUnreliable*{.pure, final.} = object + header*: TENetProtocolCommandHeader + unreliableSequenceNumber*: cushort + dataLength*: cushort + + TENetProtocolSendUnsequenced*{.pure, final.} = object + header*: TENetProtocolCommandHeader + unsequencedGroup*: cushort + dataLength*: cushort + + TENetProtocolSendFragment*{.pure, final.} = object + header*: TENetProtocolCommandHeader + startSequenceNumber*: cushort + dataLength*: cushort + fragmentCount*: cuint + fragmentNumber*: cuint + totalLength*: cuint + fragmentOffset*: cuint + + ## this is incomplete; need helper templates or something + ## ENetProtocol + TENetProtocol*{.pure, final.} = object + header*: TENetProtocolCommandHeader +const + ENET_BUFFER_MAXIMUM* = (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) + ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024 + ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024 + ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000 + ENET_HOST_DEFAULT_MTU = 1400 + + ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500 + ENET_PEER_DEFAULT_PACKET_THROTTLE = 32 + ENET_PEER_PACKET_THROTTLE_SCALE = 32 + ENET_PEER_PACKET_THROTTLE_COUNTER = 7 + ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2 + ENET_PEER_PACKET_THROTTLE_DECELERATION = 2 + ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000 + ENET_PEER_PACKET_LOSS_SCALE = (1 shl 16) + ENET_PEER_PACKET_LOSS_INTERVAL = 10000 + ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024 + ENET_PEER_TIMEOUT_LIMIT = 32 + ENET_PEER_TIMEOUT_MINIMUM = 5000 + ENET_PEER_TIMEOUT_MAXIMUM = 30000 + ENET_PEER_PING_INTERVAL = 500 + ENET_PEER_UNSEQUENCED_WINDOWS = 64 + ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024 + ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32 + ENET_PEER_RELIABLE_WINDOWS = 16 + ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000 + ENET_PEER_FREE_RELIABLE_WINDOWS = 8 + +when defined(Linux): + import posix + const + ENET_SOCKET_NULL*: cint = -1 + type + TENetSocket* = cint + PEnetBuffer* = ptr object + TENetBuffer*{.pure, final.} = object + data*: pointer + dataLength*: csize + TENetSocketSet* = Tfd_set + ## see if these are different on win32, if not then get rid of these + template ENET_HOST_TO_NET_16*(value: expr): expr = + (htons(value)) + template ENET_HOST_TO_NET_32*(value: expr): expr = + (htonl(value)) + template ENET_NET_TO_HOST_16*(value: expr): expr = + (ntohs(value)) + template ENET_NET_TO_HOST_32*(value: expr): expr = + (ntohl(value)) + + template ENET_SOCKETSET_EMPTY*(sockset: expr): expr = + FD_ZERO(addr((sockset))) + template ENET_SOCKETSET_ADD*(sockset, socket: expr): expr = + FD_SET(socket, addr((sockset))) + template ENET_SOCKETSET_REMOVE*(sockset, socket: expr): expr = + FD_CLEAR(socket, addr((sockset))) + template ENET_SOCKETSET_CHECK*(sockset, socket: expr): expr = + FD_ISSET(socket, addr((sockset))) + +when defined(Windows): + ## put the content of win32.h in here + + +type + PChannel* = ptr TChannel + TChannel*{.pure, final.} = object + outgoingReliableSequenceNumber*: cushort + outgoingUnreliableSequenceNumber*: cushort + usedReliableWindows*: cushort + reliableWindows*: array[0..ENET_PEER_RELIABLE_WINDOWS - 1, cushort] + incomingReliableSequenceNumber*: cushort + incomingUnreliableSequenceNumber*: cushort + incomingReliableCommands*: TENetList + incomingUnreliableCommands*: TENetList + + PPeer* = ptr TPeer + TPeer*{.pure, final.} = object + dispatchList*: TEnetListNode + host*: ptr THost + outgoingPeerID*: cushort + incomingPeerID*: cushort + connectID*: cuint + outgoingSessionID*: cuchar + incomingSessionID*: cuchar + address*: TAddress + data*: pointer + state*: TPeerState + channels*: PChannel + channelCount*: csize + incomingBandwidth*: cuint + outgoingBandwidth*: cuint + incomingBandwidthThrottleEpoch*: cuint + outgoingBandwidthThrottleEpoch*: cuint + incomingDataTotal*: cuint + outgoingDataTotal*: cuint + lastSendTime*: cuint + lastReceiveTime*: cuint + nextTimeout*: cuint + earliestTimeout*: cuint + packetLossEpoch*: cuint + packetsSent*: cuint + packetsLost*: cuint + packetLoss*: cuint + packetLossVariance*: cuint + packetThrottle*: cuint + packetThrottleLimit*: cuint + packetThrottleCounter*: cuint + packetThrottleEpoch*: cuint + packetThrottleAcceleration*: cuint + packetThrottleDeceleration*: cuint + packetThrottleInterval*: cuint + lastRoundTripTime*: cuint + lowestRoundTripTime*: cuint + lastRoundTripTimeVariance*: cuint + highestRoundTripTimeVariance*: cuint + roundTripTime*: cuint + roundTripTimeVariance*: cuint + mtu*: cuint + windowSize*: cuint + reliableDataInTransit*: cuint + outgoingReliableSequenceNumber*: cushort + acknowledgements*: TENetList + sentReliableCommands*: TENetList + sentUnreliableCommands*: TENetList + outgoingReliableCommands*: TENetList + outgoingUnreliableCommands*: TENetList + dispatchedCommands*: TENetList + needsDispatch*: cint + incomingUnsequencedGroup*: cushort + outgoingUnsequencedGroup*: cushort + unsequencedWindow*: array[0..ENET_PEER_UNSEQUENCED_WINDOW_SIZE div 32 - 1, + cuint] + eventData*: cuint + + PCompressor* = ptr TCompressor + TCompressor*{.pure, final.} = object + context*: pointer + compress*: proc (context: pointer; inBuffers: ptr TEnetBuffer; + inBufferCount: csize; inLimit: csize; + outData: ptr cuchar; outLimit: csize): csize{.cdecl.} + decompress*: proc (context: pointer; inData: ptr cuchar; inLimit: csize; + outData: ptr cuchar; outLimit: csize): csize{.cdecl.} + destroy*: proc (context: pointer){.cdecl.} + + TChecksumCallback* = proc (buffers: ptr TEnetBuffer; bufferCount: csize): cuint{. + cdecl.} + + PHost* = ptr THost + THost*{.pure, final.} = object + socket*: TEnetSocket + address*: TAddress + incomingBandwidth*: cuint + outgoingBandwidth*: cuint + bandwidthThrottleEpoch*: cuint + mtu*: cuint + randomSeed*: cuint + recalculateBandwidthLimits*: cint + peers*: ptr TPeer + peerCount*: csize + channelLimit*: csize + serviceTime*: cuint + dispatchQueue*: TEnetList + continueSending*: cint + packetSize*: csize + headerFlags*: cushort + commands*: array[0..ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS - 1, + TEnetProtocol] + commandCount*: csize + buffers*: array[0..ENET_BUFFER_MAXIMUM - 1, TEnetBuffer] + bufferCount*: csize + checksum*: TChecksumCallback + compressor*: TCompressor + packetData*: array[0..ENET_PROTOCOL_MAXIMUM_MTU - 1, + array[0..2 - 1, cuchar]] + receivedAddress*: TAddress + receivedData*: ptr cuchar + receivedDataLength*: csize + totalSentData*: cuint + totalSentPackets*: cuint + totalReceivedData*: cuint + totalReceivedPackets*: cuint + + TEventType*{.size: sizeof(cint).} = enum + EvtNone = 0, EvtConnect = 1, + EvtDisconnect = 2, EvtReceive = 3 + PEvent* = ptr TEvent + TEvent*{.pure, final.} = object + kind*: TEventType + peer*: ptr TPeer + channelID*: cuchar + data*: cuint + packet*: ptr TPacket + + TENetCallbacks*{.pure, final.} = object + malloc*: proc (size: csize): pointer{.cdecl.} + free*: proc (memory: pointer){.cdecl.} + no_memory*: proc (){.cdecl.} + +{.push callConv:cdecl.} +proc enet_malloc*(a2: csize): pointer{. + importc: "enet_malloc", dynlib: Lib.} +proc enet_free*(a2: pointer){. + importc: "enet_free", dynlib: Lib.} + +proc enetInit*(): cint{. + importc: "enet_initialize", dynlib: Lib.} +proc enetInit*(version: TVersion; inits: ptr TENetCallbacks): cint{. + importc: "enet_initialize_with_callbacks", dynlib: Lib.} +proc enetDeinit*(){. + importc: "enet_deinitialize", dynlib: Lib.} +proc enet_time_get*(): cuint{. + importc: "enet_time_get", dynlib: Lib.} +proc enet_time_set*(a2: cuint){. + importc: "enet_time_set", dynlib: Lib.} + +#enet docs are pretty lacking, i'm not sure what the names of these arguments should be +proc createSocket*(kind: TSocketType): TEnetSocket{. + importc: "enet_socket_create", dynlib: Lib.} +proc bindTo*(socket: TEnetSocket; address: var TAddress): cint{. + importc: "enet_socket_bind", dynlib: Lib.} +proc bindTo*(socket: TEnetSocket; address: ptr TAddress): cint{. + importc: "enet_socket_bind", dynlib: Lib.} +proc listen*(socket: TEnetSocket; a3: cint): cint{. + importc: "enet_socket_listen", dynlib: Lib.} +proc accept*(socket: TEnetSocket; address: var TAddress): TEnetSocket{. + importc: "enet_socket_accept", dynlib: Lib.} +proc accept*(socket: TEnetSocket; address: ptr TAddress): TEnetSocket{. + importc: "enet_socket_accept", dynlib: Lib.} +proc connect*(socket: TEnetSocket; address: var TAddress): cint{. + importc: "enet_socket_connect", dynlib: Lib.} +proc connect*(socket: TEnetSocket; address: ptr TAddress): cint{. + importc: "enet_socket_connect", dynlib: Lib.} +proc send*(socket: TEnetSocket; address: var TAddress; buffer: ptr TEnetBuffer; size: csize): cint{. + importc: "enet_socket_send", dynlib: Lib.} +proc send*(socket: TEnetSocket; address: ptr TAddress; buffer: ptr TEnetBuffer; size: csize): cint{. + importc: "enet_socket_send", dynlib: Lib.} +proc receive*(socket: TEnetSocket; address: var TAddress; + buffer: ptr TEnetBuffer; size: csize): cint{. + importc: "enet_socket_receive", dynlib: Lib.} +proc receive*(socket: TEnetSocket; address: ptr TAddress; + buffer: ptr TEnetBuffer; size: csize): cint{. + importc: "enet_socket_receive", dynlib: Lib.} +proc wait*(socket: TEnetSocket; a3: ptr cuint; a4: cuint): cint{. + importc: "enet_socket_wait", dynlib: Lib.} +proc setOption*(socket: TEnetSocket; a3: TSocketOption; a4: cint): cint{. + importc: "enet_socket_set_option", dynlib: Lib.} +proc destroy*(socket: TEnetSocket){. + importc: "enet_socket_destroy", dynlib: Lib.} +proc select*(socket: TEnetSocket; a3: ptr TENetSocketSet; + a4: ptr TENetSocketSet; a5: cuint): cint{. + importc: "enet_socketset_select", dynlib: Lib.} + +proc setHost*(address: PAddress; hostName: cstring): cint{. + importc: "enet_address_set_host", dynlib: Lib.} +proc setHost*(address: var TAddress; hostName: cstring): cint{. + importc: "enet_address_set_host", dynlib: Lib.} +proc getHostIP*(address: var TAddress; hostName: cstring; nameLength: csize): cint{. + importc: "enet_address_get_host_ip", dynlib: Lib.} +proc getHost*(address: var TAddress; hostName: cstring; nameLength: csize): cint{. + importc: "enet_address_get_host", dynlib: Lib.} + +## Call the above two funcs but trim the result string +proc getHostIP*(address: var TAddress; hostName: var string; nameLength: csize): cint{.inline.} = + hostName.setLen nameLength + result = getHostIP(address, cstring(hostName), nameLength) + if result == 0: + hostName.setLen(len(cstring(hostName))) +proc getHost*(address: var TAddress; hostName: var string; nameLength: csize): cint{.inline.} = + hostName.setLen nameLength + result = getHost(address, cstring(hostName), nameLength) + if result == 0: + hostName.setLen(len(cstring(hostName))) + +proc createPacket*(data: pointer; len: csize; flag: TPacketFlag): PPacket{. + importc: "enet_packet_create", dynlib: Lib.} +proc destroy*(packet: PPacket){. + importc: "enet_packet_destroy", dynlib: Lib.} +proc resize*(packet: PPacket; dataLength: csize): cint{. + importc: "enet_packet_resize", dynlib: Lib.} + +proc crc32*(buffers: ptr TEnetBuffer; bufferCount: csize): cuint{. + importc: "enet_crc32", dynlib: Lib.} + +proc createHost*(address: ptr TAddress; maxConnections, maxChannels: csize; downSpeed, upSpeed: cuint): PHost{. + importc: "enet_host_create", dynlib: Lib.} +proc createHost*(address: var TAddress; maxConnections, maxChannels: csize; downSpeed, upSpeed: cuint): PHost{. + importc: "enet_host_create", dynlib: Lib.} +proc destroy*(host: PHost){. + importc: "enet_host_destroy", dynlib: Lib.} +proc connect*(host: PHost; address: ptr TAddress; channelCount: csize; data: cuint): PPeer{. + importc: "enet_host_connect", dynlib: Lib.} +proc connect*(host: PHost; address: var TAddress; channelCount: csize; data: cuint): PPeer{. + importc: "enet_host_connect", dynlib: Lib.} + +proc checkEvents*(host: PHost; event: var TEvent): cint{. + importc: "enet_host_check_events", dynlib: Lib.} +proc checkEvents*(host: PHost; event: ptr TEvent): cint{. + importc: "enet_host_check_events", dynlib: Lib.} +proc hostService*(host: PHost; event: var TEvent; timeout: cuint): cint{. + importc: "enet_host_service", dynlib: Lib.} +proc hostService*(host: PHost; event: ptr TEvent; timeout: cuint): cint{. + importc: "enet_host_service", dynlib: Lib.} +proc flush*(host: PHost){. + importc: "enet_host_flush", dynlib: Lib.} +proc broadcast*(host: PHost; channelID: cuchar; packet: PPacket){. + importc: "enet_host_broadcast", dynlib: Lib.} +proc compress*(host: PHost; compressor: PCompressor){. + importc: "enet_host_compress", dynlib: Lib.} +proc compressWithRangeCoder*(host: PHost): cint{. + importc: "enet_host_compress_with_range_coder", dynlib: Lib.} +proc channelLimit*(host: PHost; channelLimit: csize){. + importc: "enet_host_channel_limit", dynlib: Lib.} +proc bandwidthLimit*(host: PHost; incoming, outgoing: cuint){. + importc: "enet_host_bandwidth_limit", dynlib: Lib.} +proc bandwidthThrottle*(host: PHost){. + importc: "enet_host_bandwidth_throttle", dynlib: Lib.} + + +proc send*(peer: PPeer; channel: cuchar; packet: PPacket): cint{. + importc: "enet_peer_send", dynlib: Lib.} +proc receive*(peer: PPeer; channelID: ptr cuchar): PPacket{. + importc: "enet_peer_receive", dynlib: Lib.} +proc ping*(peer: PPeer){. + importc: "enet_peer_ping", dynlib: Lib.} +proc reset*(peer: PPeer){. + importc: "enet_peer_reset", dynlib: Lib.} +proc disconnect*(peer: PPeer; a3: cuint){. + importc: "enet_peer_disconnect", dynlib: Lib.} +proc disconnectNow*(peer: PPeer; a3: cuint){. + importc: "enet_peer_disconnect_now", dynlib: Lib.} +proc disconnectLater*(peer: PPeer; a3: cuint){. + importc: "enet_peer_disconnect_later", dynlib: Lib.} +proc throttleConfigure*(peer: PPeer; interval, acceleration, deceleration: cuint){. + importc: "enet_peer_throttle_configure", dynlib: Lib.} +proc throttle*(peer: PPeer; rtt: cuint): cint{. + importc: "enet_peer_throttle", dynlib: Lib.} +proc resetQueues*(peer: PPeer){. + importc: "enet_peer_reset_queues", dynlib: Lib.} +proc setupOutgoingCommand*(peer: PPeer; outgoingCommand: POutgoingCommand){. + importc: "enet_peer_setup_outgoing_command", dynlib: Lib.} + +proc queueOutgoingCommand*(peer: PPeer; command: ptr TEnetProtocol; + packet: PPacket; offset: cuint; length: cushort): POutgoingCommand{. + importc: "enet_peer_queue_outgoing_command", dynlib: Lib.} +proc queueIncomingCommand*(peer: PPeer; command: ptr TEnetProtocol; + packet: PPacket; fragmentCount: cuint): PIncomingCommand{. + importc: "enet_peer_queue_incoming_command", dynlib: Lib.} +proc queueAcknowledgement*(peer: PPeer; command: ptr TEnetProtocol; + sentTime: cushort): PAcknowledgement{. + importc: "enet_peer_queue_acknowledgement", dynlib: Lib.} +proc dispatchIncomingUnreliableCommands*(peer: PPeer; channel: PChannel){. + importc: "enet_peer_dispatch_incoming_unreliable_commands", dynlib: Lib.} +proc dispatchIncomingReliableCommands*(peer: PPeer; channel: PChannel){. + importc: "enet_peer_dispatch_incoming_reliable_commands", dynlib: Lib.} + +proc createRangeCoder*(): pointer{. + importc: "enet_range_coder_create", dynlib: Lib.} +proc rangeCoderDestroy*(context: pointer){. + importc: "enet_range_coder_destroy", dynlib: Lib.} +proc rangeCoderCompress*(context: pointer; inBuffers: PEnetBuffer; inLimit, + bufferCount: csize; outData: cstring; outLimit: csize): csize{. + importc: "enet_range_coder_compress", dynlib: Lib.} +proc rangeCoderDecompress*(context: pointer; inData: cstring; inLimit: csize; + outData: cstring; outLimit: csize): csize{. + importc: "enet_range_coder_decompress", dynlib: Lib.} +proc protocolCommandSize*(commandNumber: cuchar): csize{. + importc: "enet_protocol_command_size", dynlib: Lib.} + +{.pop.} + +from hashes import `!$`, `!&`, THash, hash +proc hash*(x: TAddress): THash {.nimcall, noSideEffect.} = + result = !$(hash(x.host.int32) !& hash(x.port.int16)) + diff --git a/tests/manyloc/keineschweine/dependencies/enet/testclient.nim b/tests/manyloc/keineschweine/dependencies/enet/testclient.nim new file mode 100644 index 000000000..2447a1fb5 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/enet/testclient.nim @@ -0,0 +1,49 @@ +import enet, strutils + +if enetInit() != 0: + quit "Could not initialize ENet" +var + address: enet.TAddress + event: TEvent + peer: PPeer + client: PHost + +client = createHost(nil, 1, 2, 0, 0) +if client == nil: + quit "Could not create client!" + +if setHost(addr address, "localhost") != 0: + quit "Could not set host" +address.port = 8024 + +peer = client.connect(addr address, 2, 0) +if peer == nil: + quit "No available peers" + +block: + var bConnected = false + while not bConnected: + if client.hostService(event, 5000) > 0 and event.kind == EvtConnect: + echo "Connected" + bConnected = true + else: + echo "Connection failed" + quit 0 + +var runServer = true +while client.hostService(event, 1000) >= 0 and runServer: + case event.kind + of EvtReceive: + echo "Recvd ($1) $2 ".format( + event.packet.dataLength, + event.packet.data) + of EvtDisconnect: + echo "Disconnected" + event.peer.data = nil + runServer = false + of EvtNone: discard + else: + echo repr(event) + + +client.destroy() diff --git a/tests/manyloc/keineschweine/dependencies/enet/testserver.nim b/tests/manyloc/keineschweine/dependencies/enet/testserver.nim new file mode 100644 index 000000000..28a6bd1f7 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/enet/testserver.nim @@ -0,0 +1,45 @@ +import enet, strutils +var + address: enet.TAddress + server: PHost + event: TEvent + +if enetInit() != 0: + quit "Could not initialize ENet" + +address.host = EnetHostAny +address.port = 8024 + +server = enet.createHost( + addr address, 32, 2, 0, 0) +if server == nil: + quit "Could not create the server!" + +while server.hostService(addr event, 2500) >= 0: + case event.kind + of EvtConnect: + echo "New client from $1:$2".format(event.peer.address.host, event.peer.address.port) + + var + msg = "hello" + resp = createPacket(cstring(msg), msg.len + 1, FlagReliable) + + if event.peer.send(0.cuchar, resp) < 0: + echo "FAILED" + else: + echo "Replied" + of EvtReceive: + echo "Recvd ($1) $2 ".format( + event.packet.dataLength, + event.packet.data) + + destroy(event.packet) + + of EvtDisconnect: + echo "Disconnected" + event.peer.data = nil + else: + discard + +server.destroy() +enetDeinit() \ No newline at end of file diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim new file mode 100644 index 000000000..ae9dfb39f --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim @@ -0,0 +1,295 @@ +import macros, macro_dsl, streams, streams_enh +from strutils import format + +template newLenName(): stmt {.immediate.} = + let lenName {.inject.} = ^("len"& $lenNames) + inc(lenNames) + +template defPacketImports*(): stmt {.immediate, dirty.} = + import macros, macro_dsl, streams, streams_enh + from strutils import format + +proc `$`*[T](x: seq[T]): string = + result = "[seq len=" + result.add($x.len) + result.add ':' + for i in 0.. <len(x): + result.add " " + result.add($x[i]) + result.add ']' + +macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = + result = newNimNode(nnkStmtList) + let + typeName = quoted2ident(typeNameN) + packetID = ^"p" + streamID = ^"s" + var + constructorParams = newNimNode(nnkFormalParams).und(typeName) + constructor = newNimNode(nnkProcDef).und( + postfix(^("new"& $typeName.ident), "*"), + emptyNode(), + emptyNode(), + constructorParams, + emptyNode(), + emptyNode()) + pack = newNimNode(nnkProcDef).und( + postfix(^"pack", "*"), + emptyNode(), + emptyNode(), + newNimNode(nnkFormalParams).und( + emptyNode(), # : void + newNimNode(nnkIdentDefs).und( + packetID, # p: var typeName + newNimNode(nnkVarTy).und(typeName), + emptyNode()), + newNimNode(nnkIdentDefs).und( + streamID, # s: PStream + ^"PStream", + newNimNode(nnkNilLit))), + emptyNode(), + emptyNode()) + read = newNimNode(nnkProcDef).und( + newIdentNode("read"& $typeName.ident).postfix("*"), + emptyNode(), + emptyNode(), + newNimNode(nnkFormalParams).und( + typeName, #result type + newNimNode(nnkIdentDefs).und( + streamID, # s: PStream = nil + ^"PStream", + newNimNode(nnkNilLit))), + emptyNode(), + emptyNode()) + constructorBody = newNimNode(nnkStmtList) + packBody = newNimNode(nnkStmtList) + readBody = newNimNode(nnkStmtList) + lenNames = 0 + for i in 0.. typeFields.len - 1: + let + name = typeFields[i][0] + dotName = packetID.dot(name) + resName = newIdentNode(!"result").dot(name) + case typeFields[i][1].kind + of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type] + case $typeFields[i][1][0].ident + of "paddedstring": + let length = typeFields[i][1][1] + let padChar = typeFields[i][1][2] + packBody.add(newCall( + "writePaddedStr", streamID, dotName, length, padChar)) + ## result.name = readPaddedStr(s, length, char) + readBody.add(resName := newCall( + "readPaddedStr", streamID, length, padChar)) + ## make the type a string + typeFields[i] = newNimNode(nnkIdentDefs).und( + name, + ^"string", + newNimNode(nnkEmpty)) + of "array": + readBody.add( + newNimNode(nnkDiscardStmt).und( + newCall("readData", streamID, newNimNode(nnkAddr).und(resName), newCall("sizeof", resName)))) + packBody.add( + newCall("writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName))) + of "seq": + ## let lenX = readInt16(s) + newLenName() + let + item = ^"item" ## item name in our iterators + seqType = typeFields[i][1][1] ## type of seq + readName = newIdentNode("read"& $seqType.ident) + readBody.add(newNimNode(nnkLetSection).und( + newNimNode(nnkIdentDefs).und( + lenName, + newNimNode(nnkEmpty), + newCall("readInt16", streamID)))) + readBody.add( ## result.name = @[] + resName := ("@".prefix(newNimNode(nnkBracket))), + newNimNode(nnkForStmt).und( ## for item in 1..len: + item, + infix(1.lit, "..", lenName), + newNimNode(nnkStmtList).und( + newCall( ## add(result.name, unpack[seqType](stream)) + "add", resName, newNimNode(nnkCall).und(readName, streamID) + ) ) ) ) + packbody.add( + newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und( + lenName, ## var lenName = int16(len(p.name)) + newIdentNode("int16"), + newCall("int16", newCall("len", dotName)))), + newCall("writeData", streamID, newNimNode(nnkAddr).und(lenName), 2.lit), + newNimNode(nnkForStmt).und( ## for item in 0..length - 1: pack(p.name[item], stream) + item, + infix(0.lit, "..", infix(lenName, "-", 1.lit)), + newNimNode(nnkStmtList).und( + newCall("echo", item, ": ".lit), + newCall("pack", dotName[item], streamID)))) + #set the default value to @[] (new sequence) + typeFields[i][2] = "@".prefix(newNimNode(nnkBracket)) + else: + error("Unknown type: "& treeRepr(typeFields[i])) + of nnkIdent: ##normal type + case $typeFields[i][1].ident + of "string": # length encoded string + packBody.add(newCall("writeLEStr", streamID, dotName)) + readBody.add(resName := newCall("readLEStr", streamID)) + of "int8", "int16", "int32", "float32", "float64", "char", "bool": + packBody.add(newCall( + "writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName))) + readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID)) + else: ## hopefully the type you specified was another defpacket() type + packBody.add(newCall("pack", dotName, streamID)) + readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID)) + else: + error("I dont know what to do with: "& treerepr(typeFields[i])) + + var + toStringFunc = newNimNode(nnkProcDef).und( + newNimNode(nnkPostfix).und( + ^"*", + newNimNode(nnkAccQuoted).und(^"$")), + emptyNode(), + emptyNode(), + newNimNode(nnkFormalParams).und( + ^"string", + newNimNode(nnkIdentDefs).und( + packetID, # p: typeName + typeName, + emptyNode())), + emptyNode(), + emptyNode(), + newNimNode(nnkStmtList).und(#[6] + newNimNode(nnkAsgn).und( + ^"result", ## result = + newNimNode(nnkCall).und(#[6][0][1] + ^"format", ## format + emptyNode())))) ## "[TypeName $1 $2]" + formatStr = "["& $typeName.ident + + const emptyFields = {nnkEmpty, nnkNilLit} + var objFields = newNimNode(nnkRecList) + for i in 0.. < len(typeFields): + let fname = typeFields[i][0] + constructorParams.add(newNimNode(nnkIdentDefs).und( + fname, + typeFields[i][1], + typeFields[i][2])) + constructorBody.add((^"result").dot(fname) := fname) + #export the name + typeFields[i][0] = fname.postfix("*") + if not(typeFields[i][2].kind in emptyFields): + ## empty the type default for the type def + typeFields[i][2] = newNimNode(nnkEmpty) + objFields.add(typeFields[i]) + toStringFunc[6][0][1].add( + prefix("$", packetID.dot(fname))) + formatStr.add " $" + formatStr.add($(i + 1)) + + formatStr.add ']' + toStringFunc[6][0][1][1] = formatStr.lit() + + result.add( + newNimNode(nnkTypeSection).und( + newNimNode(nnkTypeDef).und( + typeName.postfix("*"), + newNimNode(nnkEmpty), + newNimNode(nnkObjectTy).und( + newNimNode(nnkEmpty), #not sure what this is + newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj")) + objFields)))) + result.add(constructor.und(constructorBody)) + result.add(pack.und(packBody)) + result.add(read.und(readBody)) + result.add(toStringFunc) + when defined(GenPacketShowOutput): + echo(repr(result)) + +proc `->`(a: string, b: string): PNimrodNode {.compileTime.} = + result = newNimNode(nnkIdentDefs).und(^a, ^b, newNimNode(nnkEmpty)) +proc `->`(a: string, b: PNimrodNode): PNimrodNode {.compileTime.} = + result = newNimNode(nnkIdentDefs).und(^a, b, newNimNode(nnkEmpty)) +proc `->`(a, b: PNimrodNode): PNimrodNode {.compileTime.} = + a[2] = b + result = a + +proc newProc*(name: string, params: varargs[PNimrodNode], resultType: PNimrodNode): PNimrodNode {.compileTime.} = + result = newNimNode(nnkProcDef).und( + ^name, + emptyNode(), + emptyNode(), + newNimNode(nnkFormalParams).und(resultType), + emptyNode(), + emptyNode(), + newNimNode(nnkStmtList)) + result[3].add(params) +macro forwardPacket*(typeName: expr, underlyingType: typedesc): stmt {.immediate.} = + result = newNimNode(nnkStmtList).und( + newProc( + "read"& $typeName.ident, + ["s" -> "PStream" -> newNimNode(nnkNilLit)], + typeName), + newProc( + "pack", + [ "p" -> newNimNode(nnkVarTy).und(typeName), + "s" -> "PStream" -> newNimNode(nnkNilLit)], + emptyNode())) + result[0][6].add(newNimNode(nnkDiscardStmt).und( + newCall( + "readData", ^"s", newNimNode(nnkAddr).und(^"result"), newCall("sizeof", ^"result") + ))) + result[1][6].add( + newCall( + "writeData", ^"s", newNimNode(nnkAddr).und(^"p"), newCall( + "sizeof", ^"p"))) + when defined(GenPacketShowOutput): + echo(repr(result)) + +template forwardPacketT*(typeName: expr): stmt {.dirty, immediate.} = + proc `read typeName`*(s: PStream): typeName = + discard readData(s, addr result, sizeof(result)) + proc `pack typeName`*(p: var typeName; s: PStream) = + writeData(s, addr p, sizeof(p)) + +when isMainModule: + type + SomeEnum = enum + A = 0'i8, + B, C + forwardPacket(SomeEnum, int8) + + + defPacket(Foo, tuple[x: array[0..4, int8]]) + var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8]) + var s2 = newStringStream("") + f.pack(s2) + assert s2.data == "\4\3\2\1\0" + + var s = newStringStream() + s.flushImpl = proc(s: PStream) = + var z = PStringStream(s) + z.setPosition(0) + z.data.setLen(0) + + + s.setPosition(0) + s.data.setLen(0) + var o = B + o.pack(s) + o = A + o.pack(s) + o = C + o.pack(s) + assert s.data == "\1\0\2" + s.flush + + defPacket(Y, tuple[z: int8]) + proc `$`(z: Y): string = result = "Y("& $z.z &")" + defPacket(TestPkt, tuple[x: seq[Y]]) + var test = newTestPkt() + test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)]) + for itm in test.x: + echo(itm) + test.pack(s) + echo(repr(s.data)) \ No newline at end of file diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim new file mode 100644 index 000000000..44d00db53 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim @@ -0,0 +1,296 @@ +import macros, macro_dsl, estreams +from strutils import format + +template newLenName(): stmt {.immediate.} = + let lenName {.inject.} = ^("len"& $lenNames) + inc(lenNames) + +template defPacketImports*(): stmt {.immediate, dirty.} = + import macros, macro_dsl, estreams + from strutils import format + +proc `$`*[T](x: seq[T]): string = + result = "[seq len=" + result.add($x.len) + result.add ':' + for i in 0.. <len(x): + result.add " " + result.add($x[i]) + result.add ']' + +macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = + result = newNimNode(nnkStmtList) + let + typeName = quoted2ident(typeNameN) + packetID = ^"p" + streamID = ^"s" + var + constructorParams = newNimNode(nnkFormalParams).und(typeName) + constructor = newNimNode(nnkProcDef).und( + postfix(^("new"& $typeName.ident), "*"), + emptyNode(), + emptyNode(), + constructorParams, + emptyNode(), + emptyNode()) + pack = newNimNode(nnkProcDef).und( + postfix(^"pack", "*"), + emptyNode(), + emptyNode(), + newNimNode(nnkFormalParams).und( + emptyNode(), # : void + newNimNode(nnkIdentDefs).und( + streamID, # s: PBuffer + ^"PBuffer", + newNimNode(nnkNilLit)), + newNimNode(nnkIdentDefs).und( + packetID, # p: var typeName + newNimNode(nnkVarTy).und(typeName), + emptyNode())), + emptyNode(), + emptyNode()) + read = newNimNode(nnkProcDef).und( + newIdentNode("read"& $typeName.ident).postfix("*"), + emptyNode(), + emptyNode(), + newNimNode(nnkFormalParams).und( + typeName, #result type + newNimNode(nnkIdentDefs).und( + streamID, # s: PBuffer = nil + ^"PBuffer", + newNimNode(nnkNilLit))), + emptyNode(), + emptyNode()) + constructorBody = newNimNode(nnkStmtList) + packBody = newNimNode(nnkStmtList) + readBody = newNimNode(nnkStmtList) + lenNames = 0 + for i in 0.. typeFields.len - 1: + let + name = typeFields[i][0] + dotName = packetID.dot(name) + resName = newIdentNode(!"result").dot(name) + case typeFields[i][1].kind + of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type] + case $typeFields[i][1][0].ident + of "seq": + ## let lenX = readInt16(s) + newLenName() + let + item = ^"item" ## item name in our iterators + seqType = typeFields[i][1][1] ## type of seq + readName = newIdentNode("read"& $seqType.ident) + readBody.add(newNimNode(nnkLetSection).und( + newNimNode(nnkIdentDefs).und( + lenName, + newNimNode(nnkEmpty), + newCall("readInt16", streamID)))) + readBody.add( ## result.name = @[] + resName := ("@".prefix(newNimNode(nnkBracket))), + newNimNode(nnkForStmt).und( ## for item in 1..len: + item, + infix(1.lit, "..", lenName), + newNimNode(nnkStmtList).und( + newCall( ## add(result.name, unpack[seqType](stream)) + "add", resName, newNimNode(nnkCall).und(readName, streamID) + ) ) ) ) + packbody.add( + newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und( + lenName, ## var lenName = int16(len(p.name)) + newIdentNode("int16"), + newCall("int16", newCall("len", dotName)))), + newCall("writeBE", streamID, lenName), + newNimNode(nnkForStmt).und( ## for item in 0..length - 1: pack(p.name[item], stream) + item, + infix(0.lit, "..", infix(lenName, "-", 1.lit)), + newNimNode(nnkStmtList).und( + newCall("echo", item, ": ".lit), + newCall("pack", streamID, dotName[item])))) + #set the default value to @[] (new sequence) + typeFields[i][2] = "@".prefix(newNimNode(nnkBracket)) + else: + error("Unknown type: "& treeRepr(typeFields[i])) + of nnkIdent: ##normal type + case $typeFields[i][1].ident + of "string": # length encoded string + packBody.add(newCall("write", streamID, dotName)) + readBody.add(resName := newCall("readStr", streamID)) + of "int8", "int16", "int32", "float32", "float64", "char", "bool": + packBody.add(newCall( + "writeBE", streamID, dotName)) + readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID)) + else: ## hopefully the type you specified was another defpacket() type + packBody.add(newCall("pack", streamID, dotName)) + readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID)) + else: + error("I dont know what to do with: "& treerepr(typeFields[i])) + + var + toStringFunc = newNimNode(nnkProcDef).und( + newNimNode(nnkPostfix).und( + ^"*", + newNimNode(nnkAccQuoted).und(^"$")), + emptyNode(), + emptyNode(), + newNimNode(nnkFormalParams).und( + ^"string", + newNimNode(nnkIdentDefs).und( + packetID, # p: typeName + typeName, + emptyNode())), + emptyNode(), + emptyNode(), + newNimNode(nnkStmtList).und(#[6] + newNimNode(nnkAsgn).und( + ^"result", ## result = + newNimNode(nnkCall).und(#[6][0][1] + ^"format", ## format + emptyNode())))) ## "[TypeName $1 $2]" + formatStr = "["& $typeName.ident + + const emptyFields = {nnkEmpty, nnkNilLit} + var objFields = newNimNode(nnkRecList) + for i in 0.. < len(typeFields): + let fname = typeFields[i][0] + constructorParams.add(newNimNode(nnkIdentDefs).und( + fname, + typeFields[i][1], + typeFields[i][2])) + constructorBody.add((^"result").dot(fname) := fname) + #export the name + typeFields[i][0] = fname.postfix("*") + if not(typeFields[i][2].kind in emptyFields): + ## empty the type default for the type def + typeFields[i][2] = newNimNode(nnkEmpty) + objFields.add(typeFields[i]) + toStringFunc[6][0][1].add( + prefix("$", packetID.dot(fname))) + formatStr.add " $" + formatStr.add($(i + 1)) + + formatStr.add ']' + toStringFunc[6][0][1][1] = formatStr.lit() + + result.add( + newNimNode(nnkTypeSection).und( + newNimNode(nnkTypeDef).und( + typeName.postfix("*"), + newNimNode(nnkEmpty), + newNimNode(nnkObjectTy).und( + newNimNode(nnkEmpty), #not sure what this is + newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj")) + objFields)))) + result.add(constructor.und(constructorBody)) + result.add(pack.und(packBody)) + result.add(read.und(readBody)) + result.add(toStringFunc) + when defined(GenPacketShowOutput): + echo(repr(result)) + +proc newProc*(name: PNimrodNode; params: varargs[PNimrodNode]; resultType: PNimrodNode): PNimrodNode {.compileTime.} = + result = newNimNode(nnkProcDef).und( + name, + emptyNode(), + emptyNode(), + newNimNode(nnkFormalParams).und(resultType), + emptyNode(), + emptyNode(), + newNimNode(nnkStmtList)) + result[3].add(params) + +proc body*(procNode: PNimrodNode): PNimrodNode {.compileTime.} = + assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList + result = procNode[6] + +proc iddefs*(a, b: string; c: PNimrodNode): PNimrodNode {.compileTime.} = + result = newNimNode(nnkIdentDefs).und(^a, ^b, c) +proc iddefs*(a: string; b: PNimrodNode): PNimrodNode {.compileTime.} = + result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode()) +proc varTy*(a: PNimrodNode): PNimrodNode {.compileTime.} = + result = newNimNode(nnkVarTy).und(a) + +macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} = + var + packetID = ^"p" + streamID = ^"s" + result = newNimNode(nnkStmtList).und( + newProc( + (^("read"& $typeName.ident)).postfix("*"), + [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ], + typeName), + newProc( + (^"pack").postfix("*"), + [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)), + iddefs("p", varTy(typeName)) ], + emptyNode())) + var + readBody = result[0][6] + packBody = result[1][6] + resName = ^"result" + + case underlyingType.kind + of nnkBracketExpr: + case $underlyingType[0].ident + of "array": + for i in underlyingType[1][1].intval.int .. underlyingType[1][2].intval.int: + readBody.add( + newCall("read", ^"s", resName[lit(i)])) + packBody.add( + newCall("writeBE", ^"s", packetID[lit(i)])) + else: + echo "Unknown type: ", repr(underlyingtype) + else: + echo "unknown type:", repr(underlyingtype) + echo(repr(result)) + +template forwardPacketT*(typeName: expr; underlyingType: expr): stmt {.dirty, immediate.} = + proc `read typeName`*(buffer: PBuffer): typeName = + #discard readData(s, addr result, sizeof(result)) + var res: underlyingType + buffer.read(res) + result = typeName(res) + proc `pack`*(buffer: PBuffer; ord: var typeName) = + #writeData(s, addr p, sizeof(p)) + buffer.write(underlyingType(ord)) + +when isMainModule: + type + SomeEnum = enum + A = 0'i8, + B, C + forwardPacket(SomeEnum, int8) + + + defPacket(Foo, tuple[x: array[0..4, int8]]) + var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8]) + var s2 = newStringStream("") + f.pack(s2) + assert s2.data == "\4\3\2\1\0" + + var s = newStringStream() + s.flushImpl = proc(s: PStream) = + var z = PStringStream(s) + z.setPosition(0) + z.data.setLen(0) + + + s.setPosition(0) + s.data.setLen(0) + var o = B + o.pack(s) + o = A + o.pack(s) + o = C + o.pack(s) + assert s.data == "\1\0\2" + s.flush + + defPacket(Y, tuple[z: int8]) + proc `$`(z: Y): string = result = "Y("& $z.z &")" + defPacket(TestPkt, tuple[x: seq[Y]]) + var test = newTestPkt() + test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)]) + for itm in test.x: + echo(itm) + test.pack(s) + echo(repr(s.data)) \ No newline at end of file diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim new file mode 100644 index 000000000..cbae1334e --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim @@ -0,0 +1,73 @@ +import macros +{.deadCodeElim: on.} +#Inline macro.add() to allow for easier nesting +proc und*(a: PNimrodNode; b: PNimrodNode): PNimrodNode {.compileTime.} = + a.add(b) + result = a +proc und*(a: PNimrodNode; b: varargs[PNimrodNode]): PNimrodNode {.compileTime.} = + a.add(b) + result = a + +proc `^`*(a: string): PNimrodNode {.compileTime.} = + ## new ident node + result = newIdentNode(!a) +proc `[]`*(a, b: PNimrodNode): PNimrodNode {.compileTime.} = + ## new bracket expression: node[node] not to be confused with node[indx] + result = newNimNode(nnkBracketExpr).und(a, b) +proc `:=`*(left, right: PNimrodNode): PNimrodNode {.compileTime.} = + ## new Asgn node: left = right + result = newNimNode(nnkAsgn).und(left, right) + +proc lit*(a: string): PNimrodNode {.compileTime.} = + result = newStrLitNode(a) +proc lit*(a: int): PNimrodNode {.compileTime.} = + result = newIntLitNode(a) +proc lit*(a: float): PNimrodNode {.compileTime.} = + result = newFloatLitNode(a) +proc lit*(a: char): PNimrodNode {.compileTime.} = + result = newNimNode(nnkCharLit) + result.intval = a.ord + +proc emptyNode*(): PNimrodNode {.compileTime.} = + result = newNimNode(nnkEmpty) + +proc dot*(left, right: PNimrodNode): PNimrodNode {.compileTime.} = + result = newNimNode(nnkDotExpr).und(left, right) +proc postfix*(a: PNimrodNode, b: string): PNimrodNode {.compileTime.} = + result = newNimNode(nnkPostfix).und(newIdentNode(!b), a) +proc prefix*(a: string, b: PNimrodNode): PNimrodNode {.compileTime.} = + result = newNimNode(nnkPrefix).und(newIdentNode(!a), b) + +proc infix*(a, b, c: PNimrodNode): PNimrodNode {.compileTime.} = + ## 5.infix("+", 10) ## => 5 + 10 + result = newNimNode(nnkInfix).und(b, a, c) +proc infix*(a: PNimrodNode; b: string; c: PNimrodNode): PNimrodNode {.compileTime.} = + ## Infix operation: infix(5, "+", 10) ## => + result = newNimNode(nnkInfix).und(newIdentNode(b), a, c) + +proc quoted2ident*(a: PNimrodNode): PNimrodNode {.compileTime.} = + if a.kind != nnkAccQuoted: + return a + var pname = "" + for piece in 0..a.len - 1: + pname.add($a[piece].ident) + result = ^pname + + +macro `?`(a: expr): expr = + ## Character literal ?A #=> 'A' + result = ($a[1].ident)[0].lit +## echo(?F,?a,?t,?t,?y) + +when isMainModule: + macro foo(x: stmt): stmt = + result = newNimNode(nnkStmtList) + result.add(newNimNode(nnkCall).und(!!"echo", "Hello thar".lit)) + result.add(newCall("echo", lit("3 * 45 = "), (3.lit.infix("*", 45.lit)))) + let stmtlist = x[1] + for i in countdown(len(stmtlist)-1, 0): + result.add(stmtlist[i]) + foo: + echo y, " * 2 = ", y * 2 + let y = 320 + diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim new file mode 100644 index 000000000..a9759687f --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim @@ -0,0 +1,47 @@ +import streams +from strutils import repeatChar + +proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString = + var lastChr = length + result = s.readStr(length) + while lastChr >= 0 and result[lastChr - 1] == padChar: dec(lastChr) + result.setLen(lastChr) + +proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') = + if str.len < length: + s.write(str) + s.write(repeatChar(length - str.len, padChar)) + elif str.len > length: + s.write(str.substr(0, length - 1)) + else: + s.write(str) + +proc readLEStr*(s: PStream): TaintedString = + var len = s.readInt16() + result = s.readStr(len) + +proc writeLEStr*(s: PStream, str: string) = + s.write(str.len.int16) + s.write(str) + +when isMainModule: + var testStream = newStringStream() + + testStream.writeLEStr("Hello") + doAssert testStream.data == "\5\0Hello" + + testStream.setPosition 0 + var res = testStream.readLEStr() + doAssert res == "Hello" + + testStream.setPosition 0 + testStream.writePaddedStr("Sup", 10) + echo(repr(testStream), testStream.data.len) + doAssert testStream.data == "Sup"&repeatChar(7, '\0') + + testStream.setPosition 0 + res = testStream.readPaddedStr(10) + doAssert res == "Sup" + + testStream.close() + diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim new file mode 100644 index 000000000..eade28c70 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim @@ -0,0 +1,83 @@ +discard """ +DO AS THOU WILST PUBLIC LICENSE + +Whoever should stumble upon this document is henceforth and forever +entitled to DO AS THOU WILST with aforementioned document and the +contents thereof. + +As said in the Olde Country, `Keepe it Gangster'.""" + +import strutils, parseopt, tables, os + +type + PTask* = ref object + desc*: string + action*: TTaskFunction + TTaskFunction* = proc() {.closure.} +var + tasks* = initTable[string, PTask](16) + +proc newTask*(desc: string; action: TTaskFunction): PTask +proc runTask*(name: string) {.inline.} +proc shell*(cmd: varargs[string, `$`]): int {.discardable.} +proc cd*(dir: string) {.inline.} + +template nakeImports*(): stmt {.immediate.} = + import tables, parseopt, strutils, os + +template task*(name: string; description: string; body: stmt): stmt {.dirty, immediate.} = + block: + var t = newTask(description, proc() {.closure.} = + body) + tasks[name] = t + +proc newTask*(desc: string; action: TTaskFunction): PTask = + new(result) + result.desc = desc + result.action = action +proc runTask*(name: string) = tasks[name].action() + +proc shell*(cmd: varargs[string, `$`]): int = + result = execShellCmd(cmd.join(" ")) +proc cd*(dir: string) = setCurrentDir(dir) +template withDir*(dir: string; body: stmt): stmt = + ## temporary cd + ## withDir "foo": + ## # inside foo + ## #back to last dir + var curDir = getCurrentDir() + cd(dir) + body + cd(curDir) + +when isMainModule: + if not existsFile("nakefile.nim"): + echo "No nakefile.nim found. Current working dir is ", getCurrentDir() + quit 1 + var args = "" + for i in 1..paramCount(): + args.add paramStr(i) + args.add " " + quit(shell("nimrod", "c", "-r", "nakefile.nim", args)) +else: + addQuitProc(proc() {.noconv.} = + var + task: string + printTaskList: bool + for kind, key, val in getOpt(): + case kind + of cmdLongOption, cmdShortOption: + case key.tolower + of "tasks", "t": + printTaskList = true + else: + echo "Unknown option: ", key, ": ", val + of cmdArgument: + task = key + else: nil + if printTaskList or task.isNil or not(tasks.hasKey(task)): + echo "Available tasks:" + for name, task in pairs(tasks): + echo name, " - ", task.desc + quit 0 + tasks[task].action()) diff --git a/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim new file mode 100644 index 000000000..24af63d10 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim @@ -0,0 +1,23 @@ +import nake +nakeImports + +task "install", "compile and install nake binary": + if shell("nimrod", "c", "nake") == 0: + let path = getEnv("PATH").split(PathSep) + for index, dir in pairs(path): + echo " ", index, ". ", dir + echo "Where to install nake binary? (quit with ^C or quit or exit)" + let ans = stdin.readLine().toLower + var index = 0 + case ans + of "q", "quit", "x", "exit": + quit 0 + else: + index = parseInt(ans) + if index > path.len or index < 0: + echo "Invalid index." + quit 1 + moveFile "nake", path[index]/"nake" + echo "Great success!" + + diff --git a/tests/manyloc/keineschweine/dependencies/sfml/README.md b/tests/manyloc/keineschweine/dependencies/sfml/README.md new file mode 100644 index 000000000..bd9b3d0e7 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/sfml/README.md @@ -0,0 +1,13 @@ +sfml-nimrod +=========== + +Nimrod binding of SFML 2.0 + +This is only tested for Linux at the moment + +### What is needed for Windows / OS X? + +* The library names need filling in +* TWindowHandle is handled differently on those platforms + +I believe that is it diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim new file mode 100644 index 000000000..27163e271 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim @@ -0,0 +1,1115 @@ +import + strutils, math +when defined(linux): + const + LibG = "libcsfml-graphics.so.2.0" + LibS = "libcsfml-system.so.2.0" + LibW = "libcsfml-window.so.2.0" +else: + {.error: "Platform unsupported".} +{.deadCodeElim: on.} +{.pragma: pf, pure, final.} +type + PClock* = ptr TClock + TClock* {.pf.} = object + TTime* {.pf.} = object + microseconds*: int64 + TVector2i* {.pf.} = object + x*, y*: cint + TVector2f* {.pf.} = object + x*, y*: cfloat + TVector3f* {.pf.} = object + x*, y*, z*: cfloat + + PInputStream* = ptr TInputStream + TInputStream* {.pf.} = object + read*: TInputStreamReadFunc + seek*: TInputStreamSeekFunc + tell*: TInputStreamTellFunc + getSize*: TInputStreamGetSizeFunc + userData*: pointer + TInputStreamReadFunc* = proc (data: pointer, size: int64, userData: pointer): int64{. + cdecl.} + TInputStreamSeekFunc* = proc (position: int16, userData: pointer): int64{. + cdecl.} + TInputStreamTellFunc* = proc (userData: pointer): int64 {.cdecl.} + TInputStreamGetSizeFunc* = proc (userData: pointer): int64 {.cdecl.} + PWindow* = ptr TWindow + TWindow* {.pf.} = object + PContextSettings* = ptr TContextSettings + TContextSettings*{.pf.} = object + depthBits: cint + stencilBits: cint + antialiasingLevel: cint + majorVersion: cint + minorVersion: cint + TVideoMode* {.pf.} = object + width*: cint + height*: cint + bitsPerPixel*: cint + TEventType*{.size: sizeof(cint).} = enum + EvtClosed, EvtResized, EvtLostFocus, EvtGainedFocus, + EvtTextEntered, EvtKeyPressed, EvtKeyReleased, EvtMouseWheelMoved, + EvtMouseButtonPressed, EvtMouseButtonReleased, EvtMouseMoved, + EvtMouseEntered, EvtMouseLeft, EvtJoystickButtonPressed, + EvtJoystickButtonReleased, EvtJoystickMoved, EvtJoystickConnected, + EvtJoystickDisconnected + TKeyEvent*{.pf.} = object + code*: TKeyCode + alt* : bool + control*: bool + shift* : bool + system* : bool + TJoystickConnectEvent*{.pf.} = object + joystickId*: cint + TJoystickButtonEvent*{.pf.} = object + joystickId*: cint + button*: cint + TJoystickMoveEvent*{.pf.} = object + joystickId*: cint + axis*: TJoystickAxis + position*: cfloat + TMouseWheelEvent*{.pf.} = object + delta*: cint + x*: cint + y*: cint + TMouseButtonEvent*{.pf.} = object + button*: TMouseButton + x*: cint + y*: cint + TMouseMoveEvent*{.pf.} = object + x*: cint + y*: cint + TTextEvent*{.pf.} = object + unicode*: cint + PEvent* = ptr TEvent + TEvent*{.pf.} = object + case kind*: TEventType + of EvtKeyPressed, EvtKeyReleased: + key*: TKeyEvent + of EvtMouseButtonPressed, EvtMouseButtonReleased: + mouseButton*: TMouseButtonEvent + of EvtTextEntered: + text*: TTextEvent + of EvtJoystickConnected, EvtJoystickDisconnected: + joystickConnect*: TJoystickConnectEvent + of EvtJoystickMoved: + joystickMove*: TJoystickMoveEvent + of EvtJoystickButtonPressed, EvtJoystickButtonReleased: + joystickButton*: TJoystickButtonEvent + of EvtResized: + size*: TSizeEvent + of EvtMouseMoved, EvtMouseEntered, EvtMouseLeft: + mouseMove*: TMouseMoveEvent + of EvtMouseWheelMoved: + mouseWheel*: TMouseWheelEvent + else: nil + TJoystickAxis*{.size: sizeof(cint).} = enum + JoystickX, JoystickY, JoystickZ, JoystickR, + JoystickU, JoystickV, JoystickPovX, JoystickPovY + TSizeEvent*{.pf.} = object + width*: cint + height*: cint + TMouseButton*{.size: sizeof(cint).} = enum + MouseLeft, MouseRight, MouseMiddle, + MouseXButton1, MouseXButton2, MouseButtonCount + TKeyCode*{.size: sizeof(cint).} = enum + KeyUnknown = - 1, KeyA, KeyB, KeyC, KeyD, KeyE, + KeyF, KeyG, KeyH, KeyI, KeyJ, KeyK, KeyL, KeyM, #/< The M key + KeyN, KeyO, KeyP, KeyQ, KeyR, KeyS, KeyT, KeyU, #/< The U key + KeyV, KeyW, KeyX, KeyY, KeyZ, KeyNum0, KeyNum1, #/< The 1 key + KeyNum2, KeyNum3, KeyNum4, KeyNum5, KeyNum6, #/< The 6 key + KeyNum7, KeyNum8, KeyNum9, KeyEscape, KeyLControl, #/< The left Control key + KeyLShift, KeyLAlt, KeyLSystem, KeyRControl, #/< The right Control key + KeyRShift, KeyRAlt, KeyRSystem, KeyMenu, #/< The Menu key + KeyLBracket, KeyRBracket, KeySemiColon, KeyComma, #/< The , key + KeyPeriod, KeyQuote, KeySlash, KeyBackSlash, #/< The \ key + KeyTilde, KeyEqual, KeyDash, KeySpace, KeyReturn, #/< The Return key + KeyBack, KeyTab, KeyPageUp, KeyPageDown, KeyEnd, #/< The End key + KeyHome, KeyInsert, KeyDelete, KeyAdd, KeySubtract, #/< - + KeyMultiply, KeyDivide, KeyLeft, KeyRight, KeyUp, #/< Up arrow + KeyDown, KeyNumpad0, KeyNumpad1, KeyNumpad2, #/< The numpad 2 key + KeyNumpad3, #/< The numpad 3 key + KeyNumpad4, #/< The numpad 4 key + KeyNumpad5, #/< The numpad 5 key + KeyNumpad6, #/< The numpad 6 key + KeyNumpad7, #/< The numpad 7 key + KeyNumpad8, #/< The numpad 8 key + KeyNumpad9, #/< The numpad 9 key + KeyF1, #/< The F1 key + KeyF2, #/< The F2 key + KeyF3, #/< The F3 key + KeyF4, #/< The F4 key + KeyF5, #/< The F5 key + KeyF6, #/< The F6 key + KeyF7, #/< The F7 key + KeyF8, #/< The F8 key + KeyF9, #/< The F8 key + KeyF10, #/< The F10 key + KeyF11, #/< The F11 key + KeyF12, #/< The F12 key + KeyF13, #/< The F13 key + KeyF14, #/< The F14 key + KeyF15, #/< The F15 key + KeyPause, #/< The Pause key + KeyCount #/< Keep last -- the total number of keyboard keys +when defined(linux): #or defined(bsd) ?? + type TWindowHandle* = clong +#elif defined(mac): +# type TWindowHandle* = pointer ##typedef void* sfWindowHandle; <- whatever the hell that is +#elif defined(windows): +# type TWindowHandle* = HWND__ ? windows is crazy. ##struct HWND__; typedef struct HWND__* sfWindowHandle; +const + sfNone* = 0 + sfTitlebar* = 1 shl 0 + sfResize* = 1 shl 1 + sfClose* = 1 shl 2 + sfFullscreen* = 1 shl 3 + sfDefaultStyle* = sfTitlebar or sfResize or sfClose +type + PRenderWindow* = ptr TRenderWindow + TRenderWindow* {.pf.} = object + + PFont* = ptr TFont + TFont* {.pf.} = object + PImage* = ptr TImage + TImage* {.pf.} = object + PShader* = ptr TShader + TShader* {.pf.} = object + PSprite* = ptr TSprite + TSprite* {.pf.} = object + PText* = ptr TText + TText* {.pf.} = object + PTexture* = ptr TTexture + TTexture* {.pf.} = object + PVertexArray* = ptr TVertexArray + TVertexArray* {.pf.} = object + PView* = ptr TView + TView* {.pf.} = object + PRenderTexture* = ptr TRenderTexture + TRenderTexture* {.pf.} = object + + PShape* = ptr TShape + TShape* {.pf.} = object + PCircleShape* = ptr TCircleShape + TCircleShape* {.pf.} = object + PRectangleShape* = ptr TRectangleShape + TRectangleShape* {.pf.} = object + PConvexShape* = ptr TConvexShape + TConvexShape* {.pf.} = object + + TTextStyle*{.size: sizeof(cint).} = enum + TextRegular = 0, TextBold = 1 shl 0, TextItalic = 1 shl 1, + TextUnderlined = 1 shl 2 + + TBlendMode*{.size: sizeof(cint).} = enum + BlendAlpha, BlendAdd, BlendMultiply, BlendNone + PRenderStates* = ptr TRenderStates + TRenderStates* {.pf.} = object + blendMode*: TBlendMode + transform*: TTransform + texture*: PTexture + shader*: PShader + + PTransform* = ptr TTransform + TTransform* {.pf.} = object + matrix*: array[0..8, cfloat] + TColor* {.pf.} = object + r*: Uint8 + g*: Uint8 + b*: Uint8 + a*: Uint8 + PFloatRect* = ptr TFloatRect + TFloatRect*{.pf.} = object + left*: cfloat + top*: cfloat + width*: cfloat + height*: cfloat + PIntRect* = ptr TIntRect + TIntRect*{.pf.} = object + left*: cint + top*: cint + width*: cint + height*: cint + TGlyph* {.pf.} = object + advance*: cint + bounds*: TIntRect + textureRect*: TIntRect + PVertex* = ptr TVertex + TVertex* {.pf.} = object + position*: TVector2f + color*: TColor + texCoords*: TVector2f + TPrimitiveType*{.size: sizeof(cint).} = enum + Points, #/< List of individual points + Lines, #/< List of individual lines + LinesStrip, #/< List of connected lines, a point uses the previous point to form a line + Triangles, #/< List of individual triangles + TrianglesStrip, #/< List of connected triangles, a point uses the two previous points to form a triangle + TrianglesFan, #/< List of connected triangles, a point uses the common center and the previous point to form a triangle + Quads + + +proc newWindow*(mode: TVideoMode, title: cstring, style: uint32, settings: PContextSettings = nil): PWindow {. + cdecl, importc: "sfWindow_create", dynlib: LibW.} + +proc close*(window: PWindow) {. + cdecl, importc: "sfWindow_close", dynlib: LibW.} +proc isOpen*(window: PWindow): bool {.cdecl, importc: "sfWindow_isOpen", dynlib: LibW.} + +proc pollEvent*(window: PWindow, event: PEvent): bool {. + cdecl, importc: "sfWindow_pollEvent", dynlib: LibW.} +proc waitEvent*(window: PWindow, event: PEvent): bool {. + cdecl, importc: "sfWindow_waitEvent", dynlib: LibW.} + +proc getDesktopMode*(): TVideoMode {. + cdecl, importc: "sfVideoMode_getDesktopMode", dynlib: LibW.} +proc isKeyPressed*(key: TKeyCode): bool {. + cdecl, importc: "sfKeyboard_isKeyPressed", dynlib: LibW.} + +proc mouseIsButtonPressed*(button: TMouseButton): bool {. + cdecl, importc: "sfMouse_isButtonPressed", dynlib: LibW.} +proc mouseGetPosition*(relativeTo: PWindow): TVector2i {. + cdecl, importc: "sfMouse_getPosition", dynlib: LibW.} +proc mouseSetPosition*(position: TVector2i, relativeTo: PWindow) {. + cdecl, importc: "sfMouse_setPosition", dynlib: LibW.} + +proc joystickIsConnected*(joystick: cint): bool {. + cdecl, importc: "sfJoystick_isConnected", dynlib: LibW.} +proc joystickGetButtonCount*(joystick: cint): cint {. + cdecl, importc: "sfJoystick_getButtonCount", dynlib: LibW.} +proc joystickHasAxis*(joystick: cint, axis: TJoystickAxis): bool {. + cdecl, importc: "sfJoystick_hasAxis", dynlib: LibW.} +proc joystickIsButtonPressed*(joystick: cint, button: cint): bool {. + cdecl, importc: "sfJoystick_isButtonPressed", dynlib: LibW.} +proc joystickGetAxisPosition*(joystick: cint, axis: TJoystickAxis): float {. + cdecl, importc: "sfJoystick_getAxisPosition", dynlib: LibW.} +proc joystickUpdate*(): void {. + cdecl, importc: "sfJoystick_update", dynlib: LibW.} + + +proc newRenderWindow*(handle: TWindowHandle, settings: PContextSettings = nil): PRenderWindow{. + cdecl, importc: "sfRenderWindow_createFromHandle", dynlib: LibG.} +proc newRenderWindow*(mode: TVideoMode, title: cstring, style: int32, settings: PContextSettings = nil): PRenderWindow {. + cdecl, importc: "sfRenderWindow_create", dynlib: LibG.} + +proc destroy*(window: PRenderWindow) {. + cdecl, importc: "sfRenderWindow_destroy", dynlib: LibG.} +proc close*(window: PRenderWindow) {. + cdecl, importc: "sfRenderWindow_close", dynlib: LibG.} +proc isOpen*(window: PRenderWindow): bool {. + cdecl, importc: "sfRenderWindow_isOpen", dynlib: LibG.} + +#void sfRenderWindow_setIcon(sfRenderWindow* renderWindow, unsigned int width, unsigned int height, const sfUint8* pixels); +#proc setIcon*(window: PRenderWindow, width, height: cint, pixels: seq[uint8]) {. +# cdecl, importc: "sfRenderWindow_setIcon", dynlib: LibG.} + +proc getSettings*(window: PRenderWindow): TContextSettings {. + cdecl, importc: "sfRenderWindow_getSettings", dynlib: LibG.} + +proc pollEvent*(window: PRenderWindow, event: PEvent): bool {. + cdecl, importc: "sfRenderWindow_pollEvent", dynlib: LibG.} +proc pollEvent*(window: PRenderWindow; event: var TEvent): bool {. + cdecl, importc: "sfRenderWindow_pollEvent", dynlib: LibG.} +proc waitEvent*(window: PRenderWindow, event: PEvent): bool {. + cdecl, importc: "sfRenderWindow_waitEvent", dynlib: LibG.} +proc waitEvent*(window: PRenderWindow, event: var TEvent): bool {. + cdecl, importc: "sfRenderWindow_waitEvent", dynlib: LibG.} +proc getPosition*(window: PRenderWindow): TVector2i {. + cdecl, importc: "sfRenderWindow_getPosition", dynlib: LibG.} +proc setPosition*(window: PRenderWindow, position: TVector2i) {. + cdecl, importc: "sfRenderWindow_setPosition", dynlib: LibG.} +proc getSize*(window: PRenderWindow): TVector2i {. + cdecl, importc: "sfRenderWindow_getSize", dynlib: LibG.} +proc setSize*(window: PRenderWindow, size: TVector2i): void {. + cdecl, importc: "sfRenderWindow_setSize", dynlib: LibG.} +proc setTitle*(window: PRenderWindow, title: cstring): void {. + cdecl, importc: "sfRenderWindow_setTitle", dynlib: LibG.} + +proc setVisible*(window: PRenderWindow, visible: bool) {. + cdecl, importc: "sfRenderWindow_setVisible", dynlib: LibG.} +proc setMouseCursorVisible*(window: PRenderWindow, show: bool) {. + cdecl, importc: "sfRenderWindow_setMouseCursorVisible", dynlib: LibG.} +proc setVerticalSyncEnabled*(window: PRenderWindow, enabled: bool) {. + cdecl, importc: "sfRenderWindow_setVerticalSyncEnabled", dynlib: LibG.} +proc setKeyRepeatEnabled*(window: PRenderWindow, enabled: bool) {. + cdecl, importc: "sfRenderWindow_setKeyRepeatEnabled", dynlib: LibG.} +proc setActive*(window: PRenderWindow, active: bool): bool {. + cdecl, importc: "sfRenderWindow_setActive", dynlib: LibG.} +proc display*(window: PRenderWindow) {. + cdecl, importc: "sfRenderWindow_display", dynlib: LibG.} +proc setFramerateLimit*(window: PRenderWindow, limit: uint) {. + cdecl, importc: "sfRenderWindow_setFramerateLimit", dynlib: LibG.} +proc setJoystickThreshold*(window: PRenderWindow, threshold: float) {. + cdecl, importc: "sfRenderWindow_setJoystickThreshold", dynlib: LibG.} +proc getSystemHandle*(window: PRenderWindow): TWindowHandle {. + cdecl, importc: "sfRenderWindow_getSystemHandle", dynlib: LibG.} + +proc clear*(window: PRenderWindow, color: TColor) {. + cdecl, importc: "sfRenderWindow_clear", dynlib: LibG.} + +proc setView*(window: PRenderWindow, view: PView) {. + cdecl, importc: "sfRenderWindow_setView", dynlib: LibG.} +proc getView*(window: PRenderWindow): PView {. + cdecl, importc: "sfRenderWindow_getView", dynlib: LibG.} +proc getDefaultView*(window: PRenderWindow): PView {. + cdecl, importc: "sfRenderWindow_getDefaultView", dynlib: LibG.} +proc getViewport*(window: PRenderWindow, view: PView): TIntRect {. + cdecl, importc: "sfRenderWindow_getViewport", dynlib: LibG.} + +proc convertCoords*(window: PRenderWindow, point: TVector2i, targetView: PView): TVector2f {. + cdecl, importc: "sfRenderWindow_convertCoords", dynlib: LibG.} + +proc draw*(window: PRenderWindow, sprite: PSprite, states: PRenderStates = nil) {. + cdecl, importc: "sfRenderWindow_drawSprite", dynlib: LibG.} +proc draw*(window: PRenderWindow, text: PText, states: PRenderStates = nil) {. + cdecl, importc: "sfRenderWindow_drawText", dynlib: LibG.} +proc draw*(window: PRenderWindow, shape: PShape, states: PRenderStates = nil) {. + cdecl, importc: "sfRenderWindow_drawShape", dynlib: LibG.} +proc draw*(window: PRenderWindow, shape: PCircleShape, states: PRenderStates = nil) {. + cdecl, importc: "sfRenderWindow_drawCircleShape", dynlib: LibG.} +proc draw*(window: PRenderWindow, shape: PRectangleShape, states: PRenderStates = nil) {. + cdecl, importc: "sfRenderWindow_drawRectangleShape", dynlib: LibG.} + +proc draw*(window: PRenderWindow, shape: PConvexShape, states: PRenderStates = nil) {. + cdecl, importc: "sfRenderWindow_drawConvexShape", dynlib: LibG.} +proc draw*(window: PRenderWindow, shape: PVertexArray, states: PRenderStates = nil) {. + cdecl, importc: "sfRenderWindow_drawVertexArray", dynlib: LibG.} +proc draw*(window: PRenderWindow, vertices: PVertex, vertexCount: cint, + vertexType: TPrimitiveType, states: PRenderStates = nil) {. + cdecl, importc: "sfRenderWindow_drawPrimitives", dynlib: LibG.} + +proc pushGlStates*(window: PRenderWindow) {. + cdecl, importc: "sfRenderWindow_pushGLStates", dynlib: LibG.} +proc popGlStates*(window: PRenderWindow) {. + cdecl, importc: "sfRenderWindow_popGLStates", dynlib: LibG.} +proc resetGlStates*(window: PRenderWindow) {. + cdecl, importc: "sfRenderWindow_resetGLStates", dynlib: LibG.} +proc capture*(window: PRenderWindow): PImage {. + cdecl, importc: "sfRenderWindow_capture", dynlib: LibG.} + +#Construct a new render texture +proc newRenderTexture*(width, height: cint; depthBuffer: Bool): PRenderTexture {. + cdecl, importc: "sfRenderTexture_create", dynlib: LibG.} +#Destroy an existing render texture +proc destroy*(renderTexture: PRenderTexture){. + cdecl, importc: "sfRenderTexture_destroy", dynlib: LibG.} +#Get the size of the rendering region of a render texture +proc getSize*(renderTexture: PRenderTexture): TVector2i {. + cdecl, importc: "sfRenderTexture_getSize", dynlib: LibG.} +#Activate or deactivate a render texture as the current target for rendering +proc setActive*(renderTexture: PRenderTexture; active: bool): bool{. + cdecl, importc: "sfRenderTexture_setActive", dynlib: LibG.} +#Update the contents of the target texture +proc display*(renderTexture: PRenderTexture){. + cdecl, importc: "sfRenderTexture_display", dynlib: LibG.} +#Clear the rendertexture with the given color +proc clear*(renderTexture: PRenderTexture; color: TColor){. + cdecl, importc: "sfRenderTexture_clear", dynlib: LibG.} +#Change the current active view of a render texture +proc setView*(renderTexture: PRenderTexture; view: PView){. + cdecl, importc: "sfRenderTexture_setView", dynlib: LibG.} +#Get the current active view of a render texture +proc getView*(renderTexture: PRenderTexture): PView{. + cdecl, importc: "sfRenderTexture_getView", dynlib: LibG.} +#Get the default view of a render texture +proc getDefaultView*(renderTexture: PRenderTexture): PView{. + cdecl, importc: "sfRenderTexture_getDefaultView", dynlib: LibG.} +#Get the viewport of a view applied to this target +proc getViewport*(renderTexture: PRenderTexture; view: PView): TIntRect{. + cdecl, importc: "sfRenderTexture_getViewport", dynlib: LibG.} +#Convert a point in texture coordinates into view coordinates +proc convertCoords*(renderTexture: PRenderTexture; point: TVector2i; targetView: PView): TVector2f{. + cdecl, importc: "sfRenderTexture_convertCoords", dynlib: LibG.} +#Draw a drawable object to the render-target +proc draw*(renderTexture: PRenderTexture; sprite: PSprite; states: PRenderStates){. + cdecl, importc: "sfRenderTexture_drawSprite", dynlib: LibG.} +proc draw*(renderTexture: PRenderTexture; text: PText; states: PRenderStates){. + cdecl, importc: "sfRenderTexture_drawText", dynlib: LibG.} +proc draw*(renderTexture: PRenderTexture; shape: PShape; states: PRenderStates){. + cdecl, importc: "sfRenderTexture_drawShape", dynlib: LibG.} +proc draw*(renderTexture: PRenderTexture; shape: PCircleShape; + states: PRenderStates){. + cdecl, importc: "sfRenderTexture_drawCircleShape", dynlib: LibG.} +proc draw*(renderTexture: PRenderTexture; shape: PConvexShape; + states: PRenderStates){. + cdecl, importc: "sfRenderTexture_drawConvexShape", dynlib: LibG.} +proc draw*(renderTexture: PRenderTexture; shape: PRectangleShape; + states: PRenderStates){. + cdecl, importc: "sfRenderTexture_drawRectangleShape", dynlib: LibG.} +proc draw*(renderTexture: PRenderTexture; va: PVertexArray; + states: PRenderStates){. + cdecl, importc: "sfRenderTexture_drawVertexArray", dynlib: LibG.} +#Draw primitives defined by an array of vertices to a render texture +proc draw*(renderTexture: PRenderTexture; vertices: PVertex; vertexCount: cint; + primitiveType: TPrimitiveType; states: PRenderStates){. + cdecl, importc: "sfRenderTexture_drawPrimitives", dynlib: LibG.} +#Save the current OpenGL render states and matrices +#/ +#/ This function can be used when you mix SFML drawing +#/ and direct OpenGL rendering. Combined with popGLStates, +#/ it ensures that: +#/ * SFML's internal states are not messed up by your OpenGL code +#/ * your OpenGL states are not modified by a call to a SFML function +#/ +#/ Note that this function is quite expensive: it saves all the +#/ possible OpenGL states and matrices, even the ones you +#/ don't care about. Therefore it should be used wisely. +#/ It is provided for convenience, but the best results will +#/ be achieved if you handle OpenGL states yourself (because +#/ you know which states have really changed, and need to be +#/ saved and restored). Take a look at the resetGLStates +#/ function if you do so. +proc pushGLStates*(renderTexture: PRenderTexture){. + cdecl, importc: "sfRenderTexture_pushGLStates", dynlib: LibG.} +#Restore the previously saved OpenGL render states and matrices +#/ +#/ See the description of pushGLStates to get a detailed +#/ description of these functions. +proc popGLStates*(renderTexture: PRenderTexture){. + cdecl, importc: "sfRenderTexture_popGLStates", dynlib: LibG.} +#Reset the internal OpenGL states so that the target is ready for drawing +#/ +#/ This function can be used when you mix SFML drawing +#/ and direct OpenGL rendering, if you choose not to use +#/ pushGLStates/popGLStates. It makes sure that all OpenGL +#/ states needed by SFML are set, so that subsequent sfRenderTexture_draw*() +#/ calls will work as expected. +proc resetGLStates*(renderTexture: PRenderTexture){. + cdecl, importc: "sfRenderTexture_resetGLStates", dynlib: LibG.} +#Get the target texture of a render texture +proc getTexture*(renderTexture: PRenderTexture): PTexture{. + cdecl, importc: "sfRenderTexture_getTexture", dynlib: LibG.} +#Enable or disable the smooth filter on a render texture +proc setSmooth*(renderTexture: PRenderTexture; smooth: bool){. + cdecl, importc: "sfRenderTexture_setSmooth", dynlib: LibG.} +#Tell whether the smooth filter is enabled or not for a render texture +proc isSmooth*(renderTexture: PRenderTexture): bool {. + cdecl, importc: "sfRenderTexture_isSmooth", dynlib: LibG.} + +proc intRect*(left, top, width, height: cint): TIntRect = + result.left = left + result.top = top + result.width = width + result.height = height +proc floatRect*(left, top, width, height: cfloat): TFloatRect = + result.left = left + result.top = top + result.width = width + result.height = height +proc contains*(rect: PFloatRect, x, y: cfloat): bool {. + cdecl, importc: "sfFloatRect_contains", dynlib: LibG.} +proc contains*(rect: PIntRect, x: cint, y: cint): bool{.cdecl, + importc: "sfIntRect_contains", dynlib: LibG.} +proc intersects*(rect1, rect2, intersection: PFloatRect): bool {. + cdecl, importc: "sfFloatRect_intersects", dynlib: LibG.} +proc intersects*(rect1, rect2, intersection: PIntRect): bool {. + cdecl, importc: "sfIntRect_intersects", dynlib: LibG.} + +proc newFont*(filename: cstring): PFont {. + cdecl, importc: "sfFont_createFromFile", dynlib: LibG.} +proc newFont*(data: pointer, sizeInBytes: cint): PFont {. + cdecl, importc: "sfFont_createFromMemory", dynlib: LibG.} +proc newFont*(stream: PInputStream): PFont {. + cdecl, importc: "sfFont_createFromStream", dynlib: LibG.} +proc copy*(font: PFont): PFont {. + cdecl, importc: "sfFont_copy", dynlib: LibG.} +proc destroy*(font: PFont) {. + cdecl, importc: "sfFont_destroy", dynlib: LibG.} +proc getGlyph*(font: PFont, codePoint: Uint32, characterSize: cint, bold: bool): TGlyph{. + cdecl, importc: "sfFont_getGlyph", dynlib: LibG.} +proc getKerning*(font: PFont, first: Uint32, second: Uint32, characterSize: cint): cint {. + cdecl, importc: "sfFont_getKerning", dynlib: LibG.} +proc getLineSpacing*(font: PFont, characterSize: cint): cint {. + cdecl, importc: "sfFont_getLineSpacing", dynlib: LibG.} +proc getTexture*(font: PFont, characterSize: cint): PTexture {. + cdecl, importc: "sfFont_getTexture", dynlib: LibG.} +#getDefaultFont() has been removed from CSFML +proc getDefaultFont*(): PFont {. + error, cdecl, importc: "sfFont_getDefaultFont", dynlib: LibG.} + +proc newCircleShape*(): PCircleShape {. + cdecl, importc: "sfCircleShape_create", dynlib: LibG.} +proc copy*(shape: PCircleShape): PCircleShape {. + cdecl, importc: "sfCircleShape_copy", dynlib: LibG.} +proc destroy*(shape: PCircleShape) {. + cdecl, importc: "sfCircleShape_destroy", dynlib: LibG.} +proc setPosition*(shape: PCircleShape, position: TVector2f) {. + cdecl, importc: "sfCircleShape_setPosition", dynlib: LibG.} +proc setRotation*(shape: PCircleShape, angle: cfloat) {. + cdecl, importc: "sfCircleShape_setRotation", dynlib: LibG.} +proc setScale*(shape: PCircleShape, scale: TVector2f) {. + cdecl, importc: "sfCircleShape_setScale", dynlib: LibG.} +proc setOrigin*(shape: PCircleShape, origin: TVector2f) {. + cdecl, importc: "sfCircleShape_setOrigin", dynlib: LibG.} +proc getPosition*(shape: PCircleShape): TVector2f {. + cdecl, importc: "sfCircleShape_getPosition", dynlib: LibG.} +proc getRotation*(shape: PCircleShape): cfloat {. + cdecl, importc: "sfCircleShape_getRotation", dynlib: LibG.} +proc getScale*(shape: PCircleShape): TVector2f {. + cdecl, importc: "sfCircleShape_getScale", dynlib: LibG.} +proc getOrigin*(shape: PCircleShape): TVector2f {. + cdecl, importc: "sfCircleShape_getOrigin", dynlib: LibG.} +proc move*(shape: PCircleShape, offset: TVector2f) {. + cdecl, importc: "sfCircleShape_move", dynlib: LibG.} +proc rotate*(shape: PCircleShape, angle: cfloat){. + cdecl, importc: "sfCircleShape_rotate", dynlib: LibG.} +proc scale*(shape: PCircleShape, factors: TVector2f) {. + cdecl, importc: "sfCircleShape_scale", dynlib: LibG.} +proc getTransform*(shape: PCircleShape): TTransform {. + cdecl, importc: "sfCircleShape_getTransform", dynlib: LibG.} +proc getInverseTransform*(shape: PCircleShape): TTransform {. + cdecl, importc: "sfCircleShape_getInverseTransform", dynlib: LibG.} +proc setTexture*(shape: PCircleShape, texture: PTexture, resetRect: bool) {. + cdecl, importc: "sfCircleShape_setTexture", dynlib: LibG.} +proc setTextureRect*(shape: PCircleShape, rect: TIntRect) {. + cdecl, importc: "sfCircleShape_setTextureRect", dynlib: LibG.} +proc setFillColor*(shape: PCircleShape, color: TColor) {. + cdecl, importc: "sfCircleShape_setFillColor", dynlib: LibG.} +proc setOutlineColor*(shape: PCircleShape, color: TColor) {. + cdecl, importc: "sfCircleShape_setOutlineColor", dynlib: LibG.} +proc setOutlineThickness*(shape: PCircleShape, thickness: cfloat) {. + cdecl, importc: "sfCircleShape_setOutlineThickness", dynlib: LibG.} +proc getTexture*(shape: PCircleShape): PTexture {. + cdecl, importc: "sfCircleShape_getTexture", dynlib: LibG.} +proc getTextureRect*(shape: PCircleShape): TIntRect {. + cdecl, importc: "sfCircleShape_getTextureRect", dynlib: LibG.} +proc getFillColor*(shape: PCircleShape): TColor {. + cdecl, importc: "sfCircleShape_getFillColor", dynlib: LibG.} +proc getOutlineColor*(shape: PCircleShape): TColor {. + cdecl, importc: "sfCircleShape_getOutlineColor", dynlib: LibG.} +proc getOutlineThickness*(shape: PCircleShape): cfloat {. + cdecl, importc: "sfCircleShape_getOutlineThickness", dynlib: LibG.} +proc getPointCount*(shape: PCircleShape): cint {. + cdecl, importc: "sfCircleShape_getPointCount", dynlib: LibG.} +proc getPoint*(shape: PCircleShape, index: cint): TVector2f {. + cdecl, importc: "sfCircleShape_getPoint", dynlib: LibG.} +proc setRadius*(shape: PCircleShape, radius: cfloat) {. + cdecl, importc: "sfCircleShape_setRadius", dynlib: LibG.} +proc getRadius*(shape: PCircleShape): cfloat {. + cdecl, importc: "sfCircleShape_getRadius", dynlib: LibG.} +proc setPointCount*(shape: PCircleShape, count: cint) {. + cdecl, importc: "sfCircleShape_setPointCount", dynlib: LibG.} +proc getLocalBounds*(shape: PCircleShape): TFloatRect {. + cdecl, importc: "sfCircleShape_getLocalBounds", dynlib: LibG.} +proc getGlobalBounds*(shape: PCircleShape): TFloatRect {. + cdecl, importc: "sfCircleShape_getGlobalBounds", dynlib: LibG.} + +proc newRectangleShape*(): PRectangleShape {. + cdecl, importc: "sfRectangleShape_create", dynlib: LibG.} +proc copy*(shape: PRectangleShape): PRectangleShape {. + cdecl, importc: "sfRectangleShape_copy", dynlib: LibG.} +proc destroy*(shape: PRectangleShape){. + cdecl, importc: "sfRectangleShape_destroy", dynlib: LibG.} +proc setPosition*(shape: PRectangleShape, position: TVector2f) {. + cdecl, importc: "sfRectangleShape_setPosition", dynlib: LibG.} +proc setRotation*(shape: PRectangleShape, angle: cfloat) {. + cdecl, importc: "sfRectangleShape_setRotation", dynlib: LibG.} +proc setScale*(shape: PRectangleShape, scale: TVector2f) {. + cdecl, importc: "sfRectangleShape_setScale", dynlib: LibG.} +proc setOrigin*(shape: PRectangleShape, origin: TVector2f) {. + cdecl, importc: "sfRectangleShape_setOrigin", dynlib: LibG.} +proc getPosition*(shape: PRectangleShape): TVector2f {. + cdecl, importc: "sfRectangleShape_getPosition", dynlib: LibG.} +proc getRotation*(shape: PRectangleShape): cfloat {. + cdecl, importc: "sfRectangleShape_getRotation", dynlib: LibG.} +proc getScale*(shape: PRectangleShape): TVector2f {. + cdecl, importc: "sfRectangleShape_getScale", dynlib: LibG.} +proc getOrigin*(shape: PRectangleShape): TVector2f {. + cdecl, importc: "sfRectangleShape_getOrigin", dynlib: LibG.} +proc move*(shape: PRectangleShape, offset: TVector2f) {. + cdecl, importc: "sfRectangleShape_move", dynlib: LibG.} +proc rotate*(shape: PRectangleShape, angle: cfloat) {. + cdecl, importc: "sfRectangleShape_rotate", dynlib: LibG.} +proc scale*(shape: PRectangleShape, factors: TVector2f) {. + cdecl, importc: "sfRectangleShape_scale", dynlib: LibG.} +proc getTransform*(shape: PRectangleShape): TTransform {. + cdecl, importc: "sfRectangleShape_getTransform", dynlib: LibG.} +proc getInverseTransform*(shape: PRectangleShape): TTransform {. + cdecl, importc: "sfRectangleShape_getInverseTransform", dynlib: LibG.} +proc setTexture*(shape: PRectangleShape, texture: PTexture, resetRect: bool) {. + cdecl, importc: "sfRectangleShape_setTexture", dynlib: LibG.} +proc setTextureRect*(shape: PRectangleShape, rect: TIntRect) {. + cdecl, importc: "sfRectangleShape_setTextureRect", dynlib: LibG.} +proc setFillColor*(shape: PRectangleShape, color: TColor) {. + cdecl, importc: "sfRectangleShape_setFillColor", dynlib: LibG.} +proc setOutlineColor*(shape: PRectangleShape, color: TColor) {. + cdecl, importc: "sfRectangleShape_setOutlineColor", dynlib: LibG.} +proc setOutlineThickness*(shape: PRectangleShape, thickness: cfloat) {. + cdecl, importc: "sfRectangleShape_setOutlineThickness", dynlib: LibG.} +proc getTexture*(shape: PRectangleShape): PTexture {. + cdecl, importc: "sfRectangleShape_getTexture", dynlib: LibG.} +proc getTextureRect*(shape: PRectangleShape): TIntRect {. + cdecl, importc: "sfRectangleShape_getTextureRect", dynlib: LibG.} +proc getFillColor*(shape: PRectangleShape): TColor {. + cdecl, importc: "sfRectangleShape_getFillColor", dynlib: LibG.} +proc getOutlineColor*(shape: PRectangleShape): TColor {. + cdecl, importc: "sfRectangleShape_getOutlineColor", dynlib: LibG.} +proc getOutlineThickness*(shape: PRectangleShape): cfloat {. + cdecl, importc: "sfRectangleShape_getOutlineThickness", dynlib: LibG.} +proc getPointCount*(shape: PRectangleShape): cint {. + cdecl, importc: "sfRectangleShape_getPointCount", dynlib: LibG.} +proc getPoint*(shape: PRectangleShape, index: cint): TVector2f {. + cdecl, importc: "sfRectangleShape_getPoint", dynlib: LibG.} +proc setSize*(shape: PRectangleShape, size: TVector2f) {. + cdecl, importc: "sfRectangleShape_setSize", dynlib: LibG.} +proc getSize*(shape: PRectangleShape): TVector2f {. + cdecl, importc: "sfRectangleShape_getSize", dynlib: LibG.} +proc getLocalBounds*(shape: PRectangleShape): TFloatRect {. + cdecl, importc: "sfRectangleShape_getLocalBounds", dynlib: LibG.} +proc getGlobalBounds*(shape: PRectangleShape): TFloatRect {. + cdecl, importc: "sfRectangleShape_getGlobalBounds", dynlib: LibG.} + + +proc newView*(): PView {. + cdecl, importc: "sfView_create", dynlib: LibG.} +proc viewFromRect*(rectangle: TFloatRect): PView{. + cdecl, importc: "sfView_createFromRect", dynlib: LibG.} +proc copy*(view: PView): PView {. + cdecl, importc: "sfView_copy", dynlib: LibG.} +proc destroy*(view: PView) {. + cdecl, importc: "sfView_destroy", dynlib: LibG.} +proc setCenter*(view: PView, center: TVector2f) {. + cdecl, importc: "sfView_setCenter", dynlib: LibG.} +proc setSize*(view: PView, size: TVector2f) {. + cdecl, importc: "sfView_setSize", dynlib: LibG.} +proc setRotation*(view: PView, angle: cfloat) {. + cdecl, importc: "sfView_setRotation", dynlib: LibG.} +proc setViewport*(view: PView, viewport: TFloatRect) {. + cdecl, importc: "sfView_setViewport", dynlib: LibG.} +proc reset*(view: PView, rectangle: TFloatRect) {. + cdecl, importc: "sfView_reset", dynlib: LibG.} +proc getCenter*(view: PView): TVector2f {. + cdecl, importc: "sfView_getCenter", dynlib: LibG.} +proc getSize*(view: PView): TVector2f {. + cdecl, importc: "sfView_getSize", dynlib: LibG.} +proc getRotation*(view: PView): cfloat {. + cdecl, importc: "sfView_getRotation", dynlib: LibG.} +proc getViewport*(view: PView): TFloatRect {. + cdecl, importc: "sfView_getViewport", dynlib: LibG.} +proc move*(view: PView, offset: TVector2f) {. + cdecl, importc: "sfView_move", dynlib: LibG.} +proc rotate*(view: PView, angle: cfloat) {. + cdecl, importc: "sfView_rotate", dynlib: LibG.} +proc zoom*(view: PView, factor: cfloat) {. + cdecl, importc: "sfView_zoom", dynlib: LibG.} + +proc newImage*(width, height: cint): PImage {. + cdecl, importc: "sfImage_create", dynlib: LibG.} +proc newImage*(width, height: cint, color: TColor): PImage {. + cdecl, importc: "sfImage_createFromColor", dynlib: LibG.} +proc newImage*(width, height: cint, pixels: pointer): PImage {. ##same deal as setIcon() + cdecl, importc: "sfImage_createFromPixels", dynlib: LibG.} +proc newImage*(filename: cstring): PImage {. + cdecl, importc: "sfImage_createFromFile", dynlib: LibG.} +proc newImage*(data: pointer, size: cint): PImage {. + cdecl, importc: "sfImage_createFromMemory", dynlib: LibG.} +proc newImage*(stream: PInputStream): PImage {. + cdecl, importc: "sfImage_createFromStream", dynlib: LibG.} +proc copy*(image: PImage): PImage {. + cdecl, importc: "sfImage_copy", dynlib: LibG.} +proc destroy*(image: PImage) {. + cdecl, importc: "sfImage_destroy", dynlib: LibG.} +proc save*(image: PImage, filename: cstring): bool {. + cdecl, importc: "sfImage_saveToFile", dynlib: LibG.} +proc getSize*(image: PImage): TVector2i {. + cdecl, importc: "sfImage_getSize", dynlib: LibG.} +proc createMask*(image: PImage, color: TColor, alpha: cchar) {. + cdecl, importc: "sfImage_createMaskFromColor", dynlib: LibG.} +proc copy*(destination, source: PImage, destX, destY: cint; + sourceRect: TIntRect, applyAlpha: bool) {. + cdecl, importc: "sfImage_copyImage", dynlib: LibG.} +proc setPixel*(image: PImage, x, y: cint, color: TColor) {. + cdecl, importc: "sfImage_setPixel", dynlib: LibG.} +proc getPixel*(image: PImage, x, y: cint): TColor {. + cdecl, importc: "sfImage_getPixel", dynlib: LibG.} +proc getPixels*(image: PImage): pointer {. + cdecl, importc: "sfImage_getPixelsPtr", dynlib: LibG.} +proc flipHorizontally*(image: PImage) {. + cdecl, importc: "sfImage_flipHorizontally", dynlib: LibG.} +proc flipVertically*(image: PImage) {. + cdecl, importc: "sfImage_flipVertically", dynlib: LibG.} + +proc newSprite*(): PSprite {. + cdecl, importc: "sfSprite_create", dynlib: LibG.} +proc copy*(sprite: PSprite): PSprite {. + cdecl, importc: "sfSprite_copy", dynlib: LibG.} +proc destroy*(sprite: PSprite) {. + cdecl, importc: "sfSprite_destroy", dynlib: LibG.} +proc setPosition*(sprite: PSprite, position: TVector2f) {. + cdecl, importc: "sfSprite_setPosition", dynlib: LibG.} +proc setRotation*(sprite: PSprite, angle: cfloat) {. + cdecl, importc: "sfSprite_setRotation", dynlib: LibG.} +proc setScale*(sprite: PSprite, scale: TVector2f) {. + cdecl, importc: "sfSprite_setScale", dynlib: LibG.} +proc setOrigin*(sprite: PSprite, origin: TVector2f) {. + cdecl, importc: "sfSprite_setOrigin", dynlib: LibG.} +proc getPosition*(sprite: PSprite): TVector2f {. + cdecl, importc: "sfSprite_getPosition", dynlib: LibG.} +proc getRotation*(sprite: PSprite): cfloat {. + cdecl, importc: "sfSprite_getRotation", dynlib: LibG.} +proc getScale*(sprite: PSprite): TVector2f {. + cdecl, importc: "sfSprite_getScale", dynlib: LibG.} +proc getOrigin*(sprite: PSprite): TVector2f {. + cdecl, importc: "sfSprite_getOrigin", dynlib: LibG.} +proc move*(sprite: PSprite, offset: TVector2f) {. + cdecl, importc: "sfSprite_move", dynlib: LibG.} +proc rotate*(sprite: PSprite, angle: cfloat) {. + cdecl, importc: "sfSprite_rotate", dynlib: LibG.} +proc scale*(sprite: PSprite, factor: TVector2f) {. + cdecl, importc: "sfSprite_scale", dynlib: LibG.} +proc getTransform*(sprite: PSprite): TTransform {. + cdecl, importc: "sfSprite_getTransform", dynlib: LibG.} +proc getInverseTransform*(sprite: PSprite): TTransform {. + cdecl, importc: "sfSprite_getInverseTransform", dynlib: LibG.} +proc setTexture*(sprite: PSprite, texture: PTexture, resetRect: bool) {. + cdecl, importc: "sfSprite_setTexture", dynlib: LibG.} +proc setTextureRect*(sprite: PSprite, rectangle: TIntRect) {. + cdecl, importc: "sfSprite_setTextureRect", dynlib: LibG.} +proc setColor*(sprite: PSprite, color: TColor) {. + cdecl, importc: "sfSprite_setColor", dynlib: LibG.} +proc getTexture*(sprite: PSprite): TTexture {. + cdecl, importc: "sfSprite_getTexture", dynlib: LibG.} +proc getTextureRect*(sprite: PSprite): TIntRect {. + cdecl, importc: "sfSprite_getTextureRect", dynlib: LibG.} +proc getColor*(sprite: PSprite): TColor {. + cdecl, importc: "sfSprite_getColor", dynlib: LibG.} +proc getLocalBounds*(sprite: PSprite): TFloatRect {. + cdecl, importc: "sfSprite_getLocalBounds", dynlib: LibG.} +proc getGlobalBounds*(sprite: PSprite): TFloatRect {. + cdecl, importc: "sfSprite_getGlobalBounds", dynlib: LibG.} + +proc newTexture*(width, height: cint): PTexture {. + cdecl, importc: "sfTexture_create", dynlib: LibG.} +proc newTexture*(filename: cstring): PTexture {. + cdecl, importc: "sfTexture_createFromFile", dynlib: LibG.} +proc newTexture*(data: pointer, size: cint, area: PIntRect): PTexture {. + cdecl, importc: "sfTexture_createFromMemory", dynlib: LibG.} +proc newTexture*(stream: PInputStream, area: PIntRect): PTexture {. + cdecl, importc: "sfTexture_createFromStream", dynlib: LibG.} +proc newTexture*(image: PImage, area: PIntRect = nil): PTexture {. + cdecl, importc: "sfTexture_createFromImage", dynlib: LibG.} +proc copy*(texture: PTexture): PTexture {. + cdecl, importc: "sfTexture_copy", dynlib: LibG.} +proc destroy*(texture: PTexture) {. + cdecl, importc: "sfTexture_destroy", dynlib: LibG.} +proc getSize*(texture: PTexture): TVector2i {. + cdecl, importc: "sfTexture_getSize", dynlib: LibG.} +proc copyToImage*(texture: PTexture): PImage {. + cdecl, importc: "sfTexture_copyToImage", dynlib: LibG.} +proc updateFromPixels*(texture: PTexture, pixels: pointer, width, height, x, y: cint) {. + cdecl, importc: "sfTexture_updateFromPixels", dynlib: LibG.} +proc updateFromImage*(texture: PTexture, image: PImage, x, y: cint) {. + cdecl, importc: "sfTexture_updateFromImage", dynlib: LibG.} +proc updateFromWindow*(texture: PTexture, window: PWindow, x, y: cint) {. + cdecl, importc: "sfTexture_updateFromWindow", dynlib: LibG.} +proc updateFromWindow*(texture: PTexture, window: PRenderWindow, x, y: cint) {. + cdecl, importc: "sfTexture_updateFromRenderWindow", dynlib: LibG.} +proc bindGL*(texture: PTexture) {. + cdecl, importc: "sfTexture_bind", dynlib: LibG.} +proc setSmooth*(texture: PTexture, smooth: bool) {. + cdecl, importc: "sfTexture_setSmooth", dynlib: LibG.} +proc isSmooth*(texture: PTexture): bool {. + cdecl, importc: "sfTexture_isSmooth", dynlib: LibG.} +proc setRepeated*(texture: PTexture, repeated: bool) {. + cdecl, importc: "sfTexture_setRepeated", dynlib: LibG.} +proc isRepeated*(texture: PTexture): bool {. + cdecl, importc: "sfTexture_isRepeated", dynlib: LibG.} +proc textureMaxSize*(): cint {. + cdecl, importc: "sfTexture_getMaximumSize", dynlib: LibG.} + +proc newVertexArray*(): PVertexArray {. + cdecl, importc: "sfVertexArray_create", dynlib: LibG.} +proc copy*(vertexArray: PVertexArray): PVertexArray {. + cdecl, importc: "sfVertexArray_copy", dynlib: LibG.} +proc destroy*(va: PVertexArray) {. + cdecl, importc: "sfVertexArray_destroy", dynlib: LibG.} +proc getVertexCount*(va: PVertexArray): cint {. + cdecl, importc: "sfVertexArray_getVertexCount", dynlib: LibG.} +proc getVertex*(va: PVertexArray, index: cint): PVertex {. + cdecl, importc: "sfVertexArray_getVertex", dynlib: LibG.} +proc clear*(va: PVertexArray) {. + cdecl, importc: "sfVertexArray_clear", dynlib: LibG.} +proc resize*(va: PVertexArray, size: cint) {. + cdecl, importc: "sfVertexArray_resize", dynlib: LibG.} +proc append*(va: PVertexArray, vertex: TVertex) {. + cdecl, importc: "sfVertexArray_append", dynlib: LibG.} +proc setPrimitiveType*(va: PVertexArray, primitiveType: TPrimitiveType) {. + cdecl, importc: "sfVertexArray_setPrimitiveType", dynlib: LibG.} +proc getPrimitiveType*(va: PVertexArray): TPrimitiveType {. + cdecl, importc: "sfVertexArray_getPrimitiveType", dynlib: LibG.} +proc getBounds*(va: PVertexArray): TFloatRect {. + cdecl, importc: "sfVertexArray_getBounds", dynlib: LibG.} + + +proc newText*(): PText {. + cdecl, importc: "sfText_create", dynlib: LibG.} +proc copy*(text: PText): PText {. + cdecl, importc: "sfText_copy", dynlib: LibG.} +proc destroy*(text: PText) {. + cdecl, importc: "sfText_destroy", dynlib: LibG.} +proc setPosition*(text: PText, position: TVector2f) {. + cdecl, importc: "sfText_setPosition", dynlib: LibG.} +proc setRotation*(text: PText, angle: cfloat) {. + cdecl, importc: "sfText_setRotation", dynlib: LibG.} +proc setScale*(text: PText, scale: TVector2f) {. + cdecl, importc: "sfText_setScale", dynlib: LibG.} +proc setOrigin*(text: PText, origin: TVector2f) {. + cdecl, importc: "sfText_setOrigin", dynlib: LibG.} +proc getPosition*(text: PText): TVector2f {. + cdecl, importc: "sfText_getPosition", dynlib: LibG.} +proc getRotation*(text: PText): cfloat {. + cdecl, importc: "sfText_getRotation", dynlib: LibG.} +proc getScale*(text: PText): TVector2f {. + cdecl, importc: "sfText_getScale", dynlib: LibG.} +proc getOrigin*(text: PText): TVector2f {. + cdecl, importc: "sfText_getOrigin", dynlib: LibG.} +proc move*(text: PText, offset: TVector2f) {. + cdecl, importc: "sfText_move", dynlib: LibG.} +proc rotate*(text: PText, angle: cfloat) {. + cdecl, importc: "sfText_rotate", dynlib: LibG.} +proc scale*(text: PText, factors: TVector2f) {. + cdecl, importc: "sfText_scale", dynlib: LibG.} +proc getTransform*(text: PText): TTransform {. + cdecl, importc: "sfText_getTransform", dynlib: LibG.} +proc getInverseTransform*(text: PText): TTransform {. + cdecl, importc: "sfText_getInverseTransform", dynlib: LibG.} +proc setString*(text: PText, string: cstring) {. + cdecl, importc: "sfText_setString", dynlib: LibG.} +proc setUnicodeString*(text: PText, string: ptr Uint32) {. + cdecl, importc: "sfText_setUnicodeString", dynlib: LibG.} +proc setFont*(text: PText, font: PFont) {. + cdecl, importc: "sfText_setFont", dynlib: LibG.} +proc setCharacterSize*(text: PText, size: cint) {. + cdecl, importc: "sfText_setCharacterSize", dynlib: LibG.} +proc setStyle*(text: PText, style: TTextStyle) {. + cdecl, importc: "sfText_setStyle", dynlib: LibG.} +proc setColor*(text: PText, color: TColor) {. + cdecl, importc: "sfText_setColor", dynlib: LibG.} +proc getString*(text: PText): cstring {. + cdecl, importc: "sfText_getString", dynlib: LibG.} +proc getUnicodeString*(text: PText): ptr Uint32 {.cdecl, + importc: "sfText_getUnicodeString", dynlib: LibG.} +proc getFont*(text: PText): PFont {. + cdecl, importc: "sfText_getFont", dynlib: LibG.} +proc getCharacterSize*(text: PText): cint {. + cdecl, importc: "sfText_getCharacterSize", dynlib: LibG.} +proc getStyle*(text: PText): Uint32 {. + cdecl, importc: "sfText_getStyle", dynlib: LibG.} +proc getColor*(text: PText): TColor {. + cdecl, importc: "sfText_getColor", dynlib: LibG.} +proc findCharacterPos*(text: PText, index: cint): TVector2f {. + cdecl, importc: "sfText_findCharacterPos", dynlib: LibG.} +proc getLocalBounds*(text: PText): TFloatRect {. + cdecl, importc: "sfText_getLocalBounds", dynlib: LibG.} +proc getGlobalBounds*(text: PText): TFloatRect {. + cdecl, importc: "sfText_getGlobalBounds", dynlib: LibG.} + +proc transformFromMatrix*(a00, a01, a02, a10, a11, a12, a20, a21, a22: cfloat): TTransform {. + cdecl, importc: "sfTransform_fromMatrix", dynlib: LibG.} +proc getMatrix*(transform: PTransform, matrix: ptr cfloat) {. + cdecl, importc: "sfTransform_getMatrix", dynlib: LibG.} +proc getInverse*(transform: PTransform): TTransform {. + cdecl, importc: "sfTransform_getInverse", dynlib: LibG.} +proc transformPoint*(transform: PTransform, point: TVector2f): TVector2f {. + cdecl, importc: "sfTransform_transformPoint", dynlib: LibG.} +proc transformRect*(transform: PTransform, rectangle: TFloatRect): TFloatRect {. + cdecl, importc: "sfTransform_transformRect", dynlib: LibG.} +proc combine*(transform: PTransform, other: PTransform) {. + cdecl, importc: "sfTransform_combine", dynlib: LibG.} +proc translate*(transform: PTransform, x, y: cfloat) {. + cdecl, importc: "sfTransform_translate", dynlib: LibG.} +proc rotate*(transform: PTransform, angle: cfloat) {. + cdecl, importc: "sfTransform_rotate", dynlib: LibG.} +proc rotateWithCenter*(transform: PTransform, angle, centerX, centerY: cfloat){. + cdecl, importc: "sfTransform_rotateWithCenter", dynlib: LibG.} +proc scale*(transform: PTransform, scaleX, scaleY: cfloat) {. + cdecl, importc: "sfTransform_scale", dynlib: LibG.} +proc scaleWithCenter*(transform: PTransform, scaleX, scaleY, centerX, centerY: cfloat) {. + cdecl, importc: "sfTransform_scaleWithCenter", dynlib: LibG.} +let IdentityMatrix*: TTransform = transformFromMatrix(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) + + +proc newShader*(VSfilename: cstring, fragmentShaderFilename: cstring): PShader {. + cdecl, importc: "sfShader_createFromFile", dynlib: LibG.} +proc newShaderFromStr*(vertexShader: cstring, fragmentShader: cstring): PShader {. + cdecl, importc: "sfShader_createFromMemory", dynlib: LibG.} +proc newShader*(vertexShaderStream: PInputStream, fragmentShaderStream: PInputStream): PShader {. + cdecl, importc: "sfShader_createFromStream", dynlib: LibG.} +proc destroy*(shader: PShader) {. + cdecl, importc: "sfShader_destroy", dynlib: LibG.} +proc setFloatParameter*(shader: PShader, name: cstring, x: cfloat) {. + cdecl, importc: "sfShader_setFloatParameter", dynlib: LibG.} +proc setFloat2Parameter*(shader: PShader, name: cstring, x, y: cfloat) {. + cdecl, importc: "sfShader_setFloat2Parameter", dynlib: LibG.} +proc setFloat3Parameter*(shader: PShader, name: cstring, x, y, z: cfloat) {. + cdecl, importc: "sfShader_setFloat3Parameter", dynlib: LibG.} +proc setFloat4Parameter*(shader: PShader, name: cstring, x, y, z, w: cfloat) {. + cdecl, importc: "sfShader_setFloat4Parameter", dynlib: LibG.} +proc setVector2Parameter*(shader: PShader, name: cstring, vector: TVector2f) {. + cdecl, importc: "sfShader_setVector2Parameter", dynlib: LibG.} +proc setVector3Parameter*(shader: PShader, name: cstring, vector: TVector3f) {. + cdecl, importc: "sfShader_setVector3Parameter", dynlib: LibG.} +proc setColorParameter*(shader: PShader, name: cstring, color: TColor) {. + cdecl, importc: "sfShader_setColorParameter", dynlib: LibG.} +proc setTransformParameter*(shader: PShader, name: cstring, transform: TTransform) {. + cdecl, importc: "sfShader_setTransformParameter", dynlib: LibG.} +proc setTextureParameter*(shader: PShader, name: cstring, texture: PTexture) {. + cdecl, importc: "sfShader_setTextureParameter", dynlib: LibG.} +proc setCurrentTextureParameter*(shader: PShader, name: cstring) {. + cdecl, importc: "sfShader_setCurrentTextureParameter", dynlib: LibG.} +proc bindGL*(shader: PShader) {. + cdecl, importc: "sfShader_bind", dynlib: LibG.} +proc unbindGL*(shader: PShader) {. + cdecl, importc: "sfShader_unbind", dynlib: LibG.} +proc shaderIsAvailable*(): bool {. + cdecl, importc: "sfShader_isAvailable", dynlib: LibG.} + +proc color*(red, green, blue: cchar): TColor {. + cdecl, importc: "sfColor_fromRGB", dynlib: LibG.} +proc color*(red, green, blue: int): TColor {.inline.} = + return color(red.cchar, green.cchar, blue.cchar) +proc color*(red, green, blue, alpha: cchar): TColor {. + cdecl, importc: "sfColor_fromRGBA", dynlib: LibG.} +proc color*(red, green, blue, alpha: int): TColor {.inline.} = + return color(red.cchar, green.cchar, blue.cchar, alpha.cchar) +proc `+`*(color1, color2: TColor): TColor {. + cdecl, importc: "sfColor_add", dynlib: LibG.} +proc `*`*(color1, color2: TColor): TColor {. + cdecl, importc: "sfColor_modulate", dynlib: LibG.} +proc newColor*(r,g,b: int): TColor {.inline.} = + return color(r,g,b) +proc newColor*(r,g,b,a: int): TColor {.inline.} = + return color(r,g,b,a) + +proc newClock*(): PClock {. + cdecl, importc: "sfClock_create", dynlib: LibS.} +proc copy*(clocK: PClock): PClock {. + cdecl, importc: "sfClock_copy", dynlib: LibS.} +proc destroy*(clock: PClock): PClock {. + cdecl, importc: "sfClock_destroy", dynlib: LibS.} +proc getElapsedTime*(clock: PClock): TTime {. + cdecl, importc: "sfClock_getElapsedTime", dynlib: LibS.} +proc restart*(clock: PClock): TTime {. + cdecl, importc: "sfClock_restart", dynlib: LibS, discardable.} +proc asSeconds*(time: TTime): cfloat {. + cdecl, importc: "sfTime_asSeconds", dynlib: LibS.} +proc asMilliseconds*(time: TTime): int32 {. + cdecl, importc: "sfTime_asMilliseconds", dynlib: LibS.} +proc asMicroseconds*(time: TTime): int64 {. + cdecl, importc: "sfTime_asMicroseconds", dynlib: LibS.} +proc seconds*(seconds: cfloat): TTime {. + cdecl, importc: "sfSeconds", dynlib: LibS.} +proc milliseconds*(ms: int32): TTime {. + cdecl, importc: "sfMilliseconds", dynlib: LibS.} +proc microseconds*(us: int64): TTime {. + cdecl, importc: "sfMicroseconds", dynlib: LibS.} + +proc newContextSettings*(depthBits: cint = 0, + stencilBits: cint = 0, + antialiasingLevel: cint = 0, + majorVersion: cint = 0, + minorVersion: cint = 0): TContextSettings = + result.depthBits = depthBits + result.stencilBits = stencilBits + result.antialiasingLevel = antialiasingLevel + result.majorVersion = majorVersion + result.minorVersion = minorVersion + +proc newCircleShape*(radius: cfloat; pointCount: cint = 30): PCircleShape = + result = newCircleShape() + result.setRadius radius + result.setPointCount pointCount +proc newText*(str: string, font: PFont, size: int): PText = + result = newText() + result.setString(str) + result.setFont(font) + result.setCharacterSize(size.cint) +proc newVertexArray*(primitiveType: TPrimitiveType, vertexCount: cint = 0): PVertexArray = + result = newVertexArray() + result.setPrimitiveType(primitiveType) + if vertexCount != 0: + result.resize(vertexCount) +proc videoMode*(width, height, bpp: cint): TVideoMode = + result.width = width + result.height = height + result.bitsPerPixel = bpp + +proc `[]`*(a: PVertexArray, index: int): PVertex = + return getVertex(a, index.cint) + +proc `$` *(a: TContextSettings): string = + return "<TContextSettings stencil=$1 aa=$2 major=$3 minor=$4 depth=$5>" % [ + $a.stencilBits, $a.antialiasingLevel, $a.majorVersion, $a.minorVersion, $a.depthBits] +proc `$` *(a: TVideoMode): string = + return "<TVideoMode $1x$2 $3bpp>" % [$a.width, $a.height, $a.bitsPerPixel] +proc `$` *(a: TFloatRect): string = + return "<TFloatRect $1,$2 $3x$4>" % [$a.left, $a.top, $a.width, $a.height] +proc `$` *(a: PView): string = + return $a.getViewport() +proc `$` *(a: TVector2f): string = + return "<TVector2f $1,$2>" % [$a.x, $a.y] + +proc vec2i*(x, y: int): TVector2i = + result.x = x.cint + result.y = y.cint +proc vec2f*(x, y: float): TVector2f = + result.x = x.cfloat + result.y = y.cfloat + +proc `+`*(a, b: TVector2f): TVector2f {.inline.} = + result.x = a.x + b.x + result.y = a.y + b.y +proc `-`*(a: TVector2f): TVector2f {.inline.} = + result.x = -a.x + result.y = -a.y +proc `-`*(a, b: TVector2f): TVector2f {.inline.}= + result.x = a.x - b.x + result.y = a.y - b.y +proc `*`*(a: TVector2f, b: cfloat): TVector2f {.inline.} = + result.x = a.x * b + result.y = a.y * b +proc `*`*(a, b: TVector2f): TVector2f {.inline.} = + result.x = a.x * b.x + result.y = a.y * b.y +proc `/`*(a: TVector2f, b: cfloat): TVector2f {.inline.} = + result.x = a.x / b + result.y = a.y / b +proc `+=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} = + a = a + b +proc `-=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} = + a = a - b +proc `*=` *(a: var TVector2f, b: float) {.inline, noSideEffect.} = + a = a * b +proc `*=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} = + a = a * b +proc `/=` *(a: var TVector2f, b: float) {.inline, noSideEffect.} = + a = a / b +proc `<` *(a, b: TVector2f): bool {.inline, noSideEffect.} = + return a.x < b.x or (a.x == b.x and a.y < b.y) +proc `<=` *(a, b: TVector2f): bool {.inline, noSideEffect.} = + return a.x <= b.x and a.y <= b.y +proc `==` *(a, b: TVector2f): bool {.inline, noSideEffect.} = + return a.x == b.x and a.y == b.y +proc length*(a: TVector2f): float {.inline.} = + return sqrt(pow(a.x, 2.0) + pow(a.y, 2.0)) +proc lengthSq*(a: TVector2f): float {.inline.} = + return pow(a.x, 2.0) + pow(a.y, 2.0) +proc distanceSq*(a, b: TVector2f): float {.inline.} = + return pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0) +proc distance*(a, b: TVector2f): float {.inline.} = + return sqrt(pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0)) +proc permul*(a, b: TVector2f): TVector2f = + result.x = a.x * b.x + result.y = a.y * b.y +proc rotate*(a: TVector2f, phi: float): TVector2f = + var c = cos(phi) + var s = sin(phi) + result.x = a.x * c - a.y * s + result.y = a.x * s + a.y * c +proc perpendicular(a: TVector2f): TVector2f = + result.x = -a.x + result.y = a.y +proc cross(a, b: TVector2f): float = + return a.x * b.y - a.y * b.x + diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim new file mode 100644 index 000000000..3cfd33c02 --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim @@ -0,0 +1,899 @@ +import + sfml +const + Lib = "libcsfml-audio.so.2.0" +type + PMusic* = ptr TMusic + TMusic* {.pure, final.} = object + PSound* = ptr TSound + TSound* {.pure, final.} = object + PSoundBuffer* = ptr TSoundBuffer + TSoundBuffer* {.pure, final.} = object + PSoundBufferRecorder* = ptr TSoundBufferRecorder + TSoundBufferRecorder* {.pure, final.} = object + PSoundRecorder* = ptr TSoundRecorder + TSoundRecorder* {.pure, final.} = object + PSoundStream* = ptr TSoundStream + TSoundStream* {.pure, final.} = object + TSoundStatus* {.size: sizeof(cint).} = enum + Stopped, Paused, Playing + +proc newMusic*(filename: cstring): PMusic {. + cdecl, importc: "sfMusic_createFromFile", dynlib: Lib.} +proc newMusic*(data: pointer, size: cint): PMusic {. + cdecl, importc: "sfMusic_createFromMemory", dynlib: Lib.} +proc newMusic*(stream: PInputStream): PMusic {. + cdecl, importc: "sfMusic_createFromStream", dynlib: Lib.} +proc destroy*(music: PMusic) {. + cdecl, importc: "sfMusic_destroy", dynlib: Lib.} +proc setLoop*(music: PMusic, loop: bool) {. + cdecl, importc: "sfMusic_setLoop", dynlib: Lib.} +proc getLoop*(music: PMusic): bool {. + cdecl, importc: "sfMusic_getLoop", dynlib: Lib.} +proc getDuration*(music: PMusic): TTime {. + cdecl, importc: "sfMusic_getDuration", dynlib: Lib.} +proc play*(music: PMusic) {. + cdecl, importc: "sfMusic_play", dynlib: Lib.} +proc pause*(music: PMusic) {. + cdecl, importc: "sfMusic_pause", dynlib: Lib.} +proc stop*(music: PMusic) {. + cdecl, importc: "sfMusic_stop", dynlib: Lib.} +proc getChannelCount*(music: PMusic): cint {. + cdecl, importc: "sfMusic_getChannelCount", dynlib: Lib.} +proc getSampleRate*(music: PMusic): cint {. + cdecl, importc: "sfMusic_getSampleRate", dynlib: Lib.} +proc getStatus*(music: PMusic): TSoundStatus {. + cdecl, importc: "sfMusic_getStatus", dynlib: Lib.} +proc getPlayingOffset*(music: PMusic): TTime {. + cdecl, importc: "sfMusic_getPlayingOffset", dynlib: Lib.} +proc setPitch*(music: PMusic, pitch: cfloat) {. + cdecl, importc: "sfMusic_setPitch", dynlib: Lib.} +proc setVolume*(music: PMusic, volume: float) {. + cdecl, importc: "sfMusic_setVolume", dynlib: Lib.} +proc setPosition*(music: PMusic, position: TVector3f) {. + cdecl, importc: "sfMusic_setPosition", dynlib: Lib.} +proc setRelativeToListener*(music: PMusic, relative: bool) {. + cdecl, importc: "sfMusic_setRelativeToListener", dynlib: Lib.} +proc setMinDistance*(music: PMusic, distance: cfloat) {. + cdecl, importc: "sfMusic_setMinDistance", dynlib: Lib.} +proc setAttenuation*(music: PMusic, attenuation: cfloat) {. + cdecl, importc: "sfMusic_setAttenuation", dynlib: Lib.} +proc setPlayingOffset*(music: PMusic, time: TTime) {. + cdecl, importc: "sfMusic_setPlayingOffset", dynlib: Lib.} +proc getPitch*(music: PMusic): cfloat {. + cdecl, importc: "sfMusic_getPitch", dynlib: Lib.} +proc getVolume*(music: PMusic): cfloat {. + cdecl, importc: "sfMusic_getVolume", dynlib: Lib.} +proc getPosition*(music: PMusic): TVector3f {. + cdecl, importc: "sfMusic_getPosition", dynlib: Lib.} +proc isRelativeToListener*(music: PMusic): bool {. + cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.} +proc getMinDistance*(music: PMusic): cfloat {. + cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.} +proc getAttenuation*(music: PMusic): cfloat {. + cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.} + +#/ \brief Create a new sound +proc newSound*(): PSound{. + cdecl, importc: "sfSound_create", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Create a new sound by copying an existing one +#/ +#/ \param sound Sound to copy +#/ +#/ \return A new sfSound object which is a copy of \a sound +#/ +#////////////////////////////////////////////////////////// +proc copy*(sound: PSound): PSound{. + cdecl, importc: "sfSound_copy", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Destroy a sound +proc destroy*(sound: PSound){. + cdecl, importc: "sfSound_destroy", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Start or resume playing a sound +#/ +#/ This function starts the sound if it was stopped, resumes +#/ it if it was paused, and restarts it from beginning if it +#/ was it already playing. +#/ This function uses its own thread so that it doesn't block +#/ the rest of the program while the sound is played. +proc play*(sound: PSound){. + cdecl, importc: "sfSound_play", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ This function pauses the sound if it was playing, +#/ otherwise (sound already paused or stopped) it has no effect. +proc pause*(sound: PSound){. + cdecl, importc: "sfSound_pause", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ This function stops the sound if it was playing or paused, +#/ and does nothing if it was already stopped. +#/ It also resets the playing position (unlike sfSound_pause). +proc stop*(sound: PSound){. + cdecl, importc: "sfSound_stop", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ It is important to note that the sound buffer is not copied, +#/ thus the sfSoundBuffer object must remain alive as long +#/ as it is attached to the sound. +proc setBuffer*(sound: PSound; buffer: PSoundBuffer){. + cdecl, importc: "sfSound_setBuffer", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the audio buffer attached to a sound +proc getBuffer*(sound: PSound): PSoundBuffer{. + cdecl, importc: "sfSound_getBuffer", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set whether or not a sound should loop after reaching the end +#/ +#/ If set, the sound will restart from beginning after +#/ reaching the end and so on, until it is stopped or +#/ sfSound_setLoop(sound, sfFalse) is called. +#/ The default looping state for sounds is false. +proc setLoop*(sound: PSound; loop: bool){. + cdecl, importc: "sfSound_setLoop", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Tell whether or not a soud is in loop mode +proc getLoop*(sound: PSound): bool {. + cdecl, importc: "sfSound_getLoop", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the current status of a sound (stopped, paused, playing) +proc getStatus*(sound: PSound): TSoundStatus{. + cdecl, importc: "sfSound_getStatus", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the pitch of a sound +#/ +#/ The pitch represents the perceived fundamental frequency +#/ of a sound; thus you can make a sound more acute or grave +#/ by changing its pitch. A side effect of changing the pitch +#/ is to modify the playing speed of the sound as well. +#/ The default value for the pitch is 1. +proc setPitch*(sound: PSound; pitch: cfloat){. + cdecl, importc: "sfSound_setPitch", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the volume of a sound +#/ +#/ The volume is a value between 0 (mute) and 100 (full volume). +#/ The default value for the volume is 100. +proc setVolume*(sound: PSound; volume: cfloat){. + cdecl, importc: "sfSound_setVolume", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the 3D position of a sound in the audio scene +#/ +#/ Only sounds with one channel (mono sounds) can be +#/ spatialized. +#/ The default position of a sound is (0, 0, 0). +proc setPosition*(sound: PSound; position: TVector3f){. + cdecl, importc: "sfSound_setPosition", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Make the sound's position relative to the listener or absolute +#/ +#/ Making a sound relative to the listener will ensure that it will always +#/ be played the same way regardless the position of the listener. +#/ This can be useful for non-spatialized sounds, sounds that are +#/ produced by the listener, or sounds attached to it. +#/ The default value is false (position is absolute). +proc setRelativeToListener*(sound: PSound; relative: bool){. + cdecl, importc: "sfSound_setRelativeToListener", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the minimum distance of a sound +#/ +#/ The "minimum distance" of a sound is the maximum +#/ distance at which it is heard at its maximum volume. Further +#/ than the minimum distance, it will start to fade out according +#/ to its attenuation factor. A value of 0 ("inside the head +#/ of the listener") is an invalid value and is forbidden. +#/ The default value of the minimum distance is 1. +proc setMinDistance*(sound: PSound; distance: cfloat){. + cdecl, importc: "sfSound_setMinDistance", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the attenuation factor of a sound +#/ +#/ The attenuation is a multiplicative factor which makes +#/ the sound more or less loud according to its distance +#/ from the listener. An attenuation of 0 will produce a +#/ non-attenuated sound, i.e. its volume will always be the same +#/ whether it is heard from near or from far. On the other hand, +#/ an attenuation value such as 100 will make the sound fade out +#/ very quickly as it gets further from the listener. +#/ The default value of the attenuation is 1. +proc setAttenuation*(sound: PSound; attenuation: cfloat){. + cdecl, importc: "sfSound_setAttenuation", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Change the current playing position of a sound +#/ +#/ The playing position can be changed when the sound is +#/ either paused or playing. +proc setPlayingOffset*(sound: PSound; timeOffset: sfml.TTime){. + cdecl, importc: "sfSound_setPlayingOffset", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the pitch of a sound +proc getPitch*(sound: PSound): cfloat{. + cdecl, importc: "sfSound_getPitch", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the volume of a sound +proc getVolume*(sound: PSound): cfloat{. + cdecl, importc: "sfSound_getVolume", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the 3D position of a sound in the audio scene +proc getPosition*(sound: PSound): TVector3f{. + cdecl, importc: "sfSound_getPosition", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Tell whether a sound's position is relative to the +#/ listener or is absolute +proc isRelativeToListener*(sound: PSound): bool{. + cdecl, importc: "sfSound_isRelativeToListener", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the minimum distance of a sound +proc getMinDistance*(sound: PSound): cfloat{. + cdecl, importc: "sfSound_getMinDistance", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the attenuation factor of a sound +proc getAttenuation*(sound: PSound): cfloat{. + cdecl, importc: "sfSound_getAttenuation", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the current playing position of a sound +proc getPlayingOffset*(sound: PSound): TTime{. + cdecl, importc: "sfSound_getPlayingOffset", dynlib: Lib.} + +#////////////////////////////////////////////////////////// +# Headers +#////////////////////////////////////////////////////////// +#////////////////////////////////////////////////////////// +#/ \brief Create a new sound buffer and load it from a file +#/ +#/ Here is a complete list of all the supported audio formats: +#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam, +#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64. +#/ +#/ \param filename Path of the sound file to load +#/ +#/ \return A new sfSoundBuffer object (NULL if failed) +#/ +#////////////////////////////////////////////////////////// +proc newSoundBuffer*(filename: cstring): PSoundBuffer{. + cdecl, importc: "sfSoundBuffer_createFromFile", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Create a new sound buffer and load it from a file in memory +#/ +#/ Here is a complete list of all the supported audio formats: +#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam, +#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64. +#/ +#/ \param data Pointer to the file data in memory +#/ \param sizeInBytes Size of the data to load, in bytes +#/ +#/ \return A new sfSoundBuffer object (NULL if failed) +#/ +#////////////////////////////////////////////////////////// +proc newSoundBuffer*(data: pointer; sizeInBytes: cint): PSoundBuffer{. + cdecl, importc: "sfSoundBuffer_createFromMemory", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Create a new sound buffer and load it from a custom stream +#/ +#/ Here is a complete list of all the supported audio formats: +#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam, +#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64. +#/ +#/ \param stream Source stream to read from +#/ +#/ \return A new sfSoundBuffer object (NULL if failed) +#/ +#////////////////////////////////////////////////////////// +proc newSoundBuffer*(stream: PInputStream): PSoundBuffer{. + cdecl, importc: "sfSoundBuffer_createFromStream", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Create a new sound buffer and load it from an array of samples in memory +#/ +#/ The assumed format of the audio samples is 16 bits signed integer +#/ (sfInt16). +#/ +#/ \param samples Pointer to the array of samples in memory +#/ \param sampleCount Number of samples in the array +#/ \param channelCount Number of channels (1 = mono, 2 = stereo, ...) +#/ \param sampleRate Sample rate (number of samples to play per second) +#/ +#/ \return A new sfSoundBuffer object (NULL if failed) +#/ +#////////////////////////////////////////////////////////// +proc createFromSamples*(samples: ptr int16; sampleCount: cuint; + channelCount: cuint; sampleRate: cuint): PSoundBuffer{. + cdecl, importc: "sfSoundBuffer_createFromSamples", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Create a new sound buffer by copying an existing one +#/ +#/ \param soundBuffer Sound buffer to copy +#/ +#/ \return A new sfSoundBuffer object which is a copy of \a soundBuffer +#/ +#////////////////////////////////////////////////////////// +proc copy*(soundBuffer: PSoundBuffer): PSoundBuffer{. + cdecl, importc: "sfSoundBuffer_copy", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Destroy a sound buffer +#/ +#/ \param soundBuffer Sound buffer to destroy +#/ +#////////////////////////////////////////////////////////// +proc destroy*(soundBuffer: PSoundBuffer){. + cdecl, importc: "sfSoundBuffer_destroy", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Save a sound buffer to an audio file +#/ +#/ Here is a complete list of all the supported audio formats: +#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam, +#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64. +#/ +#/ \param soundBuffer Sound buffer object +#/ \param filename Path of the sound file to write +#/ +#/ \return sfTrue if saving succeeded, sfFalse if it failed +#/ +#////////////////////////////////////////////////////////// +proc saveToFile*(soundBuffer: PSoundBuffer; filename: cstring): bool {. + cdecl, importc: "sfSoundBuffer_saveToFile", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the array of audio samples stored in a sound buffer +#/ +#/ The format of the returned samples is 16 bits signed integer +#/ (sfInt16). The total number of samples in this array +#/ is given by the sfSoundBuffer_getSampleCount function. +#/ +#/ \param soundBuffer Sound buffer object +#/ +#/ \return Read-only pointer to the array of sound samples +#/ +#////////////////////////////////////////////////////////// +proc sfSoundBuffer_getSamples*(soundBuffer: PSoundBuffer): ptr Int16{. + cdecl, importc: "sfSoundBuffer_getSamples", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the number of samples stored in a sound buffer +#/ +#/ The array of samples can be accessed with the +#/ sfSoundBuffer_getSamples function. +proc getSampleCount*(soundBuffer: PSoundBuffer): cint{. + cdecl, importc: "sfSoundBuffer_getSampleCount", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the sample rate of a sound buffer +#/ +#/ The sample rate is the number of samples played per second. +#/ The higher, the better the quality (for example, 44100 +#/ samples/s is CD quality). +proc getSampleRate*(soundBuffer: PSoundBuffer): cuint{. + cdecl, importc: "sfSoundBuffer_getSampleRate", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the number of channels used by a sound buffer +#/ +#/ If the sound is mono then the number of channels will +#/ be 1, 2 for stereo, etc. +proc getChannelCount*(soundBuffer: PSoundBuffer): cuint{. + cdecl, importc: "sfSoundBuffer_getChannelCount", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the total duration of a sound buffer +#/ +#/ \param soundBuffer Sound buffer object +#/ +#/ \return Sound duration +#/ +#////////////////////////////////////////////////////////// +proc getDuration*(soundBuffer: PSoundBuffer): TTime{. + cdecl, importc: "sfSoundBuffer_getDuration", dynlib: Lib.} + +#////////////////////////////////////////////////////////// +#/ \brief Change the global volume of all the sounds and musics +#/ +#/ The volume is a number between 0 and 100; it is combined with +#/ the individual volume of each sound / music. +#/ The default value for the volume is 100 (maximum). +#/ +#/ \param volume New global volume, in the range [0, 100] +#/ +#////////////////////////////////////////////////////////// +proc listenerSetGlobalVolume*(volume: cfloat){. + cdecl, importc: "sfListener_setGlobalVolume", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the current value of the global volume +#/ +#/ \return Current global volume, in the range [0, 100] +#/ +#////////////////////////////////////////////////////////// +proc listenerGetGlobalVolume*(): cfloat{. + cdecl, importc: "sfListener_getGlobalVolume", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the position of the listener in the scene +#/ +#/ The default listener's position is (0, 0, 0). +#/ +#/ \param position New position of the listener +#/ +#////////////////////////////////////////////////////////// +proc listenerSetPosition*(position: TVector3f){. + cdecl, importc: "sfListener_setPosition", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the current position of the listener in the scene +#/ +#/ \return The listener's position +#/ +#////////////////////////////////////////////////////////// +proc listenerGetPosition*(): TVector3f{. + cdecl, importc: "sfListener_getPosition", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the orientation of the listener in the scene +#/ +#/ The orientation defines the 3D axes of the listener +#/ (left, up, front) in the scene. The orientation vector +#/ doesn't have to be normalized. +#/ The default listener's orientation is (0, 0, -1). +#/ +#/ \param position New direction of the listener +#/ +#////////////////////////////////////////////////////////// +proc listenerSetDirection*(orientation: TVector3f){. + cdecl, importc: "sfListener_setDirection", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the current orientation of the listener in the scene +#/ +#/ \return The listener's direction +#/ +#////////////////////////////////////////////////////////// +proc listenerGetDirection*(): TVector3f{. + cdecl, importc: "sfListener_getDirection", dynlib: Lib.} + +type + TSoundRecorderStartCallback* = proc (a2: pointer): bool {.cdecl.} + #/< Type of the callback used when starting a capture + TSoundRecorderProcessCallback* = proc(a2: ptr int16; a3: cuint; + a4: pointer): bool {.cdecl.} + #/< Type of the callback used to process audio data + TSoundRecorderStopCallback* = proc (a2: pointer){.cdecl.} + #/< Type of the callback used when stopping a capture +#////////////////////////////////////////////////////////// +#/ \brief Construct a new sound recorder from callback functions +#/ +#/ \param onStart Callback function which will be called when a new capture starts (can be NULL) +#/ \param onProcess Callback function which will be called each time there's audio data to process +#/ \param onStop Callback function which will be called when the current capture stops (can be NULL) +#/ \param userData Data to pass to the callback function (can be NULL) +#/ +#/ \return A new sfSoundRecorder object (NULL if failed) +#/ +#////////////////////////////////////////////////////////// +proc newSoundRecorder*(onStart: TSoundRecorderStartCallback; + onProcess: TSoundRecorderProcessCallback; + onStop: TSoundRecorderStopCallback; + userData: pointer = nil): PSoundRecorder{. + cdecl, importc: "sfSoundRecorder_create", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Destroy a sound recorder +#/ +#/ \param soundRecorder Sound recorder to destroy +#/ +#////////////////////////////////////////////////////////// +proc destroy*(soundRecorder: PSoundRecorder){. + cdecl, importc: "sfSoundRecorder_destroy", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Start the capture of a sound recorder +#/ +#/ The \a sampleRate parameter defines the number of audio samples +#/ captured per second. The higher, the better the quality +#/ (for example, 44100 samples/sec is CD quality). +#/ This function uses its own thread so that it doesn't block +#/ the rest of the program while the capture runs. +#/ Please note that only one capture can happen at the same time. +#/ +#/ \param soundRecorder Sound recorder object +#/ \param sampleRate Desired capture rate, in number of samples per second +#/ +#////////////////////////////////////////////////////////// +proc start*(soundRecorder: PSoundRecorder; sampleRate: cuint){. + cdecl, importc: "sfSoundRecorder_start", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Stop the capture of a sound recorder +#/ +#/ \param soundRecorder Sound recorder object +#/ +#////////////////////////////////////////////////////////// +proc stop*(soundRecorder: PSoundRecorder){. + cdecl, importc: "sfSoundRecorder_stop", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the sample rate of a sound recorder +#/ +#/ The sample rate defines the number of audio samples +#/ captured per second. The higher, the better the quality +#/ (for example, 44100 samples/sec is CD quality). +#/ +#/ \param soundRecorder Sound recorder object +#/ +#/ \return Sample rate, in samples per second +#/ +#////////////////////////////////////////////////////////// +proc getSampleRate*(soundRecorder: PSoundRecorder): cuint{. + cdecl, importc: "sfSoundRecorder_getSampleRate", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Check if the system supports audio capture +#/ +#/ This function should always be called before using +#/ the audio capture features. If it returns false, then +#/ any attempt to use sfSoundRecorder will fail. +#/ +#/ \return sfTrue if audio capture is supported, sfFalse otherwise +#/ +#////////////////////////////////////////////////////////// +proc soundRecorderIsAvailable*(): bool {. + cdecl, importc: "sfSoundRecorder_isAvailable", dynlib: Lib.} + +#////////////////////////////////////////////////////////// +#/ \brief Create a new sound buffer recorder +#/ +#/ \return A new sfSoundBufferRecorder object (NULL if failed) +#/ +#////////////////////////////////////////////////////////// +proc newSoundBufferRecorder*(): PSoundBufferRecorder{. + cdecl, importc: "sfSoundBufferRecorder_create", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Destroy a sound buffer recorder +#/ +#/ \param soundBufferRecorder Sound buffer recorder to destroy +#/ +#////////////////////////////////////////////////////////// +proc destroy*(soundBufferRecorder: PSoundBufferRecorder){. + cdecl, importc: "sfSoundBufferRecorder_destroy", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Start the capture of a sound recorder recorder +#/ +#/ The \a sampleRate parameter defines the number of audio samples +#/ captured per second. The higher, the better the quality +#/ (for example, 44100 samples/sec is CD quality). +#/ This function uses its own thread so that it doesn't block +#/ the rest of the program while the capture runs. +#/ Please note that only one capture can happen at the same time. +#/ +#/ \param soundBufferRecorder Sound buffer recorder object +#/ \param sampleRate Desired capture rate, in number of samples per second +#/ +#////////////////////////////////////////////////////////// +proc start*(soundBufferRecorder: PSoundBufferRecorder; sampleRate: cuint){. + cdecl, importc: "sfSoundBufferRecorder_start", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Stop the capture of a sound recorder +#/ +#/ \param soundBufferRecorder Sound buffer recorder object +#/ +#////////////////////////////////////////////////////////// +proc stop*(soundBufferRecorder: PSoundBufferRecorder){. + cdecl, importc: "sfSoundBufferRecorder_stop", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the sample rate of a sound buffer recorder +#/ +#/ The sample rate defines the number of audio samples +#/ captured per second. The higher, the better the quality +#/ (for example, 44100 samples/sec is CD quality). +#/ +#/ \param soundBufferRecorder Sound buffer recorder object +#/ +#/ \return Sample rate, in samples per second +#/ +#////////////////////////////////////////////////////////// +proc getSampleRate*(soundBufferRecorder: PSoundBufferRecorder): cuint{. + cdecl, importc: "sfSoundBufferRecorder_getSampleRate", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the sound buffer containing the captured audio data +#/ +#/ The sound buffer is valid only after the capture has ended. +#/ This function provides a read-only access to the internal +#/ sound buffer, but it can be copied if you need to +#/ make any modification to it. +#/ +#/ \param soundBufferRecorder Sound buffer recorder object +#/ +#/ \return Read-only access to the sound buffer +#/ +#////////////////////////////////////////////////////////// +proc getBuffer*(soundBufferRecorder: PSoundBufferRecorder): PSoundBuffer{. + cdecl, importc: "sfSoundBufferRecorder_getBuffer", dynlib: Lib.} + + +#////////////////////////////////////////////////////////// +#/ \brief defines the data to fill by the OnGetData callback +#/ +#////////////////////////////////////////////////////////// +type + PSoundStreamChunk* = ptr TSoundStreamChunk + TSoundStreamChunk*{.pure, final.} = object + samples*: ptr int16 #/< Pointer to the audio samples + sampleCount*: cuint #/< Number of samples pointed by Samples + + TSoundStreamGetDataCallback* = proc (a2: PSoundStreamChunk; + a3: pointer): bool{.cdecl.} + #/< Type of the callback used to get a sound stream data + TSoundStreamSeekCallback* = proc (a2: TTime; a3: pointer){.cdecl.} + #/< Type of the callback used to seek in a sound stream +#////////////////////////////////////////////////////////// +#/ \brief Create a new sound stream +#/ +#/ \param onGetData Function called when the stream needs more data (can't be NULL) +#/ \param onSeek Function called when the stream seeks (can't be NULL) +#/ \param channelCount Number of channels to use (1 = mono, 2 = stereo) +#/ \param sampleRate Sample rate of the sound (44100 = CD quality) +#/ \param userData Data to pass to the callback functions +#/ +#/ \return A new sfSoundStream object +#/ +#////////////////////////////////////////////////////////// +proc create*(onGetData: TSoundStreamGetDataCallback; onSeek: TSoundStreamSeekCallback; + channelCount: cuint; sampleRate: cuint; userData: pointer): PSoundStream{. + cdecl, importc: "sfSoundStream_create", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Destroy a sound stream +#/ +#/ \param soundStream Sound stream to destroy +#/ +#////////////////////////////////////////////////////////// +proc destroy*(soundStream: PSoundStream){. + cdecl, importc: "sfSoundStream_destroy", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Start or resume playing a sound stream +#/ +#/ This function starts the stream if it was stopped, resumes +#/ it if it was paused, and restarts it from beginning if it +#/ was it already playing. +#/ This function uses its own thread so that it doesn't block +#/ the rest of the program while the music is played. +#/ +#/ \param soundStream Sound stream object +#/ +#////////////////////////////////////////////////////////// +proc play*(soundStream: PSoundStream){. + cdecl, importc: "sfSoundStream_play", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Pause a sound stream +#/ +#/ This function pauses the stream if it was playing, +#/ otherwise (stream already paused or stopped) it has no effect. +#/ +#/ \param soundStream Sound stream object +#/ +#////////////////////////////////////////////////////////// +proc pause*(soundStream: PSoundStream){. + cdecl, importc: "sfSoundStream_pause", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Stop playing a sound stream +#/ +#/ This function stops the stream if it was playing or paused, +#/ and does nothing if it was already stopped. +#/ It also resets the playing position (unlike sfSoundStream_pause). +#/ +#/ \param soundStream Sound stream object +#/ +#////////////////////////////////////////////////////////// +proc stop*(soundStream: PSoundStream){. + cdecl, importc: "sfSoundStream_stop", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the current status of a sound stream (stopped, paused, playing) +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Current status +#/ +#////////////////////////////////////////////////////////// +proc getStatus*(soundStream: PSoundStream): TSoundStatus{. + cdecl, importc: "sfSoundStream_getStatus", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Return the number of channels of a sound stream +#/ +#/ 1 channel means a mono sound, 2 means stereo, etc. +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Number of channels +#/ +#////////////////////////////////////////////////////////// +proc getChannelCount*(soundStream: PSoundStream): cuint{. + cdecl, importc: "sfSoundStream_getChannelCount", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the sample rate of a sound stream +#/ +#/ The sample rate is the number of audio samples played per +#/ second. The higher, the better the quality. +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Sample rate, in number of samples per second +#/ +#////////////////////////////////////////////////////////// +proc getSampleRate*(soundStream: PSoundStream): cuint{. + cdecl, importc: "sfSoundStream_getSampleRate", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the pitch of a sound stream +#/ +#/ The pitch represents the perceived fundamental frequency +#/ of a sound; thus you can make a stream more acute or grave +#/ by changing its pitch. A side effect of changing the pitch +#/ is to modify the playing speed of the stream as well. +#/ The default value for the pitch is 1. +#/ +#/ \param soundStream Sound stream object +#/ \param pitch New pitch to apply to the stream +#/ +#////////////////////////////////////////////////////////// +proc setPitch*(soundStream: PSoundStream; pitch: cfloat){. + cdecl, importc: "sfSoundStream_setPitch", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the volume of a sound stream +#/ +#/ The volume is a value between 0 (mute) and 100 (full volume). +#/ The default value for the volume is 100. +#/ +#/ \param soundStream Sound stream object +#/ \param volume Volume of the stream +#/ +#////////////////////////////////////////////////////////// +proc setVolume*(soundStream: PSoundStream; volume: cfloat){. + cdecl, importc: "sfSoundStream_setVolume", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the 3D position of a sound stream in the audio scene +#/ +#/ Only streams with one channel (mono streams) can be +#/ spatialized. +#/ The default position of a stream is (0, 0, 0). +#/ +#/ \param soundStream Sound stream object +#/ \param position Position of the stream in the scene +#/ +#////////////////////////////////////////////////////////// +proc setPosition*(soundStream: PSoundStream; position: TVector3f){. + cdecl, importc: "sfSoundStream_setPosition", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Make a sound stream's position relative to the listener or absolute +#/ +#/ Making a stream relative to the listener will ensure that it will always +#/ be played the same way regardless the position of the listener. +#/ This can be useful for non-spatialized streams, streams that are +#/ produced by the listener, or streams attached to it. +#/ The default value is false (position is absolute). +#/ +#/ \param soundStream Sound stream object +#/ \param relative sfTrue to set the position relative, sfFalse to set it absolute +#/ +#////////////////////////////////////////////////////////// +proc setRelativeToListener*(soundStream: PSoundStream; relative: bool){. + cdecl, importc: "sfSoundStream_setRelativeToListener", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the minimum distance of a sound stream +#/ +#/ The "minimum distance" of a stream is the maximum +#/ distance at which it is heard at its maximum volume. Further +#/ than the minimum distance, it will start to fade out according +#/ to its attenuation factor. A value of 0 ("inside the head +#/ of the listener") is an invalid value and is forbidden. +#/ The default value of the minimum distance is 1. +#/ +#/ \param soundStream Sound stream object +#/ \param distance New minimum distance of the stream +#/ +#////////////////////////////////////////////////////////// +proc setMinDistance*(soundStream: PSoundStream; distance: cfloat){. + cdecl, importc: "sfSoundStream_setMinDistance", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set the attenuation factor of a sound stream +#/ +#/ The attenuation is a multiplicative factor which makes +#/ the stream more or less loud according to its distance +#/ from the listener. An attenuation of 0 will produce a +#/ non-attenuated stream, i.e. its volume will always be the same +#/ whether it is heard from near or from far. On the other hand, +#/ an attenuation value such as 100 will make the stream fade out +#/ very quickly as it gets further from the listener. +#/ The default value of the attenuation is 1. +#/ +#/ \param soundStream Sound stream object +#/ \param attenuation New attenuation factor of the stream +#/ +#////////////////////////////////////////////////////////// +proc setAttenuation*(soundStream: PSoundStream; attenuation: cfloat){. + cdecl, importc: "sfSoundStream_setAttenuation", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Change the current playing position of a sound stream +#/ +#/ The playing position can be changed when the stream is +#/ either paused or playing. +#/ +#/ \param soundStream Sound stream object +#/ \param timeOffset New playing position +#/ +#////////////////////////////////////////////////////////// +proc setPlayingOffset*(soundStream: PSoundStream; timeOffset: TTime){. + cdecl, importc: "sfSoundStream_setPlayingOffset", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Set whether or not a sound stream should loop after reaching the end +#/ +#/ If set, the stream will restart from beginning after +#/ reaching the end and so on, until it is stopped or +#/ sfSoundStream_setLoop(stream, sfFalse) is called. +#/ The default looping state for sound streams is false. +#/ +#/ \param soundStream Sound stream object +#/ \param loop sfTrue to play in loop, sfFalse to play once +#/ +#////////////////////////////////////////////////////////// +proc setLoop*(soundStream: PSoundStream; loop: bool){. + cdecl, importc: "sfSoundStream_setLoop", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the pitch of a sound stream +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Pitch of the stream +#/ +#////////////////////////////////////////////////////////// +proc getPitch*(soundStream: PSoundStream): cfloat{. + cdecl, importc: "sfSoundStream_getPitch", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the volume of a sound stream +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Volume of the stream, in the range [0, 100] +#/ +#////////////////////////////////////////////////////////// +proc getVolume*(soundStream: PSoundStream): cfloat{. + cdecl, importc: "sfSoundStream_getVolume", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the 3D position of a sound stream in the audio scene +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Position of the stream in the world +#/ +#////////////////////////////////////////////////////////// +proc getPosition*(soundStream: PSoundStream): TVector3f{. + cdecl, importc: "sfSoundStream_getPosition", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Tell whether a sound stream's position is relative to the +#/ listener or is absolute +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return sfTrue if the position is relative, sfFalse if it's absolute +#/ +#////////////////////////////////////////////////////////// +proc isRelativeToListener*(soundStream: PSoundStream): bool{. + cdecl, importc: "sfSoundStream_isRelativeToListener", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the minimum distance of a sound stream +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Minimum distance of the stream +#/ +#////////////////////////////////////////////////////////// +proc getMinDistance*(soundStream: PSoundStream): cfloat{. + cdecl, importc: "sfSoundStream_getMinDistance", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the attenuation factor of a sound stream +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Attenuation factor of the stream +#/ +#////////////////////////////////////////////////////////// +proc getAttenuation*(soundStream: PSoundStream): cfloat{. + cdecl, importc: "sfSoundStream_getAttenuation", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Tell whether or not a sound stream is in loop mode +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return sfTrue if the music is looping, sfFalse otherwise +#/ +#////////////////////////////////////////////////////////// +proc getLoop*(soundStream: PSoundStream): bool{. + cdecl, importc: "sfSoundStream_getLoop", dynlib: Lib.} +#////////////////////////////////////////////////////////// +#/ \brief Get the current playing position of a sound stream +#/ +#/ \param soundStream Sound stream object +#/ +#/ \return Current playing position +#/ +#////////////////////////////////////////////////////////// +proc getPlayingOffset*(soundStream: PSoundStream): TTime{. + cdecl, importc: "sfSoundStream_getPlayingOffset", dynlib: Lib.} diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim new file mode 100644 index 000000000..31473b17a --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim @@ -0,0 +1,15 @@ +import sfml +{.deadCodeElim: on.} +let + Black*: TColor = color(0, 0, 0) + White*: TColor = color(255, 255, 255) + Red*: TColor = color(255, 0, 0) + Green*: TColor = color(0, 255, 0) + Blue*: TColor = color(0, 0, 255) + Yellow*: TColor = color(255, 255, 0) + Magenta*: TColor = color(255, 0, 255) + Cyan*: TColor = color(0, 255, 255) + Transparent*: TColor = color(0, 0, 0, 0) + Gray* = color(84, 84, 84) + RoyalBlue* = color(65, 105, 225) +##todo: define more colors lul \ No newline at end of file diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim new file mode 100644 index 000000000..474d249aa --- /dev/null +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim @@ -0,0 +1,2 @@ +import sfml, math, strutils +{.deadCodeElim: on.} diff --git a/tests/manyloc/keineschweine/enet_server/enet_client.nim b/tests/manyloc/keineschweine/enet_server/enet_client.nim new file mode 100644 index 000000000..f4c8732e3 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/enet_client.nim @@ -0,0 +1,228 @@ +import enet, strutils, + sfml, sfml_colors, sg_gui, input_helpers, + math_helpers, sg_packets, estreams, tables, + json, sg_assets, client_helpers +if enetInit() != 0: + quit "Could not initialize ENet" +type + TClientSettings = object + resolution*: TVideoMode + offlineFile: string + dirserver: tuple[host: string, port: int16] + website*: string +var + clientSettings: TClientSettings + event: enet.TEvent + bConnected = false + runServer = true + gui = newGuiContainer() + zonelist = newGuiContainer() + kc = newKeyClient(setActive = true) + clock = newClock() + chatBox: PMessageArea + chatInput: PTextEntry + loginBtn, playBtn: PButton + fpsText = newText("", guiFont, 18) + connectionButtons: seq[PButton] + connectButton: PButton + u_alias, u_passwd: PTextEntry + dirServer: PServer + zone: PServer + showZoneList = false + myCreds = newScLogin(0, "", "") ##my session token + +proc handleChat(server: PServer; buf: PBuffer) = + let msg = readScChat(buf) + chatBox.add msg +proc handlePlayerLogin(server: PServer; buf: PBuffer) = + let login = readScLogin(buf) + myCreds = login + echo("I am ", $myCreds) + + +kc.registerHandler MouseLeft, down, proc() = + gui.click(input_helpers.getMousePos()) + +block: + var pos = vec2f(15, 550) + chatBox = gui.newMessageArea(pos) + pos.y += 20 + chatInput = gui.newTextEntry("...", pos, proc() = + sendPubChat dirServer, chatInput.getText() + chatInput.clearText()) + +gui.setActive(chatInput) + +proc dispMessage(args: varargs[string, `$`]) = + var s = "" + for it in items(args): + s.add it + chatbox.add(s) +proc dispMessage(text: string) {.inline.} = + chatbox.add(text) +proc dispError(text: string) {.inline.} = + chatBox.add(newScChat(kind = CError, text = text)) + +proc updateButtons() = + let conn = dirServer.connected + for b in connectionButtons: setEnabled(b, conn) + if conn: + connectButton.setString "Disconnect" + else: + connectButton.setString "Connect" + +proc poll(serv: PServer; timeout: cuint = 30) = + if serv.isNil or serv.host.isNil: return + if serv.connected: + while serv.host.hostService(event, timeout) > 0: + case event.kind + of EvtReceive: + var buf = newBuffer(event.packet) + + serv.handlePackets(buf) + + event.packet.destroy() + of EvtDisconnect: + dispMessage "Disconnected" + serv.connected = false + event.peer.data = nil + updateButtons() + of EvtNone: discard + else: + echo repr(event) + else: + if serv.host.hostService(event, timeout) > 0 and event.kind == EvtConnect: + dispMessage "Connected" + serv.connected = true + if serv.peer != event.peer: + serv.peer = event.peer + event.peer.data = serv + updateButtons() + +proc tryLogin*(b: PButton) = + var login = newCsLogin( + alias = u_alias.getText(), + passwd = u_passwd.getText()) + dirServer.send HLogin, login +proc tryTransition*(b: PButton) = + #zone.writePkt HZoneJoinReq, myCreds +proc tryConnect*(b: PButton) = + if not dirServer.connected: + var error: string + if not dirServer.connect( + clientSettings.dirServer.host, + clientSettings.dirServer.port, + error): + dispError(error) + else: + dirServer.peer.disconnect(1) + +proc playOffline*(b: PButton) = + var errors: seq[string] = @[] + if loadSettingsFromFile(clientSettings.offlineFile, errors): + transition() + else: + dispMessage "Errors reading the file (", clientSettings.offlineFile, "):" + for e in errors: dispError(e) + +proc getClientSettings*(): TClientSettings = + result = clientSettings + + +proc lobbyInit*() = + var s = json.parseFile("./client_settings.json") + clientSettings.offlineFile = "data/" + clientSettings.offlineFile.add s["default-file"].str + let dirserv = s["directory-server"] + clientSettings.dirserver.host = dirserv["host"].str + clientSettings.dirserver.port = dirserv["port"].num.int16 + clientSettings.resolution.width = s["resolution"][0].num.cint + clientSettings.resolution.height= s["resolution"][1].num.cint + clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint + clientSettings.website = s["website"].str + zonelist.setPosition(vec2f(200.0, 100.0)) + connectionButtons = @[] + + var pos = vec2f(10, 10) + u_alias = gui.newTextEntry( + if s.existsKey("alias"): s["alias"].str else: "alias", + pos) + pos.y += 20 + u_passwd = gui.newTextEntry("buzz", pos) + pos.y += 20 + connectionButtons.add(gui.newButton( + text = "Login", + position = pos, + onClick = tryLogin, + startEnabled = false)) + pos.y += 20 + fpsText.setPosition pos + pos.y += 20 + connectButton = gui.newButton( + text = "Connect", + position = pos, + onClick = tryConnect) + pos.y += 20 + gui.newButton("Test Files", position = pos, onClick = proc(b: PButton) = + var req = newCsZoneJoinReq(myCreds) + dirServer.send HZoneJoinReq, req) + pos.y += 20 + connectionButtons.add(gui.newButton( + text = "Test Chat", + position = pos, + onClick = (proc(b: PButton) = + var pkt = newCsChat(text = "ohai") + dirServer.send HChat, pkt), + startEnabled = false)) + pos.y += 20 + downloadProgress.setPosition(pos) + downloadProgress.bg.setFillColor(color(34, 139, 34)) + downloadProgress.bg.setSize(vec2f(0, 0)) + gui.add(downloadProgress) + + playBtn = gui.newButton( + text = "Play", + position = vec2f(680.0, 8.0), + onClick = tryTransition, + startEnabled = false) + gui.newButton( + text = "Play Offline", + position = vec2f(680.0, 28.0), + onClick = playOffline) + discard """gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) = + messageArea.scrollBack += 1 + update(messageArea)) + gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) = + messageArea.scrollBack -= 1 + update(messageArea)) + gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) = + for i in 0.. <30: + dispMessage($i))""" + dirServer = newServer() + dirServer.addHandler HChat, handleChat + dirServer.addHandler HLogin, handlePlayerLogin + dirServer.addHandler HFileTransfer, client_helpers.handleFilePartRecv + dirServer.addHandler HChallengeResult, client_helpers.handleFileChallengeResult + dirServer.addHandler HFileChallenge, client_helpers.handleFileChallenge + +proc lobbyReady*() = + kc.setActive() + gui.setActive(u_alias) + +var i = 0 +proc lobbyUpdate*(dt: float) = + dirServer.poll() + #let res = disp.poll() + gui.update(dt) + i = (i + 1) mod 60 + if i == 0: + fpsText.setString("FPS: "& ff(1.0/dt)) + +proc lobbyDraw*(window: PRenderWindow) = + window.clear(Black) + window.draw chatBox + window.draw gui + window.draw fpsText + if showZonelist: window.draw zonelist + window.display() + diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim new file mode 100644 index 000000000..6dd1a6a7f --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim @@ -0,0 +1,294 @@ +import enet, strutils, idgen, tables, math_helpers, + estreams, sg_packets, server_utils, sg_assets, client_helpers +when appType == "gui": + import sfml, sfml_colors, sg_gui, + input_helpers, sfml_stuff +else: + import times +type + TCallback = proc(client: PClient; buffer: PBuffer) +var + server: PHost + dirServer: PServer + standAloneMode = true + event: enet.TEvent + clientID = newIDGen[int32]() + clients = initTable[int32, PClient](64) + handlers = initTable[char, TCallback](32) + +when appType == "gui": + var + gui = newGuiContainer() + chatBox = gui.newMessageArea(vec2f(15, 550)) + window = newRenderWindow(videoMode(800, 600, 32), "Sup yo", sfDefaultSTyle) + mousepos = newText("", guiFont, 16) + fpsText = mousePos.copy() + inputClient = newKeyClient(setActive = true) + chatBox.sizeVisible = 30 + mousePos.setColor(Green) + fpsText.setposition(vec2f(0, 20)) + inputClient.registerHandler MouseLeft, down, proc() = + gui.click(input_helpers.getMousePos()) + inputClient.registerHandler MouseMiddle, down, proc() = + let pos = input_helpers.getMousePos() + mousePos.setString("($1,$2)".format(ff(pos.x), ff(pos.y))) + mousePos.setPosition(pos) + proc dispMessage(args: varargs[string, `$`]) = + var s = "" + for it in items(args): + s.add it + chatbox.add(s) + proc dispError(args: varargs[string, `$`]) = + var s = "" + for it in items(args): s.add(it) + chatBox.add(newScChat(kind = CError, text = s)) +else: + proc dispMessage(args: varargs[string, `$`]) = + var m = "" + for it in items(args): m.add(it) + echo "<msg> ", m + proc dispError(args: varargs[string, `$`]) = + var m = "" + for it in items(args): m.add(it) + echo "**", m + + +var pubChatQueue = newBuffer(1024) +proc queuePub(sender: PClient, msg: CsChat) = + var chat = newScChat(kind = CPub, fromPlayer = sender.alias, text = msg.text) + pubChatQueue.write(HChat) + pubChatQueue.pack(chat) +proc flushPubChat() = + if pubChatQueue.isDirty: + let packet = pubChatQueue.toPacket(FlagReliable) + for id, client in pairs(clients): + discard client.peer.send(0.cuchar, packet) + pubChatQueue.flush() + +handlers[HChat] = proc(client: PClient; buffer: PBuffer) = + var chat = readCsChat(buffer) + + if not client.auth: + client.sendError("You are not logged in.") + return + #if chat.target != "": ##private + # if alias2client.hasKey(chat.target): + # alias2client[chat.target].forwardPrivate(client, chat.text) + #else: + + dispmessage("<", client.alias, "> ", chat.text) + queuePub(client, chat) + +handlers[HLogin] = proc(client: PClient; buffer: PBuffer) = + var info = readCsLogin(buffer) + if client.auth: + client.sendError "You are already logged in." + return + client.alias = info.alias + client.auth = true + var resp = newScLogin(client.id, client.alias, "sessionkeylulz") + client.send HLogin, resp + client.sendMessage "welcome" + dispMessage("Client logged in: ", client) + + +handlers[HFileTransfer] = server_utils.handleFilePartAck +handlers[HFileChallenge] = server_utils.handleFileChallengeResp + +handlers[HZoneJoinReq] = proc(client: PClient; buffer: PBuffer) = + var info = readCsZoneJoinReq(buffer) + dispmessage "Got zone join request" + client.startVerifyingFiles() + + + +when isMainModule: + import parseopt, matchers, os, json + + + if enetInit() != 0: + quit "Could not initialize ENet" + + var address: enet.TAddress + + block: + var zoneCfgFile = "./server_settings.json" + for kind, key, val in getOpt(): + case kind + of cmdShortOption, cmdLongOption: + case key + of "f", "file": + if existsFile(val): + zoneCfgFile = val + else: + echo("File does not exist: ", val) + else: + echo("Unknown option: ", key," ", val) + else: + echo("Unknown option: ", key, " ", val) + var jsonSettings = parseFile(zoneCfgFile) + let + port = uint16(jsonSettings["port"].num) + zoneFile = jsonSettings["settings"].str + dirServerInfo = jsonSettings["dirserver"] + + address.host = EnetHostAny + address.port = port + + var path = getAppDir()/../"data"/zoneFile + if not existsFile(path): + echo("Zone settings file does not exist: ../data/", zoneFile) + echo(path) + quit(1) + + discard """block: + var + TestFile: FileChallengePair + contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz") + testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) + testFile.file = checksumStr(contents) + myAssets.add testFile""" + + setCurrentDir getAppDir().parentDir() + let zonesettings = readFile(path) + var + errors: seq[string] = @[] + if not loadSettings(zoneSettings, errors): + echo("You have errors in your zone settings:") + for e in errors: echo("**", e) + quit(1) + errors.setLen 0 + + var pair: FileChallengePair + pair.challenge.file = zoneFile + pair.challenge.assetType = FZoneCfg + pair.challenge.fullLen = zoneSettings.len.int32 + pair.file = checksumStr(zoneSettings) + myAssets.add pair + + allAssets: + if not load(asset): + echo "Invalid or missing file ", file + else: + var pair: FileChallengePair + pair.challenge.file = file + pair.challenge.assetType = assetType + pair.challenge.fullLen = getFileSize( + expandPath(assetType, file)).int32 + pair.file = asset.contents + myAssets.add pair + + echo "Zone has ", myAssets.len, " associated assets" + + dirServer = newServer() + + dirServer.addHandler HDsMsg, proc(serv: PServer; buffer: PBuffer) = + var m = readDsMsg(buffer) + dispMessage("<DirServer> ", m.msg) + dirServer.addHandler HZoneLogin, proc(serv: PServer; buffer: PBuffer) = + let loggedIn = readDsZoneLogin(buffer).status + if loggedIn: + #dirServerConnected = true + + if dirServerInfo.kind == JArray: + var error: string + if not dirServer.connect(dirServerInfo[0].str, dirServerInfo[1].num.int16, error): + dispError("<DirServer> "&error) + + + server = enet.createHost(address, 32, 2, 0, 0) + if server == nil: + quit "Could not create the server!" + + dispMessage("Listening on port ", address.port) + + var + serverRunning = true + when appType == "gui": + var frameRate = newClock() + var pubChatDelay = newClock() + else: + var frameRate = epochTime() + var pubChatDelay = frameRate + + while serverRunning: + when appType == "gui": + let dt = frameRate.restart.asMilliseconds().float / 1000.0 + + for event in window.filterEvents(): + case event.kind + of sfml.EvtClosed: + window.close() + serverRunning = false + else: + discard + else: + let dt = epochTime() - frameRate ##is this right? probably not + frameRate = epochTime() + + while server.hostService(event, 10) > 0: + case event.kind + of EvtConnect: + var client = newClient() + clients[client.id] = client + + event.peer.data = addr client.id + client.peer = event.peer + + dispMessage("New client connected ", client) + + var + msg = "hello" + resp = createPacket(cstring(msg), msg.len + 1, FlagReliable) + + if event.peer.send(0.cuchar, resp) < 0: + echo "FAILED" + else: + echo "Replied" + of EvtReceive: + let client = clients[cast[ptr int32](event.peer.data)[]] + + var buf = newBuffer(event.packet) + let k = buf.readChar() + if handlers.hasKey(k): + handlers[k](client, buf) + else: + dispError("Unknown packet from ", client) + + destroy(event.packet) + of EvtDisconnect: + var + id = cast[ptr int32](event.peer.data)[] + client = clients[id] + if client.isNil: + disperror("CLIENT IS NIL!") + dispmessage(event.peer.data.isNil) + else: + dispMessage(clients[id], " disconnected") + GCUnref(clients[id]) + clients.del id + + event.peer.data = nil + else: + discard + + when appType == "gui": + fpsText.setString(ff(1.0/dt)) + if pubChatDelay.getElapsedTime.asSeconds > 0.25: + pubChatDelay.restart() + flushPubChat() + else: + pubChatDelay -= dt + if frameRate - pubChatDelay > 0.25: + flushPubChat() + + when appType == "gui": + window.clear(Black) + window.draw(GUI) + window.draw chatbox + window.draw mousePos + window.draw fpstext + window.display() + + server.destroy() + enetDeinit() \ No newline at end of file diff --git a/tests/manyloc/keineschweine/enet_server/nakefile.nim b/tests/manyloc/keineschweine/enet_server/nakefile.nim new file mode 100644 index 000000000..1ca93a340 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/nakefile.nim @@ -0,0 +1,13 @@ +import nake +nakeimports + +const + ServerDefines = "-d:NoSFML --forceBuild" + +task "server", "build the server": + if shell("nimrod", ServerDefines, "-r", "compile", "enet_server") != 0: + quit "Failed to build" +task "gui", "build the server GUI mode": + if shell("nimrod", "--app:gui", ServerDefines, "-r", "compile", "enet_server") != 0: + quit "Failed to build" + diff --git a/tests/manyloc/keineschweine/enet_server/nimrod.cfg b/tests/manyloc/keineschweine/enet_server/nimrod.cfg new file mode 100644 index 000000000..72ef47ee0 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/nimrod.cfg @@ -0,0 +1,9 @@ +path = ".." +path = "../dependencies/sfml" +path = "../dependencies/enet" +path = "../dependencies/nake" +path = "../dependencies/genpacket" +path = "../lib" +define = "noChipmunk" +define = "noSFML" + diff --git a/tests/manyloc/keineschweine/enet_server/server_settings.json b/tests/manyloc/keineschweine/enet_server/server_settings.json new file mode 100644 index 000000000..7d2f1d822 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/server_settings.json @@ -0,0 +1,8 @@ +{ + "name": "Alpha Zone", + "desc": "Beta Testing", + "host": "localhost", + "port": 8024, + "settings": "alphazone.json", + "dirserver":["localhost",2049,"alphazone","skittles"] +} diff --git a/tests/manyloc/keineschweine/enet_server/server_utils.nim b/tests/manyloc/keineschweine/enet_server/server_utils.nim new file mode 100644 index 000000000..8e8141075 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/server_utils.nim @@ -0,0 +1,120 @@ +import enet, sg_packets, estreams, md5, zlib_helpers, client_helpers, strutils, + idgen, sg_assets, tables, os +type + PClient* = ref object + id*: int32 + auth*: bool + alias*: string + peer*: PPeer + + FileChallengePair* = tuple[challenge: ScFileChallenge; file: TChecksumFile] + PFileChallengeSequence* = ref TFileChallengeSequence + TFileChallengeSequence = object + index: int #which file is active + transfer: ScFileTransfer + file: ptr FileChallengePair +var + clientID = newIdGen[int32]() + myAssets*: seq[FileChallengePair] = @[] + fileChallenges = initTable[int32, PFileChallengeSequence](32) +const FileChunkSize = 256 + +proc free(client: PClient) = + if client.id != 0: + fileChallenges.del client.id + clientID.del client.id +proc newClient*(): PClient = + new(result, free) + result.id = clientID.next() + result.alias = "billy" + +proc `$`*(client: PClient): string = + result = "$1:$2".format(client.id, client.alias) + +proc send*[T](client: PClient; pktType: char; pkt: var T) = + var buf = newBuffer(128) + buf.write pktType + buf.pack pkt + discard client.peer.send(0.cuchar, buf, flagReliable) + +proc sendMessage*(client: PClient; txt: string) = + var m = newScChat(CSystem, text = txt) + client.send HChat, m +proc sendError*(client: PClient; error: string) = + var m = newScChat(CError, text = error) + client.send HChat, m + + + + +proc next*(challenge: PFileChallengeSequence, client: PClient) +proc sendChunk*(challenge: PFileChallengeSequence, client: PClient) + +proc startVerifyingFiles*(client: PClient) = + var fcs: PFileChallengeSequence + new(fcs) + fcs.index = -1 + fileChallenges[client.id] = fcs + next(fcs, client) + +proc next*(challenge: PFileChallengeSequence, client: PClient) = + inc(challenge.index) + if challenge.index >= myAssets.len: + client.sendMessage "You are cleared to enter" + fileChallenges.del client.id + return + else: + echo myAssets.len, "assets" + challenge.file = addr myAssets[challenge.index] + client.send HFileChallenge, challenge.file.challenge # :rolleyes: + echo "sent challenge" + +proc sendChunk*(challenge: PFileChallengeSequence, client: PClient) = + let size = min(FileChunkSize, challenge.transfer.fileSize - challenge.transfer.pos) + challenge.transfer.data.setLen size + copyMem( + addr challenge.transfer.data[0], + addr challenge.file.file.compressed[challenge.transfer.pos], + size) + client.send HFileTransfer, challenge.transfer + echo "chunk sent" + +proc startSend*(challenge: PFileChallengeSequence, client: PClient) = + challenge.transfer.fileSize = challenge.file.file.compressed.len().int32 + challenge.transfer.pos = 0 + challenge.transfer.data = "" + challenge.transfer.data.setLen FileChunkSize + challenge.sendChunk(client) + echo "starting xfer" + +## HFileTransfer +proc handleFilePartAck*(client: PClient; buffer: PBuffer) = + echo "got filepartack" + var + ftrans = readCsFilepartAck(buffer) + fcSeq = fileChallenges[client.id] + fcSeq.transfer.pos = ftrans.lastPos + fcSeq.sendChunk client + +## HFileCHallenge +proc handleFileChallengeResp*(client: PClient; buffer: PBuffer) = + echo "got file challenge resp" + var + fcResp = readCsFileChallenge(buffer) + fcSeq = fileChallenges[client.id] + let index = $(fcSeq.index + 1) / $(myAssets.len) + if fcResp.needFile: + client.sendMessage "Sending file... "&index + fcSeq.startSend(client) + else: + var resp = newScChallengeResult(false) + if fcResp.checksum == fcSeq.file.file.sum: ##client is good + client.sendMessage "Checksum is good. "&index + resp.status = true + client.send HChallengeResult, resp + fcSeq.next(client) + else: + client.sendMessage "Checksum is bad, sending file... "&index + client.send HChallengeResult, resp + fcSeq.startSend(client) + diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim new file mode 100644 index 000000000..e868b96a5 --- /dev/null +++ b/tests/manyloc/keineschweine/keineschweine.nim @@ -0,0 +1,725 @@ +import + os, math, strutils, gl, tables, + sfml, sfml_audio, sfml_colors, chipmunk, math_helpers, + input_helpers, animations, game_objects, sfml_stuff, map_filter, + sg_gui, sg_assets, sound_buffer, enet_client +when defined(profiler): + import nimprof +{.deadCodeElim: on.} +type + PPlayer* = ref TPlayer + TPlayer* = object + id: uint16 + vehicle: PVehicle + spectator: bool + alias: string + nameTag: PText + items: seq[PItem] + PVehicle* = ref TVehicle + TVehicle* = object + body*: chipmunk.PBody + shape*: chipmunk.PShape + record*: PVehicleRecord + sprite*: PSprite + spriteRect*: TIntRect + occupant: PPlayer + when false: + position*: TVector2f + velocity*: TVector2f + angle*: float + PItem* = ref object + record: PItemRecord + cooldown: float + PLiveBullet* = ref TLiveBullet ##represents a live bullet in the arena + TLiveBullet* = object + lifetime*: float + dead: bool + anim*: PAnimation + record*: PBulletRecord + fromPlayer*: PPlayer + trailDelay*: float + body: chipmunk.PBody + shape: chipmunk.PShape +import vehicles +const + LGrabbable* = (1 shl 0).TLayers + LBorders* = (1 shl 1).TLayers + LPlayer* = ((1 shl 2) and LBorders.int).TLayers + LEnemy* = ((1 shl 4) and LBorders.int).TLayers + LEnemyFire* = (LPlayer).TLayers + LPlayerFire* = (LEnemy).TLayers + CTBullet = 1.TCollisionType + CTVehicle= 2.TCollisionType + ##temporary constants + W_LIMIT = 2.3 + V_LIMIT = 35 + MaxLocalBots = 3 +var + localPlayer: PPlayer + localBots: seq[PPlayer] = @[] + activeVehicle: PVehicle + myVehicles: seq[PVehicle] = @[] + objects: seq[PGameObject] = @[] + liveBullets: seq[PLiveBullet] = @[] + explosions: seq[PAnimation] = @[] + gameRunning = true + frameRate = newClock() + showStars = off + levelArea: TIntRect + videoMode: TVideoMode + window: PRenderWindow + worldView: PView + guiView: PView + space = newSpace() + ingameClient = newKeyClient("ingame") + specInputClient = newKeyClient("spec") + specGui = newGuiContainer() + stars: seq[PSpriteSheet] = @[] + playBtn: PButton + shipSelect = newGuiContainer() + delObjects: seq[int] = @[] + showShipSelect = false + myPosition: array[0..1, TVector3f] ##for audio positioning +let + nameTagOffset = vec2f(0.0, 1.0) +when defined(escapeMenuTest): + import browsers + var + escMenu = newGuiContainer(vec2f(100, 100)) + escMenuOpen = false + pos = vec2f(0, 0) + escMenu.newButton("Some Website", pos, proc(b: PButton) = + openDefaultBrowser(getClientSettings().website)) + pos.y += 20.0 + escMenu.newButton("Back to Lobby", pos, proc(b: PButton) = + echo "herro") + proc toggleEscape() = + escMenuOpen = not escMenuOpen + ingameClient.registerHandler(KeyEscape, down, toggleEscape) + specInputClient.registerHandler(KeyEscape, down, toggleEscape) +when defined(foo): + var mouseSprite: sfml.PCircleShape +when defined(recordMode): + var + snapshots: seq[PImage] = @[] + isRecording = false + proc startRecording() = + if snapshots.len > 100: return + echo "Started recording" + isRecording = true + proc stopRecording() = + if isRecording: + echo "Stopped recording. ", snapshots.len, " images." + isRecording = false + proc zeroPad*(s: string; minLen: int): string = + if s.len < minLen: + result = repeatChar(minLen - s.len, '0') + result.add s + else: + result = s + var + recordButton = newButton( + nil, text = "Record", position = vec2f(680, 50), + onClick = proc(b: PButton) = startRecording()) + +proc newNameTag*(text: string): PText = + result = newText() + result.setFont(guiFont) + result.setCharacterSize(14) + result.setColor(Red) + result.setString(text) + +var debugText = newNameTag("Loading...") +debugText.setPosition(vec2f(0.0, 600.0 - 50.0)) + +when defined(showFPS): + var fpsText = newNameTag("0") + #fpsText.setCharacterSize(16) + fpsText.setPosition(vec2f(300.0, (800 - 50).float)) + +proc mouseToSpace*(): TVector = + result = window.convertCoords(vec2i(getMousePos()), worldView).sfml2cp() + +proc explode*(b: PLiveBullet) +## TCollisionBeginFunc +proc collisionBulletPlayer(arb: PArbiter; space: PSpace; + data: pointer): Bool{.cdecl.} = + var + bullet = cast[PLiveBullet](arb.a.data) + target = cast[PVehicle](arb.b.data) + if target.occupant.isNil or target.occupant == bullet.fromPlayer: return + bullet.explode() + +proc angularDampingSim(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} = + body.w -= (body.w * 0.98 * dt) + body.updateVelocity(gravity, damping, dt) + +proc initLevel() = + loadAllAssets() + + if not space.isNil: space.destroy() + space = newSpace() + space.addCollisionHandler CTBullet, CTVehicle, collisionBulletPlayer, + nil, nil, nil, nil + + let levelSettings = getLevelSettings() + levelArea.width = levelSettings.size.x + levelArea.height= levelSettings.size.y + let borderSeq = @[ + vector(0, 0), vector(levelArea.width.float, 0.0), + vector(levelArea.width.float, levelArea.height.float), vector(0.0, levelArea.height.float)] + for i in 0..3: + var seg = space.addShape( + newSegmentShape( + space.staticBody, + borderSeq[i], + borderSeq[(i + 1) mod 4], + 8.0)) + seg.setElasticity 0.96 + seg.setLayers(LBorders) + if levelSettings.starfield.len > 0: + showStars = true + for sprite in levelSettings.starfield: + sprite.tex.setRepeated(true) + sprite.sprite.setTextureRect(levelArea) + sprite.sprite.setOrigin(vec2f(0, 0)) + stars.add(sprite) + var pos = vec2f(0.0, 0.0) + for veh in playableVehicles(): + shipSelect.newButton( + veh.name, + position = pos, + onClick = proc(b: PButton) = + echo "-__-") + pos.y += 18.0 + + +proc newItem*(record: PItemRecord): PItem = + new(result) + result.record = record +proc newItem*(name: string): PItem {.inline.} = + return newItem(fetchItm(name)) +proc canUse*(itm: PItem): bool = + if itm.cooldown > 0.0: return + return true +proc update*(itm: PItem; dt: float) = + if itm.cooldown > 0: + itm.cooldown -= dt + +proc free(obj: PLiveBullet) = + obj.shape.free + obj.body.free + obj.record = nil + + +template newExplosion(obj, animation): stmt = + explosions.add(newAnimation(animation, AnimOnce, obj.body.getPos.cp2sfml, obj.body.getAngle)) +template newExplosion(obj, animation, angle): stmt = + explosions.add(newAnimation(animation, AnimOnce, obj.body.getPos.cp2sfml, angle)) + +proc explode*(b: PLiveBullet) = + if b.dead: return + b.dead = true + space.removeShape b.shape + space.removeBody b.body + if not b.record.explosion.anim.isNil: + newExplosion(b, b.record.explosion.anim) + playSound(b.record.explosion.sound, b.body.getPos()) + +proc bulletUpdate(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} = + body.updateVelocity(gravity, damping, dt) + +template getPhysical() {.immediate.} = + result.body = space.addBody(newBody( + record.physics.mass, + record.physics.moment)) + result.shape = space.addShape( + chipmunk.newCircleShape( + result.body, + record.physics.radius, + vectorZero)) + +proc newBullet*(record: PBulletRecord; fromPlayer: PPlayer): PLiveBullet = + new(result, free) + result.anim = newAnimation(record.anim, AnimLoop) + result.fromPlayer = fromPlayer + result.lifetime = record.lifetime + result.record = record + getPhysical() + if fromPlayer == localPlayer: + result.shape.setLayers(LPlayerFire) + else: + result.shape.setLayers(LEnemyFire) + result.shape.setCollisionType CTBullet + result.shape.setUserData(cast[ptr TLiveBullet](result)) + let + fireAngle = fromPlayer.vehicle.body.getAngle() + fireAngleV = vectorForAngle(fireAngle) + result.body.setAngle fireAngle + result.body.setPos(fromPlayer.vehicle.body.getPos() + (fireAngleV * fromPlayer.vehicle.shape.getCircleRadius())) + #result.body.velocityFunc = bulletUpdate + result.body.setVel((fromPlayer.vehicle.body.getVel() * record.inheritVelocity) + (fireAngleV * record.baseVelocity)) + +proc update*(b: PLiveBullet; dt: float): bool = + if b.dead: return true + b.lifetime -= dt + b.anim.next(dt) + #b.anim.sprite.setPosition(b.body.getPos.floor()) + b.anim.setPos(b.body.getPos) + b.anim.setAngle(b.body.getAngle()) + if b.lifetime <= 0.0: + b.explode() + return true + b.trailDelay -= dt + if b.trailDelay <= 0.0: + b.trailDelay += b.record.trail.timer + if b.record.trail.anim.isNil: return + newExplosion(b, b.record.trail.anim) +proc draw*(window: PRenderWindow; b: PLiveBullet) {.inline.} = + draw(window, b.anim.sprite) + + +proc free*(veh: PVehicle) = + ("Destroying vehicle "& veh.record.name).echo + destroy(veh.sprite) + if veh.shape.isNil: "Free'd vehicle's shape was NIL!".echo + else: space.removeShape(veh.shape) + if veh.body.isNil: "Free'd vehicle's BODY was NIL!".echo + else: space.removeBody(veh.body) + veh.body.free() + veh.shape.free() + veh.sprite = nil + veh.body = nil + veh.shape = nil + + +proc newVehicle*(record: PVehicleRecord): PVehicle = + echo("Creating "& record.name) + new(result, free) + result.record = record + result.sprite = result.record.anim.spriteSheet.sprite.copy() + result.spriteRect = result.sprite.getTextureRect() + getPhysical() + result.body.setAngVelLimit W_LIMIT + result.body.setVelLimit result.record.handling.topSpeed + result.body.velocityFunc = angularDampingSim + result.shape.setCollisionType CTVehicle + result.shape.setUserData(cast[ptr TVehicle](result)) +proc newVehicle*(name: string): PVehicle = + result = newVehicle(fetchVeh(name)) + +proc update*(obj: PVehicle) = + obj.sprite.setPosition(obj.body.getPos.floor) + obj.spriteRect.left = (((-obj.body.getAngVel + W_LIMIT) / (W_LIMIT*2.0) * (obj.record.anim.spriteSheet.cols - 1).float).floor.int * obj.record.anim.spriteSheet.framew).cint + obj.spriteRect.top = ((obj.offsetAngle.wmod(TAU) / TAU) * obj.record.anim.spriteSheet.rows.float).floor.cint * obj.record.anim.spriteSheet.frameh.cint + obj.sprite.setTextureRect(obj.spriteRect) + + +proc newPlayer*(alias: string = "poo"): PPlayer = + new(result) + result.spectator = true + result.alias = alias + result.nameTag = newNameTag(result.alias) + result.items = @[] +proc updateItems*(player: PPlayer, dt: float) = + for i in items(player.items): + update(i, dt) +proc addItem*(player: PPlayer; name: string) = + player.items.add newItem(name) +proc useItem*(player: PPlayer; slot: int) = + if slot > player.items.len - 1: return + let item = player.items[slot] + if item.canUse: + item.cooldown += item.record.cooldown + let b = newBullet(item.record.bullet, player) + liveBullets.add(b) + sound_buffer.playSound(item.record.useSound, b.body.getPos) + +proc update*(obj: PPlayer) = + if not obj.spectator: + obj.vehicle.update() + obj.nameTag.setPosition(obj.vehicle.body.getPos.floor + (nameTagOffset * (obj.vehicle.record.physics.radius + 5).cfloat)) + +proc draw(window: PRenderWindow, player: PPlayer) {.inline.} = + if not player.spectator: + if player.vehicle != nil: + window.draw(player.vehicle.sprite) + window.draw(player.nameTag) + +proc setVehicle(p: PPlayer; v: PVehicle) = + p.vehicle = v #sorry mom, this is just how things worked out ;( + if not v.isNil: + v.occupant = p + +proc createBot() = + if localBots.len < MaxLocalBots: + var bot = newPlayer("Dodo Brown") + bot.setVehicle(newVehicle("Turret0")) + if bot.isNil: + echo "BOT IS NIL" + return + elif bot.vehicle.isNil: + echo "BOT VEH IS NIL" + return + localBots.add(bot) + bot.vehicle.body.setPos(vector(100, 100)) + echo "new bot at ", $bot.vehicle.body.getPos() + +var inputCursor = newVertexArray(sfml.Lines, 2) +inputCursor[0].position = vec2f(10.0, 10.0) +inputCursor[1].position = vec2f(50.0, 90.0) + +proc hasVehicle(p: PPlayer): bool {.inline.} = + result = not p.spectator and not p.vehicle.isNil + +proc setMyVehicle(v: PVehicle) {.inline.} = + activeVehicle = v + localPlayer.setVehicle v + +proc unspec() = + var veh = newVehicle("Turret0") + if not veh.isNil: + setMyVehicle veh + localPlayer.spectator = false + ingameClient.setActive + veh.body.setPos vector(100, 100) + veh.shape.setLayers(LPlayer) + when defined(debugWeps): + localPlayer.addItem("Mass Driver") + localPlayer.addItem("Neutron Bomb") + localPlayer.additem("Dem Lasers") + localPlayer.addItem("Mold Spore Beam") + localPlayer.addItem("Genericorp Mine") + localPlayer.addItem("Gravitic Bomb") +proc spec() = + setMyVehicle nil + localPlayer.spectator = true + specInputClient.setActive + +var + specLimiter = newClock() + timeBetweenSpeccing = 1.0 #seconds +proc toggleSpec() {.inline.} = + if specLimiter.getElapsedTime.asSeconds < timeBetweenSpeccing: + return + specLimiter.restart() + if localPlayer.isNil: + echo("OMG WTF PLAYER IS NILL!!") + elif localPlayer.spectator: unspec() + else: spec() + +proc addObject*(name: string) = + var o = newObject(name) + if not o.isNil: + echo "Adding object ", o + discard space.addBody(o.body) + discard space.addShape(o.shape) + o.shape.setLayers(LGrabbable) + objects.add(o) +proc explode(obj: PGameObject) = + echo obj, " exploded" + let ind = objects.find(obj) + if ind != -1: + delObjects.add ind +proc update(obj: PGameObject; dt: float) = + if not(obj.anim.next(dt)): + obj.explode() + else: + obj.anim.setPos(obj.body.getPos) + obj.anim.setAngle(obj.body.getAngle) + +proc toggleShipSelect() = + showShipSelect = not showShipSelect +proc handleLClick() = + let pos = input_helpers.getMousePos() + when defined(escapeMenuTest): + if escMenuOpen: + escMenu.click(pos) + return + if showShipSelect: + shipSelect.click(pos) + if localPlayer.spectator: + specGui.click(pos) + +ingameClient.registerHandler(KeyF12, down, proc() = toggleSpec()) +ingameClient.registerHandler(KeyF11, down, toggleShipSelect) +ingameClient.registerHandler(MouseLeft, down, handleLClick) +when defined(recordMode): + if not existsDir("data/snapshots"): + createDir("data/snapshots") + ingameClient.registerHandler(keynum9, down, proc() = + if not isRecording: startRecording() + else: stopRecording()) + ingameClient.registerHandler(keynum0, down, proc() = + if snapshots.len > 0 and not isRecording: + echo "Saving images (LOL)" + for i in 0..high(snapshots): + if not(snapshots[i].save("data/snapshots/image"&(zeroPad($i, 3))&".jpg")): + echo "Could not save" + snapshots[i].destroy() + snapshots.setLen 0) +when defined(DebugKeys): + ingameClient.registerHandler MouseRight, down, proc() = + echo($activevehicle.body.getAngle.vectorForAngle()) + ingameClient.registerHandler KeyBackslash, down, proc() = + createBot() + ingameClient.registerHandler(KeyNum1, down, proc() = + if localPlayer.items.len == 0: + localPlayer.addItem("Mass Driver") + echo "Gave you a mass driverz") + ingameClient.registerHandler(KeyL, down, proc() = + echo("len(livebullets) = ", len(livebullets))) + ingameClient.registerHandler(KeyRShift, down, proc() = + if keyPressed(KeyR): + echo("Friction: ", ff(activeVehicle.shape.getFriction())) + echo("Damping: ", ff(space.getDamping())) + elif keypressed(KeyM): + echo("Mass: ", activeVehicle.body.getMass.ff()) + echo("Moment: ", activeVehicle.body.getMoment.ff()) + elif keypressed(KeyI): + echo(repr(activeVehicle.record)) + elif keyPressed(KeyH): + activeVehicle.body.setPos(vector(100.0, 100.0)) + activeVehicle.body.setVel(vectorZero) + elif keyPressed(KeyComma): + activeVehicle.body.setPos mouseToSpace()) + ingameClient.registerHandler(KeyY, down, proc() = + const looloo = ["Asteroid1", "Asteroid2"] + addObject(looloo[random(looloo.len)])) + ingameClient.registerHandler(KeyO, down, proc() = + if objects.len == 0: + echo "Objects is empty" + return + for i, o in pairs(objects): + echo i, " ", o) + ingameClient.registerHandler(KeyLBracket, down, sound_buffer.report) + var + mouseJoint: PConstraint + mouseBody = space.addBody(newBody(CpInfinity, CpInfinity)) + ingameClient.registerHandler(MouseMiddle, down, proc() = + var point = mouseToSpace() + var shape = space.pointQueryFirst(point, LGrabbable, 0) + if not mouseJoint.isNil: + space.removeConstraint mouseJoint + mouseJoint.destroy() + mouseJoint = nil + if shape.isNil: + return + let body = shape.getBody() + mouseJoint = space.addConstraint( + newPivotJoint(mouseBody, body, vectorZero, body.world2local(point))) + mouseJoint.maxForce = 50000.0 + mouseJoint.errorBias = pow(1.0 - 0.15, 60)) + +var specCameraSpeed = 5.0 +specInputClient.registerHandler(MouseLeft, down, handleLClick) +specInputClient.registerHandler(KeyF11, down, toggleShipSelect) +specInputClient.registerHandler(KeyF12, down, proc() = toggleSpec()) +specInputClient.registerHandler(KeyLShift, down, proc() = specCameraSpeed *= 2) +specInputClient.registerHandler(KeyLShift, up, proc() = specCameraSpeed /= 2) + +specInputClient.registerHandler(KeyP, down, proc() = + echo("addObject(solar mold)") + addObject("Solar Mold")) + +proc resetForcesCB(body: PBody; data: pointer) {.cdecl.} = + body.resetForces() + +var frameCount= 0 +proc mainUpdate(dt: float) = + if localPlayer.spectator: + if keyPressed(KeyLeft): + worldView.move(vec2f(-1.0, 0.0) * specCameraSpeed) + elif keyPressed(KeyRight): + worldView.move(vec2f( 1.0, 0.0) * specCameraSpeed) + if keyPressed(KeyUp): + worldView.move(vec2f(0.0, -1.0) * specCameraSpeed) + elif keyPressed(KeyDown): + worldView.move(vec2f(0.0, 1.0) * specCameraSpeed) + elif not activeVehicle.isNil: + if keyPressed(KeyUp): + activeVehicle.accel(dt) + elif keyPressed(keyDown): + activeVehicle.reverse(dt) + if keyPressed(KeyRight): + activeVehicle.turn_right(dt) + elif keyPressed(KeyLeft): + activeVehicle.turn_left(dt) + if keyPressed(keyz): + activeVehicle.strafe_left(dt) + elif keyPressed(keyx): + activeVehicle.strafe_right(dt) + if keyPressed(KeyLControl): + localPlayer.useItem 0 + if keyPressed(KeyTab): + localPlayer.useItem 1 + if keyPressed(KeyQ): + localPlayer.useItem 2 + if keyPressed(KeyW): + localPlayer.useItem 3 + if Keypressed(keyA): + localPlayer.useItem 4 + if keyPressed(sfml.KeyS): + localPlayer.useItem 5 + if keyPressed(KeyD): + localPlayer.useItem 6 + worldView.setCenter(activeVehicle.body.getPos.floor)#cp2sfml) + + if localPlayer != nil: + localPlayer.update() + localPlayer.updateItems(dt) + for b in localBots: + b.update() + + for o in items(objects): + o.update(dt) + for i in countdown(high(delObjects), 0): + objects.del i + delObjects.setLen 0 + + var i = 0 + while i < len(liveBullets): + if liveBullets[i].update(dt): + liveBullets.del i + else: + inc i + i = 0 + while i < len(explosions): + if explosions[i].next(dt): inc i + else: explosions.del i + + when defined(DebugKeys): + mouseBody.setPos(mouseToSpace()) + + space.step(dt) + space.eachBody(resetForcesCB, nil) + + when defined(foo): + var coords = window.convertCoords(vec2i(getMousePos()), worldView) + mouseSprite.setPosition(coords) + + if localPlayer != nil and localPlayer.vehicle != nil: + let + pos = localPlayer.vehicle.body.getPos() + ang = localPlayer.vehicle.body.getAngle.vectorForAngle() + myPosition[0].x = pos.x + myPosition[0].z = pos.y + myPosition[1].x = ang.x + myPosition[1].z = ang.y + listenerSetPosition(myPosition[0]) + listenerSetDirection(myPosition[1]) + + inc frameCount + when defined(showFPS): + if frameCount mod 60 == 0: + fpsText.setString($(1.0/dt).round) + if frameCount mod 250 == 0: + updateSoundBuffer() + frameCount = 0 + +proc mainRender() = + window.clear(Black) + window.setView(worldView) + + if showStars: + for star in stars: + window.draw(star.sprite) + window.draw(localPlayer) + + for b in localBots: + window.draw(b) + for o in objects: + window.draw(o) + + for b in explosions: window.draw(b) + for b in liveBullets: window.draw(b) + + when defined(Foo): + window.draw(mouseSprite) + + window.setView(guiView) + + when defined(EscapeMenuTest): + if escMenuOpen: + window.draw escMenu + when defined(showFPS): + window.draw(fpsText) + when defined(recordMode): + window.draw(recordButton) + + if localPlayer.spectator: + window.draw(specGui) + if showShipSelect: window.draw shipSelect + window.display() + + when defined(recordMode): + if isRecording: + if snapshots.len < 100: + if frameCount mod 5 == 0: + snapshots.add(window.capture()) + else: stopRecording() + +proc readyMainState() = + specInputClient.setActive() + +when isMainModule: + import parseopt + + localPlayer = newPlayer() + LobbyInit() + + videoMode = getClientSettings().resolution + window = newRenderWindow(videoMode, "sup", sfDefaultStyle) + window.setFrameRateLimit 60 + + worldView = window.getView.copy() + guiView = worldView.copy() + shipSelect.setPosition vec2f(665.0, 50.0) + + when defined(foo): + mouseSprite = sfml.newCircleShape(14) + mouseSprite.setFillColor Transparent + mouseSprite.setOutlineColor RoyalBlue + mouseSprite.setOutlineThickness 1.4 + mouseSprite.setOrigin vec2f(14, 14) + + LobbyReady() + playBtn = specGui.newButton( + "Unspec - F12", position = vec2f(680.0, 8.0), onClick = proc(b: PButton) = + toggleSpec()) + + block: + var bPlayOffline = false + for kind, key, val in getOpt(): + case kind + of cmdArgument: + if key == "offline": bPlayOffline = true + else: + echo "Invalid argument ", key, " ", val + if bPlayOffline: + playoffline(nil) + + gameRunning = true + while gameRunning: + for event in window.filterEvents: + if event.kind == EvtClosed: + gameRunning = false + break + elif event.kind == EvtMouseWheelMoved and getActiveState() == Field: + if event.mouseWheel.delta == 1: + worldView.zoom(0.9) + else: + worldView.zoom(1.1) + let dt = frameRate.restart.asMilliSeconds().float / 1000.0 + case getActiveState() + of Field: + mainUpdate(dt) + mainRender() + of Lobby: + lobbyUpdate(dt) + lobbyDraw(window) + else: + initLevel() + echo("Done? lol") + doneWithSaidTransition() + readyMainState() diff --git a/tests/manyloc/keineschweine/keineschweine.nimrod.cfg b/tests/manyloc/keineschweine/keineschweine.nimrod.cfg new file mode 100644 index 000000000..048285ad9 --- /dev/null +++ b/tests/manyloc/keineschweine/keineschweine.nimrod.cfg @@ -0,0 +1,8 @@ +path = "lib" +path = "dependencies/sfml" +path = "dependencies/chipmunk" +path = "dependencies/nake" +path = "dependencies/enet" +path = "dependencies/genpacket" +path = "enet_server" +debugger = off diff --git a/tests/manyloc/keineschweine/lib/animations.nim b/tests/manyloc/keineschweine/lib/animations.nim new file mode 100644 index 000000000..a021005f0 --- /dev/null +++ b/tests/manyloc/keineschweine/lib/animations.nim @@ -0,0 +1,75 @@ +import + math, + sfml, chipmunk, + sg_assets, sfml_stuff, math_helpers +type + PAnimation* = ref TAnimation + TAnimation* = object + sprite*: PSprite + record*: PAnimationRecord + delay*: float + index*: int + direction*: int + spriteRect*: TIntRect + style*: TAnimationStyle + TAnimationStyle* = enum + AnimLoop = 0'i8, AnimBounce, AnimOnce + +proc setPos*(obj: PAnimation; pos: TVector) {.inline.} +proc setPos*(obj: PAnimation; pos: TVector2f) {.inline.} +proc setAngle*(obj: PAnimation; radians: float) {.inline.} + +proc free*(obj: PAnimation) = + obj.sprite.destroy() + obj.record = nil + +proc newAnimation*(src: PAnimationRecord; style: TAnimationStyle): PAnimation = + new(result, free) + result.sprite = src.spriteSheet.sprite.copy() + result.record = src + result.delay = src.delay + result.index = 0 + result.direction = 1 + result.spriteRect = result.sprite.getTextureRect() + result.style = style +proc newAnimation*(src: PAnimationRecord; style: TAnimationStyle; + pos: TVector2f; angle: float): PAnimation = + result = newAnimation(src, style) + result.setPos pos + setAngle(result, angle) + +proc next*(obj: PAnimation; dt: float): bool {.discardable.} = + ## step the animation. Returns false if the object is out of frames + result = true + obj.delay -= dt + if obj.delay <= 0.0: + obj.delay += obj.record.delay + obj.index += obj.direction + #if obj.index > (obj.record.spriteSheet.cols - 1) or obj.index < 0: + if not(obj.index in 0..(obj.record.spriteSheet.cols - 1)): + case obj.style + of AnimOnce: + return false + of AnimBounce: + obj.direction *= -1 + obj.index += obj.direction * 2 + of AnimLoop: + obj.index = 0 + obj.spriteRect.left = obj.index.cint * obj.record.spriteSheet.frameW.cint + obj.sprite.setTextureRect obj.spriteRect + +proc setPos*(obj: PAnimation; pos: TVector) = + setPosition(obj.sprite, pos.floor()) +proc setPos*(obj: PAnimation; pos: TVector2f) = + setPosition(obj.sprite, pos) +proc setAngle*(obj: PAnimation; radians: float) = + let rads = (radians + obj.record.angle).wmod(TAU) + if obj.record.spriteSheet.rows > 1: + ## (rotation percent * rows).floor * frameheight + obj.spriteRect.top = (rads / TAU * obj.record.spriteSheet.rows.float).floor.cint * obj.record.spriteSheet.frameh.cint + obj.sprite.setTextureRect obj.spriteRect + else: + setRotation(obj.sprite, degrees(rads)) #stupid sfml, who uses degrees these days? -__- + +proc draw*(window: PRenderWindow; obj: PAnimation) {.inline.} = + window.draw(obj.sprite) diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim new file mode 100644 index 000000000..84e42b62e --- /dev/null +++ b/tests/manyloc/keineschweine/lib/client_helpers.nim @@ -0,0 +1,142 @@ +import + tables, sg_packets, enet, estreams, sg_gui, sfml, + zlib_helpers, md5, sg_assets, os +type + PServer* = ptr TServer + TServer* = object + connected*: bool + addy: enet.TAddress + host*: PHost + peer*: PPeer + handlers*: TTable[char, TScPktHandler] + TScPktHandler* = proc(serv: PServer; buffer: PBuffer) + TFileTransfer = object + fileName: string + assetType: TAssetType + fullLen: int + pos: int32 + data: string + readyToSave: bool +var + currentFileTransfer: TFileTransfer + downloadProgress* = newButton(nil, "", vec2f(0,0), nil) +currentFileTransfer.data = "" + +proc addHandler*(serv: PServer; packetType: char; handler: TScPktHandler) = + serv.handlers[packetType] = handler + +proc newServer*(): PServer = + result = cast[PServer](alloc0(sizeof(TServer))) + result.connected = false + result.host = createHost(nil, 1, 2, 0, 0) + result.handlers = initTable[char, TScPktHandler](32) + +proc connect*(serv: PServer; host: string; port: int16; error: var string): bool = + if setHost(serv.addy, host) != 0: + error = "Could not resolve host " + error.add host + return false + serv.addy.port = port.cushort + serv.peer = serv.host.connect(serv.addy, 2, 0) + if serv.peer.isNil: + error = "Could not connect to host " + error.add host + return false + return true + +proc send*[T](serv: PServer; packetType: char; pkt: var T) = + if serv.connected: + var b = newBuffer(100) + b.write packetType + b.pack pkt + serv.peer.send(0.cuchar, b, FlagUnsequenced) + +proc sendPubChat*(server: PServer; msg: string) = + var chat = newCsChat("", msg) + server.send HChat, chat + +proc handlePackets*(server: PServer; buf: PBuffer) = + while not buf.atEnd(): + let typ = readChar(buf) + if server.handlers.hasKey(typ): + server.handlers[typ](server, buf) + else: + break + +proc updateFileProgress*() = + let progress = currentFileTransfer.pos / currentFileTransfer.fullLen + downloadProgress.bg.setSize(vec2f(progress * 100, 20)) + downloadProgress.setString($currentFileTransfer.pos &'/'& $currentFileTransfer.fullLen) + +## HFileTransfer +proc handleFilePartRecv*(serv: PServer; buffer: PBuffer) {.procvar.} = + var + f = readScFileTransfer(buffer) + updateFileProgress() + if not(f.pos == currentFileTransfer.pos): + echo "returning early from filepartrecv" + return ##issues, probably + if currentFileTransfer.data.len == 0: + echo "setting current file size" + currentFileTransfer.data.setLen f.fileSize + let len = f.data.len + copymem( + addr currentFileTransfer.data[f.pos], + addr f.data[0], + len) + currentFileTransfer.pos = f.pos + len.int32 + if currentFileTransfer.pos == f.fileSize: #file should be done, rizzight + currentFileTransfer.data = uncompress( + currentFileTransfer.data, currentFileTransfer.fullLen) + currentFileTransfer.readyToSave = true + var resp: CsFileChallenge + resp.checksum = toMD5(currentFileTransfer.data) + serv.send HFileChallenge, resp + echo "responded with challenge (ready to save)" + else: + var resp = newCsFilepartAck(currentFileTransfer.pos) + serv.send HFileTransfer, resp + echo "responded for next part" + +proc saveCurrentFile() = + if not currentFileTransfer.readyToSave: return + let + path = expandPath(currentFileTransfer.assetType, currentFileTransfer.fileName) + parent = parentDir(path) + if not existsDir(parent): + createDir(parent) + echo("Created dir") + writeFile path, currentFIleTransfer.data + echo "Write file" + +## HChallengeResult +proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) {.procvar.} = + var res = readScChallengeResult(buffer).status + echo "got challnege result: ", res + if res and currentFileTransfer.readyToSave: + echo "saving" + saveCurrentFile() + else: + currentFileTransfer.readyToSave = false + currentFileTransfer.pos = 0 + echo "REsetting current file" + +## HFileCHallenge +proc handleFileChallenge*(serv: PServer; buffer: PBuffer) {.procvar.} = + var + challenge = readScFileChallenge(buffer) + path = expandPath(challenge) + resp: CsFileChallenge + if not existsFile(path): + resp.needFile = true + echo "Got file challenge, need file." + else: + resp.checksum = toMD5(readFile(path)) + echo "got file challenge, sending sum" + currentFileTransfer.fileName = challenge.file + currentFileTransfer.assetType = challenge.assetType + currentFileTransfer.fullLen = challenge.fullLen.int + currentFileTransfer.pos = 0 + currentFileTransfer.data.setLen 0 + currentFileTransfer.readyToSave = false + serv.send HFileChallenge, resp diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim new file mode 100644 index 000000000..bd0a2c31a --- /dev/null +++ b/tests/manyloc/keineschweine/lib/estreams.nim @@ -0,0 +1,126 @@ +import endians + +proc swapEndian16*(outp, inp: pointer) = + ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to + ## contain at least 2 bytes. + var i = cast[cstring](inp) + var o = cast[cstring](outp) + o[0] = i[1] + o[1] = i[0] +when cpuEndian == bigEndian: + proc bigEndian16(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 2) +else: + proc bigEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp) + +import enet + +type + PBuffer* = ref object + data*: string + pos: int + +proc free(b: PBuffer) = + GCunref b.data +proc newBuffer*(len: int): PBuffer = + new result, free + result.data = newString(len) +proc newBuffer*(pkt: PPacket): PBuffer = + new result, free + result.data = newString(pkt.dataLength) + copyMem(addr result.data[0], pkt.data, pkt.dataLength) +proc toPacket*(buffer: PBuffer; flags: TPacketFlag): PPacket = + buffer.data.setLen buffer.pos + result = createPacket(cstring(buffer.data), buffer.pos, flags) + +proc isDirty*(buffer: PBuffer): bool {.inline.} = + result = (buffer.pos != 0) +proc atEnd*(buffer: PBuffer): bool {.inline.} = + result = (buffer.pos == buffer.data.len) +proc reset*(buffer: PBuffer) {.inline.} = + buffer.pos = 0 + +proc flush*(buf: PBuffer) = + buf.pos = 0 + buf.data.setLen(0) +proc send*(peer: PPeer; channel: cuchar; buf: PBuffer; flags: TPacketFlag): cint {.discardable.} = + result = send(peer, channel, buf.toPacket(flags)) + +proc read*[T: int16|uint16](buffer: PBuffer; outp: var T) = + bigEndian16(addr outp, addr buffer.data[buffer.pos]) + inc buffer.pos, 2 +proc read*[T: float32|int32|uint32](buffer: PBuffer; outp: var T) = + bigEndian32(addr outp, addr buffer.data[buffer.pos]) + inc buffer.pos, 4 +proc read*[T: float64|int64|uint64](buffer: PBuffer; outp: var T) = + bigEndian64(addr outp, addr buffer.data[buffer.pos]) + inc buffer.pos, 8 +proc read*[T: int8|uint8|byte|bool|char](buffer: PBuffer; outp: var T) = + copyMem(addr outp, addr buffer.data[buffer.pos], 1) + inc buffer.pos, 1 + +proc writeBE*[T: int16|uint16](buffer: PBuffer; val: var T) = + setLen buffer.data, buffer.pos + 2 + bigEndian16(addr buffer.data[buffer.pos], addr val) + inc buffer.pos, 2 +proc writeBE*[T: int32|uint32|float32](buffer: PBuffer; val: var T) = + setLen buffer.data, buffer.pos + 4 + bigEndian32(addr buffer.data[buffer.pos], addr val) + inc buffer.pos, 4 +proc writeBE*[T: int64|uint64|float64](buffer: PBuffer; val: var T) = + setLen buffer.data, buffer.pos + 8 + bigEndian64(addr buffer.data[buffer.pos], addr val) + inc buffer.pos, 8 +proc writeBE*[T: char|int8|uint8|byte|bool](buffer: PBuffer; val: var T) = + setLen buffer.data, buffer.pos + 1 + copyMem(addr buffer.data[buffer.pos], addr val, 1) + inc buffer.pos, 1 + + +proc write*(buffer: PBuffer; val: var string) = + var length = len(val).uint16 + writeBE buffer, length + setLen buffer.data, buffer.pos + length.int + copyMem(addr buffer.data[buffer.pos], addr val[0], length.int) + inc buffer.pos, length.int +proc write*[T: TNumber|bool|char|byte](buffer: PBuffer; val: T) = + var v: T + shallowCopy v, val + writeBE buffer, v + +proc readInt8*(buffer: PBuffer): int8 = + read buffer, result +proc readInt16*(buffer: PBuffer): int16 = + read buffer, result +proc readInt32*(buffer: PBuffer): int32 = + read buffer, result +proc readInt64*(buffer: PBuffer): int64 = + read buffer, result +proc readFloat32*(buffer: PBuffer): float32 = + read buffer, result +proc readFloat64*(buffer: PBuffer): float64 = + read buffer, result +proc readStr*(buffer: PBuffer): string = + let len = readInt16(buffer).int + result = "" + if len > 0: + result.setLen len + copyMem(addr result[0], addr buffer.data[buffer.pos], len) + inc buffer.pos, len +proc readChar*(buffer: PBuffer): char {.inline.} = return readInt8(buffer).char +proc readBool*(buffer: PBuffer): bool {.inline.} = return readInt8(buffer).bool + + +when isMainModule: + var b = newBuffer(100) + var str = "hello there" + b.write str + echo(repr(b)) + b.pos = 0 + echo(repr(b.readStr())) + + b.flush() + echo "flushed" + b.writeC([1,2,3]) + echo(repr(b)) + + diff --git a/tests/manyloc/keineschweine/lib/game_objects.nim b/tests/manyloc/keineschweine/lib/game_objects.nim new file mode 100644 index 000000000..37019ebcb --- /dev/null +++ b/tests/manyloc/keineschweine/lib/game_objects.nim @@ -0,0 +1,34 @@ +import chipmunk, sfml, animations, sg_assets +type + PGameObject* = ref TGameObject + TGameObject = object + body*: chipmunk.PBody + shape*: chipmunk.PShape + record*: PObjectRecord + anim*: PAnimation + + +proc `$`*(obj: PGameObject): string = + result = "<Object " + result.add obj.record.name + result.add ' ' + result.add($obj.body.getpos()) + result.add '>' +proc free(obj: PGameObject) = + obj.record = nil + free(obj.anim) + obj.anim = nil +proc newObject*(record: PObjectRecord): PGameObject = + if record.isNil: return nil + new(result, free) + result.record = record + result.anim = newAnimation(record.anim, AnimLoop) + when false: + result.sprite = record.anim.spriteSheet.sprite.copy() + result.body = newBody(result.record.physics.mass, 10.0) + result.shape = chipmunk.newCircleShape(result.body, result.record.physics.radius, vectorZero) + result.body.setPos(vector(100, 100)) +proc newObject*(name: string): PGameObject = + result = newObject(fetchObj(name)) +proc draw*(window: PRenderWindow, obj: PGameObject) {.inline.} = + window.draw(obj.anim.sprite) diff --git a/tests/manyloc/keineschweine/lib/idgen.nim b/tests/manyloc/keineschweine/lib/idgen.nim new file mode 100644 index 000000000..8124ba9bd --- /dev/null +++ b/tests/manyloc/keineschweine/lib/idgen.nim @@ -0,0 +1,23 @@ +type + PIDGen*[T: Ordinal] = ref TIDGen[T] + TIDGen*[T: Ordinal] = object + max: T + freeIDs: seq[T] + EOutOfIDs* = object of EInvalidKey + +#proc free[T](idg: PIDgen[T]) = +# result.freeIDs = nil +proc newIDGen*[T: Ordinal](): PIDGen[T] = + new(result)#, free) + result.max = 0.T + result.freeIDs = @[] +proc next*[T](idg: PIDGen[T]): T = + if idg.freeIDs.len > 0: + result = idg.freeIDs.pop + elif idg.max < high(T)-T(1): + inc idg.max + result = idg.max + else: + raise newException(EOutOfIDs, "ID generator hit max value") +proc del*[T](idg: PIDGen[T]; id: T) = + idg.freeIDs.add id diff --git a/tests/manyloc/keineschweine/lib/input_helpers.nim b/tests/manyloc/keineschweine/lib/input_helpers.nim new file mode 100644 index 000000000..120576dfb --- /dev/null +++ b/tests/manyloc/keineschweine/lib/input_helpers.nim @@ -0,0 +1,138 @@ +import + sfml, tables, hashes +type + TKeyEventKind* = enum down, up + TInputFinishedProc* = proc() + TKeyCallback = proc() + PKeyClient* = ref object + onKeyDown: TTable[int32, TKeyCallback] + onKeyUp: TTable[int32, TKeyCallback] + name: string + PTextInput* = ref object + text*: string + cursor: int + onEnter: TInputFinishedProc +var + keyState: array[-MouseButtonCount.int32 .. KeyCount.int32, bool] + mousePos: TVector2f + activeClient: PKeyClient = nil + activeInput: PTextInput = nil + +proc setActive*(client: PKeyClient) = + activeClient = client + echo("** set active client ", client.name) +proc newKeyClient*(name: string = "unnamed", setactive = false): PKeyClient = + new(result) + result.onKeyDown = initTable[int32, TKeyCallback](16) + result.onKeyUp = initTable[int32, TKeyCallback](16) + result.name = name + if setActive: + setActive(result) + +proc keyPressed*(key: TKeyCode): bool {.inline.} = + return keyState[key.int32] +proc buttonPressed*(btn: TMouseButton): bool {.inline.} = + return keyState[-btn.int32] + +proc clearKey*(key: TKeyCode) {.inline.} = + keyState[key.int32] = false +proc clearButton*(btn: TMouseButton) {.inline.} = + keyState[-btn.int32] = false + +proc addKeyEvent*(key: TKeyCode, ev: TKeyEventKind) {.inline.} = + if activeClient.isNil: return + let k = key.int32 + case ev + of down: + keyState[k] = true + if activeClient.onKeyDown.hasKey(k): + activeClient.onKeyDown[k]() + else: + keyState[k] = false + if activeClient.onKeyUp.hasKey(k): + activeClient.onKeyUp[k]() +proc addButtonEvent*(btn: TMouseButton, ev: TKeyEventKind) {.inline.} = + if activeClient.isNil: return + let b = -btn.int32 + case ev + of down: + keyState[b] = true + if activeClient.onKeyDown.hasKey(b): + activeClient.onKeyDown[b]() + else: + keyState[b] = false + if activeClient.onKeyUp.hasKey(b): + activeClient.onKeyUp[b]() +proc registerHandler*(client: PKeyClient; key: TKeyCode; + ev: TKeyEventKind; fn: TKeyCallback) = + case ev + of down: client.onKeyDown[key.int32] = fn + of up: client.onKeyUp[key.int32] = fn +proc registerHandler*(client: PKeyClient; btn: TMouseButton; + ev: TKeyEventKind; fn: TKeyCallback) = + case ev + of down: client.onKeyDown[-btn.int32] = fn + of up: client.onKeyUp[-btn.int32] = fn + +proc newTextInput*(text = "", pos = 0, onEnter: TInputFinishedProc = nil): PTextInput = + new(result) + result.text = text + result.cursor = pos + result.onEnter = onEnter +proc setActive*(i: PTextInput) = + activeInput = i +proc stopCapturingText*() = + activeInput = nil +proc clear*(i: PTextInput) = + i.text.setLen 0 + i.cursor = 0 +proc recordText*(i: PTextInput; c: cint) = + if c > 127 or i.isNil: return + if c in 32..126: ##printable + if i.cursor == i.text.len: i.text.add(c.int.chr) + else: + let rem = i.text.substr(i.cursor) + i.text.setLen(i.cursor) + i.text.add(chr(c.int)) + i.text.add(rem) + inc(i.cursor) + elif c == 8: ## \b backspace + if i.text.len > 0 and i.cursor > 0: + dec(i.cursor) + let rem = i.text.substr(i.cursor + 1) + i.text.setLen(i.cursor) + i.text.add(rem) + elif c == 10 or c == 13:## \n, \r enter + if not i.onEnter.isNil: i.onEnter() +proc recordText*(i: PTextInput; e: TTextEvent) {.inline.} = + recordText(i, e.unicode) + +proc setMousePos*(x, y: cint) {.inline.} = + mousePos.x = x.float + mousePos.y = y.float +proc getMousePos*(): TVector2f {.inline.} = result = mousePos + +var event: TEvent +# Handle and filter input-related events +iterator filterEvents*(window: PRenderWindow): PEvent = + while window.pollEvent(addr event): + case event.kind + of EvtKeyPressed: addKeyEvent(event.key.code, down) + of EvtKeyReleased: addKeyEvent(event.key.code, up) + of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down) + of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up) + of EvtTextEntered: recordText(activeInput, event.text) + of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y) + else: yield(addr event) +# Handle and return input-related events +iterator pollEvents*(window: PRenderWindow): PEvent = + while window.pollEvent(addr event): + case event.kind + of EvtKeyPressed: addKeyEvent(event.key.code, down) + of EvtKeyReleased: addKeyEvent(event.key.code, up) + of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down) + of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up) + of EvtTextEntered: recordText(activeInput, event.text) + of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y) + else: nil + yield(addr event) \ No newline at end of file diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim new file mode 100644 index 000000000..54173fa61 --- /dev/null +++ b/tests/manyloc/keineschweine/lib/map_filter.nim @@ -0,0 +1,41 @@ +template filterIt2*(seq, pred: expr, body: stmt): stmt {.immediate, dirty.} = + ## sequtils defines a filterIt() that returns a new seq, but this one is called + ## with a statement body to iterate directly over it + for it in items(seq): + if pred: body + +proc map*[A, B](x: seq[A], func: proc(y: A): B {.closure.}): seq[B] = + result = @[] + for item in x.items: + result.add func(item) + +proc mapInPlace*[A](x: var seq[A], func: proc(y: A): A {.closure.}) = + for i in 0..x.len-1: + x[i] = func(x[i]) + +template unless*(condition: expr; body: stmt): stmt {.dirty.} = + if not(condition): + body + +when isMainModule: + proc dumpSeq[T](x: seq[T]) = + for index, item in x.pairs: + echo index, " ", item + echo "-------" + + var t= @[1,2,3,4,5] + var res = t.map(proc(z: int): int = result = z * 10) + dumpSeq res + + from strutils import toHex, repeatStr + var foocakes = t.map(proc(z: int): string = + result = toHex((z * 23).biggestInt, 4)) + dumpSeq foocakes + + t.mapInPlace(proc(z: int): int = result = z * 30) + dumpSeq t + + var someSeq = @[9,8,7,6,5,4,3,2,1] ## numbers < 6 or even + filterIt2 someSeq, it < 6 or (it and 1) == 0: + echo(it) + echo "-----------" \ No newline at end of file diff --git a/tests/manyloc/keineschweine/lib/math_helpers.nim b/tests/manyloc/keineschweine/lib/math_helpers.nim new file mode 100644 index 000000000..8af56d1ed --- /dev/null +++ b/tests/manyloc/keineschweine/lib/math_helpers.nim @@ -0,0 +1,10 @@ +import strutils, math + +proc degrees*(rad: float): float = + return rad * 180.0 / PI +proc radians*(deg: float): float = + return deg * PI / 180.0 + +## V not math, sue me +proc ff*(f: float, precision = 2): string {.inline.} = + return formatFloat(f, ffDecimal, precision) diff --git a/tests/manyloc/keineschweine/lib/sfml_stuff.nim b/tests/manyloc/keineschweine/lib/sfml_stuff.nim new file mode 100644 index 000000000..a5ac91195 --- /dev/null +++ b/tests/manyloc/keineschweine/lib/sfml_stuff.nim @@ -0,0 +1,37 @@ +import + math, strutils, + sfml, input_helpers +when not defined(NoChipmunk): + import chipmunk + proc floor*(a: TVector): TVector2f {.inline.} = + result.x = a.x.floor + result.y = a.y.floor + proc sfml2cp*(a: TVector2f): TVector {.inline.} = + result.x = a.x + result.y = a.y + proc cp2sfml*(a: TVector): TVector2f {.inline.} = + result.x = a.x + result.y = a.y + +proc vec2f*(a: TVector2i): TVector2f = + result.x = a.x.cfloat + result.y = a.y.cfloat +proc vec2i*(a: TVector2f): TVector2i = + result.x = a.x.cint + result.y = a.y.cint +proc vec3f*(x, y, z: float): TVector3f = + result.x = x.cfloat + result.y = y.cfloat + result.z = z.cfloat + +proc `$`*(a: var TIntRect): string = + result = "[TIntRect $1,$2 $3x$4]".format($a.left, $a.top, $a.width, $a.height) +proc `$`*(a: TKeyEvent): string = + return "KeyEvent: code=$1 alt=$2 control=$3 shift=$4 system=$5".format( + $a.code, $a.alt, $a.control, $a.shift, $a.system) + +proc `wmod`*(x, y: float): float = return x - y * (x/y).floor +proc move*(a: var TIntRect, left, top: cint): bool = + if a.left != left or a.top != top: result = true + a.left = left + a.top = top diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim new file mode 100644 index 000000000..766bf5d82 --- /dev/null +++ b/tests/manyloc/keineschweine/lib/sg_assets.nim @@ -0,0 +1,609 @@ +import + re, json, strutils, tables, math, os, math_helpers, + sg_packets, md5, zlib_helpers + +when defined(NoSFML): + import server_utils + type TVector2i = object + x*, y*: int32 + proc vec2i(x, y: int32): TVector2i = + result.x = x + result.y = y +else: + import sfml, sfml_audio, sfml_stuff +when not defined(NoChipmunk): + import chipmunk + +type + TChecksumFile* = object + unpackedSize*: int + sum*: MD5Digest + compressed*: string + PZoneSettings* = ref TZoneSettings + TZoneSettings* = object + vehicles: seq[PVehicleRecord] + items: seq[PItemRecord] + objects: seq[PObjectRecord] + bullets: seq[PBulletRecord] + levelSettings: PLevelSettings + PLevelSettings* = ref TLevelSettings + TLevelSettings* = object + size*: TVector2i + starfield*: seq[PSpriteSheet] + PVehicleRecord* = ref TVehicleRecord + TVehicleRecord* = object + id*: int16 + name*: string + playable*: bool + anim*: PAnimationRecord + physics*: TPhysicsRecord + handling*: THandlingRecord + TItemKind* = enum + Projectile, Utility, Ammo + PObjectRecord* = ref TObjectRecord + TObjectRecord* = object + id*: int16 + name*: string + anim*: PAnimationRecord + physics*: TPhysicsRecord + PItemRecord* = ref TItemRecord + TItemRecord* = object + id*: int16 + name*: string + anim*: PAnimationRecord + physics*: TPhysicsRecord ##apply when the item is dropped in the arena + cooldown*: float + energyCost*: float + useSound*: PSoundRecord + case kind*: TItemKind + of Projectile: + bullet*: PBulletRecord + else: + nil + PBulletRecord* = ref TBulletRecord + TBulletRecord* = object + id*: int16 + name*: string + anim*: PAnimationRecord + physics*: TPhysicsRecord + lifetime*, inheritVelocity*, baseVelocity*: float + explosion*: TExplosionRecord + trail*: TTrailRecord + TTrailRecord* = object + anim*: PAnimationRecord + timer*: float ##how often it should be created + TPhysicsRecord* = object + mass*: float + radius*: float + moment*: float + THandlingRecord = object + thrust*, top_speed*: float + reverse*, strafe*, rotation*: float + TSoulRecord = object + energy*: int + health*: int + TExplosionRecord* = object + anim*: PAnimationRecord + sound*: PSoundRecord + PAnimationRecord* = ref TAnimationRecord + TAnimationRecord* = object + spriteSheet*: PSpriteSheet + angle*: float + delay*: float ##animation delay + PSoundRecord* = ref TSoundRecord + TSoundRecord* = object + file*: string + when defined(NoSFML): + contents*: TChecksumFile + else: + soundBuf*: PSoundBuffer + PSpriteSheet* = ref TSpriteSheet + TSpriteSheet* = object + file*: string + framew*,frameh*: int + rows*, cols*: int + when defined(NoSFML): + contents*: TChecksumFile + when not defined(NoSFML): + sprite*: PSprite + tex*: PTexture + TGameState* = enum + Lobby, Transitioning, Field +const + TAU* = PI * 2.0 + MomentMult* = 0.62 ## global moment of inertia multiplier +var + cfg: PZoneSettings + SpriteSheets* = initTable[string, PSpriteSheet](64) + SoundCache * = initTable[string, PSoundRecord](64) + nameToVehID*: TTable[string, int] + nameToItemID*: TTable[string, int] + nameToObjID*: TTable[string, int] + nameToBulletID*: TTable[string, int] + activeState = Lobby + +proc newSprite(filename: string; errors: var seq[string]): PSpriteSheet +proc load*(ss: PSpriteSheet): bool {.discardable.} +proc newSound(filename: string; errors: var seq[string]): PSoundRecord +proc load*(s: PSoundRecord): bool {.discardable.} + +proc validateSettings*(settings: PJsonNode; errors: var seq[string]): bool +proc loadSettings*(rawJson: string, errors: var seq[string]): bool +proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool + +proc fetchVeh*(name: string): PVehicleRecord +proc fetchItm*(itm: string): PItemRecord +proc fetchObj*(name: string): PObjectRecord +proc fetchBullet(name: string): PBulletRecord + +proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings +proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord +proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord +proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord +proc importPhys(data: PJsonNode): TPhysicsRecord +proc importAnim(data: PJsonNode; errors: var seq[string]): PAnimationRecord +proc importHandling(data: PJsonNode): THandlingRecord +proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord +proc importSoul(data: PJsonNode): TSoulRecord +proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord +proc importSound(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord + +## this is the only pipe between lobby and main.nim +proc getActiveState*(): TGameState = + result = activeState +proc transition*() = + assert activeState == Lobby, "Transition() called from a state other than lobby!" + activeState = Transitioning +proc doneWithSaidTransition*() = + assert activeState == Transitioning, "Finished() called from a state other than transitioning!" + activeState = Field + + +proc checksumFile*(filename: string): TChecksumFile = + let fullText = readFile(filename) + result.unpackedSize = fullText.len + result.sum = toMD5(fullText) + result.compressed = compress(fullText) +proc checksumStr*(str: string): TChecksumFile = + result.unpackedSize = str.len + result.sum = toMD5(str) + result.compressed = compress(str) + + +##at this point none of these should ever be freed +proc free*(obj: PZoneSettings) = + echo "Free'd zone settings" +proc free*(obj: PSpriteSheet) = + echo "Free'd ", obj.file +proc free*(obj: PSoundRecord) = + echo "Free'd ", obj.file + +proc loadAllAssets*() = + var + loaded = 0 + failed = 0 + for name, ss in SpriteSheets.pairs(): + if load(ss): + inc loaded + else: + inc failed + echo loaded," sprites loaded. ", failed, " sprites failed." + loaded = 0 + failed = 0 + for name, s in SoundCache.pairs(): + if load(s): + inc loaded + else: + inc failed + echo loaded, " sounds loaded. ", failed, " sounds failed." +proc getLevelSettings*(): PLevelSettings = + result = cfg.levelSettings + +iterator playableVehicles*(): PVehicleRecord = + for v in cfg.vehicles.items(): + if v.playable: + yield v + +template allAssets*(body: stmt) {.dirty.}= + block: + var assetType = FGraphics + for file, asset in pairs(SpriteSheets): + body + assetType = FSound + for file, asset in pairs(SoundCache): + body + +template cacheImpl(procName, cacheName, resultType: expr; body: stmt) {.dirty, immediate.} = + proc procName*(filename: string; errors: var seq[string]): resulttype = + if hasKey(cacheName, filename): + return cacheName[filename] + new(result, free) + body + cacheName[filename] = result + +template checkFile(path: expr): stmt {.dirty, immediate.} = + if not existsFile(path): + errors.add("File missing: "& path) + +cacheImpl newSprite, SpriteSheets, PSpriteSheet: + result.file = filename + if not(filename =~ re"\S+_(\d+)x(\d+)\.\S\S\S"): + errors.add "Bad file: "&filename&" must be in format name_WxH.png" + return + result.framew = strutils.parseInt(matches[0]) + result.frameh = strutils.parseInt(matches[1]) + checkFile("data/gfx"/result.file) + +cacheImpl newSound, SoundCache, PSoundRecord: + result.file = filename + checkFile("data/sfx"/result.file) + +proc expandPath*(assetType: TAssetType; fileName: string): string = + result = "data/" + case assetType + of FGraphics: result.add "gfx/" + of FSound: result.add "sfx/" + else: nil + result.add fileName +proc expandPath*(fc: ScFileChallenge): string {.inline.} = + result = expandPath(fc.assetType, fc.file) + +when defined(NoSFML): + proc load*(ss: PSpriteSheet): bool = + if not ss.contents.unpackedSize == 0: return + ss.contents = checksumFile(expandPath(FGraphics, ss.file)) + result = true + proc load*(s: PSoundRecord): bool = + if not s.contents.unpackedSize == 0: return + s.contents = checksumFile(expandPath(FSound, s.file)) + result = true +else: + proc load*(ss: PSpriteSheet): bool = + if not ss.sprite.isNil: + return + var image = sfml.newImage("data/gfx/"/ss.file) + if image == nil: + echo "Image could not be loaded" + return + let size = image.getSize() + ss.rows = int(size.y / ss.frameh) #y is h + ss.cols = int(size.x / ss.framew) #x is w + ss.tex = newTexture(image) + image.destroy() + ss.sprite = newSprite() + ss.sprite.setTexture(ss.tex, true) + ss.sprite.setTextureRect(intrect(0, 0, ss.framew.cint, ss.frameh.cint)) + ss.sprite.setOrigin(vec2f(ss.framew / 2, ss.frameh / 2)) + result = true + proc load*(s: PSoundRecord): bool = + s.soundBuf = newSoundBuffer("data/sfx"/s.file) + if not s.soundBuf.isNil: + result = true + +template addError(e: expr): stmt {.immediate.} = + errors.add(e) + result = false +proc validateSettings*(settings: PJsonNode, errors: var seq[string]): bool = + result = true + if settings.kind != JObject: + addError("Settings root must be an object") + return + if not settings.existsKey("vehicles"): + addError("Vehicles section missing") + if not settings.existsKey("objects"): + errors.add("Objects section is missing") + result = false + if not settings.existsKey("level"): + errors.add("Level settings section is missing") + result = false + else: + let lvl = settings["level"] + if lvl.kind != JObject or not lvl.existsKey("size"): + errors.add("Invalid level settings") + result = false + elif not lvl.existsKey("size") or lvl["size"].kind != JArray or lvl["size"].len != 2: + errors.add("Invalid/missing level size") + result = false + if not settings.existsKey("items"): + errors.add("Items section missing") + result = false + else: + let items = settings["items"] + if items.kind != JArray or items.len == 0: + errors.add "Invalid or empty item list" + else: + var id = 0 + for i in items.items: + if i.kind != JArray: errors.add("Item #$1 is not an array"% $id) + elif i.len != 3: errors.add("($1) Item record should have 3 fields"%($id)) + elif i[0].kind != JString or i[1].kind != JString or i[2].kind != JObject: + errors.add("($1) Item should be in form [name, type, {item: data}]"% $id) + result = false + inc id + +proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool = + if not existsFile(filename): + errors.add("File does not exist: "&filename) + else: + result = loadSettings(readFile(filename), errors) + +proc loadSettings*(rawJson: string, errors: var seq[string]): bool = + var settings: PJsonNode + try: + settings = parseJson(rawJson) + except EJsonParsingError: + errors.add("JSON parsing error: "& getCurrentExceptionMsg()) + return + except: + errors.add("Unknown exception: "& getCurrentExceptionMsg()) + return + if not validateSettings(settings, errors): + return + if cfg != nil: #TODO try this + echo("Overwriting zone settings") + free(cfg) + cfg = nil + new(cfg, free) + cfg.levelSettings = importLevel(settings, errors) + cfg.vehicles = @[] + cfg.items = @[] + cfg.objects = @[] + cfg.bullets = @[] + nameToVehID = initTable[string, int](32) + nameToItemID = initTable[string, int](32) + nameToObjID = initTable[string, int](32) + nameToBulletID = initTable[string, int](32) + var + vID = 0'i16 + bID = 0'i16 + for vehicle in settings["vehicles"].items: + var veh = importVeh(vehicle, errors) + veh.id = vID + cfg.vehicles.add veh + nameToVehID[veh.name] = veh.id + inc vID + vID = 0 + if settings.existsKey("bullets"): + for blt in settings["bullets"].items: + var bullet = importBullet(blt, errors) + bullet.id = bID + cfg.bullets.add bullet + nameToBulletID[bullet.name] = bullet.id + inc bID + for item in settings["items"].items: + var itm = importItem(item, errors) + itm.id = vID + cfg.items.add itm + nameToItemID[itm.name] = itm.id + inc vID + if itm.kind == Projectile: + if itm.bullet.isNil: + errors.add("Projectile #$1 has no bullet!"% $vID) + elif itm.bullet.id == -1: + ## this item has an anonymous bullet, fix the ID and name + itm.bullet.id = bID + itm.bullet.name = itm.name + cfg.bullets.add itm.bullet + nameToBulletID[itm.bullet.name] = itm.bullet.id + inc bID + vID = 0 + for obj in settings["objects"].items: + var o = importObject(obj, errors) + o.id = vID + cfg.objects.add o + nameToObjID[o.name] = o.id + inc vID + result = (errors.len == 0) + +proc `$`*(obj: PSpriteSheet): string = + return "<Sprite $1 ($2x$3) $4 rows $5 cols>" % [obj.file, $obj.framew, $obj.frameh, $obj.rows, $obj.cols] + +proc fetchVeh*(name: string): PVehicleRecord = + return cfg.vehicles[nameToVehID[name]] +proc fetchItm*(itm: string): PItemRecord = + return cfg.items[nameToItemID[itm]] +proc fetchObj*(name: string): PObjectRecord = + return cfg.objects[nameToObjID[name]] +proc fetchBullet(name: string): PBulletRecord = + return cfg.bullets[nameToBulletID[name]] + +proc getField(node: PJsonNode, field: string, target: var float) = + if not node.existsKey(field): + return + if node[field].kind == JFloat: + target = node[field].fnum + elif node[field].kind == JInt: + target = node[field].num.float +proc getField(node: PJsonNode, field: string, target: var int) = + if not node.existsKey(field): + return + if node[field].kind == JInt: + target = node[field].num.int + elif node[field].kind == JFloat: + target = node[field].fnum.int +proc getField(node: PJsonNode; field: string; target: var bool) = + if not node.existsKey(field): + return + case node[field].kind + of JBool: + target = node[field].bval + of JInt: + target = (node[field].num != 0) + of JFloat: + target = (node[field].fnum != 0.0) + else: nil + +template checkKey(node: expr; key: string): stmt = + if not existsKey(node, key): + return + +proc importTrail(data: PJsonNode; errors: var seq[string]): TTrailRecord = + checkKey(data, "trail") + result.anim = importAnim(data["trail"], errors) + result.timer = 1000.0 + getField(data["trail"], "timer", result.timer) + result.timer /= 1000.0 +proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings = + new(result) + result.size = vec2i(5000, 5000) + result.starfield = @[] + + checkKey(data, "level") + var level = data["level"] + if level.existsKey("size") and level["size"].kind == JArray and level["size"].len == 2: + result.size.x = level["size"][0].num.cint + result.size.y = level["size"][1].num.cint + if level.existsKey("starfield"): + for star in level["starfield"].items: + result.starfield.add(newSprite(star.str, errors)) +proc importPhys(data: PJsonNode): TPhysicsRecord = + result.radius = 20.0 + result.mass = 10.0 + + if data.existsKey("physics") and data["physics"].kind == JObject: + let phys = data["physics"] + phys.getField("radius", result.radius) + phys.getField("mass", result.mass) + when not defined(NoChipmunk): + result.moment = momentForCircle(result.mass, 0.0, result.radius, vectorZero) * MomentMult +proc importHandling(data: PJsonNode): THandlingRecord = + result.thrust = 45.0 + result.topSpeed = 100.0 #unused + result.reverse = 30.0 + result.strafe = 30.0 + result.rotation = 2200.0 + + checkKey(data, "handling") + if data["handling"].kind != JObject: + return + + let hand = data["handling"] + hand.getField("thrust", result.thrust) + hand.getField("top_speed", result.topSpeed) + hand.getField("reverse", result.reverse) + hand.getField("strafe", result.strafe) + hand.getField("rotation", result.rotation) +proc importAnim(data: PJsonNode, errors: var seq[string]): PAnimationRecord = + new(result) + result.angle = 0.0 + result.delay = 1000.0 + result.spriteSheet = nil + + if data.existsKey("anim"): + let anim = data["anim"] + if anim.kind == JObject: + if anim.existsKey("file"): + result.spriteSheet = newSprite(anim["file"].str, errors) + + anim.getField "angle", result.angle + anim.getField "delay", result.delay + elif data["anim"].kind == JString: + result.spriteSheet = newSprite(anim.str, errors) + + result.angle = radians(result.angle) ## comes in as degrees + result.delay /= 1000 ## delay comes in as milliseconds +proc importSoul(data: PJsonNode): TSoulRecord = + result.energy = 10000 + result.health = 1 + checkKey(data, "soul") + let soul = data["soul"] + soul.getField("energy", result.energy) + soul.getField("health", result.health) +proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord = + checkKey(data, "explode") + let expl = data["explode"] + result.anim = importAnim(expl, errors) + result.sound = importSound(expl, errors, "sound") +proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord = + if data.kind == JObject: + checkKey(data, fieldName) + result = newSound(data[fieldName].str, errors) + elif data.kind == JString: + result = newSound(data.str, errors) + +proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord = + new(result) + result.playable = false + if data.kind != JArray or data.len != 2 or + (data.kind == JArray and + (data[0].kind != JString or data[1].kind != JObject)): + result.name = "(broken)" + errors.add "Vehicle record is malformed" + return + var vehData = data[1] + result.name = data[0].str + result.anim = importAnim(vehdata, errors) + result.physics = importPhys(vehdata) + result.handling = importHandling(vehdata) + vehdata.getField("playable", result.playable) + if result.anim.spriteSheet.isNil and result.playable: + result.playable = false +proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord = + new(result) + if data.kind != JArray or data.len != 2: + result.name = "(broken)" + return + result.name = data[0].str + result.anim = importAnim(data[1], errors) + result.physics = importPhys(data[1]) +proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord = + new(result) + if data.kind != JArray or data.len != 3: + result.name = "(broken)" + errors.add "Item record is malformed" + return + result.name = data[0].str + result.anim = importAnim(data[2], errors) + result.physics = importPhys(data[2]) + + result.cooldown = 100.0 + data[2].getField("cooldown", result.cooldown) + result.cooldown /= 1000.0 ##cooldown is stored in ms + + result.useSound = importSound(data[2], errors, "useSound") + + case data[1].str.toLower + of "projectile": + result.kind = Projectile + if data[2]["bullet"].kind == JString: + result.bullet = fetchBullet(data[2]["bullet"].str) + elif data[2]["bullet"].kind == JInt: + result.bullet = cfg.bullets[data[2]["bullet"].num.int] + elif data[2]["bullet"].kind == JObject: + result.bullet = importBullet(data[2]["bullet"], errors) + else: + errors.add "UNKNOWN BULLET TYPE for item "& result.name + of "ammo": + result.kind = Ammo + of "utility": + nil + else: + errors.add "Invalid item type \""& data[1].str &"\" for item "& result.name + +proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord = + new(result) + result.id = -1 + + var bdata: PJsonNode + if data.kind == JArray: + result.name = data[0].str + bdata = data[1] + elif data.kind == JObject: + bdata = data + else: + errors.add "Malformed bullet record" + return + + result.anim = importAnim(bdata, errors) + result.physics = importPhys(bdata) + + result.lifetime = 2000.0 + result.inheritVelocity = 1000.0 + result.baseVelocity = 30.0 + getField(bdata, "lifetime", result.lifetime) + getField(bdata, "inheritVelocity", result.inheritVelocity) + getField(bdata, "baseVelocity", result.baseVelocity) + result.lifetime /= 1000.0 ## lifetime is stored as milliseconds + result.inheritVelocity /= 1000.0 ## inherit velocity 1000 = 1.0 (100%) + result.explosion = importExplosion(bdata, errors) + result.trail = importTrail(bdata, errors) diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim new file mode 100644 index 000000000..6741fe55e --- /dev/null +++ b/tests/manyloc/keineschweine/lib/sg_gui.nim @@ -0,0 +1,281 @@ +import + sfml, sfml_colors, + input_helpers, sg_packets +from strutils import countlines +{.deadCodeElim: on.} +type + PGuiContainer* = ref TGuiContainer + TGuiContainer* = object of TObject + position: TVector2f + activeEntry: PTextEntry + widgets: seq[PGuiObject] + buttons: seq[PButton] + PGuiObject* = ref TGuiObject + TGuiObject* = object of TObject + PButton* = ref TButton + TButton* = object of TGuiObject + enabled: bool + bg*: sfml.PRectangleShape + text*: PText + onClick*: TButtonClicked + bounds: TFloatRect + PButtonCollection* = ref TButtonCollection + TButtonCollection* = object of TGuiContainer + PTextEntry* = ref TTextEntry + TTextEntry* = object of TButton + inputClient: input_helpers.PTextInput + PMessageArea* = ref TMessageArea + TMessageArea* = object of TGuiObject + pos: TVector2f + messages: seq[TMessage] + texts: seq[PText] + scrollBack*: int + sizeVisible*: int + direction*: int + TMessage = object + color: TColor + text: string + lines: int + TButtonClicked = proc(button: PButton) +var + guiFont* = newFont("data/fnt/LiberationMono-Regular.ttf") + messageProto* = newText("", guiFont, 16) +let + vectorZeroF* = vec2f(0.0, 0.0) + +proc newGuiContainer*(): PGuiContainer +proc newGuiContainer*(pos: TVector2f): PGuiContainer {.inline.} +proc free*(container: PGuiContainer) +proc add*(container: PGuiContainer; widget: PGuiObject) +proc clearButtons*(container: PGuiContainer) +proc click*(container: PGuiContainer; position: TVector2f) +proc setActive*(container: PGuiContainer; entry: PTextEntry) +proc setPosition*(container: PGuiContainer; position: TVector2f) + +proc update*(container: PGuiContainer; dt: float) +proc draw*(window: PRenderWindow; container: PGuiContainer) {.inline.} + +proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea {.discardable.} +proc add*(m: PMessageArea; msg: ScChat) + +proc draw*(window: PRenderWindow; b: PButton) {.inline.} +proc click*(b: PButton; p: TVector2f) +proc setPosition*(b: PButton; p: TVector2f) +proc setString*(b: PButton; s: string) {.inline.} + +proc newButton*(container: PGuiContainer; text: string; position: TVector2f; + onClick: TButtonClicked; startEnabled: bool = true): PButton {.discardable.} +proc init(b: PButton; text: string; position: TVector2f; onClick: TButtonClicked) +proc setEnabled*(b: PButton; enabled: bool) +proc disable*(b: PButton) {.inline.} +proc enable*(b: PButton) {.inline.} + +proc newTextEntry*(container: PGuiContainer; text: string; + position: TVector2f; onEnter: TInputFinishedProc = nil): PTextEntry {.discardable.} +proc init(t: PTextEntry; text: string; onEnter: TInputFinishedProc) +proc draw*(window: PRenderWindow, t: PTextEntry) {.inline.} +proc setActive*(t: PTextEntry) {.inline.} +proc clearText*(t: PTextEntry) {.inline.} +proc getText*(t: PTextEntry): string {.inline.} + +proc update*(m: PMessageArea) + +if guiFont == nil: + echo("Could not load font, crying softly to myself.") + quit(1) + +proc newGuiContainer*(): PGuiContainer = + new(result, free) + result.widgets = @[] + result.buttons = @[] +proc newGuiContainer*(pos: TVector2f): PGuiContainer = + result = newGuiContainer() + result.setPosition pos +proc free*(container: PGuiContainer) = + container.widgets = nil + container.buttons = nil +proc add*(container: PGuiContainer; widget: PGuiObject) = + container.widgets.add(widget) +proc add*(container: PGuiContainer; button: PButton) = + if container.isNil: return + container.buttons.add(button) +proc clearButtons*(container: PGuiContainer) = + container.buttons.setLen 0 +proc click*(container: PGuiContainer; position: TVector2f) = + for b in container.buttons: + click(b, position) +proc setActive*(container: PGuiContainer; entry: PTextEntry) = + container.activeEntry = entry + setActive(entry) +proc setPosition*(container: PGuiContainer; position: TVector2f) = + container.position = position + + +proc update*(container: PGuiContainer; dt: float) = + if not container.activeEntry.isNil: + container.activeEntry.setString(container.activeEntry.getText()) +proc draw*(window: PRenderWindow; container: PGuiContainer) = + for b in container.buttons: + window.draw b + +proc free(c: PButton) = + c.bg.destroy() + c.text.destroy() + c.bg = nil + c.text = nil + c.onClick = nil +proc newButton*(container: PGuiContainer; text: string; + position: TVector2f; onClick: TButtonClicked; + startEnabled: bool = true): PButton = + new(result, free) + init(result, + text, + if not container.isNil: position + container.position else: position, + onClick) + container.add result + if not startEnabled: disable(result) + +proc init(b: PButton; text: string; position: TVector2f; onClick: TButtonClicked) = + b.bg = newRectangleShape() + b.bg.setSize(vec2f(80.0, 16.0)) + b.bg.setFillColor(color(20, 30, 15)) + b.text = newText(text, guiFont, 16) + b.onClick = onClick + b.setPosition(position) + b.enabled = true +proc copy*(c: PButton): PButton = + new(result, free) + result.bg = c.bg.copy() + result.text = c.text.copy() + result.onClick = c.onClick + result.setPosition(result.bg.getPosition()) + +proc setEnabled*(b: PButton; enabled: bool) = + b.enabled = enabled + if enabled: + b.text.setColor(White) + else: + b.text.setColor(Gray) +proc enable*(b: PButton) = setEnabled(b, true) +proc disable*(b: PButton) = setEnabled(b, false) + +proc draw*(window: PRenderWindow; b: PButton) = + window.draw b.bg + window.draw b.text +proc setPosition*(b: PButton, p: TVector2f) = + b.bg.setPosition(p) + b.text.setPosition(p) + b.bounds = b.text.getGlobalBounds() +proc setString*(b: PButton; s: string) = + b.text.setString(s) +proc click*(b: PButton, p: TVector2f) = + if b.enabled and (addr b.bounds).contains(p.x, p.y): + b.onClick(b) + +proc free(obj: PTextEntry) = + free(PButton(obj)) +proc newTextEntry*(container: PGuiContainer; text: string; + position: TVector2F; onEnter: TInputFinishedProc = nil): PTextEntry = + new(result, free) + init(PButton(result), text, position + container.position, proc(b: PButton) = + setActive(container, PTextEntry(b))) + init(result, text, onEnter) + container.add result +proc init(t: PTextEntry; text: string; onEnter: TInputFinishedProc) = + t.inputClient = newTextInput(text, text.len, onEnter) +proc draw(window: PRenderWindow; t: PTextEntry) = + window.draw PButton(t) +proc clearText*(t: PTextEntry) = + t.inputClient.clear() +proc getText*(t: PTextEntry): string = + return t.inputClient.text +proc setActive*(t: PTextEntry) = + if not t.isNil and not t.inputClient.isNil: + input_helpers.setActive(t.inputClient) + + +discard """proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea = + new(result) + result.messages = @[] + result.pos = position + container.add(result) +proc add*(m: PMessageArea, text: string): PText = + result = messageProto.copy() + result.setString(text) + m.messages.add(result) + let nmsgs = len(m.messages) + var pos = vec2f(m.pos.x, m.pos.y) + for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)): + setPosition(m.messages[i], pos) + pos.y -= 16.0 + +proc draw*(window: PRenderWindow; m: PMessageArea) = + let nmsgs = len(m.messages) + if nmsgs == 0: return + for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)): + window.draw(m.messages[i]) +""" +proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea = + new(result) + result.messages = @[] + result.texts = @[] + result.pos = position + container.position + result.sizeVisible = 10 + result.scrollBack = 0 + result.direction = -1 ## to push old messages up + container.add(result) + +proc add*(m: PMessageArea, msg: ScChat) = + const prependName = {CPub, CPriv} + var mmm: TMessage + if msg.kind in prependName: + mmm.text = "<" + mmm.text.add msg.fromPlayer + mmm.text.add "> " + mmm.text.add msg.text + else: + mmm.text = msg.text + case msg.kind + of CPub: mmm.color = RoyalBlue + of CPriv, CSystem: mmm.color = Green + of CError: mmm.color = Red + + mmm.lines = countLines(mmm.text)+1 + + m.messages.add mmm + update m +proc add*(m: PMessageArea, msg: string) {.inline.} = + var chat = newScChat(kind = CSystem, text = msg) + add(m, chat) + +proc proctor*(m: PText; msg: ptr TMessage; pos: ptr TVector2f) = + m.setString msg.text + m.setColor msg.color + m.setPosition pos[] +proc update*(m: PMessageArea) = + if m.texts.len < m.sizeVisible: + echo "adding ", m.sizeVisible - m.texts.len, " fields" + for i in 1..m.sizeVisible - m.texts.len: + var t = messageProto.copy() + m.texts.add messageProto.copy() + elif m.texts.len > m.sizeVisible: + echo "cutting ", m.texts.len - m.sizeVisible, " fields" + for i in m.sizeVisible.. < m.texts.len: + m.texts.pop().destroy() + let nmsgs = m.messages.len() + if m.sizeVisible == 0 or nmsgs == 0: + echo "no messages? ", m.sizeVisible, ", ", nmsgs + return + var pos = vec2f(m.pos.x, m.pos.y) + for i in 0.. min(m.sizeVisible, nmsgs)-1: + ##echo nmsgs - i - 1 - m.scrollBack + let msg = addr m.messages[nmsgs - i - 1 - m.scrollBack] + proctor(m.texts[i], msg, addr pos) + pos.y += (16 * m.direction * msg.lines).cfloat + +proc draw*(window: PRenderWindow; m: PMessageArea) = + let nmsgs = len(m.texts) + if nmsgs == 0: return + for i in countdown(nmsgs - 1, max(nmsgs - m.sizeVisible, 0)): + window.draw m.texts[i] + diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim new file mode 100644 index 000000000..30e83c147 --- /dev/null +++ b/tests/manyloc/keineschweine/lib/sg_packets.nim @@ -0,0 +1,106 @@ +import genpacket_enet, sockets, md5, enet +defPacketImports() + +type + PacketID* = char + +template idpacket(pktName, id, s2c, c2s: expr): stmt {.immediate, dirty.} = + let `H pktName`* {.inject.} = id + defPacket(`Sc pktName`, s2c) + defPacket(`Cs pktName`, c2s) + +forwardPacketT(Uint8, int8) +forwardPacketT(Uint16, int16) +forwardPacketT(TPort, int16) + +idPacket(Login, 'a', + tuple[id: int32; alias: string; sessionKey: string], + tuple[alias: string, passwd: string]) + +let HZoneJoinReq* = 'j' +defPacket(CsZoneJoinReq, tuple[session: ScLogin]) + +defPacket(ScZoneRecord, tuple[ + name: string = "", desc: string = "", + ip: string = "", port: TPort = 0.Tport]) +idPacket(ZoneList, 'z', + tuple[network: string = "", zones: seq[ScZoneRecord]], + tuple[time: string]) + +let HPoing* = 'p' +defPacket(Poing, tuple[id: int32, time: float32]) + +type ChatType* = enum + CPub = 0'i8, CPriv, CSystem, CError +forwardPacketT(ChatType, int8) +idPacket(Chat, 'C', + tuple[kind: ChatType = CPub; fromPlayer: string = ""; text: string = ""], + tuple[target: string = ""; text: string = ""]) + +idPacket(Hello, 'h', + tuple[resp: string], + tuple[i: int8 = 14]) + +let HPlayerList* = 'P' +defPacket(ScPlayerRec, tuple[id: int32; alias: string = ""]) +defPacket(ScPlayerList, tuple[players: seq[ScPlayerRec]]) + +let HTeamList* = 'T' +defPacket(ScTeam, tuple[id: int8; name: string = ""]) +defPacket(ScTeamList, tuple[teams: seq[ScTeam]]) +let HTeamChange* = 't' + +idPacket(ZoneQuery, 'Q', + tuple[playerCount: Uint16], ##i should include a time here or something + tuple[pad: char = '\0']) + +type SpawnKind = enum + SpawnItem = 1'i8, SpawnVehicle, SpawnObject +forwardPacketT(SpawnKind, int8) +defPacket(ScSpawn, tuple[ + kind: SpawnKind; id: uint16; record: uint16; amount: uint16]) + + + + +type TAssetType* = enum + FZoneCfg = 1'i8, FGraphics, FSound + +forwardPacketT(TAssetType, int8) +forwardPacket(MD5Digest, array[0..15, int8]) + +idPacket(FileChallenge, 'F', + tuple[file: string; assetType: TAssetType; fullLen: int32], + tuple[needFile: bool; checksum: MD5Digest]) + + +let HChallengeResult* = '(' +defPacket(ScChallengeResult, tuple[status: bool]) + +let HFileTransfer* = 'f' +defPacket(ScFileTransfer, tuple[fileSize: int32; pos: int32; data: string]) +defPacket(CsFilepartAck, tuple[lastpos: int32]) + +##dir server messages +let HZoneLogin* = 'u' +defPacket(SdZoneLogin, tuple[name: string; key: string; record: ScZoneRecord]) +defPacket(DsZoneLogin, tuple[status: bool]) +let HDsMsg* = 'c' +defPacket(DsMsg, tuple[msg: string]) +let HVerifyClient* = 'v' +defPacket(SdVerifyClient, tuple[session: ScLogin]) + +when isMainModule: + + var buf = newBuffer(100) + var m = toMd5("hello there") + echo(repr(m)) + buf.pack m + + echo(repr(buf.data)) + echo(len(buf.data)) + + buf.reset() + + var x = buf.readMD5Digest() + echo(repr(x)) diff --git a/tests/manyloc/keineschweine/lib/sound_buffer.nim b/tests/manyloc/keineschweine/lib/sound_buffer.nim new file mode 100644 index 000000000..a88eb08de --- /dev/null +++ b/tests/manyloc/keineschweine/lib/sound_buffer.nim @@ -0,0 +1,38 @@ +when defined(NoSFML) or defined(NoChipmunk): + {.error.} +import sfml_audio, sfml_stuff, sg_assets, chipmunk +const + MinDistance* = 350.0 + Attenuation* = 20.0 +var + liveSounds: seq[PSound] = @[] + deadSounds: seq[PSound] = @[] + +proc playSound*(sound: PSoundRecord, pos: TVector) = + if sound.isNil or sound.soundBuf.isNil: return + var s: PSound + if deadSounds.len == 0: + s = sfml_audio.newSound() + s.setLoop false + s.setRelativeToListener true + s.setAttenuation Attenuation + s.setMinDistance MinDistance + else: + s = deadSounds.pop() + s.setPosition(vec3f(pos.x, 0, pos.y)) + s.setBuffer(sound.soundBuf) + s.play() + liveSounds.add s + +proc updateSoundBuffer*() = + var i = 0 + while i < len(liveSounds): + if liveSounds[i].getStatus == Stopped: + deadSounds.add liveSounds[i] + liveSounds.del i + else: + inc i + +proc report*() = + echo "live: ", liveSounds.len + echo "dead: ", deadSounds.len diff --git a/tests/manyloc/keineschweine/lib/vehicles.nim b/tests/manyloc/keineschweine/lib/vehicles.nim new file mode 100644 index 000000000..edbd84ff9 --- /dev/null +++ b/tests/manyloc/keineschweine/lib/vehicles.nim @@ -0,0 +1,35 @@ +import + sfml, chipmunk, + sg_assets, sfml_stuff, keineschweine + + +proc accel*(obj: PVehicle, dt: float) = + #obj.velocity += vec2f( + # cos(obj.angle) * obj.record.handling.thrust.float * dt, + # sin(obj.angle) * obj.record.handling.thrust.float * dt) + obj.body.applyImpulse( + vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.thrust, + vectorZero) +proc reverse*(obj: PVehicle, dt: float) = + #obj.velocity += vec2f( + # -cos(obj.angle) * obj.record.handling.reverse.float * dt, + # -sin(obj.angle) * obj.record.handling.reverse.float * dt) + obj.body.applyImpulse( + -vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.reverse, + vectorZero) +proc strafe_left*(obj: PVehicle, dt: float) = + obj.body.applyImpulse( + vectorForAngle(obj.body.getAngle()).perp() * obj.record.handling.strafe * dt, + vectorZero) +proc strafe_right*(obj: PVehicle, dt: float) = + obj.body.applyImpulse( + vectorForAngle(obj.body.getAngle()).rperp()* obj.record.handling.strafe * dt, + vectorZero) +proc turn_right*(obj: PVehicle, dt: float) = + #obj.angle = (obj.angle + (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU + obj.body.setTorque(obj.record.handling.rotation) +proc turn_left*(obj: PVehicle, dt: float) = + #obj.angle = (obj.angle - (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU + obj.body.setTorque(-obj.record.handling.rotation) +proc offsetAngle*(obj: PVehicle): float {.inline.} = + return (obj.record.anim.angle + obj.body.getAngle()) diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim new file mode 100644 index 000000000..ef977afb0 --- /dev/null +++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim @@ -0,0 +1,40 @@ +import zlib + +proc compress*(source: string): string = + var + sourcelen = source.len + destlen = sourcelen + (sourcelen.float * 0.1).int + 16 + result = "" + result.setLen destLen + var res = zlib.compress(cstring(result), addr destLen, cstring(source), sourceLen) + if res != Z_OK: + echo "Error occured: ", res + elif destLen < result.len: + result.setLen(destLen) + +proc uncompress*(source: string, destLen: var int): string = + result = "" + result.setLen destLen + var res = zlib.uncompress(cstring(result), addr destLen, cstring(source), source.len) + if res != Z_OK: + echo "Error occured: ", res + + +when isMainModule: + import strutils + var r = compress("Hello") + echo repr(r) + var l = "Hello".len + var rr = uncompress(r, l) + echo repr(rr) + assert rr == "Hello" + + proc `*`(a: string; b: int): string {.inline.} = result = repeatStr(b, a) + var s = "yo dude sup bruh homie" * 50 + r = compress(s) + echo s.len, " -> ", r.len + + l = s.len + rr = uncompress(r, l) + echo r.len, " -> ", rr.len + assert rr == s \ No newline at end of file diff --git a/tests/manyloc/keineschweine/nakefile.nim b/tests/manyloc/keineschweine/nakefile.nim new file mode 100644 index 000000000..f175321b9 --- /dev/null +++ b/tests/manyloc/keineschweine/nakefile.nim @@ -0,0 +1,155 @@ +import nake +import httpclient, zipfiles, times, math +nakeImports + +randomize() + +const + GameAssets = "http://dl.dropbox.com/u/37533467/data-08-01-2012.7z" + BinLibs = "http://dl.dropbox.com/u/37533467/libs-2012-09-12.zip" + ExeName = "keineschweine" + ServerDefines = "-d:NoSFML -d:NoChipmunk" + TestBuildDefines = "-d:escapeMenuTest -d:debugWeps -d:showFPS -d:moreNimrod -d:debugKeys -d:foo -d:recordMode --forceBuild" + ReleaseDefines = "-d:release --deadCodeElim:on" + ReleaseTestDefines = "-d:debugWeps -d:debugKeys --forceBuild" + +task "testprofile", "..": + if shell("nimrod", TestBuildDefines, "--profiler:on", "--stacktrace:on", "compile", ExeName) == 0: + shell "."/ExeName, "offline" + +task "test", "Build with test defines": + if shell("nimrod", TestBuildDefines, "compile", ExeName) != 0: + quit "The build failed." + +task "testrun", "Build with test defines and run": + runTask "test" + shell "."/ExeName + +task "test2", "Build release test build test release build": + if shell("nimrod", ReleaseDefines, ReleaseTestDefines, "compile", ExeName) == 0: + shell "."/ExeName + +discard """task "dirserver", "build the directory server": + withDir "server": + if shell("nimrod", ServerDefines, "compile", "dirserver") != 0: + echo "Failed to build the dirserver" + quit 1""" + +task "zoneserver", "build the zone server": + withDir "enet_server": + if shell("nimrod", ServerDefines, "compile", "enet_server") != 0: + quit "Failed to build the zoneserver" +task "zoneserver-gui", "build the zone server, with gui!": + withDir "enet_server": + if shell("nimrod", ServerDefines, "--app:gui", "compile", "enet_server") != 0: + quit "Failed to build the zoneserver" + +task "servers", "build the server and directory server": + #runTask "dirserver" + runTask "zoneserver" + echo "Successfully built both servers :')" + +task "all", "run SERVERS and TEST tasks": + runTask "servers" + runTask "test" + +task "release", "release build": + let res = shell("nimrod", ReleaseDefines, "compile", ExeName) + if res != 0: + echo "The build failed." + quit 1 + else: + runTask "clean" + ## zip up all the files and such or something useful here + +task "testskel", "create skeleton test dir for testing": + let dirname = "test-"& $random(5000) + removeDir dirName + createDir dirName/"data/fnt" + copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf" + copyFile "client_settings.json", dirName/"client_settings.json" + runTask "test" + copyFile ExeName, dirName/ExeName + withDir dirName: + shell "."/ExeName + + +task "clean", "cleanup generated files": + var dirs = @["nimcache", "server"/"nimcache"] + dirs.each(proc(x: var string) = + if existsDir(x): removeDir(x)) + +task "download", "download game assets": + var + skipAssets = false + path = expandFilename("data") + path.add DirSep + path.add(extractFilename(gameAssets)) + if existsFile(path): + echo "The file already exists\n", + "[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets + case stdin.readLine.toLower + of "r": + removeFile path + of "m": + moveFile path, path/../(extractFilename(gameAssets)&"-old") + of "s": + skipAssets = true + else: + quit 0 + else: + echo "Downloading from ", GameAssets + if not skipAssets: + echo "Downloading to ", path + downloadFile gameAssets, path + echo "Download finished" + + let targetDir = parentDir(parentDir(path)) + when defined(linux): + let z7 = findExe("7z") + if z7 == "": + echo "Could not find 7z" + elif shell(z7, "t", path) != 0: ##note to self: make sure this is right + echo "Bad download" + else: + echo "Unpacking..." + shell(z7, "x", "-w[$1]" % targetDir, path) + else: + echo "I do not know how to unpack the data on this system. Perhaps you could ", + "fill this part in?" + + echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n", + "[Y]es [N]o Source: ", BinLibs + case stdin.readline.toLower + of "y", "yes": + discard ## o_O + else: + return + path = extractFilename(BinLibs) + downloadFile BinLibs, path + echo "Downloaded dem libs ", path + when true: echo "Unpack it yourself, sorry." + else: ## this crashes, dunno why + var + z: TZipArchive + destDir = getCurrentDir()/("unzip"& $random(5000)) + if not z.open(path, fmRead): + echo "Could not open zip, bad download?" + return + echo "Extracting to ", destDir + createDir destDir + #z.extractAll destDir + for f in z.walkFiles(): + z.extractFile(f, destDir/f) + z.close() + echo "Extracted the libs dir. Copy the ones you need to this dir." + +task "zip-lib", "zip up the libs dir": + var z: TZipArchive + if not z.open("libs-"& getDateStr() &".zip", fmReadWrite): + quit "Could not open zip" + for file in walkDirRec("libs", {pcFile, pcDir}): + echo "adding file ", file + z.addFile(file) + z.close() + echo "Great success!" \ No newline at end of file diff --git a/tests/manyloc/keineschweine/nakefile.nimrod.cfg b/tests/manyloc/keineschweine/nakefile.nimrod.cfg new file mode 100644 index 000000000..6f3e86fe6 --- /dev/null +++ b/tests/manyloc/keineschweine/nakefile.nimrod.cfg @@ -0,0 +1 @@ +path = "dependencies/nake" diff --git a/tests/manyloc/keineschweine/server/dirserver_settings.json b/tests/manyloc/keineschweine/server/dirserver_settings.json new file mode 100644 index 000000000..18c15fb46 --- /dev/null +++ b/tests/manyloc/keineschweine/server/dirserver_settings.json @@ -0,0 +1,7 @@ +{ + "network":"lamenet", + "port":2049, + "zones":[ + {"name":"alphazone","key":"skittles"} + ] +} \ No newline at end of file diff --git a/tests/manyloc/keineschweine/server/nimrod.cfg b/tests/manyloc/keineschweine/server/nimrod.cfg new file mode 100644 index 000000000..fdc45a8e1 --- /dev/null +++ b/tests/manyloc/keineschweine/server/nimrod.cfg @@ -0,0 +1,6 @@ +debugger = off +deadCodeElim = on +path = ".." +path = "../genpacket" +path = "../helpers" +define = NoSFML diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim new file mode 100644 index 000000000..897fc7d32 --- /dev/null +++ b/tests/manyloc/keineschweine/server/old_dirserver.nim @@ -0,0 +1,201 @@ +## directory server +## handles client authorization and assets + +import + sockets, times, streams, streams_enh, tables, json, os, + sg_packets, sg_assets, md5, server_utils, map_filter +type + THandler = proc(client: PCLient; stream: PStream) +var + server: TSocket + handlers = initTable[char, THandler](16) + thisZone = newScZoneRecord("local", "sup") + zoneList = newScZoneList() + thisZoneSettings: string + zoneSlots: seq[tuple[name: string; key: string]] = @[] + zones: seq[PClient] = @[] + ## I was high. + clients = initTable[TupAddress, PClient](16) + alias2client = initTable[string, PClient](32) + allClients: seq[PClient] = @[] + +proc findClient*(host: string; port: int16): PClient = + let addy: TupAddress = (host, port) + if clients.hasKey(addy): + return clients[addy] + result = newClient(addy) + clients[addy] = result + allClients.add(result) + +proc loginZone(client: PClient; login: SdZoneLogin): bool = + if not client.auth: + for s in zoneSlots.items: + if s.name == login.name and s.key == login.key: + client.auth = true + client.kind = CServer + client.record = login.record + result = true + break + +proc sendZoneList(client: PClient) = + echo(">> zonelist ", client, ' ', HZoneList) + client.send(HZonelist, zonelist) +proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) = + var m = newScChat(CPriv, sender.alias, txt) + rcv.send(HChat, m) +proc sendChat(client: PClient; kind: ChatType; txt: string) = + echo(">> chat ", client) + var m = newScChat(kind, "", txt) + client.send(HChat, m) + + + +var pubChatQueue = newIncomingBuffer() +proc queuePub(sender: string, msg: CsChat) = + var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text) + pubChatQueue.write(HChat) + chat.pack(pubChatQueue) + +handlers[HHello] = (proc(client: PClient; stream: PStream) = + var h = readCsHello(stream) + if h.i == 14: + var greet = newScHello("Well hello there") + client.send(HHello, greet)) +handlers[HLogin] = proc(client: PClient; stream: PStream) = + var loginInfo = readCsLogin(stream) + echo("** login: alias = ", loginInfo.alias) + if alias2client.hasKey(loginInfo.alias): + client.sendError("Alias in use.") + return + if client.loginPlayer(loginInfo): + alias2client[client.alias] = client + client.sendMessage("Welcome "& client.alias) + var session = newScLogin(client.id, client.alias, client.session) + client.send HLogin, session + client.sendZonelist() + +handlers[HZoneList] = proc(client: PClient; stream: PStream) = + var pinfo = readCsZoneList(stream) + echo("** zonelist req") + sendZoneList client +handlers[HChat] = proc(client: PClient; stream: PStream) = + var chat = readCsChat(stream) + if not client.auth: + client.sendError("You are not logged in.") + return + if chat.target != "": ##private + if alias2client.hasKey(chat.target): + alias2client[chat.target].forwardPrivate(client, chat.text) + else: + queuePub(client.alias, chat) + +proc sendServMsg(client: PClient; msg: string) = + var m = newDsMsg(msg) + client.send HDsMsg, m +handlers[HZoneLogin] = proc(client: PClient; stream: PStream) = + var + login = readSdZoneLogin(stream) + if not client.loginZone(login): + client.sendServMsg "Invalid login" + else: + client.sendServMsg "Welcome to the servers" + echo "** Zone logged in: ", login + zones.add client + zonelist.zones.add client.record + + +handlers[HFileChallenge] = proc(client: PClient; stream: PStream) = + if client.auth: + if client.kind == CServer: + var chg = readScFileChallenge(stream) + +proc handlePkt(s: PClient; stream: PStream) = + while not stream.atEnd: + var typ = readChar(stream) + if not handlers.hasKey(typ): + break + else: + handlers[typ](s, stream) + +proc createServer(port: TPort) = + if not server.isNil: + server.close() + server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false) + server.bindAddr(port) + + +var clientIndex = 0 +var incoming = newIncomingBuffer() +proc poll*(timeout: int = 250) = + if server.isNil: return + var + reads = @[server] + writes = @[server] + if select(reads, timeout) > 0: + var + addy = "" + port: TPort + incoming.data.setLen 512 + let res = server.recvFromAsync(incoming.data, 512, addy, port, 0) + if not res: + echo("No recv") + return + else: + var client = findClient(addy, port.int16) + echo "<< ", res, " ", client, ": ", len(incoming.data), " ", repr(incoming.data) + handlePkt(client, incoming) + incoming.flush() + if selectWrite(writes, timeout) > 0: + let nclients = allClients.len + if nclients == 0: + return + clientIndex = (clientIndex + 1) mod nclients + var c = allClients[clientIndex] + if c.outputBuf.getPosition > 0: + let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data) + echo("Write ", c, " result: ", res, " data: ", repr(c.outputBuf.data)) + c.outputBuf.flush() + +when isMainModule: + import parseopt, matchers, strutils + var cfgFile = "dirserver_settings.json" + for kind, key, val in getOpt(): + case kind + of cmdShortOption, cmdLongOption: + case key + of "f", "file": + if existsFile(val): + cfgFile = val + else: + echo("File does not exist: ", val) + else: + echo("Unknown option: ", key," ", val) + else: + echo("Unknown option: ", key, " ", val) + var jsonSettings = parseFile(cfgFile) + let port = TPort(jsonSettings["port"].num) + zonelist.network = jsonSettings["network"].str + for slot in jsonSettings["zones"].items: + zoneSlots.add((slot["name"].str, slot["key"].str)) + + createServer(port) + echo("Listening on port ", port, "...") + var pubChatTimer = cpuTime() #newClock() + const PubChatDelay = 1000/1000 + while true: + poll(15) + ## TODO sort this type of thing VV into a queue api + if cpuTime() - pubChatTimer > PubChatDelay: #.getElapsedTime.asMilliseconds > 100: + pubChatTimer -= pubChatDelay + if pubChatQueue.getPosition > 0: + var cn = 0 + let sizePubChat = pubChatQueue.data.len + var sent = 0 + filterIt2(allClients, it.auth == true and it.kind == CPlayer): + it.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat) + sent += 1 + #for c in allClients: + # c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat) + pubChatQueue.flush() + echo "pubChatQueue flushed to ", sent, "clients" + diff --git a/tests/manyloc/keineschweine/server/old_server_utils.nim b/tests/manyloc/keineschweine/server/old_server_utils.nim new file mode 100644 index 000000000..af9a1b01e --- /dev/null +++ b/tests/manyloc/keineschweine/server/old_server_utils.nim @@ -0,0 +1,98 @@ +import + streams, md5, sockets, unsigned, + sg_packets, zlib_helpers, idgen +type + TClientType* = enum + CServer = 0'i8, CPlayer, CUnknown + PClient* = ref TClient + TClient* = object of TObject + id*: int32 + addy*: TupAddress + clientID*: uint16 + auth*: bool + outputBuf*: PStringStream + case kind*: TClientType + of CPlayer: + alias*: string + session*: string + lastPing*: float + failedPings*: int + of CServer: + record*: ScZoneRecord + cfg*: TChecksumFile + of CUnknown: nil + TChecksumFile* = object + unpackedSize*: int + sum*: MD5Digest + compressed*: string + TupAddress* = tuple[host: string, port: int16] + PIDGen*[T: Ordinal] = ref TIDGen[T] + TIDGen[T: Ordinal] = object + max: T + freeIDs: seq[T] +var cliID = newIdGen[int32]() + +proc sendMessage*(client: PClient; txt: string) +proc sendError*(client: PClient; txt: string) +proc `$`*(client: PClient): string + +proc newIncomingBuffer*(size = 1024): PStringStream = + result = newStringStream("") + result.data.setLen size + result.data.setLen 0 + result.flushImpl = proc(stream: PStream) = + stream.setPosition(0) + PStringStream(stream).data.setLen(0) + + +proc free*(c: PClient) = + echo "Client freed: ", c + cliID.del c.id + c.outputBuf.flush() + c.outputBuf = nil +proc newClient*(addy: TupAddress): PClient = + new(result, free) + result.addy = addy + result.outputBuf = newStringStream("") + result.outputBuf.flushImpl = proc(stream: PStream) = + stream.setPosition 0 + PStringStream(stream).data.setLen 0 + +proc loginPlayer*(client: PClient; login: CsLogin): bool = + if client.auth: + client.sendError("You are already logged in.") + return + client.id = cliID.next() + client.auth = true + client.kind = CPlayer + client.alias = login.alias + client.session = getMD5(client.alias & $rand(10000)) + result = true + +proc `$`*(client: PClient): string = + if not client.auth: return $client.addy + case client.kind + of CPlayer: result = client.alias + of CServer: result = client.record.name + else: result = $client.addy +proc send*[T](client: PClient; pktType: char; pkt: var T) = + client.outputBuf.write(pktType) + pkt.pack(client.outputBuf) + +proc sendMessage*(client: PClient; txt: string) = + var m = newScChat(CSystem, text = txt) + client.send HChat, m +proc sendError*(client: PClient; txt: string) = + var m = newScChat(CError, text = txt) + client.send HChat, m + +proc checksumFile*(filename: string): TChecksumFile = + let fullText = readFile(filename) + result.unpackedSize = fullText.len + result.sum = toMD5(fullText) + result.compressed = compress(fullText) +proc checksumStr*(str: string): TChecksumFile = + result.unpackedSize = str.len + result.sum = toMD5(str) + result.compressed = compress(str) + diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim new file mode 100644 index 000000000..ac85cbf62 --- /dev/null +++ b/tests/manyloc/keineschweine/server/old_sg_server.nim @@ -0,0 +1,254 @@ +import + sockets, times, streams, streams_enh, tables, json, os, unsigned, + sg_packets, sg_assets, md5, server_utils, client_helpers +var + dirServer: PServer + thisZone = newScZoneRecord("local", "sup") + thisZoneSettings: PZoneSettings + dirServerConnected = false + ## I was high. + clients = initTable[TupAddress, PClient](16) + alias2client = initTable[string, PClient](32) + allClients: seq[PClient] = @[] + zonePlayers: seq[PClient] = @[] +const + PubChatDelay = 100/1000 #100 ms + +import hashes +proc hash*(x: uint16): THash {.inline.} = + result = int32(x) + +proc findClient*(host: string; port: int16): PClient = + let addy: TupAddress = (host, port) + if clients.hasKey(addy): + return clients[addy] + result = newClient(addy) + clients[addy] = result + allClients.add(result) + + +proc sendZoneList(client: PClient) = + echo(">> zonelist ", client) + #client.send(HZonelist, zonelist) + +proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) = + var m = newScChat(CPriv, sender.alias, txt) + rcv.send(HChat, m) +proc sendChat(client: PClient; kind: ChatType; txt: string) = + echo(">> chat ", client) + var m = newScChat(kind, "", txt) + client.send(HChat, m) + +var pubChatQueue = newStringStream("") +pubChatQueue.flushImpl = proc(stream: PStream) = + stream.setPosition(0) + PStringStream(stream).data.setLen(0) +proc queuePub(sender: string, msg: CsChat) = + var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text) + pubChatQueue.write(HChat) + chat.pack(pubChatQueue) + +handlers[HHello] = (proc(client: PClient; stream: PStream) = + var h = readCsHello(stream) + if h.i == 14: + var greet = newScHello("Well hello there") + client.send(HHello, greet)) +handlers[HLogin] = proc(client: PClient; stream: PStream) = + var loginInfo = readCsLogin(stream) + echo("** login: alias = ", loginInfo.alias) + if not dirServerConnected and client.loginPlayer(loginInfo): + client.sendMessage("Welcome "& client.alias) + alias2client[client.alias] = client + client.sendZonelist() +handlers[HZoneList] = proc(client: PClient; stream: PStream) = + var pinfo = readCsZoneList(stream) + echo("** zonelist req") +handlers[HChat] = proc(client: PClient; stream: PStream) = + var chat = readCsChat(stream) + if not client.auth: + client.sendError("You are not logged in.") + return + if chat.target != "": ##private + if alias2client.hasKey(chat.target): + alias2client[chat.target].forwardPrivate(client, chat.text) + else: + queuePub(client.alias, chat) +handlers[HZoneQuery] = proc(client: PClient; stream: PStream) = + echo("Got zone query") + var q = readCsZoneQuery(stream) + var resp = newScZoneQuery(zonePlayers.len.uint16) + client.send(HZoneQuery, resp) + + + +handlers[HZoneJoinReq] = proc(client: PClient; stream: PStream) = + var req = readCsZoneJoinReq(stream) + echo "Join zone request from (",req.session.id,") ", req.session.alias + if client.auth and client.kind == CPlayer: + echo "Client is authenticated, verifying filez" + client.startVerifyingFiles() + elif dirServerConnected: + echo "Dirserver is connected, verifying client" + dirServer.send HVerifyClient, req.session + else: + echo "Dirserver is disconnected =(" + client.startVerifyingFiles() + + + +proc handlePkt(s: PClient; stream: PStream) = + while not stream.atEnd: + var typ = readChar(stream) + if not handlers.hasKey(typ): + break + else: + handlers[typ](s, stream) + +proc createServer(port: TPort) = + if not server.isNil: + server.close() + server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false) + server.bindAddr(port) + +var clientIndex = 0 +var incoming = newIncomingBuffer() +proc poll*(timeout: int = 250) = + if server.isNil: return + var + reads = @[server] + writes = @[server] + if select(reads, timeout) > 0: + var + addy = "" + port: TPort + let res = server.recvFromAsync(incoming.data, 512, addy, port, 0) + if not res: + echo("No recv") + return + else: + var client = findClient(addy, port.int16) + #echo("<< ", res, " ", client.alias, ": ", len(line.data), " ", repr(line.data)) + handlePkt(client, incoming) + incoming.flush() + if selectWrite(writes, timeout) > 0: + let nclients = allClients.len + if nclients == 0: + return + clientIndex = (clientIndex + 1) mod nclients + var c = allClients[clientIndex] + if c.outputBuf.getPosition > 0: + let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data) + echo("Write ", c, " result: ", res, " data: ", c.outputBuf.data) + c.outputBuf.flush() + +when isMainModule: + import parseopt, matchers, strutils + var zoneCfgFile = "./server_settings.json" + for kind, key, val in getOpt(): + case kind + of cmdShortOption, cmdLongOption: + case key + of "f", "file": + if existsFile(val): + zoneCfgFile = val + else: + echo("File does not exist: ", val) + else: + echo("Unknown option: ", key," ", val) + else: + echo("Unknown option: ", key, " ", val) + var jsonSettings = parseFile(zoneCfgFile) + let + host = jsonSettings["host"].str + port = TPort(jsonSettings["port"].num) + zoneFile = jsonSettings["settings"].str + dirServerInfo = jsonSettings["dirserver"] + + var path = getAppDir()/../"data"/zoneFile + if not existsFile(path): + echo("Zone settings file does not exist: ../data/", zoneFile) + echo(path) + quit(1) + + ## Test file + block: + var + TestFile: FileChallengePair + contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz") + testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) + testFile.file = checksumStr(contents) + myAssets.add testFile + + setCurrentDir getAppDir().parentDir() + block: + let zonesettings = readFile(path) + var + errors: seq[string] = @[] + if not loadSettings(zoneSettings, errors): + echo("You have errors in your zone settings:") + for e in errors: echo("**", e) + quit(1) + errors.setLen 0 + + var pair: FileChallengePair + pair.challenge.file = zoneFile + pair.challenge.assetType = FZoneCfg + pair.challenge.fullLen = zoneSettings.len.int32 + pair.file = checksumStr(zoneSettings) + myAssets.add pair + + allAssets: + if not load(asset): + echo "Invalid or missing file ", file + else: + var pair: FileChallengePair + pair.challenge.file = file + pair.challenge.assetType = assetType + pair.challenge.fullLen = getFileSize( + expandPath(assetType, file)).int32 + pair.file = asset.contents + myAssets.add pair + + echo "Zone has ", myAssets.len, " associated assets" + + + dirServer = newServerConnection(dirServerInfo[0].str, dirServerInfo[1].num.TPort) + dirServer.handlers[HDsMsg] = proc(serv: PServer; stream: PStream) = + var m = readDsMsg(stream) + echo("DirServer> ", m.msg) + dirServer.handlers[HZoneLogin] = proc(serv: PServer; stream: PStream) = + let loggedIn = readDsZoneLogin(stream).status + if loggedIn: + dirServerConnected = true + dirServer.writePkt HZoneLogin, login + + thisZone.name = jsonSettings["name"].str + thisZone.desc = jsonSettings["desc"].str + thisZone.ip = "localhost" + thisZone.port = port + var login = newSdZoneLogin( + dirServerInfo[2].str, dirServerInfo[3].str, + thisZone) + #echo "MY LOGIN: ", $login + + + + createServer(port) + echo("Listening on port ", port, "...") + var pubChatTimer = cpuTime()#newClock() + while true: + discard dirServer.pollServer(15) + poll(15) + ## TODO sort this type of thing VV into a queue api + #let now = cpuTime() + if cpuTime() - pubChatTimer > PubChatDelay: #.getElapsedTime.asMilliseconds > 100: + pubChatTimer -= pubChatDelay #.restart() + if pubChatQueue.getPosition > 0: + var cn = 0 + let sizePubChat = pubChatQueue.data.len + for c in allClients: + c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat) + pubChatQueue.flush() + + + \ No newline at end of file diff --git a/tests/manyloc/keineschweine/server/sg_lobby.nim b/tests/manyloc/keineschweine/server/sg_lobby.nim new file mode 100644 index 000000000..042d72337 --- /dev/null +++ b/tests/manyloc/keineschweine/server/sg_lobby.nim @@ -0,0 +1,267 @@ + +import + sockets, streams, tables, times, math, strutils, json, os, md5, + sfml, sfml_vector, sfml_colors, + streams_enh, input_helpers, zlib_helpers, client_helpers, sg_packets, sg_assets, sg_gui +type + TClientSettings = object + resolution*: TVideoMode + offlineFile: string + dirserver: tuple[host: string, port: TPort] + website*: string +var + clientSettings: TClientSettings + gui = newGuiContainer() + zonelist = newGuiContainer() + u_alias, u_passwd: PTextEntry + activeInput = 0 + aliasText, passwdText: PText + fpsTimer: PButton + loginBtn: PButton + playBtn: PButton + keyClient = newKeyClient("lobby") + showZonelist = false + chatInput*: PTextEntry + messageArea*: PMessageArea + mySession*: ScLogin +var + dirServer: PServer + zone*: PServer + activeServer: PServer + bConnected = false + outgoing = newStringStream("") + downloadProgress: PButton + connectionButtons: seq[PButton] #buttons that depend on connection to function + +template dispmessage(m: expr): stmt = + messageArea.add(m) +proc connectZone(host: string; port: TPort) +proc connectToDirserv() + +proc writePkt[T](pid: PacketID; p: var T) = + if activeServer.isNil: return + activeServer.writePkt pid, p + +proc setConnected(state: bool) = + if state: + bConnected = true + for b in connectionButtons: enable(b) + else: + bConnected = false + for b in connectionButtons: disable(b) + +proc setActiveZone(ind: int; zone: ScZoneRecord) = + #hilight it or something + dispmessage("Selected " & zone.name) + connectZone(zone.ip, zone.port) + playBtn.enable() + +proc handleChat(serv: PServer; s: PStream) = + var msg = readScChat(s) + messageArea.add(msg) + +proc connectToDirserv() = + if dirServer.isNil: + dirServer = newServerConnection(clientSettings.dirserver.host, clientSettings.dirserver.port) + dirServer.handlers[HHello] = proc(serv: PServer; s: PStream) = + let msg = readScHello(s) + dispMessage(msg.resp) + setConnected(true) + dirServer.handlers[HLogin] = proc(serv: PServer; s: PStream) = + mySession = readScLogin(s) + ##do something here + dirServer.handlers[HZonelist] = proc(serv: PServer; s: PStream) = + var + info = readScZonelist(s) + zones = info.zones + if zones.len > 0: + zonelist.clearButtons() + var pos = vec2f(0.0, 0.0) + zonelist.newButton( + text = "Zonelist - "& info.network, + position = pos, + onClick = proc(b: PButton) = + dispmessage("Click on header")) + pos.y += 20 + for i in 0..zones.len - 1: + var z = zones[i] + zonelist.newButton( + text = z.name, position = pos, + onClick = proc(b: PButton) = + setActiveZone(i, z)) + pos.y += 20 + showZonelist = true + dirServer.handlers[HPoing] = proc(serv: PServer; s: PStream) = + var ping = readPoing(s) + dispmessage("Ping: "& $ping.time) + ping.time = epochTime().float32 + serv.writePkt HPoing, ping + dirServer.handlers[HChat] = handleChat + dirServer.handlers[HFileChallenge] = handleFileChallenge + var hello = newCsHello() + dirServer.writePkt HHello, hello + activeServer = dirServer + + +proc zoneListReq() = + var pkt = newCsZonelist("sup") + writePkt HZonelist, pkt + +##key handlers +keyClient.registerHandler(MouseMiddle, down, proc() = + gui.setPosition(getMousePos())) + +keyClient.registerHandler(KeyO, down, proc() = + if keyPressed(KeyRShift): echo(repr(outgoing))) +keyClient.registerHandler(KeyTab, down, proc() = + activeInput = (activeInput + 1) mod 2) #does this work? +keyClient.registerHandler(MouseLeft, down, proc() = + let p = getMousePos() + gui.click(p) + if showZonelist: zonelist.click(p)) +var mptext = newText("", guiFont, 16) +keyClient.registerHandler(MouseRight, down, proc() = + let p = getMousePos() + mptext.setPosition(p) + mptext.setString("($1,$2)"%[$p.x.int,$p.y.int])) + + +proc connectZone(host: string, port: TPort) = + echo "Connecting to zone at ", host, ':', port + if zone.isNil: + zone = newServerConnection(host, port) + zone.handlers[HFileChallenge] = handleFileChallenge + zone.handlers[HChallengeResult] = handleFileChallengeResult + zone.handlers[HFileTransfer] = handleFileTransfer + zone.handlers[HChat] = handleChat + else: + zone.sock.connect(host, port) + var hello = newCsHello() + zone.writePkt HHello, hello + + + +proc lobbyReady*() = + keyClient.setActive() + gui.setActive(u_alias) + +proc tryConnect*(b: PButton) = + connectToDirserv() +proc tryLogin*(b: PButton) = + var login = newCsLogin( + alias = u_alias.getText(), + passwd = u_passwd.getText()) + writePkt HLogin, login +proc tryTransition*(b: PButton) = + ##check if we're logged in + #<implementation censored by the church> + #var joinReq = newCsJ + zone.writePkt HZoneJoinReq, mySession + #var errors: seq[string] = @[] + #if loadSettings("", errors): + # transition() + #else: + # for e in errors: dispmessage(e) +proc playOffline*(b: PButton) = + var errors: seq[string] = @[] + if loadSettingsFromFile(clientSettings.offlineFile, errors): + transition() + else: + dispmessage("Errors reading the file ("& clientSettings.offlineFile &"):") + for e in errors: dispmessage(e) + +proc getClientSettings*(): TClientSettings = + result = clientSettings + +proc lobbyInit*() = + var s = json.parseFile("./client_settings.json") + clientSettings.offlineFile = "data/" + clientSettings.offlineFile.add s["default-file"].str + let dirserv = s["directory-server"] + clientSettings.dirserver.host = dirserv["host"].str + clientSettings.dirserver.port = dirserv["port"].num.TPort + clientSettings.resolution.width = s["resolution"][0].num.cint + clientSettings.resolution.height= s["resolution"][1].num.cint + clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint + clientSettings.website = s["website"].str + zonelist.setPosition(vec2f(200.0, 100.0)) + connectionButtons = @[] + + downloadProgress = gui.newButton( + text = "", position = vec2f(10, 130), onClick = nil) + downloadProgress.bg.setFillColor(color(34, 139, 34)) + downloadProgress.bg.setSize(vec2f(0, 0)) + + var pos = vec2f(10, 10) + u_alias = gui.newTextEntry( + if s.existsKey("alias"): s["alias"].str else: "alias", + pos) + pos.y += 20 + u_passwd = gui.newTextEntry("buzz", pos) + pos.y += 20 + connectionButtons.add(gui.newButton( + text = "Login", + position = pos, + onClick = tryLogin, + startEnabled = false)) + pos.y += 20 + fpsText.setPosition(pos) + + playBtn = gui.newButton( + text = "Play", + position = vec2f(680.0, 8.0), + onClick = tryTransition, + startEnabled = false) + gui.newButton( + text = "Play Offline", + position = vec2f(680.0, 28.0), + onClick = playOffline) + fpsTimer = gui.newButton( + text = "FPS: ", + position = vec2f(10.0, 70.0), + onClick = proc(b: PButton) = nil) + gui.newButton( + text = "Connect", + position = vec2f(10.0, 90.0), + onClick = tryConnect) + connectionButtons.add(gui.newButton( + text = "Test Chat", + position = vec2f(10.0, 110.0), + onClick = (proc(b: PButton) = + var pkt = newCsChat(text = "ohai") + writePkt HChat, pkt), + startEnabled = false)) + chatInput = gui.newTextEntry("...", vec2f(10.0, 575.0), proc() = + sendChat dirServer, chatInput.getText() + chatInput.clearText()) + messageArea = gui.newMessageArea(vec2f(10.0, 575.0 - 20.0)) + messageArea.sizeVisible = 25 + gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) = + messageArea.scrollBack += 1 + update(messageArea)) + gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) = + messageArea.scrollBack -= 1 + update(messageArea)) + gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) = + for i in 0.. <30: + dispMessage($i)) + +var i = 0 +proc lobbyUpdate*(dt: float) = + #let res = disp.poll() + gui.update(dt) + i = (i + 1) mod 60 + if i == 0: + fpsTimer.setString("FPS: "& $round(1.0/dt)) + if not pollServer(dirServer, 5) and bConnected: + setConnected(false) + echo("Lost connection") + discard pollServer(zone, 5) + +proc lobbyDraw*(window: PRenderWindow) = + window.clear(Black) + window.draw messageArea + window.draw mptext + window.draw gui + if showZonelist: window.draw zonelist + window.display() |