From b29ae90fbaec02956400804713b6307b881c0c27 Mon Sep 17 00:00:00 2001 From: squishy Date: Mon, 25 Mar 2024 04:56:33 +0000 Subject: [PATCH] split image.go into multiple files --- draw_image.go | 162 ++++++++++++++++++++++++ draw_line.go | 14 +++ draw_rect.go | 30 +++++ draw_text.go | 97 +++++++++++++++ draw_tilemap.go | 24 ++++ image.go | 320 ------------------------------------------------ 6 files changed, 327 insertions(+), 320 deletions(-) create mode 100644 draw_image.go create mode 100644 draw_line.go create mode 100644 draw_rect.go create mode 100644 draw_text.go create mode 100644 draw_tilemap.go diff --git a/draw_image.go b/draw_image.go new file mode 100644 index 0000000..d6107ad --- /dev/null +++ b/draw_image.go @@ -0,0 +1,162 @@ +package bloob + +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 Color) { + image.DrawSubColor(other, dst, Recti{Size: other.Size}, color) +} + +func (image *Image) DrawSubColor(other *Image, pos Vec2i, rect Recti, color Color) { + 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 + } +} diff --git a/draw_line.go b/draw_line.go new file mode 100644 index 0000000..a0a7f75 --- /dev/null +++ b/draw_line.go @@ -0,0 +1,14 @@ +package bloob + + +func (image *Image) DrawHLine(pos Vec2i, length int, color Color) { + for i := 0; i < length; i += 1 { + image.Data[pos.X+i+pos.Y*image.Size.X] = color + } +} + +func (image *Image) DrawVLine(pos Vec2i, length int, color Color) { + for i := 0; i < length; i += 1 { + image.Data[pos.X+(pos.Y+i)*image.Size.X] = color + } +} \ No newline at end of file diff --git a/draw_rect.go b/draw_rect.go new file mode 100644 index 0000000..8ddb9d2 --- /dev/null +++ b/draw_rect.go @@ -0,0 +1,30 @@ +package bloob + +func (image *Image) DrawRect(rect Recti, color Color) { + start, end, _ := CropToArea(image.Size, rect, Vec2i{}) + for y := start.Y; y < end.Y; y += 1 { + for x := start.X; x < end.X; x += 1 { + image.Data[x+y*image.Size.X] = color + } + } +} + +func (image *Image) DrawRectRounded(rect Recti, color Color, round int) { + round = min(max(rect.Size.X, rect.Size.Y)/2-1, round) + + start, end, _ := CropToArea(image.Size, rect, Vec2i{}) + for y := start.Y; y < end.Y; y += 1 { + ri := 0 + yt := y - start.Y + yp := -(y - end.Y + 1) + if yt < round { + ri = round - yt + } + if yp < round { + ri = round - yp + } + for x := start.X + ri; x < end.X-ri; x += 1 { + image.Data[x+y*image.Size.X] = color + } + } +} diff --git a/draw_text.go b/draw_text.go new file mode 100644 index 0000000..059be4a --- /dev/null +++ b/draw_text.go @@ -0,0 +1,97 @@ +package bloob + +import "math" + +func (image *Image) DrawText(str string, font *Font, pos Vec2i, color Color) { + 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) DrawTextCenter(str string, font *Font, rect Recti, color Color) { + size := font.StringBounds(str) + pos := Add(DivScalar(Sub(rect.Size, size), 2), Add(rect.Pos, Vec2i{X: 0, Y: 1})) + image.DrawText(str, font, pos, color) +} + +func (image *Image) DrawTextSin(str string, font *Font, pos Vec2i, color Color, 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 Color) { + 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) DrawTextOutlineCenter(str string, font *Font, rect Recti, color, outlineColor Color) { + size := font.StringBounds(str) + pos := Add(DivScalar(Sub(rect.Size, size), 2), Add(rect.Pos, Vec2i{X: 0, Y: 1})) + image.DrawTextOutline(str, font, pos, color, outlineColor) +} + +func (image *Image) DrawTextOutlineSin(str string, font *Font, pos Vec2i, color, outlineColor Color, 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 + } +} diff --git a/draw_tilemap.go b/draw_tilemap.go new file mode 100644 index 0000000..b80f8d7 --- /dev/null +++ b/draw_tilemap.go @@ -0,0 +1,24 @@ +package bloob + +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 +} diff --git a/image.go b/image.go index cac4573..69e2160 100644 --- a/image.go +++ b/image.go @@ -5,7 +5,6 @@ import ( _ "github.com/askeladdk/aseprite" "image" _ "image/png" - "math" "os" "runtime/pprof" "sync" @@ -94,322 +93,3 @@ func CropToArea(sizeDst Vec2i, rectSrc Recti, posDst Vec2i) (start, end, dst Vec func (image *Image) DrawPixel(pos Vec2i, color Color) { image.Data[pos.X+pos.Y*image.Size.X] = color } - -func (image *Image) DrawHLine(pos Vec2i, length int, color Color) { - for i := 0; i < length; i += 1 { - image.Data[pos.X+i+pos.Y*image.Size.X] = color - } -} - -func (image *Image) DrawVLine(pos Vec2i, length int, color Color) { - for i := 0; i < length; i += 1 { - image.Data[pos.X+(pos.Y+i)*image.Size.X] = color - } -} - -func (image *Image) DrawRect(rect Recti, color Color) { - start, end, _ := CropToArea(image.Size, rect, Vec2i{}) - for y := start.Y; y < end.Y; y += 1 { - for x := start.X; x < end.X; x += 1 { - image.Data[x+y*image.Size.X] = color - } - } -} - -func (image *Image) DrawRectRounded(rect Recti, color Color, round int) { - round = min(max(rect.Size.X, rect.Size.Y)/2-1, round) - - start, end, _ := CropToArea(image.Size, rect, Vec2i{}) - for y := start.Y; y < end.Y; y += 1 { - ri := 0 - yt := y - start.Y - yp := -(y - end.Y+1) - if yt < round { - ri = round - yt - } - if yp < round { - ri = round - yp - } - for x := start.X + ri; x < end.X-ri; x += 1 { - image.Data[x+y*image.Size.X] = color - } - } -} - -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 Color) { - image.DrawSubColor(other, dst, Recti{Size: other.Size}, color) -} - -func (image *Image) DrawSubColor(other *Image, pos Vec2i, rect Recti, color Color) { - 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 Color) { - 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) DrawTextCenter(str string, font *Font, rect Recti, color Color) { - size := font.StringBounds(str) - pos := Add(DivScalar(Sub(rect.Size, size), 2), Add(rect.Pos, Vec2i{X: 0, Y: 1})) - image.DrawText(str, font, pos, color) -} - -func (image *Image) DrawTextSin(str string, font *Font, pos Vec2i, color Color, 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 Color) { - 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) DrawTextOutlineCenter(str string, font *Font, rect Recti, color, outlineColor Color) { - size := font.StringBounds(str) - pos := Add(DivScalar(Sub(rect.Size, size), 2), Add(rect.Pos, Vec2i{X: 0, Y: 1})) - image.DrawTextOutline(str, font, pos, color, outlineColor) -} - -func (image *Image) DrawTextOutlineSin(str string, font *Font, pos Vec2i, color, outlineColor Color, 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 -}