Not logged inGosu Forums
Forum Gosu Homepage Help Search Register Login
Up Topic Gosu / Extending Gosu / TexPlay, drawing and hit-testing for Gosu::Image [from wiki]
1 2 Previous Next  
- By erisdiscord Date 2010-04-02 16:29 Edited 2010-04-02 16:35
If you need a tilemap class in Ruby, do have a look at my gosu-tmx. It's not complete, but contributors are welcome and encouraged.

Right now it loads TMX maps, of course, which can be made with the open source and cross platform Tiled. If I remember correctly, it doesn't handle maps where different layers have different tile sizes, but this could be added. It also only supports orthogonal maps, but these are probably what you want.

If you do make any changes, please let me know and send them back my way. :)

</shameless-self-promotion>
- By Wurstinator Date 2010-04-14 16:33
Well, as your tilemap is written in full ruby it won't be faster as a one I can write. And if I have the chance to write something on my own, I will always do it ;)
- By banister Date 2010-06-07 11:58 Edited 2010-06-12 03:48
TexPlay 0.2.910 released

provides:

* source_select, source_ignore, dest_select, dest_ignore (select exactly which source/dest pixels are affected by drawing action)
* support for Gosu::Color
* hopefully fixed opengl crashing problem in some linux distros (using Gosu::MAX_TEXTURE_SIZE)
* rows, columns, to_blob (enables Gosu::Image to be reopened using Gosu::Image.new() and load_tiles())
* bitwise drawing modes no longer affect alpha channels
* Gosu::Image.from_text now patched to automatically cache the new image
* optional :color parameter (sets background color) for TexPlay.create_image, e.g TexPlay.create_image(w, 500, 500, :color => Gosu::Color::GREEN)

Full documentation coming soon
- By ippa Date 2010-06-07 12:36
great job ban! I'll get back to you on how :color_mode => :gosu works out for me in skrutt... should make my code less complex, so it's a welcome addition.
- By banister Date 2010-06-07 13:06
also interested how dest_select works out for you, note it accepts single or multiple color parameters (in a variety of formats)

e.g

# for single
img.line 10, 10, 20, 20, :dest_select => Gosu::Color::RED

# for multiple
img.line 10, 10, 20, 20, :dest_select => [:green, Gosu::Color.new(0xff00bbcc)]
- By AmIMeYet Date 2010-06-07 16:37
Thanks for the update, Banister! :)
- By banister Date 2010-06-08 02:26
TexPlay 0.2.920 released

* :trace now supports :color_mode => :gosu

:)
- By RavensKrag Date 2010-06-15 00:31
Is there any way to draw parts of circles using texplay? I know this functionality is available in RMagick, but would like the usability and speed of texplay.  What I mean is, is there a way to draw, say, the path of a circle from the 30 degree position to the 153 degree position (just random numbers there)?

I'm trying to draw a bar for a video game which follows a circular arc.  Thus, I need to draw a specific arc length to represent the character's stats.

Also, it would be nice to be able to draw ellipses as well as circles.
- By banister Date 2010-06-15 07:50
not yet, but ill add it to the TODO list :)
- By kyonides Date 2010-06-15 20:45 Edited 2010-06-15 21:05
Well, I could do that with Chingu (a rubygem) where ippa included a circle drawing method that I modified to make it work like a HP or MP ring for RPG's.

Here's the code (you don't need to install chingu if you don't want to, this would still work since it depends on Gosu API).

