Files
physx-go/pgo/pgo.go
bloeys a01e4b6bbd Switch to mostly returning objects instead of pointers since
almost all objects contain only one pointer inside, making them
very small, so no point paying (de)allocation costs.

This has also been done to physx-c
2022-12-19 00:43:04 +04:00

694 lines
16 KiB
Go
Executable File

package pgo
/*
#cgo CFLAGS: -I physx-c
#cgo LDFLAGS: -L ./libs
// NOTE: If you change this update rigiddynamic.go as well
#cgo windows,amd64 LDFLAGS: -l physxc_checked_windows_amd64
#cgo windows,amd64,physx_release LDFLAGS: -l physxc_release_windows_amd64
#include <wrap.c>
#include <stdlib.h> //Needed for C.free
//simulation event callbacks forward declarations. Actual definitions MUST be in a go different file
void goOnContactCallback_cgo(void* pairHeader);
*/
import "C"
import (
"unsafe"
"github.com/bloeys/gglm/gglm"
)
var (
contactCallback func(ContactPairHeader) = func(ContactPairHeader) {}
)
type Foundation struct {
cFoundation C.struct_CPxFoundation
}
func (f *Foundation) Release() {
C.CPxFoundation_release(f.cFoundation)
}
func CreateFoundation() Foundation {
f := Foundation{}
f.cFoundation = C.CPxCreateFoundation()
return f
}
type Pvd struct {
cPvd C.struct_CPxPvd
}
func (p *Pvd) Connect(pvdTr PvdTransport, instFlag PvdInstrumentationFlag) bool {
return bool(C.CPxPvd_connect(p.cPvd, pvdTr.cPvdTr, uint32(instFlag)))
}
func (p *Pvd) Release() {
C.CPxPvd_release(p.cPvd)
}
func CreatePvd(f Foundation) *Pvd {
p := &Pvd{}
p.cPvd = C.CPxCreatePvd(f.cFoundation)
return p
}
type PvdTransport struct {
cPvdTr C.struct_CPxPvdTransport
}
func DefaultPvdSocketTransportCreate(host string, port, timeoutMillis int) PvdTransport {
//This CString should NOT be freed because its stored internally. If this is freed connection to PVD will fail
p := PvdTransport{}
p.cPvdTr = C.CPxDefaultPvdSocketTransportCreate(C.CString(host), C.int(port), C.int(timeoutMillis))
return p
}
type TolerancesScale struct {
cTolScale C.struct_CPxTolerancesScale
}
func NewTolerancesScale(length, speed float32) TolerancesScale {
return TolerancesScale{
cTolScale: C.struct_CPxTolerancesScale{
length: C.float(length),
speed: C.float(speed),
},
}
}
type Scene struct {
cS C.struct_CPxScene
}
func (s *Scene) GetScenePvdClient() PvdSceneClient {
return PvdSceneClient{
cPvdSceneClient: C.CPxScene_getScenePvdClient(s.cS),
}
}
func (s *Scene) AddActor(a Actor) {
C.CPxScene_addActor(s.cS, a.cA)
}
func (s *Scene) Simulate(elapsedTime float32) {
C.CPxScene_simulate(s.cS, C.float(elapsedTime))
}
func (s *Scene) Collide(elapsedTime float32) {
C.CPxScene_collide(s.cS, C.float(elapsedTime))
}
func (s *Scene) FetchCollision(block bool) bool {
return bool(C.CPxScene_fetchCollision(s.cS, C._Bool(block)))
}
func (s *Scene) Advance() {
C.CPxScene_advance(s.cS)
}
func (s *Scene) FetchResults(block bool) (bool, uint32) {
var errState uint32
b := C.CPxScene_fetchResults(s.cS, C._Bool(block), (*C.uint)(&errState))
return bool(b), errState
}
func (s *Scene) SetScratchBuffer(multiplesOf16k uint32) {
C.CPxScene_setScratchBuffer(s.cS, C.uint(multiplesOf16k))
}
func (s *Scene) Raycast(origin, unitDir *Vec3, distance float32) (bool, RaycastBuffer) {
rb := RaycastBuffer{}
ret := C.CPxScene_raycast(s.cS, &origin.cV, &unitDir.cV, C.float(distance), &rb.cRb)
return bool(ret), rb
}
func (s *Scene) RaycastWithHitBuffer(origin, unitDir *Vec3, distance float32, rb RaycastBuffer, touchesToRead uint) bool {
ret := C.CPxScene_raycastWithHitBuffer(s.cS, &origin.cV, &unitDir.cV, C.float(distance), rb.cRb, C.uint(touchesToRead))
return bool(ret)
}
type RaycastBuffer struct {
cRb *C.struct_CPxRaycastBuffer
}
func (rb *RaycastBuffer) HasBlock() bool {
return bool(rb.cRb.hasBlock)
}
func (rb *RaycastBuffer) GetBlock() RaycastHit {
return RaycastHit{
cRh: &rb.cRb.block,
}
}
func (rb *RaycastBuffer) GetnbTouches() int {
return int(rb.cRb.nbTouches)
}
func (rb *RaycastBuffer) GetTouches() []RaycastHit {
hits := make([]RaycastHit, rb.cRb.nbTouches)
touches := unsafe.Slice(rb.cRb.touches, rb.cRb.nbTouches)
for i := 0; i < len(hits); i++ {
hits[i].cRh = &touches[i]
}
return hits
}
func (rb *RaycastBuffer) Release() {
C.CPxRaycastBuffer_release(rb.cRb)
}
func NewRaycastBuffer(maxTouches uint32) RaycastBuffer {
rb := RaycastBuffer{
cRb: C.NewCPxRaycastBufferWithAlloc(C.uint(maxTouches)),
}
return rb
}
type RaycastHit struct {
cRh *C.struct_CPxRaycastHit
}
func (rh *RaycastHit) GetActor() RigidActor {
return RigidActor{
cRa: rh.cRh.actor,
}
}
func (rh *RaycastHit) GetShape() Shape {
return Shape{
cShape: rh.cRh.shape,
}
}
func (rh *RaycastHit) GetDistance() float32 {
return float32(rh.cRh.distance)
}
func (rh *RaycastHit) GetFaceIndex() uint {
return uint(rh.cRh.faceIndex)
}
func (rh *RaycastHit) GetHitFlags() HitFlag {
return HitFlag(rh.cRh.flags)
}
func (rh *RaycastHit) GetNormal() gglm.Vec3 {
return gglm.Vec3{
Data: [3]float32{
float32(rh.cRh.normal.x),
float32(rh.cRh.normal.y),
float32(rh.cRh.normal.z),
},
}
}
func (rh *RaycastHit) GetPos() gglm.Vec3 {
return gglm.Vec3{
Data: [3]float32{
float32(rh.cRh.position.x),
float32(rh.cRh.position.y),
float32(rh.cRh.position.z),
},
}
}
func (rh *RaycastHit) GetUV() (float32, float32) {
return float32(rh.cRh.u), float32(rh.cRh.v)
}
type Physics struct {
cPhysics C.struct_CPxPhysics
}
func (p *Physics) CreateScene(sd SceneDesc) Scene {
return Scene{
cS: C.CPxPhysics_createScene(p.cPhysics, sd.cSD),
}
}
func (p *Physics) CreateMaterial(staticFriction, dynamicFriction, restitution float32) Material {
return Material{
cM: C.CPxPhysics_createMaterial(p.cPhysics, C.float(staticFriction), C.float(dynamicFriction), C.float(restitution)),
}
}
func (p *Physics) CreateRigidDynamic(tr *Transform) RigidDynamic {
return RigidDynamic{
cRd: C.CPxPhysics_createRigidDynamic(p.cPhysics, &tr.cT),
}
}
func (p *Physics) CreateRigidStatic(tr *Transform) RigidStatic {
return RigidStatic{
cRs: C.CPxPhysics_createRigidStatic(p.cPhysics, &tr.cT),
}
}
func (p *Physics) Release() {
C.CPxPhysics_release(p.cPhysics)
}
func CreatePhysics(f Foundation, ts TolerancesScale, trackOutstandingAllocations bool, pvd *Pvd) Physics {
p := Physics{}
if pvd != nil {
p.cPhysics = C.CPxCreatePhysics(f.cFoundation, ts.cTolScale, C._Bool(trackOutstandingAllocations), &pvd.cPvd)
} else {
p.cPhysics = C.CPxCreatePhysics(f.cFoundation, ts.cTolScale, C._Bool(trackOutstandingAllocations), nil)
}
return p
}
type FilterData struct {
cFilterData C.struct_CPxFilterData
}
func NewFilterData(w0, w1, w2, w3 uint32) FilterData {
return FilterData{
cFilterData: C.struct_CPxFilterData{
word0: C.uint(w0),
word1: C.uint(w1),
word2: C.uint(w2),
word3: C.uint(w3),
},
}
}
type Shape struct {
cShape C.struct_CPxShape
}
func (s *Shape) GetLocalPose() *Transform {
return &Transform{
cT: C.CPxShape_getLocalPose(s.cShape),
}
}
func (s *Shape) SetLocalPose(tr *Transform) {
C.CPxShape_setLocalPose(s.cShape, &tr.cT)
}
func (s *Shape) GetSimulationFilterData() FilterData {
return FilterData{
cFilterData: C.CPxShape_getSimulationFilterData(s.cShape),
}
}
func (s *Shape) SetSimulationFilterData(fd *FilterData) {
C.CPxShape_setSimulationFilterData(s.cShape, &fd.cFilterData)
}
func CreateExclusiveShape(rigidActor RigidActor, geom Geometry, mat Material, shapeFlags ShapeFlags) Shape {
return Shape{
cShape: C.createExclusiveShape(rigidActor.cRa, geom.cG, mat.cM, uint32(shapeFlags)),
}
}
type Vec3 struct {
cV C.struct_CPxVec3
}
func (v *Vec3) X() float32 {
return float32(v.cV.x)
}
func (v *Vec3) Y() float32 {
return float32(v.cV.y)
}
func (v *Vec3) Z() float32 {
return float32(v.cV.z)
}
func NewVec3(x, y, z float32) *Vec3 {
return &Vec3{
cV: C.struct_CPxVec3{
x: C.float(x),
y: C.float(y),
z: C.float(z),
},
}
}
type CpuDispatcher struct {
cCpuDisp C.struct_CPxCpuDispatcher
}
type DefaultCpuDispatcher struct {
cDefCpuDisp C.struct_CPxDefaultCpuDispatcher
}
func (d *DefaultCpuDispatcher) ToCpuDispatcher() CpuDispatcher {
return CpuDispatcher{cCpuDisp: C.CPxDefaultCpuDispatcher_toCPxCpuDispatcher(d.cDefCpuDisp)}
}
// DefaultCpuDispatcherCreate sets the number of threads used by physX.
// If affinityMasksPerThread is nil/zero then default masks are used, otherwise the size of the array
// must match the number of threads
func DefaultCpuDispatcherCreate(numThreads uint32, affinityMasksPerThread []uint32) DefaultCpuDispatcher {
if len(affinityMasksPerThread) == 0 {
return DefaultCpuDispatcher{
cDefCpuDisp: C.CPxDefaultCpuDispatcherCreate(C.uint(numThreads), nil),
}
}
arr := make([]C.uint, len(affinityMasksPerThread))
for i := 0; i < len(arr); i++ {
arr[i] = C.uint(affinityMasksPerThread[i])
}
return DefaultCpuDispatcher{
cDefCpuDisp: C.CPxDefaultCpuDispatcherCreate(C.uint(numThreads), &arr[0]),
}
}
type SceneDesc struct {
cSD C.struct_CPxSceneDesc
}
func (sd *SceneDesc) SetGravity(v *Vec3) {
C.CPxSceneDesc_set_gravity(sd.cSD, v.cV)
}
func (sd *SceneDesc) SetCpuDispatcher(cd CpuDispatcher) {
C.CPxSceneDesc_set_cpuDispatcher(sd.cSD, cd.cCpuDisp)
}
// SetOnContactCallback sets the GLOBAL contact callback handler. Physx-c currently only supports 1 contact callback handler.
// Setting a contact callback handler overrides the previous one. Only the most recent one gets called.
func (sd *SceneDesc) SetOnContactCallback(cb func(ContactPairHeader)) {
contactCallback = cb
C.CPxSceneDesc_set_onContactCallback(sd.cSD, (C.CPxonContactCallback)(unsafe.Pointer(C.goOnContactCallback_cgo)))
}
func NewSceneDesc(ts TolerancesScale) SceneDesc {
return SceneDesc{
cSD: C.NewCPxSceneDesc(ts.cTolScale),
}
}
type ContactPairHeader struct {
cCPH *C.struct_CPxContactPairHeader
}
func (cph *ContactPairHeader) GetRigidActors() [2]RigidActor {
return [2]RigidActor{
{
cRa: cph.cCPH.actors[0],
},
{
cRa: cph.cCPH.actors[1],
},
}
}
func (cph *ContactPairHeader) GetFlags() ContactPairHeaderFlag {
return ContactPairHeaderFlag(cph.cCPH.flags)
}
func (cph *ContactPairHeader) GetnbPairs() int {
return int(cph.cCPH.nbPairs)
}
func (cph *ContactPairHeader) GetPairs() []ContactPair {
contactPairs := make([]ContactPair, cph.cCPH.nbPairs)
cPairs := unsafe.Slice(cph.cCPH.pairs, cph.cCPH.nbPairs)
for i := 0; i < len(contactPairs); i++ {
contactPairs[i].cCp = &cPairs[i]
}
return contactPairs
}
type ContactPair struct {
cCp *C.struct_CPxContactPair
}
func (cp *ContactPair) GetFlags() ContactPairFlag {
return ContactPairFlag(cp.cCp.flags)
}
func (cp *ContactPair) GetEvents() PairFlags {
return PairFlags(cp.cCp.events)
}
func (cp *ContactPair) GetPatchCount() int {
return int(cp.cCp.patchCount)
}
func (cp *ContactPair) GetContactPointCount() int {
return int(cp.cCp.contactCount)
}
func (cp *ContactPair) GetContactPoints() []ContactPairPoint {
ccps := make([]ContactPairPoint, cp.cCp.contactCount)
extractedPoints := unsafe.Slice(cp.cCp.extractedContactPoints, cp.cCp.contactCount)
for i := 0; i < len(extractedPoints); i++ {
ccps[i].cCpp = &extractedPoints[i]
}
return ccps
}
type ContactPairPoint struct {
cCpp *C.struct_CPxContactPairPoint
}
func (cpp *ContactPairPoint) GetPos() gglm.Vec3 {
return gglm.Vec3{Data: [3]float32{
float32(cpp.cCpp.position.x),
float32(cpp.cCpp.position.y),
float32(cpp.cCpp.position.z),
}}
}
func (cpp *ContactPairPoint) GetImpulse() gglm.Vec3 {
return gglm.Vec3{Data: [3]float32{
float32(cpp.cCpp.impulse.x),
float32(cpp.cCpp.impulse.y),
float32(cpp.cCpp.impulse.z),
}}
}
func (cpp *ContactPairPoint) GetNormal() gglm.Vec3 {
return gglm.Vec3{Data: [3]float32{
float32(cpp.cCpp.normal.x),
float32(cpp.cCpp.normal.y),
float32(cpp.cCpp.normal.z),
}}
}
func (cpp *ContactPairPoint) GetSeparation() float32 {
return float32(cpp.cCpp.separation)
}
func (cpp *ContactPairPoint) GetInternalFaceIndices() (float32, float32) {
return float32(cpp.cCpp.internalFaceIndex0), float32(cpp.cCpp.internalFaceIndex1)
}
type PvdSceneFlag uint32
const (
PvdSceneFlag_eTRANSMIT_CONTACTS PvdSceneFlag = (1 << 0) //Transmits contact stream to PVD.
PvdSceneFlag_eTRANSMIT_SCENEQUERIES PvdSceneFlag = (1 << 1) //Transmits scene query stream to PVD.
PvdSceneFlag_eTRANSMIT_CONSTRAINTS PvdSceneFlag = (1 << 2) //Transmits constraints visualize stream to PVD.
)
type PvdSceneClient struct {
cPvdSceneClient C.struct_CPxPvdSceneClient
}
func (p *PvdSceneClient) SetScenePvdFlag(flag PvdSceneFlag, value bool) {
C.CPxPvdSceneClient_setScenePvdFlag(p.cPvdSceneClient, uint32(flag), C._Bool(value))
}
type Material struct {
cM C.struct_CPxMaterial
}
type Plane struct {
cP C.struct_CPxPlane
}
func NewPlane(nx, ny, nz, distance float32) *Plane {
//If we don't keep a space between return and func definition this crashes?????
return &Plane{
cP: C.NewCPxPlane(C.float(nx), C.float(ny), C.float(nz), C.float(distance)),
}
}
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)),
}
}
type Transform struct {
cT C.struct_CPxTransform
}
// struct CPxTransform NewCPxTransform(struct CPxVec3*, struct CPxQuat*);
func NewTransform(v *Vec3, q *Quat) *Transform {
return &Transform{
cT: C.NewCPxTransform(&v.cV, &q.cQ),
}
}
type Geometry struct {
cG C.struct_CPxGeometry
}
type SphereGeometry struct {
cSg C.struct_CPxSphereGeometry
}
func (sg *SphereGeometry) GetRadius() float32 {
return float32(sg.cSg.radius)
}
func (sg *SphereGeometry) SetRadius(r float32) {
sg.cSg.radius = C.float(r)
}
// struct CPxGeometry CPxSphereGeometry_toCPxGeometry(struct CPxSphereGeometry*);
func (sg SphereGeometry) ToGeometry() Geometry {
return Geometry{
cG: C.CPxSphereGeometry_toCPxGeometry(&sg.cSg),
}
}
// struct CPxSphereGeometry NewCPxSphereGeometry(CPxReal radius);
func NewSphereGeometry(radius float32) SphereGeometry {
return SphereGeometry{
cSg: C.struct_CPxSphereGeometry{
radius: C.float(radius),
},
}
}
type BoxGeometry struct {
cBg C.struct_CPxBoxGeometry
}
// GetExtents returns the extents of each dimension of the box.
// An extent is half the length total length.
//
// For example, a cube of size 1x1x1 would have an extent of 0.5 on each side
func (bg *BoxGeometry) GetExtents() (ex, ey, ez float32) {
return float32(bg.cBg.hx), float32(bg.cBg.hy), float32(bg.cBg.hz)
}
func (bg *BoxGeometry) SetExtents(ex, ey, ez float32) {
bg.cBg.hx = C.float(ex)
bg.cBg.hy = C.float(ey)
bg.cBg.hz = C.float(ez)
}
func (bg BoxGeometry) ToGeometry() Geometry {
return Geometry{
cG: C.CPxBoxGeometry_toCPxGeometry(&bg.cBg),
}
}
func NewBoxGeometry(hx, hy, hz float32) BoxGeometry {
return BoxGeometry{
cBg: C.struct_CPxBoxGeometry{
hx: C.float(hx),
hy: C.float(hy),
hz: C.float(hz),
},
}
}
type CapsuleGeometry struct {
cCg C.struct_CPxCapsuleGeometry
}
func (bg *CapsuleGeometry) GetParams() (radius, extent float32) {
return float32(bg.cCg.radius), float32(bg.cCg.halfHeight)
}
func (bg *CapsuleGeometry) SetParams(radius, extent float32) {
bg.cCg.radius = C.float(radius)
bg.cCg.halfHeight = C.float(extent)
}
func (bg CapsuleGeometry) ToGeometry() Geometry {
return Geometry{
cG: C.CPxCapsuleGeometry_toCPxGeometry(&bg.cCg),
}
}
func NewCapsuleGeometry(radius, halfHeight float32) CapsuleGeometry {
return CapsuleGeometry{
cCg: C.struct_CPxCapsuleGeometry{
radius: C.float(radius),
halfHeight: C.float(halfHeight),
},
}
}
type Actor struct {
cA C.struct_CPxActor
}
type RigidActor struct {
cRa C.struct_CPxRigidActor
}
func (ra *RigidActor) SetSimFilterData(fd *FilterData) {
C.CPxRigidActor_setSimFilterData(ra.cRa, fd.cFilterData)
}
// CPxAPI void CPxRigidActor_setSimFilterData(CSTRUCT CPxRigidActor* cra, CSTRUCT CPxFilterData* cfd);
type RigidStatic struct {
cRs C.struct_CPxRigidStatic
}
func (rs *RigidStatic) ToActor() Actor {
return Actor{
cA: C.CPxRigidStatic_toCPxActor(rs.cRs),
}
}
func (rs *RigidStatic) ToRigidActor() RigidActor {
return RigidActor{
cRa: C.CPxRigidStatic_toCPxRigidActor(rs.cRs),
}
}
func CreatePlane(p Physics, plane *Plane, mat Material) RigidStatic {
return RigidStatic{
cRs: C.CPxCreatePlane(p.cPhysics, &plane.cP, mat.cM),
}
}