예제 #1
0
func octreeMesh(octree *gfx.Octant) *gfx.Mesh {
	m := new(gfx.Mesh)

	// Slice to zero.
	m.Vertices = m.Vertices[:0]
	m.Colors = m.Colors[:0]

	bci := -1
	nextBC := func() gfx.Color {
		bci++
		switch bci % 3 {
		case 0:
			return gfx.Color{1, 0, 0, 0}
		case 1:
			return gfx.Color{0, 1, 0, 0}
		case 2:
			return gfx.Color{0, 0, 1, 0}
		}
		panic("never here.")
	}

	var add func(o *gfx.Octant)
	add = func(o *gfx.Octant) {
		// Add vertices.
		before := len(m.Vertices)
		appendCube(m, float32(o.AABB.Size().X/2.0))
		center := o.AABB.Center()
		for i, v := range m.Vertices[before:] {
			vert := v.Vec3()
			vert = vert.Add(center)
			m.Vertices[before+i] = gfx.ConvertVec3(vert)
		}
		fmt.Println("Octant", o.Depth, "-", len(o.Objects), "objects")

		for s := range o.Objects {
			before := len(m.Vertices)
			appendCube(m, float32(s.AABB().Size().X/2.0))
			center := s.AABB().Center()
			//fmt.Println(center, s.AABB())
			for i, v := range m.Vertices[before:] {
				vert := v.Vec3()
				vert = vert.Add(center)
				m.Vertices[before+i] = gfx.ConvertVec3(vert)
			}
		}

		for _, octant := range o.Octants {
			if octant != nil {
				add(octant)
			}
		}
	}
	add(octree)

	for _ = range m.Vertices {
		// Add barycentric coordinates.
		m.Colors = append(m.Colors, nextBC())
	}
	return m
}
예제 #2
0
func RTreeMesh(tree *rtree.Tree, level int) *gfx.Mesh {
	m := new(gfx.Mesh)

	bci := -1
	nextBC := func() gfx.Color {
		bci++
		switch bci % 3 {
		case 0:
			return gfx.Color{1, 0, 0, 0}
		case 1:
			return gfx.Color{0, 1, 0, 0}
		case 2:
			return gfx.Color{0, 0, 1, 0}
		}
		panic("never here.")
	}

	nodes := 0
	var add func(n *rtree.Node)
	add = func(n *rtree.Node) {
		//if nodes > 100 {
		//	return
		//}
		nodes++
		if n == nil {
			return
		}
		if level == 0 || nodes == level {
			// Add vertices.
			m.Vertices = Rect3LineVerts(n.Bounds(), m.Vertices)
		}

		/*for _, s := range n.Objects {
			c := s.Bounds().Center()
			sz := 0.005
			sb := math.Rect3{
				Min: math.Vec3Zero.AddScalar(-sz).Add(c),
				Max: math.Vec3Zero.AddScalar(sz).Add(c),
			}
			m.Vertices = Rect3LineVerts(sb, m.Vertices)
		}*/

		for _, c := range n.Children {
			add(c)
		}
	}
	add(tree.Root())

	fmt.Println(tree.Count(), "objects", nodes, "nodes")

	for _ = range m.Vertices {
		// Add barycentric coordinates.
		m.Colors = append(m.Colors, nextBC())
	}
	return m
}
예제 #3
0
func appendCube(m *gfx.Mesh, scale float32) {
	addV := func(x, y, z float32) {
		m.Vertices = append(m.Vertices, gfx.Vec3{x, y, z})
	}

	s := scale

	addV(-s, -s, -s)
	addV(-s, -s, s)
	addV(-s, s, s)

	addV(s, s, -s)
	addV(-s, -s, -s)
	addV(-s, s, -s)

	addV(s, -s, s)
	addV(-s, -s, -s)
	addV(s, -s, -s)

	addV(s, s, -s)
	addV(s, -s, -s)
	addV(-s, -s, -s)

	addV(-s, -s, -s)
	addV(-s, s, s)
	addV(-s, s, -s)

	addV(s, -s, s)
	addV(-s, -s, s)
	addV(-s, -s, -s)

	addV(-s, s, s)
	addV(-s, -s, s)
	addV(s, -s, s)

	addV(s, s, s)
	addV(s, -s, -s)
	addV(s, s, -s)

	addV(s, -s, -s)
	addV(s, s, s)
	addV(s, -s, s)

	addV(s, s, s)
	addV(s, s, -s)
	addV(-s, s, -s)

	addV(s, s, s)
	addV(-s, s, -s)
	addV(-s, s, s)

	addV(s, s, s)
	addV(-s, s, s)
	addV(s, -s, s)
}
예제 #4
0
func NTreeMesh(tree *ntree.Tree, level int) *gfx.Mesh {
	m := new(gfx.Mesh)

	nodes := 0
	var add func(n *ntree.Node)
	add = func(n *ntree.Node) {
		//if nodes > 100 {
		//	return
		//}
		nodes++
		if n == nil {
			return
		}
		if level == 0 || nodes == level {
			// Add vertices.
			m.Vertices = Rect3LineVerts(n.Bounds(), m.Vertices)
		}

		fmt.Println("node", nodes, len(n.Objects), "objects")
		for _, s := range n.Objects {
			c := s.Bounds().Center()
			sz := 0.005
			sb := math.Rect3{
				Min: math.Vec3Zero.AddScalar(-sz).Add(c),
				Max: math.Vec3Zero.AddScalar(sz).Add(c),
			}
			sb = s.Bounds()
			m.Vertices = Rect3LineVerts(sb, m.Vertices)
		}

		for _, c := range n.Children {
			add(c)
		}
	}
	add(tree.Root)

	fmt.Println(tree.Count(), "objects", nodes, "nodes\n\n\n")

	// Generate the barycentric coordinates.
	//m.GenerateBary()
	return m
}
예제 #5
0
func (r *Renderer) LoadMesh(m *gfx.Mesh, done chan *gfx.Mesh) {
	// Lock the mesh until we are done loading it.
	m.Lock()
	if m.Loaded && !m.HasChanged() {
		// Mesh is already loaded and has not changed, signal completion and
		// return after unlocking.
		m.Unlock()
		select {
		case done <- m:
		default:
		}
		return
	}

	f := func() {
		// Find the native mesh, creating a new one if none exists.
		var native *nativeMesh
		if !m.Loaded {
			native = new(nativeMesh)
			native.r = r
		} else {
			native = m.NativeMesh.(*nativeMesh)
		}

		// Determine usage hint.
		usageHint := gl.STATIC_DRAW
		if m.Dynamic {
			usageHint = gl.DYNAMIC_DRAW
		}

		// Update Indices VBO.
		if !m.Loaded || m.IndicesChanged {
			if len(m.Indices) == 0 {
				// Delete indices VBO.
				r.deleteVBO(&native.indices)
			} else {
				if native.indices == 0 {
					// Create indices VBO.
					native.indices = r.createVBO()
				}
				// Update indices VBO.
				r.updateVBO(
					usageHint,
					unsafe.Sizeof(m.Indices[0]),
					len(m.Indices),
					unsafe.Pointer(&m.Indices[0]),
					native.indices,
				)
				native.indicesCount = uint32(len(m.Indices))
			}
			m.IndicesChanged = false
		}

		// Update Vertices VBO.
		if !m.Loaded || m.VerticesChanged {
			if len(m.Vertices) == 0 {
				// Delete vertices VBO.
				r.deleteVBO(&native.vertices)
				native.verticesCount = 0
			} else {
				if native.vertices == 0 {
					// Create vertices VBO.
					native.vertices = r.createVBO()
				}
				// Update vertices VBO.
				r.updateVBO(
					usageHint,
					unsafe.Sizeof(m.Vertices[0]),
					len(m.Vertices),
					unsafe.Pointer(&m.Vertices[0]),
					native.vertices,
				)
				native.verticesCount = uint32(len(m.Vertices))
			}
			m.VerticesChanged = false
		}

		// Update Colors VBO.
		if !m.Loaded || m.ColorsChanged {
			if len(m.Colors) == 0 {
				// Delete colors VBO.
				r.deleteVBO(&native.colors)
			} else {
				if native.colors == 0 {
					// Create colors VBO.
					native.colors = r.createVBO()
				}
				// Update colors VBO.
				r.updateVBO(
					usageHint,
					unsafe.Sizeof(m.Colors[0]),
					len(m.Colors),
					unsafe.Pointer(&m.Colors[0]),
					native.colors,
				)
			}
			m.ColorsChanged = false
		}

		// Update Bary VBO.
		if !m.Loaded || m.BaryChanged {
			if len(m.Bary) == 0 {
				// Delete bary VBO.
				r.deleteVBO(&native.bary)
			} else {
				if native.bary == 0 {
					// Create bary VBO.
					native.bary = r.createVBO()
				}
				// Update bary VBO.
				r.updateVBO(
					usageHint,
					unsafe.Sizeof(m.Bary[0]),
					len(m.Bary),
					unsafe.Pointer(&m.Bary[0]),
					native.bary,
				)
			}
			m.BaryChanged = false
		}

		// Any texture coordinate sets that were removed should have their
		// VBO's deleted.
		deletedMax := len(m.TexCoords)
		if deletedMax > len(native.texCoords) {
			deletedMax = len(native.texCoords)
		}
		deleted := native.texCoords[:deletedMax]
		native.texCoords = native.texCoords[:deletedMax]
		for _, vbo := range deleted {
			r.deleteVBO(&vbo)
		}

		// Any texture coordinate sets that were added should have VBO's
		// created.
		added := m.TexCoords[len(native.texCoords):]
		toUpdate := m.TexCoords
		for _, set := range added {
			vbo := r.createVBO()
			native.texCoords = append(native.texCoords, vbo)

			// Update the VBO.
			r.updateVBO(
				usageHint,
				unsafe.Sizeof(set.Slice[0]),
				len(set.Slice),
				unsafe.Pointer(&set.Slice[0]),
				vbo,
			)
		}

		// And finally, any texture coordinate sets that were changed need to
		// have their VBO's updated.
		for index, set := range toUpdate {
			if set.Changed {
				// Update the VBO.
				r.updateVBO(
					usageHint,
					unsafe.Sizeof(set.Slice[0]),
					len(set.Slice),
					unsafe.Pointer(&set.Slice[0]),
					native.texCoords[index],
				)
			}
		}

		// Ensure no buffer is active when we leave (so that OpenGL state is untouched).
		r.loader.BindBuffer(gl.ARRAY_BUFFER, 0)

		// Flush and execute OpenGL commands.
		r.loader.Flush()
		r.loader.Execute()

		// If the mesh is not loaded, then we need to assign the native mesh
		// and create a finalizer to free the native mesh later.
		if !m.Loaded {
			// Assign the native mesh.
			m.NativeMesh = native

			// Attach a finalizer to the mesh that will later free it.
			runtime.SetFinalizer(native, finalizeMesh)
		}

		// Set the mesh to loaded, clear any data slices if they are not wanted.
		m.Loaded = true
		m.ClearData()

		// Unlock, signal completion, and return.
		m.Unlock()
		select {
		case done <- m:
		default:
		}
		return
	}

	select {
	case r.LoaderExec <- f:
	default:
		go func() {
			r.LoaderExec <- f
		}()
	}
}