Programming Help needed for Colors Mod


#1

EDIT : I have finished this program and it now has it’s own thread here.
Thank you everyone for the help! :smile:


Hi guys, I was planning on keeping this a secret, but I need some help.

I’m working on a program which will allow the user to basically take one item and turn it into many items of different colors.

When finished, it will generate the necessary QB, PNG, and JSON files as well as code for recipes and the manifest.
I’ve almost got it to the point where I am ready to let the community play with it, but I’ve run into a problem: It works perfectly generating colored QBs, except for orange. Just orange, everything else turns out great, but orange.

If you guys could have a look and give me your input that would be great :smile:
Below are snippets of my code which I think might be relevant to the problem. Also I’ve uploaded the vbproject onto github, If anyone want’s to take a look at all the (messy, somewhat uncommented) code >.>;


Somewhere in the code is the reason


This section defines the colors, the 3 numbers are Hue, Saturation, and Value.
Orange’s Hue is 30, but it comes out as 0, which is red, If I change it to 31 it comes out 60, which is yellow.

Public basicColors() As dye_color = { New dye_color("red", "Red", 0, 0, 0, False, False),
      New dye_color("orange", "Orange", 30, 0, 0, False, False),
      New dye_color("yellow", "Yellow", 60, 0, 0, False, False),
      New dye_color("green", "Green", 125, 0, 0, False, False),
      New dye_color("blue", "Blue", 210, 0, 0, False, False),
      New dye_color("purple", "Purple", 275, 0, 0, False, False),
      New dye_color("undyed", "Undyed", 40, 30, 0, True, False)}

This code converts QB’s format of Int32 colors into a more usable format of RGBA. (and back again)

Public Shared Function INT32toRGBA(ByVal int32 As Integer)
    Dim bytes() As Byte = BitConverter.GetBytes(int32)
    Return bytes
End Function

Public Shared Function RGBAtoINT32(ByVal r As Integer, ByVal g As Integer, ByVal b As Integer, ByVal a As Integer)
    Dim bytes() As Byte = New Byte() {r, g, b, a}
    Dim int32 As Integer = BitConverter.ToInt32(bytes, 0)
    Return int32
End Function

This code converts RGB(no A) into HSV so that I can easily change the Hue of the QB/PNG.
hsv(0) is Hue, hsv(1) is Saturation, and hsv(2) is Value
This code is based off the the code found here.
The extra 255 in saturation is to match it up to QB Constructs Color Dialog

Public Shared Function RGBtoHSV(ByVal r As Integer, ByVal g As Integer, ByVal b As Integer)
    Dim hsv(2) As Integer
    Dim min As Double, max As Double, delta As Double

    If r <= g And r <= b Then min = r
    If b <= g And b <= r Then min = b
    If g <= r And g <= b Then min = g

    If r >= g And r >= b Then max = r
    If b >= g And b >= r Then max = b
    If g >= r And g >= b Then max = g

    hsv(2) = max
    delta = max - min

    If max <> 0 Then
        hsv(1) = (delta / max) * 255
        If r = max Then
            hsv(0) = (g - b) / delta
        ElseIf g = max Then
            hsv(0) = 2 + (b - r) / delta
        Else
            hsv(0) = 4 + (r - g) / delta
        End If
        hsv(0) = hsv(0) * 60
        If hsv(0) < 0 Then hsv(0) = hsv(0) + 360
        If hsv(0) > 360 Then hsv(0) = hsv(0) - 360

    Else
        hsv(1) = 0
        hsv(0) = 0
    End If
    Return hsv
End Function

This code converts it back to RGB
rgb(0) is red, rgb(1) is green, rgb(2) is blue.
This code is based off the the code found here.
The extra 255 in saturation is to match it up to QB Constructs Color Dialog

Public Shared Function HSVtoRGB(ByVal h As Integer, ByVal s As Integer, ByVal v As Integer)
    Dim rgb(2) As Byte
    Dim i As Long
    Dim f As Double, p As Double, q As Double, t As Double

    If s = 0 Then
        rgb(0) = v
        rgb(1) = v
        rgb(2) = v
    Else
        h = h / 60
        i = Math.Floor(h)
        f = h - i
        p = v * (1 - (s / 255))
        q = v * (1 - (s / 255) * f)
        t = v * (1 - (s / 255) * (1 - f))

        Select Case i
            Case 0
                rgb(0) = v
                rgb(1) = t
                rgb(2) = p
            Case 1
                rgb(0) = q
                rgb(1) = v
                rgb(2) = p
            Case 2
                rgb(0) = p
                rgb(1) = v
                rgb(2) = t
            Case 3
                rgb(0) = p
                rgb(1) = q
                rgb(2) = v
            Case 4
                rgb(0) = t
                rgb(1) = p
                rgb(2) = v
            Case 5
            Case Else
                rgb(0) = v
                rgb(1) = p
                rgb(2) = q
        End Select
    End If
    Return rgb
End Function

