Browse Source

Merge branch 'master' into physics

Daniel Salvadori 7 years ago
parent
commit
385579c565
60 changed files with 753 additions and 397 deletions
  1. 3 3
      README.md
  2. 129 0
      animation/animation.go
  3. 223 0
      animation/channel.go
  4. 12 0
      animation/logger.go
  5. 9 0
      audio/al/al.go
  6. 2 0
      audio/ov/vorbisfile.go
  7. 2 0
      audio/vorbis/vorbis.go
  8. 30 109
      camera/camera.go
  9. 7 3
      camera/control/orbit_control.go
  10. 27 5
      camera/orthographic.go
  11. 17 18
      camera/perspective.go
  12. 0 1
      core/doc.go
  13. 1 2
      core/logger.go
  14. 14 42
      core/node.go
  15. 2 1
      core/timer.go
  16. 17 15
      geometry/geometry.go
  17. 1 1
      gls/build.go
  18. 2 1
      gls/uniform.go
  19. 10 10
      graphic/graphic.go
  20. 2 1
      gui/align.go
  21. 4 4
      gui/assets/data.go
  22. 1 0
      gui/assets/icon/icodes.go
  23. 2 2
      gui/button.go
  24. 1 0
      gui/docklayout.go
  25. 2 2
      gui/folder.go
  26. 1 0
      gui/gridlayout.go
  27. 5 3
      gui/image_button.go
  28. 1 1
      gui/imagelabel.go
  29. 2 2
      gui/itemscroller.go
  30. 1 1
      gui/label.go
  31. 10 10
      gui/list.go
  32. 1 0
      gui/menu.go
  33. 27 27
      gui/panel.go
  34. 2 1
      gui/root.go
  35. 25 25
      gui/scroller.go
  36. 10 10
      gui/style_dark.go
  37. 2 2
      gui/style_light.go
  38. 8 9
      gui/table.go
  39. 2 2
      gui/tree.go
  40. 1 0
      gui/window.go
  41. 1 0
      light/directional.go
  42. 0 1
      light/doc.go
  43. 5 5
      light/spot.go
  44. 1 1
      material/material.go
  45. 1 1
      material/physical.go
  46. 38 0
      math32/array.go
  47. 1 10
      math32/box3.go
  48. 1 0
      math32/frustum.go
  49. 35 23
      math32/matrix4.go
  50. 0 2
      math32/plane.go
  51. 26 26
      renderer/renderer.go
  52. 1 1
      renderer/shaman.go
  53. 1 1
      text/font.go
  54. 0 1
      texture/doc.go
  55. 1 0
      tools/g3nicodes/main.go
  56. 2 1
      tools/g3nshaders/main.go
  57. 2 1
      util/logger/console.go
  58. 5 0
      util/logger/file.go
  59. 10 10
      util/logger/logger.go
  60. 4 0
      util/logger/net.go

+ 3 - 3
README.md

