texture.go (2139B)
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 } 30 31 func NewTexture(name string) (*Texture, error) { 32 return NewTextureFlip(name, false, false) 33 } 34 35 func NewTextureFlip(name string, v bool, h bool) (*Texture, error) { 36 var id uint32 37 gl.GenTextures(1, &id) 38 gl.BindTexture(gl.TEXTURE_2D, id) 39 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) 40 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) 41 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 42 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 43 img, err := loadImage(name) 44 if err != nil { 45 return nil, fmt.Errorf("load texture: %v", err) 46 } 47 rgba := image.NewRGBA(img.Bounds()) 48 if v { 49 img = flipV(img) 50 } 51 if h { 52 img = flipH(img) 53 } 54 draw.Draw(rgba, rgba.Bounds(), img, image.ZP, draw.Src) 55 if rgba.Stride != rgba.Rect.Dx()*4 { 56 return nil, fmt.Errorf("data should be packed dense") 57 } 58 gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 59 int32(rgba.Rect.Dx()), int32(rgba.Rect.Dy()), 0, 60 gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(rgba.Pix)) 61 gl.GenerateMipmap(gl.TEXTURE_2D) 62 return &Texture{id: id}, nil 63 } 64 65 func flipV(img image.Image) image.Image { 66 dst := image.NewRGBA(img.Bounds()) 67 xmin, ymin := dst.Bounds().Min.X, dst.Bounds().Min.Y 68 xmax, ymax := dst.Bounds().Max.X, dst.Bounds().Max.Y 69 for y := ymin; y < ymax; y++ { 70 for x := xmin; x < xmax; x++ { 71 dst.Set(x, ymax+ymin-y, img.At(x, y)) 72 } 73 } 74 return dst 75 } 76 77 func flipH(img image.Image) image.Image { 78 dst := image.NewRGBA(img.Bounds()) 79 xmin, ymin := dst.Bounds().Min.X, dst.Bounds().Min.Y 80 xmax, ymax := dst.Bounds().Max.X, dst.Bounds().Max.Y 81 for y := ymin; y < ymax; y++ { 82 for x := xmin; x < xmax; x++ { 83 dst.Set(xmax+xmin-x, y, img.At(x, y)) 84 } 85 } 86 return dst 87 }