Skip to content

Commit b65bf97

Browse files
committed
particles texture can be per-instance
1 parent 8440ee8 commit b65bf97

File tree

2 files changed

+42
-24
lines changed

2 files changed

+42
-24
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
v? - ?
2+
- particle systems can have a per-instance custom texture, #264
23
- fix traceback in test_tmx_hexmap.py with py35, #263
34
- autocompletion friendly, #261
45
- fix changes in pyglet.sprite.Sprite properties break cocos Sprites #260

cocos/particle.py

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,14 @@ class ExceptionNoEmptyParticle(Exception):
7777
"""particle system have no room for another particle"""
7878
pass
7979

80+
8081
rand = lambda: random.random() * 2 - 1
8182

8283

8384
# PointerToNumpy by Gary Herron
8485
# from pyglet's user list
8586
def PointerToNumpy(a, ptype=ctypes.c_float):
86-
a = numpy.ascontiguousarray(a) # Probably a NO-OP, but perhaps not
87+
a = numpy.ascontiguousarray(a) # Probably a NO-OP, but perhaps not
8788
return a.ctypes.data_as(ctypes.POINTER(ptype)) # Ugly and undocumented!
8889

8990

@@ -100,14 +101,14 @@ def to_array(self):
100101

101102
class ParticleSystem(CocosNode):
102103
"""
103-
Base class for many flawors of cocos particle systems
104+
Base class for many flavors of cocos particle systems
104105
105106
The most easy way to customize is subclass and redefine some class members;
106107
see particle_systems by example.
107108
108-
If you want to use a custom texture remember it should hold only one image,
109-
so don't use texture = pyglet.resource.image(...) (it would produce an atlas,
110-
ie multiple images in a texture); using texture = pyglet.image.load(...) is fine
109+
To define a per-class custom texture override load_texture
110+
111+
To use a per-instance custom texture, pass it in the __init__ texture kw-param
111112
"""
112113

113114
# type of particle
@@ -171,7 +172,7 @@ class ParticleSystem(CocosNode):
171172
#: Maximum particles
172173
total_particles = 0
173174

174-
#: texture for the particles. Lazy loaded because Intel weakness, #235
175+
#: texture for the particles, to be filled in __init__ because Intel weakness, #235
175176
texture = None
176177

177178
#: blend additive
@@ -183,10 +184,10 @@ class ParticleSystem(CocosNode):
183184
# position type
184185
position_type = POSITION_GROUPED
185186

186-
def __init__(self, fallback=None):
187+
def __init__(self, fallback=None, texture=None):
187188
"""
188189
fallback can be None, True, False; default is None
189-
False: use point sprites, faster, not always availabel
190+
False: use point sprites, faster, not always available
190191
True: use quads, slower but always available)
191192
None: autodetect, use the faster available
192193
@@ -227,7 +228,15 @@ def __init__(self, fallback=None):
227228
#: auto remove when particle finishes
228229
self.auto_remove_on_finish = False
229230

230-
self.load_texture()
231+
# resolve which texture will be used
232+
if texture is None:
233+
# no explicit texture, the class default texture will be
234+
# implicitly used; ensure it is loaded
235+
if self.texture is None:
236+
self.load_texture()
237+
else:
238+
# the explicit texture provided will be used
239+
self.texture = texture
231240

232241
#: rendering mode; True is quads, False is point_sprites, None is auto fallback
233242
if fallback is None:
@@ -266,9 +275,17 @@ def _init_shader(self):
266275
self.particle_size_idx = gl.glGetAttribLocation(self.sprite_shader.program, b'particle_size')
267276

268277
def load_texture(self):
269-
if self.texture is None:
270-
pic = pyglet.image.load('fire.png', file=pyglet.resource.file('fire.png'))
271-
self.__class__.texture = pic.get_texture()
278+
"""sets the default texture used by all instances of particle systems with same class
279+
280+
Override this method to change the default texture
281+
282+
By issue #168 the texture should hold only one image, so don't use
283+
texture = pyglet.resource.image('z.png').texture (produces an atlas, ie multiple images in a texture)
284+
285+
using texture = pyglet.image.load(...).get_texture() is fine
286+
"""
287+
pic = pyglet.image.load('fire.png', file=pyglet.resource.file('fire.png'))
288+
self.__class__.texture = pic.get_texture()
272289

273290
def on_enter(self):
274291
super(ParticleSystem, self).on_enter()
@@ -334,7 +351,7 @@ def draw(self):
334351

335352
size_ptr = PointerToNumpy(self.particle_size_scaled)
336353
gl.glVertexAttribPointer(self.particle_size_idx, 1, gl.GL_FLOAT,
337-
False, 0, size_ptr)
354+
False, 0, size_ptr)
338355

339356
gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT)
340357
gl.glEnable(gl.GL_BLEND)
@@ -352,8 +369,8 @@ def draw(self):
352369
# glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE )
353370

354371
self.sprite_shader.install()
355-
self.sprite_shader.usetTex('sprite_texture', 0,
356-
gl.GL_TEXTURE_2D, self.texture.id)
372+
self.sprite_shader.usetTex('sprite_texture', 0,
373+
gl.GL_TEXTURE_2D, self.texture.id)
357374

358375
gl.glDrawArrays(gl.GL_POINTS, 0, self.total_particles)
359376

@@ -387,8 +404,8 @@ def step(self, delta):
387404
rate = 1.0 / self.emission_rate
388405
self.emit_counter += delta
389406

390-
# if random.random() < 0.01:
391-
# delta += 0.5
407+
# if random.random() < 0.01:
408+
# delta += 0.5
392409

393410
while self.particle_count < self.total_particles and self.emit_counter > rate:
394411
self.add_particle()
@@ -402,9 +419,9 @@ def step(self, delta):
402419
self.update_particles(delta)
403420

404421
if (not self.active and
405-
self.particle_count == 0 and self.auto_remove_on_finish is True):
406-
self.unschedule(self.step)
407-
self.parent.remove(self)
422+
self.particle_count == 0 and self.auto_remove_on_finish is True):
423+
self.unschedule(self.step)
424+
self.parent.remove(self)
408425

409426
def add_particle(self):
410427
"""
@@ -623,7 +640,7 @@ def make_delta_pos_to_vertex(self):
623640
size2 = self.particle_size / 2.0
624641

625642
# counter-clockwise
626-
self.delta_pos_to_vertex[:,0] = numpy.array([-size2, +size2]).T # NW
627-
self.delta_pos_to_vertex[:,1] = numpy.array([-size2, -size2]).T # SW
628-
self.delta_pos_to_vertex[:,2] = numpy.array([+size2, -size2]).T # SE
629-
self.delta_pos_to_vertex[:,3] = numpy.array([+size2, +size2]).T # NE
643+
self.delta_pos_to_vertex[:, 0] = numpy.array([-size2, +size2]).T # NW
644+
self.delta_pos_to_vertex[:, 1] = numpy.array([-size2, -size2]).T # SW
645+
self.delta_pos_to_vertex[:, 2] = numpy.array([+size2, -size2]).T # SE
646+
self.delta_pos_to_vertex[:, 3] = numpy.array([+size2, +size2]).T # NE

0 commit comments

Comments
 (0)