def self.draw_ring(cx, cy, r, angle, colors, z=150)
    if !colors.is_a? Array or colors.size == 1
      self.draw_monocolor_ring(cx, cy, r, angle, colors, z)
    elsif colors.size == 2
      draw_bicolor_ring(cx, cy, r, angle, colors, z)
    elsif colors.size == 4
      draw_multicolor_ring(cx, cy, r, angle, colors, z)
    end
  end

  def self.draw_monocolor_ring(cx, cy, r, angle, color, z)
    0.step(angle, 1) do |a1|
      a2 = a1 + 1
      self.window.draw_line(cx + Gosu.offset_x(a1, r),
        cy + Gosu.offset_y(a1, r), color,
        cx + Gosu.offset_x(a2, r-28),
        cy + Gosu.offset_y(a2, r-28), color, z)
    end
  end
 
  def self.draw_bicolor_ring(cx, cy, r, angle, colors=[], z=150)
    0.step(angle, 1) do |a1|
      a2 = a1 + 1
      self.window.draw_line(cx + Gosu.offset_x(a1, r),
        cy + Gosu.offset_y(a1, r), colors[1],
        cx + Gosu.offset_x(a2, r-28),
        cy + Gosu.offset_y(a2, r-28), colors[0], z)
    end
  end
 
  def self.draw_multicolor_ring(cx, cy, r, angle, colors=[], z=150)
    color = colors[0] if angle > 270 && angle <= 360
    color = colors[1] if angle > 180 && angle <= 270
    color = colors[2] if angle > 90 && angle <= 180
    color = colors[3] if angle > 0 && angle <= 90
    0.step(angle, 1) do |a1|
      a2 = a1 + 1
      self.window.draw_line(cx + Gosu.offset_x(a1, r),
        cy + Gosu.offset_y(a1, r), color,
        cx + Gosu.offset_x(a2, r-28),
        cy + Gosu.offset_y(a2, r-28), 0xFF000000, z)
    end
  end


There's a need to check if draw_line method is still available or not but it works for me with Gosu 0.7.20. (I've got no deprecation warning.)

You might credit us, shawn, ippa and me for this piece of code.
- By RavensKrag Date 2010-06-15 22:27
Very nice, thank you so much.  I believe you and I are both trying to accomplish the same thing, oddly enough.  I will make a few changes to allow for a parameter to be sent to the method for the width of the ring, or perhaps give both the inner and outer radius.  Regardless, this is a very good base.  Still, if this code is to be included inside a class which descends from Gosu::Window, there is no need for all the explicit self calls before each method, nor the self.window calls.  I will repost the code with these modifications after I make them.

Also, small complaint, but why does the method only accept 1, 2, or 4 colors? Why not any n colors?
- By kyonides Date 2010-06-16 05:44
Because those are the amounts of colors I needed... the self originally referred to KyoBasic module, the module I create to encapsulate all of "my (own or modified)" methods.
- - By banister Date 2010-07-04 10:04
TexPlay 0.2.960 released

provides:

* :tolerance option (applies to :trace and :source_select (et al) families)
  e.g :color => [0.5, 0.5, 0.5, 1.0], :tolerance => 0.1         turns the color point [0.5,0.5,0.5,1.0] into a color sphere centered at the point with radius 0.1
* new :transparent pseudo-color (for use with :trace, and :source_select (et al)). Matches all colors with arbitrary rgb values but 0.0 alpha
Parent - By ippa Date 2010-07-04 17:19
good stuff as usual banister
Parent - - By banister Date 2010-07-16 07:24
TexPlay 0.2.965 released

"fixes" segfault in linux by hardcoding max texture size to 1024 (this should work on most linux systems, but on a minority of systems this will fail. Still, better than a segfault)
Parent - By jlnr (dev) Date 2010-07-16 07:29
Gosu uses the same approach to avoid the segfault on Linux now, except I always return 512. This is the lowest value I have encountered myself in the last 5 years :) Can we settle on this more pessimistic constant? Or would you say from experience that most people need more?
- - By Spooner Date 2010-08-10 12:46
I'm trying to use the :transparent colour matcher in order to clear "transparent but coloured" pixels out of an image so they are uniformly "transparent black" wherever the alpha channel is 0. I need to do this so that I can know that images that appear identical to the eye are the same, even if they have different "hidden" colour information in them. I'm trying to use:

    rect 0, 0, width, height, :filled => true, :color => :alpha, :dest_select => :transparent

