ZBrushCentral

Convert Hex value to R, G, B values

Hello! I’m storing swatch hex values that color a UI NoteIButton interface (eg 0xff0000) and I’m looking for a way to convert these back into R, G, B values I can use to to switch the active color ( via [IColorSet] ).

I can see in the command reference it’s possible to convert an R G B value into a combined RGB value using the [RGB, Red, Green, Blue] command. Is there another command that goes the other way?

If not, any idea how I would be able to do this using ZBrush’s command? I’m a little stumped. I have an idea of how I would work around it, but it’s not pretty haha.

image

Results don’t always have to be pretty :wink:

Haha, true words.

Ok, I actually figured it out after some fiddling and some stack overflow- because ZScript supports bit shifting I ended up with something like this:

[VarDef, r, ""]
[VarDef, g, ""]
[VarDef, b, ""]
[IButton,Play,"Convert HEX to RGB",
    // 0x824600 is the hex color for a shade of saddle brown...
    [VarSet, r, ((0x824600 >> 16) & 0xFF) ]
    [VarSet, g, ((0x824600 >> 8) & 0xFF) ]
    [VarSet, b, (0x824600 & 0xFF) ]

    [Note, r]
    [Note, g]
    [Note, b]
]/*End of ZScript*/

Based on the Stack Overflow answer linked here but modified to return a value from 0-255 rather than 0-1.

Yes, that the way to do it.

Note that if you use [IGet,Color:Main Color], ZBrush stores the color as combined RGB/65536, so you need to multiply by 65536 to get the full RGB value:

[VarSet, combinedRGB ,[IGet,Color:Main Color]*65536]
//bit-shift the value:
[VarSet,red,((combinedRGB & 0xFF0000) >> 16)]
[VarSet, green,((combinedRGB & 0x00FF00) >> 8)]
[VarSet, blue,(combinedRGB & 0x0000FF)]

[Note,[StrMerge,"R: ",red," G: ",green," B: ",blue]]

HTH,
Marcus

1 Like

Brilliant, thanks for the additional info Marcus! Much appreciated.

1 Like

hey Marcus, on the same topic, how do you pass a hexadecimal value using a StrAsk ?
[Val ] always return 0 when you pass a hexadecimal value as a string using [StrAsk].
also it seems there is no way to get the remainer / modulo on a dividing operation.

For Hex values in StrAsk, I think you will need to parse the string yourself to get the value. ZBrush will internally cast strings as floats but clearly no account is taken of hex values. (Hard coded hex values in zscript are presumably parsed when the text file is loaded, though I see that if you write them as strings - within quotes - then 0 is the result.)

For modulo, again, as far as I know, there is no zscript direct way, and you will have to calculate the remainder.

-Marcus

Thanks you Marcus, I figured out how to calculate the decimal value for the [StrAsk], so using bitwise ops now work with string .
Now, let 's try the reversed process =)

Well, I was looking at this and left bit-shifts simply don’t work after a while. Shifting by 4 or 8 are OK but shifting by 12 always gives the wrong value. I imagine this is something to do with ZBrush storing zscript values as floats.

There are also problems with larger numbers, so that, for example, if you try and add 1677720 to 251658240, ZBrush will give you 268435456. Again, probably due to using floats.

So the following example will parse HEX strings of up to 6 digits. (At least, I think it’s OK…)

[RoutineDef,ParseHEX,
	[VarDef,hexStr,""]	
	[If,[StrFind,"0x",hexStr]==0,
		[VarSet,hexStr,[StrExtract,hexStr,2,255]]
	]	
	[If,[StrLength,hexStr]>6,
		[Note,"\CffffffHEX string too long - 
			\n\Cff9234Please enter a shorter HEX \Cff9234string and try again"]
			[Exit]
	]
	[VarDef,charStr,""]
	[VarDef,char,0]
	[VarSet,hexStr,[StrUpper,hexStr]]		
	[VarSet,loopN,[StrLength,hexStr]]
	[VarSet,index,loopN-1]
	[VarSet,subVal,0]
	[Loop,loopN,
		[VarSet,charStr,[StrExtract,hexStr,index,index]]
		[VarSet,asc,[StrToAsc,charStr]]		
		[If,((asc>=48)&&(asc <=57)),// 0 - 9
			[VarSet,char,charStr]
		,//else
			[If,((asc>=65)&&(asc <=70)),// A - F
				[Loop,1,					
					[If,(asc == 65),[VarSet,char,10][LoopExit]]//A
					[If,(asc == 66),[VarSet,char,11][LoopExit]]//B
					[If,(asc == 67),[VarSet,char,12][LoopExit]]//C
					[If,(asc == 68),[VarSet,char,13][LoopExit]]//D
					[If,(asc == 69),[VarSet,char,14][LoopExit]]//E
					[If,(asc == 70),[VarSet,char,15][LoopExit]]//F
				]
			,//else not a HEX string
				[Note,"\Cff9234Please enter a \CffffffHEX \Cff9234string and try again"][Exit]
			]
		]		
		[VarSet,m,(16^^([Val,n]))]				
		[VarMul,char,[Val,m]]					
		[VarAdd,sum,[Val,char]]		
		[VarDec,index]	
	,n]			
,hexStr,sum]

[IButton,GetHexValue,"Get decimal value from HEX string",	
	[VarDef,hexValStr,""]
	[VarSet,hexValStr,[StrAsk,"0x000000","Please enter a HEX value"]]	
	[If,[StrLength,hexValStr],
		[VarSet,result,0]
		[RoutineCall,ParseHEX,hexValStr,result]
		[Note,[StrMerge,"\Cff9234HEX value in decimal is: \Cffffff",result]]
	]
]

Always ‘limitations’… sigh.

1 Like

Modulo is simpler to achieve, as I expect you know:

[RoutineDef,Modulo,
		[VarSet,m,(x/y)]
		[VarSet,f,FRAC(m)]		
		[If,f > 0,
			[VarSet,i,INT(m)*y]			
			[VarSet,m,(x-i)]
			,
			[VarSet,m,0]
		]
,x,y,m]

[IButton,GetModulo,"Get remainder of dividing x by y",
	[VarSet,result,0]
		[VarSet,x,5]
		[VarSet,y,2]
		[RoutineCall,Modulo,x,y,result]
		[Note,result]
]