And Finally, here is what reads every voxel of the QB file and recolors it if necessary.
QB is the original QB file
QB_NEG is a special file based on the original. All the pixels in QB which need recolored are black in QB_NEG.

 Public Shared Function recolorQB(ByVal QB As QBModel, ByVal QB_NEG As QBModel, ByVal hue As Integer, ByVal sat As Integer, ByVal val As Integer, ByVal setSat As Boolean, ByVal setVal As Boolean)
    Dim NewQB As New QBModel
    NewQB = QB

    'go through QB_NEG until a black voxel is found
    For i As Integer = 1 To QB_NEG.getMatrixCount
        Dim j As Integer = i - 1
        For z As Integer = 0 To QB_NEG.matrix(j).data.GetLength(2) - 1
            For y As Integer = 0 To QB_NEG.matrix(j).data.GetLength(1) - 1
                For x As Integer = 0 To QB_NEG.matrix(j).data.GetLength(0) - 1
                    If QB_NEG.matrix(j).data(x, y, z) > 0 Then
                        Dim colorbytes() As Byte = INT32toRGBA(QB_NEG.matrix(j).data(x, y, z))
                        If colorbytes(0) = 0 And colorbytes(1) = 0 And colorbytes(2) = 0 And colorbytes(3) <> 0 Then    'voxel is visible and pure black
                            'open that voxel in NewQB
                            'convert int32color to rgba, rgba to hsv
                            Dim rgba() As Byte = INT32toRGBA(NewQB.matrix(j).data(x, y, z))
                            Dim hsv() As Integer = RGBtoHSV(rgba(0), rgba(1), rgba(2))

                            'change hue
                            hsv(0) = hue
                            'change saturation
                            If setSat Then
                                hsv(1) = sat
                            Else
                                hsv(1) = hsv(1) + sat
                            End If
                            'change value
                            If setVal Then
                                hsv(2) = val
                            Else
                                hsv(2) = hsv(2) + val
                            End If

                            'make sure hsv is in the correct bounds
                            If hsv(0) < 0 Then hsv(0) = 0
                            If hsv(0) > 360 Then hsv(0) = 360

                            If hsv(1) < 0 Then hsv(1) = 0
                            If hsv(1) > 255 Then hsv(1) = 255

                            If hsv(2) < 0 Then hsv(2) = 0
                            If hsv(2) > 255 Then hsv(2) = 255

                            'convert new hsv to rgba (using original a)
                            Dim rgba_temp() As Byte = HSVtoRGB(hsv(0), hsv(1), hsv(2))
                            rgba(0) = rgba_temp(0)
                            rgba(1) = rgba_temp(1)
                            rgba(2) = rgba_temp(2)

                            'convert rbga to int32color
                            'set voxel in NewQB to int32color
                            NewQB.matrix(j).data(x, y, z) = RGBAtoINT32(rgba(0), rgba(1), rgba(2), rgba(3))
                        End If
                    End If
                Next
            Next
        Next
    Next
    Return NewQB
End Function

Any help anyone can give would be greatly appreciated!
I’m going to go digging through the code again and hope something pops up.


[Mod] Colors Mod by Chimeforest
#2

this is brilliant! :smile: :+1:

paging @RepeatPan, @Froggy, @voxel_pirate, @bitassassin:wink:


#3

I don’t see any immediately obvious mistakes. Does it work if you ONLY select the orange conversion?


#4

Form1.vb line 104:

build color selection
            For i As Integer = 0 To CheckedListBox1.Items.Count - 1

Should that be “Integer = 1” instead of “Integer = 0”? My weapon of choice is not VB but I believe everything is 1-indexed.


#5

Thanks for your suggestions

I tried only selecting one Orange, but it still doesn’t work.

VB is … weird, when it comes to indexs, Arrays (such as baseColors ) are indexed starting at 0, but Collections (such as colors_to_use ) start at 1 =/

