Parcourir la source

Merge branch 'master' into physics

Daniel Salvadori il y a 7 ans
Parent
commit
385579c565
60 fichiers modifiés avec 753 ajouts et 397 suppressions
  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
 ## Dependencies
 
 
+**G3N requires Go 1.8+**
+
 The engine needs an OpenGL driver installed in the system and on Unix like systems
 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.
 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.
 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:
   your are using [Homebrew](https://brew.sh/) as your package manager, run:
   `brew install libvorbis openal-soft`
   `brew install libvorbis openal-soft`
 
 
-G3N requires Go 1.8+
-
 ## Installation
 ## Installation
 
 
 The following command will download the engine and all its dependencies, compile and
 The following command will download the engine and all its dependencies, compile and
@@ -210,4 +210,4 @@ send pull requests.
 
 
 ## Community
 ## 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 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 linux    CFLAGS:  -DGO_LINUX   -I/usr/include/AL
 #cgo windows  CFLAGS:  -DGO_WINDOWS -I${SRCDIR}/../windows/openal-soft-1.18.2/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 darwin   LDFLAGS: -L/usr/local/opt/openal-soft/lib -lopenal
+#cgo freebsd  LDFLAGS: -L/usr/local/lib -lopenal
 #cgo linux    LDFLAGS: -lopenal
 #cgo linux    LDFLAGS: -lopenal
 #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -lOpenAL32
 #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -lOpenAL32
 
 
@@ -21,6 +23,13 @@ package al
 #include "efx.h"
 #include "efx.h"
 #endif
 #endif
 
 
+#ifdef GO_FREEBSD
+#include <stdlib.h>
+#include "al.h"
+#include "alc.h"
+#include "efx.h"
+#endif
+
 #ifdef GO_LINUX
 #ifdef GO_LINUX
 #include <stdlib.h>
 #include <stdlib.h>
 #include "al.h"
 #include "al.h"

+ 2 - 0
audio/ov/vorbisfile.go

@@ -7,9 +7,11 @@
 package ov
 package ov
 
 
 // #cgo darwin   CFLAGS:  -DGO_DARWIN  -I/usr/include/vorbis -I/usr/local/include/vorbis
 // #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 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 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 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 linux    LDFLAGS: -lvorbisfile
 // #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -llibvorbisfile
 // #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -llibvorbisfile
 // #include <stdlib.h>
 // #include <stdlib.h>

+ 2 - 0
audio/vorbis/vorbis.go

@@ -7,9 +7,11 @@
 package vorbis
 package vorbis
 
 
 // #cgo darwin   CFLAGS:  -DGO_DARWIN  -I/usr/include/vorbis -I/usr/local/include/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 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 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 darwin   LDFLAGS: -L/usr/lib -L/usr/local/lib -lvorbis
+// #cgo freebsd  LDFLAGS: -L/usr/local/lib -lvorbis
 // #cgo linux    LDFLAGS: -lvorbis
 // #cgo linux    LDFLAGS: -lvorbis
 // #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -llibvorbis
 // #cgo windows  LDFLAGS: -L${SRCDIR}/../windows/bin -llibvorbis
 // #include "codec.h"
 // #include "codec.h"

+ 30 - 109
camera/camera.go

@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 // 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
 package camera
 
 
 import (
 import (
@@ -10,7 +10,7 @@ import (
 	"github.com/g3n/engine/math32"
 	"github.com/g3n/engine/math32"
 )
 )
 
 
-// ICamera is interface for all camera types
+// ICamera is interface for all camera types.
 type ICamera interface {
 type ICamera interface {
 	GetCamera() *Camera
 	GetCamera() *Camera
 	ViewMatrix(*math32.Matrix4)
 	ViewMatrix(*math32.Matrix4)
@@ -20,151 +20,72 @@ type ICamera interface {
 	SetRaycaster(rc *core.Raycaster, x, y float32) error
 	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 {
 type Camera struct {
 	core.Node                 // Embedded Node
 	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.
 // 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() {
 func (cam *Camera) Initialize() {
 
 
 	cam.Node.Init()
 	cam.Node.Init()
 	cam.target.Set(0, 0, 0)
 	cam.target.Set(0, 0, 0)
 	cam.up.Set(0, 1, 0)
 	cam.up.Set(0, 1, 0)
 	cam.SetDirection(0, 0, -1)
 	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) {
 func (cam *Camera) LookAt(target *math32.Vector3) {
 
 
 	cam.target = *target
 	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 {
 func (cam *Camera) GetCamera() *Camera {
 
 
 	return cam
 	return cam
 }
 }
 
 
-// Target get the current target position
+// Target get the current target position.
 func (cam *Camera) Target() math32.Vector3 {
 func (cam *Camera) Target() math32.Vector3 {
 
 
 	return cam.target
 	return cam.target
 }
 }
 
 
-// Up get the current up position
+// Up get the current camera up vector.
 func (cam *Camera) Up() math32.Vector3 {
 func (cam *Camera) Up() math32.Vector3 {
 
 
 	return cam.up
 	return cam.up
 }
 }
 
 
-// SetUp sets the camera up vector
+// SetUp sets the camera up vector.
 func (cam *Camera) SetUp(up *math32.Vector3) {
 func (cam *Camera) SetUp(up *math32.Vector3) {
 
 
 	cam.up = *up
 	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) {
 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"
 	"math"
 )
 )
 
 
+// OrbitControl is a camera controller that allows orbiting a center point while looking at it.
 type OrbitControl struct {
 type OrbitControl struct {
 	Enabled         bool    // Control enabled state
 	Enabled         bool    // Control enabled state
 	EnableRotate    bool    // Rotate enabled state
 	EnableRotate    bool    // Rotate enabled state
@@ -109,6 +110,7 @@ func NewOrbitControl(icam camera.ICamera, win window.IWindow) *OrbitControl {
 	return oc
 	return oc
 }
 }
 
 
+// Dispose unsubscribes from all events
 func (oc *OrbitControl) Dispose() {
 func (oc *OrbitControl) Dispose() {
 
 
 	// Unsubscribe to event handlers
 	// Unsubscribe to event handlers
@@ -142,21 +144,21 @@ func (oc *OrbitControl) Zoom(delta float32) {
 	oc.updateZoom()
 	oc.updateZoom()
 }
 }
 
 
-// Rotate camera left by specified angle
+// RotateLeft rotates the camera left by specified angle
 func (oc *OrbitControl) RotateLeft(angle float32) {
 func (oc *OrbitControl) RotateLeft(angle float32) {
 
 
 	oc.thetaDelta -= angle
 	oc.thetaDelta -= angle
 	oc.updateRotate()
 	oc.updateRotate()
 }
 }
 
 
-// Rotate camera up by specified angle
+// RotateUp rotates the camera up by specified angle
 func (oc *OrbitControl) RotateUp(angle float32) {
 func (oc *OrbitControl) RotateUp(angle float32) {
 
 
 	oc.phiDelta -= angle
 	oc.phiDelta -= angle
 	oc.updateRotate()
 	oc.updateRotate()
 }
 }
 
 
-// Updates camera rotation from tethaDelta and phiDelta
+// Updates the camera rotation from thetaDelta and phiDelta
 func (oc *OrbitControl) updateRotate() {
 func (oc *OrbitControl) updateRotate() {
 
 
 	const EPS = 0.01
 	const EPS = 0.01
@@ -203,6 +205,7 @@ func (oc *OrbitControl) updateRotate() {
 	position = target
 	position = target
 	position.Add(&vdir)
 	position.Add(&vdir)
 	oc.cam.SetPositionVec(&position)
 	oc.cam.SetPositionVec(&position)
+	oc.cam.LookAt(&target)
 
 
 	// Reset deltas
 	// Reset deltas
 	oc.thetaDelta = 0
 	oc.thetaDelta = 0
@@ -249,6 +252,7 @@ func (oc *OrbitControl) updateRotate2() {
 	position.Add(&vdir)
 	position.Add(&vdir)
 	log.Debug("orbit set position")
 	log.Debug("orbit set position")
 	oc.cam.SetPositionVec(&position)
 	oc.cam.SetPositionVec(&position)
+	oc.cam.LookAt(&target)
 
 
 	// Reset deltas
 	// Reset deltas
 	oc.thetaDelta = 0
 	oc.thetaDelta = 0

+ 27 - 5
camera/orthographic.go

@@ -6,9 +6,10 @@ package camera
 
 
 import (
 import (
 	"github.com/g3n/engine/math32"
 	"github.com/g3n/engine/math32"
+	"github.com/g3n/engine/core"
 )
 )
 
 
-// Orthographic is
+// Orthographic is an orthographic camera.
 type Orthographic struct {
 type Orthographic struct {
 	Camera              // Embedded camera
 	Camera              // Embedded camera
 	left        float32 // left plane x coordinate
 	left        float32 // left plane x coordinate
@@ -38,26 +39,26 @@ func NewOrthographic(left, right, top, bottom, near, far float32) *Orthographic
 	return cam
 	return cam
 }
 }
 
 
-// SetZoom sets the zoom factor of the camera
+// SetZoom sets the zoom factor of the camera.
 func (cam *Orthographic) SetZoom(zoom float32) {
 func (cam *Orthographic) SetZoom(zoom float32) {
 
 
 	cam.zoom = math32.Abs(zoom)
 	cam.zoom = math32.Abs(zoom)
 	cam.projChanged = true
 	cam.projChanged = true
 }
 }
 
 
-// Zoom returns the zoom factor of the camera
+// Zoom returns the zoom factor of the camera.
 func (cam *Orthographic) Zoom() float32 {
 func (cam *Orthographic) Zoom() float32 {
 
 
 	return cam.zoom
 	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) {
 func (cam *Orthographic) Planes() (left, right, top, bottom, near, far float32) {
 
 
 	return cam.left, cam.right, cam.top, cam.bottom, cam.near, cam.far
 	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) {
 func (cam *Orthographic) ProjMatrix(m *math32.Matrix4) {
 
 
 	if cam.projChanged {
 	if cam.projChanged {
@@ -66,3 +67,24 @@ func (cam *Orthographic) ProjMatrix(m *math32.Matrix4) {
 	}
 	}
 	*m = cam.projMatrix
 	*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"
 	"github.com/g3n/engine/math32"
 )
 )
 
 
-// Perspective represents a perspective camera
+// Perspective is a perspective camera.
 type Perspective struct {
 type Perspective struct {
 	Camera                     // Embedded camera
 	Camera                     // Embedded camera
 	fov         float32        // field of view in degrees
 	fov         float32        // field of view in degrees
@@ -34,45 +34,45 @@ func NewPerspective(fov, aspect, near, far float32) *Perspective {
 	return cam
 	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) {
 func (cam *Perspective) SetFov(fov float32) {
 
 
 	cam.fov = fov
 	cam.fov = fov
 	cam.projChanged = true
 	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) {
 func (cam *Perspective) SetAspect(aspect float32) {
 
 
 	cam.aspect = aspect
 	cam.aspect = aspect
 	cam.projChanged = true
 	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 {
 func (cam *Perspective) Fov() float32 {
 
 
 	return cam.fov
 	return cam.fov
 }
 }
 
 
-// Aspect returns the current camera aspect ratio
+// Aspect returns the current camera aspect ratio.
 func (cam Perspective) Aspect() float32 {
 func (cam Perspective) Aspect() float32 {
 
 
 	return cam.aspect
 	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 {
 func (cam *Perspective) Near() float32 {
 
 
 	return cam.near
 	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 {
 func (cam *Perspective) Far() float32 {
 
 
 	return cam.far
 	return cam.far
 }
 }
 
 
-// ProjMatrix satisfies the ICamera interface
+// ProjMatrix satisfies the ICamera interface.
 func (cam *Perspective) ProjMatrix(m *math32.Matrix4) {
 func (cam *Perspective) ProjMatrix(m *math32.Matrix4) {
 
 
 	cam.updateProjMatrix()
 	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.
 // Project transforms the specified position from world coordinates to this camera projected coordinates.
 func (cam *Perspective) Project(v *math32.Vector3) (*math32.Vector3, error) {
 func (cam *Perspective) Project(v *math32.Vector3) (*math32.Vector3, error) {
 
 
-	cam.updateProjMatrix()
+	// Get camera view matrix
 	var matrix math32.Matrix4
 	var matrix math32.Matrix4
 	matrixWorld := cam.MatrixWorld()
 	matrixWorld := cam.MatrixWorld()
 	err := matrix.GetInverse(&matrixWorld)
 	err := matrix.GetInverse(&matrixWorld)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		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)
 	matrix.MultiplyMatrices(&cam.projMatrix, &matrix)
 	v.ApplyProjection(&matrix)
 	v.ApplyProjection(&matrix)
 	return v, nil
 	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) {
 func (cam *Perspective) Unproject(v *math32.Vector3) (*math32.Vector3, error) {
 
 
 	// Get inverted camera view matrix
 	// 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
 	// Get inverted camera projection matrix
 	cam.updateProjMatrix()
 	cam.updateProjMatrix()
 	var invertedProjMatrix math32.Matrix4
 	var invertedProjMatrix math32.Matrix4
-	err = invertedProjMatrix.GetInverse(&cam.projMatrix)
+	err := invertedProjMatrix.GetInverse(&cam.projMatrix)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -142,7 +141,7 @@ func (cam *Perspective) SetRaycaster(rc *core.Raycaster, sx, sy float32) error {
 	return nil
 	return nil
 }
 }
 
 
-// updateProjMatrix updates this camera projection matrix if necessary
+// updateProjMatrix updates the projection matrix if necessary.
 func (cam *Perspective) updateProjMatrix() {
 func (cam *Perspective) updateProjMatrix() {
 
 
 	if cam.projChanged {
 	if cam.projChanged {

+ 0 - 1
core/doc.go

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

+ 1 - 2
core/logger.go

@@ -1,9 +1,8 @@
 package core
 package core
 
 
 import (
 import (
-    "github.com/g3n/engine/util/logger"
+	"github.com/g3n/engine/util/logger"
 )
 )
 
 
 // Package logger
 // Package logger
 var log = logger.New("CORE", logger.Default)
 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
 	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.
 // SetQuaternionQuat sets the quaternion based on the specified quaternion pointer.
 func (n *Node) SetQuaternionQuat(q *math32.Quaternion) {
 func (n *Node) SetQuaternionQuat(q *math32.Quaternion) {
 
 
@@ -649,53 +656,18 @@ func (n *Node) UpdateMatrix() bool {
 	return true
 	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() {
 func (n *Node) UpdateMatrixWorld() {
 
 
+	n.UpdateMatrix()
 	if n.parent == nil {
 	if n.parent == nil {
-		n.updateMatrixWorld(&n.matrix)
+		n.matrixWorld = n.matrix
 	} else {
 	} else {
 		parent := n.parent.GetNode()
 		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 {
 	for _, ichild := range n.children {
-		ichild.GetNode().updateMatrixWorldNoCheck(&n.matrixWorld)
+		ichild.UpdateMatrixWorld()
 	}
 	}
-}
+}

+ 2 - 1
core/timer.go

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

+ 17 - 15
geometry/geometry.go

@@ -9,14 +9,14 @@ import (
 	"github.com/g3n/engine/math32"
 	"github.com/g3n/engine/math32"
 )
 )
 
 
-// Interface for all geometries
+// IGeometry is the interface for all geometries.
 type IGeometry interface {
 type IGeometry interface {
 	GetGeometry() *Geometry
 	GetGeometry() *Geometry
 	RenderSetup(gs *gls.GLS)
 	RenderSetup(gs *gls.GLS)
 	Dispose()
 	Dispose()
 }
 }
 
 
-// Geometry encapsulates a three-dimensional geometric shape.
+// Geometry encapsulates a three-dimensional vertex-based geometry.
 type Geometry struct {
 type Geometry struct {
 	refcount            int             // Current number of references
 	refcount            int             // Current number of references
 	vbos                []*gls.VBO      // Array of VBOs
 	vbos                []*gls.VBO      // Array of VBOs
@@ -42,7 +42,7 @@ type Geometry struct {
 	rotInertiaValid     bool            // Indicates if last calculated rotational inertia matrix is valid
 	rotInertiaValid     bool            // Indicates if last calculated rotational inertia matrix is valid
 }
 }
 
 
-// Geometry group object
+// Group is a geometry group object.
 type Group struct {
 type Group struct {
 	Start    int    // Index of first element of the group
 	Start    int    // Index of first element of the group
 	Count    int    // Number of elements in 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
 	Matid    string // Material id used when loading external models
 }
 }
 
 
+// NewGeometry creates and returns a pointer to a new Geometry.
 func NewGeometry() *Geometry {
 func NewGeometry() *Geometry {
 
 
 	g := new(Geometry)
 	g := new(Geometry)
@@ -57,7 +58,7 @@ func NewGeometry() *Geometry {
 	return g
 	return g
 }
 }
 
 
-// Init initializes the geometry
+// Init initializes the geometry.
 func (g *Geometry) Init() {
 func (g *Geometry) Init() {
 
 
 	g.refcount = 1
 	g.refcount = 1
@@ -101,19 +102,20 @@ func (g *Geometry) Dispose() {
 	g.Init()
 	g.Init()
 }
 }
 
 
+// GetGeometry satisfies the IGeometry interface.
 func (g *Geometry) GetGeometry() *Geometry {
 func (g *Geometry) GetGeometry() *Geometry {
 
 
 	return g
 	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 {
 func (g *Geometry) AddGroup(start, count, matIndex int) *Group {
 
 
 	g.groups = append(g.groups, Group{start, count, matIndex, ""})
 	g.groups = append(g.groups, Group{start, count, matIndex, ""})
 	return &g.groups[len(g.groups)-1]
 	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) {
 func (g *Geometry) AddGroupList(groups []Group) {
 
 
 	for _, group := range groups {
 	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 {
 func (g *Geometry) GroupCount() int {
 
 
 	return len(g.groups)
 	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 {
 func (g *Geometry) GroupAt(idx int) *Group {
 
 
 	return &g.groups[idx]
 	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) {
 func (g *Geometry) SetIndices(indices math32.ArrayU32) {
 
 
 	g.indices = indices
 	g.indices = indices
@@ -142,13 +144,13 @@ func (g *Geometry) SetIndices(indices math32.ArrayU32) {
 	g.boundingSphereValid = false
 	g.boundingSphereValid = false
 }
 }
 
 
-// Indices returns this geometry indices array
+// Indices returns this geometry indices array.
 func (g *Geometry) Indices() math32.ArrayU32 {
 func (g *Geometry) Indices() math32.ArrayU32 {
 
 
 	return g.indices
 	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) {
 func (g *Geometry) AddVBO(vbo *gls.VBO) {
 
 
 	// Check that the provided VBO doesn't have conflicting attributes with existing VBOs
 	// 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
 	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)
 // (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 {
 func (g *Geometry) Items() int {
 
 
 	if len(g.vbos) == 0 {
 	if len(g.vbos) == 0 {
@@ -287,7 +289,7 @@ func (g *Geometry) Indexed() bool {
 }
 }
 
 
 // BoundingBox computes the bounding box of the geometry if necessary
 // BoundingBox computes the bounding box of the geometry if necessary
-// and returns is value
+// and returns is value.
 func (g *Geometry) BoundingBox() math32.Box3 {
 func (g *Geometry) BoundingBox() math32.Box3 {
 
 
 	// If valid, return its value
 	// 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) {
 func (g *Geometry) RenderSetup(gs *gls.GLS) {
 
 
 	// First time initialization
 	// First time initialization

+ 1 - 1
gls/build.go

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

+ 2 - 1
gls/uniform.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"fmt"
 )
 )
 
 
+// Uniform represents an OpenGL uniform.
 type Uniform struct {
 type Uniform struct {
 	name      string // base name
 	name      string // base name
 	nameIdx   string // cached indexed name
 	nameIdx   string // cached indexed name
@@ -16,7 +17,7 @@ type Uniform struct {
 	lastIndex int32  // last index
 	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) {
 func (u *Uniform) Init(name string) {
 
 
 	u.name = name
 	u.name = name

+ 10 - 10
graphic/graphic.go

@@ -24,8 +24,8 @@ type Graphic struct {
 	renderable bool               // Renderable flag
 	renderable bool               // Renderable flag
 	cullable   bool               // Cullable 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
 // 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.
 // 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
 	// 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.
 // 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.
 // 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.
 // GetMaterial returns the material associated with the GraphicMaterial.

+ 2 - 1
gui/align.go

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

+ 4 - 4
gui/assets/data.go

@@ -86,7 +86,7 @@ func fontsFreemonoTtf() (*asset, error) {
 		return nil, err
 		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}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 	return a, nil
 }
 }
@@ -106,7 +106,7 @@ func fontsFreesansTtf() (*asset, error) {
 		return nil, err
 		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}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 	return a, nil
 }
 }
@@ -126,7 +126,7 @@ func fontsFreesansboldTtf() (*asset, error) {
 		return nil, err
 		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}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 	return a, nil
 }
 }
@@ -146,7 +146,7 @@ func fontsMaterialiconsRegularTtf() (*asset, error) {
 		return nil, err
 		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}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 	return a, nil
 }
 }

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

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

+ 2 - 2
gui/button.go

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

+ 1 - 0
gui/docklayout.go

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

+ 2 - 2
gui/folder.go

@@ -22,8 +22,8 @@ type Folder struct {
 // FolderStyle contains the styling of a Folder.
 // FolderStyle contains the styling of a Folder.
 type FolderStyle struct {
 type FolderStyle struct {
 	PanelStyle
 	PanelStyle
-	FgColor     math32.Color4
-	Icons       [2]string
+	FgColor math32.Color4
+	Icons   [2]string
 }
 }
 
 
 // FolderStyles contains a FolderStyle for each valid GUI state.
 // 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.
 // Copyright 2016 The G3N Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 // license that can be found in the LICENSE file.
+
 package gui
 package gui
 
 
 // GridLayout is a panel layout which arranges its children in a rectangular grid.
 // 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
 	stateImages [ButtonDisabled + 1]*texture.Texture2D // array of images for each button state
 }
 }
 
 
+// ButtonState specifies a button state.
 type ButtonState int
 type ButtonState int
 
 
+// The possible button states.
 const (
 const (
 	ButtonNormal ButtonState = iota
 	ButtonNormal ButtonState = iota
 	ButtonOver
 	ButtonOver
-	//ButtonFocus
 	ButtonPressed
 	ButtonPressed
 	ButtonDisabled
 	ButtonDisabled
+	// ButtonFocus
 )
 )
 
 
-// ImageButton style
+// ImageButtonStyle contains the styling of an ImageButton.
 type ImageButtonStyle BasicStyle
 type ImageButtonStyle BasicStyle
 
 
-// All ImageButton styles
+// ImageButtonStyles contains one ImageButtonStyle for each possible ImageButton state.
 type ImageButtonStyles struct {
 type ImageButtonStyles struct {
 	Normal   ImageButtonStyle
 	Normal   ImageButtonStyle
 	Over     ImageButtonStyle
 	Over     ImageButtonStyle

+ 1 - 1
gui/imagelabel.go

@@ -29,7 +29,7 @@ type ImageLabel struct {
 	icon  *Label // optional internal icon label
 	icon  *Label // optional internal icon label
 }
 }
 
 
-// ImageLabelStyle
+// ImageLabelStyle contains the styling of an ImageLabel.
 type ImageLabelStyle BasicStyle
 type ImageLabelStyle BasicStyle
 
 
 // NewImageLabel creates and returns a pointer to a new image label widget
 // 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
 			// Break when the view/content proportion becomes smaller than the minimum button size
 			totalHeight += item.TotalHeight()
 			totalHeight += item.TotalHeight()
 		}
 		}
-		s.vscroll.SetButtonSize(s.height * s.height/totalHeight)
+		s.vscroll.SetButtonSize(s.height * s.height / totalHeight)
 	}
 	}
 
 
 	// Items width
 	// Items width
@@ -470,7 +470,7 @@ func (s *ItemScroller) hRecalc() {
 			// Break when the view/content proportion becomes smaller than the minimum button size
 			// Break when the view/content proportion becomes smaller than the minimum button size
 			totalWidth += item.GetPanel().Width()
 			totalWidth += item.GetPanel().Width()
 		}
 		}
-		s.hscroll.SetButtonSize(s.width * s.width/totalWidth)
+		s.hscroll.SetButtonSize(s.width * s.width / totalWidth)
 	}
 	}
 
 
 	// Items height
 	// Items height

+ 1 - 1
gui/label.go

@@ -35,7 +35,7 @@ func NewLabel(text string) *Label {
 	return NewLabelWithFont(text, StyleDefault().Font)
 	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.
 // the specified text drawn using the default icon font.
 func NewIcon(icon string) *Label {
 func NewIcon(icon string) *Label {
 	return NewLabelWithFont(icon, StyleDefault().FontIcon)
 	return NewLabelWithFont(icon, StyleDefault().FontIcon)

+ 10 - 10
gui/list.go

@@ -10,13 +10,13 @@ import (
 
 
 // List represents a list GUI element
 // List represents a list GUI element
 type List struct {
 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
 // ListItem encapsulates each item inserted into the list
@@ -29,13 +29,13 @@ type ListItem struct {
 	list        *List   // Pointer to list
 	list        *List   // Pointer to list
 }
 }
 
 
-// ListStyles
+// ListStyles encapsulates a set of styles for the list and item.
 type ListStyles struct {
 type ListStyles struct {
 	Scroller *ItemScrollerStyles
 	Scroller *ItemScrollerStyles
 	Item     *ListItemStyles
 	Item     *ListItemStyles
 }
 }
 
 
-// ListItemStyles
+// ListItemStyles contains one ListItemStyle for each possible item state.
 type ListItemStyles struct {
 type ListItemStyles struct {
 	Normal      ListItemStyle
 	Normal      ListItemStyle
 	Over        ListItemStyle
 	Over        ListItemStyle
@@ -44,7 +44,7 @@ type ListItemStyles struct {
 	SelHigh     ListItemStyle
 	SelHigh     ListItemStyle
 }
 }
 
 
-// ListItemStyle
+// ListItemStyle contains the styling of a list item.
 type ListItemStyle BasicStyle
 type ListItemStyle BasicStyle
 
 
 // OnListItemResize is the identifier of the event dispatched when a ListItem's child panel is resized
 // 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"
 	"time"
 )
 )
 
 
+// Menu is the menu GUI element
 type Menu struct {
 type Menu struct {
 	Panel                // embedded panel
 	Panel                // embedded panel
 	styles   *MenuStyles // pointer to current styles
 	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
 // and a content area. The content area can be associated with a texture
 // It is the building block of most GUI widgets.
 // It is the building block of most GUI widgets.
 type Panel struct {
 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
 	udata            struct {           // Combined uniform data 8 * vec4
 		bounds        math32.Vector4 // panel bounds in texture coordinates
 		bounds        math32.Vector4 // panel bounds in texture coordinates
 		borders       math32.Vector4 // panel borders 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)
 // Many GUI components can be styled using BasicStyle or redeclared versions thereof (e.g. ButtonStyle)
 type BasicStyle struct {
 type BasicStyle struct {
 	PanelStyle
 	PanelStyle
-	FgColor     math32.Color4
+	FgColor math32.Color4
 }
 }
 
 
 const (
 const (
@@ -599,8 +599,8 @@ func (p *Panel) ContainsPosition(x, y float32) bool {
 // Unlike "ContainsPosition" is does not consider the panel margins.
 // Unlike "ContainsPosition" is does not consider the panel margins.
 func (p *Panel) InsideBorders(x, y float32) bool {
 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 false
 	}
 	}
 	return true
 	return true

+ 2 - 1
gui/root.go

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

+ 25 - 25
gui/scroller.go

@@ -5,6 +5,7 @@
 package gui
 package gui
 
 
 import (
 import (
+	"github.com/g3n/engine/math32"
 	"github.com/g3n/engine/window"
 	"github.com/g3n/engine/window"
 )
 )
 
 
@@ -26,9 +27,10 @@ type Scroller struct {
 	modKeyPressed bool           // Modifier key is pressed
 	modKeyPressed bool           // Modifier key is pressed
 }
 }
 
 
-// ScrollMode specifies which scroll directions are allowed
+// ScrollMode specifies which scroll directions are allowed.
 type ScrollMode int
 type ScrollMode int
 
 
+// The various scroll modes.
 const (
 const (
 	ScrollNone       = ScrollMode(0x00)                              // No scrolling allowed
 	ScrollNone       = ScrollMode(0x00)                              // No scrolling allowed
 	ScrollVertical   = ScrollMode(0x01)                              // Vertical scrolling allowed
 	ScrollVertical   = ScrollMode(0x01)                              // Vertical scrolling allowed
@@ -39,6 +41,7 @@ const (
 // ScrollbarInterlocking specifies what happens where the vertical and horizontal scrollbars meet.
 // ScrollbarInterlocking specifies what happens where the vertical and horizontal scrollbars meet.
 type ScrollbarInterlocking int
 type ScrollbarInterlocking int
 
 
+// The three scrollbar interlocking types.
 const (
 const (
 	ScrollbarInterlockingNone       = ScrollbarInterlocking(iota) // No scrollbar interlocking
 	ScrollbarInterlockingNone       = ScrollbarInterlocking(iota) // No scrollbar interlocking
 	ScrollbarInterlockingVertical                                 // Vertical scrollbar takes precedence
 	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.
 // For the horizontal scrollbar it specifies whether it's added to the top or to the bottom.
 type ScrollbarPosition int
 type ScrollbarPosition int
 
 
+// The four possible scrollbar positions.
 const (
 const (
 	ScrollbarLeft   = ScrollbarPosition(iota) // Scrollbar is positioned on the left of the scroller
 	ScrollbarLeft   = ScrollbarPosition(iota) // Scrollbar is positioned on the left of the scroller
 	ScrollbarRight                            // Scrollbar is positioned on the right 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
 // 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
 // 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
 const ScrollModifierKey = window.KeyLeftShift
 
 
 // NewScroller creates and returns a pointer to a new Scroller with the specified
 // 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()
 	vScrollVisible := (s.vscroll != nil) && s.vscroll.Visible()
 	hScrollVisible := (s.hscroll != nil) && s.hscroll.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 vScrollVisible {
 		if hScrollVisible {
 		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 {
 		} else {
 			// Only vertical scrollbar present - scroll it
 			// 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 {
 	} else if hScrollVisible {
 		// Only horizontal scrollbar present - scroll it
 		// Only horizontal scrollbar present - scroll it
-		s.hscroll.SetValue(float32(s.hscroll.Value()) - valOffset)
+		s.hscroll.SetValue(float32(s.hscroll.Value()) - offsetX)
 	}
 	}
 
 
 	s.recalc()
 	s.recalc()
@@ -604,4 +604,4 @@ func (s *Scroller) applyStyle(ss *ScrollerStyle) {
 	s.corner.ApplyStyle(&s.style.CornerPanel)
 	s.corner.ApplyStyle(&s.style.CornerPanel)
 
 
 	s.Update()
 	s.Update()
-}
+}

+ 10 - 10
gui/style_dark.go

@@ -11,7 +11,7 @@ import (
 	"github.com/g3n/engine/text"
 	"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 {
 func NewDarkStyle() *Style {
 
 
 	// Fonts to use
 	// Fonts to use
@@ -39,12 +39,12 @@ func NewDarkStyle() *Style {
 	oneBounds := RectBounds{1, 1, 1, 1}
 	oneBounds := RectBounds{1, 1, 1, 1}
 	twoBounds := RectBounds{2, 2, 2, 2}
 	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.Text = math32.Color4{1, 1, 1, 1}
 	s.Color.TextDis = math32.Color4{0.4, 0.4, 0.4, 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.DPI = 72
 	s.Label.FontAttributes.Hinting = text.HintingNone
 	s.Label.FontAttributes.Hinting = text.HintingNone
 	s.Label.FontAttributes.LineSpacing = 1.0
 	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
 	// Button styles
 	s.Button = ButtonStyles{}
 	s.Button = ButtonStyles{}
@@ -122,7 +122,7 @@ func NewDarkStyle() *Style {
 	s.ScrollBar.Normal.BgColor = math32.Color4{0, 0, 0, 0.2}
 	s.ScrollBar.Normal.BgColor = math32.Color4{0, 0, 0, 0.2}
 	s.ScrollBar.Normal.ButtonLength = 32
 	s.ScrollBar.Normal.ButtonLength = 32
 	s.ScrollBar.Normal.Button = PanelStyle{
 	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.Over = s.ScrollBar.Normal
 	s.ScrollBar.Disabled = 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.DPI = 72
 	s.Label.FontAttributes.Hinting = text.HintingNone
 	s.Label.FontAttributes.Hinting = text.HintingNone
 	s.Label.FontAttributes.LineSpacing = 1.0
 	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
 	// Button styles
 	s.Button = ButtonStyles{}
 	s.Button = ButtonStyles{}

+ 8 - 9
gui/table.go

@@ -16,16 +16,17 @@ import (
 )
 )
 
 
 const (
 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
 	// Parameter is TableClickEvent
 	OnTableClick = "onTableClick"
 	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"
 	OnTableRowCount = "onTableRowCount"
 )
 )
 
 
 // TableSortType is the type used to specify the sort method for a table column
 // TableSortType is the type used to specify the sort method for a table column
 type TableSortType int
 type TableSortType int
 
 
+// The various sorting types
 const (
 const (
 	TableSortNone TableSortType = iota
 	TableSortNone TableSortType = iota
 	TableSortString
 	TableSortString
@@ -36,9 +37,9 @@ const (
 type TableSelType int
 type TableSelType int
 
 
 const (
 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
 	TableSelMultiRow
 )
 )
 
 
@@ -1615,9 +1616,8 @@ func (ts tableSortString) Less(i, j int) bool {
 	sj := fmt.Sprintf(ts.format, vj)
 	sj := fmt.Sprintf(ts.format, vj)
 	if ts.asc {
 	if ts.asc {
 		return si < sj
 		return si < sj
-	} else {
-		return sj < si
 	}
 	}
+	return sj < si
 }
 }
 
 
 // tableSortNumber is an internal type implementing the sort.Interface
 // tableSortNumber is an internal type implementing the sort.Interface
@@ -1638,9 +1638,8 @@ func (ts tableSortNumber) Less(i, j int) bool {
 	nj := cv2f64(vj)
 	nj := cv2f64(vj)
 	if ts.asc {
 	if ts.asc {
 		return ni < nj
 		return ni < nj
-	} else {
-		return nj < ni
 	}
 	}
+	return nj < ni
 }
 }
 
 
 // Try to convert an interface value to a float64 number
 // 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.
 // TreeNodeStyle contains the styling of a TreeNode.
 type TreeNodeStyle struct {
 type TreeNodeStyle struct {
 	PanelStyle
 	PanelStyle
-	FgColor     math32.Color4
-	Icons       [2]string
+	FgColor math32.Color4
+	Icons   [2]string
 }
 }
 
 
 // TreeNode is a tree node.
 // 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
 // ResizeBorders specifies which window borders can be resized
 type ResizeBorders int
 type ResizeBorders int
 
 
+// Resizing can be allowed or disallowed on each window edge
 const (
 const (
 	ResizeTop = ResizeBorders(1 << (iota + 1))
 	ResizeTop = ResizeBorders(1 << (iota + 1))
 	ResizeRight
 	ResizeRight

+ 1 - 0
light/directional.go

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

+ 0 - 1
light/doc.go

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

+ 5 - 5
light/spot.go

@@ -14,11 +14,11 @@ import (
 
 
 // Spot represents a spotlight
 // Spot represents a spotlight
 type Spot struct {
 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
 		color          math32.Color   // Light color
 		position       math32.Vector3 // Light position
 		position       math32.Vector3 // Light position
 		direction      math32.Vector3 // Light direction
 		direction      math32.Vector3 // Light direction

+ 1 - 1
material/material.go

@@ -331,7 +331,7 @@ func (mat *Material) RenderSetup(gs *gls.GLS) {
 		samplerName, _ := tex.GetUniformNames()
 		samplerName, _ := tex.GetUniformNames()
 		uniIdx, _ := samplerCounts[samplerName]
 		uniIdx, _ := samplerCounts[samplerName]
 		tex.RenderSetup(gs, slotIdx, uniIdx)
 		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
 	return m
 }
 }
 
 
-// TODO add SetNormalMap (and SetSpecularMap) to StandardMaterial.
 // SetNormalMap sets this material optional normal texture.
 // SetNormalMap sets this material optional normal texture.
 // Returns pointer to this updated material.
 // Returns pointer to this updated material.
+// TODO add SetNormalMap (and SetSpecularMap) to StandardMaterial.
 func (m *Physical) SetNormalMap(tex *texture.Texture2D) *Physical {
 func (m *Physical) SetNormalMap(tex *texture.Texture2D) *Physical {
 
 
 	m.normalTex = tex
 	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
 // AppendColor appends any number of Color to the array
 func (a *ArrayF32) AppendColor(v ...*Color) {
 func (a *ArrayF32) AppendColor(v ...*Color) {
 
 
@@ -92,6 +100,16 @@ func (a ArrayF32) GetVector3(pos int, v *Vector3) {
 	v.Z = a[pos+2]
 	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
 // GetColor stores in the specified Color the
 // values from the array starting at the specified pos
 // values from the array starting at the specified pos
 func (a ArrayF32) GetColor(pos int, v *Color) {
 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]
 	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
 // Set sets the values of the array starting at the specified pos
 // from the specified values
 // from the specified values
 func (a ArrayF32) Set(pos int, v ...float32) {
 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
 	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
 // SetColor sets the values of the array at the specified pos
 // from the RGB values of the specified Color
 // from the RGB values of the specified Color
 func (a ArrayF32) SetColor(pos int, v *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.
 // Returns pointer to this updated bounding box.
 func (b *Box3) ApplyMatrix4(matrix *Matrix4) *Box3 {
 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[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
 	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
 	planes []Plane
 }
 }
 
 
+// NewFrustumFromMatrix creates and returns a Frustum based on the provided matrix
 func NewFrustumFromMatrix(m *Matrix4) *Frustum {
 func NewFrustumFromMatrix(m *Matrix4) *Frustum {
 	f := new(Frustum)
 	f := new(Frustum)
 	f.planes = make([]Plane, 6)
 	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.
 // Returns pointer to this updated matrix.
 func (m *Matrix4) LookAt(eye, target, up *Vector3) *Matrix4 {
 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
 	return m
 }
 }

+ 0 - 2
math32/plane.go

@@ -4,8 +4,6 @@
 
 
 package math32
 package math32
 
 
-import ()
-
 // Plane represents a plane in 3D space by its normal vector and a constant.
 // 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.
 // When the the normal vector is the unit vector the constant is the distance from the origin.
 type Plane struct {
 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.
 // Renderer renders a 3D scene and/or a 2D GUI on the current window.
 type Renderer struct {
 type Renderer struct {
 	gs           *gls.GLS
 	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.
 // 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 {
 				if backToFront {
 					return g1pos.Z < g2pos.Z
 					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.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)
 	// 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) {
 		if len(ss.Defines) != len(other.Defines) {
 			return false
 			return false
 		}
 		}
-		for k, _ := range ss.Defines {
+		for k := range ss.Defines {
 			v1, ok1 := ss.Defines[k]
 			v1, ok1 := ss.Defines[k]
 			v2, ok2 := other.Defines[k]
 			v2, ok2 := other.Defines[k]
 			if v1 != v2 || ok1 != ok2 {
 			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
 			// Draw caret vertical line
 			caretH := int(f.attrib.PointSize) + 2
 			caretH := int(f.attrib.PointSize) + 2
 			caretY := int(d.Dot.Y>>6) - 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++ {
 			for j := caretY; j < caretY+caretH; j++ {
 				c.RGBA.Set(x+width, j, color)
 				c.RGBA.Set(x+width, j, color)
 			}
 			}

+ 0 - 1
texture/doc.go

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

+ 1 - 0
tools/g3nicodes/main.go

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

+ 2 - 1
tools/g3nshaders/main.go

@@ -24,6 +24,7 @@ import (
 	"text/template"
 	"text/template"
 )
 )
 
 
+// Program constants.
 const (
 const (
 	PROGNAME      = "g3nshaders"
 	PROGNAME      = "g3nshaders"
 	VMAJOR        = 0
 	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.
 // maps describing the include and shader names and programs shaders.
 //
 //
 const TEMPLATE = `// File generated by G3NSHADERS. Do not edit.
 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,
 	FATAL: bmagenta,
 }
 }
 
 
-// logger Console writer type
+// Console is a console writer used for logging.
 type Console struct {
 type Console struct {
 	writer *os.File
 	writer *os.File
 	color  bool
 	color  bool
@@ -52,6 +52,7 @@ func NewConsole(color bool) *Console {
 	return &Console{os.Stdout, color}
 	return &Console{os.Stdout, color}
 }
 }
 
 
+// Write writes the provided logger event to the console.
 func (w *Console) Write(event *Event) {
 func (w *Console) Write(event *Event) {
 
 
 	if w.color {
 	if w.color {

+ 5 - 0
util/logger/file.go

@@ -8,10 +8,12 @@ import (
 	"os"
 	"os"
 )
 )
 
 
+// File is a file writer used for logging.
 type File struct {
 type File struct {
 	writer *os.File
 	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) {
 func NewFile(filename string) (*File, error) {
 
 
 	file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
 	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
 	return &File{file}, nil
 }
 }
 
 
+// Write writes the provided logger event to the file.
 func (f *File) Write(event *Event) {
 func (f *File) Write(event *Event) {
 
 
 	f.writer.Write([]byte(event.fmsg))
 	f.writer.Write([]byte(event.fmsg))
 }
 }
 
 
+// Close closes the file.
 func (f *File) Close() {
 func (f *File) Close() {
 
 
 	f.writer.Close()
 	f.writer.Close()
 	f.writer = nil
 	f.writer = nil
 }
 }
 
 
+// Sync commits the current contents of the file to stable storage.
 func (f *File) Sync() {
 func (f *File) Sync() {
 
 
 	f.writer.Sync()
 	f.writer.Sync()

+ 10 - 10
util/logger/logger.go

@@ -38,11 +38,11 @@ const (
 var levelNames = [...]string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
 var levelNames = [...]string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
 
 
 // Default logger and global mutex
 // Default logger and global mutex
-var Default *Logger = nil
+var Default *Logger
 var rootLoggers = []*Logger{}
 var rootLoggers = []*Logger{}
 var mutex sync.Mutex
 var mutex sync.Mutex
 
 
-// Interface for all logger writers
+// LoggerWriter is the interface for all logger writers
 type LoggerWriter interface {
 type LoggerWriter interface {
 	Write(*Event)
 	Write(*Event)
 	Close()
 	Close()
@@ -61,7 +61,7 @@ type Logger struct {
 	children []*Logger
 	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 {
 type Event struct {
 	time    time.Time
 	time    time.Time
 	level   int
 	level   int
@@ -76,7 +76,7 @@ func init() {
 	Default.AddWriter(NewConsole(false))
 	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
 // If a parent logger is specified, the created logger inherits the
 // parent's configuration.
 // parent's configuration.
 func New(name string, parent *Logger) *Logger {
 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
 // 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
 // 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
 // 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
 // Log emits a log message with the specified level

+ 4 - 0
util/logger/net.go

@@ -8,10 +8,12 @@ import (
 	"net"
 	"net"
 )
 )
 
 
+// Net is a network writer used for logging.
 type Net struct {
 type Net struct {
 	conn net.Conn
 	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) {
 func NewNet(network string, address string) (*Net, error) {
 
 
 	n := new(Net)
 	n := new(Net)
@@ -23,11 +25,13 @@ func NewNet(network string, address string) (*Net, error) {
 	return n, nil
 	return n, nil
 }
 }
 
 
+// Write writes the provided logger event to the network.
 func (n *Net) Write(event *Event) {
 func (n *Net) Write(event *Event) {
 
 
 	n.conn.Write([]byte(event.fmsg))
 	n.conn.Write([]byte(event.fmsg))
 }
 }
 
 
+// Clone closes the network connection.
 func (n *Net) Close() {
 func (n *Net) Close() {
 
 
 	n.conn.Close()
 	n.conn.Close()