texture.go (2231B)
1 package tofu 2 3 import ( 4 "fmt" 5 "image" 6 draw "image/draw" 7 _ "image/jpeg" 8 _ "image/png" 9 "os" 10 11 "github.com/go-gl/gl/v3.3-core/gl" 12 ) 13 14 func loadImage(name string) (image.Image, error) { 15 f, err := os.Open(name) 16 if err != nil { 17 return nil, fmt.Errorf("open: %v", err) 18 } 19 defer f.Close() 20 img, _, err := image.Decode(f) 21 if err != nil { 22 return nil, fmt.Errorf("decode image %s: %v", name, err) 23 } 24 return img, nil 25 } 26 27 type Texture struct { 28 id uint32 29 unit uint32 30 } 31 32 var nextUnit uint32 = gl.TEXTURE0 33 34 func NewTexture(name string) (*Texture, error) { 35 return NewTextureFlip(name, false, false) 36 } 37 38 func NewTextureFlip(name string, v bool, h bool) (*Texture, error) { 39 var id uint32 40 gl.GenTextures(1, &id) 41 gl.BindTexture(gl.TEXTURE_2D, id) 42 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) 43 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) 44 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 45 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 46 img, err := loadImage(name) 47 if err != nil { 48 return nil, fmt.Errorf("load texture: %v", err) 49 } 50 rgba := image.NewRGBA(img.Bounds()) 51 if v { 52 img = flipV(img) 53 } 54 if h { 55 img = flipH(img) 56 } 57 draw.Draw(rgba, rgba.Bounds(), img, image.ZP, draw.Src) 58 if rgba.Stride != rgba.Rect.Dx()*4 { 59 return nil, fmt.Errorf("data should be packed dense") 60 } 61 gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 62 int32(rgba.Rect.Dx()), int32(rgba.Rect.Dy()), 0, 63 gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(rgba.Pix)) 64 gl.GenerateMipmap(gl.TEXTURE_2D) 65 unit := nextUnit 66 nextUnit++ 67 return &Texture{id: id, unit: unit}, nil 68 } 69 70 func flipV(img image.Image) image.Image { 71 dst := image.NewRGBA(img.Bounds()) 72 xmin, ymin := dst.Bounds().Min.X, dst.Bounds().Min.Y 73 xmax, ymax := dst.Bounds().Max.X, dst.Bounds().Max.Y 74 for y := ymin; y < ymax; y++ { 75 for x := xmin; x < xmax; x++ { 76 dst.Set(x, ymax+ymin-y, img.At(x, y)) 77 } 78 } 79 return dst 80 } 81 82 func flipH(img image.Image) image.Image { 83 dst := image.NewRGBA(img.Bounds()) 84 xmin, ymin := dst.Bounds().Min.X, dst.Bounds().Min.Y 85 xmax, ymax := dst.Bounds().Max.X, dst.Bounds().Max.Y 86 for y := ymin; y < ymax; y++ { 87 for x := xmin; x < xmax; x++ { 88 dst.Set(xmax+xmin-x, y, img.At(x, y)) 89 } 90 } 91 return dst 92 }