mirror of
https://github.com/Kugelschieber/go-game.git
synced 2026-01-18 06:40:28 +00:00
Added ply loader and camera.
This commit is contained in:
78
camera.go
Normal file
78
camera.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package goga
|
||||||
|
|
||||||
|
const (
|
||||||
|
default_camera_pos_x = 5
|
||||||
|
default_camera_pos_y = 5
|
||||||
|
default_camera_pos_z = 5
|
||||||
|
default_camera_up_x = 0
|
||||||
|
default_camera_up_y = 0
|
||||||
|
default_camera_up_z = 1
|
||||||
|
default_camera_fov = 60
|
||||||
|
default_camera_znear = 1
|
||||||
|
default_camera_zfar = 20
|
||||||
|
)
|
||||||
|
|
||||||
|
type Camera struct {
|
||||||
|
Viewport Vec4
|
||||||
|
Position, LookAt, Up Vec3
|
||||||
|
Fov, Ratio, Znear, Zfar float64
|
||||||
|
Projection, Ortho3D, View Mat4
|
||||||
|
Ortho Mat3
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new 2D/3D camera.
|
||||||
|
// Pass the viewport as arguments.
|
||||||
|
func NewCamera(x, y, width, height int) *Camera {
|
||||||
|
camera := &Camera{}
|
||||||
|
camera.Position = Vec3{default_camera_pos_x, default_camera_pos_y, default_camera_pos_z}
|
||||||
|
camera.Up = Vec3{default_camera_up_x, default_camera_up_y, default_camera_up_z}
|
||||||
|
camera.Fov = default_camera_fov
|
||||||
|
camera.Znear = default_camera_znear
|
||||||
|
camera.Zfar = default_camera_zfar
|
||||||
|
camera.SetViewport(x, y, width, height)
|
||||||
|
camera.CalcRatio()
|
||||||
|
|
||||||
|
return camera
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates viewport.
|
||||||
|
func (c *Camera) SetViewport(x, y, width, height int) {
|
||||||
|
c.Viewport = Vec4{float64(x), float64(y), float64(width), float64(height)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates viewport ratio (width/height).
|
||||||
|
func (c *Camera) CalcRatio() {
|
||||||
|
c.Ratio = (c.Viewport.Z - c.Viewport.X) / (c.Viewport.W - c.Viewport.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates projection matrix and returns it.
|
||||||
|
func (c *Camera) CalcProjection() *Mat4 {
|
||||||
|
c.Projection.Identity()
|
||||||
|
c.Projection.Perspective(c.Fov, c.Ratio, c.Znear, c.Zfar)
|
||||||
|
|
||||||
|
return &c.Projection
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates orthogonal projection matrix and returns it.
|
||||||
|
func (c *Camera) CalcOrtho() *Mat3 {
|
||||||
|
c.Ortho.Identity()
|
||||||
|
c.Ortho.Ortho(c.Viewport)
|
||||||
|
|
||||||
|
return &c.Ortho
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates 3D orthogonal projection matrix and returns it.
|
||||||
|
func (c *Camera) CalcOrtho3D() *Mat4 {
|
||||||
|
c.Ortho3D.Identity()
|
||||||
|
c.Ortho3D.Ortho(c.Viewport, c.Znear, c.Zfar)
|
||||||
|
|
||||||
|
return &c.Ortho3D
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates view matrix and returns it.
|
||||||
|
func (c *Camera) CalcView() *Mat4 {
|
||||||
|
c.View.Identity()
|
||||||
|
c.View.LookAt(c.Position, c.LookAt, c.Up)
|
||||||
|
|
||||||
|
return &c.View
|
||||||
|
}
|
||||||
233
loader.go
233
loader.go
@@ -1,11 +1,15 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v4.5-core/gl"
|
||||||
"image"
|
"image"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
"image/png"
|
"image/png"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Loads textures from png files.
|
// Loads textures from png files.
|
||||||
@@ -56,3 +60,232 @@ func (p *PngLoader) Load(file string) (Res, error) {
|
|||||||
func (p *PngLoader) Ext() string {
|
func (p *PngLoader) Ext() string {
|
||||||
return "png"
|
return "png"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Standford ply file resource.
|
||||||
|
type Ply struct {
|
||||||
|
name string
|
||||||
|
path string
|
||||||
|
ext string
|
||||||
|
|
||||||
|
firstLine, data, hasVertex, hasTexCoord, hasNormal bool
|
||||||
|
elements, faces int
|
||||||
|
indices []uint32
|
||||||
|
vertices, texCoords, normals []float32
|
||||||
|
|
||||||
|
IndexBuffer, VertexBuffer, TexCoordBuffer, NormalBuffer *VBO
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the name of this resource.
|
||||||
|
func (p *Ply) GetName() string {
|
||||||
|
return p.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the name of this resource.
|
||||||
|
func (p *Ply) SetName(name string) {
|
||||||
|
p.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the path of this resource.
|
||||||
|
func (p *Ply) GetPath() string {
|
||||||
|
return p.path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the path of this resource.
|
||||||
|
func (p *Ply) SetPath(path string) {
|
||||||
|
p.path = path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the file extension of this resource.
|
||||||
|
func (p *Ply) GetExt() string {
|
||||||
|
return p.ext
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the file extension of this resource.
|
||||||
|
func (p *Ply) SetExt(ext string) {
|
||||||
|
p.ext = ext
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loads ply files and creates VBOs within the Ply resource.
|
||||||
|
// The indices must be present as triangles.
|
||||||
|
// Expected type is float32. If it fails to parse, it will panic.
|
||||||
|
type PlyLoader struct {
|
||||||
|
VboUsage uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PlyLoader) Load(file string) (Res, error) {
|
||||||
|
handle, err := os.Open(file)
|
||||||
|
defer handle.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(handle)
|
||||||
|
ply := Ply{}
|
||||||
|
ply.indices = make([]uint32, 0)
|
||||||
|
ply.vertices = make([]float32, 0)
|
||||||
|
ply.texCoords = make([]float32, 0)
|
||||||
|
ply.normals = make([]float32, 0)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.ToLower(scanner.Text())
|
||||||
|
|
||||||
|
if ply.data && ply.elements == 0 && ply.faces > 0 {
|
||||||
|
ply.faces--
|
||||||
|
|
||||||
|
if err := ply.parseIndices(line); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ply.data && ply.elements > 0 {
|
||||||
|
ply.elements--
|
||||||
|
|
||||||
|
if err := ply.parseData(line); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ply.parseHeader(line); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ply.firstLine = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
index, vertex, texCoord, normal := ply.createVBOs(p.VboUsage)
|
||||||
|
ply.IndexBuffer = index
|
||||||
|
ply.VertexBuffer = vertex
|
||||||
|
ply.TexCoordBuffer = texCoord
|
||||||
|
ply.NormalBuffer = normal
|
||||||
|
|
||||||
|
return &ply, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Ply) createVBOs(vboUsage uint32) (*VBO, *VBO, *VBO, *VBO) {
|
||||||
|
index := NewVBO(gl.ELEMENT_ARRAY_BUFFER)
|
||||||
|
index.Fill(gl.Ptr(p.indices), 4, len(p.indices), vboUsage)
|
||||||
|
|
||||||
|
vertex := NewVBO(gl.ARRAY_BUFFER)
|
||||||
|
vertex.Fill(gl.Ptr(p.vertices), 4, len(p.vertices), vboUsage)
|
||||||
|
|
||||||
|
var texCoord, normal *VBO
|
||||||
|
|
||||||
|
if p.hasTexCoord {
|
||||||
|
texCoord = NewVBO(gl.ARRAY_BUFFER)
|
||||||
|
texCoord.Fill(gl.Ptr(p.texCoords), 4, len(p.texCoords), vboUsage)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.hasNormal {
|
||||||
|
normal = NewVBO(gl.ARRAY_BUFFER)
|
||||||
|
normal.Fill(gl.Ptr(p.normals), 4, len(p.normals), vboUsage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return index, vertex, texCoord, normal
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Ply) parseHeader(line string) error {
|
||||||
|
if p.firstLine && line != "ply" { // make sure it's a ply file
|
||||||
|
return errors.New("File is not of type ply")
|
||||||
|
} else if strings.Contains(line, "element vertex") { // number of elements
|
||||||
|
elements, err := strconv.Atoi(line[15:])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("Elements could not be parsed")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.elements = elements
|
||||||
|
} else if strings.Contains(line, "property float") {
|
||||||
|
line = line[15:]
|
||||||
|
|
||||||
|
if line == "x" || line == "y" || line == "z" {
|
||||||
|
p.hasVertex = true
|
||||||
|
} else if line == "nx" || line == "ny" || line == "nz" {
|
||||||
|
p.hasNormal = true
|
||||||
|
} else if line == "s" || line == "t" {
|
||||||
|
p.hasTexCoord = true
|
||||||
|
}
|
||||||
|
} else if strings.Contains(line, "element face") { // number of faces
|
||||||
|
faces, err := strconv.Atoi(line[13:])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("Faces could not be parsed")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.faces = faces
|
||||||
|
} else if strings.Contains(line, "end_header") {
|
||||||
|
p.data = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Ply) parseData(line string) error {
|
||||||
|
if !p.hasVertex {
|
||||||
|
return errors.New("ply must have vertex data")
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(line, " ")
|
||||||
|
i := 0
|
||||||
|
|
||||||
|
p.vertices = append(p.vertices, parseFloat32(parts[0]))
|
||||||
|
p.vertices = append(p.vertices, parseFloat32(parts[1]))
|
||||||
|
p.vertices = append(p.vertices, parseFloat32(parts[2]))
|
||||||
|
|
||||||
|
if p.hasNormal {
|
||||||
|
i += 3
|
||||||
|
|
||||||
|
p.normals = append(p.normals, parseFloat32(parts[3]))
|
||||||
|
p.normals = append(p.normals, parseFloat32(parts[4]))
|
||||||
|
p.normals = append(p.normals, parseFloat32(parts[5]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.hasTexCoord {
|
||||||
|
p.texCoords = append(p.texCoords, parseFloat32(parts[3+i]))
|
||||||
|
p.texCoords = append(p.texCoords, parseFloat32(parts[4+i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFloat32(str string) float32 {
|
||||||
|
float, err := strconv.ParseFloat(str, 32)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return float32(float)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Ply) parseIndices(line string) error {
|
||||||
|
parts := strings.Split(line, " ")
|
||||||
|
|
||||||
|
if len(parts) != 4 || parts[0] != "3" {
|
||||||
|
return errors.New("Expected triangles for indices")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.indices = append(p.indices, parseUint32(parts[1]))
|
||||||
|
p.indices = append(p.indices, parseUint32(parts[2]))
|
||||||
|
p.indices = append(p.indices, parseUint32(parts[3]))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseUint32(str string) uint32 {
|
||||||
|
i, err := strconv.Atoi(str)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint32(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PlyLoader) Ext() string {
|
||||||
|
return "ply"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user