• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[Snippet] String Colors

Level 31
Joined
Jul 10, 2007
Messages
6,306
String Colors
By Nestharus and Sevion


This colors strings with spiffy colors by converting RGB values to hexadecimal strings.

This also supports gradients as well as segmented gradients.

A segmented gradient is a gradient that is applied across the string multiple times. Each segment is a gradient. When a segment ends, the gradient restarts. If reversal is on, the gradient will reverse itself.

For example, if the color is red and the gradient is green and the string is segmented 6 times

Code:
0      1        2      3        4      5        6
red -> green -> red -> green -> red -> green -> red

Background
Sevion started working on a library for coloring strings for a friend of his and I then got interested and started coding my own in parallel to his.

I'd give him my code so that he could improve his own and at the very end we decided to submit the one I coded together since mine had the original code as well as segmented gradients.

We went over the syntax and design together and added a method. I made initial docs, Sevion made drastic changes to those docs, and then I tweaked his changes.

The post, ColorHex, mixing, and Segmented Gradients were not made in parallel, those were solely by me ; \.

JASS:
library StringColors /* v2.0.0.2
*************************************************************************************
*
*   Used for creating Color objects that have alpha, red, green, and blue channels.
*
*************************************************************************************
*
*   struct Color extends array
*       integer alpha
*       integer red
*       integer green
*       integer blue
*       readonly string color
*           -   The color as a string "|c + color"
*
*       static method create takes integer alpha, integer red, integer green, integer blue returns Color
*       static method createEx takes integer red, integer green, integer blue returns Color
*       static method createFromHex takes integer hex returns Color
*       static method createFromHexEx takes integer hex returns Color
*       static method createFromMix takes Color color, Color gradient, real weight returns Color
*
*       method destroy takes nothing returns nothing
*
*       method reset takes nothing returns nothing
*           -   Resets color to white with no fade
*
*       static method convert takes integer alpha, integer red, integer green, integer blue returns string
*           -   Converts alpha, red, green, blue to color string
*           ->  "|cffffffff"
*
*       static method convertHex takes integer hex returns string
*           -   Converts alpha, red, green, blue to color string
*           ->  "|cffffffff"
*
*       method apply takes string toBeColored returns string
*           -   Applies color to string
*
*       method setMix takes Color color, Color gradient, real weight returns nothing
*           -   Sets color to mixture between target color and gradient given a weight
*           -   Weight is how much to apply the gradient to the color. A weight of 1 means apply the gradient fully.
*           -   A weight of 0 means don't apply the gradient at all.
*
*   struct Color.Gradient extends array
*       static method apply takes string toBeColored, Color color, Color gradient, integer segments, boolean reverses returns string
*       static method applyHex takes string toBeColored, integer colorHex, integer gradientHex, integer segments, boolean reverses returns string
*
*************************************************************************************/
    public keyword ColorGradient
    
    globals
        private string array hexChars
    endglobals
    
    struct Color extends array
        private static integer instanceCount = 0
        private static integer array recycler
        
        private integer redX
        private integer greenX
        private integer blueX
        private integer alphaX
        private string colorX
        
        public static method operator Gradient takes nothing returns ColorGradient
            return 0
        endmethod
        
        public static method convert takes integer alpha, integer red, integer green, integer blue returns string
            return "|c" + hexChars[alpha] + hexChars[red] + hexChars[green] + hexChars[blue]
        endmethod
        static method convertHex takes integer hex returns string
            local integer alpha
            local integer red
            local integer green
            local integer blue
            
            if (0 > hex) then
                set hex = -(-hex + 2147483648)
                set alpha = 128 + hex/16777216
                set hex = hex - (alpha - 128)*16777216
            else
                set alpha = hex/16777216
                set hex = hex - alpha*16777216
            endif
            
            set red = hex/65536
            
            set hex = hex - red*65536
            set green = hex/256
            set blue = hex - green*256
            
            return convert(alpha, red, green, blue)
        endmethod
        
        public method apply takes string toBeColored returns string
            return colorX + toBeColored + "|r"
        endmethod
        
        public method operator red takes nothing returns integer
            return redX
        endmethod
        
        public method operator red= takes integer val returns nothing
            set redX = val
            set colorX = convert(alphaX, redX, greenX, blueX)
        endmethod
        
        public method operator green takes nothing returns integer
            return greenX
        endmethod
        
        public method operator green= takes integer val returns nothing
            set greenX = val
            set colorX = convert(alphaX, redX, greenX, blueX)
        endmethod
        
        public method operator blue takes nothing returns integer
            return blueX
        endmethod
        
        public method operator blue= takes integer val returns nothing
            set blueX = val
            set colorX = convert(alphaX, redX, greenX, blueX)
        endmethod
        
        method operator alpha takes nothing returns integer
            return alphaX
        endmethod
        
        method operator alpha= takes integer val returns nothing
            set alphaX = val
            set colorX = convert(alphaX, redX, greenX, blueX)
        endmethod
        
        public method operator color takes nothing returns string
            return colorX
        endmethod
        
        method reset takes nothing returns nothing
            set alphaX = 255
            set redX = 255
            set greenX = 255
            set blueX = 255
            set colorX = convert(alphaX, redX, greenX, blueX)
        endmethod
        
        public static method create takes integer alpha, integer red, integer green, integer blue returns thistype
            local thistype this = recycler[0]
            
            if (0 == this) then
                set this = instanceCount + 1
                set instanceCount = this
            else
                set recycler[0] = recycler[this]
            endif
            
            set redX = red
            set greenX = green
            set blueX = blue
            set alphaX = alpha
            set colorX = convert(alpha, red, green, blue)
            
            return this
        endmethod
        
        static method createEx takes integer red, integer green, integer blue returns thistype
            return create(255, red, green, blue)
        endmethod
        
        static method createFromHex takes integer hex returns thistype
            local integer alpha
            local integer red
            local integer green
            local integer blue
        
            if (0 > hex) then
                set hex = -(-hex + 2147483648)
                set alpha = 128 + hex/16777216
                set hex = hex - (alpha - 128)*16777216
            else
                set alpha = hex/16777216
                set hex = hex - alpha*16777216
            endif
            
            set red = hex/65536
            
            set hex = hex - red*65536
            set green = hex/256
            set blue = hex - green*256
            
            return create(alpha, red, green, blue)
        endmethod
        
        static method createFromHexEx takes integer hex returns thistype
            return createFromHex(4278190080 + hex)
        endmethod
        
        public static method createFromMix takes Color color, Color gradient, real weight returns thistype
            local thistype this = recycler[0]
            
            if (0 == this) then
                set this = instanceCount + 1
                set instanceCount = this
            else
                set recycler[0] = recycler[this]
            endif
            
            set this.red = R2I(color.red-(color.red-gradient.red)*weight+.5)
            set this.green = R2I(color.green-(color.green-gradient.green)*weight+.5)
            set this.blue = R2I(color.blue-(color.blue-gradient.blue)*weight+.5)
            set this.alpha = R2I(color.alpha-(color.alpha-gradient.alpha)*weight+.5)
            
            return this
        endmethod
        
        public method destroy takes nothing returns nothing
            set recycler[this] = recycler[0]
            set recycler[0] = this
        endmethod
        
        private static method onInit takes nothing returns nothing
            local integer d0 = 16
            local integer d1
            set hexChars[0] = "0"
            set hexChars[1] = "1"
            set hexChars[2] = "2"
            set hexChars[3] = "3"
            set hexChars[4] = "4"
            set hexChars[5] = "5"
            set hexChars[6] = "6"
            set hexChars[7] = "7"
            set hexChars[8] = "8"
            set hexChars[9] = "9"
            set hexChars[10] = "A"
            set hexChars[11] = "B"
            set hexChars[12] = "C"
            set hexChars[13] = "D"
            set hexChars[14] = "E"
            set hexChars[15] = "F"
            
            loop
                set d0 = d0 - 1
                set d1 = 16
                loop
                    set d1 = d1 - 1
                    set hexChars[d0*16+d1] = hexChars[d0]+hexChars[d1]
                    exitwhen d1 == 0
                endloop
                exitwhen d0 == 0
            endloop
        endmethod
        
        public method setMix takes Color color, Color gradient, real weight returns nothing
            set this.red = R2I(color.red-(color.red-gradient.red)*weight+.5)
            set this.green = R2I(color.green-(color.green-gradient.green)*weight+.5)
            set this.blue = R2I(color.blue-(color.blue-gradient.blue)*weight+.5)
            set this.alpha = R2I(color.alpha-(color.alpha-gradient.alpha)*weight+.5)
            set this.colorX = convert(this.alpha, this.red, this.green, this.blue)
        endmethod
    endstruct
    
    public struct ColorGradient extends array
        public static method apply takes string toBeColored, Color color, Color gradient, integer segments, boolean reverses returns string
            local string colored        //the colored string
            local integer length        //length of string to color
            local integer position      //current character position of string to color
            
            local real addRed           //how much red to add
            local real addGreen         //how much green to add
            local real addBlue          //how much blue to add
            local real addAlpha         //how much alpha to add
            local real red              //current red
            local real green            //current green
            local real blue             //current blue
            local real alpha            //current alpha
            
            local integer segment       //current coloring segment
            local integer subPosition   //sub position of segment
            local integer subLength     //length of current segment (needed if string can't be split entirely)
            local real percent          //percent of color to use
            local integer flag          //neg flag
            
            //if the string exists, go on
            if (toBeColored != null and toBeColored != "") then
                set length = StringLength(toBeColored)
                set colored = ""
                set flag = 0
                set red = color.red
                set green = color.green
                set blue = color.blue
                set alpha = color.alpha
                set position = 0
                //if result is a single character or micro segments
                //return the string as base color
                if (length == 1 or segments >= length or segments <= 0) then
                    set colored = color.color + toBeColored
                elseif (segments > 1) then
                    //because subPosition starts at 0
                    //decrease by 1
                    set subLength = length/segments-1
                    //set sub position
                    set subPosition = 0
                    //all of the adders are just the complete as percents
                    //are used instead
                    set addRed = gradient.red - color.red
                    set addGreen = gradient.green - color.green
                    set addBlue = gradient.blue - color.blue
                    set addAlpha = gradient.alpha - color.alpha
                    //flag starts positive
                    set flag = 1
                    //segment starts at 0
                    set segment = 0
                    
                    loop
                        //add colored character to colored string
                        set colored = colored + Color.convert(R2I(alpha+.5), R2I(red+.5), R2I(green+.5), R2I(blue+.5))+SubString(toBeColored, position, position+1)
                        set position = position + 1
                        exitwhen position == length
                        
                        //if hit end of sub, reverse direction of gradient
                        if (subPosition == subLength or (subPosition == 0 and flag < 1)) then
                            set segment = segment + 1
                            set subLength = (length-position)/(segments-segment)
                            if (reverses) then
                                set flag = flag * -1
                                if (subPosition != 0) then
                                    set subPosition = subLength
                                endif
                            else
                                set subPosition = 0
                            endif
                        endif
                        
                        //move ahead the sub sub string
                        set subPosition = subPosition + flag
                        //get current percentage of movement
                        set percent = (subPosition +0.)/subLength
                        //set colors by percent
                        set red = color.red+addRed*percent
                        set green = color.green+addGreen*percent
                        set blue = color.blue+addBlue*percent
                        set alpha = color.alpha+addAlpha*percent
                    endloop
                //process single segment gradient
                else
                    //because this starts on 0, set length to length-1
                    set subLength = length-1
                    
                    //adders are based on total length
                    set addRed = (gradient.red - color.red + 0.)/subLength
                    set addGreen = (gradient.green - color.green + 0.)/subLength
                    set addBlue = (gradient.blue - color.blue + 0.)/subLength
                    set addAlpha = (gradient.alpha - color.alpha + 0.)/subLength
                    
                    loop
                        set colored = colored + Color.convert(R2I(alpha+.5), R2I(red+.5), R2I(green+.5), R2I(blue+.5))+SubString(toBeColored, position, position+1)
                        
                        set position = position + 1
                        exitwhen position == length
                        
                        set red = red + addRed
                        set green = green + addGreen
                        set blue = blue + addBlue
                        set alpha = alpha + addAlpha
                    endloop
                endif
                return colored + "|r"
            endif
            return null
        endmethod
        public static method applyHex takes string toBeColored, integer colorHex, integer gradientHex, integer segments, boolean reverses returns string
            local Color color = Color.createFromHex(colorHex)
            local Color gradient = Color.createFromHex(gradientHex)
            local string colored = apply(toBeColored, color, gradient, segments, reverses)
            
            call color.destroy()
            call gradient.destroy()
            
            return colored
        endmethod
    endstruct