@@ -21,6 +21,8 @@ G3N was heavily inspired by [three.js](https://threejs.org/).
 
 ## Dependencies
 
+**G3N requires Go 1.8+**
+
 The engine needs an OpenGL driver installed in the system and on Unix like systems
 depends on some C libraries that can be installed using the distribution package manager.
 In all cases it is necessary to have a gcc compatible C compiler installed.
@@ -48,8 +50,6 @@ In all cases it is necessary to have a gcc compatible C compiler installed.
   your are using [Homebrew](https://brew.sh/) as your package manager, run:
   `brew install libvorbis openal-soft`
 
-G3N requires Go 1.8+
-
 ## Installation
 
 The following command will download the engine and all its dependencies, compile and
@@ -210,4 +210,4 @@ send pull requests.
 
 ## Community
 
-Join our [channel](https://gophers.slack.com/messages/g3n) on Gophers Slack.
+Join our [channel](https://gophers.slack.com/messages/g3n) on Gophers Slack ([Click here to register for Gophers Slack](https://invite.slack.golangbridge.org/)).

+ 129 - 0
animation/animation.go

@@ -0,0 +1,129 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package animation
+package animation
+
+// Animation is a keyframe animation, containing channels.
+// Each channel animates a specific property of an object.
+// Animations can span multiple objects and properties.
+type Animation struct {
+	name     string     // Animation name
+	loop     bool       // Whether the animation loops
+	paused   bool       // Whether the animation is paused
+	start    float32    // Initial time offset value
+	time     float32    // Total running time
+	minTime  float32    // Minimum time value across all channels
+	maxTime  float32    // Maximum time value across all channels
+	channels []IChannel // List of channels
+}
+
+// NewAnimation creates and returns a pointer to a new Animation object.
+func NewAnimation() *Animation {
+
+	anim := new(Animation)
+	return anim
+}
+
+// SetName sets the animation name.
+func (anim *Animation) SetName(name string) {
+
+	anim.name = name
+}
+
+// Name returns the animation name.
+func (anim *Animation) Name() string {
+
+	return anim.name
+}
+
+// Reset resets the animation to the beginning.
+func (anim *Animation) Reset() {
+
+	anim.time = anim.start
+}
+
+// SetPaused sets whether the animation is paused.
+func (anim *Animation) SetPaused(state bool) {
+
+	anim.paused = state
+}
+
+// Paused returns whether the animation is paused.
+func (anim *Animation) Paused() bool {
+
+	return anim.paused
+}
+
+// SetLoop sets whether the animation is looping.
+func (anim *Animation) SetLoop(state bool) {
+
+	anim.loop = state
+}
+
+// Loop returns whether the animation is looping.
+func (anim *Animation) Loop() bool {
+
+	return anim.loop
+}
+
+// SetStart sets the initial time offset value.
+func (anim *Animation) SetStart(v float32) {
+
+	anim.start = v
+}
+
+// Update interpolates and updates the target values for each channel.
+// If the animation is paused, returns false. If the animation is not paused,
+// returns true if the input value is inside the key frames ranges or false otherwise.
+func (anim *Animation) Update(delta float32) bool {
+
+	// Check if paused
+	if anim.paused {
+		return false
+	}
+
+	// Check if input is less than minimum
+	anim.time = anim.time + delta
+	if anim.time < anim.minTime {
+		return false
+	}
+
+	// Check if input is greater than maximum
+	if anim.time > anim.maxTime {
+		if anim.loop {
+			anim.Reset()
+		} else {
+			return false
+		}
+	}
+
+	// Update all channels
+	for i := 0; i < len(anim.channels); i++ {
+		ch := anim.channels[i]
+		ch.Update(anim.time)
+	}
+
+	return true
+}
+
+// AddChannel adds a channel to the animation.
+func (anim *Animation) AddChannel(ch IChannel) {
+
+	// TODO (maybe) prevent user from adding two channels of the same type that share target ?
+
+	// Add the channel
+	anim.channels = append(anim.channels, ch)
+
+	// Update maxTime and minTime values
+	kf := ch.Keyframes()
+	firstKf := kf[0]
+	if anim.minTime > firstKf {
+		anim.minTime = firstKf
+	}
+	lastKf := kf[len(kf)-1]
+	if anim.maxTime < lastKf {
+		anim.maxTime = lastKf
+	}
+}

+ 223 - 0
animation/channel.go

@@ -0,0 +1,223 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package animation
+
+import (
+	"github.com/g3n/engine/core"
+	"github.com/g3n/engine/math32"
+)
+
+// A Channel associates an animation parameter channel to an interpolation sampler
+type Channel struct {
+	keyframes          math32.ArrayF32          // Input keys (usually time)
+	values             math32.ArrayF32          // Outputs values for the keys
+	interpType         InterpolationType        // Interpolation type
+	interpAction       func(idx int, k float32) // Combined function for interpolation and update
+	updateInterpAction func()                   // Function to update interpAction based on interpolation type
+	inTangent          math32.ArrayF32          // Origin tangents for Spline interpolation
+	outTangent         math32.ArrayF32          // End tangents for Spline interpolation
+}
+
+// SetBuffers sets the keyframe and value buffers.
+func (c *Channel) SetBuffers(keyframes, values math32.ArrayF32) {
+
+	c.keyframes = keyframes
+	c.values = values
+}
+
+// Keyframes returns the keyframe buffer.
+func (c *Channel) Keyframes() math32.ArrayF32 {
+
+	return c.keyframes
+}
+
+// Values returns the value buffer.
+func (c *Channel) Values() math32.ArrayF32 {
+
+	return c.values
+}
+
+// SetInterpolationTangents sets the interpolation tangents.
+func (c *Channel) SetInterpolationTangents(inTangent, outTangent math32.ArrayF32) {
+
+	c.inTangent = inTangent
+	c.outTangent = outTangent
+}
+
+// InterpolationTangents sets the interpolation tangents
+func (c *Channel) InterpolationTangents() (inTangent, outTangent math32.ArrayF32) {
+
+	return c.inTangent, c.outTangent
+}
+
+// SetInterpolationType sets the interpolation type for this channel.
+func (c *Channel) SetInterpolationType(it InterpolationType) {
+
+	// Don't update function if not needed
+	if c.interpType == it {
+		return
+	}
+
+	// Save interpolation type
+	c.interpType = it
+
+	// Call specialized function that updates the interpAction function
+	c.updateInterpAction()
+}
+
+// InterpolationType returns the current interpolation type.
+func (c *Channel) InterpolationType() InterpolationType {
+
+	return c.interpType
+}
+
+// Update finds the keyframe preceding the specified time.
+// Then, calls a stored function to interpolate the relevant values and update the target.
+func (c *Channel) Update(time float32) {
+
+	// Test limits
+	if (len(c.keyframes) < 2) || (time < c.keyframes[0]) || (time > c.keyframes[len(c.keyframes)-1]) {
+		return
+	}
+
+	// Find key frame interval
+	var idx int
+	for idx = 0; idx < len(c.keyframes)-1; idx++ {
+		if time >= c.keyframes[idx] && time < c.keyframes[idx+1] {
+			break
+		}
+	}
+
+	// Check if last keyframe
+	if idx >= len(c.keyframes)-1 {
+		return
+	}
+
+	// Interpolate and update
+	relativeDelta := (time-c.keyframes[idx])/(c.keyframes[idx+1]-c.keyframes[idx])
+	c.interpAction(idx, relativeDelta)
+}
+
+// IChannel is the interface for all channel types.
+type IChannel interface {
+	Update(time float32)
+	Keyframes() math32.ArrayF32
+	Values() math32.ArrayF32
+	SetInterpolationType(it InterpolationType)
+}
+
+// NodeChannel is the IChannel for all node transforms.
+type NodeChannel struct {
+	Channel
+	target core.INode
+}
+
+// PositionChannel is the animation channel for a node's position.
+type PositionChannel NodeChannel
+
+func NewPositionChannel(node core.INode) *PositionChannel {
+
+	pc := new(PositionChannel)
+	pc.target = node
+	pc.updateInterpAction = func() {
+		// Get node
+		node := pc.target.GetNode()
+		// Update interpolation function
+		switch pc.interpType {
+		case STEP:
+			pc.interpAction = func(idx int, k float32) {
+				var v math32.Vector3
+				pc.values.GetVector3(idx*3, &v)
+				node.SetPositionVec(&v)
+			}
+		case LINEAR:
+			pc.interpAction = func(idx int, k float32) {
+				var v1, v2 math32.Vector3
+				pc.values.GetVector3(idx*3, &v1)
+				pc.values.GetVector3((idx+1)*3, &v2)
+				v1.Lerp(&v2, k)
+				node.SetPositionVec(&v1)
+			}
+		}
+	}
+	pc.SetInterpolationType(LINEAR)
+	return pc
+}
+
+// RotationChannel is the animation channel for a node's rotation.
+type RotationChannel NodeChannel
+
+func NewRotationChannel(node core.INode) *RotationChannel {
+
+	rc := new(RotationChannel)
+	rc.target = node
+	rc.updateInterpAction = func() {
+		// Get node
+		node := rc.target.GetNode()
+		// Update interpolation function
+		switch rc.interpType {
+		case STEP:
+			rc.interpAction = func(idx int, k float32) {
+				var q math32.Vector4
+				rc.values.GetVector4(idx*4, &q)
+				node.SetQuaternionVec(&q)
+			}
+		case LINEAR:
+			rc.interpAction = func(idx int, k float32) {
+				var q1, q2 math32.Vector4
+				rc.values.GetVector4(idx*4, &q1)
+				rc.values.GetVector4((idx+1)*4, &q2)
+				quat1 := math32.NewQuaternion(q1.X, q1.Y, q1.Z, q1.W)
+				quat2 := math32.NewQuaternion(q2.X, q2.Y, q2.Z, q2.W)
+				quat1.Slerp(quat2, k)
+				node.SetQuaternionQuat(quat1)
+			}
+		}
+	}
+	rc.SetInterpolationType(LINEAR)
+	return rc
+}
+
+// ScaleChannel is the animation channel for a node's scale.
+type ScaleChannel NodeChannel
+
+func NewScaleChannel(node core.INode) *ScaleChannel {
+
+	sc := new(ScaleChannel)
+	sc.target = node
+	sc.updateInterpAction = func() {
+		// Get node
+		node := sc.target.GetNode()
+		// Update interpolation function
+		switch sc.interpType {
+		case STEP:
+			sc.interpAction = func(idx int, k float32) {
+				var v math32.Vector3
+				sc.values.GetVector3(idx*3, &v)
+				node.SetScaleVec(&v)
+			}
+		case LINEAR:
+			sc.interpAction = func(idx int, k float32) {
+				var v1, v2 math32.Vector3
+				sc.values.GetVector3(idx*3, &v1)
+				sc.values.GetVector3((idx+1)*3, &v2)
+				v1.Lerp(&v2, k)
+				node.SetScaleVec(&v1)
+			}
+		}
+	}
+	sc.SetInterpolationType(LINEAR)
+	return sc
+}
+
+// InterpolationType specifies the interpolation type.
+type InterpolationType int
+
+// The various interpolation types.
+const (
+	STEP        = InterpolationType(iota) // The animated values remain constant to the output of the first keyframe, until the next keyframe.
+	LINEAR                                // The animated values are linearly interpolated between keyframes. Spherical linear interpolation (slerp) is used to interpolate quaternions.
+	CUBICSPLINE                           // TODO
+)

+ 12 - 0
animation/logger.go

@@ -0,0 +1,12 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package animation
+
+import (
+	"github.com/g3n/engine/util/logger"
+)
+
+// Package logger
+var log = logger.New("ANIMATION", logger.Default)

+ 9 - 0
audio/al/al.go

@@ -8,9 +8,11 @@ package al
 
 /*
 #cgo darwin   CFLAGS:  -DGO_DARWIN  -I/usr/local/opt/openal-soft/include/AL -I/usr/include/AL
+#cgo freebsd  CFLAGS:  -DGO_FREEBSD -I/usr/local/include/AL
 #cgo linux    CFLAGS:  -DGO_LINUX   -I/usr/include/AL
 #cgo windows  CFLAGS:  -DGO_WINDOWS -I${SRCDIR}/../windows/openal-soft-1.18.2/include/AL
 #cgo darwin   LDFLAGS: -L/usr/local/opt/openal-soft/lib -lopenal
+#cgo freebsd  LDFLAGS: -L/usr/local/lib -lopenal
 #cgo linux    LDFLAGS: -lopenal
 #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -lOpenAL32
 
@@ -21,6 +23,13 @@ package al
 #include "efx.h"
 #endif
 
+#ifdef GO_FREEBSD
+#include <stdlib.h>
+#include "al.h"
+#include "alc.h"
+#include "efx.h"
+#endif
+
 #ifdef GO_LINUX
 #include <stdlib.h>
 #include "al.h"

+ 2 - 0
audio/ov/vorbisfile.go

@@ -7,9 +7,11 @@
 package ov
 
 // #cgo darwin   CFLAGS:  -DGO_DARWIN  -I/usr/include/vorbis -I/usr/local/include/vorbis
+// #cgo freebsd  CFLAGS:  -DGO_FREEBSD -I/usr/include/vorbis -I/usr/local/include/vorbis
 // #cgo linux    CFLAGS:  -DGO_LINUX   -I/usr/include/vorbis
 // #cgo windows  CFLAGS:  -DGO_WINDOWS -I${SRCDIR}/../windows/libvorbis-1.3.5/include/vorbis -I${SRCDIR}/../windows/libogg-1.3.3/include
 // #cgo darwin   LDFLAGS: -L/usr/lib -L/usr/local/lib -lvorbisfile
+// #cgo freebsd  LDFLAGS: -L/usr/lib -L/usr/local/lib -lvorbisfile
 // #cgo linux    LDFLAGS: -lvorbisfile
 // #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -llibvorbisfile
 // #include <stdlib.h>

+ 2 - 0
audio/vorbis/vorbis.go

@@ -7,9 +7,11 @@
 package vorbis
 
 // #cgo darwin   CFLAGS:  -DGO_DARWIN  -I/usr/include/vorbis -I/usr/local/include/vorbis
+// #cgo freebsd  CFLAGS:  -DGO_FREEBSD -I/usr/local/include/vorbis
 // #cgo linux    CFLAGS:  -DGO_LINUX   -I/usr/include/vorbis
 // #cgo windows  CFLAGS:  -DGO_WINDOWS -I${SRCDIR}/../windows/libvorbis-1.3.5/include/vorbis -I${SRCDIR}/../windows/libogg-1.3.3/include
 // #cgo darwin   LDFLAGS: -L/usr/lib -L/usr/local/lib -lvorbis
+// #cgo freebsd  LDFLAGS: -L/usr/local/lib -lvorbis
 // #cgo linux    LDFLAGS: -lvorbis
 // #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -llibvorbis
 // #include "codec.h"

+ 30 - 109
camera/camera.go

@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package camera contain common camera types used for rendering 3D scenes.
+// Package camera contains common camera types used for rendering 3D scenes.
 package camera
 
 import (
@@ -10,7 +10,7 @@ import (
 	"github.com/g3n/engine/math32"
 )
 
-// ICamera is interface for all camera types
+// ICamera is interface for all camera types.
 type ICamera interface {
 	GetCamera() *Camera
 	ViewMatrix(*math32.Matrix4)
@@ -20,151 +20,72 @@ type ICamera interface {
 	SetRaycaster(rc *core.Raycaster, x, y float32) error
 }
 
-// Camera is the base camera which is normally embedded in other camera types
+// Camera is the base camera which is normally embedded in other camera types.
 type Camera struct {
 	core.Node                 // Embedded Node
-	target     math32.Vector3 // camera target in world coordinates
-	up         math32.Vector3 // camera Up vector
-	viewMatrix math32.Matrix4 // last calculated view matrix
+	target     math32.Vector3 // Camera target in world coordinates
+	up         math32.Vector3 // Camera Up vector
+	viewMatrix math32.Matrix4 // Last calculated view matrix
 }
 
 // Initialize initializes the base camera.
-// It is used by other camera types which embed this base camera
+// Normally used by other camera types which embed this base camera.
 func (cam *Camera) Initialize() {
 
 	cam.Node.Init()
 	cam.target.Set(0, 0, 0)
 	cam.up.Set(0, 1, 0)
 	cam.SetDirection(0, 0, -1)
-	cam.updateQuaternion()
 }
 
-// WorldDirection updates the specified vector with the
-// current world direction the camera is pointed
-func (cam *Camera) WorldDirection(result *math32.Vector3) {
-
-	var wpos math32.Vector3
-	cam.WorldPosition(&wpos)
-	*result = cam.target
-	result.Sub(&wpos).Normalize()
-}
-
-// LookAt sets the camera target position
+// LookAt rotates the camera to look at the specified target position.
+// This method does not support objects with rotated and/or translated parent(s).
+// TODO: maybe move method to Node, or create similar in Node.
 func (cam *Camera) LookAt(target *math32.Vector3) {
 
 	cam.target = *target
-	cam.updateQuaternion()
+
+	var rotMat math32.Matrix4
+	pos := cam.Position()
+	rotMat.LookAt(&pos, &cam.target, &cam.up)
+
+	var q math32.Quaternion
+	q.SetFromRotationMatrix(&rotMat)
+	cam.SetQuaternionQuat(&q)
 }
 
-// GetCamera satisfies the ICamera interface
+// GetCamera satisfies the ICamera interface.
 func (cam *Camera) GetCamera() *Camera {
 
 	return cam
 }
 
-// Target get the current target position
+// Target get the current target position.
 func (cam *Camera) Target() math32.Vector3 {
 
 	return cam.target
 }
 
-// Up get the current up position
+// Up get the current camera up vector.
 func (cam *Camera) Up() math32.Vector3 {
 
 	return cam.up
 }
 
-// SetUp sets the camera up vector
+// SetUp sets the camera up vector.
 func (cam *Camera) SetUp(up *math32.Vector3) {
 
 	cam.up = *up
+	cam.LookAt(&cam.target) // TODO Maybe remove and let user call LookAt explicitly
 }
 
-// SetPosition sets this camera world position
-// This method overrides the Node method to update
-// the camera quaternion, because changing the camera position
-// may change its rotation
-func (cam *Camera) SetPosition(x, y, z float32) {
-
-	cam.Node.SetPosition(x, y, z)
-	cam.updateQuaternion()
-}
-
-// SetPositionX sets this camera world position
-// This method overrides the Node method to update
-// the camera quaternion, because changing the camera position
-// may change its rotation
-func (cam *Camera) SetPositionX(x float32) {
-	cam.Node.SetPositionX(x)
-	cam.updateQuaternion()
-}
-
-// SetPositionY sets this camera world position
-// This method overrides the Node method to update
-// the camera quaternion, because changing the camera position
-// may change its rotation
-func (cam *Camera) SetPositionY(y float32) {
-	cam.Node.SetPositionY(y)
-	cam.updateQuaternion()
-}
-
-// SetPositionZ sets this camera world position
-// This method overrides the Node method to update
-// the camera quaternion, because changing the camera position
-// may change its rotation
-func (cam *Camera) SetPositionZ(z float32) {
-	cam.Node.SetPositionZ(z)
-	cam.updateQuaternion()
-}
-
-// SetPositionVec sets this node position from the specified vector pointer
-// This method overrides the Node method to update
-// the camera quaternion, because changing the camera position
-// may change its rotation
-func (cam *Camera) SetPositionVec(vpos *math32.Vector3) {
-
-	cam.Node.SetPositionVec(vpos)
-	cam.updateQuaternion()
-}
-
-// ViewMatrix returns the current view matrix of this camera
+// ViewMatrix returns the current view matrix of this camera.
 func (cam *Camera) ViewMatrix(m *math32.Matrix4) {
 
-	var wpos math32.Vector3
-	cam.WorldPosition(&wpos)
-	cam.viewMatrix.LookAt(&wpos, &cam.target, &cam.up)
-	*m = cam.viewMatrix
-}
-
-// updateQuaternion must be called when the camera position or target
-// is changed to update its quaternion.
-// This is important if the camera has children, such as an audio listener
-func (cam *Camera) updateQuaternion() {
-
-	var wdir math32.Vector3
-	cam.WorldDirection(&wdir)
-	var q math32.Quaternion
-	q.SetFromUnitVectors(&math32.Vector3{0, 0, -1}, &wdir)
-	cam.SetQuaternionQuat(&q)
-}
-
-// Project satisfies the ICamera interface and must
-// be implemented for specific camera types.
-func (cam *Camera) Project(v *math32.Vector3) (*math32.Vector3, error) {
-
-	panic("Not implemented")
-}
-
-// Unproject satisfies the ICamera interface and must
-// be implemented for specific camera types.
-func (cam *Camera) Unproject(v *math32.Vector3) (*math32.Vector3, error) {
-
-	panic("Not implemented")
-}
-
-// SetRaycaster satisfies the ICamera interface and must
-// be implemented for specific camera types.
-func (cam *Camera) SetRaycaster(rc *core.Raycaster, x, y float32) error {
-
-	panic("Not implemented")
+	cam.UpdateMatrixWorld()
+	matrixWorld := cam.MatrixWorld()
+	err := m.GetInverse(&matrixWorld)
+	if err != nil {
+		panic("Camera.ViewMatrix: Couldn't invert matrix")
+	}
 }

+ 7 - 3
camera/control/orbit_control.go

@@ -12,6 +12,7 @@ import (
 	"math"
 )
 
+// OrbitControl is a camera controller that allows orbiting a center point while looking at it.
 type OrbitControl struct {
 	Enabled         bool    // Control enabled state
 	EnableRotate    bool    // Rotate enabled state
@@ -109,6 +110,7 @@ func NewOrbitControl(icam camera.ICamera, win window.IWindow) *OrbitControl {
 	return oc
 }
 
+// Dispose unsubscribes from all events
 func (oc *OrbitControl) Dispose() {
 
 	// Unsubscribe to event handlers
@@ -142,21 +144,21 @@ func (oc *OrbitControl) Zoom(delta float32) {
 	oc.updateZoom()
 }
 
-// Rotate camera left by specified angle
+// RotateLeft rotates the camera left by specified angle
 func (oc *OrbitControl) RotateLeft(angle float32) {
 
 	oc.thetaDelta -= angle
 	oc.updateRotate()
 }
 
-// Rotate camera up by specified angle
+// RotateUp rotates the camera up by specified angle
 func (oc *OrbitControl) RotateUp(angle float32) {
 
 	oc.phiDelta -= angle
 	oc.updateRotate()
 }
 
-// Updates camera rotation from tethaDelta and phiDelta
+// Updates the camera rotation from thetaDelta and phiDelta
 func (oc *OrbitControl) updateRotate() {
 
 	const EPS = 0.01
@@ -203,6 +205,7 @@ func (oc *OrbitControl) updateRotate() {
 	position = target
 	position.Add(&vdir)
 	oc.cam.SetPositionVec(&position)
+	oc.cam.LookAt(&target)
 
 	// Reset deltas
 	oc.thetaDelta = 0
@@ -249,6 +252,7 @@ func (oc *OrbitControl) updateRotate2() {
 	position.Add(&vdir)
 	log.Debug("orbit set position")
 	oc.cam.SetPositionVec(&position)
+	oc.cam.LookAt(&target)
 
 	// Reset deltas
 	oc.thetaDelta = 0

+ 27 - 5
camera/orthographic.go

@@ -6,9 +6,10 @@ package camera
 
 import (
 	"github.com/g3n/engine/math32"
+	"github.com/g3n/engine/core"
 )
 
-// Orthographic is
+// Orthographic is an orthographic camera.
 type Orthographic struct {
 	Camera              // Embedded camera
 	left        float32 // left plane x coordinate
@@ -38,26 +39,26 @@ func NewOrthographic(left, right, top, bottom, near, far float32) *Orthographic
 	return cam
 }
 
-// SetZoom sets the zoom factor of the camera
+// SetZoom sets the zoom factor of the camera.
 func (cam *Orthographic) SetZoom(zoom float32) {
 
 	cam.zoom = math32.Abs(zoom)
 	cam.projChanged = true
 }
 
-// Zoom returns the zoom factor of the camera
+// Zoom returns the zoom factor of the camera.
 func (cam *Orthographic) Zoom() float32 {
 
 	return cam.zoom
 }
 
-// Planes returns the coordinates of the camera planes
+// Planes returns the coordinates of the camera planes.
 func (cam *Orthographic) Planes() (left, right, top, bottom, near, far float32) {
 
 	return cam.left, cam.right, cam.top, cam.bottom, cam.near, cam.far
 }
 
-// ProjMatrix satisfies the ICamera interface
+// ProjMatrix satisfies the ICamera interface.
 func (cam *Orthographic) ProjMatrix(m *math32.Matrix4) {
 
 	if cam.projChanged {
@@ -66,3 +67,24 @@ func (cam *Orthographic) ProjMatrix(m *math32.Matrix4) {
 	}
 	*m = cam.projMatrix
 }
+
+// Project satisfies the ICamera interface and must
+// be implemented for specific camera types.
+func (cam *Camera) Project(v *math32.Vector3) (*math32.Vector3, error) {
+
+	panic("Not implemented")
+}
+
+// Unproject satisfies the ICamera interface and must
+// be implemented for specific camera types.
+func (cam *Camera) Unproject(v *math32.Vector3) (*math32.Vector3, error) {
+
+	panic("Not implemented")
+}
+
+// SetRaycaster satisfies the ICamera interface and must
+// be implemented for specific camera types.
+func (cam *Camera) SetRaycaster(rc *core.Raycaster, x, y float32) error {
+
+	panic("Not implemented")
+}

+ 17 - 18
camera/perspective.go

@@ -9,7 +9,7 @@ import (
 	"github.com/g3n/engine/math32"
 )
 
-// Perspective represents a perspective camera
+// Perspective is a perspective camera.
 type Perspective struct {
 	Camera                     // Embedded camera
 	fov         float32        // field of view in degrees
@@ -34,45 +34,45 @@ func NewPerspective(fov, aspect, near, far float32) *Perspective {
 	return cam
 }
 
-// SetFov sets the camera field of view in degrees
+// SetFov sets the camera field of view in degrees.
 func (cam *Perspective) SetFov(fov float32) {
 
 	cam.fov = fov
 	cam.projChanged = true
 }
 
-// SetAspect sets the camera aspect ratio (width/height)
+// SetAspect sets the camera aspect ratio (width/height).
 func (cam *Perspective) SetAspect(aspect float32) {
 
 	cam.aspect = aspect
 	cam.projChanged = true
 }
 
-// Fov returns the current camera FOV (field of view) in degrees
+// Fov returns the current camera FOV (field of view) in degrees.
 func (cam *Perspective) Fov() float32 {
 
 	return cam.fov
 }
 
-// Aspect returns the current camera aspect ratio
+// Aspect returns the current camera aspect ratio.
 func (cam Perspective) Aspect() float32 {
 
 	return cam.aspect
 }
 
-// Near returns the current camera near plane Z coordinate
+// Near returns the current camera near plane Z coordinate.
 func (cam *Perspective) Near() float32 {
 
 	return cam.near
 }
 
-// Far returns the current camera far plane Z coordinate
+// Far returns the current camera far plane Z coordinate.
 func (cam *Perspective) Far() float32 {
 
 	return cam.far
 }
 
-// ProjMatrix satisfies the ICamera interface
+// ProjMatrix satisfies the ICamera interface.
 func (cam *Perspective) ProjMatrix(m *math32.Matrix4) {
 
 	cam.updateProjMatrix()
@@ -82,13 +82,18 @@ func (cam *Perspective) ProjMatrix(m *math32.Matrix4) {
 // Project transforms the specified position from world coordinates to this camera projected coordinates.
 func (cam *Perspective) Project(v *math32.Vector3) (*math32.Vector3, error) {
 
-	cam.updateProjMatrix()
+	// Get camera view matrix
 	var matrix math32.Matrix4
 	matrixWorld := cam.MatrixWorld()
 	err := matrix.GetInverse(&matrixWorld)
 	if err != nil {
 		return nil, err
 	}
+
+	// Update camera projection matrix
+	cam.updateProjMatrix()
+
+	// Multiply viewMatrix by projMatrix and apply the resulting projection matrix to the provided vector
 	matrix.MultiplyMatrices(&cam.projMatrix, &matrix)
 	v.ApplyProjection(&matrix)
 	return v, nil
@@ -98,18 +103,12 @@ func (cam *Perspective) Project(v *math32.Vector3) (*math32.Vector3, error) {
 func (cam *Perspective) Unproject(v *math32.Vector3) (*math32.Vector3, error) {
 
 	// Get inverted camera view matrix
-	var viewMatrix math32.Matrix4
-	cam.ViewMatrix(&viewMatrix)
-	var invertedViewMatrix math32.Matrix4
-	err := invertedViewMatrix.GetInverse(&viewMatrix)
-	if err != nil {
-		return nil, err
-	}
+	invertedViewMatrix := cam.MatrixWorld()
 
 	// Get inverted camera projection matrix
 	cam.updateProjMatrix()
 	var invertedProjMatrix math32.Matrix4
-	err = invertedProjMatrix.GetInverse(&cam.projMatrix)
+	err := invertedProjMatrix.GetInverse(&cam.projMatrix)
 	if err != nil {
 		return nil, err
 	}
@@ -142,7 +141,7 @@ func (cam *Perspective) SetRaycaster(rc *core.Raycaster, sx, sy float32) error {
 	return nil
 }
 
-// updateProjMatrix updates this camera projection matrix if necessary
+// updateProjMatrix updates the projection matrix if necessary.
 func (cam *Perspective) updateProjMatrix() {
 
 	if cam.projChanged {

+ 0 - 1
core/doc.go

@@ -4,4 +4,3 @@
 
 // Package core implements some basic types used by other packages.
 package core
-

+ 1 - 2
core/logger.go

@@ -1,9 +1,8 @@
 package core
 
 import (
-    "github.com/g3n/engine/util/logger"
+	"github.com/g3n/engine/util/logger"
 )
 
 // Package logger
 var log = logger.New("CORE", logger.Default)
-

+ 14 - 42
core/node.go

@@ -490,6 +490,13 @@ func (n *Node) SetQuaternion(x, y, z, w float32) {
 	n.changed = true
 }
 
+// SetQuaternionVec sets the quaternion based on the specified quaternion unit multiples vector.
+func (n *Node) SetQuaternionVec(q *math32.Vector4) {
+
+	n.quaternion.Set(q.X, q.Y, q.Z, q.W)
+	n.changed = true
+}
+
 // SetQuaternionQuat sets the quaternion based on the specified quaternion pointer.
 func (n *Node) SetQuaternionQuat(q *math32.Quaternion) {
 
@@ -649,53 +656,18 @@ func (n *Node) UpdateMatrix() bool {
 	return true
 }
 
-// UpdateMatrixWorld updates the world transform matrix for this node and for all of its children.
+// UpdateMatrixWorld updates this node world transform matrix and of all its children
 func (n *Node) UpdateMatrixWorld() {
 
+	n.UpdateMatrix()
 	if n.parent == nil {
-		n.updateMatrixWorld(&n.matrix)
+		n.matrixWorld = n.matrix
 	} else {
 		parent := n.parent.GetNode()
-		n.updateMatrixWorld(&parent.matrixWorld)
-	}
-}
-
-// updateMatrixWorld is used internally by UpdateMatrixWorld.
-// If the local transform matrix has changed, this method updates it and also the world matrix of this node.
-// Children are updated recursively. If any node has changed, then we update the world matrix
-// of all of its descendants regardless if their local matrices have changed.
-func (n *Node) updateMatrixWorld(parentMatrixWorld *math32.Matrix4) {
-
-	// If the local transform matrix for this node has changed then we need to update the local
-	// matrix for this node and also the world matrix for this and all subsequent nodes.
-	if n.UpdateMatrix() {
-		n.matrixWorld.MultiplyMatrices(parentMatrixWorld, &n.matrix)
-
-		// Update matrices of children recursively, always updating the world matrix
-		for _, ichild := range n.children {
-			ichild.GetNode().updateMatrixWorldNoCheck(&n.matrixWorld)
-		}
-	} else {
-		// Update matrices of children recursively, continuing to check for changes
-		for _, ichild := range n.children {
-			ichild.GetNode().updateMatrixWorld(&n.matrixWorld)
-		}
+		n.matrixWorld.MultiplyMatrices(&parent.matrixWorld, &n.matrix)
 	}
-}
-
-// updateMatrixWorldNoCheck is used internally by updateMatrixWorld.
-// This method should be called when a node has changed since it always updates the matrix world.
-func (n *Node) updateMatrixWorldNoCheck(parentMatrixWorld *math32.Matrix4) {
-
-	// Update the local transform matrix (if necessary)
-	n.UpdateMatrix()
-
-	// Always update the matrix world since an ancestor of this node has changed
-	// (i.e. and ancestor had its local transform matrix modified)
-	n.matrixWorld.MultiplyMatrices(parentMatrixWorld, &n.matrix)
-
-	// Update matrices of children recursively
+	// Update this Node children matrices
 	for _, ichild := range n.children {
-		ichild.GetNode().updateMatrixWorldNoCheck(&n.matrixWorld)
+		ichild.UpdateMatrixWorld()
 	}
-}
+}

+ 2 - 1
core/timer.go

@@ -8,12 +8,13 @@ import (
 	"time"
 )
 
+// TimerManager manages multiple timers
 type TimerManager struct {
 	nextID int       // next timer id
 	timers []timeout // list of timeouts
 }
 
-// Type for timer callback functions
+// TimerCallback is the type for timer callback functions
 type TimerCallback func(interface{})
 
 // Internal structure for each active timer

+ 17 - 15
geometry/geometry.go

@@ -9,14 +9,14 @@ import (
 	"github.com/g3n/engine/math32"
 )
 
-// Interface for all geometries
+// IGeometry is the interface for all geometries.
 type IGeometry interface {
 	GetGeometry() *Geometry
 	RenderSetup(gs *gls.GLS)
 	Dispose()
 }
 
-// Geometry encapsulates a three-dimensional geometric shape.
+// Geometry encapsulates a three-dimensional vertex-based geometry.
 type Geometry struct {
 	refcount            int             // Current number of references
 	vbos                []*gls.VBO      // Array of VBOs
@@ -42,7 +42,7 @@ type Geometry struct {
 	rotInertiaValid     bool            // Indicates if last calculated rotational inertia matrix is valid
 }
 
-// Geometry group object
+// Group is a geometry group object.
 type Group struct {
 	Start    int    // Index of first element of the group
 	Count    int    // Number of elements in the group
@@ -50,6 +50,7 @@ type Group struct {
 	Matid    string // Material id used when loading external models
 }
 
+// NewGeometry creates and returns a pointer to a new Geometry.
 func NewGeometry() *Geometry {
 
 	g := new(Geometry)
@@ -57,7 +58,7 @@ func NewGeometry() *Geometry {
 	return g
 }
 
-// Init initializes the geometry
+// Init initializes the geometry.
 func (g *Geometry) Init() {
 
 	g.refcount = 1
@@ -101,19 +102,20 @@ func (g *Geometry) Dispose() {
 	g.Init()
 }
 
+// GetGeometry satisfies the IGeometry interface.
 func (g *Geometry) GetGeometry() *Geometry {
 
 	return g
 }
 
-// AddGroup adds a geometry group (for multimaterial)
+// AddGroup adds a geometry group (for multimaterial).
 func (g *Geometry) AddGroup(start, count, matIndex int) *Group {
 
 	g.groups = append(g.groups, Group{start, count, matIndex, ""})
 	return &g.groups[len(g.groups)-1]
 }
 
-// AddGroupList adds the specified list of groups to this geometry
+// AddGroupList adds the specified list of groups to this geometry.
 func (g *Geometry) AddGroupList(groups []Group) {
 
 	for _, group := range groups {
@@ -121,19 +123,19 @@ func (g *Geometry) AddGroupList(groups []Group) {
 	}
 }
 
-// GroupCount returns the number of geometry groups (for multimaterial)
+// GroupCount returns the number of geometry groups (for multimaterial).
 func (g *Geometry) GroupCount() int {
 
 	return len(g.groups)
 }
 
-// GroupAt returns pointer to geometry group at the specified index
+// GroupAt returns pointer to geometry group at the specified index.
 func (g *Geometry) GroupAt(idx int) *Group {
 
 	return &g.groups[idx]
 }
 
-// SetIndices sets the indices array for this geometry
+// SetIndices sets the indices array for this geometry.
 func (g *Geometry) SetIndices(indices math32.ArrayU32) {
 
 	g.indices = indices
@@ -142,13 +144,13 @@ func (g *Geometry) SetIndices(indices math32.ArrayU32) {
 	g.boundingSphereValid = false
 }
 
-// Indices returns this geometry indices array
+// Indices returns this geometry indices array.
 func (g *Geometry) Indices() math32.ArrayU32 {
 
 	return g.indices
 }
 
-// AddVBO adds a Vertex Buffer Object for this geometry
+// AddVBO adds a Vertex Buffer Object for this geometry.
 func (g *Geometry) AddVBO(vbo *gls.VBO) {
 
 	// Check that the provided VBO doesn't have conflicting attributes with existing VBOs
@@ -175,9 +177,9 @@ func (g *Geometry) VBO(attrib string) *gls.VBO {
 	return nil
 }
 
-// Returns the number of items in the first VBO
+// Items returns the number of items in the first VBO.
 // (The number of items should be same for all VBOs)
-// An item is a complete group of attributes in the VBO buffer
+// An item is a complete group of attributes in the VBO buffer.
 func (g *Geometry) Items() int {
 
 	if len(g.vbos) == 0 {
@@ -287,7 +289,7 @@ func (g *Geometry) Indexed() bool {
 }
 
 // BoundingBox computes the bounding box of the geometry if necessary
-// and returns is value
+// and returns is value.
 func (g *Geometry) BoundingBox() math32.Box3 {
 
 	// If valid, return its value
@@ -457,7 +459,7 @@ func (g *Geometry) ApplyMatrix(m *math32.Matrix4) {
 	})
 }
 
-// RenderSetup is called by the renderer before drawing the geometry
+// RenderSetup is called by the renderer before drawing the geometry.
 func (g *Geometry) RenderSetup(gs *gls.GLS) {
 
 	// First time initialization

+ 1 - 1
gls/build.go

@@ -9,7 +9,7 @@ package gls
 
 // // Platform build flags
 // #cgo freebsd CFLAGS:  -DGL_GLEXT_PROTOTYPES
-// #cgo freebsd LDFLAGS: -ldl
+// #cgo freebsd LDFLAGS: 
 //
 // #cgo linux   CFLAGS:  -DGL_GLEXT_PROTOTYPES
 // #cgo linux   LDFLAGS: -ldl

+ 2 - 1
gls/uniform.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 )
 
+// Uniform represents an OpenGL uniform.
 type Uniform struct {
 	name      string // base name
 	nameIdx   string // cached indexed name
@@ -16,7 +17,7 @@ type Uniform struct {
 	lastIndex int32  // last index
 }
 
-// Init initializes this uniform location cache and sets its name
+// Init initializes this uniform location cache and sets its name.
 func (u *Uniform) Init(name string) {
 
 	u.name = name

+ 10 - 10
graphic/graphic.go

@@ -24,8 +24,8 @@ type Graphic struct {
 	renderable bool               // Renderable flag
 	cullable   bool               // Cullable flag
 
-	mvm        math32.Matrix4     // Cached ModelView matrix
-	mvpm       math32.Matrix4     // Cached ModelViewProjection matrix
+	mvm  math32.Matrix4 // Cached ModelView matrix
+	mvpm math32.Matrix4 // Cached ModelViewProjection matrix
 }
 
 // GraphicMaterial specifies the material to be used for
@@ -169,24 +169,24 @@ func (gr *Graphic) GetMaterial(vpos int) material.IMaterial {
 }
 
 // CalculateMatrices calculates the model view and model view projection matrices.
-func (g *Graphic) CalculateMatrices(gs *gls.GLS, rinfo *core.RenderInfo) {
+func (gr *Graphic) CalculateMatrices(gs *gls.GLS, rinfo *core.RenderInfo) {
 
 	// Calculate model view and model view projection matrices
-	mw := g.MatrixWorld()
-	g.mvm.MultiplyMatrices(&rinfo.ViewMatrix, &mw)
-	g.mvpm.MultiplyMatrices(&rinfo.ProjMatrix, &g.mvm)
+	mw := gr.MatrixWorld()
+	gr.mvm.MultiplyMatrices(&rinfo.ViewMatrix, &mw)
+	gr.mvpm.MultiplyMatrices(&rinfo.ProjMatrix, &gr.mvm)
 }
 
 // ModelViewMatrix returns the last cached model view matrix for this graphic.
-func (g *Graphic) ModelViewMatrix() *math32.Matrix4 {
+func (gr *Graphic) ModelViewMatrix() *math32.Matrix4 {
 
-	return &g.mvm
+	return &gr.mvm
 }
 
 // ModelViewProjectionMatrix returns the last cached model view projection matrix for this graphic.
-func (g *Graphic) ModelViewProjectionMatrix() *math32.Matrix4 {
+func (gr *Graphic) ModelViewProjectionMatrix() *math32.Matrix4 {
 
-	return &g.mvpm
+	return &gr.mvpm
 }
 
 // GetMaterial returns the material associated with the GraphicMaterial.

+ 2 - 1
gui/align.go

@@ -4,9 +4,10 @@
 
 package gui
 
-// Align specifies the alignment of an object inside another
+// Align specifies the alignment of an object inside another.
 type Align int
 
+// The various types of alignment.
 const (
 	AlignNone   = Align(iota) // No alignment
 	AlignLeft                 // Align horizontally at left

+ 4 - 4
gui/assets/data.go

@@ -86,7 +86,7 @@ func fontsFreemonoTtf() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "fonts/FreeMono.ttf", size: 592632, mode: os.FileMode(436), modTime: time.Unix(1512153466, 0)}
+	info := bindataFileInfo{name: "fonts/FreeMono.ttf", size: 592632, mode: os.FileMode(438), modTime: time.Unix(1515256752, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -106,7 +106,7 @@ func fontsFreesansTtf() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "fonts/FreeSans.ttf", size: 1563256, mode: os.FileMode(436), modTime: time.Unix(1512153466, 0)}
+	info := bindataFileInfo{name: "fonts/FreeSans.ttf", size: 1563256, mode: os.FileMode(438), modTime: time.Unix(1515256752, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -126,7 +126,7 @@ func fontsFreesansboldTtf() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "fonts/FreeSansBold.ttf", size: 416128, mode: os.FileMode(436), modTime: time.Unix(1512153466, 0)}
+	info := bindataFileInfo{name: "fonts/FreeSansBold.ttf", size: 416128, mode: os.FileMode(438), modTime: time.Unix(1515256752, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -146,7 +146,7 @@ func fontsMaterialiconsRegularTtf() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "fonts/MaterialIcons-Regular.ttf", size: 128180, mode: os.FileMode(436), modTime: time.Unix(1512153466, 0)}
+	info := bindataFileInfo{name: "fonts/MaterialIcons-Regular.ttf", size: 128180, mode: os.FileMode(438), modTime: time.Unix(1515256752, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }

+ 1 - 0
gui/assets/icon/icodes.go

@@ -5,6 +5,7 @@
 
 package icon
 
+// Icon constants.
 const (
 	N3dRotation                           = string(0xe84d)
 	AcUnit                                = string(0xeb3b)

+ 2 - 2
gui/button.go

@@ -32,10 +32,10 @@ type Button struct {
 	pressed   bool          // true if button is pressed
 }
 
-// Button style
+// ButtonStyle contains the styling of a Button
 type ButtonStyle BasicStyle
 
-// All Button styles
+// ButtonStyles contains one ButtonStyle for each possible button state
 type ButtonStyles struct {
 	Normal   ButtonStyle
 	Over     ButtonStyle

+ 1 - 0
gui/docklayout.go

@@ -13,6 +13,7 @@ type DockLayoutParams struct {
 	Edge int
 }
 
+// The different types of docking.
 const (
 	DockTop = iota + 1
 	DockRight

+ 2 - 2
gui/folder.go

@@ -22,8 +22,8 @@ type Folder struct {
 // FolderStyle contains the styling of a Folder.
 type FolderStyle struct {
 	PanelStyle
-	FgColor     math32.Color4
-	Icons       [2]string
+	FgColor math32.Color4
+	Icons   [2]string
 }
 
 // FolderStyles contains a FolderStyle for each valid GUI state.

+ 1 - 0
gui/gridlayout.go

@@ -1,6 +1,7 @@
 // Copyright 2016 The G3N Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
+
 package gui
 
 // GridLayout is a panel layout which arranges its children in a rectangular grid.

+ 5 - 3
gui/image_button.go

@@ -21,20 +21,22 @@ type ImageButton struct {
 	stateImages [ButtonDisabled + 1]*texture.Texture2D // array of images for each button state
 }
 
+// ButtonState specifies a button state.
 type ButtonState int
 
+// The possible button states.
 const (
 	ButtonNormal ButtonState = iota
 	ButtonOver
-	//ButtonFocus
 	ButtonPressed
 	ButtonDisabled
+	// ButtonFocus
 )
 
-// ImageButton style
+// ImageButtonStyle contains the styling of an ImageButton.
 type ImageButtonStyle BasicStyle
 
-// All ImageButton styles
+// ImageButtonStyles contains one ImageButtonStyle for each possible ImageButton state.
 type ImageButtonStyles struct {
 	Normal   ImageButtonStyle
 	Over     ImageButtonStyle

+ 1 - 1
gui/imagelabel.go

@@ -29,7 +29,7 @@ type ImageLabel struct {
 	icon  *Label // optional internal icon label
 }
 
-// ImageLabelStyle
+// ImageLabelStyle contains the styling of an ImageLabel.
 type ImageLabelStyle BasicStyle
 
 // NewImageLabel creates and returns a pointer to a new image label widget

+ 2 - 2
gui/itemscroller.go

@@ -405,7 +405,7 @@ func (s *ItemScroller) vRecalc() {
 			// Break when the view/content proportion becomes smaller than the minimum button size
 			totalHeight += item.TotalHeight()
 		}
-		s.vscroll.SetButtonSize(s.height * s.height/totalHeight)
+		s.vscroll.SetButtonSize(s.height * s.height / totalHeight)
 	}
 
 	// Items width
@@ -470,7 +470,7 @@ func (s *ItemScroller) hRecalc() {
 			// Break when the view/content proportion becomes smaller than the minimum button size
 			totalWidth += item.GetPanel().Width()
 		}
-		s.hscroll.SetButtonSize(s.width * s.width/totalWidth)
+		s.hscroll.SetButtonSize(s.width * s.width / totalWidth)
 	}
 
 	// Items height

+ 1 - 1
gui/label.go

@@ -35,7 +35,7 @@ func NewLabel(text string) *Label {
 	return NewLabelWithFont(text, StyleDefault().Font)
 }
 
-// NewLabel creates and returns a label panel with
+// NewIcon creates and returns a label panel with
 // the specified text drawn using the default icon font.
 func NewIcon(icon string) *Label {
 	return NewLabelWithFont(icon, StyleDefault().FontIcon)

+ 10 - 10
gui/list.go

@@ -10,13 +10,13 @@ import (
 
 // List represents a list GUI element
 type List struct {
-	ItemScroller         // Embedded scroller
-	styles   *ListStyles // Pointer to styles
-	single   bool        // Single selection flag (default is true)
-	focus    bool        // has keyboard focus
-	dropdown bool        // this is used as dropdown
-	keyNext  window.Key  // Code of key to select next item
-	keyPrev  window.Key  // Code of key to select previous item
+	ItemScroller             // Embedded scroller
+	styles       *ListStyles // Pointer to styles
+	single       bool        // Single selection flag (default is true)
+	focus        bool        // has keyboard focus
+	dropdown     bool        // this is used as dropdown
+	keyNext      window.Key  // Code of key to select next item
+	keyPrev      window.Key  // Code of key to select previous item
 }
 
 // ListItem encapsulates each item inserted into the list
@@ -29,13 +29,13 @@ type ListItem struct {
 	list        *List   // Pointer to list
 }
 
-// ListStyles
+// ListStyles encapsulates a set of styles for the list and item.
 type ListStyles struct {
 	Scroller *ItemScrollerStyles
 	Item     *ListItemStyles
 }
 
-// ListItemStyles
+// ListItemStyles contains one ListItemStyle for each possible item state.
 type ListItemStyles struct {
 	Normal      ListItemStyle
 	Over        ListItemStyle
@@ -44,7 +44,7 @@ type ListItemStyles struct {
 	SelHigh     ListItemStyle
 }
 
-// ListItemStyle
+// ListItemStyle contains the styling of a list item.
 type ListItemStyle BasicStyle
 
 // OnListItemResize is the identifier of the event dispatched when a ListItem's child panel is resized

+ 1 - 0
gui/menu.go

@@ -12,6 +12,7 @@ import (
 	"time"
 )
 
+// Menu is the menu GUI element
 type Menu struct {
 	Panel                // embedded panel
 	styles   *MenuStyles // pointer to current styles

+ 27 - 27
gui/panel.go

@@ -58,30 +58,30 @@ type IPanel interface {
 // and a content area. The content area can be associated with a texture
 // It is the building block of most GUI widgets.
 type Panel struct {
-	*graphic.Graphic                // Embedded graphic
-	root         *Root              // pointer to root container
-	width        float32            // external width in pixels
-	height       float32            // external height in pixels
-	mat          *material.Material // panel material
-	marginSizes  RectBounds         // external margin sizes in pixel coordinates
-	borderSizes  RectBounds         // border sizes in pixel coordinates
-	paddingSizes RectBounds         // padding sizes in pixel coordinates
-	content      Rect               // current content rectangle in pixel coordinates
-	pospix       math32.Vector3     // absolute position in pixels
-	posclip      math32.Vector3     // position in clip (NDC) coordinates
-	wclip        float32            // width in clip coordinates
-	hclip        float32            // height in clip coordinates
-	xmin         float32            // minimum absolute x this panel can use
-	xmax         float32            // maximum absolute x this panel can use
-	ymin             float32        // minimum absolute y this panel can use
-	ymax             float32        // maximum absolute y this panel can use
-	bounded          bool           // panel is bounded by its parent
-	enabled          bool           // enable event processing
-	cursorEnter      bool           // mouse enter dispatched
-	layout           ILayout        // current layout for children
-	layoutParams     interface{}    // current layout parameters used by container panel
-	uniMatrix        gls.Uniform    // model matrix uniform location cache
-	uniPanel         gls.Uniform    // panel parameters uniform location cache
+	*graphic.Graphic                    // Embedded graphic
+	root             *Root              // pointer to root container
+	width            float32            // external width in pixels
+	height           float32            // external height in pixels
+	mat              *material.Material // panel material
+	marginSizes      RectBounds         // external margin sizes in pixel coordinates
+	borderSizes      RectBounds         // border sizes in pixel coordinates
+	paddingSizes     RectBounds         // padding sizes in pixel coordinates
+	content          Rect               // current content rectangle in pixel coordinates
+	pospix           math32.Vector3     // absolute position in pixels
+	posclip          math32.Vector3     // position in clip (NDC) coordinates
+	wclip            float32            // width in clip coordinates
+	hclip            float32            // height in clip coordinates
+	xmin             float32            // minimum absolute x this panel can use
+	xmax             float32            // maximum absolute x this panel can use
+	ymin             float32            // minimum absolute y this panel can use
+	ymax             float32            // maximum absolute y this panel can use
+	bounded          bool               // panel is bounded by its parent
+	enabled          bool               // enable event processing
+	cursorEnter      bool               // mouse enter dispatched
+	layout           ILayout            // current layout for children
+	layoutParams     interface{}        // current layout parameters used by container panel
+	uniMatrix        gls.Uniform        // model matrix uniform location cache
+	uniPanel         gls.Uniform        // panel parameters uniform location cache
 	udata            struct {           // Combined uniform data 8 * vec4
 		bounds        math32.Vector4 // panel bounds in texture coordinates
 		borders       math32.Vector4 // panel borders in texture coordinates
@@ -108,7 +108,7 @@ type PanelStyle struct {
 // Many GUI components can be styled using BasicStyle or redeclared versions thereof (e.g. ButtonStyle)
 type BasicStyle struct {
 	PanelStyle
-	FgColor     math32.Color4
+	FgColor math32.Color4
 }
 
 const (
@@ -599,8 +599,8 @@ func (p *Panel) ContainsPosition(x, y float32) bool {
 // Unlike "ContainsPosition" is does not consider the panel margins.
 func (p *Panel) InsideBorders(x, y float32) bool {
 
-	if 	x < (p.pospix.X + p.marginSizes.Left) || x >= (p.pospix.X + p.width - p.marginSizes.Right) ||
-		y < (p.pospix.Y + p.marginSizes.Top) ||	y >= (p.pospix.Y + p.height - p.marginSizes.Bottom) {
+	if x < (p.pospix.X+p.marginSizes.Left) || x >= (p.pospix.X+p.width-p.marginSizes.Right) ||
+		y < (p.pospix.Y+p.marginSizes.Top) || y >= (p.pospix.Y+p.height-p.marginSizes.Bottom) {
 		return false
 	}
 	return true

+ 2 - 1
gui/root.go

@@ -25,6 +25,7 @@ type Root struct {
 	targets           []IPanel       // preallocated list of target panels
 }
 
+// Types of event propagation stopping.
 const (
 	StopGUI = 0x01             // Stop event propagation to GUI
 	Stop3D  = 0x02             // Stop event propagation to 3D
@@ -164,7 +165,7 @@ func (r *Root) SetCursorText() {
 	r.win.SetStandardCursor(window.IBeamCursor)
 }
 
-// SetCursorText sets the cursor over the associated window to the crosshair type.
+// SetCursorCrosshair sets the cursor over the associated window to the crosshair type.
 func (r *Root) SetCursorCrosshair() {
 
 	r.win.SetStandardCursor(window.CrosshairCursor)

+ 25 - 25
gui/scroller.go

@@ -5,6 +5,7 @@
 package gui
 
 import (
+	"github.com/g3n/engine/math32"
 	"github.com/g3n/engine/window"
 )
 
@@ -26,9 +27,10 @@ type Scroller struct {
 	modKeyPressed bool           // Modifier key is pressed
 }
 
-// ScrollMode specifies which scroll directions are allowed
+// ScrollMode specifies which scroll directions are allowed.
 type ScrollMode int
 
+// The various scroll modes.
 const (
 	ScrollNone       = ScrollMode(0x00)                              // No scrolling allowed
 	ScrollVertical   = ScrollMode(0x01)                              // Vertical scrolling allowed
@@ -39,6 +41,7 @@ const (
 // ScrollbarInterlocking specifies what happens where the vertical and horizontal scrollbars meet.
 type ScrollbarInterlocking int
 
+// The three scrollbar interlocking types.
 const (
 	ScrollbarInterlockingNone       = ScrollbarInterlocking(iota) // No scrollbar interlocking
 	ScrollbarInterlockingVertical                                 // Vertical scrollbar takes precedence
@@ -50,6 +53,7 @@ const (
 // For the horizontal scrollbar it specifies whether it's added to the top or to the bottom.
 type ScrollbarPosition int
 
+// The four possible scrollbar positions.
 const (
 	ScrollbarLeft   = ScrollbarPosition(iota) // Scrollbar is positioned on the left of the scroller
 	ScrollbarRight                            // Scrollbar is positioned on the right of the scroller
@@ -79,10 +83,7 @@ type ScrollerScrollbarStyle struct {
 // TODO these configuration variables could be made part of a global engine configuration object in the future
 // They should not be added to style since they are not style changes and not to the struct since they are global
 
-// ScrollPreference specifies the default scroll direction if both scrollbars are present
-const ScrollPreference = ScrollVertical
-
-// ScrollModifierKey is the Key that changes the scrolling direction to the non-preferred direction
+// ScrollModifierKey is the Key that changes the scrolling direction from vertical to horizontal
 const ScrollModifierKey = window.KeyLeftShift
 
 // NewScroller creates and returns a pointer to a new Scroller with the specified
@@ -301,33 +302,32 @@ func (s *Scroller) onScroll(evname string, ev interface{}) {
 	vScrollVisible := (s.vscroll != nil) && s.vscroll.Visible()
 	hScrollVisible := (s.hscroll != nil) && s.hscroll.Visible()
 
-	valOffset := sev.Yoffset / 10
+	mult := float32(1) / float32(10)
+	offsetX := sev.Xoffset * mult
+	offsetY := sev.Yoffset * mult
+
+	// If modifier key is pressed (left shift by default) - then scroll in the horizontal direction
+	if s.modKeyPressed {
+		if math32.Abs(offsetY) > math32.Abs(offsetX) {
+			offsetX = offsetY
+		}
+		offsetY = 0
+	}
+
+	log.Error("X: %v, Y: %v", offsetX, offsetY)
 
 	if vScrollVisible {
 		if hScrollVisible {
-			// Both scrollbars are present. Which to scroll depends on the system-set preference
-			pref := ScrollPreference
-			// If modifier key is pressed (left shift by default) - then scroll in the non-preferential direction
-			if s.modKeyPressed {
-				if pref == ScrollVertical {
-					pref = ScrollHorizontal
-				} else if pref == ScrollHorizontal {
-					pref = ScrollVertical
-				}
-			}
-			// Scroll the appropriate scrollbar
-			if pref == ScrollVertical {
-				s.vscroll.SetValue(float32(s.vscroll.Value()) - valOffset)
-			} else if pref == ScrollHorizontal {
-				s.hscroll.SetValue(float32(s.hscroll.Value()) - valOffset)
-			}
+			// Both scrollbars are present - scroll both
+			s.vscroll.SetValue(float32(s.vscroll.Value()) - offsetY)
+			s.hscroll.SetValue(float32(s.hscroll.Value()) - offsetX)
 		} else {
 			// Only vertical scrollbar present - scroll it
-			s.vscroll.SetValue(float32(s.vscroll.Value()) - valOffset)
+			s.vscroll.SetValue(float32(s.vscroll.Value()) - offsetY)
 		}
 	} else if hScrollVisible {
 		// Only horizontal scrollbar present - scroll it
-		s.hscroll.SetValue(float32(s.hscroll.Value()) - valOffset)
+		s.hscroll.SetValue(float32(s.hscroll.Value()) - offsetX)
 	}
 
 	s.recalc()
@@ -604,4 +604,4 @@ func (s *Scroller) applyStyle(ss *ScrollerStyle) {
 	s.corner.ApplyStyle(&s.style.CornerPanel)
 
 	s.Update()
-}
+}

+ 10 - 10
gui/style_dark.go

@@ -11,7 +11,7 @@ import (
 	"github.com/g3n/engine/text"
 )
 
-// NewLightStyle creates and returns a pointer to the a new "light" style
+// NewDarkStyle creates and returns a pointer to the a new "dark" style
 func NewDarkStyle() *Style {
 
 	// Fonts to use
@@ -39,12 +39,12 @@ func NewDarkStyle() *Style {
 	oneBounds := RectBounds{1, 1, 1, 1}
 	twoBounds := RectBounds{2, 2, 2, 2}
 
-	s.Color.BgDark = math32.Color4{43.0/256.0, 43.0/256.0, 43.0/256.0, 1}
-	s.Color.BgMed = math32.Color4{49.0/256.0, 51.0/256.0, 53.0/256.0, 1}
-	s.Color.BgNormal = math32.Color4{60.0/256.0, 63.0/256.0, 65.0/256.0, 1}
-	s.Color.BgOver = math32.Color4{70.0/256.0, 74.0/256.0, 77.0/256.0, 1}
-	s.Color.Highlight = math32.Color4{75.0/256.0, 110.0/256.0, 175.0/256.0, 1}
-	s.Color.Select = math32.Color4{13.0/256.0, 41.0/256.0, 62.0/256.0, 1}
+	s.Color.BgDark = math32.Color4{43.0 / 256.0, 43.0 / 256.0, 43.0 / 256.0, 1}
+	s.Color.BgMed = math32.Color4{49.0 / 256.0, 51.0 / 256.0, 53.0 / 256.0, 1}
+	s.Color.BgNormal = math32.Color4{60.0 / 256.0, 63.0 / 256.0, 65.0 / 256.0, 1}
+	s.Color.BgOver = math32.Color4{70.0 / 256.0, 74.0 / 256.0, 77.0 / 256.0, 1}
+	s.Color.Highlight = math32.Color4{75.0 / 256.0, 110.0 / 256.0, 175.0 / 256.0, 1}
+	s.Color.Select = math32.Color4{13.0 / 256.0, 41.0 / 256.0, 62.0 / 256.0, 1}
 	s.Color.Text = math32.Color4{1, 1, 1, 1}
 	s.Color.TextDis = math32.Color4{0.4, 0.4, 0.4, 1}
 
@@ -65,8 +65,8 @@ func NewDarkStyle() *Style {
 	s.Label.FontAttributes.DPI = 72
 	s.Label.FontAttributes.Hinting = text.HintingNone
 	s.Label.FontAttributes.LineSpacing = 1.0
-	s.Label.BgColor = math32.Color4{1,1,1, 0}
-	s.Label.FgColor = math32.Color4{1,1,1,1}
+	s.Label.BgColor = math32.Color4{1, 1, 1, 0}
+	s.Label.FgColor = math32.Color4{1, 1, 1, 1}
 
 	// Button styles
 	s.Button = ButtonStyles{}
@@ -122,7 +122,7 @@ func NewDarkStyle() *Style {
 	s.ScrollBar.Normal.BgColor = math32.Color4{0, 0, 0, 0.2}
 	s.ScrollBar.Normal.ButtonLength = 32
 	s.ScrollBar.Normal.Button = PanelStyle{
-		BgColor:     math32.Color4{0.8, 0.8, 0.8, 0.5},
+		BgColor: math32.Color4{0.8, 0.8, 0.8, 0.5},
 	}
 	s.ScrollBar.Over = s.ScrollBar.Normal
 	s.ScrollBar.Disabled = s.ScrollBar.Normal

+ 2 - 2
gui/style_light.go

@@ -59,8 +59,8 @@ func NewLightStyle() *Style {
 	s.Label.FontAttributes.DPI = 72
 	s.Label.FontAttributes.Hinting = text.HintingNone
 	s.Label.FontAttributes.LineSpacing = 1.0
-	s.Label.BgColor = math32.Color4{0,0,0,0}
-	s.Label.FgColor = math32.Color4{0,0,0,1}
+	s.Label.BgColor = math32.Color4{0, 0, 0, 0}
+	s.Label.FgColor = math32.Color4{0, 0, 0, 1}
 
 	// Button styles
 	s.Button = ButtonStyles{}

+ 8 - 9
gui/table.go

@@ -16,16 +16,17 @@ import (
 )
 
 const (
-	// Name of the event generated when the table is right or left clicked
+	// OnTableClick is the event generated when the table is right or left clicked
 	// Parameter is TableClickEvent
 	OnTableClick = "onTableClick"
-	// Name of the event generated when the table row count changes (no parameters)
+	// OnTableRowCount is the event generated when the table row count changes (no parameters)
 	OnTableRowCount = "onTableRowCount"
 )
 
 // TableSortType is the type used to specify the sort method for a table column
 type TableSortType int
 
+// The various sorting types
 const (
 	TableSortNone TableSortType = iota
 	TableSortString
@@ -36,9 +37,9 @@ const (
 type TableSelType int
 
 const (
-	// Single row selection mode (default)
-	TableSelSingleRow = iota
-	// Multiple row selection mode
+	// TableSelSingleRow is the single row selection mode (default)
+	TableSelSingleRow TableSelType = iota
+	// TableSelMultiRow is the multiple row selection mode
 	TableSelMultiRow
 )
 
@@ -1615,9 +1616,8 @@ func (ts tableSortString) Less(i, j int) bool {
 	sj := fmt.Sprintf(ts.format, vj)
 	if ts.asc {
 		return si < sj
-	} else {
-		return sj < si
 	}
+	return sj < si
 }
 
 // tableSortNumber is an internal type implementing the sort.Interface
@@ -1638,9 +1638,8 @@ func (ts tableSortNumber) Less(i, j int) bool {
 	nj := cv2f64(vj)
 	if ts.asc {
 		return ni < nj
-	} else {
-		return nj < ni
 	}
+	return nj < ni
 }
 
 // Try to convert an interface value to a float64 number

+ 2 - 2
gui/tree.go

@@ -30,8 +30,8 @@ type TreeNodeStyles struct {
 // TreeNodeStyle contains the styling of a TreeNode.
 type TreeNodeStyle struct {
 	PanelStyle
-	FgColor     math32.Color4
-	Icons       [2]string
+	FgColor math32.Color4
+	Icons   [2]string
 }
 
 // TreeNode is a tree node.

+ 1 - 0
gui/window.go

@@ -64,6 +64,7 @@ type WindowStyles struct {
 // ResizeBorders specifies which window borders can be resized
 type ResizeBorders int
 
+// Resizing can be allowed or disallowed on each window edge
 const (
 	ResizeTop = ResizeBorders(1 << (iota + 1))
 	ResizeRight

+ 1 - 0
light/directional.go

@@ -12,6 +12,7 @@ import (
 	"github.com/g3n/engine/math32"
 )
 
+// Directional represents a directional, positionless light
 type Directional struct {
 	core.Node              // Embedded node
 	color     math32.Color // Light color

+ 0 - 1
light/doc.go

@@ -5,4 +5,3 @@
 // Package light contains common light types which can be
 // add to a 3D scene to illuminate it.
 package light
-

+ 5 - 5
light/spot.go

@@ -14,11 +14,11 @@ import (
 
 // Spot represents a spotlight
 type Spot struct {
-	core.Node                // Embedded node
-	color     math32.Color   // Light color
-	intensity float32        // Light intensity
-	uni       gls.Uniform    // Uniform location cache
-	udata     struct {       // Combined uniform data in 5 vec3:
+	core.Node              // Embedded node
+	color     math32.Color // Light color
+	intensity float32      // Light intensity
+	uni       gls.Uniform  // Uniform location cache
+	udata     struct {     // Combined uniform data in 5 vec3:
 		color          math32.Color   // Light color
 		position       math32.Vector3 // Light position
 		direction      math32.Vector3 // Light direction

+ 1 - 1
material/material.go

@@ -331,7 +331,7 @@ func (mat *Material) RenderSetup(gs *gls.GLS) {
 		samplerName, _ := tex.GetUniformNames()
 		uniIdx, _ := samplerCounts[samplerName]
 		tex.RenderSetup(gs, slotIdx, uniIdx)
-		samplerCounts[samplerName] = uniIdx+1
+		samplerCounts[samplerName] = uniIdx + 1
 	}
 }
 

+ 1 - 1
material/physical.go

@@ -118,9 +118,9 @@ func (m *Physical) SetMetallicRoughnessMap(tex *texture.Texture2D) *Physical {
 	return m
 }
 
-// TODO add SetNormalMap (and SetSpecularMap) to StandardMaterial.
 // SetNormalMap sets this material optional normal texture.
 // Returns pointer to this updated material.
+// TODO add SetNormalMap (and SetSpecularMap) to StandardMaterial.
 func (m *Physical) SetNormalMap(tex *texture.Texture2D) *Physical {
 
 	m.normalTex = tex

+ 38 - 0
math32/array.go

@@ -59,6 +59,14 @@ func (a *ArrayF32) AppendVector3(v ...*Vector3) {
 	}
 }
 
+// AppendVector4 appends any number of Vector4 to the array
+func (a *ArrayF32) AppendVector4(v ...*Vector4) {
+
+	for i := 0; i < len(v); i++ {
+		*a = append(*a, v[i].X, v[i].Y, v[i].Z, v[i].W)
+	}
+}
+
 // AppendColor appends any number of Color to the array
 func (a *ArrayF32) AppendColor(v ...*Color) {
 
@@ -92,6 +100,16 @@ func (a ArrayF32) GetVector3(pos int, v *Vector3) {
 	v.Z = a[pos+2]
 }
 
+// GetVector4 stores in the specified Vector4 the
+// values from the array starting at the specified pos.
+func (a ArrayF32) GetVector4(pos int, v *Vector4) {
+
+	v.X = a[pos]
+	v.Y = a[pos+1]
+	v.Z = a[pos+2]
+	v.W = a[pos+3]
+}
+
 // GetColor stores in the specified Color the
 // values from the array starting at the specified pos
 func (a ArrayF32) GetColor(pos int, v *Color) {
@@ -101,6 +119,16 @@ func (a ArrayF32) GetColor(pos int, v *Color) {
 	v.B = a[pos+2]
 }
 
+// GetColor4 stores in the specified Color the
+// values from the array starting at the specified pos
+func (a ArrayF32) GetColor4(pos int, v *Color4) {
+
+	v.R = a[pos]
+	v.G = a[pos+1]
+	v.B = a[pos+2]
+	v.A = a[pos+3]
+}
+
 // Set sets the values of the array starting at the specified pos
 // from the specified values
 func (a ArrayF32) Set(pos int, v ...float32) {
@@ -127,6 +155,16 @@ func (a ArrayF32) SetVector3(pos int, v *Vector3) {
 	a[pos+2] = v.Z
 }
 
+// SetVector4 sets the values of the array at the specified pos
+// from the XYZ values of the specified Vector4
+func (a ArrayF32) SetVector4(pos int, v *Vector4) {
+
+	a[pos] = v.X
+	a[pos+1] = v.Y
+	a[pos+2] = v.Z
+	a[pos+3] = v.W
+}
+
 // SetColor sets the values of the array at the specified pos
 // from the RGB values of the specified Color
 func (a ArrayF32) SetColor(pos int, v *Color) {

+ 1 - 10
math32/box3.go

@@ -239,16 +239,7 @@ func (b *Box3) Union(other *Box3) *Box3 {
 // Returns pointer to this updated bounding box.
 func (b *Box3) ApplyMatrix4(matrix *Matrix4) *Box3 {
 
-	points := []Vector3{
-		Vector3{},
-		Vector3{},
-		Vector3{},
-		Vector3{},
-		Vector3{},
-		Vector3{},
-		Vector3{},
-		Vector3{},
-	}
+	points := make([]Vector3, 8)
 
 	points[0].Set(b.Min.X, b.Min.Y, b.Min.Z).ApplyMatrix4(matrix) // 000
 	points[1].Set(b.Min.X, b.Min.Y, b.Max.Z).ApplyMatrix4(matrix) // 001

+ 1 - 0
math32/frustum.go

@@ -9,6 +9,7 @@ type Frustum struct {
 	planes []Plane
 }
 
+// NewFrustumFromMatrix creates and returns a Frustum based on the provided matrix
 func NewFrustumFromMatrix(m *Matrix4) *Frustum {
 	f := new(Frustum)
 	f.planes = make([]Plane, 6)

+ 35 - 23
math32/matrix4.go

@@ -224,29 +224,41 @@ func (m *Matrix4) MakeRotationFromQuaternion(q *Quaternion) *Matrix4 {
 // Returns pointer to this updated matrix.
 func (m *Matrix4) LookAt(eye, target, up *Vector3) *Matrix4 {
 
-	var f Vector3
-	var s Vector3
-	var u Vector3
-	f.SubVectors(target, eye).Normalize()
-	s.CrossVectors(&f, up).Normalize()
-	u.CrossVectors(&s, &f)
-
-	m[0] = s.X
-	m[1] = u.X
-	m[2] = -f.X
-	m[3] = 0.0
-	m[4] = s.Y
-	m[5] = u.Y
-	m[6] = -f.Y
-	m[7] = 0.0
-	m[8] = s.Z
-	m[9] = u.Z
-	m[10] = -f.Z
-	m[11] = 0.0
-	m[12] = -s.Dot(eye)
-	m[13] = -u.Dot(eye)
-	m[14] = f.Dot(eye)
-	m[15] = 1.0
+	var x, y, z Vector3
+
+	z.SubVectors(eye, target)
+	if z.LengthSq() == 0 {
+		// Eye and target are in the same position
+		z.Z = 1
+	}
+	z.Normalize()
+
+	x.CrossVectors(up, &z)
+	if x.LengthSq() == 0 {
+		// Up and Z are parallel
+		if Abs(up.Z) == 1 {
+			z.X += 0.0001
+		} else {
+			z.Z += 0.0001
+		}
+		z.Normalize()
+		x.CrossVectors(up, &z)
+	}
+	x.Normalize()
+
+	y.CrossVectors(&z, &x)
+
+	m[0] = x.X
+	m[1] = x.Y
+	m[2] = x.Z
+
+	m[4] = y.X
+	m[5] = y.Y
+	m[6] = y.Z
+
+	m[8] = z.X
+	m[9] = z.Y
+	m[10] = z.Z
 
 	return m
 }

+ 0 - 2
math32/plane.go

@@ -4,8 +4,6 @@
 
 package math32
 
-import ()
-
 // Plane represents a plane in 3D space by its normal vector and a constant.
 // When the the normal vector is the unit vector the constant is the distance from the origin.
 type Plane struct {

+ 26 - 26
renderer/renderer.go

@@ -18,29 +18,29 @@ import (
 // Renderer renders a 3D scene and/or a 2D GUI on the current window.
 type Renderer struct {
 	gs           *gls.GLS
-	shaman       Shaman                      // Internal shader manager
-	stats        Stats                       // Renderer statistics
-	prevStats    Stats                       // Renderer statistics for previous frame
-	scene        core.INode                  // Node containing 3D scene to render
-	panelGui     gui.IPanel                  // Panel containing GUI to render
-	panel3D      gui.IPanel                  // Panel which contains the 3D scene
-	ambLights    []*light.Ambient            // Array of ambient lights for last scene
-	dirLights    []*light.Directional        // Array of directional lights for last scene
-	pointLights  []*light.Point              // Array of point
-	spotLights   []*light.Spot               // Array of spot lights for the scene
-	others       []core.INode                // Other nodes (audio, players, etc)
-	rgraphics    []*graphic.Graphic          // Array of rendered graphics
-	cgraphics    []*graphic.Graphic          // Array of rendered graphics
-	grmatsOpaque []*graphic.GraphicMaterial  // Array of rendered opaque graphic materials for scene
-	grmatsTransp []*graphic.GraphicMaterial  // Array of rendered transparent graphic materials for scene
-	rinfo        core.RenderInfo             // Preallocated Render info
-	specs        ShaderSpecs                 // Preallocated Shader specs
-	sortObjects  bool                        // Flag indicating whether objects should be sorted before rendering
-	redrawGui    bool                        // Flag indicating the gui must be redrawn completely
-	rendered     bool                        // Flag indicating if anything was rendered
-	panList      []gui.IPanel                // list of panels to render
-	frameBuffers int                         // Number of frame buffers
-	frameCount   int                         // Current number of frame buffers to write
+	shaman       Shaman                     // Internal shader manager
+	stats        Stats                      // Renderer statistics
+	prevStats    Stats                      // Renderer statistics for previous frame
+	scene        core.INode                 // Node containing 3D scene to render
+	panelGui     gui.IPanel                 // Panel containing GUI to render
+	panel3D      gui.IPanel                 // Panel which contains the 3D scene
+	ambLights    []*light.Ambient           // Array of ambient lights for last scene
+	dirLights    []*light.Directional       // Array of directional lights for last scene
+	pointLights  []*light.Point             // Array of point
+	spotLights   []*light.Spot              // Array of spot lights for the scene
+	others       []core.INode               // Other nodes (audio, players, etc)
+	rgraphics    []*graphic.Graphic         // Array of rendered graphics
+	cgraphics    []*graphic.Graphic         // Array of rendered graphics
+	grmatsOpaque []*graphic.GraphicMaterial // Array of rendered opaque graphic materials for scene
+	grmatsTransp []*graphic.GraphicMaterial // Array of rendered transparent graphic materials for scene
+	rinfo        core.RenderInfo            // Preallocated Render info
+	specs        ShaderSpecs                // Preallocated Shader specs
+	sortObjects  bool                       // Flag indicating whether objects should be sorted before rendering
+	redrawGui    bool                       // Flag indicating the gui must be redrawn completely
+	rendered     bool                       // Flag indicating if anything was rendered
+	panList      []gui.IPanel               // list of panels to render
+	frameBuffers int                        // Number of frame buffers
+	frameCount   int                        // Current number of frame buffers to write
 }
 
 // Stats describes how many object types were rendered.
@@ -310,14 +310,14 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 
 				if backToFront {
 					return g1pos.Z < g2pos.Z
-				} else {
-					return g1pos.Z > g2pos.Z
 				}
+
+				return g1pos.Z > g2pos.Z
 			})
 		}
 
 		zSortGraphicMaterials(r.grmatsOpaque, false) // Sort opaque graphics front to back
-		zSortGraphicMaterials(r.grmatsTransp, true) // Sort transparent graphics back to front
+		zSortGraphicMaterials(r.grmatsTransp, true)  // Sort transparent graphics back to front
 	}
 
 	// Render other nodes (audio players, etc)

+ 1 - 1
renderer/shaman.go

@@ -328,7 +328,7 @@ func (ss *ShaderSpecs) compareDefines(other *ShaderSpecs) bool {
 		if len(ss.Defines) != len(other.Defines) {
 			return false
 		}
-		for k, _ := range ss.Defines {
+		for k := range ss.Defines {
 			v1, ok1 := ss.Defines[k]
 			v2, ok2 := other.Defines[k]
 			if v1 != v2 || ok1 != ok2 {

+ 1 - 1
text/font.go

@@ -290,7 +290,7 @@ func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) err
 			// Draw caret vertical line
 			caretH := int(f.attrib.PointSize) + 2
 			caretY := int(d.Dot.Y>>6) - int(f.attrib.PointSize) + 2
-			color := Color4RGBA(&math32.Color4{0,0,0,1}) // Hardcoded to black
+			color := Color4RGBA(&math32.Color4{0, 0, 0, 1}) // Hardcoded to black
 			for j := caretY; j < caretY+caretH; j++ {
 				c.RGBA.Set(x+width, j, color)
 			}

+ 0 - 1
texture/doc.go

@@ -5,4 +5,3 @@
 // Package texture contains several types of textures which
 // can be added to materials.
 package texture
-

+ 1 - 0
tools/g3nicodes/main.go

@@ -153,6 +153,7 @@ const templText = `// File generated by g3nicodes. Do not edit.
 
 package {{.Packname}}
 
+// Icon constants.
 const (
 	{{range .Consts}}
 		{{.Name}} = string({{.Value}})

+ 2 - 1
tools/g3nshaders/main.go

@@ -24,6 +24,7 @@ import (
 	"text/template"
 )
 
+// Program constants.
 const (
 	PROGNAME      = "g3nshaders"
 	VMAJOR        = 0
@@ -36,7 +37,7 @@ const (
 )
 
 //
-// Go template to generate the output file with the shaders' sources and
+// TEMPLATE is a Go template to generate the output file with the shaders' sources and
 // maps describing the include and shader names and programs shaders.
 //
 const TEMPLATE = `// File generated by G3NSHADERS. Do not edit.

+ 2 - 1
util/logger/console.go

@@ -38,7 +38,7 @@ var colorMap = map[int]string{
 	FATAL: bmagenta,
 }
 
-// logger Console writer type
+// Console is a console writer used for logging.
 type Console struct {
 	writer *os.File
 	color  bool
@@ -52,6 +52,7 @@ func NewConsole(color bool) *Console {
 	return &Console{os.Stdout, color}
 }
 
+// Write writes the provided logger event to the console.
 func (w *Console) Write(event *Event) {
 
 	if w.color {

+ 5 - 0
util/logger/file.go

@@ -8,10 +8,12 @@ import (
 	"os"
 )
 
+// File is a file writer used for logging.
 type File struct {
 	writer *os.File
 }
 
+// NewFile creates and returns a pointer to a new File object along with any error that occurred.
 func NewFile(filename string) (*File, error) {
 
 	file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
@@ -21,17 +23,20 @@ func NewFile(filename string) (*File, error) {
 	return &File{file}, nil
 }
 
+// Write writes the provided logger event to the file.
 func (f *File) Write(event *Event) {
 
 	f.writer.Write([]byte(event.fmsg))
 }
 
+// Close closes the file.
 func (f *File) Close() {
 
 	f.writer.Close()
 	f.writer = nil
 }
 
+// Sync commits the current contents of the file to stable storage.
 func (f *File) Sync() {
 
 	f.writer.Sync()

+ 10 - 10
util/logger/logger.go

@@ -38,11 +38,11 @@ const (
 var levelNames = [...]string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
 
 // Default logger and global mutex
-var Default *Logger = nil
+var Default *Logger
 var rootLoggers = []*Logger{}
 var mutex sync.Mutex
 
-// Interface for all logger writers
+// LoggerWriter is the interface for all logger writers
 type LoggerWriter interface {
 	Write(*Event)
 	Close()
@@ -61,7 +61,7 @@ type Logger struct {
 	children []*Logger
 }
 
-// Logger event passed from the logger to its writers.
+// Event is a logger event passed from the logger to its writers.
 type Event struct {
 	time    time.Time
 	level   int
@@ -76,7 +76,7 @@ func init() {
 	Default.AddWriter(NewConsole(false))
 }
 
-// New() creates and returns a new logger with the specified name.
+// New creates and returns a new logger with the specified name.
 // If a parent logger is specified, the created logger inherits the
 // parent's configuration.
 func New(name string, parent *Logger) *Logger {
@@ -177,21 +177,21 @@ func (l *Logger) Info(format string, v ...interface{}) {
 }
 
 // Warn emits a WARN level log message
-func (self *Logger) Warn(format string, v ...interface{}) {
+func (l *Logger) Warn(format string, v ...interface{}) {
 
-	self.Log(WARN, format, v...)
+	l.Log(WARN, format, v...)
 }
 
 // Error emits an ERROR level log message
-func (self *Logger) Error(format string, v ...interface{}) {
+func (l *Logger) Error(format string, v ...interface{}) {
 
-	self.Log(ERROR, format, v...)
+	l.Log(ERROR, format, v...)
 }
 
 // Fatal emits a FATAL level log message
-func (self *Logger) Fatal(format string, v ...interface{}) {
+func (l *Logger) Fatal(format string, v ...interface{}) {
 
-	self.Log(FATAL, format, v...)
+	l.Log(FATAL, format, v...)
 }
 
 // Log emits a log message with the specified level

+ 4 - 0
util/logger/net.go

@@ -8,10 +8,12 @@ import (
 	"net"
 )
 
+// Net is a network writer used for logging.
 type Net struct {
 	conn net.Conn
 }
 
+// NewNet creates and returns a pointer to a new Net object along with any error that occurred.
 func NewNet(network string, address string) (*Net, error) {
 
 	n := new(Net)
@@ -23,11 +25,13 @@ func NewNet(network string, address string) (*Net, error) {
 	return n, nil
 }
 
+// Write writes the provided logger event to the network.
 func (n *Net) Write(event *Event) {
 
 	n.conn.Write([]byte(event.fmsg))
 }
 
+// Clone closes the network connection.
 func (n *Net) Close() {
 
 	n.conn.Close()