/
texture.go
206 lines (188 loc) · 5.04 KB
/
texture.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package sge
import (
"unsafe"
)
import (
"github.com/chsc/gogl/gl33"
"github.com/klkblake/Go-SDL/sdl"
)
var activeTexture int
var boundTexture2D *Texture
var boundTexture2DArray *Texture
var boundTextureCubeMap *Texture
var boundTextureBuffer *Texture
type Texture struct {
Id gl33.Uint
Type gl33.Enum
Width int
Height int
}
func NewTexture2D() *Texture {
tex := new(Texture)
gl33.GenTextures(1, &tex.Id)
tex.Type = gl33.TEXTURE_2D
return tex
}
func NewTextureArray() *Texture {
tex := new(Texture)
gl33.GenTextures(1, &tex.Id)
tex.Type = gl33.TEXTURE_2D_ARRAY
return tex
}
func NewTextureCubeMap() *Texture {
tex := new(Texture)
gl33.GenTextures(1, &tex.Id)
tex.Type = gl33.TEXTURE_CUBE_MAP
return tex
}
func LoadTexture2D(filename string, minFilter int, magFilter int) *Texture {
ch := make(chan *Texture)
GL <- func() {
tex := NewTexture2D()
tex.SetFilters(minFilter, magFilter)
tex.Bind(0)
surface := sdl.Load(filename)
if surface == nil {
panic(sdl.GetError())
}
defer surface.Free()
tex.Width = int(surface.W)
tex.Height = int(surface.H)
uploadSurface(gl33.TEXTURE_2D, surface)
gl33.GenerateMipmap(gl33.TEXTURE_2D)
ch <- tex
}
return <-ch
}
func LoadTextureArray(filenames []string, minFilter int, magFilter int) *Texture {
ch := make(chan *Texture)
GL <- func() {
tex := NewTextureArray()
tex.SetFilters(minFilter, magFilter)
tex.Bind(0)
surfaces := make([]*sdl.Surface, len(filenames))
for i, filename := range filenames {
surfaces[i] = sdl.Load(filename)
if surfaces[i] == nil {
panic(sdl.GetError())
}
defer surfaces[i].Free()
}
tex.Width = int(surfaces[0].W)
tex.Height = int(surfaces[0].H)
var internalFormat gl33.Int
var format gl33.Enum
var size int
if surfaces[0].Format.BitsPerPixel == 32 {
internalFormat = gl33.RGBA8
format = gl33.RGBA
size = 4
} else {
internalFormat = gl33.RGB8
format = gl33.RGB
size = 3
}
pixels := make([]byte, tex.Width*tex.Height*len(surfaces)*size)
for i, surface := range surfaces {
p := uintptr(surface.Pixels)
for j := 0; j < tex.Width*tex.Height*size; j++ {
pixels[i*tex.Width*tex.Height*size+j] = *(*byte)(unsafe.Pointer(p + uintptr(j)))
}
}
gl33.TexImage3D(gl33.TEXTURE_2D_ARRAY, 0, internalFormat, gl33.Sizei(tex.Width), gl33.Sizei(tex.Height), gl33.Sizei(len(surfaces)), 0, format, gl33.UNSIGNED_BYTE, gl33.Pointer(&pixels[0]))
gl33.GenerateMipmap(gl33.TEXTURE_2D_ARRAY)
ch <- tex
}
return <-ch
}
func LoadTextureCubeMap(filenames *[6]string, minFilter int, magFilter int) *Texture {
ch := make(chan *Texture)
GL <- func() {
tex := NewTextureCubeMap()
tex.SetFilters(minFilter, magFilter)
tex.Bind(0)
var surfaces [6]*sdl.Surface
for i, filename := range filenames {
surfaces[i] = sdl.Load(filename)
if surfaces[i] == nil {
panic(sdl.GetError())
}
defer surfaces[i].Free()
}
tex.Width = int(surfaces[0].W)
tex.Height = int(surfaces[0].H)
uploadSurface(gl33.TEXTURE_CUBE_MAP_POSITIVE_X, surfaces[0])
uploadSurface(gl33.TEXTURE_CUBE_MAP_NEGATIVE_X, surfaces[1])
uploadSurface(gl33.TEXTURE_CUBE_MAP_POSITIVE_Y, surfaces[2])
uploadSurface(gl33.TEXTURE_CUBE_MAP_NEGATIVE_Y, surfaces[3])
uploadSurface(gl33.TEXTURE_CUBE_MAP_POSITIVE_Z, surfaces[4])
uploadSurface(gl33.TEXTURE_CUBE_MAP_NEGATIVE_Z, surfaces[5])
gl33.GenerateMipmap(gl33.TEXTURE_CUBE_MAP)
ch <- tex
}
return <-ch
}
func uploadSurface(target gl33.Enum, surface *sdl.Surface) {
if target == gl33.TEXTURE_CUBE_MAP && surface.W != surface.H {
panic("Non-square texture in cube map")
}
var internalFormat gl33.Int
var format gl33.Enum
if surface.Format.BitsPerPixel == 32 {
internalFormat = gl33.RGBA8
format = gl33.RGBA
} else {
internalFormat = gl33.RGB8
format = gl33.RGB
}
gl33.TexImage2D(target, 0, internalFormat, gl33.Sizei(surface.W), gl33.Sizei(surface.H), 0, format, gl33.UNSIGNED_BYTE, gl33.Pointer(surface.Pixels))
}
func UnbindTexture2D() {
if boundTexture2D != nil {
boundTexture2D.Unbind()
}
}
func UnbindTextureCubeMap() {
if boundTextureCubeMap != nil {
boundTextureCubeMap.Unbind()
}
}
func (tex *Texture) bound() **Texture {
switch tex.Type {
case gl33.TEXTURE_2D:
return &boundTexture2D
case gl33.TEXTURE_2D_ARRAY:
return &boundTexture2DArray
case gl33.TEXTURE_CUBE_MAP:
return &boundTextureCubeMap
case gl33.TEXTURE_BUFFER:
return &boundTextureBuffer
}
panic("Unsupported texture type")
}
func (tex *Texture) Bind(textureUnit int) {
if activeTexture != textureUnit {
gl33.ActiveTexture(gl33.Enum(gl33.TEXTURE0 + textureUnit))
activeTexture = textureUnit
}
bound := tex.bound()
if *bound != tex {
gl33.BindTexture(tex.Type, tex.Id)
*bound = tex
}
}
func (tex *Texture) Unbind() {
bound := tex.bound()
if *bound == tex {
gl33.BindTexture(tex.Type, 0)
*bound = nil
}
}
func (tex *Texture) Delete() {
gl33.DeleteTextures(1, &tex.Id)
}
func (tex *Texture) SetFilters(minFilter int, magFilter int) {
tex.Bind(0)
gl33.TexParameteri(tex.Type, gl33.TEXTURE_MIN_FILTER, gl33.Int(minFilter))
gl33.TexParameteri(tex.Type, gl33.TEXTURE_MAG_FILTER, gl33.Int(magFilter))
}