endlibrary
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
One flaw you guys might not have noticed for this library is that it is literally only useful for strings and is actually inferior when dealing with anything other than strings (images, texttags, etc).

With a small tweak, it could be useful for images/texttags given that they didn't use alpha filters. With some major tweaks, it could be useful for that.

Now, what I could possibly do is add a boolean for enabling non string coloring and add some new color objects = ). I could also add a boolean for enabling string coloring. In this way, you could pick and choose what you wanted ^.^.

Thoughts?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I've been thinking something that JASS is absolutely terrible at is string-handling on the level of PHP or even JavaScript, so if you made something that enabled features like exploding or imploding user-friendly, that could open up some doors.

what does that have to do with string coloring? : P

also, Romek already made something for exploding : D.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
I find this way more difficult to use than ARGB; the interface isn't even natural.

Why do you have a type ColorHex when an integer will do the exact same thing? You can quite easily convert between an integer and a hexadecimal code using substring methods on "0123456789ABCDEF". I'll tell you right now that I probably won't ever need to use this, but azlier has approved it so I suppose my input isn't very important at this point.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
and you should never use integers like ARGB does >.<....

Where exactly did you hear that?

This is way more efficient than your method mate (uses an array)

I don't know about that. I'm not saying either method is better, but I wouldn't be so quick to jump to the conclusion that your method is superior unless you've got benchmarks behind to prove it.

