129 lines
3.5 KiB
Go
129 lines
3.5 KiB
Go
package graphics
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/go-gl/gl/v3.3-core/gl"
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
)
|
|
|
|
// CreateTextureFromSurface uploads an SDL surface to an OpenGL texture and returns the texture ID.
|
|
func CreateTextureFromSurface(surface *sdl.Surface) (uint32, error) {
|
|
if surface == nil {
|
|
return 0, fmt.Errorf("CreateTextureFromSurface: input surface is nil")
|
|
}
|
|
|
|
var textureID uint32
|
|
var err error
|
|
|
|
surfaceToUpload := surface
|
|
var convertedSurface *sdl.Surface = nil
|
|
|
|
sdlFormatEnum := surface.Format.Format
|
|
var dataFormat uint32
|
|
var internalFormat int32 = gl.RGBA8
|
|
|
|
if sdlFormatEnum == sdl.PIXELFORMAT_INDEX8 {
|
|
convertedSurface, err = surface.ConvertFormat(sdl.PIXELFORMAT_ARGB8888, 0)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to convert INDEX8 surface to ARGB8888: %w", err)
|
|
}
|
|
defer convertedSurface.Free()
|
|
|
|
surfaceToUpload = convertedSurface
|
|
sdlFormatEnum = surfaceToUpload.Format.Format
|
|
}
|
|
|
|
switch sdlFormatEnum {
|
|
case sdl.PIXELFORMAT_ARGB8888:
|
|
dataFormat = gl.BGRA
|
|
case sdl.PIXELFORMAT_ABGR8888:
|
|
dataFormat = gl.RGBA
|
|
case sdl.PIXELFORMAT_RGBA8888:
|
|
dataFormat = gl.RGBA
|
|
case sdl.PIXELFORMAT_BGRA8888:
|
|
dataFormat = gl.BGRA
|
|
default:
|
|
return 0, fmt.Errorf("unhandled SDL pixel format for OpenGL upload: %s", sdl.GetPixelFormatName(uint(sdlFormatEnum)))
|
|
}
|
|
|
|
for errCode := gl.GetError(); errCode != gl.NO_ERROR; errCode = gl.GetError() {
|
|
log.Printf("OpenGL error pending before GenTextures: 0x%X", errCode)
|
|
}
|
|
|
|
gl.GenTextures(1, &textureID)
|
|
if errCode := gl.GetError(); errCode != gl.NO_ERROR {
|
|
return 0, fmt.Errorf("OpenGL error 0x%X after GenTextures", errCode)
|
|
}
|
|
if textureID == 0 {
|
|
return 0, fmt.Errorf("gl.GenTextures returned textureID 0")
|
|
}
|
|
|
|
gl.BindTexture(gl.TEXTURE_2D, textureID)
|
|
|
|
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.PixelStorei(gl.UNPACK_ALIGNMENT, 1)
|
|
|
|
expectedPitch := surfaceToUpload.W * int32(surfaceToUpload.Format.BytesPerPixel)
|
|
if int32(surfaceToUpload.Pitch) != expectedPitch {
|
|
gl.PixelStorei(gl.UNPACK_ROW_LENGTH, surfaceToUpload.Pitch/int32(surfaceToUpload.Format.BytesPerPixel))
|
|
} else {
|
|
gl.PixelStorei(gl.UNPACK_ROW_LENGTH, 0)
|
|
}
|
|
|
|
gl.TexImage2D(
|
|
gl.TEXTURE_2D,
|
|
0,
|
|
internalFormat,
|
|
surfaceToUpload.W,
|
|
surfaceToUpload.H,
|
|
0,
|
|
dataFormat,
|
|
gl.UNSIGNED_BYTE,
|
|
gl.Ptr(surfaceToUpload.Pixels()),
|
|
)
|
|
|
|
gl.PixelStorei(gl.UNPACK_ALIGNMENT, 4)
|
|
gl.PixelStorei(gl.UNPACK_ROW_LENGTH, 0)
|
|
|
|
if glErr := gl.GetError(); glErr != gl.NO_ERROR {
|
|
gl.DeleteTextures(1, &textureID)
|
|
return 0, fmt.Errorf("OpenGL error 0x%X after TexImage2D", glErr)
|
|
}
|
|
|
|
gl.BindTexture(gl.TEXTURE_2D, 0)
|
|
return textureID, nil
|
|
}
|
|
|
|
// CheckGLError queries OpenGL for errors and returns the first one found.
|
|
func CheckGLError() error {
|
|
errCode := gl.GetError()
|
|
if errCode == gl.NO_ERROR {
|
|
return nil
|
|
}
|
|
|
|
switch errCode {
|
|
case gl.INVALID_ENUM:
|
|
return fmt.Errorf("INVALID_ENUM")
|
|
case gl.INVALID_VALUE:
|
|
return fmt.Errorf("INVALID_VALUE")
|
|
case gl.INVALID_OPERATION:
|
|
return fmt.Errorf("INVALID_OPERATION")
|
|
case gl.STACK_OVERFLOW:
|
|
return fmt.Errorf("STACK_OVERFLOW")
|
|
case gl.STACK_UNDERFLOW:
|
|
return fmt.Errorf("STACK_UNDERFLOW")
|
|
case gl.OUT_OF_MEMORY:
|
|
return fmt.Errorf("OUT_OF_MEMORY")
|
|
case gl.INVALID_FRAMEBUFFER_OPERATION:
|
|
return fmt.Errorf("INVALID_FRAMEBUFFER_OPERATION")
|
|
default:
|
|
return fmt.Errorf("Unknown GL error: 0x%X", errCode)
|
|
}
|
|
}
|