ZBrushCentral

Brush WrapMode button toggle

Hello Zbrushers,

I am pretty new to Zscripting and I am trying to learn as I go, creating some small utilities for my ZBrush interface. :smiley:

At the moment I am trying to create a custom button to toggle the WrapMode between 0 and 1 for each brush without having to use the slider (that I find really annoying).

Using the ISwitch command I managed to create a simple script that add the Brush WrapMode subpallet in the Zplugin menu that contain a switch button named WrapMode: when enabled sets the WrapMode of the selected brush to 1, when disabled reset the WrapMode of the selected brush to 0.

That’s the code:

[ISubPalette,“Zplugin:Brush WrapMode”]

[ISwitch, “Zplugin:Brush WrapMode:WrapMode”,0, “Toggle the brush WrapMode between 0 and 1”,

[ISet,Brush:Curve:WrapMode,1] , [ISet,Brush:Curve:WrapMode,0] ]

At the moment unfortunately the button switch doesn’t work as I would like.
The button status (ON/OFF) doesn’t update when I change brush.
Lets say that I am using the Standard brush and I enable the WrapMode using my script (the button turns ON), then I change brush, but the button remains ON (instead should turn OFF because that other brush has WrapMode set to = at the moment).
The problem is that I cannot figure out a way to update the button switch status according to each brush I select.
It should be matter, each time I select a new brush, to read the WrapMode value of each brush and then update the WrapMode status button accordingly.

After checking the Pixologic documentation about the ISwitch command I tried many different scripts but I cannot figure out a solution that solves the bug described above.

Anybody can help me please? :wink:

Attachments

WrapMode_Plugin.jpg

WrapMode_Plugin_ON.jpg

I’m afraid you’ve hit one of the big drawbacks with zscript. It’s not possible to monitor what ZBrush is doing and therefore keep your plugin button in the correct state. There’s currently no way round this.

The only solution would be to have an ‘update’ button which when pressed would get the current state of the slider and update your switch accordingly.

Hey marcus many thanks for the explanation: at least now I know that is something that cannot be done. :smiley:

Yesterday I “wasted” quite a lot of time trying to figure out a solution: well at least I practiced more with Zscripting. :confused:

So I think that the “intermidiate” solution I found is the best one: I created a simple button (not a switch) and I placed it in the interface near the WrapMode slider, so to be able to tell if each brush has the WrapMode to 0 or 1. :slight_smile:

WrapMode_0.jpg WrapMode_1.jpg

well marcus, many thanks again for the help! :wink:

As Marcus said there is no way to keep a ZScript generated interface item in sync with a ZBrush interface item, at least not without caveats. The [Sleep,…] command can monitor when an interface item has been pressed, but as there can only be one active ZScript at any given time, your sleep command would become inactive when the user pressed on another ZScript.

But if you are interested in how the [Sleep,…] command would look in code, perhaps for an “in the zone” modeling ZScript, then please take a look.

[HR][/HR]
// An IConfig with the ZBrush version you developed on ensures
// that your ZScript will still work if the WrapMode slider,
// for example, relocates in the next version of ZBrush.
[IConfig, 4.73]

[ISubPalette, “Zplugin:Brush WrapMode”]

[ISwitch, “Zplugin:Brush WrapMode:WrapMode”, [IGet, “Brush:Curve:WrapMode”], “Toggle the brush WrapMode between 0 and 1”,[ISet, “Brush:Curve:WrapMode”, 1]
,
[ISet, “Brush:Curve:WrapMode”, 0]
]

[VarSet, previousBrush, [IGet, 30516]]

// A sleep event of 1024 wakes the ZScript on each click of
// an interface item. We then check if the brush number has
// changed.
[Sleep, ,[VarSet, currentBrush, [IGet, 30516]] // 30516 is the Brush slider.
[If, previousBrush != currentBrush,

[VarSet, previousBrush, currentBrush]

[If, [IGet, “Brush:Curve:WrapMode”],

[ISet, “Zplugin:Brush WrapMode:WrapMode”, 1]

,

[ISet, “Zplugin:Brush WrapMode:WrapMode”, 0]

]

]
[If, uiID == 1102, // The WrapMode slider.

[ISet, “Zplugin:Brush WrapMode:WrapMode”, [IGet, 1102]]

]
[SleepAgain]
, 1024, awokeEvent, uiID]

Marcus many thanks for the explanation. at least now I know that I can’t do it.

At the end I had to surrender to use a button, and to keep it in the interface on the side of the WrapMode slider: it’s not as fancy as a toggle, but it works. :slight_smile:

[ISubPalette,“Zplugin:Brush WrapMode”]
[IButton, “Zplugin:Brush WrapMode:WrapMode”,“Toggle brush WrapMode between 0 and 1”,
[If,[IGet,Brush:Curve:WrapMode]=0,
[ISet,Brush:Curve:WrapMode,1]
,
[ISet,Brush:Curve:WrapMode,0]
]
]