:transparent matches no pixels in my image (coloured or black, transparent or opaque), so the image is not changed in any way. Using :dest_ignore instead matches all pixels and clears the whole image.

:dest_select seems to work fine with other specific colours though. I also tried:

    line x1, y1, x2, y2, dest_select => :transparent

and

    line x1, y1, x2, y2, :trace { :while_color => :transparent }
    line x1, y1, x2, y2, :trace { :until_color => :transparent }

with similar effects, where :transparent matched no pixels in my image. I am specifically using :trace to draw an outline around an image as well as to allow me to autocrop (both actions would take forever if done with get/set_pixel), but then I realised I needed to clear out all the coloured transparent areas anyway, so I don't need to use :transparent with :trace any more).

:trace and :dest_select seem to work fine with specific colours, including :alpha.

Any thoughts on this dilemma appreciated (whether I'm doing it wrong or if there is a bug in :transparent). Oh, and thanks for giving us really fast, amazingly versatile functionality like this in Ruby. Really helping me!

(Win7x64 / RubyInstaller 1.9.2 / Texplay 0.2.965 gem)
Parent - - By banister Date 2010-08-10 14:21
ill have a look at it soon, i finally got gdb up and running so this shouldn't be such a nightmare to debug.

could you gist up some small example code and attach the image you're working with?

thanks
Parent - - By Spooner Date 2010-08-10 15:47
:transparent fail case (written as one of your examples; feel free to use it): http://gist.github.com/517474

What I see is: http://cl.ly/eb53ab6e93e238481366

Thanks for taking a look!
Parent - - By banister Date 2010-08-13 14:01 Edited 2010-08-13 15:51
i think i fixed the :transparent bug, try the new 0.2.970 gem and let me know if it works

note that it may be useful to use :tolerance too, since some graphics programs dont use an alpha value of exactly 0.

so:
    img.rect 0, 0, width, height, :color => :alpha, :dest_select => :transparent, :fill => true, :tolerance => 0.01
Parent - - By Spooner Date 2010-08-13 16:03
Thanks! This gem works correctly with that failing test I gave you.

Just going to check with my real code using real edited images. I'll see if I need the tolerance too.
Parent - - By Spooner Date 2010-08-13 17:21 Edited 2010-08-13 17:47
Ooohkay, I had mixed results!

With this:

  img.rect 0, 0, width, height, :fill => true, :color => :red, :dest_select => :transparent

I get all the values with alpha == 0 being turned red. The ones with 0 < alpha < 0.01 didn't turn, so that operates as it should now.

As you suspected, I had an image where some of the apparently transparent areas did have very low, non-zero, alpha values. So I tried:

  img.rect 0, 0, width, height, :fill => true, :color => :red, :dest_select => :transparent, :tolerance => 0.01

Turned the whole image red, including those coloured areas at alpha == 1

   img.rect 0, 0, width, height, :fill => true, :color => :red, :dest_select => :transparent, :tolerance => 0

I would expect this to act as though there wasn't a tolerance value specified, however it still turned the whole image red!

Sooo, as far as I can tell, :transparent is working correctly now, but :transparent + :tolerance is not...

Attached the test image I am using.
Parent - By banister Date 2010-08-14 02:07
hehe,

ok i really should build a test suite for texplay....

ill get onto the current bug asap :)
Parent - - By banister Date 2010-08-14 02:40
ok, pushed out a new 0.2.975 gem. should hopefully fix the tolerance issue, since the bug was quite glaring.... (i was checking color1.alpha <= tolerance rather than color2.alpha <= tolerance :D)
Parent - By Spooner Date 2010-08-14 07:52
Great; that works as expected in my app now. Thanks!
Parent - - By banister Date 2010-08-13 15:36
For interest's sake another approach to achieve this could be:

img.each { |c|
    if c[3] == 0 then
        c[0] = 0
        c[1] = 0
        c[2] = 0
    end
}
Parent - - By Spooner Date 2010-08-13 16:00
Thanks. Yes, I think I did consider that method, but assumed it would be only an order of magnitude faster than iterating through x and y and using getpixel/setpixel. That method was taking quite a few seconds and I need to import and clean up a potentially large number of images in a realistic time (something that should take a few frames per image, not seconds). The rect/:transparent method I wanted to use, although it didn't actually work when I tried it, was virtually instant, even for large images.
Parent - By banister Date 2010-08-13 16:40
set_pixel can be sped up significantly by using :no_sync,

e.g

img.set_pixel x, y, :color => :red, :sync_mode => :no_sync

or by doing your pixel setting inside a paint block:

img.paint {
    0.upto(width) { |x|
        0.upto(height) { |y|
            set_pixel x,y
        }
    }
}
- By banister Date 2010-08-16 07:36
Ok, i pushed a new 0.2.980 gem, that provides greater control over caching (for improved speed and efficiency)

(1) adds :caching option (to both Gosu::Image.new and TexPlay.set_options... remember it only accepts true and false)
(2) gets rid of auto-caching for TexPlay.create_image() (this should be a significant boost to some games)
(3) also added TexPlay#clear method, it essentially  just sticks a filled rect over an image, e.g
     img.clear :color => :red, :dest_select => :transparent
     is equivalent to:
     img.rect 0,0, width, height, :fill => true, :color => :red, :dest_select => :transparent
- - By kaBOOM Date 2010-12-14 22:03
I would like to thank Mr. Banister for making TexPlay. It is a great complementary tool for Gosu. In my opinion, when it becomes more refined it should come with the standard Gosu library. One of the things I most like, its the macro function. Thats just pure genious. That said, I would like to share some input. Take in consideration I have only used the program for 2 days, so I may be mistaken.

     1.  get_pixel() function return an array of floats. Why is that? Why not an array of numbers from 0 to 255. The ‘set color’ works like this,  
    why not the former? Sometimes this floats can get really long.

     2.  I notice that there can be errors if one manipulates the ‘load_tiles’ version of an image. What I do in my currect project is reload the   
     image with the ‘ new’ version of the image and everything works fine. Example:
 
     @tiles = Gosu::Image.load_tiles(window, ‘tileset.png’ , 32, 32, true)
     #trying to manipulate @tiles[0] is a failure, but…
     @tiles[0] = Gosu::Image.new(window, @tiles[0] , true)
     #now @tiles[0] can be manipulated; no problem

Anyway, I will share more later. Thanks once again.
Parent - - By banister Date 2010-12-14 22:24 Edited 2010-12-14 23:06
@kaBoom, thanks for your feedback.

(1) You can get your colors back as Gosu::Color by using get_pixel x, y, :color_mode => :gosu
The reason why i made the design decision to return an array of floats was because that is how colors are stored internally and converting to another format would result in a performance hit --- perhaps not for one pixel, but imagine processing thousands of pixels consecutively -- converting the floats to ints or any other format would have significantly impacted on performance (:gosu => :color_mode already is 1.5 times slower than the float approach). Also i dont konw waht you mean by the 'set_color' works like this. TexPlay's color argument accepts many different color formats - though the float array approach is the oldest and possibly most common.

(2) I've never heard of this error before, can you provide more information about the error such as the error message, or even better, a tiny code sample that reproduces the problem? (preferably with the image you used available too)

Regarding 'macro', haha, i was thinking of retiring that method since i didn't think anyone used it *and* it doesn't really provide any extra functionality over and above define_singleton_method :)

Cheers
Parent - - By RavensKrag Date 2010-12-15 09:02
While on the topic of advancements to TexPlay I'd like to have the ability to draw ellipses and the ability to get some anti-aliasing on curved shapes.  (this is why I use both TexPlay and RMagick in fact).

