Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / Controlling Image Transparency
- - By RavensKrag Date 2010-08-05 19:23
Is there any way to control the transparency of a Gosu::Image object in Ruby?  I'm thinking of something analogous to the way layers of an image can be made more transparent in programs like photoshop or the GIMP. 

As for a use case, I'm trying to make a wall turn semi-transparent when the player's character walks behind it, thus allowing the player to maintain sight of his or her character.
Parent - - By Basic Date 2010-08-05 20:17
I think you can push the alpha into when you draw

image.draw(x, y, z, factor_x, factor_y, colour)

colour is by default 0xffffffff the first two 'ff's control the alpha (and the factors are 1 by default)
so you could do

image.draw(x, y, z, 1, 1, 0x33ffffff)
image.draw_rot(x, y, z, 0.5, 0.5, 1, 1, 0x33ffffff)

which would give you a semi transparent look.
Parent - - By RavensKrag Date 2010-08-05 20:39
Thank you so much.  Here I was, thinking I'd have to do some complex trick with Texplay to get this to work.  Classic example of over thinking I suppose ^_^; Yes, this is exactly what I was looking for.  Thanks again for such a speedy reply.
Parent - - By jlnr (dev) Date 2010-08-05 23:38
Note that you can even draw each corner of an image with a different alpha value by using #draw_as_quad. This makes it possible to add some smoothness to your effect if you are drawing the wall using a lot of tiles. Of course, the computation can be a bit ugly and even slow (in Ruby).
Parent - - By RavensKrag Date 2010-08-11 18:27
What about this process makes it "ugly and even slow" in ruby.  I assume that by singling out the ruby version, the problem does not occur in C++.  Would it be possible to replace some part with a native ruby gem to make the process go faster?

(Side note, I really need to figure out how to do that, the more I think of it, the more useful it seems to be able to write native gems...)
Parent - By Basic Date 2010-08-11 18:46
I think the the "ugly and slow" refers the fact that game logic in ruby can sometimes get a little out of hand when it comes to games. Its quite amazing how nice ruby is when making a website, and goes quite mental in other areas.

If you are going to the hassle to make ruby gems for your game you may as well do the game in C++ :) Well just my opinion.
Parent - - By jlnr (dev) Date 2010-08-12 04:21
If you want things to fade out smoothly in front of the player, depending on a tile's distance to them, you'd need to use four transparency values per tile (four corners). You'd have to calculate one transparency value per tile if you are good with reusing them.

It's not that the C++ code would be more beautiful, but my gut feeling says the Ruby code might take some CPU cycles while the C++ one won't. As soon as you start to have lots of loops and mathematical calculations, things usually get more dangerous.

That said, a smart Ruby implementation will probably be fast enough on common PCs, so I don't want to be too negative. Integrating Ruby with C++, on the other hand, is so ugly that it's worth avoiding IMHO :)
Parent - - By Spooner Date 2010-08-13 11:21
Yeah, that would probably be slow in Ruby, but you could cut the Gordian knot and just draw a big image over the tiles, centred on the player, which was transparent in the centre and fading to black at the edges. This would use more memory, to store the image, but it would remove the need for complex Ruby code. Whether it would actually be a lot faster is another question though. The secret to optimising Ruby, I think, is to offload everything you can to C using the _fewest_ Ruby commands, even if you wouldn't actually implement it that way in actual C because it would be inefficient. While you are there, why draw all your tiles every frame if you can draw them into a buffer image and only redraw when needed? Again, sacrificing memory for speed, but that might be a sacrifice that is worth making depending on what spec machine you are aiming for.

I also think it isn't a bad idea to program in Ruby and drop to C/C++ when you need to. A significant chunk of game code (e.g. options screens, saving the game, configuration, any stuff that just calls a binary gem to do all the work) probably isn't even processor limited, so why write all that in C when you can write it in Ruby and only drop down for actual bottlenecks?

Stuff like RubyInline make integration about as easy as it can get, I expect.

Disclaimer: Although I have often considered dropping to C, I have never actually needed it enough to get it working :$
Parent - - By jlnr (dev) Date 2010-08-13 12:25 Edited 2010-08-13 12:29

> which was transparent in the centre and fading to black at the edges


If the surroundings are really only black, then this would be *much* better in terms of performance and even looks! If the player is behind a textured wall stuff gets uglier though, even in C with OpenGL.

> While you are there, why draw all your tiles every frame if you can draw them into a buffer image and only redraw when needed?


