func createTexture(r io.Reader) (gl.Texture, error) { img, err := png.Decode(r) if err != nil { return gl.Texture(0), err } rgbaImg, ok := img.(*image.NRGBA) if !ok { return gl.Texture(0), errors.New("texture must be an NRGBA image") } textureId := gl.GenTexture() textureId.Bind(gl.TEXTURE_2D) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) // flip image: first pixel is lower left corner imgWidth, imgHeight := img.Bounds().Dx(), img.Bounds().Dy() data := make([]byte, imgWidth*imgHeight*4) lineLen := imgWidth * 4 dest := len(data) - lineLen for src := 0; src < len(rgbaImg.Pix); src += rgbaImg.Stride { copy(data[dest:dest+lineLen], rgbaImg.Pix[src:src+rgbaImg.Stride]) dest -= lineLen } gl.TexImage2D(gl.TEXTURE_2D, 0, 4, imgWidth, imgHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, data) return textureId, nil }
// NewAtlas will create a new atlas with enough space to // at least nRows X nColumns chunks of widthXheight size. The total // number of chunks are determinated by the power of two rule below. // // The actual memory used might be larger since all atlas MUST BE // a power of 2 rect (16, 32, 64, 128...). But the rectangle used // by the chunk is limited to width/height. func NewAtlas(width, height, nRows, nColumns int) *Atlas { _, max := minMaxOf(powerOfTwo(nRows*height), powerOfTwo(nColumns*width)) return &Atlas{ cw: width, ch: height, data: image.NewRGBA(image.Rect(0, 0, max, max)), gltex: gl.Texture(gl.FALSE), } }
func (a *Atlas) unbind(release bool) error { if !gl.Object(a.gltex).IsTexture() { return nil } a.gltex.Unbind(gl.TEXTURE_2D) if release { a.gltex.Delete() } a.gltex = gl.Texture(gl.FALSE) return checkGlError() }
// Bind binds the texture func (t *Texture) Bind(coordType CoordType) { // ensureGlContext() if t != nil && t.t != 0 { // Bind the texture t.t.Bind(gl.TEXTURE_2D) // Check if we need to define a special texture matrix if coordType == CoordPixels || t.pixelsFlipped { matrix := [16]float32{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1} // If non-normalized coordinates (= pixels) are requested, we need to // setup scale factors that convert the range [0 .. size] to [0 .. 1] if coordType == CoordPixels { matrix[0] = 1.0 / t.size.X matrix[5] = 1.0 / t.size.Y } // If pixels are flipped we must invert the Y axis if t.pixelsFlipped { matrix[5] = -matrix[5] matrix[13] = 1.0 } // Load the matrix gl.MatrixMode(gl.TEXTURE) gl.LoadMatrixf(&matrix) // Go back to model-view mode (sf::RenderTarget relies on it) gl.MatrixMode(gl.MODELVIEW) } } else { // Bind no texture gl.Texture(0).Unbind(gl.TEXTURE_2D) // Reset the texture matrix gl.MatrixMode(gl.TEXTURE) gl.LoadIdentity() // Go back to model-view mode (sf::RenderTarget relies on it) gl.MatrixMode(gl.MODELVIEW) } }
func TextureFromDDS(fname string) (gl.Texture, error) { file, err := os.Open(fname) if err != nil { return gl.Texture(0), fmt.Errorf("Cannot open DDS file: %v", err) } defer file.Close() var filecode [4]byte binary.Read(file, binary.LittleEndian, &filecode) // DDS is always Little Endian encoded if string(filecode[:]) != "DDS " { return gl.Texture(0), fmt.Errorf("File code is not DDS, instead got %v.", string(filecode[:])) } header := ddsHeader{} err = binary.Read(file, binary.LittleEndian, &header) if err != nil { return gl.Texture(0), fmt.Errorf("Couldn't read DDS header: %v", err) } stat, err := file.Stat() if err != nil { return gl.Texture(0), fmt.Errorf("Couldn't get size of file: %v", err) } // All of the file after the header and file identifier "DDS " // is images. 4 byte identifier + 124 byte header = 128 bytes // to take off the file size. bufSize := stat.Size() - 128 buffer := make([]byte, bufSize) err = binary.Read(file, binary.LittleEndian, buffer) if err != nil { return gl.Texture(0), fmt.Errorf("Couldn't read all mipmaps into buffer: %v", err) } //var components uint32 var blockSize uint32 var format gl.GLenum switch header.PixelFormat.FourCC { case fourCC_DXT1: format = gl.COMPRESSED_RGBA_S3TC_DXT1_EXT //components = 3 blockSize = 8 case fourCC_DXT3: format = gl.COMPRESSED_RGBA_S3TC_DXT3_EXT //components = 4 blockSize = 16 case fourCC_DXT5: format = gl.COMPRESSED_RGBA_S3TC_DXT5_EXT //components = 4 blockSize = 16 default: return gl.Texture(0), fmt.Errorf("Invalid four CC in DDS header. Got: %x; Expected %x; %x; or %x", header.PixelFormat.FourCC, fourCC_DXT1, fourCC_DXT3, fourCC_DXT5) } offset := 0 tex := gl.GenTexture() tex.Bind(gl.TEXTURE_2D) gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1) for level, width, height := 0, header.Width, header.Height; level < int(header.MipMapCount) && (width > 0 || height > 0); level, width, height = level+1, width/2, height/2 { size := int(((width + 3) / 4) * ((height + 3) / 4) * blockSize) gl.CompressedTexImage2D(gl.TEXTURE_2D, level, format, int(width), int(height), 0, size, &buffer[offset]) offset += size } return tex, nil }