mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 05:18:21 +00:00
Loading cubemap textures+don't store texture by default
This commit is contained in:
@ -1,8 +1,8 @@
|
|||||||
package assets
|
package assets
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Textures map[uint32]Texture = make(map[uint32]Texture)
|
Textures = make(map[uint32]Texture)
|
||||||
TexturePaths map[string]uint32 = make(map[string]uint32)
|
TexturePaths = make(map[string]uint32)
|
||||||
)
|
)
|
||||||
|
|
||||||
func AddTextureToCache(t Texture) {
|
func AddTextureToCache(t Texture) {
|
||||||
|
|||||||
@ -4,8 +4,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"image/jpeg"
|
||||||
"image/png"
|
"image/png"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/go-gl/gl/v4.1-core/gl"
|
"github.com/go-gl/gl/v4.1-core/gl"
|
||||||
@ -30,6 +34,18 @@ type TextureLoadOptions struct {
|
|||||||
TryLoadFromCache bool
|
TryLoadFromCache bool
|
||||||
WriteToCache bool
|
WriteToCache bool
|
||||||
GenMipMaps bool
|
GenMipMaps bool
|
||||||
|
KeepPixelsInMem bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cubemap struct {
|
||||||
|
// These only exists for textures loaded from disk
|
||||||
|
RightPath string
|
||||||
|
LeftPath string
|
||||||
|
TopPath string
|
||||||
|
BotPath string
|
||||||
|
FrontPath string
|
||||||
|
BackPath string
|
||||||
|
TexID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadTexturePNG(file string, loadOptions *TextureLoadOptions) (Texture, error) {
|
func LoadTexturePNG(file string, loadOptions *TextureLoadOptions) (Texture, error) {
|
||||||
@ -56,28 +72,10 @@ func LoadTexturePNG(file string, loadOptions *TextureLoadOptions) (Texture, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
tex := Texture{
|
tex := Texture{
|
||||||
Path: file,
|
Path: file,
|
||||||
Width: int32(img.Bounds().Dx()),
|
|
||||||
Height: int32(img.Bounds().Dy()),
|
|
||||||
Pixels: make([]byte, img.Bounds().Dx()*img.Bounds().Dy()*4),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: Load bottom left to top right because this is the texture coordinate system used by OpenGL
|
tex.Pixels, tex.Width, tex.Height = pixelsFromNrgbaPng(img)
|
||||||
//NOTE: We only support 8-bit channels (32-bit colors) for now
|
|
||||||
i := 0
|
|
||||||
for y := img.Bounds().Dy() - 1; y >= 0; y-- {
|
|
||||||
for x := 0; x < img.Bounds().Dx(); x++ {
|
|
||||||
|
|
||||||
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
|
||||||
|
|
||||||
tex.Pixels[i] = c.R
|
|
||||||
tex.Pixels[i+1] = c.G
|
|
||||||
tex.Pixels[i+2] = c.B
|
|
||||||
tex.Pixels[i+3] = c.A
|
|
||||||
|
|
||||||
i += 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Prepare opengl stuff
|
//Prepare opengl stuff
|
||||||
gl.GenTextures(1, &tex.TexID)
|
gl.GenTextures(1, &tex.TexID)
|
||||||
@ -100,37 +98,21 @@ func LoadTexturePNG(file string, loadOptions *TextureLoadOptions) (Texture, erro
|
|||||||
AddTextureToCache(tex)
|
AddTextureToCache(tex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !loadOptions.KeepPixelsInMem {
|
||||||
|
tex.Pixels = nil
|
||||||
|
}
|
||||||
|
|
||||||
return tex, nil
|
return tex, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadTextureInMemImg(img image.Image, loadOptions *TextureLoadOptions) (Texture, error) {
|
func LoadTextureInMemPngImg(img image.Image, loadOptions *TextureLoadOptions) (Texture, error) {
|
||||||
|
|
||||||
if loadOptions == nil {
|
if loadOptions == nil {
|
||||||
loadOptions = &TextureLoadOptions{}
|
loadOptions = &TextureLoadOptions{}
|
||||||
}
|
}
|
||||||
|
|
||||||
tex := Texture{
|
tex := Texture{}
|
||||||
Width: int32(img.Bounds().Dx()),
|
tex.Pixels, tex.Width, tex.Height = pixelsFromNrgbaPng(img)
|
||||||
Height: int32(img.Bounds().Dy()),
|
|
||||||
Pixels: make([]byte, img.Bounds().Dx()*img.Bounds().Dy()*4),
|
|
||||||
}
|
|
||||||
|
|
||||||
//NOTE: Load bottom left to top right because this is the texture coordinate system used by OpenGL
|
|
||||||
//NOTE: We only support 8-bit channels (32-bit colors) for now
|
|
||||||
i := 0
|
|
||||||
for y := img.Bounds().Dy() - 1; y >= 0; y-- {
|
|
||||||
for x := 0; x < img.Bounds().Dx(); x++ {
|
|
||||||
|
|
||||||
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
|
||||||
|
|
||||||
tex.Pixels[i] = c.R
|
|
||||||
tex.Pixels[i+1] = c.G
|
|
||||||
tex.Pixels[i+2] = c.B
|
|
||||||
tex.Pixels[i+3] = c.A
|
|
||||||
|
|
||||||
i += 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Prepare opengl stuff
|
//Prepare opengl stuff
|
||||||
gl.GenTextures(1, &tex.TexID)
|
gl.GenTextures(1, &tex.TexID)
|
||||||
@ -153,5 +135,174 @@ func LoadTextureInMemImg(img image.Image, loadOptions *TextureLoadOptions) (Text
|
|||||||
AddTextureToCache(tex)
|
AddTextureToCache(tex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !loadOptions.KeepPixelsInMem {
|
||||||
|
tex.Pixels = nil
|
||||||
|
}
|
||||||
|
|
||||||
return tex, nil
|
return tex, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadTextureJpeg(file string, loadOptions *TextureLoadOptions) (Texture, error) {
|
||||||
|
|
||||||
|
if loadOptions == nil {
|
||||||
|
loadOptions = &TextureLoadOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if loadOptions.TryLoadFromCache {
|
||||||
|
if tex, ok := GetTextureFromCachePath(file); ok {
|
||||||
|
return tex, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Load from disk
|
||||||
|
fileBytes, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return Texture{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
img, err := jpeg.Decode(bytes.NewReader(fileBytes))
|
||||||
|
if err != nil {
|
||||||
|
return Texture{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tex := Texture{
|
||||||
|
Path: file,
|
||||||
|
}
|
||||||
|
|
||||||
|
tex.Pixels, tex.Width, tex.Height = pixelsFromNrgbaPng(img)
|
||||||
|
|
||||||
|
//Prepare opengl stuff
|
||||||
|
gl.GenTextures(1, &tex.TexID)
|
||||||
|
gl.BindTexture(gl.TEXTURE_2D, tex.TexID)
|
||||||
|
|
||||||
|
// set the texture wrapping/filtering options (on the currently bound texture object)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||||
|
|
||||||
|
// load and generate the texture
|
||||||
|
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, tex.Width, tex.Height, 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&tex.Pixels[0]))
|
||||||
|
|
||||||
|
if loadOptions.GenMipMaps {
|
||||||
|
gl.GenerateMipmap(tex.TexID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if loadOptions.WriteToCache {
|
||||||
|
AddTextureToCache(tex)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !loadOptions.KeepPixelsInMem {
|
||||||
|
tex.Pixels = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tex, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func pixelsFromNrgbaPng(img image.Image) (pixels []byte, width, height int32) {
|
||||||
|
|
||||||
|
//NOTE: Load bottom left to top right because this is the texture coordinate system used by OpenGL
|
||||||
|
//NOTE: We only support 8-bit channels (32-bit colors) for now
|
||||||
|
i := 0
|
||||||
|
width, height = int32(img.Bounds().Dx()), int32(img.Bounds().Dy())
|
||||||
|
pixels = make([]byte, img.Bounds().Dx()*img.Bounds().Dy()*4)
|
||||||
|
for y := img.Bounds().Dy() - 1; y >= 0; y-- {
|
||||||
|
for x := 0; x < img.Bounds().Dx(); x++ {
|
||||||
|
|
||||||
|
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
||||||
|
|
||||||
|
pixels[i] = c.R
|
||||||
|
pixels[i+1] = c.G
|
||||||
|
pixels[i+2] = c.B
|
||||||
|
pixels[i+3] = c.A
|
||||||
|
|
||||||
|
i += 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pixels, width, height
|
||||||
|
}
|
||||||
|
|
||||||
|
func pixelsFromNrgbaJpg(img image.Image) (pixels []byte, width, height int32) {
|
||||||
|
|
||||||
|
//NOTE: Load bottom left to top right because this is the texture coordinate system used by OpenGL
|
||||||
|
//NOTE: We only support 8-bit channels (32-bit colors) for now
|
||||||
|
i := 0
|
||||||
|
width, height = int32(img.Bounds().Dx()), int32(img.Bounds().Dy())
|
||||||
|
pixels = make([]byte, img.Bounds().Dx()*img.Bounds().Dy()*4)
|
||||||
|
for y := img.Bounds().Dy() - 1; y >= 0; y-- {
|
||||||
|
for x := 0; x < img.Bounds().Dx(); x++ {
|
||||||
|
|
||||||
|
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
||||||
|
|
||||||
|
pixels[i] = c.R
|
||||||
|
pixels[i+1] = c.G
|
||||||
|
pixels[i+2] = c.B
|
||||||
|
pixels[i+3] = c.A
|
||||||
|
|
||||||
|
i += 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pixels, width, height
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadCubemapTextures(rightTex, leftTex, topTex, botTex, frontTex, backTex string) (Cubemap, error) {
|
||||||
|
|
||||||
|
var imgDecoder func(r io.Reader) (image.Image, error)
|
||||||
|
var pixelDecoder func(image.Image) ([]byte, int32, int32)
|
||||||
|
ext := strings.ToLower(path.Ext(rightTex))
|
||||||
|
if ext == ".jpg" || ext == ".jpeg" {
|
||||||
|
imgDecoder = jpeg.Decode
|
||||||
|
pixelDecoder = pixelsFromNrgbaJpg
|
||||||
|
} else if ext == ".png" {
|
||||||
|
imgDecoder = png.Decode
|
||||||
|
pixelDecoder = pixelsFromNrgbaPng
|
||||||
|
} else {
|
||||||
|
panic("unknown image extension: " + ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmap := Cubemap{
|
||||||
|
RightPath: rightTex,
|
||||||
|
LeftPath: leftTex,
|
||||||
|
TopPath: topTex,
|
||||||
|
BotPath: botTex,
|
||||||
|
FrontPath: frontTex,
|
||||||
|
BackPath: backTex,
|
||||||
|
}
|
||||||
|
|
||||||
|
texturePaths := []string{rightTex, leftTex, topTex, botTex, frontTex, backTex}
|
||||||
|
for i := 0; i < len(texturePaths); i++ {
|
||||||
|
|
||||||
|
fPath := texturePaths[i]
|
||||||
|
|
||||||
|
//Load from disk
|
||||||
|
fileBytes, err := os.ReadFile(fPath)
|
||||||
|
if err != nil {
|
||||||
|
return Cubemap{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
img, err := imgDecoder(bytes.NewReader(fileBytes))
|
||||||
|
if err != nil {
|
||||||
|
return Cubemap{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pixels, width, height := pixelDecoder(img)
|
||||||
|
|
||||||
|
//Prepare opengl stuff
|
||||||
|
gl.GenTextures(1, &cmap.TexID)
|
||||||
|
gl.BindTexture(gl.TEXTURE_CUBE_MAP, cmap.TexID)
|
||||||
|
|
||||||
|
// load and generate the texture
|
||||||
|
gl.TexImage2D(gl.TEXTURE_CUBE_MAP, 0, gl.RGBA8, int32(width), int32(height), 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&pixels[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the texture wrapping/filtering options (on the currently bound texture object)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||||
|
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE)
|
||||||
|
|
||||||
|
return cmap, nil
|
||||||
|
}
|
||||||
|
|||||||
11
main.go
11
main.go
@ -56,6 +56,8 @@ var (
|
|||||||
|
|
||||||
debugDrawDepthBuffer bool
|
debugDrawDepthBuffer bool
|
||||||
debugDepthMat *materials.Material
|
debugDepthMat *materials.Material
|
||||||
|
|
||||||
|
skyboxCmap assets.Cubemap
|
||||||
)
|
)
|
||||||
|
|
||||||
type OurGame struct {
|
type OurGame struct {
|
||||||
@ -169,6 +171,15 @@ func (g *OurGame) Init() {
|
|||||||
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
|
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skyboxCmap, err = assets.LoadCubemapTextures(
|
||||||
|
// "./res/textures/sb-right.jpg", "./res/textures/sb-left.jpg",
|
||||||
|
// "./res/textures/sb-top.jpg", "./res/textures/sb-bottom.jpg",
|
||||||
|
// "./res/textures/sb-front.jpg", "./res/textures/sb-back.jpg",
|
||||||
|
// )
|
||||||
|
// if err != nil {
|
||||||
|
// logging.ErrLog.Fatalln("Failed to load cubemap. Err: ", err)
|
||||||
|
// }
|
||||||
|
|
||||||
//Configure material
|
//Configure material
|
||||||
simpleMat.DiffuseTex = tex.TexID
|
simpleMat.DiffuseTex = tex.TexID
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user