WrapMode_0.jpg WrapMode_1.jpg

Hey Mark many thanks for the explanation of the [Sleep] command. :wink:

Actually another user (on the Polycount forum) suggested me to use a similar solution to the mouse behavior, but I had no clue about how to do it: so your detailed explanation will definitely help me!
I will mess with it a little more to better understand what I can do with it.

One question though: I was looking at the Command Reference documentation for the [Sleep] command and is not clear to me how the “Sleep amount in seconds” is expressed.
In the documentation has been used 100 , while in your example you use 1024. What these 2 measures means in seconds?
Sorry for the dumb question but I am unsure about that. :smiley:

Sleep [Sleep , Sleep amount in seconds, Commands group to execute when awaken,Optional event (default:1) (1:Timer 2:Mouse Moved 4:LButton down 8:LButton up 16:KeyDown 32:keyUp 64:ModifierKeyDown 128:ModifierKeyUp 256:Startup 512:Shut down 1024:InterfaceItem pressed/unpressed 2048:tool selected 4096:texture selected 8192:alpha selected), Optional output variable which will contain the event code that has awaken the ZScript, Optional output variable which will contain the ID of the window pointed by the mouse]
Exists ZScript and be awaken by specified event (can be placed anywhere).
Example:[Sleep, 100, [Note, “LButton pressed”], 4]Sleeps until awakened when left mouse button clicked.

Now that I think about I have an additional question: what if I want to affect the WrapMode of all the brushes at once (for one ZBrush session only)?
What I have in mind is like a script to toggle on and off to set the WrapMode of all the brushes at once for that particular session .
I am unsure how I can affect all the brushes at once: any hint on how to do that? :slight_smile:

Many thanks in advance. :wink:

I believe the sleep amount in seconds is only required if one of your awaken events is a timer. I say events because you can have multiple by combining the event codes using the bitwise inclusive OR symbol, which is the pipe character |

In the following the sleep command is awoken when the mouse moved (event 2), when a modifier key is released (event 128) and when a texture is selected (event 4096). The sleep command awakes as soon as one of the events occur.

[Sleep, ,[If, awokeEvent == 4096,

[NoteBar, “Texture was selected.”]

]
[If, awokeEvent == 128,

[NoteBar, “Modifier key released.”]

]
[If, awokeEvent == 2,

[NoteBar, “The mouse moved.”]

]
[SleepAgain]
// You could also use an event code of 4226, which is the three event codes added together.
, 2 | 128 | 4096, awokeEvent, uiID]

Incidentally I cannot get the timer event to work; it used to.

To set the WrapMode of every brush you will need to loop through them, which would be inefficient and fill the brush palette with every brush available. The Brush:R (Restore Configuration) button will remove all but a few brushes from the brush palette, but I would still not recommend looping through each brush.

Hope that was of some help.

Many thanks for the clarification about the “Sleep amount”, now it make more sense (especially since you pointed out that more than one event can be attached to the [Sleep] command). At least now I have a better idea about what I can use it for: the rest would be a trial and error process, especially if (like me) you working knowledge of Zscripting is limited. :slight_smile:

You next example of the [Sleep] command then clarified it even more: don’t worry too much if you don’t get it to work right now (I am sure it use to work as you said). For the moment is interesting to understand what it can be used for, then working on it I am sure that I will find a way to get it to work. :wink:

Thanks as well for the tips about the Loop and the Brush:R commands.
The Loop, as you described, doesn’t look like something efficient at all: I still think would be better to do it manually brush by brush using my simple button.
A the moment I think I will focus to get to work the Sleep Command Example to execute on the mouse click using the [Sleep] command. :slight_smile:

I was wondering if there’s any way I can specify the name of the Brushes I want to affect and apply the change only to those?

You have been really helpful: you gave me several different ideas about where to start, pointing me in the right direction. Now it’s matter to get the hands dirty and work on it.

I will post any relevant progress I will be (maybe) able to do. :wink:

I think I must have had ZBrush running too long while testing ZScripts (a week or two) because when I restarted ZBrush looping through all the brushes was not so bad. In addition, adding an [IFreeze,…] command that encapsulates all the commands inside the [IButton,…] can speed up ZScripts that affect the interface (the changing of the brushes).

I was wondering if there’s any way I can specify the name of the Brushes I want to affect and apply the change only to those?

You could hardcode the brush names in an array and loop through those. The following example will flip the wrap mode for the currently selected brush, whether or not it is part of the list of hardcoded brushes. Then it adjusts the wrap mode accordingly for the hardcoded brushes.

But to support any of the masking, selection or smoothing brushes, either hardcoded or simply looping through the brushes, you will need to add more code to account for the CTRL, CTRL + SHIFT and SHIFT keys that are required to change such brushes. For example, [IKeyPress,…] allows you to define a key(s) that is pressed while a group of commands is executed but you will need more than that to handle those types of brushes.

