class Starfield(Widget): def __init__(self, **kwargs): Widget.__init__(self, **kwargs) self.canvas = RenderContext(use_parent_projection=True) self.canvas.shader.source = 'starfield.glsl' self.vfmt = ( ('vCenter', 2, 'float'), ('vScale', 1, 'float'), ('vPosition', 2, 'float'), ('vTexCoords0', 2, 'float'), ) self.vsize = sum(attr[1] for attr in self.vfmt) self.indices = [] for i in xrange(0, 4 * NSTARS, 4): self.indices.extend(( i, i + 1, i + 2, i + 2, i + 3, i)) self.vertices = [] for i in xrange(NSTARS): self.vertices.extend(( 0, 0, 1, -24, -24, 0, 1, 0, 0, 1, 24, -24, 1, 1, 0, 0, 1, 24, 24, 1, 0, 0, 0, 1, -24, 24, 0, 0, )) self.texture = Image('star.png').texture self.stars = [Star(self, i) for i in xrange(NSTARS)] def update_glsl(self, nap): x0, y0 = self.center max_distance = 1.1 * max(x0, y0) for i in xrange(NSTARS): star = self.stars[i] star.distance *= 2 * nap + 1 star.size += 0.25 * nap if (star.distance > max_distance): star.reset() else: star.update(x0, y0) self.canvas.clear() with self.canvas: Mesh(fmt=self.vfmt, mode='triangles', indices=self.indices, vertices=self.vertices, texture=self.texture)
class PSWidget(Widget): indices = [] vertices = [] particles = [] def __init__(self, **kwargs): Widget.__init__(self, **kwargs) self.canvas = RenderContext(use_parent_projection=True) self.canvas.shader.source = self.glsl self.vfmt = ( ('vCenter', 2, 'float'), ('vScale', 1, 'float'), ('vPosition', 2, 'float'), ('vTexCoords0', 2, 'float'), ) self.vsize = sum(attr[1] for attr in self.vfmt) self.texture, self.uvmap = load_atlas(self.atlas) def make_particles(self, Cls, num): count = len(self.particles) uv = self.uvmap[Cls.tex_name] for i in xrange(count, count + num): j = 4 * i self.indices.extend(( j, j + 1, j + 2, j + 2, j + 3, j)) self.vertices.extend(( 0, 0, 1, -uv.su, -uv.sv, uv.u0, uv.v1, 0, 0, 1, uv.su, -uv.sv, uv.u1, uv.v1, 0, 0, 1, uv.su, uv.sv, uv.u1, uv.v0, 0, 0, 1, -uv.su, uv.sv, uv.u0, uv.v0, )) p = Cls(self, i) self.particles.append(p) def update_glsl(self, nap): for p in self.particles: p.advance(nap) p.update() self.canvas.clear() with self.canvas: Mesh(fmt=self.vfmt, mode='triangles', indices=self.indices, vertices=self.vertices, texture=self.texture)
class Screen(Widget): def __init__(self, **kwargs): self.canvas = RenderContext() self.pressed_keys = set() Window.bind(on_key_down=self.key_down) Window.bind(on_key_up=self.key_up) super().__init__(**kwargs) def key_down(self, _, key, *args): self.pressed_keys.add(key) def key_up(self, _, key, *args): self.pressed_keys.discard(key) def render(self, delta): """Override this method and render graphics""" def update(self, delta): """Override this method for updating state""" def on_create(self): """Called when initialized from screen manager""" def on_destroy(self): """Called when removed from screen manager""" def on_open(self): """Called when the screen is opened""" def on_close(self): """Called when the screen is closed""" def on_resize(self, width: int, height: int): """Called on window resize""" def clear(self): self.canvas.clear() def set_projection_matrix(self, matrices): self.canvas['projection_mat'] = matrices[0] self.canvas['modelview_mat'] = matrices[1] def render_screen(self, delta): """Wrapper method for render, should not be overrided""" with self.canvas: self.render(delta)
class PSWidget(Widget): indices = [] vertices = [] particles = [] def __init__(self, **kwargs): Widget.__init__(self, **kwargs) self.canvas = RenderContext(use_parent_projection=True) self.canvas.shader.source = self.glsl self.vfmt = ( ('vCenter', 2, 'float'), ('vScale', 1, 'float'), ('vPosition', 2, 'float'), ('vTexCoords0', 2, 'float'), ) self.vsize = sum(attr[1] for attr in self.vfmt) self.texture, self.uvmap = load_atlas(self.atlas) def make_particles(self, Cls, num): count = len(self.particles) uv = self.uvmap[Cls.tex_name] for i in xrange(count, count + num): j = 4 * i self.indices.extend((j, j + 1, j + 2, j + 2, j + 3, j)) self.vertices.extend(( 0, 0, 1, -uv.su, -uv.sv, uv.u0, uv.v1, 0, 0, 1, uv.su, -uv.sv, uv.u1, uv.v1, 0, 0, 1, uv.su, uv.sv, uv.u1, uv.v0, 0, 0, 1, -uv.su, uv.sv, uv.u0, uv.v0, )) p = Cls(self, i) self.particles.append(p) def update_glsl(self, nap): for p in self.particles: p.advance(nap) p.update() self.canvas.clear() with self.canvas: Mesh(fmt=self.vfmt, mode='triangles', indices=self.indices, vertices=self.vertices, texture=self.texture)
class Console(Widget): _vertices = [] _indices = [] _vfmt = ( (b'vCenter', 2, 'float'), (b'vPosition', 2, 'float'), (b'vTexCoords0', 2, 'float'), (b'vColor', 3, 'float'), (b'isTexFlag', 1, 'float'), ) _vsize = sum(i[1] for i in _vfmt) _fg_color = (1.0, 1.0, 1.0) _bg_color = (0.0, 0.0, 0.0) _shader = 'console.glsl' _font_source = 'terminal8x12_gs_ro.png' _font_size = (8, 12) def __init__(self, screen_size, font_source=None, font_size=None, fg_color=None, bg_color=None, **kwargs): super().__init__(**kwargs) self.screen_size = screen_size self.fg_color = fg_color or self._fg_color self.bg_color = bg_color or self._bg_color self.font_source = font_source or self._font_source self.font_size = font_size or self._font_size self.font_tex, self.font_map = load_font(self.font_source, self.font_size) self.canvas = RenderContext(use_parent_projection=True) self.canvas.shader.source = self._shader self.console_bg_color() @property def max_indice(self): return max(self._indices) + 1 if self._indices else 0 def get_pixel_pos(self, pos, is_bg=False): font_w, font_h = self.font_size tx, ty = pos w, h = font_w * 0.5, font_h * 0.5 x, y = (tx * font_w) + w, (ty * font_h) + h if is_bg: x, y = tx * font_w, ty * font_h return x, y def get_console_pos(self, pos): # TODO: Assuming that the pos coords could be referring to any pixel # within the font size, I need to get the relative bottom right # coords and use that for the tx, ty values instead. This will # increase the accuracy of the translation. font_w, font_h = self.font_size tx, ty = pos x, y = tx / font_w, ty / font_h return round(x, 0), round(y, 0) def console_bg_color(self): self.put_rect((0, 0), self.screen_size, self.bg_color) def put_char(self, char, pos, color=None): x, y = self.get_pixel_pos(pos) r, g, b = color or self.fg_color idx = self.max_indice uv = self.font_map.get(ord(char)) or self.uvmap.get(ord(' ')) self._vertices.extend(( x, y, -uv.su, -uv.sv, uv.u0, uv.v1, r, g, b, 1, x, y, uv.su, -uv.sv, uv.u1, uv.v1, r, g, b, 1, x, y, uv.su, uv.sv, uv.u1, uv.v0, r, g, b, 1, x, y, -uv.su, uv.sv, uv.u0, uv.v0, r, g, b, 1, )) self._indices.extend(( idx, idx + 1, idx + 2, idx + 2, idx + 3, idx )) def put_bg_color(self, pos, color): font_w, font_h = self.font_size x, y = self.get_pixel_pos(pos, is_bg=True) r, g, b = color idx = self.max_indice self._vertices.extend(( x, y, 0, 0, 0, 0, r, g, b, 0, x, y, font_w, 0, 0, 0, r, g, b, 0, x, y, font_w, font_h, 0, 0, r, g, b, 0, x, y, 0, font_h, 0, 0, r, g, b, 0, )) self._indices.extend(( idx, idx + 1, idx + 2, idx + 2, idx + 3, idx )) def put_text(self, text, pos, color=None, wrap=None): x, y = pos start_x = x ctr = 0 for char in iter(text): if isinstance(wrap, int) and ctr >= wrap: ctr = 0 x = start_x y -= 1 if not char.strip() and x == start_x: continue self.put_char(char, pos=(x, y), color=color) x += 1 ctr += 1 def put_rect(self, pos, size, color): font_w, font_h = self.font_size w, h = size x, y = self.get_pixel_pos(pos, is_bg=True) r, g, b = color idx = self.max_indice self._vertices.extend(( x, y, 0, 0, 0, 0, r, g, b, 0, x, y, w * font_w, 0, 0, 0, r, g, b, 0, x, y, w * font_w, h * font_h, 0, 0, r, g, b, 0, x, y, 0, h * font_h, 0, 0, r, g, b, 0, )) self._indices.extend(( idx, idx + 1, idx + 2, idx + 2, idx + 3, idx )) def flush(self): self.canvas.clear() with self.canvas: Mesh(fmt=self._vfmt, mode='triangles', indices=self._indices, vertices=self._vertices, texture=self.font_tex)
def clear(self, canvas: RenderContext): canvas.clear()
class PSWidget(Widget): """ Abstract class to handle all sprite rendering An instance of this renderer will only hold a single source of texture. """ indices = [] vertices = [] particles = [] def __init__(self, **kwargs): super(PSWidget, self).__init__(**kwargs) self.canvas = RenderContext(use_parent_projection=True) self.canvas.shader.source = self.glsl self.vfmt = ( (b'vCenter', 2, 'float'), (b'vScale', 1, 'float'), (b'vPosition', 2, 'float'), (b'vTexCoords0', 2, 'float'), ) self.vsize = sum(attr[1] for attr in self.vfmt) self.texture, self.uvmap = load_atlas(self.atlas) def make_particles(self, Cls, num): """ Convenience method to add a large number (`num`) of similar particles Parameters ---------- Cls (obj) - Particle class instance. This should implement a `tex_name` property to lookup the correct sprite in the UV mapping. num (int) - Number of particles to add. """ count = len(self.particles) uv = self.uvmap[Cls.tex_name] for i in range(count, count + num): j = 4 * i self.indices.extend(( j, j + 1, j + 2, j + 2, j + 3, j)) self.vertices.extend(( 0, 0, 1, -uv.su, -uv.sv, uv.u0, uv.v1, 0, 0, 1, uv.su, -uv.sv, uv.u1, uv.v1, 0, 0, 1, uv.su, uv.sv, uv.u1, uv.v0, 0, 0, 1, -uv.su, uv.sv, uv.u0, uv.v0, )) p = Cls(self, i) self.particles.append(p) def update_glsl(self, nap): """ Update the canvas. NOTES: Take the ff. into consideration when optimization is necessary: The particles update loop: - This loop should parallelized in full or partially. - This could also be run on another thread completely, and not update on every frame. This may apply to selected particle sub-classes, i.e. stuff in the background that doesn't affect program flow. Parameters ---------- nap (float) - TODO """ # Update the state of all particles for p in self.particles: p.advance(nap) p.update() # Draw the changes self.canvas.clear() with self.canvas: Mesh(fmt=self.vfmt, mode='triangles', indices=self.indices, vertices=self.vertices, texture=self.texture)
class Game(Widget): '''Game renderer''' REPLACE_CURSOR = False def __init__(self, **kwargs): self.canvas = RenderContext(use_parent_modelview=True, use_parent_projection=True) self.canvas.shader.source = resource_find('game.glsl') Widget.__init__(self, **kwargs) self.blending_is_broken = blending_is_broken() self.tex, self.tex_uv = load_tex_uv('a.atlas') update_tex_uv(self.tex_uv) self.root_note = NOTES[0] self.scale_class = SCALES[0] self.scale = self.scale_class(self.root_note) self.tuning = TUNING_DEFAULT self.build(False) from kivy.core.window import Window global g_window g_window = Window def build(self, updating=True): fretboard = build_fretboard(self.scale, self.tuning) if Game.REPLACE_CURSOR: self.begin_cursor = len(fretboard) * VERTEX_SIZE * 4 fretboard += [Quad(x=0, y=0, size=1, tex='cursor')] self.indices = [] ix = self.indices.extend for c in range(0, len(fretboard) << 2, 4): ix((c, c + 1, c + 2, c + 2, c + 3, c)) self.vertices = [] vx = self.vertices.extend self.animate = set() for i, o in enumerate(fretboard): uv = self.tex_uv[o[3]] vx(( o[0], o[1], o[2], -uv[4], -uv[5], uv[0], uv[1], o[0], o[1], o[2], uv[4], -uv[5], uv[2], uv[1], o[0], o[1], o[2], uv[4], uv[5], uv[2], uv[3], o[0], o[1], o[2], -uv[4], uv[5], uv[0], uv[3], )) if o[2] < 1: self.animate.add(i) if updating: self.set_updating() self.update_heading() def set_updating(self): Clock.unschedule(self.update_glsl) Clock.schedule_interval(self.update_glsl, 60 ** -1) on_start = set_updating def update_glsl(self, nap): ''' https://github.com/kivy/kivy/issues/2178 if Game.REPLACE_CURSOR: cur_x, cur_y = g_window.mouse_pos cur_x += CURSOR_OFFSET_X cur_y += CURSOR_OFFSET_Y for c in (self.begin_cursor, self.begin_cursor + VERTEX_SIZE, self.begin_cursor + VERTEX_SIZE * 2, self.begin_cursor + VERTEX_SIZE * 3): self.vertices[c] = cur_x self.vertices[c + 1] = cur_y ''' if self.animate: for i in self.animate.copy(): idx = i * VERTEX_SIZE * 4 + 2 val = self.vertices[idx] * (nap * 25 + 1) if val >= 1: val = 1 self.animate.remove(i) for c in (idx, idx + VERTEX_SIZE, idx + VERTEX_SIZE * 2, idx + VERTEX_SIZE * 3): self.vertices[c] = val if not self.animate and not Game.REPLACE_CURSOR: Clock.unschedule(self.update_glsl) self.canvas.clear() if self.blending_is_broken: self.canvas.before.add(select_blend_func) self.canvas.after.add(reset_blend_func) self.canvas.add(Mesh(indices=self.indices, vertices=self.vertices, fmt=VERTEX_FORMAT, mode='triangles', texture=self.tex)) def set_root_note(self, root_note): self.root_note = root_note self.scale = self.scale_class(self.root_note) self.build() def set_scale_class(self, scale_class): self.scale_class = scale_class self.scale = self.scale_class(self.root_note) self.build() def set_tuning(self, tuning): self.tuning = tuning self.build() _heading = None def update_heading(self): if self._heading: self._heading.text = u'%s \u2013 %s tuning' % (unicode(self.scale), self.tuning['name']) set_animooted = lambda self, val: set_ani(val)
class PSWidget(Widget): #widget sınıfı oluşturuldu. indices = [] #indis listesi vertices = [] #köşe listesi particles = [] #particles listesi def __init__(self, **kwargs): #Pencere ayarlaması yapıldı. Widget.__init__(self, **kwargs) self.canvas = RenderContext(use_parent_projection=True) self.canvas.shader.source = self.glsl self.vfmt = ( (b'vCenter', 2, 'float'), (b'vScale', 1, 'float'), (b'vPosition', 2, 'float'), (b'vTexCoords0', 2, 'float'), ) self.vsize = sum(attr[1] for attr in self.vfmt) self.texture, self.uvmap = load_atlas(self.atlas) def make_particles(self, Cls, num): #Particle oluşturma fonksiyonu tanımlandı. count = len(self.particles) uv = self.uvmap[Cls.tex_name] for i in range(count, count + num): j = 4 * i self.indices.extend((j, j + 1, j + 2, j + 2, j + 3, j)) self.vertices.extend(( #particle konumlanması amaçlandı. 0, 0, 1, -uv.su, -uv.sv, uv.u0, uv.v1, 0, 0, 1, uv.su, -uv.sv, uv.u1, uv.v1, 0, 0, 1, uv.su, uv.sv, uv.u1, uv.v0, 0, 0, 1, -uv.su, uv.sv, uv.u0, uv.v0, )) p = Cls(self, i) self.particles.append(p) def update_glsl(self, nap): #update fonksiyonu oluşturuldu. for p in self.particles: p.advance(nap) #advance fonksiyonu çağırıldı. p.update() #update fonksiyonu çağırıldı. self.canvas.clear() #pencerenin temizlenmesi sağlandı. with self.canvas: Mesh(fmt=self.vfmt, mode='triangles', indices=self.indices, vertices=self.vertices, texture=self.texture)
class Starfield(Widget): def __init__(self, **kwargs): super(Starfield, self).__init__(**kwargs) self.canvas = RenderContext(use_parent_projection=True) self.canvas.shader.source = 'starfield.glsl' self.vfmt = ( (b'vCenter', 2, 'float'), # Denotes the star's center point on # the screen. (b'vScale', 1, 'float'), # The star's scale factor. 1 being # the original size (48x48 px) (b'vPosition', 2, 'float'), # Position of each vertex relative # to the star's center point. (b'vTexCoords0', 2, 'float'), # Refers to texture coordinates. ) # Note the length of a single vertex in the array of vertices self.vsize = sum(attr[1] for attr in self.vfmt) self.indices = [] for i in range(0, 4 * NSTARS, 4): self.indices.extend(( i, i + 1, i + 2, i + 2, i + 2, i + 3, i )) # Essentially, the vertices contain all the data about our stars that # we need to retain, however this is not ideal to operate on. # So instead, we create a `Star()` class to encapsulate the operations # and computations. It will also contain additional properties such as # size, angle, distance from center, etc. self.vertices = [] for i in range(NSTARS): self.vertices.extend(( 0, 0, 1, -24, -24, 0, 1, 0, 0, 1, 24, -24, 1, 1, 0, 0, 1, 24, 24, 1, 0, 0, 0, 1, -24, 24, 0, 0, )) self.texture = Image('assets/star.png').texture self.stars = [Star(self, i) for i in range(NSTARS)] def update_glsl(self, nap): """ Implement the starfield motion algorithm. """ # Determine the max distance a star will travel based on the starfield # widget's center. x0, y0 = self.center max_distance = 1.1 * max(x0, y0) for star in self.stars: # We then move the stars towards the max_distance, enlarging it at # the same time. When it reaches the max_distance, we reset it. star.distance *= 2 * nap + 1 star.size += 0.25 * nap if star.distance > max_distance: star.reset() else: star.update(x0, y0) # Finally we draw them on the canvas self.canvas.clear() with self.canvas: Mesh(fmt=self.vfmt, mode='triangles', indices=self.indices, vertices=self.vertices, texture=self.texture)
class Game(Widget): '''Game renderer''' REPLACE_CURSOR = False def __init__(self, **kwargs): self.canvas = RenderContext(use_parent_modelview=True, use_parent_projection=True) self.canvas.shader.source = resource_find('game.glsl') Widget.__init__(self, **kwargs) self.blending_is_broken = blending_is_broken() self.tex, self.tex_uv = load_tex_uv('a.atlas') update_tex_uv(self.tex_uv) self.root_note = NOTES[0] self.scale_class = SCALES[0] self.scale = self.scale_class(self.root_note) self.tuning = TUNING_DEFAULT self.build(False) from kivy.core.window import Window global g_window g_window = Window def build(self, updating=True): fretboard = build_fretboard(self.scale, self.tuning) if Game.REPLACE_CURSOR: self.begin_cursor = len(fretboard) * VERTEX_SIZE * 4 fretboard += [Quad(x=0, y=0, size=1, tex='cursor')] self.indices = [] ix = self.indices.extend for c in range(0, len(fretboard) << 2, 4): ix((c, c + 1, c + 2, c + 2, c + 3, c)) self.vertices = [] vx = self.vertices.extend self.animate = set() for i, o in enumerate(fretboard): uv = self.tex_uv[o[3]] vx(( o[0], o[1], o[2], -uv[4], -uv[5], uv[0], uv[1], o[0], o[1], o[2], uv[4], -uv[5], uv[2], uv[1], o[0], o[1], o[2], uv[4], uv[5], uv[2], uv[3], o[0], o[1], o[2], -uv[4], uv[5], uv[0], uv[3], )) if o[2] < 1: self.animate.add(i) if updating: self.set_updating() self.update_heading() def set_updating(self): Clock.unschedule(self.update_glsl) Clock.schedule_interval(self.update_glsl, 60**-1) on_start = set_updating def update_glsl(self, nap): ''' https://github.com/kivy/kivy/issues/2178 if Game.REPLACE_CURSOR: cur_x, cur_y = g_window.mouse_pos cur_x += CURSOR_OFFSET_X cur_y += CURSOR_OFFSET_Y for c in (self.begin_cursor, self.begin_cursor + VERTEX_SIZE, self.begin_cursor + VERTEX_SIZE * 2, self.begin_cursor + VERTEX_SIZE * 3): self.vertices[c] = cur_x self.vertices[c + 1] = cur_y ''' if self.animate: for i in self.animate.copy(): idx = i * VERTEX_SIZE * 4 + 2 val = self.vertices[idx] * (nap * 25 + 1) if val >= 1: val = 1 self.animate.remove(i) for c in (idx, idx + VERTEX_SIZE, idx + VERTEX_SIZE * 2, idx + VERTEX_SIZE * 3): self.vertices[c] = val if not self.animate and not Game.REPLACE_CURSOR: Clock.unschedule(self.update_glsl) self.canvas.clear() if self.blending_is_broken: self.canvas.before.add(select_blend_func) self.canvas.after.add(reset_blend_func) self.canvas.add( Mesh(indices=self.indices, vertices=self.vertices, fmt=VERTEX_FORMAT, mode='triangles', texture=self.tex)) def set_root_note(self, root_note): self.root_note = root_note self.scale = self.scale_class(self.root_note) self.build() def set_scale_class(self, scale_class): self.scale_class = scale_class self.scale = self.scale_class(self.root_note) self.build() def set_tuning(self, tuning): self.tuning = tuning self.build() _heading = None def update_heading(self): if self._heading: self._heading.text = u'%s \u2013 %s tuning' % (unicode( self.scale), self.tuning['name']) set_animooted = lambda self, val: set_ani(val)