Skip to content

Commit

Permalink
Merge pull request #74 from oakmound/release/2.0.0
Browse files Browse the repository at this point in the history
Oak 2.0.0
  • Loading branch information
200sc committed Feb 7, 2018
2 parents 02f2f13 + 3c48a73 commit d7a0494
Show file tree
Hide file tree
Showing 298 changed files with 11,914 additions and 3,923 deletions.
41 changes: 21 additions & 20 deletions README.md
Expand Up @@ -24,36 +24,41 @@ oak.AddScene("firstScene",
func()(nextScene string, result *oak.SceneResult){return "firstScene", nil})
oak.Init("firstScene")
```
See the [examples](examples) folder for longer demos.
See the [examples](examples) folder for longer demos, [godoc](https://godoc.org/github.com/oakmound/oak) for reference documentation, and the [wiki](https://github.com/oakmound/oak/wiki) for more guided feature sets, tutorials and walkthroughs.

## Motivation
The initial version of oak was made to support Oakmound Studio's game,
[Agent Blue](https://github.com/OakmoundStudio/AgentRelease) and was developed in parallel.
Oak supports Windows with no dependencies and Linux with limited audio dependencies.
[Agent Blue](https://github.com/OakmoundStudio/AgentRelease), and was developed in parallel.
Oak supports Windows with no dependencies and Linux with limited audio dependencies. We don't own a machine to check with, but hypothetically it supports OSX as well.
We hope that users will be able to make great pure Go games with oak and welcome improvements.

Because Oak wants to have as few dependencies as possible, Oak does not use OpenGL or [GLFW](https://github.com/go-gl/glfw).
Because Oak wants to have as few non-Go dependencies as possible, Oak does not use OpenGL or [GLFW](https://github.com/go-gl/glfw).
We're open to adding support for these in the future for performance gains, but we always want
an alternative that requires zero or near-zero dependencies. (We are very sad about the linux audio
dependency and are considering writing an audio driver just to get rid of it.)

## Support

For talk about the engine or help, that is not significant enough to be an Issue or PR, see the #oak channel on the [gophers slack](https://invite.slack.golangbridge.org/).

## Features
1. Window Rendering
- Windows and key events through [shiny](https://github.com/golang/exp/tree/master/shiny)
- Windows and key events forked from [shiny](https://github.com/oakmound/shiny)
- Logical frame rate distinct from Draw rate
1. [Image Management](https://godoc.org/github.com/oakmound/oak/render)
- `render.Renderable` interface
- TileSheet Batch Loading
- Sprite Sheet Batch Loading at startup
- Manipulation
- `render.Modifiable` interface
- Built in Shaping, Coloring, Shading, ...
- Some built ins via [gift](https://github.com/disintegration/gift)
- extensible Modification syntax `func(image.Image) *image.RGBA`
- Copying
- Built in Transformations and Filters
- Some built-ins via [gift](https://github.com/disintegration/gift)
- Extensible Modification syntax `func(image.Image) *image.RGBA`
- Built in `Renderable` types
- `Sprite`
- Sheet `Animation`
- `Sequence`, `Compound`, `Composite`
- Primitive builders, `ColorBox`, `Line`, `Bezier`
- `Sequence` for animations
- `Switch` for conditionally displaying one other Renderable
- `Composite` for displaying multiple Renderables as one
- History-tracking `Reverting`
- Primarily 2D
1. [Particle System](https://godoc.org/github.com/oakmound/oak/render/particle)
Expand All @@ -66,8 +71,8 @@ Oak supports Windows with no dependencies and Linux with limited audio dependenc
- Batch Loading
- Positional filters to pan and scale audio based on a listening position
1. [Collision](https://godoc.org/github.com/oakmound/oak/collision)
- Collision R-Tree from [rtreego](https://github.com/dhconnelly/rtreego)
- 2D Raycasting
- Collision R-Tree forked from [rtreego](https://github.com/dhconnelly/rtreego)
- [2D Raycasting](collision/ray)
- Collision Spaces
- Attachable to Objects
- Auto React to collisions through events
Expand Down Expand Up @@ -96,9 +101,5 @@ Oak supports Windows with no dependencies and Linux with limited audio dependenc
- 2D arrays
1. [Custom Console Commands](debugConsole.go)
1. [Logging](https://godoc.org/github.com/oakmound/oak/dlog)
- Controlled by config files
- Filterable by string, debug level

## Package-specific Usage

... Pending! See examples or godoc!
- Swappable with custom implementations
- Default Implementation: 4 log levels, writes to file and stdout
33 changes: 33 additions & 0 deletions alg/degrees.go
@@ -0,0 +1,33 @@
package alg

import "math"

const (
// DegToRad is the constant value something in
// degrees should be multiplied by to obtain
// something in radians.
DegToRad = math.Pi / 180
// RadToDeg is the constant value something in
// radians should be multiplied by to obtain
// something in degrees.
RadToDeg = 180 / math.Pi
)

// We might not want these types
// It might be too much of a hassle to deal with them

// A Radian value is a float that specifies it should be in radians.
type Radian float64

// Degrees converts a Radian to Degrees.
func (r Radian) Degrees() Degree {
return Degree(r * RadToDeg)
}

// A Degree value is a float that specifies it should be in degrees.
type Degree float64

// Radians converts a Degree to Radians.
func (d Degree) Radians() Radian {
return Radian(d * DegToRad)
}
15 changes: 15 additions & 0 deletions alg/degrees_test.go
@@ -0,0 +1,15 @@
package alg

import (
"math"
"testing"

"github.com/stretchr/testify/assert"
)

func TestDegrees(t *testing.T) {
var f Degree = 90
assert.Equal(t, Radian(f*DegToRad), f.Radians())
var f2 Radian = math.Pi / 2
assert.Equal(t, Degree(f2*RadToDeg), f2.Degrees())
}
117 changes: 115 additions & 2 deletions alg/floatgeom/point.go
@@ -1,6 +1,10 @@
package floatgeom

import "math"
import (
"math"

"github.com/oakmound/oak/alg"
)

// Point2 represents a 2D point in space.
type Point2 [2]float64
Expand Down Expand Up @@ -157,6 +161,8 @@ func (p Point2) MulConst(fs ...float64) Point2 {
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) Div(ps ...Point2) Point2 {
for _, p2 := range ps {
p[0] /= p2[0]
Expand All @@ -165,6 +171,17 @@ func (p Point2) Div(ps ...Point2) Point2 {
return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) DivConst(fs ...float64) Point2 {
for _, f := range fs {
p[0] /= f
p[1] /= f
}
return p
}

// Add combines the input points via addition.
func (p Point3) Add(ps ...Point3) Point3 {
for _, p2 := range ps {
Expand Down Expand Up @@ -206,6 +223,8 @@ func (p Point3) MulConst(fs ...float64) Point3 {
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) Div(ps ...Point3) Point3 {
for _, p2 := range ps {
p[0] /= p2[0]
Expand All @@ -215,6 +234,81 @@ func (p Point3) Div(ps ...Point3) Point3 {
return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) DivConst(fs ...float64) Point3 {
for _, f := range fs {
p[0] /= f
p[1] /= f
p[2] /= f
}
return p
}

// Dot returns the dot product of the input points
func (p Point2) Dot(p2 Point2) float64 {
return p[0]*p2[0] + p[1]*p2[1]
}

// Dot returns the dot product of the input points
func (p Point3) Dot(p2 Point3) float64 {
return p[0]*p2[0] + p[1]*p2[1] + p[2]*p2[2]
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point2) Magnitude() float64 {
return math.Sqrt(p.Dot(p))
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point3) Magnitude() float64 {
return math.Sqrt(p.Dot(p))
}

// Normalize converts this point into a unit vector.
func (p Point2) Normalize() Point2 {
mgn := p.Magnitude()
if mgn == 0 {
return p
}
return p.DivConst(mgn)
}

// Normalize converts this point into a unit vector.
func (p Point3) Normalize() Point3 {
mgn := p.Magnitude()
if mgn == 0 {
return p
}
return p.DivConst(mgn)
}

// Rotate takes in a set of angles and rotates v by their sum
// the input angles are expected to be in degrees.
func (p Point2) Rotate(fs ...float64) Point2 {
angle := 0.0
for _, f := range fs {
angle += f
}
mgn := p.Magnitude()
angle = p.ToRadians() + (angle * alg.DegToRad)

return Point2{math.Cos(angle) * mgn, math.Sin(angle) * mgn}
}

// RotateRadians takes in a set of angles and rotates v by their sum
// the input angles are expected to be in radians.
func (p Point2) RotateRadians(fs ...float64) Point2 {
angle := p.ToRadians()
for _, f := range fs {
angle += f
}
mgn := p.Magnitude()

return Point2{math.Cos(angle) * mgn, math.Sin(angle) * mgn}
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point2) ToRect(span float64) Rect2 {
Expand All @@ -227,9 +321,28 @@ func (p Point3) ToRect(span float64) Rect3 {
return NewRect3WH(p[0], p[1], p[2], span, span, span)
}

// ProjectX projects the Point3 onto the x axis, removing it's
// x component and returning a Point2
// todo: I'm not sure about this (these) function name
func (p Point3) ProjectX() Point2 {
return Point2{p[1], p[2]}
}

// ProjectY projects the Point3 onto the y axis, removing it's
// y component and returning a Point2
func (p Point3) ProjectY() Point2 {
return Point2{p[0], p[2]}
}

// ProjectZ projects the Point3 onto the z axis, removing it's
// z component and returning a Point2
func (p Point3) ProjectZ() Point2 {
return Point2{p[0], p[1]}
}

// ToAngle returns this point as an angle in degrees.
func (p Point2) ToAngle() float64 {
return p.ToRadians() * 180 / math.Pi
return p.ToRadians() * alg.RadToDeg
}

// ToRadians returns this point as an angle in radians.
Expand Down
78 changes: 78 additions & 0 deletions alg/floatgeom/point_test.go
Expand Up @@ -4,10 +4,88 @@ import (
"math"
"math/rand"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func Seed() {
rand.Seed(time.Now().UnixNano())
}

func TestPointRotate(t *testing.T) {
p := Point2{0, 1}
assert.Equal(t, -1.0, p.Rotate(90).X())
assert.Equal(t, -1.0, p.RotateRadians(math.Pi).Y())
}

func TestPointNormalize(t *testing.T) {
p1 := Point2{100, 200}.Normalize()
p2 := Point3{100, 200, 300}.Normalize()

assert.InEpsilon(t, p1.X(), 1/math.Sqrt(5), .0001)
assert.InEpsilon(t, p1.Y(), 2/math.Sqrt(5), .0001)
assert.InEpsilon(t, p2.X(), 1/math.Sqrt(14), .0001)
assert.InEpsilon(t, p2.Y(), 2/math.Sqrt(14), .0001)
assert.InEpsilon(t, p2.Z(), 3/math.Sqrt(14), .0001)

p3 := Point2{0, 0}
p4 := Point3{0, 0, 0}
assert.Equal(t, p3, p3.Normalize())
assert.Equal(t, p4, p4.Normalize())
}

func TestPointProject(t *testing.T) {
Seed()
for i := 0; i < randTests; i++ {
x, y, z := rand.Float64(), rand.Float64(), rand.Float64()
p := Point3{x, y, z}
assert.Equal(t, Point2{x, y}, p.ProjectZ())
assert.Equal(t, Point2{x, z}, p.ProjectY())
assert.Equal(t, Point2{y, z}, p.ProjectX())
}
}

func TestPointConstMods(t *testing.T) {
p1 := Point2{1, 1}
p2 := Point3{1, 1, 1}
assert.Equal(t, Point2{5, 5}, p1.MulConst(5))
assert.Equal(t, Point3{100, 100, 100}, p2.MulConst(100))
p3 := Point2{2, 2}
p4 := Point3{2, 2, 2}
assert.Equal(t, Point2{.5, .5}, p3.DivConst(4))
assert.Equal(t, Point3{.25, .25, .25}, p4.DivConst(8))
}

func TestAnglePoints(t *testing.T) {
p1 := Point2{1, 0}
p2 := Point2{0, 1}

assert.Equal(t, p1, AnglePoint(0))
assert.Equal(t, p1, RadianPoint(0))
p3 := AnglePoint(90)
p4 := RadianPoint(math.Pi / 2)
assert.InEpsilon(t, p2.Y(), p3.Y(), .0001)
assert.InEpsilon(t, p2.Y(), p4.Y(), .0001)

deg := p1.ToAngle()
rds := p1.ToRadians()

assert.Equal(t, 0.0, deg)
assert.Equal(t, 0.0, rds)

deg = p2.ToAngle()
rds = p2.ToRadians()

assert.InEpsilon(t, 90.0, deg, .0001)
assert.InEpsilon(t, math.Pi/2, rds, .0001)

p5 := Point2{-1, 0}

assert.InEpsilon(t, 45.0, p2.AngleTo(p5), .0001)
assert.InEpsilon(t, math.Pi/4, p2.RadiansTo(p5), .0001)
}

func TestPointGreaterOf(t *testing.T) {
a := Point2{0, 1}
b := Point2{1, 0}
Expand Down

0 comments on commit d7a0494

Please sign in to comment.