Merge branch 'master' into gl2.1
This commit is contained in:
commit
c331fe2583
|
@ -20,6 +20,7 @@ covering several topics of Pixel. Here's the content of the tutorial parts so fa
|
||||||
- [Pressing keys and clicking mouse](https://github.com/faiface/pixel/wiki/Pressing-keys-and-clicking-mouse)
|
- [Pressing keys and clicking mouse](https://github.com/faiface/pixel/wiki/Pressing-keys-and-clicking-mouse)
|
||||||
- [Drawing efficiently with Batch](https://github.com/faiface/pixel/wiki/Drawing-efficiently-with-Batch)
|
- [Drawing efficiently with Batch](https://github.com/faiface/pixel/wiki/Drawing-efficiently-with-Batch)
|
||||||
- [Drawing shapes with IMDraw](https://github.com/faiface/pixel/wiki/Drawing-shapes-with-IMDraw)
|
- [Drawing shapes with IMDraw](https://github.com/faiface/pixel/wiki/Drawing-shapes-with-IMDraw)
|
||||||
|
- [Typing text on the screen](https://github.com/faiface/pixel/wiki/Typing-text-on-the-screen)
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|
2
data.go
2
data.go
|
@ -45,7 +45,7 @@ func (td *TrianglesData) SetLen(len int) {
|
||||||
Color RGBA
|
Color RGBA
|
||||||
Picture Vec
|
Picture Vec
|
||||||
Intensity float64
|
Intensity float64
|
||||||
}{ZV, Alpha(1), ZV, 0})
|
}{Color: RGBA{1, 1, 1, 1}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len < td.Len() {
|
if len < td.Len() {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 stephen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Maze generator in Go
|
||||||
|
|
||||||
|
Created by [Stephen Chavez](https://github.com/redragonx)
|
||||||
|
|
||||||
|
This uses the game engine: Pixel. Install it here: https://github.com/faiface/pixel
|
||||||
|
|
||||||
|
I made this to improve my understanding of Go and some game concepts with some basic maze generating algorithms.
|
||||||
|
|
||||||
|
Controls: Press 'R' to restart the maze.
|
||||||
|
|
||||||
|
Optional command-line arguments: `go run ./maze-generator.go`
|
||||||
|
- `-w` sets the maze's width in pixels.
|
||||||
|
- `-h` sets the maze's height in pixels.
|
||||||
|
- `-c` sets the maze cell's size in pixels.
|
||||||
|
|
||||||
|
Code based on the Recursive backtracker algorithm.
|
||||||
|
- https://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker
|
||||||
|
|
||||||
|

|
|
@ -0,0 +1,317 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Code based on the Recursive backtracker algorithm.
|
||||||
|
// https://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker
|
||||||
|
// See https://youtu.be/HyK_Q5rrcr4 as an example
|
||||||
|
// YouTube example ported to Go for the Pixel library.
|
||||||
|
|
||||||
|
// Created by Stephen Chavez
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/faiface/pixel"
|
||||||
|
"github.com/faiface/pixel/examples/community/maze/stack"
|
||||||
|
"github.com/faiface/pixel/imdraw"
|
||||||
|
"github.com/faiface/pixel/pixelgl"
|
||||||
|
|
||||||
|
"github.com/pkg/profile"
|
||||||
|
"golang.org/x/image/colornames"
|
||||||
|
)
|
||||||
|
|
||||||
|
var visitedColor = pixel.RGB(0.5, 0, 1).Mul(pixel.Alpha(0.35))
|
||||||
|
var hightlightColor = pixel.RGB(0.3, 0, 0).Mul(pixel.Alpha(0.45))
|
||||||
|
var debug = false
|
||||||
|
|
||||||
|
type cell struct {
|
||||||
|
walls [4]bool // Wall order: top, right, bottom, left
|
||||||
|
|
||||||
|
row int
|
||||||
|
col int
|
||||||
|
visited bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cell) Draw(imd *imdraw.IMDraw, wallSize int) {
|
||||||
|
drawCol := c.col * wallSize // x
|
||||||
|
drawRow := c.row * wallSize // y
|
||||||
|
|
||||||
|
imd.Color = colornames.White
|
||||||
|
if c.walls[0] {
|
||||||
|
// top line
|
||||||
|
imd.Push(pixel.V(float64(drawCol), float64(drawRow)), pixel.V(float64(drawCol+wallSize), float64(drawRow)))
|
||||||
|
imd.Line(3)
|
||||||
|
}
|
||||||
|
if c.walls[1] {
|
||||||
|
// right Line
|
||||||
|
imd.Push(pixel.V(float64(drawCol+wallSize), float64(drawRow)), pixel.V(float64(drawCol+wallSize), float64(drawRow+wallSize)))
|
||||||
|
imd.Line(3)
|
||||||
|
}
|
||||||
|
if c.walls[2] {
|
||||||
|
// bottom line
|
||||||
|
imd.Push(pixel.V(float64(drawCol+wallSize), float64(drawRow+wallSize)), pixel.V(float64(drawCol), float64(drawRow+wallSize)))
|
||||||
|
imd.Line(3)
|
||||||
|
}
|
||||||
|
if c.walls[3] {
|
||||||
|
// left line
|
||||||
|
imd.Push(pixel.V(float64(drawCol), float64(drawRow+wallSize)), pixel.V(float64(drawCol), float64(drawRow)))
|
||||||
|
imd.Line(3)
|
||||||
|
}
|
||||||
|
imd.EndShape = imdraw.SharpEndShape
|
||||||
|
|
||||||
|
if c.visited {
|
||||||
|
imd.Color = visitedColor
|
||||||
|
imd.Push(pixel.V(float64(drawCol), (float64(drawRow))), pixel.V(float64(drawCol+wallSize), float64(drawRow+wallSize)))
|
||||||
|
imd.Rectangle(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cell) GetNeighbors(grid []*cell, cols int, rows int) ([]*cell, error) {
|
||||||
|
neighbors := []*cell{}
|
||||||
|
j := c.row
|
||||||
|
i := c.col
|
||||||
|
|
||||||
|
top, _ := getCellAt(i, j-1, cols, rows, grid)
|
||||||
|
right, _ := getCellAt(i+1, j, cols, rows, grid)
|
||||||
|
bottom, _ := getCellAt(i, j+1, cols, rows, grid)
|
||||||
|
left, _ := getCellAt(i-1, j, cols, rows, grid)
|
||||||
|
|
||||||
|
if top != nil && !top.visited {
|
||||||
|
neighbors = append(neighbors, top)
|
||||||
|
}
|
||||||
|
if right != nil && !right.visited {
|
||||||
|
neighbors = append(neighbors, right)
|
||||||
|
}
|
||||||
|
if bottom != nil && !bottom.visited {
|
||||||
|
neighbors = append(neighbors, bottom)
|
||||||
|
}
|
||||||
|
if left != nil && !left.visited {
|
||||||
|
neighbors = append(neighbors, left)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(neighbors) == 0 {
|
||||||
|
return nil, errors.New("We checked all cells...")
|
||||||
|
}
|
||||||
|
return neighbors, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cell) GetRandomNeighbor(grid []*cell, cols int, rows int) (*cell, error) {
|
||||||
|
neighbors, err := c.GetNeighbors(grid, cols, rows)
|
||||||
|
if neighbors == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(neighbors))))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
randomIndex := nBig.Int64()
|
||||||
|
return neighbors[randomIndex], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cell) hightlight(imd *imdraw.IMDraw, wallSize int) {
|
||||||
|
x := c.col * wallSize
|
||||||
|
y := c.row * wallSize
|
||||||
|
|
||||||
|
imd.Color = hightlightColor
|
||||||
|
imd.Push(pixel.V(float64(x), float64(y)), pixel.V(float64(x+wallSize), float64(y+wallSize)))
|
||||||
|
imd.Rectangle(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCell(col int, row int) *cell {
|
||||||
|
newCell := new(cell)
|
||||||
|
newCell.row = row
|
||||||
|
newCell.col = col
|
||||||
|
|
||||||
|
for i := range newCell.walls {
|
||||||
|
newCell.walls[i] = true
|
||||||
|
}
|
||||||
|
return newCell
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the inital maze slice for use.
|
||||||
|
func initGrid(cols, rows int) []*cell {
|
||||||
|
grid := []*cell{}
|
||||||
|
for j := 0; j < rows; j++ {
|
||||||
|
for i := 0; i < cols; i++ {
|
||||||
|
newCell := newCell(i, j)
|
||||||
|
grid = append(grid, newCell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return grid
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupMaze(cols, rows int) ([]*cell, *stack.Stack, *cell) {
|
||||||
|
// Make an empty grid
|
||||||
|
grid := initGrid(cols, rows)
|
||||||
|
backTrackStack := stack.NewStack(len(grid))
|
||||||
|
currentCell := grid[0]
|
||||||
|
|
||||||
|
return grid, backTrackStack, currentCell
|
||||||
|
}
|
||||||
|
|
||||||
|
func cellIndex(i, j, cols, rows int) int {
|
||||||
|
if i < 0 || j < 0 || i > cols-1 || j > rows-1 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return i + j*cols
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCellAt(i int, j int, cols int, rows int, grid []*cell) (*cell, error) {
|
||||||
|
possibleIndex := cellIndex(i, j, cols, rows)
|
||||||
|
|
||||||
|
if possibleIndex == -1 {
|
||||||
|
return nil, fmt.Errorf("cellIndex: CellIndex is a negative number %d", possibleIndex)
|
||||||
|
}
|
||||||
|
return grid[possibleIndex], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeWalls(a *cell, b *cell) {
|
||||||
|
x := a.col - b.col
|
||||||
|
|
||||||
|
if x == 1 {
|
||||||
|
a.walls[3] = false
|
||||||
|
b.walls[1] = false
|
||||||
|
} else if x == -1 {
|
||||||
|
a.walls[1] = false
|
||||||
|
b.walls[3] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
y := a.row - b.row
|
||||||
|
|
||||||
|
if y == 1 {
|
||||||
|
a.walls[0] = false
|
||||||
|
b.walls[2] = false
|
||||||
|
} else if y == -1 {
|
||||||
|
a.walls[2] = false
|
||||||
|
b.walls[0] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() {
|
||||||
|
// unsiged integers, because easier parsing error checks.
|
||||||
|
// We must convert these to intergers, as done below...
|
||||||
|
uScreenWidth, uScreenHeight, uWallSize := parseArgs()
|
||||||
|
|
||||||
|
var (
|
||||||
|
// In pixels
|
||||||
|
// Defualt is 800x800x40 = 20x20 wallgrid
|
||||||
|
screenWidth = int(uScreenWidth)
|
||||||
|
screenHeight = int(uScreenHeight)
|
||||||
|
wallSize = int(uWallSize)
|
||||||
|
|
||||||
|
frames = 0
|
||||||
|
second = time.Tick(time.Second)
|
||||||
|
|
||||||
|
grid = []*cell{}
|
||||||
|
cols = screenWidth / wallSize
|
||||||
|
rows = screenHeight / wallSize
|
||||||
|
currentCell = new(cell)
|
||||||
|
backTrackStack = stack.NewStack(1)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set game FPS manually
|
||||||
|
fps := time.Tick(time.Second / 60)
|
||||||
|
|
||||||
|
cfg := pixelgl.WindowConfig{
|
||||||
|
Title: "Pixel Rocks! - Maze example",
|
||||||
|
Bounds: pixel.R(0, 0, float64(screenHeight), float64(screenWidth)),
|
||||||
|
}
|
||||||
|
|
||||||
|
win, err := pixelgl.NewWindow(cfg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
grid, backTrackStack, currentCell = setupMaze(cols, rows)
|
||||||
|
|
||||||
|
gridIMDraw := imdraw.New(nil)
|
||||||
|
|
||||||
|
for !win.Closed() {
|
||||||
|
if win.JustReleased(pixelgl.KeyR) {
|
||||||
|
fmt.Println("R pressed")
|
||||||
|
grid, backTrackStack, currentCell = setupMaze(cols, rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
win.Clear(colornames.Gray)
|
||||||
|
gridIMDraw.Clear()
|
||||||
|
|
||||||
|
for i := range grid {
|
||||||
|
grid[i].Draw(gridIMDraw, wallSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 1
|
||||||
|
// Make the initial cell the current cell and mark it as visited
|
||||||
|
currentCell.visited = true
|
||||||
|
currentCell.hightlight(gridIMDraw, wallSize)
|
||||||
|
|
||||||
|
// step 2.1
|
||||||
|
// If the current cell has any neighbours which have not been visited
|
||||||
|
// Choose a random unvisited cell
|
||||||
|
nextCell, _ := currentCell.GetRandomNeighbor(grid, cols, rows)
|
||||||
|
if nextCell != nil && !nextCell.visited {
|
||||||
|
// step 2.2
|
||||||
|
// Push the current cell to the stack
|
||||||
|
backTrackStack.Push(currentCell)
|
||||||
|
|
||||||
|
// step 2.3
|
||||||
|
// Remove the wall between the current cell and the chosen cell
|
||||||
|
|
||||||
|
removeWalls(currentCell, nextCell)
|
||||||
|
|
||||||
|
// step 2.4
|
||||||
|
// Make the chosen cell the current cell and mark it as visited
|
||||||
|
nextCell.visited = true
|
||||||
|
currentCell = nextCell
|
||||||
|
} else if backTrackStack.Len() > 0 {
|
||||||
|
currentCell = backTrackStack.Pop().(*cell)
|
||||||
|
}
|
||||||
|
|
||||||
|
gridIMDraw.Draw(win)
|
||||||
|
win.Update()
|
||||||
|
<-fps
|
||||||
|
updateFPSDisplay(win, &cfg, &frames, grid, second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses the maze arguments, all of them are optional.
|
||||||
|
// Uses uint as implicit error checking :)
|
||||||
|
func parseArgs() (uint, uint, uint) {
|
||||||
|
var mazeWidthPtr = flag.Uint("w", 800, "w sets the maze's width in pixels.")
|
||||||
|
var mazeHeightPtr = flag.Uint("h", 800, "h sets the maze's height in pixels.")
|
||||||
|
var wallSizePtr = flag.Uint("c", 40, "c sets the maze cell's size in pixels.")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// If these aren't default values AND if they're not the same values.
|
||||||
|
// We should warn the user that the maze will look funny.
|
||||||
|
if *mazeWidthPtr != 800 || *mazeHeightPtr != 800 {
|
||||||
|
if *mazeWidthPtr != *mazeHeightPtr {
|
||||||
|
fmt.Printf("WARNING: maze width: %d and maze height: %d don't match. \n", *mazeWidthPtr, *mazeHeightPtr)
|
||||||
|
fmt.Println("Maze will look funny because the maze size is bond to the window size!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *mazeWidthPtr, *mazeHeightPtr, *wallSizePtr
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateFPSDisplay(win *pixelgl.Window, cfg *pixelgl.WindowConfig, frames *int, grid []*cell, second <-chan time.Time) {
|
||||||
|
*frames++
|
||||||
|
select {
|
||||||
|
case <-second:
|
||||||
|
win.SetTitle(fmt.Sprintf("%s | FPS: %d with %d Cells", cfg.Title, *frames, len(grid)))
|
||||||
|
*frames = 0
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if debug {
|
||||||
|
defer profile.Start().Stop()
|
||||||
|
}
|
||||||
|
pixelgl.Run(run)
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,86 @@
|
||||||
|
package stack
|
||||||
|
|
||||||
|
type Stack struct {
|
||||||
|
top *Element
|
||||||
|
size int
|
||||||
|
max int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Element struct {
|
||||||
|
value interface{}
|
||||||
|
next *Element
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStack(max int) *Stack {
|
||||||
|
return &Stack{max: max}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the stack's length
|
||||||
|
func (s *Stack) Len() int {
|
||||||
|
return s.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the stack's max
|
||||||
|
func (s *Stack) Max() int {
|
||||||
|
return s.max
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push a new element onto the stack
|
||||||
|
func (s *Stack) Push(value interface{}) {
|
||||||
|
if s.size+1 > s.max {
|
||||||
|
if last := s.PopLast(); last == nil {
|
||||||
|
panic("Unexpected nil in stack")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.top = &Element{value, s.top}
|
||||||
|
s.size++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the top element from the stack and return it's value
|
||||||
|
// If the stack is empty, return nil
|
||||||
|
func (s *Stack) Pop() (value interface{}) {
|
||||||
|
if s.size > 0 {
|
||||||
|
value, s.top = s.top.value, s.top.next
|
||||||
|
s.size--
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stack) PopLast() (value interface{}) {
|
||||||
|
if lastElem := s.popLast(s.top); lastElem != nil {
|
||||||
|
return lastElem.value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Peek returns a top without removing it from list
|
||||||
|
func (s *Stack) Peek() (value interface{}, exists bool) {
|
||||||
|
exists = false
|
||||||
|
if s.size > 0 {
|
||||||
|
value = s.top.value
|
||||||
|
exists = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stack) popLast(elem *Element) *Element {
|
||||||
|
if elem == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// not last because it has next and a grandchild
|
||||||
|
if elem.next != nil && elem.next.next != nil {
|
||||||
|
return s.popLast(elem.next)
|
||||||
|
}
|
||||||
|
|
||||||
|
// current elem is second from bottom, as next elem has no child
|
||||||
|
if elem.next != nil && elem.next.next == nil {
|
||||||
|
last := elem.next
|
||||||
|
// make current elem bottom of stack by removing its next element
|
||||||
|
elem.next = nil
|
||||||
|
s.size--
|
||||||
|
return last
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,78 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/faiface/pixel"
|
||||||
|
"github.com/faiface/pixel/pixelgl"
|
||||||
|
"github.com/faiface/pixel/text"
|
||||||
|
"github.com/golang/freetype/truetype"
|
||||||
|
"golang.org/x/image/colornames"
|
||||||
|
"golang.org/x/image/font"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadTTF(path string, size float64) (font.Face, error) {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
bytes, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
font, err := truetype.Parse(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return truetype.NewFace(font, &truetype.Options{
|
||||||
|
Size: size,
|
||||||
|
GlyphCacheEntries: 1,
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() {
|
||||||
|
cfg := pixelgl.WindowConfig{
|
||||||
|
Title: "Pixel Rocks!",
|
||||||
|
Bounds: pixel.R(0, 0, 1024, 768),
|
||||||
|
}
|
||||||
|
win, err := pixelgl.NewWindow(cfg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
win.SetSmooth(true)
|
||||||
|
|
||||||
|
face, err := loadTTF("intuitive.ttf", 80)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
atlas := text.NewAtlas(face, text.ASCII)
|
||||||
|
txt := text.New(pixel.V(50, 500), atlas)
|
||||||
|
|
||||||
|
txt.Color = colornames.Lightgrey
|
||||||
|
|
||||||
|
fps := time.Tick(time.Second / 120)
|
||||||
|
|
||||||
|
for !win.Closed() {
|
||||||
|
txt.WriteString(win.Typed())
|
||||||
|
if win.JustPressed(pixelgl.KeyEnter) || win.Repeated(pixelgl.KeyEnter) {
|
||||||
|
txt.WriteRune('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
win.Clear(colornames.Darkcyan)
|
||||||
|
txt.Draw(win, pixel.IM.Moved(win.Bounds().Center().Sub(txt.Bounds().Center())))
|
||||||
|
win.Update()
|
||||||
|
|
||||||
|
<-fps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pixelgl.Run(run)
|
||||||
|
}
|
|
@ -227,10 +227,7 @@ func (dl *dotlight) Draw(t pixel.Target, m pixel.Matrix) {
|
||||||
dl.imd.Color = pixel.Alpha(0)
|
dl.imd.Color = pixel.Alpha(0)
|
||||||
for i := 0.0; i <= 32; i++ {
|
for i := 0.0; i <= 32; i++ {
|
||||||
angle := i * 2 * math.Pi / 32
|
angle := i * 2 * math.Pi / 32
|
||||||
dl.imd.Push(dl.pos.Add(pixel.V(
|
dl.imd.Push(dl.pos.Add(pixel.V(dl.radius, 0).Rotated(angle)))
|
||||||
math.Cos(angle)*dl.radius,
|
|
||||||
math.Sin(angle)*dl.radius,
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
dl.imd.Polygon(0)
|
dl.imd.Polygon(0)
|
||||||
dl.imd.Draw(t)
|
dl.imd.Draw(t)
|
||||||
|
|
73
geometry.go
73
geometry.go
|
@ -3,8 +3,6 @@ package pixel
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/go-gl/mathgl/mgl64"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Vec is a 2D vector type with X and Y coordinates.
|
// Vec is a 2D vector type with X and Y coordinates.
|
||||||
|
@ -251,7 +249,7 @@ func (r Rect) Union(s Rect) Rect {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matrix is a 3x3 transformation matrix that can be used for all kinds of spacial transforms, such
|
// Matrix is a 3x2 affine matrix that can be used for all kinds of spatial transforms, such
|
||||||
// as movement, scaling and rotations.
|
// as movement, scaling and rotations.
|
||||||
//
|
//
|
||||||
// Matrix has a handful of useful methods, each of which adds a transformation to the matrix. For
|
// Matrix has a handful of useful methods, each of which adds a transformation to the matrix. For
|
||||||
|
@ -261,38 +259,41 @@ func (r Rect) Union(s Rect) Rect {
|
||||||
//
|
//
|
||||||
// This code creates a Matrix that first moves everything by 100 units horizontally and 200 units
|
// This code creates a Matrix that first moves everything by 100 units horizontally and 200 units
|
||||||
// vertically and then rotates everything by 90 degrees around the origin.
|
// vertically and then rotates everything by 90 degrees around the origin.
|
||||||
type Matrix [9]float64
|
//
|
||||||
|
// Layout is:
|
||||||
|
// [0] [2] [4]
|
||||||
|
// [1] [3] [5]
|
||||||
|
// 0 0 1 (implicit row)
|
||||||
|
type Matrix [6]float64
|
||||||
|
|
||||||
// IM stands for identity matrix. Does nothing, no transformation.
|
// IM stands for identity matrix. Does nothing, no transformation.
|
||||||
var IM = Matrix(mgl64.Ident3())
|
var IM = Matrix{1, 0, 0, 1, 0, 0}
|
||||||
|
|
||||||
// String returns a string representation of the Matrix.
|
// String returns a string representation of the Matrix.
|
||||||
//
|
//
|
||||||
// m := pixel.IM
|
// m := pixel.IM
|
||||||
// fmt.Println(m) // Matrix(1 0 0 | 0 1 0 | 0 0 1)
|
// fmt.Println(m) // Matrix(1 0 0 | 0 1 0)
|
||||||
func (m Matrix) String() string {
|
func (m Matrix) String() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"Matrix(%v %v %v | %v %v %v | %v %v %v)",
|
"Matrix(%v %v %v | %v %v %v)",
|
||||||
m[0], m[3], m[6],
|
m[0], m[2], m[4],
|
||||||
m[1], m[4], m[7],
|
m[1], m[3], m[5],
|
||||||
m[2], m[5], m[8],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Moved moves everything by the delta vector.
|
// Moved moves everything by the delta vector.
|
||||||
func (m Matrix) Moved(delta Vec) Matrix {
|
func (m Matrix) Moved(delta Vec) Matrix {
|
||||||
m3 := mgl64.Mat3(m)
|
m[4], m[5] = m[4]+delta.X, m[5]+delta.Y
|
||||||
m3 = mgl64.Translate2D(delta.XY()).Mul3(m3)
|
return m
|
||||||
return Matrix(m3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScaledXY scales everything around a given point by the scale factor in each axis respectively.
|
// ScaledXY scales everything around a given point by the scale factor in each axis respectively.
|
||||||
func (m Matrix) ScaledXY(around Vec, scale Vec) Matrix {
|
func (m Matrix) ScaledXY(around Vec, scale Vec) Matrix {
|
||||||
m3 := mgl64.Mat3(m)
|
m[4], m[5] = m[4]-around.X, m[5]-around.Y
|
||||||
m3 = mgl64.Translate2D(around.Scaled(-1).XY()).Mul3(m3)
|
m[0], m[2], m[4] = m[0]*scale.X, m[2]*scale.X, m[4]*scale.X
|
||||||
m3 = mgl64.Scale2D(scale.XY()).Mul3(m3)
|
m[1], m[3], m[5] = m[1]*scale.Y, m[3]*scale.Y, m[5]*scale.Y
|
||||||
m3 = mgl64.Translate2D(around.XY()).Mul3(m3)
|
m[4], m[5] = m[4]+around.X, m[5]+around.Y
|
||||||
return Matrix(m3)
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scaled scales everything around a given point by the scale factor.
|
// Scaled scales everything around a given point by the scale factor.
|
||||||
|
@ -302,36 +303,42 @@ func (m Matrix) Scaled(around Vec, scale float64) Matrix {
|
||||||
|
|
||||||
// Rotated rotates everything around a given point by the given angle in radians.
|
// Rotated rotates everything around a given point by the given angle in radians.
|
||||||
func (m Matrix) Rotated(around Vec, angle float64) Matrix {
|
func (m Matrix) Rotated(around Vec, angle float64) Matrix {
|
||||||
m3 := mgl64.Mat3(m)
|
sint, cost := math.Sincos(angle)
|
||||||
m3 = mgl64.Translate2D(around.Scaled(-1).XY()).Mul3(m3)
|
m[4], m[5] = m[4]-around.X, m[5]-around.Y
|
||||||
m3 = mgl64.Rotate3DZ(angle).Mul3(m3)
|
m = m.Chained(Matrix{cost, sint, -sint, cost, 0, 0})
|
||||||
m3 = mgl64.Translate2D(around.XY()).Mul3(m3)
|
m[4], m[5] = m[4]+around.X, m[5]+around.Y
|
||||||
return Matrix(m3)
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chained adds another Matrix to this one. All tranformations by the next Matrix will be applied
|
// Chained adds another Matrix to this one. All tranformations by the next Matrix will be applied
|
||||||
// after the transformations of this Matrix.
|
// after the transformations of this Matrix.
|
||||||
func (m Matrix) Chained(next Matrix) Matrix {
|
func (m Matrix) Chained(next Matrix) Matrix {
|
||||||
m3 := mgl64.Mat3(m)
|
return Matrix{
|
||||||
m3 = mgl64.Mat3(next).Mul3(m3)
|
m[0]*next[0] + m[2]*next[1],
|
||||||
return Matrix(m3)
|
m[1]*next[0] + m[3]*next[1],
|
||||||
|
m[0]*next[2] + m[2]*next[3],
|
||||||
|
m[1]*next[2] + m[3]*next[3],
|
||||||
|
m[0]*next[4] + m[2]*next[5] + m[4],
|
||||||
|
m[1]*next[4] + m[3]*next[5] + m[5],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Project applies all transformations added to the Matrix to a vector u and returns the result.
|
// Project applies all transformations added to the Matrix to a vector u and returns the result.
|
||||||
//
|
//
|
||||||
// Time complexity is O(1).
|
// Time complexity is O(1).
|
||||||
func (m Matrix) Project(u Vec) Vec {
|
func (m Matrix) Project(u Vec) Vec {
|
||||||
m3 := mgl64.Mat3(m)
|
return Vec{X: m[0]*u.X + m[2]*u.Y + m[4], Y: m[1]*u.X + m[3]*u.Y + m[5]}
|
||||||
proj := m3.Mul3x1(mgl64.Vec3{u.X, u.Y, 1})
|
|
||||||
return V(proj.X(), proj.Y())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unproject does the inverse operation to Project.
|
// Unproject does the inverse operation to Project.
|
||||||
//
|
//
|
||||||
|
// It turns out that multiplying a vector by the inverse matrix of m can be nearly-accomplished by
|
||||||
|
// subtracting the translate part of the matrix and multplying by the inverse of the top-left 2x2
|
||||||
|
// matrix, and the inverse of a 2x2 matrix is simple enough to just be inlined in the computation.
|
||||||
|
//
|
||||||
// Time complexity is O(1).
|
// Time complexity is O(1).
|
||||||
func (m Matrix) Unproject(u Vec) Vec {
|
func (m Matrix) Unproject(u Vec) Vec {
|
||||||
m3 := mgl64.Mat3(m)
|
d := (m[0] * m[3]) - (m[1] * m[2])
|
||||||
inv := m3.Inv()
|
u.X, u.Y = (u.X-m[4])/d, (u.Y-m[5])/d
|
||||||
unproj := inv.Mul3x1(mgl64.Vec3{u.X, u.Y, 1})
|
return Vec{u.X*m[3] - u.Y*m[1], u.Y*m[0] - u.X*m[2]}
|
||||||
return V(unproj.X(), unproj.Y())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ type IMDraw struct {
|
||||||
EndShape EndShape
|
EndShape EndShape
|
||||||
|
|
||||||
points []point
|
points []point
|
||||||
|
pool [][]point
|
||||||
matrix pixel.Matrix
|
matrix pixel.Matrix
|
||||||
mask pixel.RGBA
|
mask pixel.RGBA
|
||||||
|
|
||||||
|
@ -109,7 +110,7 @@ func (imd *IMDraw) Clear() {
|
||||||
//
|
//
|
||||||
// This does not affect matrix and color mask set by SetMatrix and SetColorMask.
|
// This does not affect matrix and color mask set by SetMatrix and SetColorMask.
|
||||||
func (imd *IMDraw) Reset() {
|
func (imd *IMDraw) Reset() {
|
||||||
imd.points = nil
|
imd.points = imd.points[:0]
|
||||||
imd.Color = pixel.Alpha(1)
|
imd.Color = pixel.Alpha(1)
|
||||||
imd.Picture = pixel.ZV
|
imd.Picture = pixel.ZV
|
||||||
imd.Intensity = 0
|
imd.Intensity = 0
|
||||||
|
@ -256,10 +257,22 @@ func (imd *IMDraw) EllipseArc(radius pixel.Vec, low, high, thickness float64) {
|
||||||
|
|
||||||
func (imd *IMDraw) getAndClearPoints() []point {
|
func (imd *IMDraw) getAndClearPoints() []point {
|
||||||
points := imd.points
|
points := imd.points
|
||||||
|
// use one of the existing pools so we don't reallocate as often
|
||||||
|
if len(imd.pool) > 0 {
|
||||||
|
pos := len(imd.pool) - 1
|
||||||
|
imd.points = imd.pool[pos][:0]
|
||||||
|
imd.pool = imd.pool[:pos]
|
||||||
|
} else {
|
||||||
imd.points = nil
|
imd.points = nil
|
||||||
|
}
|
||||||
return points
|
return points
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (imd *IMDraw) restorePoints(points []point) {
|
||||||
|
imd.pool = append(imd.pool, imd.points)
|
||||||
|
imd.points = points[:0]
|
||||||
|
}
|
||||||
|
|
||||||
func (imd *IMDraw) applyMatrixAndMask(off int) {
|
func (imd *IMDraw) applyMatrixAndMask(off int) {
|
||||||
for i := range (*imd.tri)[off:] {
|
for i := range (*imd.tri)[off:] {
|
||||||
(*imd.tri)[off+i].Position = imd.matrix.Project((*imd.tri)[off+i].Position)
|
(*imd.tri)[off+i].Position = imd.matrix.Project((*imd.tri)[off+i].Position)
|
||||||
|
@ -271,6 +284,7 @@ func (imd *IMDraw) fillRectangle() {
|
||||||
points := imd.getAndClearPoints()
|
points := imd.getAndClearPoints()
|
||||||
|
|
||||||
if len(points) < 2 {
|
if len(points) < 2 {
|
||||||
|
imd.restorePoints(points)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +306,7 @@ func (imd *IMDraw) fillRectangle() {
|
||||||
in: (a.in + b.in) / 2,
|
in: (a.in + b.in) / 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, p := range []point{a, b, c, a, b, d} {
|
for k, p := range [...]point{a, b, c, a, b, d} {
|
||||||
(*imd.tri)[j+k].Position = p.pos
|
(*imd.tri)[j+k].Position = p.pos
|
||||||
(*imd.tri)[j+k].Color = p.col
|
(*imd.tri)[j+k].Color = p.col
|
||||||
(*imd.tri)[j+k].Picture = p.pic
|
(*imd.tri)[j+k].Picture = p.pic
|
||||||
|
@ -302,12 +316,15 @@ func (imd *IMDraw) fillRectangle() {
|
||||||
|
|
||||||
imd.applyMatrixAndMask(off)
|
imd.applyMatrixAndMask(off)
|
||||||
imd.batch.Dirty()
|
imd.batch.Dirty()
|
||||||
|
|
||||||
|
imd.restorePoints(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imd *IMDraw) outlineRectangle(thickness float64) {
|
func (imd *IMDraw) outlineRectangle(thickness float64) {
|
||||||
points := imd.getAndClearPoints()
|
points := imd.getAndClearPoints()
|
||||||
|
|
||||||
if len(points) < 2 {
|
if len(points) < 2 {
|
||||||
|
imd.restorePoints(points)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,12 +340,15 @@ func (imd *IMDraw) outlineRectangle(thickness float64) {
|
||||||
imd.pushPt(pixel.V(b.pos.X, a.pos.Y), mid)
|
imd.pushPt(pixel.V(b.pos.X, a.pos.Y), mid)
|
||||||
imd.polyline(thickness, true)
|
imd.polyline(thickness, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imd.restorePoints(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imd *IMDraw) fillPolygon() {
|
func (imd *IMDraw) fillPolygon() {
|
||||||
points := imd.getAndClearPoints()
|
points := imd.getAndClearPoints()
|
||||||
|
|
||||||
if len(points) < 3 {
|
if len(points) < 3 {
|
||||||
|
imd.restorePoints(points)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,16 +356,19 @@ func (imd *IMDraw) fillPolygon() {
|
||||||
imd.tri.SetLen(imd.tri.Len() + 3*(len(points)-2))
|
imd.tri.SetLen(imd.tri.Len() + 3*(len(points)-2))
|
||||||
|
|
||||||
for i, j := 1, off; i+1 < len(points); i, j = i+1, j+3 {
|
for i, j := 1, off; i+1 < len(points); i, j = i+1, j+3 {
|
||||||
for k, p := range []point{points[0], points[i], points[i+1]} {
|
for k, p := range [...]int{0, i, i + 1} {
|
||||||
(*imd.tri)[j+k].Position = p.pos
|
tri := &(*imd.tri)[j+k]
|
||||||
(*imd.tri)[j+k].Color = p.col
|
tri.Position = points[p].pos
|
||||||
(*imd.tri)[j+k].Picture = p.pic
|
tri.Color = points[p].col
|
||||||
(*imd.tri)[j+k].Intensity = p.in
|
tri.Picture = points[p].pic
|
||||||
|
tri.Intensity = points[p].in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imd.applyMatrixAndMask(off)
|
imd.applyMatrixAndMask(off)
|
||||||
imd.batch.Dirty()
|
imd.batch.Dirty()
|
||||||
|
|
||||||
|
imd.restorePoints(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imd *IMDraw) fillEllipseArc(radius pixel.Vec, low, high float64) {
|
func (imd *IMDraw) fillEllipseArc(radius pixel.Vec, low, high float64) {
|
||||||
|
@ -387,6 +410,8 @@ func (imd *IMDraw) fillEllipseArc(radius pixel.Vec, low, high float64) {
|
||||||
imd.applyMatrixAndMask(off)
|
imd.applyMatrixAndMask(off)
|
||||||
imd.batch.Dirty()
|
imd.batch.Dirty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imd.restorePoints(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness float64, doEndShape bool) {
|
func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness float64, doEndShape bool) {
|
||||||
|
@ -485,12 +510,15 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imd.restorePoints(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
points := imd.getAndClearPoints()
|
points := imd.getAndClearPoints()
|
||||||
|
|
||||||
if len(points) == 0 {
|
if len(points) == 0 {
|
||||||
|
imd.restorePoints(points)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(points) == 1 {
|
if len(points) == 1 {
|
||||||
|
@ -521,6 +549,8 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
imd.pushPt(points[j].pos.Sub(normal), points[j])
|
imd.pushPt(points[j].pos.Sub(normal), points[j])
|
||||||
|
|
||||||
// middle points
|
// middle points
|
||||||
|
// compute "previous" normal:
|
||||||
|
ijNormal := points[1].pos.Sub(points[0].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
|
||||||
for i := 0; i < len(points); i++ {
|
for i := 0; i < len(points); i++ {
|
||||||
j, k := i+1, i+2
|
j, k := i+1, i+2
|
||||||
|
|
||||||
|
@ -536,7 +566,6 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
k %= len(points)
|
k %= len(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
ijNormal := points[j].pos.Sub(points[i].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
|
|
||||||
jkNormal := points[k].pos.Sub(points[j].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
|
jkNormal := points[k].pos.Sub(points[j].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
|
||||||
|
|
||||||
orientation := 1.0
|
orientation := 1.0
|
||||||
|
@ -567,6 +596,8 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
imd.pushPt(points[j].pos.Add(jkNormal), points[j])
|
imd.pushPt(points[j].pos.Add(jkNormal), points[j])
|
||||||
imd.pushPt(points[j].pos.Sub(jkNormal), points[j])
|
imd.pushPt(points[j].pos.Sub(jkNormal), points[j])
|
||||||
}
|
}
|
||||||
|
// "next" normal becomes previous normal
|
||||||
|
ijNormal = jkNormal
|
||||||
}
|
}
|
||||||
|
|
||||||
// last point
|
// last point
|
||||||
|
@ -591,4 +622,6 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), normal.Angle(), normal.Angle()-math.Pi)
|
imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), normal.Angle(), normal.Angle()-math.Pi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imd.restorePoints(points)
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,8 +91,13 @@ func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
|
||||||
|
|
||||||
// SetMatrix sets a Matrix that every point will be projected by.
|
// SetMatrix sets a Matrix that every point will be projected by.
|
||||||
func (c *Canvas) SetMatrix(m pixel.Matrix) {
|
func (c *Canvas) SetMatrix(m pixel.Matrix) {
|
||||||
for i := range m {
|
// pixel.Matrix is 3x2 with an implicit 0, 0, 1 row after it. So
|
||||||
c.mat[i] = float32(m[i])
|
// [0] [2] [4] [0] [3] [6]
|
||||||
|
// [1] [3] [5] => [1] [4] [7]
|
||||||
|
// 0 0 1 0 0 1
|
||||||
|
// since all matrix ops are affine, the last row never changes, and we don't need to copy it
|
||||||
|
for i, j := range [...]int{0, 1, 3, 4, 6, 7} {
|
||||||
|
c.mat[j] = float32(m[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +223,11 @@ func (c *Canvas) Texture() *glhf.Texture {
|
||||||
return c.gf.Texture()
|
return c.gf.Texture()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frame returns the underlying OpenGL Frame of this Canvas.
|
||||||
|
func (c *Canvas) Frame() *glhf.Frame {
|
||||||
|
return c.gf.frame
|
||||||
|
}
|
||||||
|
|
||||||
// SetPixels replaces the content of the Canvas with the provided pixels. The provided slice must be
|
// SetPixels replaces the content of the Canvas with the provided pixels. The provided slice must be
|
||||||
// an alpha-premultiplied RGBA sequence of correct length (4 * width * height).
|
// an alpha-premultiplied RGBA sequence of correct length (4 * width * height).
|
||||||
func (c *Canvas) SetPixels(pixels []uint8) {
|
func (c *Canvas) SetPixels(pixels []uint8) {
|
||||||
|
|
|
@ -103,15 +103,17 @@ func (gt *GLTriangles) updateData(t pixel.Triangles) {
|
||||||
tx, ty = (*t)[i].Picture.XY()
|
tx, ty = (*t)[i].Picture.XY()
|
||||||
in = (*t)[i].Intensity
|
in = (*t)[i].Intensity
|
||||||
)
|
)
|
||||||
gt.data[i*gt.vs.Stride()+0] = float32(px)
|
s := gt.vs.Stride()
|
||||||
gt.data[i*gt.vs.Stride()+1] = float32(py)
|
d := gt.data[i*s : i*s+9]
|
||||||
gt.data[i*gt.vs.Stride()+2] = float32(col.R)
|
d[0] = float32(px)
|
||||||
gt.data[i*gt.vs.Stride()+3] = float32(col.G)
|
d[1] = float32(py)
|
||||||
gt.data[i*gt.vs.Stride()+4] = float32(col.B)
|
d[2] = float32(col.R)
|
||||||
gt.data[i*gt.vs.Stride()+5] = float32(col.A)
|
d[3] = float32(col.G)
|
||||||
gt.data[i*gt.vs.Stride()+6] = float32(tx)
|
d[4] = float32(col.B)
|
||||||
gt.data[i*gt.vs.Stride()+7] = float32(ty)
|
d[5] = float32(col.A)
|
||||||
gt.data[i*gt.vs.Stride()+8] = float32(in)
|
d[6] = float32(tx)
|
||||||
|
d[7] = float32(ty)
|
||||||
|
d[8] = float32(in)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue