Skip to content

Commit

Permalink
support point cloud decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal committed Feb 28, 2021
1 parent a29e564 commit efee1be
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 138 deletions.
7 changes: 6 additions & 1 deletion draco/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ func NewDecoder() *Decoder {
}

func (d *Decoder) DecodeMesh(data []byte, m *Mesh) error {
s := C.dracoDecoderArrayToMesh(d.ref, (*C.char)(unsafe.Pointer(&data[0])), C.size_t(len(data)), m.ref)
s := C.dracoDecoderDecodeMesh(d.ref, (*C.char)(unsafe.Pointer(&data[0])), C.size_t(len(data)), m.ref)
return newError(s)
}

func (d *Decoder) DecodePointCloud(data []byte, pc *PointCloud) error {
s := C.dracoDecoderDecodePointCloud(d.ref, (*C.char)(unsafe.Pointer(&data[0])), C.size_t(len(data)), pc.ref)
return newError(s)
}
84 changes: 2 additions & 82 deletions draco/mesh.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ package draco
// #include "packaged/include/c_api.h"
import "C"
import (
"fmt"
"reflect"
"runtime"
"unsafe"
)

type Mesh struct {
ref *C.draco_mesh
PointCloud
}

func (m *Mesh) free() {
Expand All @@ -20,7 +18,7 @@ func (m *Mesh) free() {
}

func NewMesh() *Mesh {
m := &Mesh{C.dracoNewMesh()}
m := &Mesh{PointCloud{C.dracoNewMesh()}}
runtime.SetFinalizer(m, (*Mesh).free)
return m
}
Expand All @@ -29,14 +27,6 @@ func (m *Mesh) NumFaces() uint32 {
return uint32(C.dracoMeshNumFaces(m.ref))
}

func (m *Mesh) NumPoints() uint32 {
return uint32(C.dracoMeshNumPoints(m.ref))
}

func (m *Mesh) NumAttrs() int32 {
return int32(C.dracoMeshNumAttrs(m.ref))
}

func (m *Mesh) Faces(buffer []Face) []Face {
n := m.NumFaces()
if len(buffer) < int(n) {
Expand All @@ -45,73 +35,3 @@ func (m *Mesh) Faces(buffer []Face) []Face {
C.dracoMeshGetTrianglesUint32(m.ref, C.size_t(n*3*4), (*C.uint32_t)(unsafe.Pointer(&buffer[0])))
return buffer[:n]
}

func (m *Mesh) Attr(i int32) *PointAttr {
attr := C.dracoMeshGetAttribute(m.ref, C.int32_t(i))
if attr == nil {
return nil
}
return &PointAttr{ref: attr}
}

func (m *Mesh) AttrByUniqueID(id uint32) *PointAttr {
attr := C.dracoMeshGetAttributeByUniqueId(m.ref, C.uint32_t(id))
if attr == nil {
return nil
}
return &PointAttr{ref: attr}
}

func (m *Mesh) NamedAttributeID(gt GeometryType) int32 {
return int32(C.dracoMeshGetNamedAttributeId(m.ref, C.draco_geometry_type(gt)))
}

func (m *Mesh) AttrData(pa *PointAttr, buffer interface{}) (interface{}, bool) {
var dt DataType
n := m.NumPoints() * uint32(pa.NumComponents())
if buffer == nil {
dt = pa.DataType()
buffer = reflect.MakeSlice(reflect.SliceOf(dt.goType()), int(n), int(n)).Interface()
} else {
v := reflect.ValueOf(buffer)
if v.IsNil() {
buffer = reflect.MakeSlice(reflect.SliceOf(dt.goType()), int(n), int(n)).Interface()
}
if v.Kind() != reflect.Slice {
panic(fmt.Sprintf("draco-go: expecting a slice but got %s", v.Kind()))
}
l := v.Len()
switch buffer.(type) {
case []int8:
dt = DT_INT8
case []uint8:
dt = DT_UINT8
case []int16:
dt = DT_INT16
case []uint16:
dt = DT_UINT16
case []int32:
dt = DT_INT32
case []uint32:
dt = DT_UINT32
case []int64:
dt = DT_INT64
case []uint64:
dt = DT_UINT64
case []float32:
dt = DT_FLOAT32
case []float64:
dt = DT_FLOAT64
default:
panic("draco-go: unsupported data type")
}
if l < int(n) {
tmp := reflect.MakeSlice(reflect.SliceOf(dt.goType()), int(n)-l, int(n)-l).Interface()
buffer = reflect.AppendSlice(reflect.ValueOf(buffer), reflect.ValueOf(tmp)).Interface()
}
}
v := reflect.ValueOf(buffer).Index(0)
size := n * dt.Size()
ok := C.dracoMeshGetAttributeData(m.ref, pa.ref, C.draco_data_type(dt), C.size_t(size), unsafe.Pointer(v.UnsafeAddr()))
return buffer, bool(ok)
}
60 changes: 37 additions & 23 deletions draco/packaged/include/c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,48 +101,56 @@ EXPORT_API int64_t dracoPointAttrByteOffset(const draco_point_attr* pa);

EXPORT_API uint32_t dracoPointAttrUniqueId(const draco_point_attr* pa);

// draco::PointCloud

typedef struct draco_point_cloud draco_point_cloud;

EXPORT_API draco_point_cloud* dracoNewPointCloud();

EXPORT_API void dracoPointCloudRelease(draco_point_cloud *pc);

EXPORT_API uint32_t dracoPointCloudNumPoints(const draco_point_cloud *pc);

EXPORT_API int32_t dracoPointCloudNumAttrs(const draco_point_cloud *pc);

EXPORT_API const draco_point_attr* dracoPointCloudGetAttribute(const draco_point_cloud *pc, int32_t att_id);

EXPORT_API int32_t dracoPointCloudGetNamedAttributeId(const draco_point_cloud *pc, draco_geometry_type geo_type);

EXPORT_API const draco_point_attr* dracoPointCloudGetAttributeByUniqueId(const draco_point_cloud *pc, uint32_t unique_id);

EXPORT_API bool dracoPointCloudGetAttributeData(const draco_point_cloud *pc,
const draco_point_attr *pa,
draco_data_type data_type,
const size_t out_size,
void *out_values);

// draco::Mesh

typedef struct draco_mesh draco_mesh;
typedef struct draco_point_cloud draco_mesh;

EXPORT_API draco_mesh* dracoNewMesh();

EXPORT_API void dracoMeshRelease(draco_mesh *mesh);

EXPORT_API uint32_t dracoMeshNumFaces(const draco_mesh *mesh);

EXPORT_API uint32_t dracoMeshNumPoints(const draco_mesh *mesh);

EXPORT_API int32_t dracoMeshNumAttrs(const draco_mesh *mesh);

// Queries an array of 3*face_count elements containing the triangle indices.
// out_values must be allocated to contain at least 3*face_count uint16_t elements.
// out_size must be exactly 3*face_count*sizeof(uint16_t), else out_values
// won´t be filled and returns false.
// won't be filled and returns false.
EXPORT_API bool dracoMeshGetTrianglesUint16(const draco_mesh *mesh,
const size_t out_size,
uint16_t *out_values);

// Queries an array of 3*face_count elements containing the triangle indices.
// out_values must be allocated to contain at least 3*face_count uint32_t elements.
// out_size must be exactly 3*face_count*sizeof(uint32_t), else out_values
// won´t be filled and returns false.
// won't be filled and returns false.
EXPORT_API bool dracoMeshGetTrianglesUint32(const draco_mesh *mesh,
const size_t out_size,
uint32_t *out_values);

EXPORT_API const draco_point_attr* dracoMeshGetAttribute(const draco_mesh *mesh, int32_t att_id);

EXPORT_API int32_t dracoMeshGetNamedAttributeId(const draco_mesh *mesh, draco_geometry_type geo_type);

EXPORT_API const draco_point_attr* dracoMeshGetAttributeByUniqueId(const draco_mesh *mesh, uint32_t unique_id);

EXPORT_API bool dracoMeshGetAttributeData(const draco_mesh *mesh,
const draco_point_attr *pa,
draco_data_type data_type,
const size_t out_size,
void *out_values);

// draco::Decoder

typedef struct draco_decoder draco_decoder;
Expand All @@ -151,10 +159,16 @@ EXPORT_API draco_decoder* dracoNewDecoder();

EXPORT_API void dracoDecoderRelease(draco_decoder *decoder);

EXPORT_API draco_status* dracoDecoderArrayToMesh(draco_decoder *decoder,
const char *data,
size_t data_size,
draco_mesh *out_mesh);
EXPORT_API draco_status* dracoDecoderDecodeMesh(draco_decoder *decoder,
const char *data,
size_t data_size,
draco_mesh *out_mesh);


EXPORT_API draco_status* dracoDecoderDecodePointCloud(draco_decoder *decoder,
const char *data,
size_t data_size,
draco_point_cloud *out_pc);

#ifdef __cplusplus
}
Expand Down
Binary file modified draco/packaged/lib/darwin_amd64/libdraco_c.a
Binary file not shown.
Binary file modified draco/packaged/lib/linux_amd64/libdraco_c.a
Binary file not shown.
Binary file modified draco/packaged/lib/windows_amd64/libdraco_c.a
Binary file not shown.
104 changes: 104 additions & 0 deletions draco/pointcloud.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package draco

// #include "packaged/include/c_api.h"
import "C"
import (
"fmt"
"reflect"
"runtime"
"unsafe"
)

type PointCloud struct {
ref *C.draco_point_cloud
}

func (pc *PointCloud) free() {
if pc.ref != nil {
C.dracoPointCloudRelease(pc.ref)
}
}

func NewPointCloud() *PointCloud {
pc := &PointCloud{C.dracoNewPointCloud()}
runtime.SetFinalizer(pc, (*PointCloud).free)
return pc
}

func (pc *PointCloud) NumPoints() uint32 {
return uint32(C.dracoPointCloudNumPoints(pc.ref))
}

func (pc *PointCloud) NumAttrs() int32 {
return int32(C.dracoPointCloudNumAttrs(pc.ref))
}

func (pc *PointCloud) Attr(i int32) *PointAttr {
attr := C.dracoPointCloudGetAttribute(pc.ref, C.int32_t(i))
if attr == nil {
return nil
}
return &PointAttr{ref: attr}
}

func (pc *PointCloud) AttrByUniqueID(id uint32) *PointAttr {
attr := C.dracoPointCloudGetAttributeByUniqueId(pc.ref, C.uint32_t(id))
if attr == nil {
return nil
}
return &PointAttr{ref: attr}
}

func (pc *PointCloud) NamedAttributeID(gt GeometryType) int32 {
return int32(C.dracoPointCloudGetNamedAttributeId(pc.ref, C.draco_geometry_type(gt)))
}

func (pc *PointCloud) AttrData(pa *PointAttr, buffer interface{}) (interface{}, bool) {
var dt DataType
n := pc.NumPoints() * uint32(pa.NumComponents())
if buffer == nil {
dt = pa.DataType()
buffer = reflect.MakeSlice(reflect.SliceOf(dt.goType()), int(n), int(n)).Interface()
} else {
v := reflect.ValueOf(buffer)
if v.IsNil() {
buffer = reflect.MakeSlice(reflect.SliceOf(dt.goType()), int(n), int(n)).Interface()
}
if v.Kind() != reflect.Slice {
panic(fmt.Sprintf("draco-go: expecting a slice but got %s", v.Kind()))
}
l := v.Len()
switch buffer.(type) {
case []int8:
dt = DT_INT8
case []uint8:
dt = DT_UINT8
case []int16:
dt = DT_INT16
case []uint16:
dt = DT_UINT16
case []int32:
dt = DT_INT32
case []uint32:
dt = DT_UINT32
case []int64:
dt = DT_INT64
case []uint64:
dt = DT_UINT64
case []float32:
dt = DT_FLOAT32
case []float64:
dt = DT_FLOAT64
default:
panic("draco-go: unsupported data type")
}
if l < int(n) {
tmp := reflect.MakeSlice(reflect.SliceOf(dt.goType()), int(n)-l, int(n)-l).Interface()
buffer = reflect.AppendSlice(reflect.ValueOf(buffer), reflect.ValueOf(tmp)).Interface()
}
}
v := reflect.ValueOf(buffer).Index(0)
size := n * dt.Size()
ok := C.dracoPointCloudGetAttributeData(pc.ref, pa.ref, C.draco_data_type(dt), C.size_t(size), unsafe.Pointer(v.UnsafeAddr()))
return buffer, bool(ok)
}
64 changes: 32 additions & 32 deletions examples/decode/main.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
package main

import (
"io/ioutil"
"log"

"github.com/qmuntal/draco-go/draco"
)

func main() {
data, err := ioutil.ReadFile("../../testdata/test_nm.obj.edgebreaker.cl4.2.2.drc")
if err != nil {
log.Fatalf("failed to read test file: %v", err)
}
m := draco.NewMesh()
d := draco.NewDecoder()
if err := d.DecodeMesh(data, m); err != nil {
log.Fatalf("failed to decode mesh: %v", err)
}
log.Println(m.NumFaces())
if n := m.NumFaces(); n != 170 {
log.Fatalf("Mesh.NumFaces got 170, got %d", n)
}
if n := m.NumPoints(); n != 99 {
log.Fatalf("Mesh.NumFaces got 99, got %d", n)
}
faces := m.Faces(nil)
want := [3]uint32{0, 1, 2}
if got := faces[0]; got != want {
log.Fatalf("Mesh.Faces[0] got %v, got %v", want, got)
}
}
package main

import (
"io/ioutil"
"log"

"github.com/qmuntal/draco-go/draco"
)

func main() {
data, err := ioutil.ReadFile("../../testdata/test_nm.obj.edgebreaker.cl4.2.2.drc")
if err != nil {
log.Fatalf("failed to read test file: %v", err)
}
m := draco.NewMesh()
d := draco.NewDecoder()
if err := d.DecodeMesh(data, m); err != nil {
log.Fatalf("failed to decode mesh: %v", err)
}
log.Println(m.NumFaces())
if n := m.NumFaces(); n != 170 {
log.Fatalf("Mesh.NumFaces got 170, got %d", n)
}
if n := m.NumPoints(); n != 99 {
log.Fatalf("Mesh.NumFaces got 99, got %d", n)
}
faces := m.Faces(nil)
want := [3]uint32{0, 1, 2}
if got := faces[0]; got != want {
log.Fatalf("Mesh.Faces[0] got %v, got %v", want, got)
}
}

0 comments on commit efee1be

Please sign in to comment.