Description
I'm encountering some strange behavior when rendering textures.
Basically, when I render one texture, it interacts with any textures rendered previously.
Examples
Here's the most simple example of my problem:
Most simple example
The following code consistently renders a black screen for me, despite secondary_buffer
never being draw. If you alter the order of the primary_buffer
and secondary_buffer
renders in #update
, then it draws the 250x250 red square at (0,0) as expected.
require 'gosu'
require 'ashton'
class TestGame < Gosu::Window
def initialize
super(500, 500, false)
end
def update
primary_buffer.render do
pixel.draw 0, 0, 0, 250, 250, 0xaaff0000 # RED
end
secondary_buffer.render do
pixel.draw 250, 250, 0, 250, 250, 0xaa00ff00 # GREEN
end
end
def draw
primary_buffer.draw 0, 0, 0
end
end
TestGame.new.show
Rendering onto another texture
That remains the same if I try to render onto another texture, and then render that. (This isn't terribly surprising to me, but I know essentially nothing about OpenGL, so I'm not sure that it shouldn't be surprising...)
require 'gosu'
require 'ashton'
class TestGame < Gosu::Window
def initialize
super(500, 500, false)
@screen = Ashton::WindowBuffer.new
end
def update
primary_buffer.render do
pixel.draw 0, 0, 0, 250, 250, 0xaaff0000 # RED
end
secondary_buffer.render do
pixel.draw 250, 250, 0, 250, 250, 0xaa00ff00 # GREEN
end
@screen.render do
primary_buffer.draw 0, 0, 0
end
end
def draw
@screen.draw 0, 0, 0
end
end
TestGame.new.show
Retroactive interaction?
The craziest thing is that it actually seems like it is effecting things retroactively. Even if I render primary_buffer
and then immediately draw it to @screen,
a subsequent render to secondary_buffer
, which is never drawn, messes that up.
In the following example, I have made secondary_buffer
not render for 1 second at the beginning to show this effect more clearly.
require 'gosu'
require 'ashton'
class TestGame < Gosu::Window
def initialize
super(500, 500, false)
@screen = Ashton::WindowBuffer.new
end
def update
primary_buffer.render do
pixel.draw 0, 0, 0, 250, 250, 0xaaff0000 # RED
end
@screen.render do
primary_buffer.draw 0, 0, 0
end
if Gosu::milliseconds > 1000
secondary_buffer.render do
pixel.draw 250, 250, 0, 250, 250, 0xaa00ff00 # GREEN
end
end
end
def draw
@screen.draw 0, 0, 0
end
end
TestGame.new.show
Insanity with many textures
I honestly thought this was a pretty simple interaction, and so I decided to make an example with a bunch of textures to show it. But to my surprise, it worked as expected (well, the colors were slightly dimmer than expected, but we can't have everything, can we?). So I removed some, and my head exploded, because apparently it's all rather more complicated than I thought.
require 'gosu'
require 'ashton'
class TestGame < Gosu::Window
def initialize
super(600, 600, false)
@a = Ashton::WindowBuffer.new
@b = Ashton::WindowBuffer.new
@c = Ashton::WindowBuffer.new
@d = Ashton::WindowBuffer.new
@e = Ashton::WindowBuffer.new
@f = Ashton::WindowBuffer.new
@g = Ashton::WindowBuffer.new
@h = Ashton::WindowBuffer.new
@i = Ashton::WindowBuffer.new
@renders = [
proc { @a.render { pixel.draw 0, 0, 0, 200, 200, 0xaaff0000 } }, # RED at ( 0, 0)
proc { @b.render { pixel.draw 200, 0, 0, 200, 200, 0xaa00ff00 } }, # GREEN at (200, 0)
proc { @c.render { pixel.draw 400, 0, 0, 200, 200, 0xaa0000ff } }, # BLUE at (400, 0)
proc { @d.render { pixel.draw 0, 200, 0, 200, 200, 0xaaffff00 } }, # YELLOW at ( 0, 200)
proc { @e.render { pixel.draw 200, 200, 0, 200, 200, 0xaaffffff } }, # WHITE at (200, 200)
proc { @f.render { pixel.draw 400, 200, 0, 200, 200, 0xaaff00ff } }, # PURPLE at (400, 200)
proc { @g.render { pixel.draw 0, 400, 0, 200, 200, 0xaa00ffff } }, # CYAN at ( 0, 400)
# proc { @h.render { pixel.draw 200, 400, 0, 200, 200, 0xaa333333 } }, # DARKGRAY at (200, 400)
# proc { @i.render { pixel.draw 400, 400, 0, 200, 200, 0xaa999999 } }, # LIGHTGRAY at (400, 400)
]
@draws = [
proc { @a.draw 0, 0, 0 },
proc { @b.draw 0, 0, 0 },
proc { @c.draw 0, 0, 0 },
proc { @d.draw 0, 0, 0 },
proc { @e.draw 0, 0, 0 },
proc { @f.draw 0, 0, 0 },
proc { @g.draw 0, 0, 0 },
# proc { @h.draw 0, 0, 0 },
# proc { @i.draw 0, 0, 0 },
]
end
def update
@renders.map &:call
end
def draw
@draws.map &:call
end
end
TestGame.new.show
But the real icing on the cake is when you uncomment @h
and @i
above and change update to @renders.shuffle.map &:call
(spoiler alert: you probably shouldn't do this if you are prone to seizures).
It's worth noting that shuffling the draws does not seem to affect anything.
So... what?
So, am I just doing something wrong? Or is my computer broken? Or is this a big bug?
For reference, I'm running on Windows 8.1 with Ruby 1.9.3 and the latest versions of Ashton (from Git) and Gosu (0.8.3).