JASS:
    struct ColorHex extends array
        public method operator red takes nothing returns integer
            return this/65536
        endmethod
        
        public method setRed takes integer val returns integer
            return this-this/256*256+(this/256-this/65536*256)*256+val*65536
        endmethod
        
        public method operator green takes nothing returns integer
            return this/256-this/65536*256
        endmethod
        
        public method setGreen takes integer val returns integer
            return this-this/256*256+val*256+this/65536*65536
        endmethod
        
        public method operator blue takes nothing returns integer
            return this-this/256*256
        endmethod
        
        public method setBlue takes integer val returns integer
            return this/256*256+val
        endmethod
        
        public method operator color takes nothing returns string
            return "|cff"+hexChars[this/65536]+hexChars[this/256-this/65536*256]+hexChars[this-this/256*256]
        endmethod
        
        public method apply takes string toBeColored returns string
            return color+toBeColored+"|r"
        endmethod
        
        public static method create takes integer red, integer green, integer blue returns thistype
            return (red*256+green)*256+blue
        endmethod
        
        public static method mix takes ColorHex color, ColorHex gradient, real weight returns ColorHex
            return (R2I(color/65536-(color/65536-gradient/65536)*weight+.5)*256+R2I((color/256-color/65536*256)-((color/256-color/65536*256)-(gradient/256-gradient/65536*256))*weight+.5))*256+R2I((color-color/256*256)-((color-color/256*256)-(gradient-gradient/256*256))*weight+.5)
        endmethod
        
        public static method operator Gradient takes nothing returns HexColorGradient
            return 0
        endmethod
    endstruct

This is pretty much just a wrapper, but why are you using a wrapper when we already are capable of using hexadecimal integers?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I don't know about that. I'm not saying either method is better, but I wouldn't be so quick to jump to the conclusion that your method is superior unless you've got benchmarks behind to prove it.

benchmarking it would be entirely pointless.. adding 3 strings together is faster than adding 6 strings together + using substring native 6x. That should be painfully obvious to you as well...

Where exactly did you hear that?

From nowhere... that again is painfully obvious... accessing a single value in an array is much faster than doing all the math necessary on a given integer to rip the value out of it... especially if you are doing ARGB values as wc3 does not support unsigned integers.

If you are just using it like a local (purely temp), using a global is still much better than using an integer with ARGB ...

Only reason I supported integers in this one (the hex stuff) was for the hell of it : P. I don't think it should ever be used under any circumstances.

