198 lines
5.1 KiB
Go
198 lines
5.1 KiB
Go
package render
|
|
|
|
import (
|
|
"image"
|
|
|
|
"github.com/go-gl/gl/all-core/gl"
|
|
)
|
|
|
|
func curTextureBinding() uint32 {
|
|
var id int32
|
|
gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &id)
|
|
return uint32(id)
|
|
}
|
|
|
|
// Texture holds handle to OpenGL Texture on the graphics card memory.
|
|
type Texture struct {
|
|
tex uint32
|
|
|
|
hasMipmap bool
|
|
smooth bool
|
|
}
|
|
|
|
// NewTexture creates a new, empty Texture.
|
|
func NewTexture() *Texture {
|
|
// Restore current texture binding
|
|
defer gl.BindTexture(gl.TEXTURE_2D, curTextureBinding())
|
|
|
|
var tex uint32
|
|
|
|
gl.GenTextures(1, &tex)
|
|
gl.BindTexture(gl.TEXTURE_2D, tex)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
|
|
|
return &Texture{tex: tex}
|
|
}
|
|
|
|
// NewTextureRGBA creates a new Texture with image.
|
|
func NewTextureRGBA(image *image.RGBA) *Texture {
|
|
// Restore current texture binding
|
|
defer gl.BindTexture(gl.TEXTURE_2D, curTextureBinding())
|
|
|
|
var tex uint32
|
|
|
|
gl.GenTextures(1, &tex)
|
|
gl.BindTexture(gl.TEXTURE_2D, tex)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
|
|
|
gl.TexImage2D(
|
|
gl.TEXTURE_2D,
|
|
0,
|
|
gl.RGBA,
|
|
int32(image.Rect.Size().X),
|
|
int32(image.Rect.Size().Y),
|
|
0,
|
|
gl.RGBA,
|
|
gl.UNSIGNED_BYTE,
|
|
gl.Ptr(image.Pix),
|
|
)
|
|
|
|
return &Texture{tex: tex}
|
|
}
|
|
|
|
// NewTextureFromHandle creates a new *Texture from an existing OpenGL handle.
|
|
func NewTextureFromHandle(handle uint32) *Texture {
|
|
return &Texture{tex: handle}
|
|
}
|
|
|
|
// updateFilters updates the MIN/MAG_FILTER parameters of the texture based on t.smooth and t.hasMipmap.
|
|
//
|
|
// It does not bind the texture; the caller has to do that
|
|
func (t *Texture) updateFilters() {
|
|
if t.smooth {
|
|
if t.hasMipmap {
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
|
} else {
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
|
}
|
|
} else {
|
|
if t.hasMipmap {
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
|
} else {
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetSmooth sets the min/mag filters to LINEAR(smooth) or NEAREST(not smooth)
|
|
func (t *Texture) SetSmooth(smooth bool) {
|
|
defer gl.BindTexture(gl.TEXTURE_2D, curTextureBinding())
|
|
gl.BindTexture(gl.TEXTURE_2D, t.tex)
|
|
t.smooth = smooth
|
|
t.updateFilters()
|
|
}
|
|
|
|
// UpdateRGBA updates the content of the texture with image.
|
|
// It deletes existing mipmap, you need to generate it again.
|
|
func (t *Texture) UpdateRGBA(image *image.RGBA) {
|
|
|
|
// Restore current texture binding
|
|
defer gl.BindTexture(gl.TEXTURE_2D, curTextureBinding())
|
|
|
|
gl.BindTexture(gl.TEXTURE_2D, t.tex)
|
|
gl.TexImage2D(
|
|
gl.TEXTURE_2D,
|
|
0,
|
|
gl.RGBA,
|
|
int32(image.Rect.Size().X),
|
|
int32(image.Rect.Size().Y),
|
|
0,
|
|
gl.RGBA,
|
|
gl.UNSIGNED_BYTE,
|
|
gl.Ptr(image.Pix),
|
|
)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
|
|
|
t.hasMipmap = false
|
|
t.updateFilters()
|
|
}
|
|
|
|
// UpdatesRGB updates the content of the texture with image in sRGB space.
|
|
// It deletes existing mipmap, you need to generate it again.
|
|
//
|
|
// The internal data is converted from sRGB to linear space by OpenGL:
|
|
//
|
|
// linear = sRGB/12.92 (if sRGB <= 0.04045)
|
|
// [(sRGB+0.055)/1.055]^2.4 (if sRGB > 0.04045)
|
|
//
|
|
// The Alpha component is not converted.
|
|
func (t *Texture) UpdatesRGB(image *image.RGBA) {
|
|
// Restore current texture binding
|
|
defer gl.BindTexture(gl.TEXTURE_2D, curTextureBinding())
|
|
|
|
gl.BindTexture(gl.TEXTURE_2D, t.tex)
|
|
gl.TexImage2D(
|
|
gl.TEXTURE_2D,
|
|
0,
|
|
gl.SRGB_ALPHA,
|
|
int32(image.Rect.Size().X),
|
|
int32(image.Rect.Size().Y),
|
|
0,
|
|
gl.RGBA,
|
|
gl.UNSIGNED_BYTE,
|
|
gl.Ptr(image.Pix),
|
|
)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
|
|
|
t.hasMipmap = false
|
|
t.updateFilters()
|
|
}
|
|
|
|
// GenerateMipMap generates mipmap for the texture.
|
|
func (t *Texture) GenerateMipMap() {
|
|
|
|
// Restore current texture binding
|
|
defer gl.BindTexture(gl.TEXTURE_2D, curTextureBinding())
|
|
|
|
gl.BindTexture(gl.TEXTURE_2D, t.tex)
|
|
gl.GenerateMipmap(gl.TEXTURE_2D)
|
|
|
|
t.hasMipmap = true
|
|
t.updateFilters()
|
|
}
|
|
|
|
// InvalidateMipMap invalidates mipmap for the texture.
|
|
func (t *Texture) InvalidateMipMap() {
|
|
|
|
// Restore current texture binding
|
|
defer gl.BindTexture(gl.TEXTURE_2D, curTextureBinding())
|
|
|
|
gl.BindTexture(gl.TEXTURE_2D, t.tex)
|
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
|
|
|
t.hasMipmap = false
|
|
t.updateFilters()
|
|
}
|
|
|
|
// Handle returns the OpenGL handle of the texture.
|
|
func (t *Texture) Handle() uint32 {
|
|
return t.tex
|
|
}
|
|
|
|
// Free deletes the texture.
|
|
func (t *Texture) Free() {
|
|
if t.tex != 0 {
|
|
gl.DeleteTextures(1, &t.tex)
|
|
}
|
|
}
|