Gosu contains undocumented code for recording all sorts of rendering code into a single macro (vertex array). Advantage being that you can actually still rotate and resize the resulting Image seamlessly, kind of like a vector image. The speed-up factor for drawing large tiled map is 1 to 100 or something like that even in C++. The problem is that it only works if all images happen to be placed on the same internal OpenGL texture. I wish I could finish this but I have some game content to churn out first :)
Parent - - By Spooner Date 2010-08-13 13:20
Yeah, if objects that shouldn't be faded are behind objects that should be then my optimisation does go very wrong of course, as it would if you wanted line-of-sight shading in a 2D maze. Still, the point was that there are tricks to massively optimise things that aren't immediately obvious and/or that seem more complex than the "slow" method on first appearances.

I assume that undocumented code is just usable in C++, not Ruby? Hmm, if the OpenGL texture Gosu currently uses is arbitrary, then I guess it is mostly useless in a real app (you could check via tex_info if images shared the same texture, but if they didn't, I suppose you couldn't do anything to fix it). I have done a little raw OpenGL in the distant past, so I remember utilising nested macros to render complex object hierarchies and I did wonder if not macroing stuff was a major reason frameworks like Gosu/SDL were relatively slow.
Parent - - By jlnr (dev) Date 2010-08-13 13:36 Edited 2010-08-13 13:38

> Still, the point was that there are tricks to massively optimise things that aren't immediately obvious and/or that seem more complex than the "slow" method on first appearances.


That is most definitely true! Also, those tricks are mad fun. If the wall would be single-colored, you could clip_to() the cutout field of view and make the illusion perfect.

> I assume that undocumented code is just usable in C++, not Ruby? Hmm, if the OpenGL texture Gosu currently uses is arbitrary, then I guess it is mostly useless in a real app (you could check via tex_info if images shared the same texture, but if they didn't, I suppose you couldn't do anything to fix it).


It is available in Ruby as Window#record { arbitrary_rendering_code_here; }, which returns a Gosu::Image, an interface of which I am very proud. ;) If you have less than 512x512 pixels of map tiles, you can just load your map tiles first and try it out (they should all be on texture 0).

> if not macroing stuff was a major reason frameworks like Gosu/SDL were relatively slow


There's only so much you can macro in 2D gamedev. All the objects, often simple quads, move relative to each other. People also animate or change tiles. Macro'ing the (static parts of the) map is a huge boost for Ruby games but not a massive improvement for a common C++ platformer. Especially OpenGL ES seems to be a pretty bad match for 2D games to me. Then again, 3D HW is unavoidable, and I think Gosu and other libs are doing pretty well at working *with* rather than *against* OpenGL. The SDL is the oddball example though, because its interface just doesn't suit any common hardware anymore :)
Parent - - By Spooner Date 2010-08-13 14:04

> If the wall would be single-colored, you could clip_to() the cutout field of view and make the illusion perfect.


Sorry, I don't understand why the wall would need to be single-coloured to be affected by being darkened by blitting semi-transparent black on top. I do that at the moment, though you could argue it isn't precisely the same effect you can get by altering the corner colours when rendering a quad. I'm just using flat black though, in order to fade out stuff in the background (Oops, I suddenly realised I could just alter the draw colour of each thing that is faded out and get the same effect!).

> If you have less than 512x512 pixels of map tiles, you can just load your map tiles first and try it out (they should all be on texture 0).


Unfortunately, my assets are user-edited, so quite arbitrary in number and sizes. Nice to know the option is there for other projects though (or the original poster). Hmm, just thought: Can I macro drawing commands as well? They don't use textures, do they? So texture-sharing wouldn't matter, would it?

>  All the objects, often simple quads, move relative to each other.


Actually, that would suit me, since each of my moving objects is made up of multiple non-animating images (essentially, each discrete object is made up of an arbitrary number of image layers; so a man would be head layer, body layer, arms layer, etc). I was planning to cache the combined image and render that to speed things up. Still, since the user can make up an object out of an arbitrary number of layers of arbitrary size, no guarantee they would fit on a single GL texture even if it could be made to work that way.
Parent - - By jlnr (dev) Date 2010-08-13 19:15 Edited 2010-08-13 19:18

> Sorry, I don't understand why the wall would need to be single-coloured to be affected by being darkened by blitting semi-transparent black on top.


I understood that the OP wanted to make an existing foreground wall transparent, not darker, when the player moves behind it. Without any smooth-ness, that's no problem. If the wall is single-colored, you could use your idea and just draw a same-colored texture with a round, smooth cutout over the player and clip it to the old wall's boundaries. At least that's how I understood the idea :)

> Can I macro drawing commands as well? They don't use textures, do they? So texture-sharing wouldn't matter, would it?


