ZBrushCentral

Quick Sketch Session - Various Questions

I am content just being pointed in the right direction if it’s what you can offer. Thanks!

Ok, so I have several scripting questions that would be much easier to solve by asking than by googling. To start, I will post the questions with as little need for context as possible along with a basic idea of what I’m coding, then I’ll post my code for anyone who might want to go the extra mile in helping me.

The Script Description (optional reading)
My script allows me to set up a timed practice sculpt which can be repeated as many times as I specify so that I might get through a dozen 5 minute sculpts or six ten minute sculpts, for example. In addition, it prompts for and quickly saves to a directory you’ve chosen before you’ve begun (an outbox for quick sketches). It allows you to include tags and it includes the time spent on each sculpt in the filename so that, if I want to go back, I can look through my filename tags (ratings, for example) and find sculpts I’m interested in continuing.

After accomplishing this basic helper, I intend to add a reference system so that, for each quick sculpt, a set of words or a picture is shown as inspiration. This will help me be more decisive about designing on the fly, rather than blanking and staring at the screen trying to figure out what to do. Ideally I would go so far as to make themed folders so that I might choose to do a set of anatomy themed cycles or a set of animal themed or alien themed or mechanical themed cycles. These would be organized in personal folders set up and maintained by the user. I don’t know if zbrush can handle it but eventually that might include putting ‘used’ files in a separate bin to keep things fresh.

The goal is to make this process impersonal, so that I don’t have to be the one to decide that time’s up (because I can’t!). I have trouble starting quick sculpts because I know I will take forever and I have trouble stopping them because I enjoy them so much once I begin. This way I can amass many smaller studies and improve myself in much more meaningful ways.
I describe each timed sculpt as a cycle and each set of cycles a session.

The Questions! (in order of importance to me right now)
*“The number of inputs exceeds the number of inputs defined by the target routine”: I seem to have made some fundamental mistake in my coding because I get this whenever I attempt to call any of my routines for a second time. If I exit the entire script, then hit a resume button, the script begin to function again without problem but if I get to the end of a cycle and try to jump back to the top and reset my variables, the routineCall fails. I don’t know if it’s a recursion problem from somehow being unable to call a function until it has ended entirely (A finishes and calls B. B finishes and attempts to call A. A is still waiting for B to finish before it can start over) or if I’m just doing something wrong with the code. Google thinks this is a really old problem that no one has had since the turn of the century so I don’t know where to go with this.

*Timers: Right now my script needs to have a timer to count down the minutes. Something that can use a variable that I can update, reset, and increment as I want. I’m using a delay to create that tick, so that it runs code, delays, runs code, delays, and repeats until the variable reaches zero. Unfortunately, delay seems to lock up all of zbrush so that I can’t anything while it’s running. I also see that, even running at a very visible rate it is having trouble smoothly updating three sliders which display the time (time left, time elapsed, and time total). I’d like to know a better way to do this and perhaps a more efficient way to go about it.

*Saving files: I’ve built my saving code randomly as I discovered what was available. I want it to be as minimal as possible so you don’t have to jump to the mouse, keyboard, and tablet any more than necessary. The user chooses the directory for saving files before they can start anything (the default otherwise is to save to the macro folder). Though the load file dialogue seems a better place to start since it isn’t expecting input for a filename, the save dialogue is the only one that can select a folder and give you back its path information.
After a cycle completes, the user is prompted to “name your creation”, and then again to include a tag (rating, description, theme, etc.) which precedes the file name. I’ve set it up to increment the filename in that location and to include elapsed time in a prefix. All of the strings are then put together, set as the FileNameSetNext, and the Save As button is clicked.
Aside from whether this is the appropriate way to do all this, I’m also wondering how I can get zbrush to properly display the directory with backslashes and special characters. I have a prompt tell the user where the file is saved and what it was saved as, to be clear to them what’s going on.

