initial commit
This commit is contained in:
parent
4b293cd424
commit
1e2c2fe662
|
@ -0,0 +1,2 @@
|
||||||
|
.fleet
|
||||||
|
.idea
|
|
@ -0,0 +1,5 @@
|
||||||
|
set CGO_ENABLED=1
|
||||||
|
set CC=x86_64-w64-mingw32-gcc
|
||||||
|
set GOOS=windows
|
||||||
|
set GOARCH=amd64
|
||||||
|
go build -tags static -ldflags "-s -w"
|
|
@ -0,0 +1,4 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
const White = 0xffffffff
|
||||||
|
const Black = 0xff000000
|
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,32 @@
|
||||||
|
package bloob
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
type ch struct {
|
||||||
|
xForward int
|
||||||
|
image *Image
|
||||||
|
}
|
||||||
|
|
||||||
|
type Font struct {
|
||||||
|
chars []ch
|
||||||
|
lineHeight int
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:embed "font.png"
|
||||||
|
var fontdata []byte
|
||||||
|
var DefaultFont = LoadTilesetFontBytes(fontdata, Vec2i{X: 8, Y: 14})
|
||||||
|
|
||||||
|
//go:embed "font-thin.png"
|
||||||
|
var fontdataThin []byte
|
||||||
|
var DefaultFontThin = LoadTilesetFontBytes(fontdataThin, Vec2i{X: 6, Y: 8})
|
||||||
|
|
||||||
|
func LoadTilesetFontBytes(data []byte, tilesize Vec2i) *Font {
|
||||||
|
tiles := LoadImageBytes(data).MakeTileset(tilesize)
|
||||||
|
var font Font
|
||||||
|
for i := 0; i < len(tiles); i += 1 {
|
||||||
|
c := ch{xForward: tilesize.X, image: tiles[i]}
|
||||||
|
font.chars = append(font.chars, c)
|
||||||
|
}
|
||||||
|
font.lineHeight = tilesize.Y + 2
|
||||||
|
return &font
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,9 @@
|
||||||
|
module git.danitheskunk.com/squishy/blooblib
|
||||||
|
|
||||||
|
go 1.22.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/askeladdk/aseprite v0.0.4
|
||||||
|
github.com/veandco/go-sdl2 v0.4.38
|
||||||
|
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
github.com/askeladdk/aseprite v0.0.4 h1:/k1VTiDkPORnrzonUUV5oXWwdHBoYjIIYJ1K/PupNMU=
|
||||||
|
github.com/askeladdk/aseprite v0.0.4/go.mod h1:lVW4EwZ7lgQjeHp7MhYj1NII5a/yLYyvAo7COPIn3WY=
|
||||||
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/veandco/go-sdl2 v0.4.38 h1:lx8syOA2ccXlgViYkQe2Kn/4xt+p9mdd1Qc/yYMrmSo=
|
||||||
|
github.com/veandco/go-sdl2 v0.4.38/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
||||||
|
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc=
|
||||||
|
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
|
||||||
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
|
@ -0,0 +1,356 @@
|
||||||
|
package bloob
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
_ "github.com/askeladdk/aseprite"
|
||||||
|
"image"
|
||||||
|
_ "image/png"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"runtime/pprof"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
Data []uint32
|
||||||
|
Size Vec2i
|
||||||
|
Alpha bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var threadProfile = pprof.Lookup("threadcreate")
|
||||||
|
|
||||||
|
func NewImage(size Vec2i) *Image {
|
||||||
|
return &Image{Data: make([]uint32, size.Size()), Size: Vec2i{X: size.X, Y: size.Y}, Alpha: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewImageFromPointer(pointer unsafe.Pointer, size Vec2i) *Image {
|
||||||
|
return &Image{Data: unsafe.Slice((*uint32)(pointer), size.Size()), Size: Vec2i{X: size.X, Y: size.Y}, Alpha: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadImage(path string) *Image {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return LoadImageBytes(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadImageBytes(data []byte) *Image {
|
||||||
|
file, _, _ := image.Decode(bytes.NewReader(data))
|
||||||
|
|
||||||
|
width := file.Bounds().Max.X
|
||||||
|
height := file.Bounds().Max.Y
|
||||||
|
img := NewImage(Vec2i{X: width, Y: height})
|
||||||
|
for y := 0; y < height; y += 1 {
|
||||||
|
for x := 0; x < width; x += 1 {
|
||||||
|
r, g, b, a := file.At(x, y).RGBA()
|
||||||
|
r = r >> 8
|
||||||
|
g = g >> 8
|
||||||
|
b = b >> 8
|
||||||
|
a = a >> 8
|
||||||
|
img.Data[x+y*width] = r<<16 | g<<8 | b | a<<24
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) Clear(color uint32) {
|
||||||
|
for i := 0; i < image.Size.X*image.Size.Y; i += 1 {
|
||||||
|
image.Data[i] = color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CropToArea(sizeDst Vec2i, rectSrc Recti, posDst Vec2i) (start, end, dst Vec2i) {
|
||||||
|
if posDst.X+rectSrc.Pos.X < 0 {
|
||||||
|
start.X = -posDst.X
|
||||||
|
} else {
|
||||||
|
start.X = rectSrc.Pos.X
|
||||||
|
}
|
||||||
|
if posDst.X+rectSrc.Size.X-rectSrc.Pos.X >= sizeDst.X {
|
||||||
|
end.X = sizeDst.X - posDst.X
|
||||||
|
} else {
|
||||||
|
end.X = rectSrc.Pos.X + rectSrc.Size.X
|
||||||
|
}
|
||||||
|
|
||||||
|
if posDst.Y+rectSrc.Pos.Y < 0 {
|
||||||
|
start.Y = -posDst.Y
|
||||||
|
} else {
|
||||||
|
start.Y = rectSrc.Pos.Y
|
||||||
|
}
|
||||||
|
if posDst.Y+rectSrc.Size.Y-rectSrc.Pos.Y >= sizeDst.Y {
|
||||||
|
end.Y = sizeDst.Y - posDst.Y
|
||||||
|
} else {
|
||||||
|
end.Y = rectSrc.Pos.Y + rectSrc.Size.Y
|
||||||
|
}
|
||||||
|
dst = Sub(posDst, rectSrc.Pos)
|
||||||
|
//println(dst.X, posDst.X, rectSrc.Pos.X)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) Draw(other *Image, dst Vec2i) {
|
||||||
|
image.DrawSub(other, dst, Recti{Size: other.Size})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawSub(other *Image, pos Vec2i, rect Recti) {
|
||||||
|
start, end, dst := CropToArea(image.Size, rect, pos)
|
||||||
|
//println(start.X, "|", end.X, "|", dst.X, "|", pos.X)
|
||||||
|
//println(end.Y)
|
||||||
|
if other.Alpha {
|
||||||
|
for y := start.Y; y < end.Y; y += 1 {
|
||||||
|
for x := start.X; x < end.X; x += 1 {
|
||||||
|
//println(y)
|
||||||
|
val := other.Data[x+y*other.Size.X]
|
||||||
|
if val&0xff000000 > 0 {
|
||||||
|
image.Data[(x+dst.X)+(y+dst.Y)*image.Size.X] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for y := start.Y; y < end.Y; y += 1 {
|
||||||
|
for x := start.X; x < end.X; x += 1 {
|
||||||
|
image.Data[(x+dst.X)+(y+dst.Y)*image.Size.X] = other.Data[x+y*other.Size.X]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawColor(other *Image, dst Vec2i, color uint32) {
|
||||||
|
image.DrawSubColor(other, dst, Recti{Size: other.Size}, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawSubColor(other *Image, pos Vec2i, rect Recti, color uint32) {
|
||||||
|
start, end, dst := CropToArea(image.Size, rect, pos)
|
||||||
|
for y := start.Y; y < end.Y; y += 1 {
|
||||||
|
for x := start.X; x < end.X; x += 1 {
|
||||||
|
//println(y)
|
||||||
|
val := other.Data[x+y*other.Size.X]
|
||||||
|
if val&0xff000000 > 0 {
|
||||||
|
image.Data[(x+dst.X)+(y+dst.Y)*image.Size.X] = color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawUpscale(other *Image) {
|
||||||
|
var scale int
|
||||||
|
if image.Size.X/other.Size.X < image.Size.Y/other.Size.Y {
|
||||||
|
scale = image.Size.X / other.Size.X
|
||||||
|
} else {
|
||||||
|
scale = image.Size.Y / other.Size.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
switch scale {
|
||||||
|
case 1:
|
||||||
|
wg.Add(other.Size.Y)
|
||||||
|
for y := 0; y < other.Size.Y; y += 1 {
|
||||||
|
go func(image, other *Image, y int) {
|
||||||
|
defer wg.Done()
|
||||||
|
for x := 0; x < other.Size.X; x += 1 {
|
||||||
|
val := other.Data[x+y*other.Size.X]
|
||||||
|
image.Data[(x*scale)+(y*scale)*image.Size.X] = val
|
||||||
|
}
|
||||||
|
}(image, other, y)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
wg.Add(other.Size.Y)
|
||||||
|
for y := 0; y < other.Size.Y; y += 1 {
|
||||||
|
go func(image, other *Image, y int) {
|
||||||
|
defer wg.Done()
|
||||||
|
for x := 0; x < other.Size.X; x += 1 {
|
||||||
|
val := other.Data[x+y*other.Size.X]
|
||||||
|
val2 := (val & 0xfefefe) >> 1
|
||||||
|
dx := x * 2
|
||||||
|
dy := y * 2
|
||||||
|
image.Data[(dx+0)+(dy+0)*image.Size.X] = val
|
||||||
|
image.Data[(dx+1)+(dy+0)*image.Size.X] = val
|
||||||
|
image.Data[(dx+0)+(dy+1)*image.Size.X] = val2
|
||||||
|
image.Data[(dx+1)+(dy+1)*image.Size.X] = val2
|
||||||
|
}
|
||||||
|
}(image, other, y)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
wg.Add(other.Size.Y)
|
||||||
|
//println("Before thread count : ", threadProfile.Count())
|
||||||
|
for y := 0; y < other.Size.Y; y += 1 {
|
||||||
|
go func(image, other *Image, y int) {
|
||||||
|
defer wg.Done()
|
||||||
|
for x := 0; x < other.Size.X; x += 1 {
|
||||||
|
val := other.Data[x+y*other.Size.X]
|
||||||
|
val2 := (val & 0xfefefe) >> 1
|
||||||
|
dx := x * 3
|
||||||
|
dy := y * 3
|
||||||
|
image.Data[(dx+0)+(dy+0)*image.Size.X] = val
|
||||||
|
image.Data[(dx+1)+(dy+0)*image.Size.X] = val
|
||||||
|
image.Data[(dx+2)+(dy+0)*image.Size.X] = val2
|
||||||
|
image.Data[(dx+0)+(dy+1)*image.Size.X] = val
|
||||||
|
image.Data[(dx+1)+(dy+1)*image.Size.X] = val
|
||||||
|
image.Data[(dx+2)+(dy+1)*image.Size.X] = val2
|
||||||
|
image.Data[(dx+0)+(dy+2)*image.Size.X] = val2
|
||||||
|
image.Data[(dx+1)+(dy+2)*image.Size.X] = val2
|
||||||
|
image.Data[(dx+2)+(dy+2)*image.Size.X] = val2
|
||||||
|
}
|
||||||
|
}(image, other, y)
|
||||||
|
}
|
||||||
|
//println("After thread count : ", threadProfile.Count())
|
||||||
|
wg.Wait()
|
||||||
|
break
|
||||||
|
case 4:
|
||||||
|
wg.Add(other.Size.Y)
|
||||||
|
for y := 0; y < other.Size.Y; y += 1 {
|
||||||
|
go func(image, other *Image, y int) {
|
||||||
|
defer wg.Done()
|
||||||
|
for x := 0; x < other.Size.X; x += 1 {
|
||||||
|
val := other.Data[x+y*other.Size.X]
|
||||||
|
dx := x * 4
|
||||||
|
dy := y * 4
|
||||||
|
image.Data[(dx+0)+(dy+0)*image.Size.X] = val
|
||||||
|
image.Data[(dx+1)+(dy+0)*image.Size.X] = val
|
||||||
|
image.Data[(dx+2)+(dy+0)*image.Size.X] = val
|
||||||
|
image.Data[(dx+3)+(dy+0)*image.Size.X] = val
|
||||||
|
image.Data[(dx+0)+(dy+1)*image.Size.X] = val
|
||||||
|
image.Data[(dx+1)+(dy+1)*image.Size.X] = val
|
||||||
|
image.Data[(dx+2)+(dy+1)*image.Size.X] = val
|
||||||
|
image.Data[(dx+3)+(dy+1)*image.Size.X] = val
|
||||||
|
image.Data[(dx+0)+(dy+2)*image.Size.X] = val
|
||||||
|
image.Data[(dx+1)+(dy+2)*image.Size.X] = val
|
||||||
|
image.Data[(dx+2)+(dy+2)*image.Size.X] = val
|
||||||
|
image.Data[(dx+3)+(dy+2)*image.Size.X] = val
|
||||||
|
image.Data[(dx+0)+(dy+3)*image.Size.X] = val
|
||||||
|
image.Data[(dx+1)+(dy+3)*image.Size.X] = val
|
||||||
|
image.Data[(dx+2)+(dy+3)*image.Size.X] = val
|
||||||
|
image.Data[(dx+3)+(dy+3)*image.Size.X] = val
|
||||||
|
}
|
||||||
|
}(image, other, y)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
wg.Add(other.Size.Y)
|
||||||
|
for y := 0; y < other.Size.Y; y += 1 {
|
||||||
|
go func(image, other *Image, y int) {
|
||||||
|
defer wg.Done()
|
||||||
|
for x := 0; x < other.Size.X; x += 1 {
|
||||||
|
val := other.Data[x+y*other.Size.X]
|
||||||
|
for sy := 0; sy < scale; sy += 1 {
|
||||||
|
for sx := 0; sx < scale; sx += 1 {
|
||||||
|
image.Data[(x*scale+sx)+(y*scale+sy)*image.Size.X] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(image, other, y)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawText(str string, font *Font, pos Vec2i, color uint32) {
|
||||||
|
origX := pos.X
|
||||||
|
for _, ch := range str {
|
||||||
|
c := font.chars[ch]
|
||||||
|
if ch == 10 {
|
||||||
|
pos.X = origX
|
||||||
|
pos.Y += font.lineHeight
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
image.DrawColor(c.image, pos, color)
|
||||||
|
pos.X += c.xForward
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawTextSin(str string, font *Font, pos Vec2i, color uint32, freq, amplitude, phase float64) {
|
||||||
|
origX := pos.X
|
||||||
|
for _, ch := range str {
|
||||||
|
c := font.chars[ch]
|
||||||
|
if ch == 10 {
|
||||||
|
pos.X = origX
|
||||||
|
pos.Y += font.lineHeight
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
image.DrawColor(c.image, Vec2i{X: pos.X, Y: int(math.Sin(float64(pos.X)*math.Pi/4/freq+phase*math.Pi*2)*amplitude) + pos.Y}, color)
|
||||||
|
pos.X += c.xForward
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawTextOutline(str string, font *Font, pos Vec2i, color, outlineColor uint32) {
|
||||||
|
origX := pos.X
|
||||||
|
for _, ch := range str {
|
||||||
|
c := font.chars[ch]
|
||||||
|
if ch == 10 {
|
||||||
|
pos.X = origX
|
||||||
|
pos.Y += font.lineHeight
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
x := pos.X
|
||||||
|
y := pos.Y
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x - 1, Y: y}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x + 1, Y: y}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x, Y: y - 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x, Y: y + 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x - 1, Y: y - 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x + 1, Y: y + 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x + 1, Y: y - 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x - 1, Y: y + 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x, Y: y + 2}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x - 1, Y: y + 2}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x + 1, Y: y + 2}, outlineColor)
|
||||||
|
image.DrawColor(c.image, pos, color)
|
||||||
|
pos.X += c.xForward
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawTextOutlineSin(str string, font *Font, pos Vec2i, color, outlineColor uint32, freq, amplitude, phase float64) {
|
||||||
|
origX := pos.X
|
||||||
|
for _, ch := range str {
|
||||||
|
c := font.chars[ch]
|
||||||
|
if ch == 10 {
|
||||||
|
pos.X = origX
|
||||||
|
pos.Y += font.lineHeight
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
x := pos.X
|
||||||
|
y := int(math.Sin(float64(pos.X)*math.Pi/4/freq+phase*math.Pi*2)*amplitude) + pos.Y
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x - 1, Y: y}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x + 1, Y: y}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x, Y: y - 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x, Y: y + 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x - 1, Y: y - 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x + 1, Y: y + 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x + 1, Y: y - 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x - 1, Y: y + 1}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x, Y: y + 2}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x - 1, Y: y + 2}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x + 1, Y: y + 2}, outlineColor)
|
||||||
|
image.DrawColor(c.image, Vec2i{X: x, Y: y}, color)
|
||||||
|
pos.X += c.xForward
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) DrawTilemap(tilemap *Tilemap, pos Vec2i) {
|
||||||
|
tilesize := tilemap.Tileset[0].Size
|
||||||
|
for y := 0; y < tilemap.Size.Y; y += 1 {
|
||||||
|
for x := 0; x < tilemap.Size.X; x += 1 {
|
||||||
|
tpos := Vec2i{X: x, Y: y}
|
||||||
|
image.Draw(tilemap.Tileset[tilemap.Get(tpos)], Add(Mul(tpos, tilesize), pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (image *Image) MakeTileset(tileSize Vec2i) []*Image {
|
||||||
|
tileCount := Div(image.Size, tileSize)
|
||||||
|
var tiles []*Image
|
||||||
|
for y := 0; y < tileCount.Y; y += 1 {
|
||||||
|
for x := 0; x < tileCount.X; x += 1 {
|
||||||
|
tile := NewImage(tileSize)
|
||||||
|
tile.DrawSub(image, Vec2i{}, Recti{Pos: Vec2i{X: x * tileSize.X, Y: y * tileSize.Y}, Size: tileSize})
|
||||||
|
tiles = append(tiles, tile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tiles
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"git.danitheskunk.com/squishy/blooblib/color"
|
||||||
|
. "git.danitheskunk.com/squishy/blooblib/src"
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Width = 640
|
||||||
|
const Height = 360
|
||||||
|
|
||||||
|
//test
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_ = sdl.Init(sdl.INIT_EVERYTHING)
|
||||||
|
defer sdl.Quit()
|
||||||
|
|
||||||
|
scale := 3
|
||||||
|
|
||||||
|
window, _ := sdl.CreateWindow(
|
||||||
|
"test",
|
||||||
|
sdl.WINDOWPOS_CENTERED,
|
||||||
|
sdl.WINDOWPOS_CENTERED,
|
||||||
|
int32(Width*scale),
|
||||||
|
int32(Height*scale),
|
||||||
|
sdl.WINDOW_SHOWN,
|
||||||
|
)
|
||||||
|
surface, _ := window.GetSurface()
|
||||||
|
//data := unsafe.Slice((*uint32)(surface.Data()), Width*Height)
|
||||||
|
windowImage := NewImageFromPointer(surface.Data(), Vec2i{X: Width * scale, Y: Height * scale})
|
||||||
|
screen := NewImage(Vec2i{X: Width, Y: Height})
|
||||||
|
screen.Alpha = false
|
||||||
|
//sprite := NewImage(Vec2i{X: 32, Y: 32})
|
||||||
|
//sprite.Clear(0xabcdef)
|
||||||
|
fmt.Printf("%d\n", surface.Format.BitsPerPixel)
|
||||||
|
println("\n"[0])
|
||||||
|
|
||||||
|
tiles := LoadImage("go.png").MakeTileset(Vec2i{X: 16, Y: 16})
|
||||||
|
tilemap := NewTilemap(Vec2i{X: 40, Y: 23}, tiles)
|
||||||
|
tilemap.Clear(16)
|
||||||
|
for y := 0; y < 19; y += 1 {
|
||||||
|
for x := 0; x < 19; x += 1 {
|
||||||
|
tilemap.Set(Vec2i{X: 10 + x, Y: 1 + y}, 3)
|
||||||
|
}
|
||||||
|
//tilemap.Set(Vec2i{X: 9, Y: 1 + y}, 17)
|
||||||
|
tilemap.Set(Vec2i{X: 10, Y: 1 + y}, 11)
|
||||||
|
tilemap.Set(Vec2i{X: 28, Y: 1 + y}, 12)
|
||||||
|
}
|
||||||
|
|
||||||
|
for x := 0; x < 19; x += 1 {
|
||||||
|
//tilemap.Set(Vec2i{X: 10 + x, Y: 0}, 18)
|
||||||
|
tilemap.Set(Vec2i{X: 10 + x, Y: 1}, 9)
|
||||||
|
tilemap.Set(Vec2i{X: 10 + x, Y: 19}, 10)
|
||||||
|
tilemap.Set(Vec2i{X: 10 + x, Y: 20}, 17)
|
||||||
|
tilemap.Set(Vec2i{X: 10 + x, Y: 21}, 18)
|
||||||
|
}
|
||||||
|
|
||||||
|
for y := 0; y < 21; y += 1 {
|
||||||
|
tilemap.Set(Vec2i{X: 29, Y: 1 + y}, 19)
|
||||||
|
}
|
||||||
|
tilemap.Set(Vec2i{X: 10, Y: 21}, 20)
|
||||||
|
tilemap.Set(Vec2i{X: 29, Y: 1}, 21)
|
||||||
|
|
||||||
|
tilemap.Set(Vec2i{X: 10, Y: 1}, 5)
|
||||||
|
tilemap.Set(Vec2i{X: 28, Y: 1}, 6)
|
||||||
|
tilemap.Set(Vec2i{X: 10, Y: 19}, 7)
|
||||||
|
tilemap.Set(Vec2i{X: 28, Y: 19}, 8)
|
||||||
|
|
||||||
|
tilemap.Set(Vec2i{X: 13, Y: 4}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 25, Y: 4}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 13, Y: 16}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 25, Y: 16}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 13, Y: 10}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 13, Y: 16}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 25, Y: 10}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 25, Y: 16}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 19, Y: 4}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 19, Y: 10}, 4)
|
||||||
|
tilemap.Set(Vec2i{X: 19, Y: 16}, 4)
|
||||||
|
|
||||||
|
_ = window.UpdateSurface()
|
||||||
|
|
||||||
|
lastSecond := time.Now()
|
||||||
|
framesSinceLastSecond := 0
|
||||||
|
|
||||||
|
targetFPS := 60
|
||||||
|
frameDuration := time.Second / time.Duration(targetFPS)
|
||||||
|
lastFrame := lastSecond
|
||||||
|
|
||||||
|
running := true
|
||||||
|
tick := 0
|
||||||
|
for running {
|
||||||
|
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
||||||
|
switch event.(type) {
|
||||||
|
case *sdl.QuitEvent:
|
||||||
|
running = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
now := time.Now()
|
||||||
|
delta := now.Sub(lastSecond)
|
||||||
|
//println(delta.Seconds())
|
||||||
|
//println(now.Second())
|
||||||
|
if delta.Seconds() >= 1.0 {
|
||||||
|
fmt.Printf("FPS: %5d | mspf: %f\n", framesSinceLastSecond, 1000.0/float32(framesSinceLastSecond))
|
||||||
|
framesSinceLastSecond = 0
|
||||||
|
lastSecond = lastSecond.Add(time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
delta2 := now.Sub(lastFrame)
|
||||||
|
if delta2 >= frameDuration {
|
||||||
|
|
||||||
|
//t := (float64(tick)) / 1000
|
||||||
|
screen.Clear(0x123456)
|
||||||
|
screen.DrawTextOutline(
|
||||||
|
// "Hello World, this is a test,\nand now for another line :)",
|
||||||
|
// "Hello World, this is a test",
|
||||||
|
// "Vigilance, deathtouch, haste\n\nQuesting Beast can't be blocked by creatures\nwith power 2 or less.\n\nCombat damage that would be dealt by\ncreatures you control can't be prevented.\n\nWhenever Questing Beast deals combat damage\nto an opponent, it deals that much damage to\ntarget planeswalker that player controls.",
|
||||||
|
"Lorem ipsum dolor sit amet,\n"+
|
||||||
|
"consectetur adipiscing elit,\n"+
|
||||||
|
"sed do eiusmod tempor incididunt\n"+
|
||||||
|
"ut labore et dolore magna aliqua.\n"+
|
||||||
|
"Ut enim ad minim veniam, quis\n"+
|
||||||
|
"nostrud exercitation ullamco\n"+
|
||||||
|
"laboris nisi ut aliquip ex ea\n"+
|
||||||
|
"commodo consequat. Duis aute\n"+
|
||||||
|
"irure dolor in reprehenderit in\n"+
|
||||||
|
"voluptate velit esse cillum dolore\n"+
|
||||||
|
"eu fugiat nulla pariatur.\n"+
|
||||||
|
"Excepteur sint occaecat cupidatat\n"+
|
||||||
|
"non proident, sunt in culpa qui\n"+
|
||||||
|
"officia deserunt mollit anim id\n"+
|
||||||
|
"est laborum.",
|
||||||
|
DefaultFont,
|
||||||
|
Vec2i{X: 10, Y: 10},
|
||||||
|
0xffdddd,
|
||||||
|
color.Black,
|
||||||
|
// 50,
|
||||||
|
// 3.0,
|
||||||
|
// float64(tick) / 60.0,
|
||||||
|
)
|
||||||
|
screen.DrawTilemap(tilemap, Vec2i{})
|
||||||
|
screen.Draw(tilemap.Tileset[2], Vec2i{X: 16 * 25, Y: 16 * 4})
|
||||||
|
screen.Draw(tilemap.Tileset[1], Vec2i{X: 16 * 13, Y: 16 * 16})
|
||||||
|
windowImage.DrawUpscale(screen)
|
||||||
|
//windowImage.Draw(screen, Vec2i{})
|
||||||
|
tick += 1
|
||||||
|
framesSinceLastSecond += 1
|
||||||
|
lastFrame = lastFrame.Add(frameDuration)
|
||||||
|
}
|
||||||
|
_ = window.UpdateSurface()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package bloob
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
func FastSin(x float64) float64 {
|
||||||
|
const PI = 3.14159265358979323846264338327950288
|
||||||
|
const INVPI = 0.31830988618379067153776752674502872
|
||||||
|
const A = 0.00735246819687011731341356165096815
|
||||||
|
const B = -0.16528911397014738207016302002888890
|
||||||
|
const C = 0.99969198629596757779830113868360584
|
||||||
|
|
||||||
|
k := int32(math.Round(INVPI * x))
|
||||||
|
x -= float64(k) * PI
|
||||||
|
x2 := x * x
|
||||||
|
x = x * (C + x2*(B+A*x2))
|
||||||
|
if k%2 != 0 {
|
||||||
|
x = -x
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func FastCos(x float64) float64 {
|
||||||
|
return FastSin(x + math.Pi/2)
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package bloob
|
||||||
|
|
||||||
|
type Rect[T Number] struct {
|
||||||
|
Pos, Size Vec2[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Recti = Rect[int]
|
|
@ -0,0 +1,31 @@
|
||||||
|
package bloob
|
||||||
|
|
||||||
|
type Tilemap struct {
|
||||||
|
tiles []int
|
||||||
|
Size Vec2i
|
||||||
|
Tileset []*Image
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTilemap(size Vec2i, tileset []*Image) *Tilemap {
|
||||||
|
return &Tilemap{tiles: make([]int, size.Size()), Size: size, Tileset: tileset}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tilemap *Tilemap) Set(pos Vec2i, val int) {
|
||||||
|
if pos.X >= 0 && pos.Y >= 0 && pos.X < tilemap.Size.X && pos.Y < tilemap.Size.Y {
|
||||||
|
tilemap.tiles[pos.X+pos.Y*tilemap.Size.X] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tilemap *Tilemap) Get(pos Vec2i) int {
|
||||||
|
if pos.X >= 0 && pos.Y >= 0 && pos.X < tilemap.Size.X && pos.Y < tilemap.Size.Y {
|
||||||
|
return tilemap.tiles[pos.X+pos.Y*tilemap.Size.X]
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tilemap *Tilemap) Clear(val int) {
|
||||||
|
for i := 0; i < len(tilemap.tiles); i += 1 {
|
||||||
|
tilemap.tiles[i] = val
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package bloob
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Number interface {
|
||||||
|
constraints.Integer | constraints.Float
|
||||||
|
}
|
||||||
|
type Vec2[T Number] struct {
|
||||||
|
X, Y T
|
||||||
|
}
|
||||||
|
type Vec2i = Vec2[int]
|
||||||
|
|
||||||
|
func Add[T Number](a, b Vec2[T]) Vec2[T] {
|
||||||
|
return Vec2[T]{X: a.X + b.X, Y: a.Y + b.Y}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddScalar[T Number](a Vec2[T], b T) Vec2[T] {
|
||||||
|
return Vec2[T]{X: a.X + b, Y: a.Y + b}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sub[T Number](a, b Vec2[T]) Vec2[T] {
|
||||||
|
return Vec2[T]{X: a.X - b.X, Y: a.Y - b.Y}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubScalar[T Number](a Vec2[T], b T) Vec2[T] {
|
||||||
|
return Vec2[T]{X: a.X - b, Y: a.Y - b}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Mul[T Number](a, b Vec2[T]) Vec2[T] {
|
||||||
|
return Vec2[T]{X: a.X * b.X, Y: a.Y * b.Y}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MulScalar[T Number](a Vec2[T], b T) Vec2[T] {
|
||||||
|
return Vec2[T]{X: a.X * b, Y: a.Y * b}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Div[T Number](a, b Vec2[T]) Vec2[T] {
|
||||||
|
return Vec2[T]{X: a.X / b.X, Y: a.Y / b.Y}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DivScalar[T Number](a Vec2[T], b T) Vec2[T] {
|
||||||
|
return Vec2[T]{X: a.X / b, Y: a.Y / b}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Vec2[T]) Size() T {
|
||||||
|
return a.X * a.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
func Dot[T Number](a, b Vec2[T]) T {
|
||||||
|
return a.X*b.X + a.Y*b.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Vec2[T]) Mag() float64 {
|
||||||
|
return math.Sqrt(float64(a.MagSqr()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Vec2[T]) MagSqr() T {
|
||||||
|
return a.X*a.X + a.Y*a.Y
|
||||||
|
}
|
Loading…
Reference in New Issue