/
texture.go
234 lines (203 loc) · 7.29 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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// Copyright 2014 The Azul3D Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gfx
import (
"image"
"sync"
)
// TexFormat specifies a single texture storage format.
type TexFormat uint8
// Bits returns the number of bits per color component in this texture format.
// For example:
// r, g, b, a := RGB.Bits()
// r == 8 && g == 8 && b == 8 && a == 0
// A panic will occur if the format is not one of the predefined ones in this
// package.
//
// ZeroTexFormat, DXT1, DXT3, and DXT5 formats will return only zero.
func (t TexFormat) Bits() (r, g, b, a uint8) {
switch t {
case RGB:
return 8, 8, 8, 0
case RGBA:
return 8, 8, 8, 8
case ZeroTexFormat:
return 0, 0, 0, 0
case DXT1:
return 0, 0, 0, 0
case DXT1RGBA:
return 0, 0, 0, 0
case DXT3:
return 0, 0, 0, 0
case DXT5:
return 0, 0, 0, 0
}
panic("invalid format")
}
const (
// ZeroTexFormat is the zero-value texture format, it is not a valid format
// and is mainly used to catch zero-value errors.
ZeroTexFormat TexFormat = iota
// RGBA is a standard 32-bit premultiplied alpha image format.
RGBA
// RGB is a standard 24-bit RGB image format with no alpha component.
RGB
// DXT1 is a DXT1 texture compression format in RGB form (i.e. fully
// opaque) each 4x4 block of pixels take up 64-bits of data, as such when
// compared to a standard 24-bit RGB format it provides a 6:1 compression
// ratio.
DXT1
// DXT1RGBA is a DXT1 texture compression format in RGBA form with 1 bit
// reserved for alpha (i.e. fully transparent or fully opaque per-pixel
// transparency).
DXT1RGBA
// DXT3 is a RGBA texture compression format with four bits per pixel
// reserved for alpha. Each 4x4 block of pixels take up 128-bits of data,
// as such when compared to a standard 32-bit RGBA format it provides a 4:1
// compression ratio. Color information stored in DXT3 is mostly the same
// as DXT1.
DXT3
// DXT5 is a RGBA format similar to DXT3 except it compresses the alpha
// chunk in a similar manner to DXT1's color storage. It provides the same
// 4:1 compression ratio as DXT3.
DXT5
)
// Downloadable represents a image that can be downloaded from the graphics
// hardware into system memory (e.g. for taking a screen-shot).
type Downloadable interface {
// Download should download the given intersecting rectangle of this
// downloadable image from the graphics hardware into system memory and
// send it to the complete channel when done.
//
// If downloading this texture is impossible (i.e. hardware does not
// support this) then nil will be sent over the channel and all future
// attempts to download this texture will fail as well.
//
// It should be noted that the downloaded image may not be pixel-identical
// to the previously uploaded source image of a texture, for instance if
// texture compression was used it may suffer from compression artifacts,
// etc.
//
// Only a texture created from render-to-texture is guaranteed to succeed,
// others may not (esp. compressed textures). Most devices support
// downloading RGB/A textures and some support depth/alpha ones.
Download(r image.Rectangle, complete chan image.Image)
}
// NativeTexture represents the native object of a *Texture, the device is
// responsible for creating these and fulfilling the interface.
type NativeTexture interface {
Destroyable
Downloadable
// ChosenFormat tells the texture format chosen by the device for storing
// this texture on the graphics device. It may differ from the Texture's
// Format field only if the graphics device does not support that format.
ChosenFormat() TexFormat
}
// Texture represents a single 2D texture that may be applied to a mesh for
// drawing.
//
// A texture and it's methods are not safe for access from multiple goroutines
// concurrently.
type Texture struct {
// The native object of this texture. Once the texture is loaded by a
// device this field will be initialized by the device. Only device
// implementations should assign values to this field.
NativeTexture
// Weather or not this texture is currently loaded or not. If Loaded is set
// false on a already-loaded texture, it will cause the device to reload
// the texture.
Loaded bool
// If true then when this texture is loaded the data image source of it
// will be kept instead of being set to nil (which allows it to be garbage
// collected).
KeepDataOnLoad bool
// Dynamic is a hint (it does not restrict how the texture may be used) to
// the graphics device on how this texture might be used. If you intend to
// update texture data often (i.e. it's not static) then set this to true.
Dynamic bool
// The bounds of the texture, in the case of a texture loaded from a image
// this should be set to the image's bounds. In the case of rendering to a
// texture this should be set to the desired canvas resolution.
Bounds image.Rectangle
// The source image of the texture, may be nil (i.e. in the case of render
// to texture, unless downloaded).
Source image.Image
// The texture format to use for storing this texture on the GPU, which may
// result in lossy conversions (e.g. RGB would lose the alpha channel, etc).
//
// If the format is not supported then the device may use an image format
// that is similar and is supported (and the format chosen by the device
// can be determined via NativeTexture's ChosenFormat method).
Format TexFormat
// The U and V wrap modes of this texture.
WrapU, WrapV TexWrap
// The color of the border when a wrap mode is set to BorderColor.
BorderColor Color
// The texture filtering used for minification and magnification of the
// texture.
MinFilter, MagFilter TexFilter
}
// Copy returns a new copy of this Texture. Explicitly not copied over is the
// native texture, the OnLoad slice, the Loaded status, and the source image
// (because the image type is not strictly known). Because the texture's source
// image is not copied over, you may want to copy it directly over yourself.
func (t *Texture) Copy() *Texture {
return &Texture{
nil, // Native texture -- not copied.
false, // Loaded status -- not copied.
t.KeepDataOnLoad,
t.Dynamic,
t.Bounds,
nil, // Source image -- not copied.
t.Format,
t.WrapU,
t.WrapV,
t.BorderColor,
t.MinFilter,
t.MagFilter,
}
}
// ClearData sets the data source image, t.Source, of this texture to nil if
// t.KeepDataOnLoad is set to false.
func (t *Texture) ClearData() {
if !t.KeepDataOnLoad {
t.Source = nil
}
}
// Reset resets this texture to it's default (NewTexture) state.
func (t *Texture) Reset() {
t.NativeTexture = nil
t.Loaded = false
t.KeepDataOnLoad = false
t.Dynamic = false
t.Bounds = image.Rectangle{}
t.Source = nil
t.Format = RGBA
t.WrapU = 0
t.WrapV = 0
t.BorderColor = Color{}
t.MinFilter = 0
t.MagFilter = 0
}
// Destroy destroys this texture for use by other callees to NewTexture. You
// must not use it after calling this method. This makes an implicit call to
// t.NativeTexture.Destroy.
func (t *Texture) Destroy() {
if t.NativeTexture != nil {
t.NativeTexture.Destroy()
}
t.Reset()
texturePool.Put(t)
}
var texturePool = sync.Pool{
New: func() interface{} {
t := &Texture{}
t.Reset()
return t
},
}
// NewTexture returns a new, initialized *Texture object.
func NewTexture() *Texture {
return texturePool.Get().(*Texture)
}