This is pretty much just a wrapper, but why are you using a wrapper when we already are capable of using hexadecimal integers?

... you are seriously telling me that you enjoy writing out all of the math??? ... furthermore, wrappers should always be used... even if it's just calling another function with specific parameters. It provides stability and lessens the work a coder has to do. Normally, I'd split the methods up into many tiny 1-3 line methods, but this is JASS : P. If vjass had inline, I'd def do it >: D.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Both this system and ARGB use struct arrays to reference colors; the actual ARGB struct is similar in functionality (though far more advanced) but since they are both simply arrays of values that can be randomly accessed, the performance of either system is going to be about the same. This basically just applies the logic that ARGB offers to a string (though instead of using ARGB, you create your own).

From nowhere... that again is painfully obvious... accessing a single value in an array is much faster than doing all the math necessary on a given integer to rip the value out of it... especially if you are doing ARGB values as wc3 does not support unsigned integers.

So you heard "using an array instead of an integer" is better from nowhere, yet you're trying to impose it as if it is written in stone. Please provide where you heard that using integers is bad. I don't know what you're talking about "unsigned integers" for either it's irrelevant to this discussion.

If you are just using it like a local (purely temp), using a global is still much better than using an integer with ARGB ...

What ARGB does is use the integer for an array index look-up on the struct array; exactly as you have yours. You're telling me that yours is faster than ARGB aside from using the same mechanics to process the calculations.

... you are seriously telling me that you enjoy writing out all of the math???

No, but I don't have to, thanks to ARGB which allows me to apply my color gradients to everything, not just strings. There are a whole whack of other types that use RGB colors and I would rather not implement several systems that have the same struct array, rather use a single system that globalizes the entire process.

furthermore, wrappers should always be used...

Not when they aren't necessary.

Only reason I supported integers in this one (the hex stuff) was for the hell of it : P. I don't think it should ever be used under any circumstances.

You have a struct array that represents all of your colors, and you assign a struct variable to an integer (which is then translated by your wrapper); yet you say that simply using integers is bad. That doesn't make any sense - you have a wrapper class for an integer.

JASS:
    static method create takes integer a, integer r, integer g, integer b returns ARGB
        return ARGB(b + g*0x100 + r*0x10000 + a*0x1000000)
    endmethod

This simplifies everything you are trying to do in the ColorHex struct. You should actually read the ARGB library script.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
.... i've seen argb and it uses the first struct version unless he changed it : |... like ColorHex


half of your post is incoherent ; P . You are trying to talk about both of the structs in this thing as if they work together. They don't ; ).

ARGB uses a single integer like 0xHHHHHHHH. From here, it rips the different numbers out of it.. because there are no unsigned integers, it has to do some funky stuff ; |. Without unsigned integers, doing full ARGB is very fugly because ARGB values go up to 2^32-1 rather than 2^32/2-1 (the latter is wc3's signed limit in either direction).

so no, ARGB color.red does not return something like red[500]... it rips the red value out of your integer. Returning red[500] or something is far faster than performing all the math on an integer like 0xHHHHHHHH to rip the HH out of it : |.

It is exactly like ColorHex, yes, the struct that I said you should never use under any circumstances and the struct that I said I implemented only for the hell of it : ). I am talking about Color, not ColorHex, because again I said you should never ever use ColorHex : P.

And I will stand by this statement forever- "using an array instead of an integer"

Using an array is better than performing all of the necessary operations on an integer to rip out the values.