*Loading a random mesh: I want to include an option to randomly select a starter mesh to mix things up further. These would be things like male/female busts, body types, quick symmetry setups, base anatomical features, etc… They would be placed in a folder alongside the macro and updated by the user if they choose. I haven’t looked into how to sift through files and choose one at random yet but it would help.

*My strAsk prompts don’t appear until I move the mouse a lot of the time. It looks like it lags as a result. There isn’t anything in the function that says that should happen. How can I fix it, or do I have things running that shouldn’t be?

*Reference: I haven’t gotten to this but I know I’ll need to be more informed about saving and loading files to zbrush before I even try. Here’s a quick list of basic actions I want to know about.
*Displaying a picture within an interface cleanly, without prior resizing, and with minimal lag.
*Removing a picture without destroying the interface or hiding it away for the memory to chew on for awhile.
*Reading through a text file, parsing it at the commas, and displaying a list in a meaningful way (ie. clean and evenly spaced buttons?) for the user to refer to.
*Choosing a random file within a directory.

*Alternate interfaces: A floating window maybe. I found the progress bar toggle for the notebar but I don’t know how to display the actual progress on it (it’s always 100%). Right now I’m working from a macro, but I had put it in as a plugin or in the zscript windows. It doesn’t really matter as far as I know.

*Zscripting environment: I don’t have one. I’m terrible at setting them up so if you’ve got a good suggestion, I would be glad for the simple how-to-set-it-up link as well.

*Literally anything else I should know

Thanks in advance!

Here’s the script (if I uploaded it right). Place the sessions folder in your startup macro folder and reload. Right now it’s meant to be docked on one side of the screen or the other.

There are a few drawbacks with what you are trying to do. Anyway, I will answer as best I can:

  1. The ‘too many inputs’ is one of those catch-all error messages that doesn’t tell you exactly what is wrong. Sometimes it occurs because of a recursive call, sometimes the script just can’t find the routine, and sometimes there are actually too many inputs! In your case I couldn’t see why it was failing. (I did some refactoring before testing and didn’t get the error.) I tend to put my interface code after all the routines and other code and certainly it’s a long time since I’ve seen that message. I’m not sure of the wisdom of putting the buttons in the macro palette. I think I’d create a proper plugin in one of the other palettes - this is what I did to test your code.

I had a few problems, mostly to do with the fact that there was no ZVR data file. You need to make sure that it is created when it doesn’t exist otherwise there’s no way of getting started.

  1. Timers. As you found, using ‘delay’ prohibited working in ZBrush. The only way of doing what you ant is to use the ‘Sleep’ command. This is OK, except the ‘Timer’ option doesn’t work so you need to use something else to wake it up. I’ve attached an example which uses mouse movement. The code gets the ZBrush runtime using [ZBrushInfo,2] and then compares this to the session time in order to create a display.

The biggest drawback with zscript is that only one can be active at a time. If you use another plugin - such as adjusting your DrawSize using the [ or ] keys - then your script will exit. This puts a serious limitation on anything involving a timer. That’s why I have added a ‘Refresh’ button. So in my example the display will only update when:
a) the mouse is being moved
b) the plugin is the active zscript

  1. I don’t especially like using StrAsk unless I really have to. For file names I think I’d use FileNameAsk and then extract whatever I needed from that. This is personal preference though. If I wanted to reduce the load on the user then I would simply use the name of the tool in the Tool palette and combine that with whatever else.

[Notes] will not display back slashes (as well as some other characters). You would need to write a routine that replaced the back slashes with forward slashes in order to show them satisfactorily.

  1. If you want to select files from a folder then you will need to use the ZFileUtils dll to process the folder contents. You can read about that here: http://docs.pixologic.com/user-guide/customizing-zbrush/zscripting/zfileutils/

  2. StrAsk prompts not appearing: I’m not sure why this is happening for you but it may be to do with using the Macro palette for your plugin. The example I have attached shows how to create a proper plugin.

  3. For the rest I suggest you read up in the online docs: http://docs.pixologic.com/user-guide/customizing-zbrush/zscripting/
    ZScript is quite limited as far as interfaces are concerned, though NoteInterfaces can be made quite attractive with some ingenuity, or used to display images. For the NoteBar display see the attached script.

