Possible means to speed up Bitmap TONE code?
#1
Well, this is what I wanna speed up within RPGMaker XP...

Code:
#==============================================================================
# ** Bitmap
#------------------------------------------------------------------------------
#  The bitmap class. Bitmaps are expressions of so-called graphics.
#==============================================================================

class Bitmap
  #-------------------------------------------------------------------------
  # * Tone Adjust
  #    r : red adjustment   (defaulted to 0 middle of -255 - 255 range)
  #    g : green adjustment (defaulted to 0 middle of -255 - 255 range)
  #    b : blue adjustment  (defaulted to 0 middle of -255 - 255 range)
  #-------------------------------------------------------------------------
  def tone_adjust(r=0, g=0, b=0)

    # Adjust values to be within -255 to 255 ranges
    r   = tone_ranges(r)
    g   = tone_ranges(g)
    b   = tone_ranges(b)

    # Cycle through the bitmaps pixels
    for x in 0..self.width
      for y in 0..self.height
        #
        # Base mechanics for each pixel
        color = self.get_pixel(x, y)                  # Get single pixel color
        next  if color.alpha == 0                     # Skip if transparent
        rr    = color.red   + r                       # Adjust the red
        gg    = color.green + g                       # Adjust the green
        bb    = color.blue  + b                       # Adjust the blue
        self.set_pixel(x, y, Color.new(rr, gg, bb))   # Replace the pixel
        #
      end
    end

  end 
  #-------------------------------------------------------------------------
  # * Tone Range Adjustment
  #    value : value (forced to stay in -255 to -255 range)
  #-------------------------------------------------------------------------
  def tone_ranges(value)
    value = -255    if value < 255
    value =  255    if value > 255
  end
end

Now within RPGMaker XP:
  • You can hue-adjust bitmaps within a 0-360 range.
  • You can tone adjust sprites, or increase the red, green and/or blue tones in a range of -255 to 255, darkening or lightening them accordingly.

But, you'd think they woulda PUT TONE ADJUST INTO THE BITMAP CLASS?????



Still, for anything large, this code does take some time to change a bitmap.  If I could adjust the bitmap with the Tone class I could with sprites, it would be dang near instantaneous.  Unfortunately, I need something FAAAAST!

And no. You cannot tone adjust a sprite and copy the contents into a bitmap.  The sprite's own properties are what is adjusted, not the bitmap contained within.

So, does anyone know of a faster means to adjust the tone of a bitmap?
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)

[Image: QrnbKlx.jpg]
[Image: sGz1ErF.png]    [Image: liM4ikn.png]    [Image: fdzKgZA.png]    [Image: sj0H81z.png]
[Image: QL7oRau.png]    [Image: uSqjY09.png]    [Image: GAA3qE9.png]    [Image: 2Hmnx1G.png]    [Image: BwtNdKw.png%5B]
  Above are clickable links
Reply }
#2
I think the code is wrong. For the tone value operation, I think you'd need to employ a "min / max" array function or use modulous to cut the number to it's proper negative or positive value. What exactly are you trying to do? Can the "sprite.color = some_color" help achieve the results you're looking for? Changing hue? Changing tone? What are you trying to speed up?

I'll have to come back and give a proper response when I have time because we're kinda facing the same challenge with hue change operations, albeit in different arenas. Busy, busy, busy ;_;

First off; I suggest benchmarking to see if fill_rect is faster than set_pixel for a single pixel operation. I could be wrong but I think it is, oddly enough.

Second: Using shaders is probably the fastest way to support this operation, unless you can utilize the RGSS Core engine to do it. I believe you should be able to do it with RGSS. Internally, I doubt it iterates with a "for X / Y" block, I think it's all handled as a "pass through" operation using shaders. Same goes for Tone, Angle, Zoom, the operations of a Plane, etc.

From what I understand, RMXP uses the Direct X standard. I believe it probably utilizes a primitive OpenGL standard too, and all operations are Shader operations, but I could be wrong or misunderstanding with how RMXP really works. Based on my limited understanding of the black box known as the RMXP hidden classes, plus what I've been doing with the RGL Core, I'm probably more right than wrong. I welcome any corrections because I like to know and understand these things better than I currently do, I hate speculating on such a topic.
[Image: Button-BOTB.png]
[Image: Save-Point.gif][Image: Button-You-Tube2.png][Image: Button-Sound-Cloud2.png][Image: Button-Audio-Mack2.png]
[Image: LS-Banner.gif]
NEW ALBUM OUT NOW!

Reply }
#3
Kain "Man-o-Wolf" Nobel Wrote:First off; I suggest benchmarking to see if fill_rect is faster than set_pixel for a single pixel operation. I could be wrong but I think it is, oddly enough.

It makes you think so mainly because set_pixel "might" look for the color and then set it, while fill_rect would simply dump it all there. At the end it gotta be a slight advantage at most, yet, the benchmarking would make the difference. And a large picture gotta be use as a sample for that benchmarking!

Kain "Man-o-Wolf" Nobel Wrote:From what I understand, RMXP uses the Direct X standard. I believe it probably utilizes a primitive OpenGL standard too, and all operations are Shader operations, but I could be wrong or misunderstanding with how RMXP really works. Based on my limited understanding of the black box known as the RMXP hidden classes, plus what I've been doing with the RGL Core, I'm probably more right than wrong.

Sad Sadly, you gotta be wrong on this one. DirectX and any old fashioned OpenGL aren't that similar or compatible. If it were, all custom implementations of the RM series up to VX Ace would have been quite faster than they are. Hey! They'd even allow you to draw triangles like crazy. (They still could if Ojima ever cared about adding them, but the implementation would have been totally different from OpenGL's for sure.)

For instance, on Linux you NEED shaders to draw stuff on screen, even for a plain old sprite. Linux always relied on OpenGL for drawing operations before Vulkan came out. That's not necessarily the case on Windows.

Kain "Man-o-Wolf" Nobel Wrote:I doubt it iterates with a "for X / Y" block, I think it's all handled as a "pass through" operation using shaders. Same goes for Tone, Angle, Zoom, the operations of a Plane, etc.

For set_pixel method? I don't think they need a loop at all. Taking HiddenChest as an example, I'd venture to say the engine would simply calculate the real location of the pixels array and set the color directly. If Ojima followed that same train of thought at all...

The main problem that I can see between set_pixel and fill_rect is that for large areas, fill_rect is ideal. Heck, it just checks and convert the color from RGSS to C or C++ or C# once. set_pixel would have to do that conversion tons of times instead. And it IS a slow conversion.


One of the main reasons why set_pixel can get slow is because you can pass it 3 or 4 arguments at a given time. Ruby Ruby will treat it as a C Array that needs to be parsed internally one by one. Then it looks for the Color data wrapper after having done the same with the Bitmap wrapper...
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#4
(06-11-2023, 01:27 AM)Kain Nobel Wrote: I think the code is wrong. For the tone value operation, I think you'd need to employ a "min / max" array function or use modulous to cut the number to it's proper negative or positive value.

First off.. um... The basis for the code was your own 'Grayscale' script for the MACL, used to evaluate and alter the individual pixels of an image and convert an image to grayscale.  Insofar as employing a min/max function, that's what the simple 'tone_ranges' method performs. 

Kainer's Greyscale

Admittedly, correct on one part, there is an error.  and this is the more correct version of the main function:

Code:
  #-------------------------------------------------------------------------
  # * Tone Adjust
  #     r : red adjustment   (defaulted to 0 middle of -255 - 255 range)
  #     g : green adjustment (defaulted to 0 middle of -255 - 255 range)
  #     b : blue adjustment  (defaulted to 0 middle of -255 - 255 range)
  #-------------------------------------------------------------------------
  def tone_adjust(r=0, g=0, b=0)
    time = Time.now
    # Cycle through the bitmaps pixels
    for x in 0..self.width
      for y in 0..self.height
        #
        color = self.get_pixel(x, y)                  # Get single pixel color
        next if color.alpha == 0                      # Skip if transparent
        rr = color.red   + r                          # Adjust the red
        gg = color.green + g                          # Adjust the green
        bb = color.blue  + b                          # Adjust the blue
        rr = tone_ranges(rr)                          # Keep within ranges
        gg = tone_ranges(gg)                          # '              '
        bb = tone_ranges(bb)                          # '              '
        self.set_pixel(x, y, Color.new(rr, gg, bb))   # Replace the pixel
        #
      end
    end
    p "Execution Time: #{Time.now - time}"
  end

Yes, I employed the execution time to the code to determine if it was faster with fill_rect than with set_pixel.  It is not.

(06-11-2023, 01:43 AM)kyonides Wrote: It makes you think so mainly because set_pixel "might" look for the color and then set it, while fill_rect would simply dump it all there. At the end it gotta be a slight advantage at most, yet, the benchmarking would make the difference. And a large picture gotta be use as a sample for that benchmarking!

Big-size file benchmarking?  Now some context... Imagine if you will that you are converting a veeery large png bitmap like a 120KB 16-shaded grayscale image (600 x 6615px in size). Using this method with setPixel on my PC, it takes 3.815 to convert the image.  If I were to use fill_rect, it takes 4.131 seconds.

More context, this for my layered spritesheet tool.  It uses direct bitmap editing so it can save output in pure .png format of any size (relative to RMXP's max size capacity) and with alpha transparency support.


(06-11-2023, 01:43 AM)kyonides Wrote: The main problem that I can see between set_pixel and fill_rect is that for large areas, fill_rect is ideal. Heck, it just checks and convert the color from RGSS to C or C++ or C# once. set_pixel would have to do that conversion tons of times instead. And it IS a slow conversion.

Fill rect merely fills a rectangle area with a color as its name implies, and is not a shader.  Otherwise, it would be the ideal tone_adjust code for the bitmap class. I see nothing in the documentation for fill_rect about it checking and converting anything.

Help Documentation (even VX too) Wrote:fill_rect(x, y, width, height, color)
fill_rect(rect, color)

    Fills the bitmap box (x, y, width, height) or rect (Rect) with color (Color).
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)

[Image: QrnbKlx.jpg]
[Image: sGz1ErF.png]    [Image: liM4ikn.png]    [Image: fdzKgZA.png]    [Image: sj0H81z.png]
[Image: QL7oRau.png]    [Image: uSqjY09.png]    [Image: GAA3qE9.png]    [Image: 2Hmnx1G.png]    [Image: BwtNdKw.png%5B]
  Above are clickable links
Reply }
#5
Obviously, it would be impossible to apply multiple colors to the bitmap through a fill_rect method for it only asks you to provide one and that's all. Sad 
Nonetheless, your benchmarks, whether hypothetical or not, would be worrisome for a method that only needs to keep track of a single color. Confused I wonder why that'd be quite slow here.
Thinking Would my bitmap.invert scriptlet be as slow as these methods we've been discussing here?
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#6
(Note to self: Install RPG Maker XP on this machine. Also, disclaimer; I'm going off of memory, everything I said below could be wrong.)

I believe Tone is a read-only Sprite property with Viewport having ownership of the Tone object in question. In other words, I don't think any of the Sprite objects holds a unique Tone, I believe it all goes back to Viewport. When referencing sprite.tone, I believe you're receiving sprite.viewport.tone. If you were adjust the "sprite's tone", you'd be adjusting the global tone used for all sprites, hence why they don't have sprite.adjust_tone.

(Correct me if I'm wrong^)

To do the math on the Tone, you could possibly normalize the values from 255 to a 1.0 based value, get the percentage, and adjust each pixel individually based on said percentage. Red at 50% (0.5) is like Red -128. Red at 150% (1.5) would be like Red 128. To do the Gray value from Tone, you'd need to convert RGB to HSV and get the value to modify S(aturation), then convert back to RGB 255. If a value is pushed outside the bounds of the -255 to 255 range, you'd need to clamp them.

Yes, iterating a "for x/y" is slower than using a shader but it's OK for simple operations on sprites that aren't giant. It's too bad RMXP didn't provide a faster iterator for draw functions, or allow shaders, but it is what it is. I know overtly, Shaders aren't used in RMXP, but internally they most likely do use them when adjusting any/all Sprite properties. I can't imagine the Blend Mode, Hue, Angle and other properties would be as quick as they are if the program wasn't internally using Shaders to perform the operations, you'd have more lag than you do.

Again, I could be wrong. To be fair, I've never violated the EULA to find out, nor do I ever plan to, but I would like to find out more about how they did everything. I kind of get an idea of how things work when viewing similar functionality as RMXP but from non-RPG Maker game projects and open source code, which is how I come to these conclusions such as "RMXP internally uses Shaders". They probably don't use them for fill_rect or set_pixel; they'd be used for Transforms such as Angle, Hue, Zoom. Or Graphics.transition.
[Image: Button-BOTB.png]
[Image: Save-Point.gif][Image: Button-You-Tube2.png][Image: Button-Sound-Cloud2.png][Image: Button-Audio-Mack2.png]
[Image: LS-Banner.gif]
NEW ALBUM OUT NOW!

Reply }
#7
(06-11-2023, 06:21 AM)kyonides Wrote: Nonetheless, your benchmarks, whether hypothetical or not, would be worrisome for a method that only needs to keep track of a single color. Confused I wonder why that'd be quite slow here.
Oh, it's not keeping track of a single color. This method takes the values supplied, goes through every pixel, alters the color of each individual pixel, and reapplies based on the values provided.

Unfortunately, I expect it would be just as slow with your invert scriptette since it too needs to go through every pixel, acquire the pixel color, and reapply with set_pixel with an altered color.


(06-11-2023, 09:41 AM)Kain Nobel Wrote: I believe Tone is a read-only Sprite property with Viewport having ownership of the Tone object in question. In other words, I don't think any of the Sprite objects holds a unique Tone, I believe it all goes back to Viewport. When referencing sprite.tone, I believe you're receiving sprite.viewport.tone. If you were adjust the "sprite's tone", you'd be adjusting the global tone used for all sprites, hence why they don't have sprite.adjust_tone.

Nope. Both the Sprite class and the Viewport class have 'tone' properties that may be applied. So you can change the tone of a viewport and make it deep red, and apply a deep green to a few select sprites as well. SCREWED UP TONE ATTACK, HOOOO!

Insofar as the math, you would assume colors are 0-255. But to reduce the brightness, you apply a negative version. So the actual adjustment range is from -255 to 255.

And colors range initially from 0-255. Now if the image is quite white, you would need to reduce one (or more) of the three color values down to -255 to make black or near black. No rounding values to percentages... gotta be specific to the individual units.

Ahem... could be food for thought to include such additions in C++ code for ReGaL and/or Hidden Chest to permit such commands.

So no one would have knowledge of any means to use DirectDraw or applicable functions in place?
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)