Also, I agree, having TexPlay be included with Gosu as some sort of dependency or something would be pretty cool.
Parent - - By banister Date 2010-12-15 09:57
sure i can implement some ellipse functionality, anti-aliasing is quite straight forward too (i assume). I was also thinking of implementing some spline stuff to fill in the gaps of the very limited bezier curves. I'm thinking of doing another release fairly soon so if you want certain features pls file issues on github.com/banister/texplay   as i tend to forget :)
Parent - - By RavensKrag Date 2010-12-16 09:51
I'll just mention this issue here instead of on GitHub as I see you already closed this issue, and I'm just looking for clarification.

Did you implement Gosu::Image#== or some similar method? I tried to call it, and it did not work.  The method simply uses the default implementation (defined in object I believe) which is the same as #equal?.  It's simple enough to just monkey-patch it in, but I just wanted to make sure this was not a bug.

Side note: Oddly enough, the first time I ran a test for this, the address for the clone had the letters "bad" in it.  Just thought that was funny.
Parent - - By banister Date 2010-12-16 12:47
oops, i didn't mean to close it (reopened now). Yeah it's not implemented yet, it's coming soon though. I'll also take Spooner's advice and implement it as '#==' rather than '#compare'
Parent - - By jlnr (dev) Date 2010-12-16 18:37
Reminds me. Do you still use OpenGL to get pixel data out of Gosu's images? Or do you use to_blob? Would it simplify our combined codebase if I put some effort into making to_blob faster?

My thinking was that Image#== could just compare width, height and to_blob. But if TexPlay has already cached the image's contents, there's no need to call to_blob again, so there is at least a reason to have it in TexPlay *too*.

In pure Gosu, I am not so sure about the semantics. It should be consistent with TexPlay but how do I compare for identity then, which is usually enough? .equal? .eql? Man, it was hard enough to study these three for Scheme. ;)
Parent - By banister Date 2010-12-16 23:34
Ruby does it like this:

(1) == (compare data)
(2) .eql? (compare data AND type)
(3) .equal? (compare object_id, identity)

so for example:

Point[1, 1] == Vector[1, 1, 3]  (since @x and @y are equal)