[HR][/HR]
[IConfig, 4.5]

[ISubPalette, “Zplugin:Brush WrapMode”]

[VarSet, brushCount, 5]
[VarDef, brushes(brushCount), “”]
[VarSet, brushes(0), “Brush:Clay”]
[VarSet, brushes(1), “Brush:ClayBuildup”]
[VarSet, brushes(2), “Brush:Standard”]
[VarSet, brushes(3), “Brush:Flatten”]
[VarSet, brushes(4), “Brush:Move Elastic”]

[IButton, “ZPlugin:brush WrapMode:Flip WrapModes”, “Flips the WrapMode between 0 an 1.”,

// Store the currently selected brush.
[VarSet, currentBrush, [IGet, 30516]] // 30516 is the Brush slider.
// Determine the new WrapMode
[If, [IGet, “Brush:Curve:WrapMode”], // WrapMode is 1 or higher.

[VarSet, newWrapMode, 0]

,

[VarSet, newWrapMode, 1]

]
// First flip the WrapMode for the currently selected brush.
[ISet, “Brush:Curve:WrapMode”, newWrapMode]
// Then flip your hardcoded brushes.
[Loop, brushCount,

[IPress, brushes(index)]

[ISet, “Brush:Curve:WrapMode”, newWrapMode]

, index]
// And switch back to the original brush.
[ISet, 30516, currentBrush]

, /DISABLED ?/, /BUTTON WIDTH/, , /BUTTON ICON/, /BUTTON HEIGHT/]

[HR][/HR]
If you would like to specify the brushes dynamically instead of hardcoding, you should probably look into memory blocks. [MVarDef,…] is the easiest way to create one but limits the storage value to floating points (4, 1.1, -0.003, -2322). But that is good enough for storing the numerical value of the Brush slider (UI ID 30516) which will give you the index of the currently selected brush.

Just remember that the more you add the more edge cases you need to take into account. With the above example in mind, what if the user had deleted one of the hardcoded brushes from their ZBrush installation? The ZScript would fail again and again for that user. Instead replace the loop that goes through the hardcoded brushes with the following loop:

[HR][/HR]

[Loop, brushCount,

// Checks if the interface path name or UI ID exists.

[If, [IExists, brushes(index)],

[IPress, brushes(index)]


[ISet, “Brush:Curve:WrapMode”, newWrapMode]


]

, index]

[HR][/HR]
Hope I was of some help and you enjoy your ZScripting journey.

Mark … what to say … you did all the hard work for me ! :smiley:

So the least I can say is … many many M A N Y thanks. :wink:

I think I must have had ZBrush running too long while testing ZScripts (a week or two) because when I restarted ZBrush looping through all the brushes was not so bad. In addition, adding an [IFreeze,…] command that encapsulates all the commands inside the [IButton,…] can speed up ZScripts that affect the interface (the changing of the brushes).

Damn, you have had Zbrush running for 1 or 2 weeks in a row? :confused:
Or you meant 1 or 2 weeks without resetting it? :smiley:

Btw interesting command the [IFreeze,…] , if I understood it correctly (reading the reference documentation) prevent the ZBrush interface to refresh for all the duration of the script (in this case the Brush WrapMode update). Pretty smart (and efficient).

You could hardcode the brush names in an array and loop through those. The following example will flip the wrap mode for the currently selected brush, whether or not it is part of the list of hardcoded brushes. Then it adjusts the wrap mode accordingly for the hardcoded brushes.

Your example is crystal clear. :wink:
If I got it correctly you declare the number of brushes to affect in the brushCount variable and then you assign a new variable to each brush brushes(0),brushes(1), etc ,am I right? There’s any limit to the amount of brushes I can hard code? (I guess there isn’t but just in case make sense to ask).

Btw in my case make sense to make a list of brushes to affect instead of updating the WrapMode of all the Brushes (that I guess is gonna take longer and with the most unpredictable effects).
When I am sculpting tilable textures I tent to use always the same bunch of brushes (I guess 5 or 6 … overall maybe 10): so make sense to change the WrapMode of those 10 brushes, and then change the WrapMode of the other brushes manually my button.

But to support any of the masking, selection or smoothing brushes, either hardcoded or simply looping through the brushes, you will need to add more code to account for the CTRL, CTRL + SHIFT and SHIFT keys that are required to change such brushes. For example, [IKeyPress,…] allows you to define a key(s) that is pressed while a group of commands is executed but you will need more than that to handle those types of brushes.

I am not sure to understand this part.
You meant that if I want to be able to use the CTRL and the SHIFT based brushes (like mask, cut, slice and trim) I should add them to the hard coded brushes list as well, am I right? :slight_smile:

If you would like to specify the brushes dynamically instead of hardcoding, you should probably look into memory blocks. [MVarDef,…] is the easiest way to create one but limits the storage value to floating points (4, 1.1, -0.003, -2322). But that is good enough for storing the numerical value of the Brush slider (UI ID 30516) which will give you the index of the currently selected brush.

