Bläddra i källkod

Remove geometry types, make geometry generators return *Geometry

Daniel Salvadori 6 år sedan
förälder
incheckning
baaac266bb
6 ändrade filer med 98 tillägg och 173 borttagningar
  1. 24 47
      geometry/box.go
  2. 33 29
      geometry/cylinder.go
  3. 16 33
      geometry/circle.go
  4. 9 20
      geometry/plane.go
  5. 7 21
      geometry/sphere.go
  6. 9 23
      geometry/torus.go

+ 24 - 47
geometry/box.go

@@ -9,54 +9,31 @@ import (
 	"github.com/g3n/engine/math32"
 )
 
-// Box represents the geometry of a rectangular cuboid.
-// See https://en.wikipedia.org/wiki/Cuboid#Rectangular_cuboid for more details.
-// A Box geometry is defined by its width, height, and length and also by the number
-// of segments in each dimension.
-type Box struct {
-	Geometry
-	Width          float32
-	Height         float32
-	Length         float32
-	WidthSegments  int // > 0
-	HeightSegments int // > 0
-	LengthSegments int // > 0
+// NewCube creates a cube geometry with the specified size.
+func NewCube(size float32) *Geometry {
+	return NewSegmentedCube(size, 1)
 }
 
-// NewCube creates a new cube geometry of the specified size.
-func NewCube(size float32) *Box {
-	return NewSegmentedBox(size, size, size, 1, 1, 1)
-}
-
-// NewSegmentedCube creates a cube geometry of the specified size and number of segments.
-func NewSegmentedCube(size float32, segments int) *Box {
+// NewSegmentedCube creates a segmented cube geometry with the specified size and number of segments.
+func NewSegmentedCube(size float32, segments int) *Geometry {
 	return NewSegmentedBox(size, size, size, segments, segments, segments)
 }
 
-// NewBox creates a box geometry of the specified width, height, and length.
-func NewBox(width, height, length float32) *Box {
+// NewBox creates a box geometry with the specified width, height, and length.
+func NewBox(width, height, length float32) *Geometry {
 	return NewSegmentedBox(width, height, length, 1, 1, 1)
 }
 
-// NewSegmentedBox creates a box geometry of the specified size and with the specified number
-// of segments in each dimension. This is the Box constructor with most tunable parameters.
-func NewSegmentedBox(width, height, length float32, widthSegments, heightSegments, lengthSegments int) *Box {
+// NewSegmentedBox creates a segmented box geometry with the specified width, height, length, and number of segments in each dimension.
+func NewSegmentedBox(width, height, length float32, widthSegments, heightSegments, lengthSegments int) *Geometry {
 
-	box := new(Box)
-	box.Geometry.Init()
+	box := NewGeometry()
 
 	// Validate arguments
 	if widthSegments <= 0 || heightSegments <= 0 || lengthSegments <= 0 {
 		panic("Invalid argument(s). All segment quantities should be greater than zero.")
 	}
 
-	box.Width = width
-	box.Height = height
-	box.Length = length
-	box.WidthSegments = widthSegments
-	box.HeightSegments = heightSegments
-	box.LengthSegments = lengthSegments
-
 	// Create buffers
 	positions := math32.NewArrayF32(0, 16)
 	normals := math32.NewArrayF32(0, 16)
@@ -67,18 +44,18 @@ func NewSegmentedBox(width, height, length float32, widthSegments, heightSegment
 	buildPlane := func(u, v string, udir, vdir int, width, height, length float32, materialIndex uint) {
 
 		offset := positions.Len() / 3
-		gridX := box.WidthSegments
-		gridY := box.HeightSegments
+		gridX := widthSegments
+		gridY := heightSegments
 		var w string
 
 		if (u == "x" && v == "y") || (u == "y" && v == "x") {
 			w = "z"
 		} else if (u == "x" && v == "z") || (u == "z" && v == "x") {
 			w = "y"
-			gridY = box.LengthSegments
+			gridY = lengthSegments
 		} else if (u == "z" && v == "y") || (u == "y" && v == "z") {
 			w = "x"
-			gridX = box.LengthSegments
+			gridX = lengthSegments
 		}
 
 		var normal math32.Vector3
@@ -123,16 +100,16 @@ func NewSegmentedBox(width, height, length float32, widthSegments, heightSegment
 		box.AddGroup(gstart, gcount, int(materialIndex))
 	}
 
-	wHalf := box.Width / 2
-	hHalf := box.Height / 2
-	lHalf := box.Length / 2
+	wHalf := width / 2
+	hHalf := height / 2
+	lHalf := length / 2
 
-	buildPlane("z", "y", -1, -1, box.Length, box.Height, wHalf, 0) // px
-	buildPlane("z", "y", 1, -1, box.Length, box.Height, -wHalf, 1) // nx
-	buildPlane("x", "z", 1, 1, box.Width, box.Length, hHalf, 2)    // py
-	buildPlane("x", "z", 1, -1, box.Width, box.Length, -hHalf, 3)  // ny
-	buildPlane("x", "y", 1, -1, box.Width, box.Height, lHalf, 4)   // pz
-	buildPlane("x", "y", -1, -1, box.Width, box.Height, -lHalf, 5) // nz
+	buildPlane("z", "y", -1, -1, length, height, wHalf, 0) // px
+	buildPlane("z", "y", 1, -1, length, height, -wHalf, 1) // nx
+	buildPlane("x", "z", 1, 1, width, length, hHalf, 2)    // py
+	buildPlane("x", "z", 1, -1, width, length, -hHalf, 3)  // ny
+	buildPlane("x", "y", 1, -1, width, height, lHalf, 4)   // pz
+	buildPlane("x", "y", -1, -1, width, height, -lHalf, 5) // nz
 
 	box.SetIndices(indices)
 	box.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
@@ -145,7 +122,7 @@ func NewSegmentedBox(width, height, length float32, widthSegments, heightSegment
 	box.boundingBoxValid = true
 
 	// Update bounding sphere
-	box.boundingSphere.Radius = math32.Sqrt(math32.Pow(width/2,2) + math32.Pow(height/2,2) + math32.Pow(length/2,2))
+	box.boundingSphere.Radius = math32.Sqrt(math32.Pow(width/2, 2) + math32.Pow(height/2, 2) + math32.Pow(length/2, 2))
 	box.boundingSphereValid = true
 
 	// Update area

+ 33 - 29
geometry/cylinder.go

@@ -10,37 +10,41 @@ import (
 	"math"
 )
 
-// Cylinder represents a cylinder geometry
-type Cylinder struct {
-	Geometry
-	RadiusTop      float64
-	RadiusBottom   float64
-	Height         float64
-	RadialSegments int
-	HeightSegments int
-	ThetaStart     float64
-	ThetaLength    float64
-	Top            bool
-	Bottom         bool
+// NewCone creates a cone geometry with the specified base radius, height,
+// number of radial segments, number of height segments, and presence of a bottom cap.
+func NewCone(radius, height float64, radialSegments, heightSegments int, bottom bool) *Geometry {
+	return NewConeSector(radius, height, radialSegments, heightSegments, 0, 2*math.Pi, bottom)
 }
 
-// NewCylinder creates and returns a pointer to a new Cylinder geometry object.
-func NewCylinder(radiusTop, radiusBottom, height float64,
-	radialSegments, heightSegments int,
-	thetaStart, thetaLength float64, top, bottom bool) *Cylinder {
-
-	c := new(Cylinder)
-	c.Geometry.Init()
-
-	c.RadiusTop = radiusTop
-	c.RadiusBottom = radiusBottom
-	c.Height = height
-	c.RadialSegments = radialSegments
-	c.HeightSegments = heightSegments
-	c.ThetaStart = thetaStart
-	c.ThetaLength = thetaLength
-	c.Top = top
-	c.Bottom = bottom
+// NewConeSector creates a cone sector geometry with the specified base radius, height, number of radial segments,
+// number of height segments, sector start angle in radians, sector size angle in radians, and presence of a bottom cap.
+func NewConeSector(radius, height float64, radialSegments, heightSegments int, thetaStart, thetaLength float64, bottom bool) *Geometry {
+	return NewTruncatedConeSector(0, radius, height, radialSegments, heightSegments, thetaStart, thetaLength, false, bottom)
+}
+
+// NewCylinder creates a cylinder geometry with the specified radius, height,
+// number of radial segments, number of height segments, and presence of a top and/or bottom cap.
+func NewCylinder(radius, height float64, radialSegments, heightSegments int, top, bottom bool) *Geometry {
+	return NewCylinderSector(radius, height, radialSegments, heightSegments, 0, 2*math.Pi, top, bottom)
+}
+
+// NewCylinderSector creates a cylinder sector geometry with the specified radius, height, number of radial segments,
+// number of height segments, sector start angle in radians, sector size angle in radians, and presence of a top and/or bottom cap.
+func NewCylinderSector(radius, height float64, radialSegments, heightSegments int, thetaStart, thetaLength float64, top, bottom bool) *Geometry {
+	return NewTruncatedConeSector(radius, radius, height, radialSegments, heightSegments, thetaStart, thetaLength, top, bottom)
+}
+
+// NewTruncatedCone creates a truncated cone geometry with the specified top and bottom radii,
+// height, number of radial segments, number of height segments, and presence of a top and/or bottom cap.
+func NewTruncatedCone(radiusTop, radiusBottom, height float64, radialSegments, heightSegments int, top, bottom bool) *Geometry {
+	return NewTruncatedConeSector(radiusTop, radiusBottom, height, radialSegments, heightSegments, 0, 2*math.Pi, top, bottom)
+}
+
+// NewTruncatedConeSector creates a truncated cone sector geometry with the specified top and bottom radii, height, number of radial segments,
+// number of height segments, sector start angle in radians, sector size angle in radians, and presence of a top and/or bottom cap.
+func NewTruncatedConeSector(radiusTop, radiusBottom, height float64, radialSegments, heightSegments int, thetaStart, thetaLength float64, top, bottom bool) *Geometry {
+
+	c := NewGeometry()
 
 	heightHalf := height / 2
 	vertices := [][]int{}

+ 16 - 33
geometry/circle.go

@@ -10,41 +10,24 @@ import (
 	"math"
 )
 
-// Circle represents the geometry of a filled circle (i.e. a disk)
-// The center of the circle is at the origin, and theta runs counter-clockwise
-// on the XY plane, starting at (x,y,z)=(1,0,0).
-type Circle struct {
-	Geometry
-	Radius      float64
-	Segments    int // >= 3
-	ThetaStart  float64
-	ThetaLength float64
+// NewDisk creates a disk (filled circle) geometry with the specified
+// radius and number of radial segments/triangles (minimum 3).
+func NewDisk(radius float64, segments int) *Geometry {
+	return NewDiskSector(radius, segments, 0, 2*math.Pi)
 }
 
-// NewCircle creates a new circle geometry with the specified radius
-// and number of radial segments/triangles (minimum 3).
-func NewCircle(radius float64, segments int) *Circle {
-	return NewCircleSector(radius, segments, 0, 2*math.Pi)
-}
-
-// NewCircleSector creates a new circle or circular sector geometry with the specified radius,
-// number of radial segments/triangles (minimum 3), sector start angle in radians (thetaStart),
-// and sector size angle in radians (thetaLength). This is the Circle constructor with most tunable parameters.
-func NewCircleSector(radius float64, segments int, thetaStart, thetaLength float64) *Circle {
+// NewDiskSector creates a disk (filled circle) or disk sector geometry with the specified radius,
+// number of radial segments/triangles (minimum 3), sector start angle in radians, and sector size angle in radians.
+// The center of the disk is at the origin, and theta runs counter-clockwise on the XY plane, starting at (x,y,z)=(1,0,0).
+func NewDiskSector(radius float64, segments int, thetaStart, thetaLength float64) *Geometry {
 
-	circ := new(Circle)
-	circ.Geometry.Init()
+	d := NewGeometry()
 
 	// Validate arguments
 	if segments < 3 {
 		panic("Invalid argument: segments. The number of segments needs to be greater or equal to 3.")
 	}
 
-	circ.Radius = radius
-	circ.Segments = segments
-	circ.ThetaStart = thetaStart
-	circ.ThetaLength = thetaLength
-
 	// Create buffers
 	positions := math32.NewArrayF32(0, 16)
 	normals := math32.NewArrayF32(0, 16)
@@ -81,14 +64,14 @@ func NewCircleSector(radius float64, segments int, thetaStart, thetaLength float
 		indices.Append(uint32(i), uint32(i)+1, 0)
 	}
 
-	circ.SetIndices(indices)
-	circ.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
-	circ.AddVBO(gls.NewVBO(normals).AddAttrib(gls.VertexNormal))
-	circ.AddVBO(gls.NewVBO(uvs).AddAttrib(gls.VertexTexcoord))
+	d.SetIndices(indices)
+	d.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
+	d.AddVBO(gls.NewVBO(normals).AddAttrib(gls.VertexNormal))
+	d.AddVBO(gls.NewVBO(uvs).AddAttrib(gls.VertexTexcoord))
 
 	// Update volume
-	circ.volume = 0
-	circ.volumeValid = true
+	d.volume = 0
+	d.volumeValid = true
 
-	return circ
+	return d
 }

+ 9 - 20
geometry/plane.go

@@ -9,28 +9,17 @@ import (
 	"github.com/g3n/engine/math32"
 )
 
-// Plane represents a plane geometry
-type Plane struct {
-	Geometry
-	Width          float32
-	Height         float32
-	WidthSegments  int
-	HeightSegments int
-}
-
-// NewPlane creates and returns a pointer to a Plane Geometry.
-// The plane is defined by its width, height and the number of width and height segments.
-// The minimum number of segments for the width and/or the height is 1.
+// NewPlane creates a plane geometry with the specified width and height.
 // The plane is generated centered in the XY plane with Z=0.
-func NewPlane(width, height float32, widthSegments, heightSegments int) *Plane {
+func NewPlane(width, height float32) *Geometry {
+	return NewSegmentedPlane(width, height, 1, 1)
+}
 
-	plane := new(Plane)
-	plane.Geometry.Init()
+// NewSegmentedPlane creates a segmented plane geometry with the specified width, height, and number of
+// segments in each dimension (minimum 1 in each). The plane is generated centered in the XY plane with Z=0.
+func NewSegmentedPlane(width, height float32, widthSegments, heightSegments int) *Geometry {
 
-	plane.Width = width
-	plane.Height = height
-	plane.WidthSegments = widthSegments
-	plane.HeightSegments = heightSegments
+	plane := NewGeometry()
 
 	widthHalf := width / 2
 	heightHalf := height / 2
@@ -76,7 +65,7 @@ func NewPlane(width, height float32, widthSegments, heightSegments int) *Plane {
 	plane.AddVBO(gls.NewVBO(uvs).AddAttrib(gls.VertexTexcoord))
 
 	// Update area
-	plane.area = width*height
+	plane.area = width * height
 	plane.areaValid = true
 
 	// Update volume

+ 7 - 21
geometry/sphere.go

@@ -10,30 +10,16 @@ import (
 	"math"
 )
 
-// Sphere represents a sphere geometry
-type Sphere struct {
-	Geometry
-	Radius         float64
-	WidthSegments  int
-	HeightSegments int
-	PhiStart       float64
-	PhiLength      float64
-	ThetaStart     float64
-	ThetaLength    float64
+// NewSphere creates a sphere geometry with the specified radius and number of radial segments in each dimension.
+func NewSphere(radius float64, widthSegments, heightSegments int) *Geometry {
+	return NewSphereSector(radius, widthSegments, heightSegments, 0, math.Pi*2, 0, math.Pi)
 }
 
-// NewSphere returns a pointer to a new Sphere geometry object
-func NewSphere(radius float64, widthSegments, heightSegments int, phiStart, phiLength, thetaStart, thetaLength float64) *Sphere {
+// NewSphereSector creates a sphere sector geometry with the specified radius, number of radial segments in each dimension, elevation
+// start angle in radians, elevation size angle in radians, sector start angle in radians, and sector size angle in radians.
+func NewSphereSector(radius float64, widthSegments, heightSegments int, phiStart, phiLength, thetaStart, thetaLength float64) *Geometry {
 
-	s := new(Sphere)
-	s.Geometry.Init()
-
-	s.Radius = radius
-	s.WidthSegments = widthSegments
-	s.HeightSegments = heightSegments
-	s.PhiStart = phiStart
-	s.PhiLength = phiLength
-	s.ThetaStart = thetaStart
+	s := NewGeometry()
 
 	thetaEnd := thetaStart + thetaLength
 	vertexCount := (widthSegments + 1) * (heightSegments + 1)

+ 9 - 23
geometry/torus.go

@@ -10,27 +10,13 @@ import (
 	"math"
 )
 
-// Torus represents a torus geometry
-type Torus struct {
-	Geometry                // embedded geometry
-	Radius          float64 // Torus radius
-	Tube            float64 // Diameter of the torus tube
-	RadialSegments  int     // Number of radial segments
-	TubularSegments int     // Number of tubular segments
-	Arc             float64 // Central angle
-}
-
-// NewTorus returns a pointer to a new torus geometry
-func NewTorus(radius, tube float64, radialSegments, tubularSegments int, arc float64) *Torus {
-
-	t := new(Torus)
-	t.Geometry.Init()
+// NewTorus creates a torus geometry with the specified revolution radius, tube radius,
+// number of radial segments, number of tubular segments, and arc length angle in radians.
+// TODO instead of 'arc' have thetaStart and thetaLength for consistency with other generators
+// TODO then rename this to NewTorusSector and add a NewTorus constructor
+func NewTorus(radius, tubeRadius float64, radialSegments, tubularSegments int, arc float64) *Geometry {
 
-	t.Radius = radius
-	t.Tube = tube
-	t.RadialSegments = radialSegments
-	t.TubularSegments = tubularSegments
-	t.Arc = arc
+	t := NewGeometry()
 
 	// Create buffers
 	positions := math32.NewArrayF32(0, 0)
@@ -48,9 +34,9 @@ func NewTorus(radius, tube float64, radialSegments, tubularSegments int, arc flo
 			center.Y = float32(radius * math.Sin(u))
 
 			var vertex math32.Vector3
-			vertex.X = float32((radius + tube*math.Cos(v)) * math.Cos(u))
-			vertex.Y = float32((radius + tube*math.Cos(v)) * math.Sin(u))
-			vertex.Z = float32(tube * math.Sin(v))
+			vertex.X = float32((radius + tubeRadius*math.Cos(v)) * math.Cos(u))
+			vertex.Y = float32((radius + tubeRadius*math.Cos(v)) * math.Sin(u))
+			vertex.Z = float32(tubeRadius * math.Sin(v))
 			positions.AppendVector3(&vertex)
 
 			uvs.Append(float32(float64(i)/float64(tubularSegments)), float32(float64(j)/float64(radialSegments)))