5 Commits

Author SHA1 Message Date
c740204bd5 Wrap more rigiddynamic funcs 2023-10-10 03:43:00 +04:00
8c12404511 Fix bug in create dynamic 2023-10-09 09:27:06 +04:00
fdb8fbbccf Implement transform get/set functions 2023-10-09 07:19:09 +04:00
3d0a4f977b Comments and ClearUserData 2023-10-05 14:34:42 +04:00
5a55870493 Add funcs to set/get rigid actor user data 2023-10-05 13:25:48 +04:00
7 changed files with 157 additions and 14 deletions

28
main.go
View File

@ -2,12 +2,17 @@ package main
import (
"fmt"
"unsafe"
"github.com/bloeys/physx-go/pgo"
)
func contactHandler(cph pgo.ContactPairHeader) {
// ra1 := cph.GetRigidActors()[0]
// ra2 := cph.GetRigidActors()[1]
// fmt.Printf("Collision! User data 1: %v; User data 2: %v\n", ra1.GetUserData(), ra2.GetUserData())
// pairs := cph.GetPairs()
// for i := 0; i < len(pairs); i++ {
@ -138,6 +143,21 @@ func main() {
raycastBuffer := pgo.NewRaycastBuffer(1)
defer raycastBuffer.Release()
// Example of correct usage of user data
x := new(int64)
*x = 1095
ra.SetUserData(unsafe.Pointer(x))
z := (*int64)(ra.GetUserData())
fmt.Println("User data:", *z)
// The rigid actor might get garbage collected after this point (as its no longer used), but that will now cause
// a memory leak and a crash since the user data got pinned (i.e. GC will not move or free it) when we used SetUserData above, but can no longer be unpinned as the runtime.Pinner object will get garbage collected with the rigid actor.
//
// To solve this we have 2 options:
// 1. The pinner is unpinned before it is garbage collected by calling ClearUserData
// 2. The object holding the active pinner (the rigid actor on which SetUserData was used) must remain alive (e.g. by pinning it, putting it in file scope, in a long lived object etc)
ra.ClearUserData()
scene.SetScratchBuffer(4)
for {
scene.Collide(1 / 50.0)
@ -147,10 +167,10 @@ func main() {
scene.RaycastWithHitBuffer(pgo.NewVec3(0, 0, 0), pgo.NewVec3(0, 1, 0), 9, raycastBuffer, 1)
if raycastBuffer.HasBlock() {
block := raycastBuffer.GetBlock()
d := block.GetDistance()
pos := block.GetPos()
fmt.Printf("Raycast hit at dist (%v) and post %v\n", d, pos.String())
// block := raycastBuffer.GetBlock()
// d := block.GetDistance()
// pos := block.GetPos()
// fmt.Printf("Raycast hit at dist (%v) and post %v\n", d, pos.String())
}
// fmt.Printf("\nRaycast hit: %v\n", rHit)
// fmt.Println("Press enter...")

View File

@ -16,6 +16,7 @@ void goOnContactCallback_cgo(void* pairHeader);
*/
import "C"
import (
"runtime"
"unsafe"
"github.com/bloeys/gglm/gglm"
@ -544,7 +545,6 @@ type Quat struct {
cQ C.struct_CPxQuat
}
// CPxAPI CPxInline CSTRUCT CPxQuat NewCPxQuat(float angleRads, float x, float y, float z);
func NewQuat(angleRads, x, y, z float32) *Quat {
return &Quat{
cQ: C.NewCPxQuat(C.float(angleRads), C.float(x), C.float(y), C.float(z)),
@ -555,6 +555,50 @@ type Transform struct {
cT C.struct_CPxTransform
}
func (t *Transform) Pos() Vec3 {
return Vec3{cV: t.cT.p}
}
func (t *Transform) PosX() float32 {
return float32(t.cT.p.x)
}
func (t *Transform) PosY() float32 {
return float32(t.cT.p.y)
}
func (t *Transform) PosZ() float32 {
return float32(t.cT.p.z)
}
func (t *Transform) SetPos(v *Vec3) {
t.cT.p = v.cV
}
func (t *Transform) Rot() Quat {
return Quat{cQ: t.cT.q}
}
func (t *Transform) RotX() float32 {
return float32(t.cT.q.x)
}
func (t *Transform) RotY() float32 {
return float32(t.cT.q.y)
}
func (t *Transform) RotZ() float32 {
return float32(t.cT.q.z)
}
func (t *Transform) RotW() float32 {
return float32(t.cT.q.w)
}
func (t *Transform) SetRot(r *Quat) {
t.cT.q = r.cQ
}
// struct CPxTransform NewCPxTransform(struct CPxVec3*, struct CPxQuat*);
func NewTransform(v *Vec3, q *Quat) *Transform {
return &Transform{
@ -661,14 +705,49 @@ type Actor struct {
}
type RigidActor struct {
cRa C.struct_CPxRigidActor
cRa C.struct_CPxRigidActor
pinner runtime.Pinner
}
func (ra *RigidActor) SetSimFilterData(fd *FilterData) {
C.CPxRigidActor_setSimFilterData(ra.cRa, fd.cFilterData)
}
// CPxAPI void CPxRigidActor_setSimFilterData(CSTRUCT CPxRigidActor* cra, CSTRUCT CPxFilterData* cfd);
// SetUserData sets the void* field on the rigid actor which can be used for any purpose.
// For example, it can be used to store an id or pointer that ties this rigid actor to some other object
//
// Note-1: The passed pointer will be stored in C and as such needs to be pinned, which this function will do.
// You can refer to this for notes on pinning and pointer rules: Refer to: https://pkg.go.dev/cmd/cgo#hdr-Passing_pointers
//
// Note-2: Since this RigidActor object is the one that pinned the user data, it MUST be kept alive at least until ClearUserData is used, at which point the data is unpinned and cleared.
// If this RigidActor object gets garabage collected before clear, the pinner will detect its getting collected with stuff still pinned (which is a leak) and will panic.
func (ra *RigidActor) SetUserData(userData unsafe.Pointer) {
// Note: Do NOT use interfaces here, as we need to ensure the original value
// pointed to is pinned, not the pointer to the interface (i.e. pinning the interface).
// Better avoid crazy to debug issues
// User data is a Go pointer stored in C/C++ code, and as such MUST be pinned
// before that is done, and must be unpinned when no longer stored in C/C++.
//
// Here we assume every write is of a different object, and so we always unpin before storing
// the new object.
//
// Refer to: https://pkg.go.dev/cmd/cgo#hdr-Passing_pointers
ra.pinner.Unpin()
ra.pinner.Pin(userData)
C.CPxRigidActor_set_userData(ra.cRa, userData)
}
func (ra *RigidActor) GetUserData() unsafe.Pointer {
return C.CPxRigidActor_get_userData(ra.cRa)
}
func (ra *RigidActor) ClearUserData() {
ra.pinner.Unpin()
C.CPxRigidActor_set_userData(ra.cRa, nil)
}
type RigidStatic struct {
cRs C.struct_CPxRigidStatic

View File

@ -4,16 +4,19 @@
#include "CPxFilterData.h"
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
struct CPxRigidActor
{
void* obj;
void *obj;
};
//Sets the CPxFilterData on all the shapes of the actor.
// Sets the CPxFilterData on all the shapes of the actor.
CPxAPI void CPxRigidActor_setSimFilterData(CSTRUCT CPxRigidActor cra, CSTRUCT CPxFilterData cfd);
CPxAPI void CPxRigidActor_set_userData(CSTRUCT CPxRigidActor cra, void *userData);
CPxAPI void *CPxRigidActor_get_userData(CSTRUCT CPxRigidActor cra);
#ifdef __cplusplus
}

View File

@ -30,7 +30,17 @@ extern "C" {
CPxAPI CPxReal CPxRigidDynamic_getAngularDamping(CSTRUCT CPxRigidDynamic crd);
CPxAPI CSTRUCT CPxVec3 CPxRigidDynamic_getLinearVelocity(CSTRUCT CPxRigidDynamic crd);
CPxAPI void CPxRigidDynamic_setLinearVelocity(CSTRUCT CPxRigidDynamic crd, CSTRUCT CPxVec3* velocity, bool autoAwake);
CPxAPI CPxReal CPxRigidDynamic_getMaxLinearVelocity(CSTRUCT CPxRigidDynamic crd);
CPxAPI void CPxRigidDynamic_setMaxLinearVelocity(CSTRUCT CPxRigidDynamic crd, CPxReal maxLinearVelocity);
CPxAPI CSTRUCT CPxVec3 CPxRigidDynamic_getAngularVelocity(CSTRUCT CPxRigidDynamic crd);
CPxAPI void CPxRigidDynamic_setAngularVelocity(CSTRUCT CPxRigidDynamic crd, CSTRUCT CPxVec3* velocity, bool autoAwake);
CPxAPI CPxReal CPxRigidDynamic_getMaxAngularVelocity(CSTRUCT CPxRigidDynamic crd);
CPxAPI void CPxRigidDynamic_setMaxAngularVelocity(CSTRUCT CPxRigidDynamic crd, CPxReal maxAngularVelocity);
CPxAPI void CPxRigidDynamic_setMass(CSTRUCT CPxRigidDynamic crd, CPxReal mass);
CPxAPI CPxReal CPxRigidDynamic_getMass(CSTRUCT CPxRigidDynamic crd);

View File

@ -29,14 +29,14 @@ func (rd *RigidDynamic) SetLinearDamping(damping float32) {
C.CPxRigidDynamic_setLinearDamping(rd.cRd, C.float(damping))
}
func (rd *RigidDynamic) SetAngularDamping(damping float32) {
C.CPxRigidDynamic_setAngularDamping(rd.cRd, C.float(damping))
}
func (rd *RigidDynamic) GetLinearDamping() float32 {
return float32(C.CPxRigidDynamic_getLinearDamping(rd.cRd))
}
func (rd *RigidDynamic) SetAngularDamping(damping float32) {
C.CPxRigidDynamic_setAngularDamping(rd.cRd, C.float(damping))
}
func (rd *RigidDynamic) GetAngularDamping() float32 {
return float32(C.CPxRigidDynamic_getAngularDamping(rd.cRd))
}
@ -47,12 +47,36 @@ func (rd *RigidDynamic) GetLinearVelocity() Vec3 {
}
}
func (rd *RigidDynamic) SetLinearVelocity(vel *Vec3, autoWake bool) {
C.CPxRigidDynamic_setLinearVelocity(rd.cRd, &vel.cV, C._Bool(autoWake))
}
func (rd *RigidDynamic) GetAngularVelocity() Vec3 {
return Vec3{
cV: C.CPxRigidDynamic_getAngularVelocity(rd.cRd),
}
}
func (rd *RigidDynamic) SetAngularVelocity(vel *Vec3, autoWake bool) {
C.CPxRigidDynamic_setAngularVelocity(rd.cRd, &vel.cV, C._Bool(autoWake))
}
func (rd *RigidDynamic) GetMaxLinearVelocity() float32 {
return float32(C.CPxRigidDynamic_getMaxLinearVelocity(rd.cRd))
}
func (rd *RigidDynamic) SetMaxLinearVelocity(vel float32) {
C.CPxRigidDynamic_setMaxLinearVelocity(rd.cRd, C.float(vel))
}
func (rd *RigidDynamic) GetMaxAngularVelocity() float32 {
return float32(C.CPxRigidDynamic_getMaxAngularVelocity(rd.cRd))
}
func (rd *RigidDynamic) SetMaxAngularVelocity(vel float32) {
C.CPxRigidDynamic_setMaxAngularVelocity(rd.cRd, C.float(vel))
}
func (rd *RigidDynamic) SetMass(mass float32) {
C.CPxRigidDynamic_setMass(rd.cRd, C.float(mass))
}
@ -122,6 +146,13 @@ func (rd *RigidDynamic) ToRigidActor() RigidActor {
}
func CreateDynamic(p Physics, t *Transform, g Geometry, m Material, density float32, shapeOffset *Transform) RigidDynamic {
if shapeOffset == nil {
return RigidDynamic{
cRd: C.CPxCreateDynamic(p.cPhysics, &t.cT, g.cG, m.cM, C.float(density), nil),
}
}
return RigidDynamic{
cRd: C.CPxCreateDynamic(p.cPhysics, &t.cT, g.cG, m.cM, C.float(density), &shapeOffset.cT),
}