Ehehe I appreciate your effort trying to explain me this, but not being a programmer I am not sure if I get this. :smiley:
Dynamically means that would allow me to change all the brush library without hardcoding any brush as you did in your example above?
Btw I checked the the reference documentation about the [MVarDef] that says:

MVarDef [MVarDef, Mem block identifier, Mem block variables count, Initial fill? (omitted:noFill - faster to create)]
Defines a new variables memory block. Output: Returns the variables count of the new memory block or error code…0=Error -1=Memory already exists -2=Can’t create memory block.
Example:[MVarDef, myTempData, 1000, 0]Creates a new data block named myTempData of 1000 variables in size, clear it to 0 and return the variables count. Returns 0 if data block could not be created.

But still make hardly sense to me ! But don’t worry, I don’t think I want to go dynamic on this: the hardcoded solution you explained above seems to work fine for my need.
But many thanks for taking the time and the effort to explain the whole thing: probably with the practice it will start to make sense in a bit or so. :smiley:

Just remember that the more you add the more edge cases you need to take into account. With the above example in mind, what if the user had deleted one of the hardcoded brushes from their ZBrush installation? The ZScript would fail again and again for that user.

Yep this makes sense: I will be carefull to hard code just the brushes that I have in my actual library: hopefully this should prevent the scenario of the missing brush.:wink:

Instead replace the loop that goes through the hardcoded brushes with the following loop:

[Loop, brushCount,
// Checks if the interface path name or UI ID exists.
[If, [IExists, brushes(index)],
[IPress, brushes(index)]
[ISet, “Brush:Curve:WrapMode”, newWrapMode]
]
, index]

