While I can understand why you wouldn't like the create_XXXX syntax, I'm
not convinced that combining the window and the renderer makes sense for
the API.  As was mentioned, a window can have multiple renderers (or none
at all!), so I'm not sure what combining them together grants for pygame
users.


> Does the renderer keep a reference to the Window? Does the Window keep a
reference to the renderer? How is a reference cycle prevented?

I don't believe that you would need to keep references to a parent window
for renderers, or that you would need them for windows.  The SDL2 API will
take care of those details.  (hopefully?)

I don't agree that separate renderers and windows should feel clunky.
Pygame's API is rife with the pattern of creating objects for something,
then setting attributes and using them.  Why would it be any different if
you create a Renderer?

My last point about Windows tracking if they have a renderer or not (and
raising exceptions when using the old surface api) was simply a way to
allow the pygame API to remain backwards compatible and also use the
renderer api, if desired....Without resorting to different window classes,
as your API demo suggests.


On Wed, Apr 19, 2017 at 1:16 AM, Lenard Lindstrom <le...@telus.net> wrote:

> 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.
>>
>>
>>
>>
>

Reply via email to