Where is Azlier : (.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
You are seriously telling me that you believe this
JASS:
    method operator red takes nothing returns integer
     local integer c=integer(this)*0x100
        if(c<0) then
            return 0x80+(-(-c+0x80000000))/0x1000000
        else
            return c/0x1000000
        endif
    endmethod
    method operator red= takes integer nr returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(b + g*0x100 + nr*0x10000 + a*0x1000000) 
    endmethod

is faster than this?
JASS:
    method operator red takes nothing returns integer
        return colorRed[this]
    endmethod
    method operator red= takes integer nr returns ARGB
        set colorRed[this] = nr
    endmethod

As I said, benchmarks are totally unnecessary...

Also, ARGB's return is fugly because all integers in JASS are unsigned. It wouldn't need those extra checks or anything if JASS supported unsigned integers ; (.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Well, I didn't think that ARGB would use that much calculations D:
that's most likely slower than an array lookup, of course.

That code came straight out of ARGB.... so it does use that many calculations >.<..

That code was what this entire argument was about. I swear I was starting to think everyone was on crack.

So are there any other arguments against this or is everyone ok now? We handled the 3 string vs 6 string + 6 natives, the unsigned vs signed, the rip the values out of an integer vs an array look up, and the never use ColorHex (which is RGB instead of ARGB, which is faster since it can run off of a signed integer just fine, meaning that ARGB should never be used as well, lol).
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
the rip the values out of an integer vs an array look up

ARGB doesn't "rip" the values out of an integer, it uses a very similar method to what you're doing. ARGB does not use substring calls, it doesn't use any. There is not one single native call in ARGB - you should actually read the code before explaining to people how yours is more efficient.

is RGB instead of ARGB, which is faster since it can run off of a signed integer just fine

Where do you get this idea that it's faster since it can run off of a signed integer.

What are you people on?

An array look up is ALWAYS going to be faster than a native call.

On the contrary, what are you on. As I said, ARGB does not use a single native call. Maybe you should actually read the code that you are claiming to have more optimization over.

Vex's also has useless alpha

It isn't useless on text-tags, or images, or units, or half of the types in Warcraft. Clearly you're the one on crack.

ARGB uses a single integer like 0xHHHHHHHH. From here, it rips the different numbers out of it.. because there are no unsigned integers, it has to do some funky stuff ; |. Without unsigned integers, doing full ARGB is very fugly because ARGB values go up to 2^32-1 rather than 2^32/2-1 (the latter is wc3's signed limit in either direction)

JASS:
    static method create takes integer a, integer r, integer g, integer b returns ARGB
        return ARGB(b + g*0x100 + r*0x10000 + a*0x1000000)
    endmethod

What are you talking about, "some funky stuff", there is nothing "funky" about this it is incredibly straight forward. These are simple math calculations.

Also you earlier compared two unfair segments of code. ARGB factors in certain calculations allowing you to manipulate the gradient of the color. The contraption you have said up for gradients is far slower than what Vexorian does. Take a look at his mixing method:

JASS:
    static method mix takes ARGB c1, ARGB c2, real s returns ARGB
      //widest function ever
      return ARGB( R2I(c2.blue*s+c1.blue*(1-s)+0.5) + R2I(c2.green*s+c1.green*(1-s)+0.5)*0x100 + R2I(c2.red*s+c1.red*(1-s)+0.5)*0x10000 + R2I(c2.alpha*s+c1.alpha*(1-s)+0.5)*0x1000000)
    endmethod

That beats the hell out of:

JASS:
    public struct ColorGradient extends array
        public static method apply takes string toBeColored, Color color, Color gradient, integer segments, boolean reverses returns string
            local string colored //the colored string
            local integer length //length of string to color
            local integer position //current character position of string to color
            
            local real addRed //how much red to add
            local real addGreen //how much green to add
            local real addBlue //how much blue to add
            local real red //current red
            local real green //current green
            local real blue //current blue
            
            local integer segment //current coloring segment
            local integer subPosition //sub position of segment
            local integer subLength //length of current segment (needed if string can't be split entirely)
            local real percent //percent of color to use
            local integer flag //neg flag
            
            //if the string exists, go on
            if (toBeColored != null and toBeColored != "") then
                set length = StringLength(toBeColored)
                set colored = ""
                set flag = 0
                set red = color.red
                set green = color.green
                set blue = color.blue
                set position = 0
                //if result is a single character or micro segments
                //return the string as base color
                if (length == 1 or segments >= length or segments <= 0) then
                    set colored = color.color+toBeColored
                elseif (segments > 1) then
                    //because subPosition starts at 0
                    //decrease by 1
                    set subLength = length/segments-1
                    //set sub position
                    set subPosition = 0
                    //all of the adders are just the complete as percents
                    //are used instead
                    set addRed = gradient.red - color.red
                    set addGreen = gradient.green - color.green
                    set addBlue = gradient.blue - color.blue
                    //flag starts positive
                    set flag = 1
                    //segment starts at 0
                    set segment = 0
                    
                    loop
                        //add colored character to colored string
                        set colored = colored + Color.convert(R2I(red+.5), R2I(green+.5), R2I(blue+.5))+SubString(toBeColored, position, position+1)
                        set position = position + 1
                        exitwhen position == length
                        
                        //if hit end of sub, reverse direction of gradient
                        if (subPosition == subLength or (subPosition == 0 and flag < 1)) then
                            set segment = segment + 1
                            set subLength = (length-position)/(segments-segment)
                            if (reverses) then
                                set flag = flag * -1
                                if (subPosition != 0) then
                                    set subPosition = subLength
                                endif
                            else
                                set subPosition = 0
                            endif
                        endif
                        
                        //move ahead the sub sub string
                        set subPosition = subPosition + flag
                        //get current percentage of movement
                        set percent = I2R(subPosition)/subLength
                        //set colors by percent
                        set red = color.red+addRed*percent
                        set green = color.green+addGreen*percent
                        set blue = color.blue+addBlue*percent
                    endloop
                //process single segment gradient
                else
                    //because this starts on 0, set length to length-1
                    set subLength = length-1
                    
                    //adders are based on total length
                    set addRed = I2R(gradient.red - color.red)/subLength
                    set addGreen = I2R(gradient.green - color.green)/subLength
                    set addBlue = I2R(gradient.blue - color.blue)/subLength
                    
                    loop
                        set colored = colored + Color.convert(R2I(red+.5), R2I(green+.5), R2I(blue+.5))+SubString(toBeColored, position, position+1)
                        
                        set position = position + 1
                        exitwhen position == length
                        
                        set red = red + addRed
                        set green = green + addGreen
                        set blue = blue + addBlue
                    endloop
                endif
                return colored+"|r"
            endif
            return null
        endmethod
    endstruct

Bottom line your library is 490 lines of code, where as ARGB is only 306. Not to mention ARGB includes a method for coloring strings - meaning it achieves the exact same functionality as yours in 200 lines of less code. Yours is most definitely not more optimal, nor does it prove useful when you're trying to color handles.
 
Last edited:
Level 8
Joined
Oct 3, 2008
Messages
367
Okay, some stuff here. And stop accusing eachother of being on various drugs. That means you, Nestarts.

1) ARGB DOES in fact include native calls. Berb realizes this now, but meh. Just shows how WC3C's highlighting doesn't help.

2) I2R is a useless native. Didn't spot this earlier. It can be replaced with i + 0. Yes, it's definitely faster. I'd change that, Nestathus.

3) I do believe there's a separate native for alpha on texttags. But, I also believe that string alpha fails to work pretty much everywhere else, including widgets, tooltips of various types, text messages, dialogs, multiboards, etc. Really, the only place alpha seems to be truly useful is those TextSplat things that nobody seems to remember anymore.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
TextSplat, Image, Unit (forget about vertex color?) - I would consider these to be necessity enough to warrant being supported.

