Пример #1
0
func (b bbox) Contains(pos mgl32.Vec3) bool {
	return pos.X() > b[0].X() &&
		pos.Y() > b[0].Y() &&
		pos.Z() > b[0].Z() &&
		pos.X() < b[1].X() &&
		pos.Y() < b[1].Y() &&
		pos.Z() < b[1].Z()

}
Пример #2
0
// Rotate adjusts the direction vectors by a delta vector of {pitch, yaw, roll}.
// Roll is ignored for now.
func (c *EulerCamera) Rotate(delta mgl.Vec3) {
	c.yaw += float64(delta.Y())
	c.pitch += float64(delta.X())

	// Limit vertical rotation to avoid gimbal lock
	if c.pitch > halfPi {
		c.pitch = halfPi
	} else if c.pitch < -halfPi {
		c.pitch = -halfPi
	}

	c.updateVectors()
}
Пример #3
0
func TestTransformSetPosition(t *testing.T) {
	transform := NewTransform()

	expectedPosition := mgl32.Vec3{5, 10, 3.5}
	transform.SetPosition(expectedPosition.X(), expectedPosition.Y(), expectedPosition.Z())

	if transform.position != expectedPosition {
		t.Errorf("Expected position to be %v got %v", expectedPosition, transform.position)
	}

	if transform.matrix[12] != expectedPosition.X() ||
		transform.matrix[13] != expectedPosition.Y() ||
		transform.matrix[14] != expectedPosition.Z() {
		t.Error("Matrix was not updated correctly after translation.")
	}
}
Пример #4
0
func TestTransformScale(t *testing.T) {
	transform := NewTransform()
	scale := mgl32.Vec3{2, 2, 2}

	transform.Scale(scale.X(), scale.Y(), scale.Z())

	if transform.scale != scale {
		t.Errorf("Expected scale to be %v got %v", scale, transform.scale)
	}

	if transform.matrix[0] != scale.X() ||
		transform.matrix[5] != scale.Y() ||
		transform.matrix[10] != scale.Z() {
		t.Error("Matrix was not updated correctly after translation.")
	}
}
Пример #5
0
func findFace(bound vmath.AABB, at mgl32.Vec3) direction.Type {
	switch {
	case bound.Min.X() == at.X():
		return direction.West
	case bound.Max.X() == at.X():
		return direction.East
	case bound.Min.Y() == at.Y():
		return direction.Down
	case bound.Max.Y() == at.Y():
		return direction.Up
	case bound.Min.Z() == at.Z():
		return direction.North
	case bound.Max.Z() == at.Z():
		return direction.South
	}
	return direction.Up
}
Пример #6
0
func TestTransformTranslate(t *testing.T) {
	transform := NewTransform()
	transform.SetPosition(10, 10, 10)

	vector := mgl32.Vec3{-5, 6, 3}
	expected := mgl32.Vec3{5, 16, 13}
	transform.Translate(vector)

	if transform.position != expected {
		t.Errorf("Expected position to be %v got %v", expected, transform.position)
	}

	if transform.matrix[12] != expected.X() ||
		transform.matrix[13] != expected.Y() ||
		transform.matrix[14] != expected.Z() {
		t.Error("Matrix was not updated correctly after translation.")
	}
}
Пример #7
0
// NewPianoKey returns a key for our piano.
func NewPianoKey(pos mgl32.Vec3, lightColor mgl32.Vec3, white bool, freq float32) PianoKey {
	var color mgl32.Vec4
	var keySize float32
	if white {
		color = mgl32.Vec4{0.98, 0.97, 0.94}
		keySize = 2
	} else {
		color = mgl32.Vec4{0.1, 0.1, 0.1, 1.0}
		keySize = 1

	}
	pk := PianoKey{Pos: pos, Angle: 0, Color: color, Frequency: freq, Finger: -1, white: white, LightColor: lightColor}
	pk.BBox[0] = pos.Sub(mgl32.Vec3{0.5, 0.6, keySize})
	pk.BBox[1] = pos.Add(mgl32.Vec3{0.5, 0.6, keySize})
	pk.source = al.GenSources(1)[0]
	pk.source.SetGain(1.0)
	pk.source.SetPosition(al.Vector{pos.X(), pos.Y(), pos.Z()})
	pk.source.SetVelocity(al.Vector{})
	pk.buffers = al.GenBuffers(3)

	var samples [1024 * 16]int16

	sampleRate := 44100
	amplitude := float32(0.8 * 0x7FFF)

	for i := 0; i < len(samples); i++ {
		val := f32.Sin((2.0 * math.Pi * freq) / float32(sampleRate) * float32(i))
		samples[i] = int16(amplitude * val)
	}

	buf := &bytes.Buffer{}
	binary.Write(buf, binary.LittleEndian, &samples)
	pk.buffers[0].BufferData(al.FormatMono16, buf.Bytes(), 44100)

	f, _ := os.Create("audio.raw")
	binary.Write(f, binary.LittleEndian, &samples)
	f.Close()

	return pk
}
Пример #8
0
func (a AABB) MoveOutOf(o AABB, dir mgl32.Vec3) AABB {
	if dir.X() != 0 {
		if dir.X() > 0 {
			ox := a.Max.X()
			a.Max[0] = o.Min.X() - 0.0001
			a.Min[0] += a.Max.X() - ox
		} else {
			ox := a.Min.X()
			a.Min[0] = o.Max.X() + 0.0001
			a.Max[0] += a.Min.X() - ox
		}
	}
	if dir.Y() != 0 {
		if dir.Y() > 0 {
			oy := a.Max.Y()
			a.Max[1] = o.Min.Y() - 0.0001
			a.Min[1] += a.Max.Y() - oy
		} else {
			oy := a.Min.Y()
			a.Min[1] = o.Max.Y() + 0.0001
			a.Max[1] += a.Min.Y() - oy
		}
	}

	if dir.Z() != 0 {
		if dir.Z() > 0 {
			oz := a.Max.Z()
			a.Max[2] = o.Min.Z() - 0.0001
			a.Min[2] += a.Max.Z() - oz
		} else {
			oz := a.Min.Z()
			a.Min[2] = o.Max.Z() + 0.0001
			a.Max[2] += a.Min.Z() - oz
		}
	}
	return a
}
Пример #9
0
func (i *Instance) SetScale(s mgl32.Vec3) {
	if i.scale.X() != s.X() || i.scale.Y() != s.Y() || i.scale.Z() != s.Z() {
		i.scale = s
		i.dirty = true
	}
}
Пример #10
0
func Vector3bytes(w io.Writer, vector mgl32.Vec3) {
	Float32bytes(w, vector.X())
	Float32bytes(w, vector.Y())
	Float32bytes(w, vector.Z())
}
Пример #11
0
// returns true if line (L1, L2) intersects with the box (B1, B2)
// returns intersection point in Hit
func checkLineBox(B1, B2, L1, L2 mgl32.Vec3) (bool, mgl32.Vec3) {
	var Hit mgl32.Vec3

	if L2.X() < B1.X() && L1.X() < B1.X() {
		return false, mgl32.Vec3{}
	}
	if L2.X() > B2.X() && L1.X() > B2.X() {
		return false, mgl32.Vec3{}
	}
	if L2.Y() < B1.Y() && L1.Y() < B1.Y() {
		return false, mgl32.Vec3{}
	}
	if L2.Y() > B2.Y() && L1.Y() > B2.Y() {
		return false, mgl32.Vec3{}
	}
	if L2.Z() < B1.Z() && L1.Z() < B1.Z() {
		return false, mgl32.Vec3{}
	}
	if L2.Z() > B2.Z() && L1.Z() > B2.Z() {
		return false, mgl32.Vec3{}
	}
	if L1.X() > B1.X() && L1.X() < B2.X() &&
		L1.Y() > B1.Y() && L1.Y() < B2.Y() &&
		L1.Z() > B1.Z() && L1.Z() < B2.Z() {
		Hit = L1
		return true, Hit
	}
	if (getIntersection(L1.X()-B1.X(), L2.X()-B1.X(), L1, L2, &Hit) && inBox(Hit, B1, B2, 1)) ||
		(getIntersection(L1.Y()-B1.Y(), L2.Y()-B1.Y(), L1, L2, &Hit) && inBox(Hit, B1, B2, 2)) ||
		(getIntersection(L1.Z()-B1.Z(), L2.Z()-B1.Z(), L1, L2, &Hit) && inBox(Hit, B1, B2, 3)) ||
		(getIntersection(L1.X()-B2.X(), L2.X()-B2.X(), L1, L2, &Hit) && inBox(Hit, B1, B2, 1)) ||
		(getIntersection(L1.Y()-B2.Y(), L2.Y()-B2.Y(), L1, L2, &Hit) && inBox(Hit, B1, B2, 2)) ||
		(getIntersection(L1.Z()-B2.Z(), L2.Z()-B2.Z(), L1, L2, &Hit) && inBox(Hit, B1, B2, 3)) {
		return true, Hit
	}

	return false, mgl32.Vec3{}
}
Пример #12
0
func inBox(Hit, B1, B2 mgl32.Vec3, Axis int) bool {
	if Axis == 1 && Hit.Z() > B1.Z() && Hit.Z() < B2.Z() && Hit.Y() > B1.Y() && Hit.Y() < B2.Y() {
		return true
	}
	if Axis == 2 && Hit.Z() > B1.Z() && Hit.Z() < B2.Z() && Hit.X() > B1.X() && Hit.X() < B2.X() {
		return true
	}
	if Axis == 3 && Hit.X() > B1.X() && Hit.X() < B2.X() && Hit.Y() > B1.Y() && Hit.Y() < B2.Y() {
		return true
	}
	return false
}
Пример #13
0
func programLoop(window *win.Window) error {

	// the linked shader program determines how the data will be rendered
	vertShader, err := gfx.NewShaderFromFile("shaders/phong.vert", gl.VERTEX_SHADER)
	if err != nil {
		return err
	}

	fragShader, err := gfx.NewShaderFromFile("shaders/phong.frag", gl.FRAGMENT_SHADER)
	if err != nil {
		return err
	}

	program, err := gfx.NewProgram(vertShader, fragShader)
	if err != nil {
		return err
	}
	defer program.Delete()

	lightFragShader, err := gfx.NewShaderFromFile("shaders/light.frag", gl.FRAGMENT_SHADER)
	if err != nil {
		return err
	}

	// special shader program so that lights themselves are not affected by lighting
	lightProgram, err := gfx.NewProgram(vertShader, lightFragShader)
	if err != nil {
		return err
	}

	VAO := createVAO(cubeVertices, nil)
	lightVAO := createVAO(cubeVertices, nil)

	// ensure that triangles that are "behind" others do not draw over top of them
	gl.Enable(gl.DEPTH_TEST)

	camera := cam.NewFpsCamera(mgl32.Vec3{0, 0, 3}, mgl32.Vec3{0, 1, 0}, -90, 0, window.InputManager())

	for !window.ShouldClose() {

		// swaps in last buffer, polls for window events, and generally sets up for a new render frame
		window.StartFrame()

		// update camera position and direction from input evevnts
		camera.Update(window.SinceLastFrame())

		// background color
		gl.ClearColor(0, 0, 0, 1.0)
		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // depth buffer needed for DEPTH_TEST

		// cube rotation matrices
		rotateX := (mgl32.Rotate3DX(mgl32.DegToRad(-45 * float32(glfw.GetTime()))))
		rotateY := (mgl32.Rotate3DY(mgl32.DegToRad(-45 * float32(glfw.GetTime()))))
		rotateZ := (mgl32.Rotate3DZ(mgl32.DegToRad(-45 * float32(glfw.GetTime()))))

		// creates perspective
		fov := float32(60.0)
		projectTransform := mgl32.Perspective(mgl32.DegToRad(fov),
			float32(window.Width())/float32(window.Height()),
			0.1,
			100.0)

		camTransform := camera.GetTransform()
		lightPos := mgl32.Vec3{0.6, 1, 0.1}
		lightTransform := mgl32.Translate3D(lightPos.X(), lightPos.Y(), lightPos.Z()).Mul4(
			mgl32.Scale3D(0.2, 0.2, 0.2))

		program.Use()
		gl.UniformMatrix4fv(program.GetUniformLocation("view"), 1, false, &camTransform[0])
		gl.UniformMatrix4fv(program.GetUniformLocation("project"), 1, false,
			&projectTransform[0])

		gl.BindVertexArray(VAO)

		// draw each cube after all coordinate system transforms are bound

		// obj is colored, light is white
		gl.Uniform3f(program.GetUniformLocation("material.ambient"), 1.0, 0.5, 0.31)
		gl.Uniform3f(program.GetUniformLocation("material.diffuse"), 1.0, 0.5, 0.31)
		gl.Uniform3f(program.GetUniformLocation("material.specular"), 0.5, 0.5, 0.5)
		gl.Uniform1f(program.GetUniformLocation("material.shininess"), 32.0)

		lightColor := mgl32.Vec3{
			float32(math.Sin(glfw.GetTime() * 1)),
			float32(math.Sin(glfw.GetTime() * 0.35)),
			float32(math.Sin(glfw.GetTime() * 0.65)),
		}

		diffuseColor := mgl32.Vec3{
			0.5 * lightColor[0],
			0.5 * lightColor[1],
			0.5 * lightColor[2],
		}
		ambientColor := mgl32.Vec3{
			0.2 * lightColor[0],
			0.2 * lightColor[1],
			0.2 * lightColor[2],
		}

		gl.Uniform3f(program.GetUniformLocation("light.ambient"),
			ambientColor[0], ambientColor[1], ambientColor[2])
		gl.Uniform3f(program.GetUniformLocation("light.diffuse"),
			diffuseColor[0], diffuseColor[1], diffuseColor[2])
		gl.Uniform3f(program.GetUniformLocation("light.specular"), 1.0, 1.0, 1.0)
		gl.Uniform3f(program.GetUniformLocation("light.position"), lightPos.X(), lightPos.Y(), lightPos.Z())

		for _, pos := range cubePositions {

			// turn the cubes into rectangular prisms for more fun
			worldTranslate := mgl32.Translate3D(pos[0], pos[1], pos[2])
			worldTransform := worldTranslate.Mul4(
				rotateX.Mul3(rotateY).Mul3(rotateZ).Mat4(),
			)

			gl.UniformMatrix4fv(program.GetUniformLocation("model"), 1, false,
				&worldTransform[0])

			gl.DrawArrays(gl.TRIANGLES, 0, 36)
		}
		gl.BindVertexArray(0)

		// Draw the light obj after the other boxes using its separate shader program
		// this means that we must re-bind any uniforms
		lightProgram.Use()
		gl.BindVertexArray(lightVAO)
		gl.UniformMatrix4fv(lightProgram.GetUniformLocation("model"), 1, false, &lightTransform[0])
		gl.UniformMatrix4fv(lightProgram.GetUniformLocation("view"), 1, false, &camTransform[0])
		gl.UniformMatrix4fv(lightProgram.GetUniformLocation("project"), 1, false, &projectTransform[0])
		gl.DrawArrays(gl.TRIANGLES, 0, 36)

		gl.BindVertexArray(0)

		// end of draw loop
	}

	return nil
}
Пример #14
0
func randomVector(min, max mgl32.Vec3) mgl32.Vec3 {
	r1, r2, r3 := rand.Float32(), rand.Float32(), rand.Float32()
	return mgl32.Vec3{min.X()*(1.0-r1) + max.X()*r1, min.Y()*(1.0-r2) + max.Y()*r2, min.Z()*(1.0-r3) + max.Z()*r3}
}
Пример #15
0
//
// objectToObjectData
// Turns the data from .obj format into an internal OpenGL friendly
// format. The following information needs to be created for each mesh.
//
//    mesh.V = append(mesh.V, ...4-float32) - indexed from 0
//    mesh.N = append(mesh.N, ...3-float32) - indexed from 0
//    mesh.T = append(mesh.T, ...2-float32)	- indexed from 0
//    mesh.F = append(mesh.F, ...3-uint16)	- refers to above zero indexed values
//
// objectData holds the global vertex, texture, and normal point information.
// faces are the indexes for this mesh.
//
// Additionally the normals at each vertex are generated as the sum of the
// normals for each face that shares that vertex.
//
// @param name (string) The Name of the Object.
// @param objectData (*objectData) A temporary object data pointer.
// @param objectData (*objectData) The array of Faces / Indices.
//
// @return data (*ObjectData) A pointer to the Object.
// @return error (error) the error (if any)
//
func (loader *Loader) objectToObjectData(name string, objectData *objectData, faces []face) (data *ObjectData, err error) {
	data = &ObjectData{}
	data.Name = name
	vmap := make(map[string]int) // the unique vertex data points for this face.
	vcnt := -1

	// process each vertex of each face.  Each one represents a combination vertex,
	// texture coordinate, and normal.
	for _, face := range faces {
		for pi := 0; pi < 3; pi++ { // Load only triangles
			//		for pi, _ := range face.s {
			v, t, n := -1, -1, -1

			if len(face.s) > pi {
				faceIndex := face.s[pi]

				if v, t, n, err = parseFaceIndices(faceIndex); err != nil {
					return data, fmt.Errorf("Could not parse face data %s", err)
				}

				// cut down the amount of information passed around by reusing points
				// where the vertex and the texture coordinate information is the same.
				vertexIndex := fmt.Sprintf("%d/%d/%d", v, t, n)
				if _, ok := vmap[vertexIndex]; !ok {

					// add a new data point.
					vcnt++
					vmap[vertexIndex] = vcnt
					data.Vertex = append(data.Vertex, objectData.vertices[v].x, objectData.vertices[v].y, objectData.vertices[v].z)

					// Object might not have normals
					if n != -1 {
						data.Normals = append(data.Normals, objectData.normals[n].x, objectData.normals[n].y, objectData.normals[n].z)
					}

					// Object might not have texture information
					if t != -1 {
						data.Coordinates = append(data.Coordinates, objectData.texture[t].u, objectData.texture[t].v)
					}
				} else {
					// update the normal at the vertex to be a combination of
					// all the normals of each face that shares the vertex.
					ni := vmap[vertexIndex] * 3

					// Obj might not have normals
					if n != -1 && len(data.Normals) > (ni+2) {
						var n1 mgl32.Vec3 = mgl32.Vec3{
							float32(data.Normals[ni]),
							float32(data.Normals[ni+1]),
							float32(data.Normals[ni+2]),
						}

						var n2 mgl32.Vec3 = mgl32.Vec3{
							float32(objectData.normals[n].x),
							float32(objectData.normals[n].y),
							float32(objectData.normals[n].z),
						}

						n2 = n2.Add(n1).Normalize()

						data.Normals[ni], data.Normals[ni+1], data.Normals[ni+2] = float32(n2.X()), float32(n2.Y()), float32(n2.Z())
					}
				}

				data.Faces = append(data.Faces, uint16(vmap[vertexIndex]))
			}
		}
	}
	return data, err
}
Пример #16
0
func (i *Instance) SetPosition(p mgl32.Vec3) {
	if i.position.X() != p.X() || i.position.Y() != p.Y() || i.position.Z() != p.Z() {
		i.position = p
		i.dirty = true
	}
}
Пример #17
0
func playSoundInternal(cat soundCategory, snd sound, vol, pitch float64, rel bool, pos mgl32.Vec3, cb func()) {
	vol *= snd.Volume * 100
	baseVol := vol
	vol *= float64(muVolMaster.Value()) / 100
	if v, ok := volVars[cat]; ok {
		vol *= float64(v.Value()) / 100
	}
	if vol <= 0 {
		if cb != nil {
			go func() { syncChan <- cb }()
		}
		return
	}
	name := snd.Name
	key := pluginKey{"minecraft", name}
	sb, ok := loadedSounds[key]
	if !ok {
		f, err := resource.Open("minecraft", "sounds/"+name+".ogg")
		if err != nil {
			v, ok := assets.Objects[fmt.Sprintf("minecraft/sounds/%s.ogg", name)]
			if !ok {
				console.Text("Missing sound %s", key)
				if cb != nil {
					cb()
				}
				return
			}
			loc := fmt.Sprintf("./resources/%s", hashPath(v.Hash))
			f, err = os.Open(loc)
			if err != nil {
				console.Text("Missing sound %s", key)
				if cb != nil {
					cb()
				}
				return
			}
		}
		if snd.Stream {
			m := audio.NewMusic(f)
			m.SetVolume(vol)
			m.SetPitch(pitch)
			m.Play()
			currentMusic = append(currentMusic, music{Music: m, cb: cb, cat: cat, vol: baseVol})
			return
		}
		defer f.Close()
		data, err := ioutil.ReadAll(f)
		if err != nil {
			panic(err)
		}
		sb = audio.NewSoundBufferData(data)
		loadedSounds[key] = sb
	}
	var s audio.Sound
	n := true
	for _, sn := range soundList {
		if sn.Status() == audio.StatStopped {
			s = sn
			n = false
			break
		}
	}
	if n {
		if len(soundList) >= 100 {
			console.Component(
				format.Build("WARN: Skipping playing sound due to limit").
					Color(format.Yellow).Create(),
			)
			return
		}
		s = audio.NewSound()
		soundList = append(soundList, s)
	}
	s.SetBuffer(sb)
	s.SetVolume(vol)
	s.SetMinDistance(5)
	s.SetAttenuation(0.008)
	s.SetPitch(pitch)
	s.Play()
	if rel {
		s.SetRelative(true)
		s.SetPosition(pos.X(), pos.Y(), pos.Z())
	} else {
		s.SetRelative(false)
	}
}
Пример #18
0
func traceRay(max float32, s, d mgl32.Vec3, cb func(x, y, z int) bool) {
	type gen struct {
		count   int
		base, d float32
	}
	newGen := func(start, d float32) *gen {
		g := &gen{}
		if d > 0 {
			g.base = (float32(math.Ceil(float64(start))) - start) / d
		} else if d < 0 {
			d = float32(math.Abs(float64(d)))
			g.base = (start - float32(math.Floor(float64(start)))) / d
		}
		g.d = d
		return g
	}
	next := func(g *gen) float32 {
		g.count++
		if g.d == 0 {
			return float32(math.Inf(1))
		}
		return g.base + float32(g.count-1)/g.d
	}

	aGen := newGen(s.X(), d.X())
	bGen := newGen(s.Y(), d.Y())
	cGen := newGen(s.Z(), d.Z())
	nextNA := next(aGen)
	nextNB := next(bGen)
	nextNC := next(cGen)

	x, y, z := int(math.Floor(float64(s.X()))), int(math.Floor(float64(s.Y()))), int(math.Floor(float64(s.Z())))

	for {
		if !cb(x, y, z) {
			return
		}
		nextN := float32(0.0)
		if nextNA <= nextNB {
			if nextNA <= nextNC {
				nextN = nextNA
				nextNA = next(aGen)
				x += int(math.Copysign(1, float64(d.X())))
			} else {
				nextN = nextNC
				nextNC = next(cGen)
				z += int(math.Copysign(1, float64(d.Z())))
			}
		} else {
			if nextNB <= nextNC {
				nextN = nextNB
				nextNB = next(bGen)
				y += int(math.Copysign(1, float64(d.Y())))
			} else {
				nextN = nextNC
				nextNC = next(cGen)
				z += int(math.Copysign(1, float64(d.Z())))
			}
		}
		if nextN > max {
			break
		}
	}
}