'Advanced' Bitmap && Color methods

● ARCHIVED · READ-ONLY
Started by ?????? 20 posts View original ↗
  1. Hey there,

    To give you a little back story...

    Spoiler
    I recently began writing a script to rewrite the way that vx ace draws text. The script I have written essentially changes the regular fonts for an 'image reel' that can be customized alot more than what a font can be. At least that is the end game plan...

    So while messing around with the aforementioned 'font image reel' script I began messing around with the Bitmap class. This was initially so that I could replace the white within the bitmap to another color - to enable alternate color fonts.

    This is what I came up with...

    1405523245_445536.png

    As you can see, the result is less than desirable. 

    This is mostly due to the font image reel used having various shades of grey along with the black and white.

    I posted a question within the RGSSx questions that dont deserve their own thread in the hope of finding a reasonable solution to this issue. The question was answered (somewhat) by 'Pablo Neirotti' who suggested I simply create a method like so..

    class Color  def dark?    red <= 75 && green <= 75 && blue <= 75  endendand then check whether my current color (color of each pixel within the bitmap) is dark? before changing it to another color.

    Unfortunately, this suggestion wielded the same results as above as this is essentially what I had done, in a different way..

            next unless color.alpha > 0        next unless color.red < 80        next unless color.green < 80        next unless color.blue < 80But this suggestion got me thinking, why not just move what methods I can into the color class and then call them from the bitmap class when required. Thus creating more methods that can be used in both classes.

    After a little bit of rearranging the code, I managed to create a combination of methods to determine whether my font color should be changed...

    class Color  #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def is_light?    is_visible? && is_highred? && is_highgreen? && is_highblue?  end  #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def is_midshade?    !is_dark? && !is_light? && is_shade?  endendAs you can see, these methods utilize a fair number of other new methods. The result though, is undeniably a vast improvement.

    1405553026_991532.png

    Now, because I am directly modifying the bitmap, rather than changing the color / tint of an actual sprite, this means I can modify more than just my font images...

    I could, for example, invert EVERYTHING...

    1405516440_702977.png
    Or maybe I want to blur some bitmaps, but with more control than the regular blur option offers...

    Spoiler
    1405515609_713178.png
    Apply a greyscale (black and white) effect...

    Spoiler
    1405516288_282732.png
    Now as I am sure you can tell, there is quite a few things that could be done with effects such as this... The main problem is how long it takes to apply the effects. (some are much faster than others)

    Anyway...


    Basically, I am wondering if other script writers would actually use a script that offers such features?

    Current methods :

    Bitmap Class- brighten(amount=10)- brighten!(amount=10)- darken(amount=10)- darken!(amount=10)- invert- invert!- greyscale(scaler=3)- greyscale!(scaler=3)- sepia? # Not sure whether it looks right or not - randomize(times=2)- randomize!(times=2)- make_color(new_color) # recolors all white / grey to new_color- make_shadow_color(new_color) # recolors all black / grey to new_color- remove_white- remove_blackColor Class- brighten(amount=10)- brighten!(amount=10)- darken(amount=10)- darken!(amount=10)- invert- invert!- greyscale(scaler=3)- greyscale!(scaler=3)- sepia? # Not sure whether it looks right or not - recolor(new_color) # sets to new color while maintaining current alpha- recolor!(new_color)- is_dark?- is_light?- is_color?- is_highshade?- is_midshade?- is_lowshade?- is_shade?- is_highred?(highval=180)- is_highgreen?(highval=180)- is_highblue?(highval=180)- is_highalpha?(highval=180)- is_lowred?(lowval=75)- is_lowgreen?(lowval=75)- is_lowblue?(lowval=75)- is_lowalpha?(lowval=75)- is_red?(val=0)- is_blue?(val=0)- is_green?(val=0)- is_alpha?(val=0)- is_visible?I am also wondering what other methods you guys have created for these two classes. Mostly methods for the bitmap class - to perform various filters and effects to the bitmaps. But whatever your methods do, if they are new and for these classes, please share ^_^

    As always, your comments and thoughts are appreciated :)
  2. I don't really like changing color from a bitmap. It's mainly because it will take much time.
    I've ever tried to make a invert bitmap.

    Spoiler
    10369719_10202160330477929_7019919292412245971_n.jpg
    But sure, it takes time much.
    Then I got idea to precache the bitmap.
    Basically, when you inverted your bitmap, save it, to be called later. So, you wont invert the bitmap twice or more
    But I come across another problem. Your memory usage could be doubled by doing this.
     
    Here is my code
    Spoiler
    class Bitmap attr_accessor :is_invert attr_writer :negative alias theo_negative_init initialize def initialize(*args) theo_negative_init(*args) @negative = nil if PreCache_Invert @negative = make_inverted_bitmap @negative.negative = self @negative.is_invert = true end @is_invert = false end def negative if @negative.nil? @negative = make_inverted_bitmap @negative.negative = self @negative.is_invert = true end return @negative end def make_inverted_bitmap bmp = self.clone bmp.color_invert bmp end def color_invert for i in 0..width for j in 0..height col = get_pixel(i,j) col.red = 255 - col.red col.green = 255 - col.green col.blue = 255 - col.blue set_pixel(i,j,col) end end end alias theo_negative_dispose dispose def dispose theo_negative_dispose @negative.dispose if @negative && @negative.is_invert end end 
     
    And also, it's a simple method, yet it's pretty useful for a lazy developer like me
    Code:
    class Bitmap    # Fill entire bitmap with color  def entire_fill(color = Color.new(0,0,0,150))    fill_rect(self.rect,color)  end    # Fill bitmap edge only  def border_fill(color = Color.new(255,255,255))    fill_rect(0,0,width,1,color)    fill_rect(0,0,1,height,color)    fill_rect(width-1,0,1,height,color)    fill_rect(0,height-1,width,1,color)  end  end
    And how about color comparison?

    class Color # Is color same as other? def same?(*args) return false if args.empty? return args.any?{|color| self.red == color.red && self.green == color.green && self.blue == color.blue && self.alpha == color.alpha} end # Is color empty? def empty? return self.alpha <= 0 end endThese taken from my basic modules
  3. You could slightly speed up your make_invert method by doing a simply check for the color alpha being > 0 before processing the change.

    I also wrote a 'kind_of?' method after posting this that looks like...

      #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def kind_of?(type=:red)    case type    when :red   then r > 0 && g < r && b < r && a > 0    when :green then g > 0 && r < g && b < g && a > 0    when :blue  then b > 0 && r < b && g < b && a > 0    end  end ;)

    Also, I feel your method to invert is quite lengthy... At least compared to what I had done...

    #===============================================================================class Color#===============================================================================  #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def invert    set(255-r, 255-g, 255-b, a)    self  end  #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def invert!    clone.invert  endend#===============================================================================class Bitmap#===============================================================================  #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def invert    (0...width).each do |w|      (0...height).each do |h|        color = get_pixel(w, h)        next unless color.alpha > 0        new_c = color.invert        set_pixel(w, h, new_c)      end    end    self  end  #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def invert!    clone.invert  endendyou could of course call invert in the bitmap initialize to see the performance difference - really though, the performance is only gained on non visible portions of the sprite :) (and is lost immediately due to no cache, but as long as your not going crazy, it should be ok)

    Also, I quite like how you have a checker for whether the image has been inverted or not. I never thought of that cause you can just re-invert the image to return it to normal :p

    And I quite like those 'lazy methods' you have there :)

    Just proves that not everything has to be complex ^_^

    Edit:

    Just pinched and modified your same? method to this...

      #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def is_same_as?(color)    r == color.r && g == color.g && b == color.b && a == color.a  endThanks for sharing ^_^
  4. That alpha checking. it definitely boost up the invert. I haven't thought this one. Thanks anyway :D

    Your is quite neat. Separate invert function in Color class, apply them in Bitmap class. It looks like you want to make a basic module for Bitmap and Color. Meanwhile, mine are not. I'm not really insterested anyway lol

    Btw, a method with exclamation marks "!" is usually used to modify self.

    While method with no exlamation marks is used to make a new modified object. I think you need to swap those two methods name to prevent confusion.

    Just my 50 cent
  5. TheoAllen said:
    ... It looks like you want to make a basic module for Bitmap and Color. Meanwhile, mine are not. I'm not really insterested anyway lol

    Btw, a method with exclamation marks "!" is usually used to modify self.

    While method with no exlamation marks is used to make a new modified object. I think you need to swap those two methods name to prevent confusion.
    Yea, pretty much that. I am trying to piece together some nice functions just to see what I can do with it :)

    Thanks for pointing out the ! thing lmao, I didn't even notice that I had put them the wrong way round :D
  6. Basically, I am wondering if other script writers would actually use a script that offers such features?
    I would. Possibly for some potential tools I have in mind.
  7. Perhaps I will neatened up the code a little and release it with the hope others can help build it into a viable bitmap handling system. The system currently in place is lacking quite a bit :/
  8. How about drawing shapes?

    Spoiler
    Basic shapes and polygon like thisshape2.jpg

    Or even something awesome like this. All hail maths

    dafuqivedone.jpg
    It can be used within polygon status style

    Spoiler
    shape7.jpg
    Those are present on my basic modules. But the codes are somewhat messy and too long. And I forgot how it works  :guffaw:
  9. Oh those are real cool.

    I seen Cidiomar wrote some methods for drawing non horz/vert lines and such a while back, was just thinking of looking those up and seeing what they had to offer, but your screenshots show some real promise (I assume they will be somewhat similar except yours probably a little more math-y) :D

    I especially like how you have the pokemon pokeblock looking thing in your status screen, thats pretty damn neat :p

    Edit:

    anyone have a good idea how one would define a sepia (or other filter type) tone from the current color?

    The one i have came up with is...

      #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def sepia?    t = (r + g +     set(t / 3, t / 4, t / 5, a)    self  endand it doesnt quite seem right :/
  10. I had an old one I kinda(I think I found the original code in a php site and rewrote it to suit RGSS) wrote back in... I believe it was 2009. It's not very good, but I hope it helps in some way.

    Code:
      #----------------------------------------------------------------------------  # * Sepia  #----------------------------------------------------------------------------  def sepia    for y in 0...self.height      for x in 0...self.width        rgb = get_pixel(x, y)        avg = (0.3*rgb.red + 0.59*rgb.green + 0.11*rgb.blue)/(0.3 + 0.59 + 0.11)        rgb.red = avg*2.4        rgb.green = avg*1.7        rgb.blue = avg*1.3        args = [rgb.red, rgb.green, rgb.blue, rgb.alpha]        self.fill_rect(x,y,1,1,Color.new(*args))      end      Graphics.update    end  end
  11. My computer is shouting for me to restart it to complete updates... When they finish I will test our your color calculation and see how it looks compared to what I had.

    I am currently wondering whether filling the image using fill_rect would be more efficient than using the current set_pixel method... :/

    Edit:

    Here is the difference between the method I had and your suggestion..

    Spoiler
    Mine:

    1405566738_045003.png

    Yours:

    1405567018_495157.png
    Not quite sure yours works as setting a sepia style tone, but it definitely sets some kind of effect :D

    Just not quite sure what it would be called lol
  12. No, no, no, no, no. Do not overwrite kind_of?, just don't. I'm annoyed enough as-is that RGSS3 decides to overwrite the class method for actors, don't start messing around with kind_of? just to perform some type-check like that. That's not what that method is for, and having a single object type which reacts differently than every other object -- literally -- is bad.


    At the same time, Theo, instead of defining some method called same?, why don't you just include the Comparable module and provide the <=> binary operator to perform checking for equality and sorting? Defining that method appropriately means you could actually compare Color instances in a meaningful way, or even store them in an array and call sort on it.


    And really, this post may come across as harsh, but don't take Game_Actor#class and SceneManager.exit as good examples to follow; they aren't. Both overwrite methods which have entirely different functionality in every single context other than the particular one that they were overwritten in.


    That is bad.
  13. Dekita said:
    Not quite sure yours works as setting a sepia style tone, but it definitely sets some kind of effect :D


    Just not quite sure what it would be called lol
    Weird. Here's how my sepia should look.
    a32e78c4_o.png


    Though it can get a little bright...


    503b8320_o.png
  14. @Solistra - I realized after calling it kind_of? that there was already a more important method with that name :p

    It has since been changed to 'is_a?..

      #-----------------------------------------------------------------------------  #  #-----------------------------------------------------------------------------  def is_a?(type=:red)    case type    when :red   then r > 0 && g < r && b < r && a > 0    when :green then g > 0 && r < g && b < g && a > 0    when :blue  then b > 0 && r < b && g < b && a > 0    end  endIf you can think of a better name for it please share. :)

    @PK8 - yea thats looks much more like it. Unfortunately, even when I copy your exact method into the bitmap class (below my methods) it changes the image like the one I posted above.
  15. Ahahahaha! You think changing it from `kind_of?` to `is_a?` is a good idea? Those are both used internally! They produce identical results! Different scripters use them interchangeably depending on personal preference, so changing them could be disastrous! Please, before you write even one more word of code, do read over the Ruby documentation - or at least the documentation for Object, Module, and Kernel. It's simply insane to reuse the names of any methods found in there unless you intend to return the same information but require specific evaluation based on aspects of the class you're defining. You want a better name? Try something like `is_color?` or `primary_value_is?` that describes the result you want and isn't already present in the Ruby library. If you don't like those, use literally anything else.
  16. Is 'same?' method a built-in method from Ruby? If yes, it's definitely need to be changed. Thanks for notice.

    Yes, I'm also annoyed that RGSS3 decides to overwrite 'Game_Actor#class'. But I have no problem with 'SceneManager#exit' somehow
  17. TheoAllen said:
    Is 'same?' method a built-in method from Ruby? If yes, it's definitely need to be changed. Thanks for notice.


    Yes, I'm also annoyed that RGSS3 decides to overwrite 'Game_Actor#class'. But I have no problem with 'SceneManager#exit' somehow
    I have a problem with SceneManager.exit (it's '.' as opposed to '#' due to being a class method) because I use a REPL constantly, and closing the REPL via a call to exit when I'm in the context of SceneManager unexpectedly closes the game. That's annoying, and defining a method with the same name as a vital method defined in Kernel is obnoxious.


    By the way, no, same? is not a vital built-in method or anything, it's just that including Comparable and defining <=> allows you to compare and sort objects using the natural comparison operators (<, <=, >, >=, and ==).
  18. Enelvon said:
    Ahahahaha! You think changing it from `kind_of?` to `is_a?` is a good idea? Those are both used internally! They produce identical results! Different scripters use them interchangeably depending on personal preference, so changing them could be disastrous! Please, before you write even one more word of code, do read over the Ruby documentation - or at least the documentation for Object, Module, and Kernel. It's simply insane to reuse the names of any methods found in there unless you intend to return the same information but require specific evaluation based on aspects of the class you're defining. You want a better name? Try something like `is_color?` or `primary_value_is?` that describes the result you want and isn't already present in the Ruby library. If you don't like those, use literally anything else.
    Rofl... Cant believe I overlooked the same thing (essentially), twice in a row...

    I use is_a? all the time as well...

    Feel like a total newb now :(

    I think I will have a good look over the docs for those. At the very least is should ensure I stop trying to overwrite important methods :D

    Edit - I fixed that method *again* so now its called 'is_primary_color?(type=:red)'.

    Now gonna read over that documentation :p
  19. Enelvon said:
    If you don't like those, use literally anything else.
    Literally? Because this totally works:

    Code:
    class Color  define_method(:"anything else") do    # ...  endendColor.new.send(:"anything else")
    Yes, I'm being facetious.
  20. Solistra said:
    I have a problem with SceneManager.exit (it's '.' as opposed to '#' due to being a class method) because I use a REPL constantly, and closing the REPL via a call to exit when I'm in the context of SceneManager unexpectedly closes the game. That's annoying, and defining a method with the same name as a vital method defined in Kernel is obnoxious.
    A bit out of topic. But it seems you still could call Kernel exit by calling

    Code:
    Kernel.exit