This is the native for text-tag coloring: native SetTextTagColor takes texttag t, integer red, integer green, integer blue, integer alpha returns nothing

So text-tag is also on that list. I'd consider these fairly important elements of gameplay, especially units.

JASS:
native SetImageColor takes image whichImage, integer red, integer green, integer blue, integer alpha returns nothing
native SetLightningColor takes lightning whichBolt, real r, real g, real b, real a returns boolean
native SetUnitVertexColor takes unit whichUnit, integer red, integer green, integer blue, integer alpha returns nothing
native SetWaterBaseColor takes integer red, integer green, integer blue, integer alpha returns nothing
native TimerDialogSetTimeColor takes timerdialog whichDialog, integer red, integer green, integer blue, integer alpha returns nothing
native SetTextTagColor takes texttag t, integer red, integer green, integer blue, integer alpha returns nothing
native CreateUbersplat takes real x, real y, string name, integer red, integer green, integer blue, integer alpha, boolean forcePaused, boolean noBirthTime returns ubersplat

  • Lightning
  • Image
  • Unit
  • TextTag
  • Ubersplat
  • Water Color

Lightning is another important one.

Fairly significant. Whatever though, my arguing doesn't solve anything - if people want to use this resource they can do so whether I approve it or not. I just hate to see unsatisfactory resources be approved for people to run into problems with. Not to mention the interface is relatively difficult to follow.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Berb, I'm done arguing. Your statements don't make any sense at all nor do your examples. It's like me trying to compare the inefficiency in fuel of a car as compared to an engine.

Obviously I've already posted my own examples as to precisely what I'm talking about and you simply choose to ignore them calling them unfair : ). You post example of things that don't even do the same thing and I go wth?

Berb, just step back and relax for a bit. When you aren't as emotional, come back, think for a moment, and you'll start to see everything more clearly, k.

I2R is a useless native. Didn't spot this earlier. It can be replaced with i + 0. Yes, it's definitely faster. I'd change that, Nestathus.

I shall : )

I would consider these to be necessity enough to warrant being supported.

And remember, this library is for coloring strings : P. Because of the fugliness of signed integers vs unsigned integers when dealing with ARGB values on plain hex values, it's best to have 2 separate libraries or have one library using another one : P.

edit
1.2.0.4 going up with removal of all I2R
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Berb, I'm done arguing. Your statements don't make any sense at all nor do your examples. It's like me trying to compare the inefficiency in fuel of a car as compared to an engine.

Berb said:
ARGB doesn't "rip" the values out of an integer, it uses a very similar method to what you're doing. ARGB does not use substring calls, it doesn't use any. There is not one single native call in ARGB - you should actually read the code before explaining to people how yours is more efficient.

Clearly incoherent, yes. Sounds like you're just trying to avoid facts.

Obviously I've already posted my own examples as to precisely what I'm talking about and you simply choose to ignore them calling them unfair : ). You post example of things that don't even do the same thing and I go wth?

I didn't ignore them, but you're comparing the most efficient part of your system to the least efficient part of ARGB - as if yours is skyrocketing in efficiency. If you want to truly argue then go produce a benchmark of how long it takes to successfully color a string with gradients using your system.

"using an array instead of an integer"
We handled the 3 string vs 6 string + 6 natives, the unsigned vs signed, the rip the values out of an integer vs an array look up

You don't even make any fucking sense, and you're calling me incoherent. You've said several different things and upon me replying you've simply restated them, without any factual support for any of your claims.

I haven't done a whole lot of work with coloring handles/strings, so the only thing I have to argue on here is logic - which you have presented none of. You've told me several times now that using an array is faster than using an integer which only shows your complete misunderstanding of how vJass works, not to mention using a single integer is faster than an array look-up (so I don't know where the hell you're coming from), and it all started with this:

so no, ARGB color.red does not return something like red[500]... it rips the red value out of your integer. Returning red[500] or something is far faster than performing all the math on an integer like 0xHHHHHHHH to rip the HH out of it : |.

All you need is division to get the "HH" from "0xHHHHHHHH", what do you mean "all the math", division is hardly a performance lagger.

What the fuck is "red[500]". Obviously "ARGB does not return something like red[500]" because red[500] is stupid and unusable. It isn't logical in any sense to consider colors that way, nor do I even understand where the hell you get that interface idea from.

Now, since you haven't replied with any facts to anything I have said, let me restate the questions:

  • Where do you get the idea that it's faster since it can run off of a signed integer.
  • What are you talking about, "some funky stuff", there is nothing "funky" about this it is incredibly straight forward. These are simple math calculations.
  • So you heard "using an array instead of an integer" is better from nowhere, yet you're trying to impose it as if it is written in stone. Please provide where you heard that using integers is bad. I don't know what you're talking about "unsigned integers" for either it's irrelevant to this discussion. (http://www.hiveworkshop.com/forums/1653650-post18.html)
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
At this point (since this last post was just over the top) I'm going to just agree to disagree with you. I'll stay away from your threads from now on.

Eh, ok ; ). It seems like you are completely misunderstanding me, even though I said specifically why, in this case, using an integer is worse than using arrays. It has to do with the math involved in ripping out the values... not so much in the plain ripping, but the ripping so that those values can be set.

When you are dealing with a composite integer, to set a value within that integer you have to break that integer down, set the value, and then reconstruct the integer. With arrays, it's already broken down for you, so it doesn't need to be deconstructed/reconstructed. The math involved in deconstructing and reconstructing has a lot more overhead than setting an array.

Furthermore, reading an array should be faster than reading a specific value out of an integer. For the largest value, you only need to divide, but the number you are dividing by is 16^3... for the ones in between you need to use a combination of modulos math and division. For the smallest, it is modulos math.

The only code you have been really focusing on is the constructor. I'm talking about everything else. When I tried to paste an example of what I was talking about, you said that code was unfair (it was read + write)... so you tried to compare the mixing to setting a gradient, and keep in mind gradients are not the same thing as mixing two colors at all... gradient is setting every character of a string over a color spectrum. Mixing is mixing 2 colors to form 1 color. Obviously they are not even close to the same thing. I said you were comparing a car to an engine because just like gradients use mixing as their core, cars use engines as their core.

With red[500], 500 is a reference for a struct and red is one of that struct's fields.

set red[500] = 15 is much faster than taking 0xAARRGGBB, deconstructing it to AA RR GGBB, setting the RR portion to 15, and then reconstructing it to AARRGGBB. That is the major point I was making.

Furthermore, 8 hexadecimal numbers when combined to one number can result in a value of 2^32-1, which is the max size of an integer. This is the reason these colors are called 32 bit. With a signed integer, half of the value is used for negative and the other half is used for positive. What this means is (unless you want negative colors, which doesn't make sense) that you are only able to use 2^32/2-1. The fugliness I was referring to was in handling the negative numbers.. when you go above or below 2^32/2+-1, the sign flips. The fugliness comes in handling the negative numbers, which if you actually paid attention to the ARGB code, is exactly what Vexorian does.

I hope you can clearly understand what I am saying now.

And for the record, if you want to look at the mixing, then compare ARGB's mixing method to mine... don't compare the mixing method to the gradient method.... if you look, it's 3 array values vs deconstructing 2 hexadecimal numbers and reconstructing them as 1.



The reason I kept saying you seem utterly confused is because you were completely missing all of the points above, which I was repeating from post to post to post.
 
Level 14
Joined
Jan 5, 2009
Messages
1,127
Seriously, why argue about making something so pefect... Seriously, what Nestharus has done is wonderful, Its nicely explained.
So some noob can go import done
JASS:
local string noob = green.apply("Noobs Rule!")
instead of
JASS:
local string noob = "|cff00ff00Noobs Rules!|r"
Gosh.
Anyway.
If it works fast and doesn't take a huge amount processor memory be happy.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Seriously, why argue about making something so pefect... Seriously, what Nestharus has done is wonderful, Its nicely explained.
So some noob can go import done

Well, personally I'm a perfectionist.

My stance is that Berb is simply confused and that one day he will finally get it and go, "whoops."

I'm presenting all of this so that people from the sidelines can see precisely what was being argued over and what is going on.

Argument 1:
The argument was concerning breaking down an integer into 4 integers (lots of math), setting one of those 4 integers to a value, and then reconstructing those 4 integers into an integer (ARGB) vs using 3 arrays = P.

If you can't visualize the above, imagine setting an array value like set red[this] = val vs return this-this/256*256+(this/256-this/65536*256)*256+val*65536

My argument was that the arrays are faster than the integer. Berb's argument is that the integer is faster than the arrays (I know, I was thinking wtf too).

Argument 2:
The other argument was providing alpha for a library called String Colors... My argument was that didn't make sense since this library is for strings. I also brought up unsigned when dealing with those integers, which apparently flew past Berb multiple times. ((255*256+255)*256+255)*256+255, the max possible value for an integer when including the alpha filter, goes up to 2^32-1, or 4294967295. If you recall, the maximum size for an integer in wc3 is 2147483647, or 2^32/2-1. The reason for this is because wc3 integers are all signed. Colors are 32 bit, which is where the huge number comes from. If wc3 could use unsigned integers, the max for an int would be 2^32-1, meaning that alpha filters for something like ARGB would be absolutely no problem. When you do something like 2147483647+1, it'll go to -2147483647. ARGB handles full 32 bit colors in a single signed integer by handling the negatives, which requires extra processing (more math on top of all the math you already need to do). This is the reason I said that alpha filters aren't worth it considering they don't work on strings and that wc3 doesn't support unsigned integers.

Argument 3:
This argument compared ARGB's mixing method to this system's gradient method... if you know what a gradient is, you should be thinking wtf at this point. If you don't, gradients will take a string and a color spectrum (2 colors like red to green) and apply that color spectrum to that string (like a rainbow moving from red to green). This means it does in fact use mixing to do each character (mine is a bit smarter), but mixing is certainly not at all the same thing as a gradient.

Comparing the actual mixing method with this one's mixing method, the ARGB's does deconstruction of 2 integers and reconstructs them as one mixed integer. This one just does 3 array sets ; P. I already showed the math above in Argument 1 as compared to an array set, so it should be fairly obvious which one wins.

The gradients this uses supports segmented gradients (like moving from red to green, then red to green, etc) and reversal segmented gradients (moving from red to green to red to green), so that's where the extra code comes in. Each loop is its own thing and it goes through an if statement to determine which loop to use (to make it faster).

Argument 4:
Why do you have a type ColorHex when an integer will do the exact same thing? You can quite easily convert between an integer and a hexadecimal code using substring methods on "0123456789ABCDEF"
I responded with the Color struct instead of the ColorHex (probably where the confusion started) and made my stance that ColorHex should never be used. Color struct does 3 array reads and adds 5 strings together (alpha filter, 3 array reads, and reset). Using substring methods on the string he proposed would use 6 native calls, 6 string reads, and add 8 strings together (alpha, 6 substring chars, reset). I said that there is no comparison between them. At this point more confusion arose about something to do with natives in ARGB or w/e... I have no idea how my argument was misconstrued o-o, I thought it was quite clear.

There is nothing wrong with this library except for the fact that it has the extraneous ColorHex (something I said should never be used).

For those on the sidelines, I hope that this post will provide clarity to what's been going on in this thread. I know some people have jumped in having no idea what was going on. This post should fill you in.

Furthermore, this was and continues to be my closing statement
Berb, I'm done arguing. Your statements don't make any sense at all nor do your examples. It's like me trying to compare the inefficiency in fuel of a car as compared to an engine.

I, again, am simply presenting my understanding of what was argued so people can come in knowing precisely what was happening on this thread without having to read through a bundle of posts = ). This post is also here to help people make an informed decision on what coloring system they should use =).
 
