Hi Leif,
On 17-04-18 09:10 AM, Leif Theden wrote:
The renderer should have its own class, and for simplicity, I think it
should be instanced by calling a method on the window that contains
it. Just preference.
Having both a Window and a Renderer class makes sense if renderers are
cheap to create and discard. For practical purposes, a window's renderer
will live as long as it's window. If a Window class has a
create_renderer() method, then what happens when it is called more then
once. Also, what happens to the renderer instance when the window is
closed. Does the renderer keep a reference to the Window? Does the
Window keep a reference to the renderer? How is a reference cycle prevented?
To complicate matters, a window can have a display surface instead of a
renderer. So we add a create_surface() method. Now the Window class must
track whether it has a renderer or a surface. And a Pygame Surface does
not know about windows. So if we want the Surface instance to reference
a window we need a new WindowSurface subclass.
My thinking is if we need a WindowSurface to reference a window, then it
can directly manage the SDL window as well. The same goes for a
WindowRenderer Renderer subclass. Everything relating to a particular
window is in one convenient place. And when the window is closed, there
is only one, not two, dead objects lying around.
Now I have experimented with separate Window and Renderer. I found a
somewhat acceptable solution to the problems mentioned above. But it
still felt clunky. Then, when I combined the window and renderer into on
class, much of the complexity went away. The only real downside is that
the window management code, the window method definitions, will be
duplicated in both the WindowRenderer and WindowSurface classes. But
then that is just cut and paste, provide one remembers to do it.
Lenard Lindstrom
Renderer does not below with the draw module, because it is not for
drawing lines, and primitives on software surface. It is a
cross-platform and simple API for high-speed accelerated graphics with
textures and includes some facilities for drawing primitives.
==============================================================
What about something like this?
import pygame as pg
window = pg.display.new_window() # new Window class method
screen = pg.display.set_mode(...) # creates a new window, return
surface
renderer = window.create_renderer() # renderer, yay!
renderer = pg.renderer.Renderer(window) # alternative. "window" optional
surf = pg.image.load(filename)
texture = renderer.create_texture(surface=surf) # clean syntax?
texture = pg.texture.from_surface(surface, renderer) # alternative,
"renderer" optional
while running:
renderer.clear() # you should do this each frame
for tex, rect in textures:
renderer.render_copy(tex, rect) # this is analogous to "blit",
but is HW accel'd
renderer.present() # like display.flip()
==============================================================
# texture sprites
sprite = pg.sprite.TextureSprite()
sprite.texture = tex
sprite.rect = text.get_rect()
sprite.origin = 0, 0 # where the origin of texture is
sprite.rotation = 76 # rotation of the sprite
group = renderer.create_group(all_the_sprites, flags=0xDEADBEEF) # clean?
group = pg.sprite.TextureSpriteGroup(renderer) # alternative
==============================================================
# sample of a SpriteGroup
# Group.add
if hasattr(sprite, 'texture'):
raise ICannotDoThatDaveError # legacy group will not render a
texture sprite
# TextureSpriteGroup.draw
for sprite in self._hw_sprites:
renderer.render_copy_ex(sprite.tex,
None,
sprite.rect,
sprite.rotation,
sprite.origin,
sprite.flipped)
The group module should become simplified. Choose a group type that
works well for software sprites, and develop a new one for Renderers.
Add some checks to legacy groups to prevent Sprites with textures from
being added.
==============================================================
# pygame.display will be an alias for a Window
pygame.init()
window = pygame.display.get_window(0) # return instance of created
window
>>> window is pygame.display
True
==============================================================
# Consider the following
* When a renderer is created for a window, the window will raise an
exception if a blit or draw is attempted on it.
* All windows are py1 until a renderer is created on it.
* Once renderer is created, leave window in renderer mode. (or not?)
* Blits between software surfaces will always work, regardless of
the window mode.
screen = pg.display.set_mode(...) # automatic py1 window
screen.blit(legacy_cruft) # works!
renderer = pg.display.create_renderer() # works b/c display is alias
to first window
renderer = pg.renderer.Renderer() # implicit 1st window as
target of renderer
screen.blit(oops) # raise ThouShaltNotBlitError
pg.draw.lines(screen, ...) # raise
ThouShaltNotDrawUponThyScreenError
==============================================================
There is no way forward to give old pygame apps free performance. New
pygame apps will need to choose to use the accelerated graphics API,
or not.