I tried setting “Integer = 1”, but all that did was skip red (color #0)

VB isn’t usually my weapon of choice either, even though it was my first real programming language. I chose it because it would be good practice and because it can update progress bars without having to program a special work thread to do it ^^

If all else fails, I could try doing it in Java, but I’m so close to finishing it.
And there is no guarantee that this same problem won’t occur again in java =/


#6

I did something very similar as a ShPad extension (to prove that even simple re-coloration can add a lot to individualisation I think) where it allowed you to re-color (or I think “tint”) matrices as you please.

I’m afraid I can’t help you here however as I don’t know VB, nor do I intend to learn it. It’s not a language that I find particularly interesting.

Looks really interesting though! It makes me wonder whether building Jofferson as some sort of IDE with plugins would be worth the effort.


#7

Could you describe your algorithm to me? I get the basic idea from looking at your code but I’d like to see what the intention was.

For example (I didn’t base this off of anything, just giving a random example):

Loop over all of the selected colors
Load selected .qb files
Loop over voxels in file
Convert RGBA to HSL

This is such a weird bug it feels like this should be a very simple fix.


#8

Sure! Here it is:

Define global variables
    basicColors()
    currentColor

On Button Click
    Define local vars
    Loop; Go through input folder and sort into QB,PNG,JSON and misc.
    Loop; if checked, add color to colors_to_use[]
    Import QBs into variables
    Import PNGs into variables
    ~~MAIN~~
    Loop{i} for all colors_to_use[]
        current_color = colors_to_use[i]
        Make needed folder
        Recolor QB to current_color
             Loop over voxels in QB_NEG file
             If voxel = black; recolor in QB
                 Convert INT32 qb color to RGBA
                 Convert RGBA to HSV
                 Change Hue, Saturation, and Value to currentColor
                 Convert new HSV to RGBA
                 Convert RGBA to INT32
                 Change QB voxel color to new INT32
             End Loop
        Recolor PNG(not implemented yet)
        Parse JSONs(not implemented yet in main)
    End Loop
End OnClick

I think the problem must be somewhere in the RGBAtoHSV or HSVtoRGBA since orange is the only color affected.
I’m going to try some stuff with the code to see if I can pinpoint exactly where it is getting miscolored.


#9

Thanks for breaking it down like that. Without trying to run this code or fiddle with it, I’m inclined to agree that it’s either RGBtoHSV or HSVtoRGB. I looked at that website where you sourced your functions from and I thought I might have noticed some inconsistencies.

If I have some time tonight and you haven’t figured this out, I might try to write both your version and that website’s version of those functions and see what output I get.

Have you tried to debug to see if supplying some RGB or HSV value to one of these functions spits out an unexpected result? There are a lot of online converters you can compare your results to.

Also, a quick comment on clarity:

Instead of rgb(1) = * and hsv(2) = * or whatever, I would recommend creating some local variables called r,g,b or h,s,v and using those. It’s much clearer to look at:

r = 10
g = 10
b = 10

than

rgb(1) = 10
rgb(2) = 10
rgb(3) = 10

Let me know what you find out. I love a challenge! :slight_smile:


#10

Ok, pretty sure RGBtoHSV is wrong.

I ported your code and the code from the RIT website you linked over to JavaScript (very simple to do). Except for the Saturation 255 thing (which I removed), the results matched.

Then I took some existing JS function from StackOverflow and also picked a couple RGBtoHSV websites and did the exact same conversion. In all cases these results match to each other, but NOT the previous results.

So basically, your code and the source code you based your work off of match, but they don’t match any other implementation I can find.

I would start here. I didn’t check the reverse function. Also, you might just be able to copy/paste these: c# - Algorithm to Switch Between RGB and HSB Color Values - Stack Overflow


#11

Thanks =D

I actually just ran the program with a couple debug lines in it and came to the same conclusion ^^

I’ll have a look at that website, and make a function based off of it instead and see if that works =]


#12

:confetti_ball: :balloon: VICTORY!!! :balloon: :confetti_ball:

Thank You So Much for your help @jonzoid, adding objects to my mod will be much much faster now :smile:
I should have this program fully functional within the next few days.

As a reward, I would like to offer to specially make a stonehearth item for you to put into the game =D
Any sort of item (decoration, furniture, plant, whatever) just name it and I’ll do my best to add it into the game ^^


#13

Awesome! Victory is it’s own reward. :smile:

However, since you’re offering and in keeping with the theme of your mod, I’ve always really liked this style of banner.

Instead of the castle icon, how about one of these shield icons?

Great mod and glad I could help.


#14

I can definitely do that =D
Which shield icon would you like?

Edit: and what colors would you like it in?


#15

I think the moon would be neat, but if the curves are too troublesome then here’s a second choice.

In black / dark blue
or
In magenta / indigo


#16

I’ll get to work on its as soon as I fine-tune the recolorer.
I’ll send you a PM when I get closer to finishing the banner.


#17

excellent collaboration @jonzoid and @chimeforest … well done! :clap:

as its one of the only “things” i can offer, i’m thinking of some fun custom titles as token of my appreciation…

for @jonzoid, something along the lines of “Code Sleuth”… and for @chimeforest, I thought perhaps “In Living Color!”

thoughts? :smile:

p.s. cant wait to see the new banner!


#18

Sweet, a custom title! :smile:
I’ll have to think over what I’d want mine to be, definitely color related :wink:


In other news, who wants to beta test the program? I just want to see if it will run on other peoples computers, I’ll include a .zip will all the QBs and JSONs and stuff, all you’ll need to do is open it, click start, and tell me what it outputs :smile:


#19

I accept! :slight_smile:

I’ll be happy to give it a shot and let you know how it works.


#20

Thanks =D I’ll send you the link via PM

There are a couple bugs with the current version, but I should get them fixed sometime today.

  1. Recipes can only be made from a recipe.json
  2. For some reason, it is remembering the sat/val changes from the previous QB recoloration (but not PNG)
  3. The How-To section is incomplete and ugly >.<