Last edited:
Level 7
Joined
Jun 6, 2010
Messages
224
It's so boring watching others that state that their vJass interface,structs are faster.

vJass is for babies, and vJass compiles into one huge BJ
How's that faster

Jass > ALL

Get over it and stop arguing like babies.
And you can't really benchmark this since all it does is maths.
even a 100mhz proccessor can handle millions of instances of your silly code berb.

---------
to topic

I won't use this cause i don't need it, but good job.
+rep
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
You obviously don't realize you are talking to one of the best coders that I know, even the spell moderator considers him as good as the mod himself. So now, you say that they wine and argue like babies, maybe you should re-read your post then make a better judgement.

I agree ; ). When reading your post Prince, you seem somewhat ignorant as to what vjass does. This statement kind of gave that away

vJass is for babies, and vJass compiles into one huge BJ
How's that faster

But thank you for the compliment ; ).

I also think that Berb is quite the good coder (I was somewhat shocked in some of the things that were said in this argument: he's normally not like that at all).

Anyways, this argument did kind of end a while ago... you should have read the final summary on what was being argued about and why I was so confused as to what Berb was saying o-o. It was written for a reason : P.

Oh well, again thank you for the compliment.

In finality, this library does have a couple of issues:
1. Should support an RGB color as well as an ARGB color. Only supports RGB atm. ARGB should not inherit from RGB so as to keep the methods efficient.
2. ColorHex should be removed.. it's useless ; |.

But this really did drop way down on my priority list... so will I ever actually do those things? Probably not. After all, SC2 came out... that makes wc3 a relic in my eyes ; P. This means that to me, spending my time doing JASS code is a waste of time ^.^.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Perhaps it is my prejudice towards scripts that perform very similarly functionality-wise. If I were to be using ARGB for coloring handles (of which above there is a list) then I probably wouldn't want to download this specifically for coloring strings. I just find it much easier not to have multiple systems that do the same thing - it makes debugging problems that much more problematic and it can slow things down if you don't know what you're doing.

I suppose this library isn't THE SUCK, probably better than many of the libraries that are in the JASS section - but why did you have to make something that was already made. I guess I let it get to me too much.

Now that that's settled.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I suppose this library isn't THE SUCK, probably better than many of the libraries that are in the JASS section - but why did you have to make something that was already made. I guess I let it get to me too much.

It says why this was made etc in the very first post. Sevion was working on a string coloring library for a friend of his and I got interested and made this one in parallel = ). Yes, I didn't even do any research on current string coloring libraries. I made it for the hell of it, not because I was going to actually use it ; P. I guess to me it was a competition as to who could make the better string coloring library faster.

Perhaps it is my prejudice towards scripts that perform very similarly functionality-wise. If I were to be using ARGB for coloring handles (of which above there is a list) then I probably wouldn't want to download this specifically for coloring strings. I just find it much easier not to have multiple systems that do the same thing - it makes debugging problems that much more problematic and it can slow things down if you don't know what you're doing.

My thoughts were making this support RGB and ARGB and getting rid of the HexColor struct ^.^. The ARGB and RGB would be sep structs to make the methods as fast as possible as well as the loops ; ). They'd essentially use the same globals, but not the same methods ; P.

Again, chances are that the update will never happen because SC2 is out ; (.

Oh well, at least everyone is finally on the same page and we all understand each other (almost everyone anyways).
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Oh and Prince.Zero
JASS:
struct Hi extends array
    public integer oh
endstruct

That compiles to around
integer array oh

And methods that are static within structs that extend array are exactly the functions. Methods that aren't take an extra argument integer this.

If you know the right way to use vjass, there isn't an overhead ; ).

I personally prefer an OO syntax over plain old procedural syntax, so given no overhead and OO syntax, I pick vjass over plain old JASS.

And you guys seem a little confused... that post I posted was directed at Prince.Zero (given I said Prince in it), not Midnighters.

You are right, I do not know Jass or vJass. but I trust berbs choices. Unlike what you guys think.

And I don't know who you are talking to Midnighters, because not once did I say vjass was a bad choice and I was actually supporting you... you guys both seem confused ; P.

Now come on guys, if you are going to argue about something unrelated to this system or w/e, do it in a pm or something >.<.

Also vJASS can't be compared to GUI... vjass is a precompiler... GUI is a graphical user interface that happens to run off of function wrappers (the infamous BJs). vJASS does not compile into a bundle of function wrappers... that doesn't even make sense >.>... this is why I said that you "Prince" didn't seem to understand what vjass was or did.
 
Top