So basically to prevent an error in case a brush is missing I should replace the script above to the one below (takes from the script example.
Am I right ? :o

// Then flip your hardcoded brushes.
[Loop, brushCount,
[IPress, brushes(index)]
[ISet, “Brush:Curve:WrapMode”, newWrapMode]
, index]

Hope I was of some help and you enjoy your ZScripting journey.

Mark you have been extremely kind and helpful: many thanks again for taking the time to explain me all those interesting things. I learn many more things from your replies that from the official documentation. :wink:

Ok, I tested your script hardcoding all the brushes that I think I might need (probably are even too many, but who cares, I can always go back later on and remove some brushes): it works pretty well, both setting the WrapMode to 1 and re-setting it back to 0 (pressing it a second time). :slight_smile:

The only problem is that doesn’t seem to work with the Smooth and Mask brushes (highlited in the code below in green): do you have any idea about the reason why?

Other than that the whole script works great ! Many thanks again for the great work. :slight_smile:

That’s the code (in the script I am using at the moment I have removed the Smooth and the Mask brushes because the script doesn’t affect them):

[IConfig, 4.73]

[ISubPalette, “Zplugin:Brush WrapMode”]

[VarSet, brushCount, 36]
[VarDef, brushes(brushCount), “”]
[VarSet, brushes(0), “Brush:Morph”]
[VarSet, brushes(1), “Brush:Standard”]
[VarSet, brushes(2), “Brush: Dam_Standard”]
[VarSet, brushes(3), “Brush:hPolish”]
[VarSet, brushes(4), “Brush:Flatten”]
[VarSet, brushes(5), “Brush:Planar”]
[VarSet, brushes(6), “Brush:TrimDynamic”]
[VarSet, brushes(7), “Brush:TrimAdaptive”]
[VarSet, brushes(8), “Brush:TrimSmoothBorder”]
[VarSet, brushes(9), “Brush:MalletFast”]
[VarSet, brushes(10), “Brush:MalletFast2”]
[VarSet, brushes(11), “Brush:Move”]
[VarSet, brushes(12), “Brush:Move Elastic”]
[VarSet, brushes(13), “Brush:Alpha”]
[VarSet, brushes(14), “Brush:Clay”]
[VarSet, brushes(15), “Brush:ClayBuildup”]
[VarSet, brushes(16), “Brush:ClayTubes”]
[VarSet, brushes(17), “Brush:Clay”]
[VarSet, brushes(18), “Brush:ClayBuildup”]
[VarSet, brushes(19), “Brush:ClayPolish”]
[VarSet, brushes(20), “Brush:ajClay”]
[VarSet, brushes(21), “Brush:ajPolish”]
[VarSet, brushes(22), “Brush:ajNoise”]
[VarSet, brushes(23), “Brush:Orb.Cracks”]
[VarSet, brushes(24), “Brush:ajCracks”]
[VarSet, brushes(25), “Brush:ajPinch”]
[VarSet, brushes(26), “Brush:Pinch”]
[VarSet, brushes(27), “Brush:Inflat”]
[VarSet, brushes(28), “Brush:Magnify”]
[VarSet, brushes(29), “Brush:Smooth”]
[VarSet, brushes(30), “Brush:SmoothValleys”]
[VarSet, brushes(31), “Brush:SmoothPeaks”]
[VarSet, brushes(32), “Brush:CurveTubeSnap”]
[VarSet, brushes(33), “Brush:CurveLineTube”]
[VarSet, brushes(34), “Brush:MaskPen”]
[VarSet, brushes(35), “Brush:LazyMask”]

[IButton, “ZPlugin:brush WrapMode:WrapMode Main Brushes”, “Toggle WrapMode of the Main Brushes between 0 an 1.”,

// Store the currently selected brush.
[VarSet, currentBrush, [IGet, 30516]] // 30516 is the Brush slider.
// Determine the new WrapMode
[If, [IGet, “Brush:Curve:WrapMode”], // WrapMode is 1 or higher.
[VarSet, newWrapMode, 0]

,

[VarSet, newWrapMode, 1]

]
// First flip the WrapMode for the currently selected brush.
[ISet, “Brush:Curve:WrapMode”, newWrapMode]
// Then flip your hardcoded brushes.
[Loop, brushCount,
[IPress, brushes(index)]

[ISet, “Brush:Curve:WrapMode”, newWrapMode]

, index]
// And switch back to the original brush.
[ISet, 30516, currentBrush]

, /DISABLED ?/, /BUTTON WIDTH/, , /BUTTON ICON/, /BUTTON HEIGHT/]
/End of ZScript/

You are more than welcome Andrea. When the person asking a question articulates it as clearly as you do it makes understanding and solving the problem much more enjoyable. Thank you for the kind words.

Damn, you have had Zbrush running for 1 or 2 weeks in a row? :confused:

What! You don’t have ZBrush running all the time? How do you know if your ZSpheres move around while you sleep? You don’t know, do you? Come on, you gotta protect yourself!

Yeah, I meant 1-2 weeks without restarting ZBrush :slight_smile:

Btw interesting command the [IFreeze,…] , if I understood it correctly (reading the reference documentation) prevent the ZBrush interface to refresh for all the duration of the script (in this case the Brush WrapMode update)

An [ISet, “Draw: Draw Size”, 70] command will cause an interface update, as will an [IPress, “Tool:Make PolyMesh3D”]. Putting both of those commands inside an [IFreeze,…] command will delay the interface update until the end of the [IFreeze,…] command. Not so useful with only two interface updating commands … but with 150 there is a measurable performance boost.

If I got it correctly you declare the number of brushes to affect in the brushCount variable and then you assign a new variable to each brush brushes(0),brushes(1), etc ,am I right? There’s any limit to the amount of brushes I can hard code? (I guess there isn’t but just in case make sense to ask).

Yes, and it is always very important that the two counts match. That is to say if you have 20 brushes() then your brushCount must also be 20 and vice versa. But remember that variable arrays, like brushes(), start at 0. Don’t worry about the limit, you will never be able to load that many brushes into ZBrush and exceed it. Or put another way: I have no idea what the limit is :wink:

Btw in my case make sense to make a list of brushes to affect instead of updating the WrapMode of all the Brushes

I think this is the best solution for you right now.

You meant that if I want to be able to use the CTRL and the SHIFT based brushes (like mask, cut, slice and trim) I should add them to the hard coded brushes list as well, am I right? :slight_smile:

Sorry, no :slight_smile: I meant do not add them to the hardcoded list as that will not work and will require a great deal more code. You would need two lists, one for the path to the brush and another to describe which type of brush it is (masking, smoothing, selection). At that point you might be able to use the [IKeyPress,…] command to change those types of brushes. I have not tried it yet but have a feeling it might work (I am always optimistic, except when England plays football).

Ehehe I appreciate your effort trying to explain me this, but not being a programmer I am not sure if I get this. :smiley:
Dynamically means that would allow me to change all the brush library without hardcoding any brush as you did in your example above?

Exactly !! See, you are a programmer after all! Sorry, I sometimes get excited and suggest something only a programmer (like you!) would know. Dynamic, in this case, would mean there was no hardcoded list and that you could add each brush yourself through the ZBrush interface.

So basically to prevent an error in case a brush is missing I should replace the script above to the one below

Yes. In programming 0 means false/no and 1 means true/yes. So when [IExists,…] returns 1 it means the brush exists. The [If,…] command receives the true or false from the [IExists,…] command and runs the true or false code.

Hope I answered your questions. Buona notte.

As I mentioned, the smooth, mask and selection brushes are special in that they are not immediately editable through ZScript. They require a simulation of the SHIFT, CTRL or CTRL + SHIFT keys, respectively.

Luckily the [IKeyPress,…] command might work, but I have not had time to experiment. I will have a look at it during the weekend.

But your ZScript is looking fine. You are however missing the [IFreeze,…] command.

What! You don’t have ZBrush running all the time? How do you know if your ZSpheres move around while you sleep? You don’t know, do you? Come on, you gotta protect yourself!

Yeah, I meant 1-2 weeks without restarting ZBrush

Ahahah I was sure that I should have kept my ZBrush running 24/7 to get better ! :confused:
Shame on me. :laughing:

An [ISet, “Draw: Draw Size”, 70] command will cause an interface update, as will an [IPress, “Tool:Make PolyMesh3D”]. Putting both of those commands inside an [IFreeze,…] command will delay the interface update until the end of the [IFreeze,…] command. Not so useful with only two interface updating commands … but with 150 there is a measurable performance boost.

But your ZScript is looking fine. You are however missing the [IFreeze,…] command.

Ok now it’s (crystal) clear how the [IFreeze] command should be use: I prefer to leave it out of the script because I was unsure how and where to use it. :slight_smile:

Yes, and it is always very important that the two counts match. That is to say if you have 20 brushes() then yourbrushCount must also be 20 and vice versa. But remember that variable arrays, like brushes(), start at 0. Don’t worry about the limit, you will never be able to load that many brushes into ZBrush and exceed it. Or put another way: I have no idea what the limit is :wink:

This one was more straight forward and I took the risk to test it out straight away: your code was pretty clear already on that matter (you declared 5 brushes, and you got 5 entries counting from 0 to 4) and I asked just to be 100% sure.
As you explained I noticed that if you declare an incorrect number of brushes (compared to the # of brushes in the list) ZBrush generate an error when you load the script, but it’s kind of easy to fix this kind of mistakes. :smiley:

Sorry, no :slight_smile: I meant do not add them to the hardcoded list as that will not work and will require a great deal more code. You would need two lists, one for the path to the brush and another to describe which type of brush it is (masking, smoothing, selection). At that point you might be able to use the [IKeyPress,…] command to change those types of brushes.

I have not tried it yet but have a feeling it might work (I am always optimistic, except when England plays football).

No worries I will give it a shot as well to see if I can understand how it works: however at the moment neither my simple button script is able to affect the SHIFT and the CTRL Brushes.
For example, if I enable the Smooth Brush (pressing SHIFT) and I run my simple WrapMode Button (the one that toggle a simple brush between 0 and 1) the WrapMode value doesn’t get any change. The only way to affect it is to use the slider. I am not really sure of the reason but that’s what happens. :o
Btw is not a big deal: we are just talking about a bunch of Brushes (probably 4 or 5), doesn’t take much to manually change the WrapMode value for those brushes. :smiley:

Ahahah I understand your pain about your national football team: to avoid that pain I stop watching the Italian national football team a long ago (even because I am not quite fond about football). :smiley:

Exactly !! See, you are a programmer after all! Sorry, I sometimes get excited and suggest something only a programmer (like you!) would know. Dynamic, in this case, would mean there was no hardcoded list and that you could add each brush yourself through the ZBrush interface.

Well thanks for the nice words: I try my best, even if my “programming” skills are ultra basic.
I just learned the basics of Lua ages ago when I had the opportunity to scrip some game levels for one of the first companies I worked for. But since then I haven’t studied or done nothing meaningful programming-wise (just some Excel nested formulas). :confused:
However I understand how exciting it could be when you have an idea in mind (for like a script or a plugin) and you can make it work. The problem is that for you it take 30 minutes (tops). For me probably takes between 2 and 5 hours. :laughing:

Yes. In programming 0 means false/no and 1 means true/yes. So when [IExists,…] returns 1 it means the brush exists. The [If,…] command receives the true or false from the [IExists,…] command and runs the true or false code.

Make perfect sense.

Once again many thanks for the detailed explanations. :+1:

Good night and I’ll speak you later. :wink:

, I added the [IFreeze,…] command to the script and seem to work well.
The update of the brushes instantly happens without updating the interface (definitely faster the before, where was obvious that was setting brush after brush) .
The big downside is that now is not clear if Zbrush did something or not (or at least is not that apparent). :lol:
Luckily I have the WrapMode slider near the brush pallets so it’s easy to see if the WrapMode of the selected brush has been changed or not.


[IConfig, 4.73]

[ISubPalette, “Zplugin:Brush WrapMode”]

[VarSet, brushCount, 31]
[VarDef, brushes(brushCount), “”]
[VarSet, brushes(0), “Brush:Morph”]
[VarSet, brushes(1), “Brush:Standard”]
[VarSet, brushes(2), “Brush: Dam_Standard”]
[VarSet, brushes(3), “Brush:hPolish”]
[VarSet, brushes(4), “Brush:Flatten”]
[VarSet, brushes(5), “Brush:Planar”]
[VarSet, brushes(6), “Brush:TrimDynamic”]
[VarSet, brushes(7), “Brush:TrimAdaptive”]
[VarSet, brushes(8), “Brush:TrimSmoothBorder”]
[VarSet, brushes(9), “Brush:MalletFast”]
[VarSet, brushes(10), “Brush:MalletFast2”]
[VarSet, brushes(11), “Brush:Move”]
[VarSet, brushes(12), “Brush:Move Elastic”]
[VarSet, brushes(13), “Brush:Alpha”]
[VarSet, brushes(14), “Brush:Clay”]
[VarSet, brushes(15), “Brush:ClayBuildup”]
[VarSet, brushes(16), “Brush:ClayTubes”]
[VarSet, brushes(17), “Brush:Clay”]
[VarSet, brushes(18), “Brush:ClayBuildup”]
[VarSet, brushes(19), “Brush:ClayPolish”]
[VarSet, brushes(20), “Brush:ajClay”]
[VarSet, brushes(21), “Brush:ajPolish”]
[VarSet, brushes(22), “Brush:ajNoise”]
[VarSet, brushes(23), “Brush:Orb.Cracks”]
[VarSet, brushes(24), “Brush:ajCracks”]
[VarSet, brushes(25), “Brush:ajPinch”]
[VarSet, brushes(26), “Brush:Pinch”]
[VarSet, brushes(27), “Brush:Inflat”]
[VarSet, brushes(28), “Brush:Magnify”]
[VarSet, brushes(29), “Brush:CurveTubeSnap”]
[VarSet, brushes(30), “Brush:CurveLineTube”]

[IButton, “ZPlugin:brush WrapMode:WrapMode Main Brushes”, “Toggle WrapMode of the Main Brushes between 0 an 1.”,

[IFreeze,

// Store the currently selected brush.
[VarSet, currentBrush, [IGet, 30516]] // 30516 is the Brush slider.
// Determine the new WrapMode
[If, [IGet, “Brush:Curve:WrapMode”], // WrapMode is 1 or higher.
[VarSet, newWrapMode, 0]
,

[VarSet, newWrapMode, 1]

]
// First flip the WrapMode for the currently selected brush.
[ISet, “Brush:Curve:WrapMode”, newWrapMode]
// Then flip your hardcoded brushes.
[Loop, brushCount,
[IPress, brushes(index)]

[ISet, “Brush:Curve:WrapMode”, newWrapMode]

, index]

// And switch back to the original brush.
[ISet, 30516, currentBrush]

]

, /DISABLED ?/, /BUTTON WIDTH/, , /BUTTON ICON/, /BUTTON HEIGHT/]


Tomorrow I will give a shot to the [IKeyPress] command to see if I can get it work: maybe I will try a simpler script only with SHIFT or CTRL brushes to make it easier. :o

IKeyPress [IKeyPress, The key to press (with an optional CTRL/CMD, ALT/OPT, SHIFT or TAB combination.) , Commands group to execute while the key is pressed ,Optional H cursor position prior to key press , Optional V cursor position prior to key press]
Simulates a key press
Example:[IKeyPress, ‘x’]Simulates “x” key press
[IKeyPress, CTRL+‘z’]Simulates “Ctrl+z” key press

Oh btw I have another question: which text editor do you use to code ZScripting and get the color coding that you post here? (that definitely easy to read that compared to a white slate of text).
I use Notepad ++ but it doesn’t recognize Zscripting as language and so is not able to format it: I saw that you can add formatting rules for a new language, but I have no idea how to set those rules. :frowning:

Cheers :wink: I believe that 25 brushes was the most recommended.
There was a recent post regarding the formatting you mentioned.
I use the Crimson Editor here for the scripts I do(and Notepad)

Cheers :wink: I believe that 25 brushes was the most recommended.
There was a recent post regarding the formatting you mentioned.
I use the Crimson Editor here for the scripts I do(and Notepad)

Hey Doug, many thanks for the hints ! :wink:

Regarding the number of brushes I am not far away from the recommended # (30 vs 25) and so far the script is running smoothly (both with and without the [IFreeze] command.
However thanks for the information ! At least now I am aware that a recommended # has been given. :slight_smile:

Regarding the text editor, I think I found the thread about the formatting post you were talking about :slight_smile: :
ZScript syntax highlighter for Sublime Text - beta
Many thanks pointing me to that that: I downloaded Sublime Text 3 (I love that by default has a dark background instead of a white one) and the syntax text highlighter for ZScripting, and they seem to work pretty well- :wink:

:slight_smile: Actually it was this thread with a link to a page.
http://www.zbrushcentral.com/showthread.php?195838-ZBrushCentral-Syntax-Highlighting

:slight_smile: Actually it was this thread with a link to a page.
http://www.zbrushcentral.com/showthr…x-Highlighting

Oh ok, I missed that one (for some reason).

many thanks ! :slight_smile:

Hi Andrea,

Sorry about the delay. I had a look at it last weekend but for some reason, the code I imagined would work simply did not.

But I think I found the culprit. Reading a brush name during an [IKeyPress,…] did not work for me. Adding a slight delay solved the problem.

So, the following code will flip the wrap mode according to the wrap mode of the currently selected brush. Any brushes that you hardcode will also need a variable to define which type of brush they are. The standard modelling, smoothing and masking brushes are supported but not the clip and selection brushes. I took those out as I tried to narrow down the problem, besides, they do not seem to be affected by the wrap mode setting.

You still cannot hold any modifier keys while pressing the plugin button or the plugin might fail. Not sure what to do about that as the previous modifier key detection solution does not seem to work anymore.

Edit: I just noticed copy / pasting the code does not preserve the indentation. So here is the file:

[IConfig, 4.5]

[ISubPalette, “Zplugin:Brush WrapMode”]

[VarSet, brushCount, 4]
// brushes() defines the pathname and brushType() defines what type of brush it is.
// 0: standard modeling brush.
// 1: smooth brush.
// 2: masking brush.
[VarDef, brushes(brushCount), “”] [VarDef, brushType(brushCount), 0]
[VarSet, brushes(0), “Brush:Clay”] [VarSet, brushType(0), 0]
[VarSet, brushes(1), “Brush:Standard”] [VarSet, brushType(1), 0]
[VarSet, brushes(2), “Brush:Smooth”] [VarSet, brushType(2), 1]
[VarSet, brushes(3), “Brush:MaskPen”] [VarSet, brushType(3), 2]

[IButton, “ZPlugin:Brush WrapMode:Flip WrapModes”, “Flip WrapModes.”,[IFreeze, // Stops interface updates while we switch brushes.

// Store the currently selected modeling brush.

[VarSet, currentBrush, [IGet, 30516]] // 30516 is the Brush slider.

// Determine the new WrapMode

[If, [IGet, “Brush:Curve:WrapMode”], // WrapMode is 1 or higher.

[VarSet, newWrapMode, 0]

,

[VarSet, newWrapMode, 1]

]

// Set the new WrapMode for the currently selected brush.

[ISet, “Brush:Curve:WrapMode”, newWrapMode]

// Store the currently selected smooth brush.

[IKeyPress, SHIFT,

[Delay, 0.05] // Apparently needed to read the brushName.

[VarSet, brushName, [IGetTitle, 30516]]

[VarSet, smoothPath, [StrMerge, “Brush:”, brushName]]

// Remove the . and space from the path.

[VarSet, smoothPath, [StrExtract, smoothPath, 0, [StrLength, smoothPath] - 2]]

[ISet, “Brush:Curve:WrapMode”, newWrapMode]

]

// Store the currenlty selected masking brush.

[IKeyPress, CTRL,

[Delay, 0.05] // Apparently needed to read the brushName.

[VarSet, brushName, [IGetTitle, 30516]]

[VarSet, maskPath, [StrMerge, “Brush:”, brushName]]

// Remove the . and space from the path.

[VarSet, maskPath, [StrExtract, maskPath, 0, [StrLength, maskPath] - 2]]

[ISet, “Brush:Curve:WrapMode”, newWrapMode]

]

// Then set WrapMode for the hardcoded brushes.

[Loop, brushCount,

// Checks if the interface path name or UI ID exists.

[If, [IExists, brushes(index)],

[If, brushType(index) == 0,


[IPress, brushes(index)]



[ISet, “Brush:Curve:WrapMode”, newWrapMode]



[LoopContinue] // No need to check for other brushType().



]


[If, brushType(index) == 1,


[IKeyPress, SHIFT,



[IPress, brushes(index)]




[ISet, “Brush:Curve:WrapMode”, newWrapMode]




]



[LoopContinue] // No need to check for other brushType().



]


[If, brushType(index) == 2,


[IKeyPress, CTRL,



[IPress, brushes(index)]




[ISet, “Brush:Curve:WrapMode”, newWrapMode]




]



]


]

, index]

// Restore the previously selected smooth, mask and modeling brushes.

[IKeyPress, SHIFT,

[IPress, smoothPath]

]

[IKeyPress, CTRL,

[IPress, maskPath]

]

[ISet, 30516, currentBrush]

] // End of IFreeze
, /DISABLED ?/, /BUTTON WIDTH/, , /BUTTON ICON/, /BUTTON HEIGHT/]

Hi < Ash >,

Sorry about the delay. I had a look at it last weekend but for some reason, the code I imagined would work simply did not.

Hey Mark, don’t worry, there was not rush at all, besides, the script that you previously helped me to develop works great: whenever I am scultping a tilable texture now I can easily tweak all the brushes I need in once click ! As to say: I was already pretty happy with the previous result. :wink:

So many thanks for looking into it furthermore: I admit that being able to have also a couple of smooth and masking brushes affected by the WrapMode script would be pretty awesome).

Your script looks great: I don’t think that the fact to be able to hold any modifier key while running the script would matter (does it?). In the end as long as it sets the WrapMode value for the hardcoded brushes is all right.

Pretty interesting the trick to define the “type of brush” !

I will give a shot to the script tomorrow to see how it works. :smiley:

That said, many thanks again for taking the time to solve this issue for me ! :slight_smile: