This is a thread to discuss and show various zscript code implementations that will assist the users general workflow and/or zscript inter-compatibility.
None of the following 5 suggestions will restrict the functionality of existing zscripts, or future zscripts for that matter. So take a look and consider implementing these functionalities in your zscripts.
If you have suggestions of your own then, if possible, please submit them in a similar format, i.e What, Why, When, Description and Code.
Whenever I mention Zscripts I am referring to Zscripts as well as Zplugins. When Zplugins are mentioned Zplugins is the focus.
<b>[color=Orange]1. :white_small_square:The Rebound Effect:white_small_square:</span></b> <b>What:</b> Switches to the previously active zscript after execution of the current zscript. <b>Why:</b> Assists users workflow and allows for a modular construction of zplugins. <b>When:</b> Whenever a zplugin's function does not require it to remain the active zscript. <b>Description:</b>
Zplugins that are imbedded in the Zbrush interface or use Note windows for their interface, should not remain active after completing their function but instead return to the previously active zscript. For example, the currently active zscript has its interface in the Zscript Window and then the Transform > Zspinner > SpinIt button is pressed. The SpinIt button is a zplugin and therefore becomes the active zscript but it has no function after it is run and so should return to the previously active zscript.
Projection Master, XYZadjust and the Zbrush Help button are all examples of zplugins that should implement the rebound effect. Svengali first came up with this simple but excellent idea.
<b>Code:</b> The code is very simple. All that is required is to press the <b>Zscript > Previous</b> button. After pressing the button the current zscript looses control, so you want to press it when your zscript has completed its function.
[[color=PaleGreen]Ibutton, "</span>[color=Orange]Zplugin:Misc Utilities :</span>[color=Orange]Show Polygon Count", "Displays the number of polygons currently visible",</span> [[color=PaleGreen]Vardef, Polygons, 0]</span> // Variable for Mesh3DGet [[color=PaleGreen]If, [Iexists, Tool:Geometry:Cage],</span> //Make sure a PolyMesh tool is selected [[color=PaleGreen]Mesh3DGet, 1, , , Polygons]</span> //Get polygon count [[color=PaleGreen]Note, [StrMerge, "Number of Polygons : \CEE1E1E", Polygons]]</span> //Display polygon count [[color=PaleGreen]IshowActions, 0] // Hide the following Ipress from the user</span> [[color=PaleGreen]Ipress, Zscript:Previous]</span> // Return to previous Zscript ] [color=Black]// End of If statement </span>] // End of Ibutton
Zplugins that use Note Window interfaces are a problem when implementing the Rebound Effect. If the user closes the Note Window by pressing the corresponding Note Window button there is no problem, it can be detected and the previous zscript can be reloaded. But if the user presses the ‘Escape’ key we loose all control as the zscript has ended. Until we can detect and handle a user initiated zscript abortion this will remain a problem.
To take full advantage of the Rebound Effect, zscripts must be able to remember their state during a zbrush session. See the Clever Zscript functionality below.
<b>2. :white_small_square:Memory Block Naming:white_small_square:</b> <b>What:</b> Naming convention for memory blocks defined by any zscript. <b>Why:</b> To avoid memory block conflicts. <b>When:</b> Whenever a memory block is defined. </span> <b>Description:</b>
Memory blocks are an important and very useful new addition to Zbrush. They open up the ability to quickly save settings of your zscript, parse and modify text files and load/save binary files. Memory Blocks remain active across an entire Zbrush session and as such offer a way to keep track of data from within any zscript. One zscript can keep track of where the other is by analyzing its memory block. That will of course only be true for zscripts were the author has implemented such functionality and shares that info. However this can also cause problems
If everybody uses a memory block to store their settings and calls it “Options” there will be a conflict. A zscript might fail. A zscript might become buggy because another zscript is modifying a memory block with the same name. A very simple solution is to base all memory block IDs on a simple nomenclature.
For example: <b>FSoptions</b> is NOT a good Memory Block ID. <b> TV6_NMFS_options</b> would be an ok Memory Block ID. So lets examine that nomenclature. <b>TV</b> is based on the 2 first characters of my ZBC userid. There might be more people with the same first 2 initials but few who write zscripts. <b>6</b> is because this is the sixth zscript I made. <b>_</b> is just for readability. Include as many as you want in your memory block ID. <b>NMFS</b> is the shortname of the zscript in question, in this case it stands for "Normal Map Flip/Swap". <b> options</b> is what you originaly wanted to assign your memory block as an ID. The above nomenclature would pretty much elimenate any Memory Block ID conflicts. <b>Code:</b>
Even though proper naming of memory blocks should eliminate most conflicts it is still necessary to perform a standard memory block creation test. I place the following IF statement at then end of my code. You can see why in the 3rd section, Clever Zscripts.
[[color=PaleGreen]If, [MemGetSize, TV6_NMFS_options] = 0, // If size = 0 then memory block does not exist [MemCreate, TV6_NMFS_options, 64, 1] // create the memory block ,[If, [MemGetSize, TV6_NMFS_options] != 64, // if memory block is not the same size as when it was created report it. [Note, "Memory block size has changed. Zscript might not function properly"] ] ] //End of If statement</span>
<b>3. :white_small_square:Clever Zscripts:white_small_square:</b> <b>What:</b> Storing of a zscripts critical variables and current state in a memory block. <b>Why:</b> To lessen user interaction when switching zscripts. </span> <b>When:</b> Whenever a zscript critical variable is changed. <b>Description:</b> </span>
The Rebound Effect is not much use if the user needs to reapply all his/her settings when a zscript is reloaded. Storing a zscripts critical values in a memory block allows easy restoration of the zscripts previous state when switching between zscripts.
A zscript critical value is one that is either user assignable (a switch status, current tool, a user defined directory etc) or the state of the zscript (Activating Projection Master once enters one state, activating it again enters another).
The state of interface items generated by zplugins need not be stored. They are part of the Zbrush interface and are handled by Zbrush when switching zscripts.
A memory block is the easiest way to store the state of a Zscript. The following code shows how to store the values of a Zscript generated switch and slider.
[[color=PaleGreen]VarDef, Init, 1] // used to stop the If statement below from looping [Ibutton, "Show values", , [Note, [StrMerge, "Slider value: ", [Iget, Zscript:TVSlider], " ", "Switch Status: ", [Iget, Zscript:TVSwitch]]] ] // Define the slider and write to the memory block each time the slider value changes [Islider, TVSlider, 4, 1, 0, 10, "Change fdfdsj ratio", [MemWrite, TV5_example_1, [Iget, Zscript:TVSlider], , 0] , , 100] // Define the switch and write to the memory block each time the switch value changes [ISwitch, TVSwitch, 0, "Switch the effect of efdjsh", [MemWrite, TV5_example_1, [Iget, Zscript:TVSwitch], , 4],[MemWrite, TV5_example_1, [Iget, Zscript:TVSwitch], , 4]] [If, Init, [If, [MemGetSize, TV5_example_1] = 0, // If size = 0 then memory block does not exist [MemCreate, TV5_example_1, 8, 1] // create a memory block 8 bytes in size [MemWrite, TV5_example_1, [Iget, Zscript:TVSlider], , 0] [MemWrite, TV5_example_1, [Iget, Zscript:TVSwitch], , 4] , [If, [MemGetSize, TV5_example_1] != 8, // if memory block is not 8 bytes in size then report it. [Note, "Memory block size has changed. Zscript might not function properly"] ] ] [Vardef, TempValue] // define dummy/temp value for the MemRead command // Read values from memory block and set zscript interface items [MemRead, TV5_example_1, TempValue, , 0] [Iset, Zscript:TVSlider, TempValue] [MemRead, TV5_example_1, TempValue, , 4] [Iset, Zscript:TVSwitch, TempValue] [Varset, Init, 0] ]</span> // End of If statement
<b>4. :white_small_square:Size Matters:white_small_square:</b> <b>What:</b> Adjusts the height of the Zscript Window to fit the active Zscripts interface. <b>Why:</b> Assists user workflow when switching between Zscripts that utilise the Zscript Window. <b>When:</b> Performed in Zscripts that display in the Zscript Window. <b>Descripton: </b>
Zscripts that display in the Zscript Window have varying interface sizes. Switching between such zscripts usualy requires the user to either increase the height of the zscript Window to view its entire interface or to decrease the height so as to not waste valuable screen space. Automatic adjustment of the Zscript Window’s height would help workflow.
You should not worry about implementing this functionality while writing your zscript. You can and should wait until your Zscript Window Interface is finished before thinking of adjusting the ZW height.
<b>Code:</b> It might look slightly complicated but trust me, the implementation is easy.
As it needs to run automatically the following code needs to be placed as top level commands. A good idea is to place the variables at the start of your zscript for easy adjustment and the rest wherever you want.
The following code evaluates the height of the Zscript Window(Window ID 1006) and adjusts the position of the Zscript Window Divider(Window ID 1002) accordingly by [Iclick,…]'ing it. The extra [If,…] statements are needed to ensure the Zscript Window Divider is not moved less than 4 pixels. Moving the divider 3 pixels or less is the same as a mouse click which hides/unhides the Zscript Window.
[[color=PaleGreen]Vardef, ZwindowHeight, 58] // Set to your desired window height [Vardef, Init, 1] // Used for running the code below once, insert your other initialisation code in the following [If,...] statement if you wish. </span>[If, Init, [If, [Iheight, 1006</span>] < ZwindowHeight, [If, [Iheight, 1006</span>] > (ZwindowHeight-4), [Iclick, 1002, [IHpos, 1002]+100, [IVpos, 1002], [IHpos, 1002</span>]+100, ([IVPos, 1002]-10)] // Move Zscript Divider down 10 pixels ] [Iclick,1002, [IHpos,1002]+100, [IVpos, 1002], [IHpos, 1002]+100, (([IVPos, 1002]+[Iheight, 1006]) - ZwindowHeight)] // Set Zscript Divider to ZwindowHeight ] [If, [Iheight, 1006] > ZwindowHeight, [If, [Iheight, 1006] < (ZwindowHeight+4), [Iclick, 1002, [IHpos, 1002]+100, [IVpos, 1002], [IHpos, 1002</span>]+100, ([IVPos, 1002]-10)] </span>[color=Black]// Move Zscript Divider down 10 pixels</span> ] [[color=PaleGreen]Iclick, 1002, [IHpos, 1002]+100, [IVpos, 1002], [IHpos, 1002]+100, (([IVPos, 1002]+[Iheight, 1006]) - ZwindowHeight)] </span>[color=Black]// Set Zscript Divider to ZwindowHeight</span> ] [[color=PaleGreen]Varset, Init, 0] // stops If statement from looping ]</span> //End of If statement</span>
Do not concern yourself with the Zscript Window height until you are finished with your zscript. When you are finished it is simply a matter of dragging the Zscript Window Divider to your liking and adding a button that displays the current height. Remove the button when you have determined your ideal Zscript Window Heigh and then adjust the ZwindowHeight variable.
[[color=PaleGreen]Ibutton,"ZW height","Displays the current Zscript Window Height", [Note,[Iheight, 1006]], , , 'b']</span>
<b> 5. :white_small_square:The Untouched Canvas:white_small_square:</b> <b>What:</b> Restores the Canvas Zoom and Pan settings. <b>Why:</b> To minimize the zscript's effect on user workflow. <b>When:</b> Whenever the Canvas zoom and pan settings are adjusted by a zscript. <b>Description:</b>
Zscripts sometimes need to change the zoom and pan of the canvas in order to function properly. The most immediate example is when exporting the document( Document>Export ). In order to export an image with the original dimensions the Antialiased Half Size (AAHalf) view mode must be disabled which is usualy done by pressing Actual Size. This recenters the canvas and sets the zoom level to .5.
To make such an action transparent to the user we need to store the Canvas Horizontal and Vertical Pan as well as the Canvas Zoom level before pressing Actual Size. After all actions are performed the Canvas H/V Pan and Zoom level are restored.
This might not seem like an important function but if the user is currently editing a 4096*4096 sized document then the less zooming in/out and scrolling the better.
[color=Black]//Variable definitions [Vardef, Zoom] [Vardef, CpanH] [Vardef, CpanV] [Ibutton, "Zplugin:Misc Utilities :GrabFulDoc", "Grab a full size canvas texture", //Before performing canvas pan and zoom altering commands [Varset, Zoom, [CanvasZoomGet]] // store zoom level [Varset, CpanH, [CanvasPanGetH]] // store horizontal pan [Varset, CpanV, [CanvasPanGetV]] // store vertical pan [Ifreeze, //Stops the following commands from updating the interface [IShowActions, 0] //Stops the following commands from being shown to the user //Canvas zoom and pan altering function [CanvasZoomSet, 1] // Set zoom level for a 1:1 GrabDoc [Ipress, Texture:GrabDoc] // Grab canvas as a texture //After canvas pan and zoom altering function(s) [CanvasZoomSet, Zoom] // restore zoom level [CanvasPanSet, CpanH, CpanV] // restore horizontal and vertical pan ] // end of Ifreeze [Ishow, 28601, 1] // Notify user of new texture [Iset, Zscript:previous, 1] // Reload previous zscript ] //end of Ibutton</span>
That is it. I hope that people will implement most of the above suggestions and hopefully write some useful functionality code themselves. But remember it should be code that does not hinder general zscripting and zscript functionality. Happy zscripting.
Thanks goes to Svengali for providing me with feedback.