Point[1, 1] NOT eql? Vector[1, 1, 3] (since they're diff types)

Point[1, 1] NOT equal? Point[1, 1] (since they're different objects, even though they have the same value)

TP is still using OpenGL to get image data; is Gosu::Image#to_blob a lot faster? Doesn't it do the same thing internally though? caching images is still one of the most expensive operations so it would be good if this could be made faster. Though to_blob data is INT right? I'd still need to convert all the image date to floats, though im sure that's not so expensive.
Parent - - By jlnr (dev) Date 2010-12-15 17:40
I think the gems should be kept separate, Ruby is powerful enough to integrate them without any noticeable rough edges.

Where it makes sense, I already "include" TexPlay though. For example, the RubyGame.app template builds a three-way universal texplay.bundle for easier OS X deployment. (The problem is, sadly, that the .app itself is 10.6 only. That should be fixed in the next time.)
Parent - By RavensKrag Date 2010-12-15 21:19
Oh yeah, totally agree that the gems should be separate, just thought Gosu could install TexPlay as well.  But I guess some people might not want that, so it'd be better just to let them install the gems separately? I don't know ^_^;
Parent - - By kaBOOM Date 2010-12-18 04:03
About number 2: Ok. Im using this macro: 

TexPlay.create_macro(:alpha_set) { 
no_color = self.get_pixel(0,0)
self.rect 0, 0, width, height, :fill => true,
:color => :transparent, :dest_select => no_color
}
#so i want to use the first pixel as the alpha color, so i can use other images with tranparency besides (.bmp)s.
If i use this the image become complete transparent, but if I 'reload' the image it works like intended.

I should also say I'm using hahses as cache like this:
$cache[:image_no_alpha]  = @img
$cache[:image_with_alpha] = @img.alpha_set

Maybe its something I'm doing wrong...
Thank You.
Parent - By banister Date 2010-12-18 08:52
One thing that comes to mind is you really shouldn't be using :transparent, as it's a pseudo-color for use with :dest_select and friends. Try replacing it with :alpha instead. Also, since i assume just doing that wont fix your problem, could you please give me a complete code sample (one that i can execute) along with the image you're using. Try to make the code sample as small as possible so it just contains the bare minimum to reproduce your issue.

Thanks! :)
- - By banister Date 2011-02-21 15:47
TexPlay 0.3.3 released, features a few more :alpha_blend modes

:alpha_blend => :source   (default, same as :alpha_blend => true)
:alpha_blend => :dest, uses destination pixels alpha instead of source's alpha for alpha blending
:alpha_blend => :source_with_fixed_alpha, same as :source but doesn't affect alpha channel of destination pixel
:alpha_blend => :dest_with_fixed_alpha, same as :dest but doesn't affect alpha channel of destination pixel
:alpha_blend => false (no alpha blending, same as current behaviour. nil also accepted)

This version also has gem test support, do the following:
gem install rubygems-test
gem install texplay
gem test texplay

and upload results.

THere's also a few easter eggs in thsi release, require 'texplay/alone' let's you do image manip ostensively without gosu -- (really just wraps and hides gosu stuff): TexPlay.create_image(100, 100).clear(color: :red).save("blah.png")

and require 'texplay/live' a REPL session for image editting; totally undocumented and therefore hard to use :P requires 'pry' gem
Parent - - By RunnerPack Date 2011-03-01 04:44 Edited 2011-03-01 04:50
While using my paint program just now, I came up with two new (possibly) useful :alpha_blend modes. The first I call ":source_as_alpha" and the second could be called either ":copy_alpha" or just ":copy".

The first uses the grey-scale value of the pixels in the source to alter the alpha channel of the destination, without affecting the color channels. You could either do a straight copy, or an actual composite taking into account the source's alpha channel. Maybe there should be separate flags for both modes (:source_as_alpha_over?). Also, it could be split into ":red_as_alpha" etc. which would give the option of skipping the redundant computation of a grey value for a known grey pixel. (The ":copy_alpha" mode below could actually also be called ":alpha_as_alpha" for symmetry, although it's rather more cumbersome...)

The second mode (:copy_alpha) just draws the source's alpha channel to the destination's, ignoring the color channels of both images.

It's up to you whether either of these also respects the blending modes.

Whaddaya think? :D
Parent - - By banister Date 2011-03-01 06:02
they are interesting but can you give example applications? im curious what sort of affect they have
Parent - - By RunnerPack Date 2011-03-01 07:02
The one that popped into my head is a "search light" effect, where you have a black, opaque image over another image, and you splice a transparent circle into the black image to show the background through. Of course, the "darkness" doesn't have to just be black, it could just be really dim, or foggy, etc. It could even be used for "x-ray vision". Basically, anywhere you'd need to "punch holes" in another bitmap, or plug holes up, without affecting the color.
Parent - - By Spooner Date 2011-03-02 00:58
You'd use standard :multiply mode with [1, 1, 1, alpha] for that effect.

This wouldn't affect the rgb channels, but would multiply the alpha of each pixel by an amount (0 to clear, 0.5 to make it half as opaque). It doesn't set it directly, but multiplication is actually more generally useful, I think.
Parent - - By RunnerPack Date 2011-03-02 04:15
Oh, I wasn't aware that blend modes worked on the alpha channel, too. That's cool! But, doesn't that mess things up when you just want a straight alpha composite with multiply? e.g. a sprite with an anti-aliased edge.
Parent - By Spooner Date 2011-03-11 01:24
Er, I dunno :$ I just knew I had a clue about the exact thing I was commenting on (I think).
Up Topic Gosu / Extending Gosu / TexPlay, drawing and hit-testing for Gosu::Image [from wiki]
1 2 Previous Next  

Powered by mwForum 2.29.1 © 1999-2013 Markus Wichitill