[Image: QrnbKlx.jpg]
[Image: sGz1ErF.png]    [Image: liM4ikn.png]    [Image: fdzKgZA.png]    [Image: sj0H81z.png]
[Image: QL7oRau.png]    [Image: uSqjY09.png]    [Image: GAA3qE9.png]    [Image: 2Hmnx1G.png]    [Image: BwtNdKw.png%5B]
  Above are clickable links
Reply }
#8
Some Wulfo once Wrote:Nope. Both the Sprite class and the Viewport class have 'tone' properties that may be applied. So you can change the tone of a viewport and make it deep red, and apply a deep green to a few select sprites as well. SCREWED UP TONE ATTACK, HOOOO!

If the maker had not created the Game_Screen class the way it did, the developer could still have used the viewport's tone property to achieve the same old map slip damage effect for poisoned heroes.
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }


Possibly Related Threads…
Thread Author Replies Views Last Post
   Permanently modifying move speed Keeroh 5 9,624 05-24-2017, 05:47 AM
Last Post: DerVVulfman
   Meagan's Particles' speed Raou 6 9,288 04-01-2015, 03:43 PM
Last Post: Raou
   Custom Game_Event code lags too much! MechanicalPen 4 6,647 06-27-2013, 11:22 PM
Last Post: MechanicalPen
   Ruby, RGSS & General Code Discussion Kain Nobel 6 10,904 12-22-2012, 05:11 AM
Last Post: MechanicalPen
   Getting bitmap width and height of leading party member? PK8 5 8,573 08-27-2012, 11:41 AM
Last Post: Kain Nobel
   Pixelmovement and speed ark 2 5,675 05-31-2010, 05:51 PM
Last Post: ark
   VX Show Picture Event Command Code? PK8 2 6,370 02-27-2009, 11:30 PM
Last Post: PK8



Users browsing this thread: 1 Guest(s)