99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
package levels
|
|
|
|
import (
|
|
"math"
|
|
|
|
mgl "github.com/go-gl/mathgl/mgl32"
|
|
)
|
|
|
|
// LimitedCamera is a camera implementation with ranged controls for zooming and moving.
|
|
type LimitedCamera struct {
|
|
viewportWidth, viewportHeight float32
|
|
minZoom, maxZoom float32
|
|
minPos, maxPos float32
|
|
|
|
requestedZoomLevel float32
|
|
viewOffsetX, viewOffsetY float32
|
|
|
|
viewMatrix mgl.Mat4
|
|
}
|
|
|
|
// NewLimitedCamera returns a new instance of a LimitedCamera.
|
|
func NewLimitedCamera(minZoom, maxZoom float32, minPos, maxPos float32) *LimitedCamera {
|
|
cam := &LimitedCamera{
|
|
viewportWidth: 1.0,
|
|
viewportHeight: 1.0,
|
|
minZoom: minZoom,
|
|
maxZoom: maxZoom,
|
|
minPos: minPos,
|
|
maxPos: maxPos,
|
|
viewMatrix: mgl.Ident4()}
|
|
|
|
return cam
|
|
}
|
|
|
|
// SetViewportSize notifies the camera how big the view is.
|
|
func (cam *LimitedCamera) SetViewportSize(width, height float32) {
|
|
if (cam.viewportWidth != width) || (cam.viewportHeight != height) {
|
|
cam.viewportWidth, cam.viewportHeight = width, height
|
|
cam.updateViewMatrix()
|
|
}
|
|
}
|
|
|
|
// ViewMatrix implements the Viewer interface.
|
|
func (cam *LimitedCamera) ViewMatrix() *mgl.Mat4 {
|
|
return &cam.viewMatrix
|
|
}
|
|
|
|
// MoveBy adjusts the requested view offset by given delta values in world coordinates.
|
|
func (cam *LimitedCamera) MoveBy(dx, dy float32) {
|
|
cam.MoveTo(cam.viewOffsetX+dx, cam.viewOffsetY+dy)
|
|
}
|
|
|
|
// MoveTo sets the requested view offset to the given world coordinates.
|
|
func (cam *LimitedCamera) MoveTo(worldX, worldY float32) {
|
|
cam.viewOffsetX = cam.limitValue(worldX, -cam.maxPos, cam.minPos)
|
|
cam.viewOffsetY = cam.limitValue(worldY, -cam.maxPos, cam.minPos)
|
|
cam.updateViewMatrix()
|
|
}
|
|
|
|
// ZoomAt adjusts the requested zoom level by given delta, centered around given world position.
|
|
// Positive values zoom in.
|
|
func (cam *LimitedCamera) ZoomAt(levelDelta float32, x, y float32) {
|
|
cam.requestedZoomLevel = cam.limitValue(cam.requestedZoomLevel+levelDelta, cam.minZoom, cam.maxZoom)
|
|
|
|
focusPoint := mgl.Vec4{x, y, 0.0, 1.0}
|
|
oldPixel := cam.viewMatrix.Mul4x1(focusPoint)
|
|
|
|
cam.updateViewMatrix()
|
|
|
|
newPixel := cam.viewMatrix.Mul4x1(focusPoint)
|
|
scaleFactor := cam.scaleFactor()
|
|
cam.MoveBy(-(newPixel[0]-oldPixel[0])/scaleFactor, +(newPixel[1]-oldPixel[1])/scaleFactor)
|
|
}
|
|
|
|
func (cam *LimitedCamera) limitValue(value float32, min, max float32) float32 {
|
|
result := value
|
|
|
|
if result < min {
|
|
result = min
|
|
}
|
|
if result > max {
|
|
result = max
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (cam *LimitedCamera) scaleFactor() float32 {
|
|
return float32(math.Pow(2.0, float64(cam.requestedZoomLevel)))
|
|
}
|
|
|
|
func (cam *LimitedCamera) updateViewMatrix() {
|
|
scaleFactor := cam.scaleFactor()
|
|
cam.viewMatrix = mgl.Ident4().
|
|
Mul4(mgl.Translate3D(cam.viewportWidth/2.0, cam.viewportHeight/2.0, 0)).
|
|
Mul4(mgl.Scale3D(scaleFactor, -scaleFactor, 1.0)).
|
|
Mul4(mgl.Translate3D(cam.viewOffsetX, cam.viewOffsetY, 0))
|
|
}
|