Hmmm, I think they do not work yet. Since they *require* that no texture is selected, they will have the same texturing problem: they don't mix with anything else. I was thinking about putting a small white pixel on every texture so I can use that to do single-colored primitives no matter which texture is currently selected.
Parent - By Spooner Date 2010-08-13 19:23
Oops, yes, I had completely forgotten what the original post was about on the way. Sorry for adding confusion!

Adding a white pixel could make sense to allow draw macros; it wouldn't help me a massive amount, but I could see it being very useful in certain situations.
Parent - - By RavensKrag Date 2010-08-13 19:30

> I was planning to cache the combined image and render that to speed things up.


Most of your discussion on this topic has gone way over my head in the last 5 posts or so ^_^; However, I am using much the same system in my game, having the different parts of a person exist on different "layers" that are composited at runtime.  Though, mine are of a set size, so caching the composite image as a separate Gosu::Image using Texplay works fine for me.

>> which was transparent in the centre and fading to black at the edges
>
>If the surroundings are really only black, then this would be *much* better in terms of performance and even looks! If the player is behind a textured wall stuff gets >uglier though, even in C with OpenGL.


Would this process be merely ugly in Ruby? or would it be slow as well? I'm making a 2D game both in order to reduce computational complexity, as well as allow the game to be played to "decent" hardware.  By this I mean anything with an integrated graphics card that has been released relatively recently. 

Also, I would like to use textured walls, if at all possible.  In light of this, would it be better to just use #draw_as_quad or the image-which-fades-to-black method?
Parent - - By Spooner Date 2010-08-13 19:50
My suggestion was answering a different question, because my ability to read and comprehend is lacking , so you can safely ignore it. I'd somehow convinced myself you were trying to draw the background darker away from the player, such as if they were carrying a lamp in a dungeon. Don't ask...

Actually, I just had an epiphany, which was to draw everything normally, then draw the player a second time on top of everything at half normal alpha! This would have no effect when out in the open, but would make the player appear to be showing through the occluding wall. Oh well, just another option, though it wouldn't make the foreground object look transparent properly (you'd see the player through it, but not the background).

> Though, mine are of a set size, so caching the composite image as a separate Gosu::Image using Texplay works fine for me.


I could do that too, but either I have the problem of having a lot of very large images created at the start and take a hit to FPS to render them at full size even if the actual object is 10x10 pixels or create the required size images when they are needed which, due to Texplay image creation being very slow, would slow down level changes significantly. Oh well, I'll work something out, I'm sure.
Parent - - By RavensKrag Date 2010-08-13 21:00

> due to Texplay image creation being very slow


It is painfully slow isn't it? Glad it's not just me.  I have to find away around creating so many images in my game (that part is unrelated to this but... whatever).  It's so bad the framerate drops to 5fps in the worst case.

> such as if they were carrying a lamp in a dungeon.


Actually, I might do that later, so thank you for that suggestion.

> Actually, I just had an epiphany, which was to draw everything normally,
> then draw the player a second time on top of everything at half normal alpha!


This sounds cool, though it may or may not work for me.  I'll consider it, at least.  Thank you.

> ...I have the problem of having a lot of very large images created at the start...


Can't you do some sort of amortized cost thing and spread out the creation of images? Or you could cache them on the hard drive if you're going to use them on subsequent runs of the application.  I'm sure you've already though of this, but I thought I'd mention it just in case.
Parent - By Spooner Date 2010-08-14 08:57

> Can't you do some sort of amortized cost thing and spread out the creation of images? Or you could cache them on the hard drive if you're going to use them on subsequent runs of the application.


The problem with caching them on the disk is that once you use Texplay in your app, all creation of images is slowed down to cache the image ready for Texplay manipulation, whether they are created as blank images or loaded from the disk. I could disable caching on loaded images though, via a bit of Texplay monkey-patching, since they wouldn't be being further composited. Another problem comes when new level data is sent over the wire, since I'd need to send all the composited images as well as the layer images, rather than just send the layers and composite in a new image at the client-side (bandwidth goes up significantly then). Think I'll start up another thread about this issue of slow image creation/loading...
Parent - - By kyonides Date 2010-08-13 20:47
I wonder if you ever tried to save the composite player image or sprite in a file after the player selected his or her favorite combination so the game only needs to read the file to display it on screen.
Parent - By RavensKrag Date 2010-08-13 20:58
That's the next step for me, actually.  But I'm having a problem during image compositing.  Still, that's a problem for another thread, so I think I'll go start another one.
Up Topic Gosu / Gosu Exchange / Controlling Image Transparency

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill