Texture.load_gl()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 3
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
dl 3
loc 3
rs 10
c 1
b 0
f 0
1
2
from PIL import Image
3
4
from ed2d.opengl import gl, pgl
5
6
from ed2d.assets import hdr
7
8
9
def load_image(path):
10
    img = Image.open(path)
11
12
    # Verify that the image is in RGBA format
13
    if ''.join(img.getbands()) != 'RGBA':
14
        img = img.convert('RGBA')
15
16
    # Get image data as a list
17
    data = list(img.getdata())
18
19
    width, height = img.size
20
    return width, height, data
21
22
def load_image_hdr(path):
23
    myhdr = hdr.HDR()
24
    myhdrloader = hdr.HDRLoader()
25
    myhdrloader.load(path, myhdr)
26
27
    test = []
28
29
    for i in range(len(myhdr.cols) / 3):
30
        test.append([myhdr.cols[i], myhdr.cols[i + 1], myhdr.cols[i + 2]])
31
32
    return myhdr.width, myhdr.height, test
33
34
35
class BaseTexture(object):
36
    ''' Texture manager'''
37
    # Just for clarity
38
    # This is basically a static variable
39
    # It will be for assigning each texture unit id easily.
40
    # We use the id for calculating GL_TEXTUREi. This value propagates
41
    # down into the class instances also, even as it is changed. :D
42
    #
43
    # edit: decide if this would be better off as an __init__ method that
44
    # the subclasses call via super. Would be the best thing if we want to
45
    # have external subclasses of the BaseTexture.
46
47
    _textureCount = 0
48
49
    def _set_unit_id(self):
50
        self.texUnitID = self._textureCount
51
        BaseTexture._textureCount += 1
52
53
    def __init__(self, program):
54
55
        self.program = program
56
        self.texFormat = None
57
        self.pixelType = None
58
59
        self._set_unit_id()
60
61
    def load_gl(self):
62
63
        self.texSampID = self.program.new_uniform(b'textureSampler')
64
        self.texResID = self.program.new_uniform(b'textureResolution')
65
66
        if self.texFormat is None:
67
            self.texFormat = gl.GL_RGBA
68
        if self.pixelType is None:
69
            self.pixelType = gl.GL_UNSIGNED_BYTE
70
71
        # Load image into new opengl texture
72
        self.texID = pgl.glGenTextures(1)
73
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.texID)
74
        gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)
75
76
        gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
77
        gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
78
79
        pgl.glTexImage2D(gl.GL_TEXTURE_2D, 0, self.texFormat, self.width, self.height,
80
                         0, self.texFormat, self.pixelType, self.data)
81
82
    def bind(self):
83
        gl.glActiveTexture(gl.GL_TEXTURE0 + self.texUnitID)
84
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.texID)
85
        self.program.set_uniform(self.texSampID, self.texUnitID)
86
87
88 View Code Duplication
class HDRTexture(BaseTexture):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
89
90
    def __init__(self, path, program):
91
        super(HDRTexture, self).__init__(program)
92
        self.path = path
93
94
        self.texFormat = gl.GL_RGBA16F
95
        self.pixelType = gl.GL_FLOAT
96
97
        self.width, self.height, self.data = load_image_hdr(self.path)
98
99
        self.load_gl()
100
101
    def load_gl(self):
102
        super(HDRTexture, self).load_gl()
103
        self.program.set_uniform_array(self.texResID, [float(self.width), float(self.height)])
104
105 View Code Duplication
class Texture(BaseTexture):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
106
107
    def __init__(self, path, program):
108
        super(Texture, self).__init__(program)
109
        self.path = path
110
111
        self.texFormat = gl.GL_RGBA
112
        self.pixelType = gl.GL_UNSIGNED_BYTE
113
114
        self.width, self.height, self.data = load_image(self.path)
115
116
        self.load_gl()
117
118
    def load_gl(self):