For a ZScripting environment, I don’t have any particular suggestions. There are some threads in this forum where people have posted some taglist files etc. for various editors. I’ll post the links when I can find them. I use UltraEdit but that is not free.

Sample zscript plugin:

HTH,

Thanks for the quick and detailed reply.

I’m working on turning it into a plugin and I’m going to try to reorganize it as I do so (manually rewriting a lot of it). I made a quick macro to reload it to make it easy to test and a set of buttons to delete any other interface item and load any script. I saw the reloading button somewhere in my searching and it helps a lot.

I’ll be sure to post my progress as I look through your suggestions and rewrite this.

Just some notes for myself:
*ILock works better than IDisable/Enable for preventing user fiddling. Interface items are enabled automatically when updated but are not unlocked.
*You can include an IF statement to check the NoteIGet right in the button’s commands so that you never have to worry about checking the right set of buttons again.

*Four step interface (each requires the last to be active):

  1. Setup a directory or detect one before anything can happen.
  2. Setup a session or use existing settings if they could work.
  3. Session in progress.
  4. Cycle in progress.

*I see where I missed the progress bar value. I thought it was a toggle rather than an actual value. That makes life easier.
*Breaking it down into more routines for smaller functions.
*Better control over the interface, better handling of whether the settings exist to run properly, etc.
*Separate session and cycle routines. Each has an active function, an ending function, and functions to extend them.

*Resume will just check to see if all the variables exist and are in a reasonable range before jumping back into the session the same as a new cycle would do. It should work anywhere within the process.

Yes, I meant to mention that a memblock is necessary because standard variables are reset if the zscript is reloaded. Also you may have noticed you can use fractional values for button widths: 1 is full palette width, 0.5 half palette width etc. This means your buttons will scale correctly if the button size is changed in Preferences.

Some script editor threads:

http://www.zbrushcentral.com/showthread.php?46930-Zscript-3-Syntax-files-for-TextPad-UltraEdit-and-Editpad-Pro

http://www.zbrushcentral.com/showthread.php?182680-Zscript-syntax-for-Notepad-PP

http://www.zbrushcentral.com/showthread.php?24137-For-those-still-looking-for-an-editor-JEdit-might-work

Thanks again for the reply.
I didn’t know that widths could be set that easily. I suspected something like that at first, because it seemed odd that everything else places so naturally within the interfaces. I will definitely take some time to look through the sleep command and memory blocks before I attempt to rewrite that section. Just preparing the interface for the most part right now.

Quick questions (for later. No hurry):
Is there a way to create blank interface sections (like the blank pieces in the custom UI)?

Is there a way to make floats with less digits?

What is the proper way to send inputs through and out of routines? The documentation lists about a dozen inputs but I just want to return a number.

http://docs.pixologic.com/user-guide/customizing-zbrush/zscripting/command-reference/
Just in case you haven’t found it.

I’ve been using that for just about everything as well as some of the other doc pages, thanks.

I can understand most of it and have managed to piece it into a fairly decent script so far but for most everything I always have to run several tests to get used to using a new function (and keep a reference sheet for placement of inputs for things like buttons). There are things I either haven’t found on there or simply didn’t understand when I saw them though.

Never hurts to include some comments as to what stuff does as well as variables used etc. :wink:
I’ve played some but not as extensively as you’re doing here.

  1. You can use a new hidden sub-palette and hidden button:
    [ISubPalette,“ZPlugin:Session:separator”,2]
    [IButton, "ZPlugin:Session:separator: ", “Separator”, 1, 1, , 2]

