'Advanced' Bitmap && Color methods

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
Hey there,

To give you a little back story...

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



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.



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

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

Apply a greyscale (black and white) effect...

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 :)
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
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.

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

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
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 ^_^
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
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
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
... 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
 

PK8

I sense there's something in the wind...
Veteran
Joined
Mar 17, 2012
Messages
1,220
Reaction score
152
Primarily Uses
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.
 
Last edited by a moderator:

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
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 :/
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
How about drawing shapes?

Basic shapes and polygon like this


Or even something awesome like this. All hail maths

It can be used within polygon status style

Those are present on my basic modules. But the codes are somewhat messy and too long. And I forgot how it works  :guffaw:
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
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 :/
 
Last edited by a moderator:

PK8

I sense there's something in the wind...
Veteran
Joined
Mar 17, 2012
Messages
1,220
Reaction score
152
Primarily Uses
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
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
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..

Mine:



Yours:

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
 
Last edited by a moderator:

Solistra

Veteran
Veteran
Joined
Aug 15, 2012
Messages
593
Reaction score
247
Primarily Uses
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.
 

PK8

I sense there's something in the wind...
Veteran
Joined
Mar 17, 2012
Messages
1,220
Reaction score
152
Primarily Uses
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.



Though it can get a little bright...


 
Last edited by a moderator:

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
@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.
 

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
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.
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
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
 

Solistra

Veteran
Veteran
Joined
Aug 15, 2012
Messages
593
Reaction score
247
Primarily Uses
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 ==).
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
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
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
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
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Couple hours of work. Might use in my game as a secret find or something. Not sure. Fancy though no? :D
Holy stink, where have I been? Well, I started my temporary job this week. So less time to spend on game design... :(
Cartoonier cloud cover that better fits the art style, as well as (slightly) improved blending/fading... fading clouds when there are larger patterns is still somewhat abrupt for some reason.
Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??

Forum statistics

Threads
105,862
Messages
1,017,049
Members
137,569
Latest member
Shtelsky
Top