119
        super(Texture, self).load_gl()
120
        self.program.set_uniform_array(self.texResID, [float(self.width), float(self.height)])
121
122
123
class TextureAtlas(BaseTexture):
124
    def __init__(self, program, maxWidth=1024, texFormat=None):
125
        super(TextureAtlas, self).__init__(program)
126
127
        self.program = program
128
129
        self.texFormat = texFormat
130
131
        # Data format will be as follows:
132
        #    Indexed by textureID
133
        #    value:
134
        #        - a second dict with information about that texture
135
        #            - x, y position in texture, width and height, texture
136
        #              data/uvcoords
137
        self.textures = []
138
        self.data = 0
139
        self.maxWidth = maxWidth
140
141
        self.width = 0
142
        self.height = 0
143
        self.cursorPosY = 0
144
        self.cursorPosX = 0
145
        self.lineHeight = 0
146
        self.maxSubTextureHeight = 0
147
148
    def add_texture(self, width, height, texData):
149
        textureID = len(self.textures)
150
151
        imgWidth = width
152
        imgHeight = height
153
154
        if (self.cursorPosX + imgWidth + 1) >= self.maxWidth:
155
156
            self.width = max(self.width, self.cursorPosX)
157
            self.cursorPosY += self.lineHeight
158
159
            self.maxSubTextureHeight = max(self.maxSubTextureHeight, self.lineHeight - 1)
160
161
            self.lineHeight = 0
162
            self.cursorPosX = 0
163
164
        x1 = self.cursorPosX
165
        x2 = self.cursorPosX + imgWidth
166
        y1 = self.cursorPosY
167
        y2 = self.cursorPosY + imgHeight
168
169
        self.cursorPosX += imgWidth + 1
170
        self.lineHeight = max(self.lineHeight, imgHeight + 1)
171
172
        self.textures.append({
173
                'x1': x1, 'x2': x2, 'y1': y1, 'y2': y2,
174
                'width': width, 'height': height,
175
                'texData': texData, 'uvCoords': None,
176
        })
177
        return textureID
178
179
    def get_uvcoords(self, texID):
180
181
        tex = self.textures[texID]
182
183
        x1 = tex['x1'] / float(self.width)
184
        x2 = tex['x2'] / float(self.width)
185
        y1 = tex['y1'] / float(self.height)
186
        y2 = tex['y2'] / float(self.height)
187
188
        coord = [[x1, y2],
189
                 [x2, y2],
190
                 [x1, y1],
191
                 [x2, y1]]
192
193
        return coord
194
195
    def get_vertex_scale(self, texID):
196
        '''
197
        Returns calculated vertex scaleing for textures by textureID
198
        This nomalizes all subtextures to the height of the tallest texture.
199
        This is done because the vertex data sent to the gpu is the same for
200
        each
201
        '''
202
203
        tex = self.textures[texID]
204
205
        imgWidth = tex['width']
206
        imgHeight = tex['height']
207
208
        vertScaleY = imgHeight / float(self.maxSubTextureHeight)
209
        vertScaleX = imgWidth / float(self.maxSubTextureHeight)
210
211
        return (vertScaleX, vertScaleY)
212
213
    def gen_atlas(self):
214
215
        self.cursorPosY += self.lineHeight
216
217
        self.width = max(self.width, self.cursorPosX)
218
        self.height = self.cursorPosY
219
220
        self.maxSubTextureHeight = max(self.maxSubTextureHeight, self.lineHeight - 1)
221
222
        self.load_gl()
223
224
        # add data to blank gl texture with
225
        # glTexSubImage2D here
226
        for tex in self.textures:
227
            x1 = tex['x1']
228
            y1 = tex['y1']
229
            width = tex['width']
230
            height = tex['height']
231
            texData = tex['texData']
232
233
            pgl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, x1, y1, width, height, self.texFormat, gl.GL_UNSIGNED_BYTE, texData)
234