The ‘2’ in the SubPalette code makes sure it’s hidden. With the button, the ‘2’ specifies a height of 2 pixels which is ignored by ZBrush so the button doesn’t appear. If you don’t use the hidden button then you’ll get a wide gap. Buttons after the separator would have the same path as before otherwise they’d be put in the ‘separator’ sub-palette, so use “ZPlugin:Session:myButton” or whatever.

You can also use disabled switches or buttons but they will show to a greater or lesser extent (see the Multi Map Exporter plugin). Buttons can be useful though as you can control their size, and you can also use them as titles (as in the UV Master plugin).

  1. You mean in sliders? No, for some reason whatever you set the increment to, other than an integer, you’ll get a lot of digits.

  2. If you want to use local variables you could do it like this:

[RoutineDef,ReturnCubeOrSquare,
[If,mode == 1,
[VarMul, x, x]
]
[If,mode == 2,
[VarSet, i, x]
[VarMul, x, x]
[VarMul,x,i]
]
,x,mode]

[IButton,DoIt,“Do it”,
[VarSet,num,3]
[RoutineCall,ReturnCubeOrSquare,num,1]
[Note,num,3]
[RoutineCall,ReturnCubeOrSquare,num,2]
[Note,num,3]
]

Note: if you use [VarDef,num,3] above instead of [VarSet] ZBrush treats it as a global variable and the value is not reset with further clicks of the button.

I seem to be having an issue resetting for the next cycle automatically. I can do it manually by letting the entire script end and jumping back in using a button click (“resume”), but both of the two coded options I have are giving me difficulties. The button lets me run through all of the cycles one at a time until I get to the end of the routine.

For reference, the basic pseudo code for the relevant chunk goes like this:

[RunSession,
—Loop counting down Cycles
------RunCycle
—EndSession]

[RunCycle,
—Sleep until the cycle is complete or until paused.
------Pausing exits the script, temporarily saving variables in memory.
—EndCycle]

[EndCycle,
—Save or continue options.]

Now, in order to run the next cycle, I have a few options.

  1. Use a loop in the RunSession so that the routine is called as if there were a For loop.
    *My problem with this is that the loop doesn’t wait for the Sleep commands to finish before it goes back to the top. It will start the cycles immediately one right after the other.
    —*I tried creating a loop with a variable set on or off to indicate when the sleep timer is active. The only time the loop needs to progress is when the timer has been stopped, which happens either when time runs out or when resumed. The loop didn’t start back up again though. Not sure why yet.

  2. Call RunSession at the end of the EndCycle.
    *This gives me the issue I had before with overlapping recursion (runSession > runCycle > endCycle > runSession?). It refuses to run any code the second time around (though it doesn’t warn me until then).

Other problems:

*This one’s actually really annoying and related to the above issue, but I don’t know how to prevent a routine from running forward before it’s resolved something like a note. I have a lot of note prompts so I can summarize and guide myself through the program but they will remain open even as the timer runs. With my sleep timer, it begins immediately after the note which tells me about the current cycle. If the cycle is set too low, it will run below zero before I even close the note!

*strAsk’s default doesn’t allow you to just accept and continue. Is there a way to allow you to just hit the enter button and deal with the default value?

*My strAsk commands don’t update unless I move the mouse so if I type the number of cycles, I won’t see the prompt for cycle length until I grab the mouse again.

*Can you restrict user input to only accept number values?

*What I meant about using floats was whether I could cut them down to two decimal points or something reasonable. I think there’s a command for extracting the section after the decimal and you might be able to read off the first two digits from that and add them to an integer of the original but that seems like the long way around.

I actually wrote out a lot more questions here but if the question made enough sense to be worth asking then I usually figured it out shortly after. On the other hand I also wrote a lot of questions that were either unintelligible to me when I wrote them or made no sense to me now just before I post.

