Repository navigation
Expand file tree
/
Copy pathtexture.go
More file actions
108 lines (88 loc) · 2.31 KB
/
Copy pathtexture.go
File metadata and controls
108 lines (88 loc) · 2.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package aeno
import (
"bytes"
"image"
"net/http"
"time"
_ "image/jpeg" // Ensure decoders are present
_ "image/png"
"math"
)
type Texture interface {
Sample(u, v float64) Color
BilinearSample(u, v float64) Color
}
type ImageTexture struct {
Width int
Height int
Image image.Image
}
func NewImageTexture(im image.Image) Texture {
return &ImageTexture{
Width: im.Bounds().Dx(),
Height: im.Bounds().Dy(),
Image: im,
}
}
func LoadTexture(path string) (Texture, error) {
im, err := LoadImage(path)
if err != nil {
return nil, err
}
return NewImageTexture(im), nil
}
func LoadTextureFromURL(url string) Texture {
client := http.Client{
Timeout: 10 * time.Second, // Prevent hanging
}
resp, err := client.Get(url)
if err != nil || resp.StatusCode != 200 {
return nil
}
defer resp.Body.Close()
im, _, err := image.Decode(resp.Body)
if err != nil {
return nil
}
return NewImageTexture(im)
}
func TexFromBytes(data []byte) Texture {
im, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
return nil
}
return NewImageTexture(im)
}
func (t *ImageTexture) Sample(u, v float64) Color {
// Wrap coords
u = u - math.Floor(u)
v = v - math.Floor(v)
x := int(u * float64(t.Width))
y := int(v * float64(t.Height))
// Bounds check
if x >= t.Width { x = t.Width - 1 }
if y >= t.Height { y = t.Height - 1 }
return MakeColor(t.Image.At(x, y))
}
func (t *ImageTexture) BilinearSample(u, v float64) Color {
u = math.Max(0, math.Min(1.0-1e-9, u))
v = math.Max(0, math.Min(1.0-1e-9, v))
uScaled := u * float64(t.Width-1)
vScaled := v * float64(t.Height-1)
x0, y0 := int(uScaled), int(vScaled)
x1 := x0 + 1
y1 := y0 + 1
if x1 >= t.Width { x1 = t.Width - 1 }
if y1 >= t.Height { y1 = t.Height - 1 }
if x0 >= t.Width { x0 = t.Width - 1 } // Safety clamp
if y0 >= t.Height { y0 = t.Height - 1 }
uFrac := uScaled - math.Floor(uScaled)
vFrac := vScaled - math.Floor(vScaled)
c00 := MakeColor(t.Image.At(x0, y0))
c10 := MakeColor(t.Image.At(x1, y0))
c01 := MakeColor(t.Image.At(x0, y1))
c11 := MakeColor(t.Image.At(x1, y1))
top := c00.Lerp(c10, uFrac)
bottom := c01.Lerp(c11, uFrac)
return top.Lerp(bottom, vFrac)
}