I uploaded the plugin as it is now. The “plugin development” folder is the macro which I use to reset the plugin (sometimes it will disappear completely if there’s an error in the code) and the Quick Sketch folder goes in the zstartup>zplugs folder. Unless I’m too tired to remember having changed it, it should mostly work except that the next cycles don’t trigger properly. Depending on what state I left it, you should be able to hit “resume” to manually start them. I currently have minutes equaling 1 second for testing.

If anything, maybe just load it up and see how far you can get. It’s a bit dense for me to look at without an entire afternoon.

I’ll take a look at this when I can but it’s unlikely to be for a few days.

Some people actually DO read read me files :wink: lol
Nicely documented code :+1:
Going to play with it and see what it does.

I added a slider up in the top of the interface so that I can change the length of a “minute”. It has the side effect of recalculating how many “minutes” have passed so that if I was half way done with a 10 minute cycle in which each “minute” lasted for 10 seconds, I would still only be 50 seconds into the cycle even if I paused and changed each minute to last 60 seconds (ie. it would jump back to “9 minutes left”).

There are two buttons that restart the plugin (sort of). Next Cycle sounds as if it should advance the plugin but it actually needs to pass through the End Cycle routine which, as I mentioned before, can’t seem to loop back to the top of the code properly and just dead-ends. The second button is actually Resume, which doesn’t expect to go through the saving dialogue or anything. If you try to run a cycle with zero seconds left, it will start the next cycle from the beginning without passing through the End Cycle routine, so you can use Resume to start the next cycle after running time out and selecting one of the options that comes up. Just a bit of a workaround.

The main issue I need resolved is how to loop back from End Cycle (save/continue/exit) all the way back up to the routine which initiates each cycle (reloading the gun).
*Trying to go straight from End Cycle to the top causes overlapping recursion or something.
*Since recursion is already occurring on some level, I should be able to get the code to return back up the line but I can’t.
*I tried using a loop that triggers back on whenever time is paused (which disables the lower routines) but heard nothing back from it.

Ok, to make life easier for me and to make it easier for you to look at the code, I made a simplified version of the loop I’m trying to work with. It’s just three basic routines:

  1. A director routine. The top of the routine stack.
    —2. A timer. A toggle allows it to exit the loop.
    ------3. A timer reset. It adjusts variables and, in my larger code, allows you to save.

It needs to jump back from 3 to 1 with updated variables. I’ve made a macro with this basic frame so that you guys might be able to look at it and tell me what’s wrong (or I might be able to fix it myself!). It has a button to reset and start it, sliders to quickly set up test values, and its results appear in the notebar. I tried to put as many notes in there as possible so I can use this for reference later.

The sleepDirector has two separate attempts included in it. I couldn’t figure out how to loop in the way I need to loop. LOOP itself fires thousands of times before the timer routine gets anywhere. SLEEP, which I then tried in place of LOOP, seems to override the child sleep and doesn’t do anything.

I can set this up to manually loop by removing certain resets in the command for the button. It will run all the way down just fine if that’s the case, hitting all the proper IF statements. I just can’t get it to loop right.

The attached file is a macro.

Well, I’ve had a look at this. I couldn’t get it to work in the way you want - with routines - in that I always encountered the recursion problem. I think this a case of it just won’t work rather than there being a correct way to do it that we don’t know about. I’m afraid that zscript will throw up some odd things now and again and you just have to work around them.

I did find a solution though. In the code below I use a hidden button to hold the Sleep command. This behaves essentially the same way as a routine, with the rest of your code unchanged except for adding a [SleepAgain] after the [RoutineCall,wakeup] in the hidden button. This just makes sure the Sleep gets started again for the next in the cycle. You could use a Switch instead of a Button, with Sleep in the ‘on’ section, if you wanted to have a display in the palette that the cycle was running.

I don’t think you can have more than one Sleep active in a script but I’ve not experimented much with the command. As you’ve found, Loops will run until completion and effectively stop any sculpting, so not very useful for a script of this sort.

HTH,