PDA

View Full Version : execute and variable scope


3rd Dimentia
05-24-2008, 09:19 AM
Before anyone says it, yeah I know I should stay away from using execute as much as possible. But I don't know another way around what I need to do.
I've only just discovered execute and am not really sure why it's not working for me.

I'm trying to replace this block of repetitive code with a loop.

if chk_ambientMap.state then activeMaterial.materialList[i].ambientMap = Bitmaptexture filename:(mapList[iter])
if chk_diffuseMap.state then activeMaterial.materialList[i].diffuseMap = Bitmaptexture filename:(mapList[iter])
if chk_specularMap.state then activeMaterial.materialList[i].specularMap = Bitmaptexture filename:(mapList[iter])
if chk_specularLevelMap.state then activeMaterial.materialList[i].specularLevelMap = Bitmaptexture filename:(mapList[iter])
if chk_glossinessMap.state then activeMaterial.materialList[i].glossinessMap = Bitmaptexture filename:(mapList[iter])
if chk_selfillumMap.state then activeMaterial.materialList[i].selfillumMap = Bitmaptexture filename:(mapList[iter])
if chk_opacityMap.state then activeMaterial.materialList[i].opacityMap = Bitmaptexture filename:(mapList[iter])
if chk_filterMap.state then activeMaterial.materialList[i].filterMap = Bitmaptexture filename:(mapList[iter])
if chk_bumpMap.state then activeMaterial.materialList[i].bumpMap = Bitmaptexture filename:(mapList[iter])
if chk_reflectionMap.state then activeMaterial.materialList[i].reflectionMap = Bitmaptexture filename:(mapList[iter])
if chk_refractionMap.state then activeMaterial.materialList[i].refractionMap = Bitmaptexture filename:(mapList[iter])
if chk_displacementMap.state then activeMaterial.materialList[i].displacementMap = Bitmaptexture filename:(mapList[iter])

So I defined an array with all the map names in it

MapTypesArray = #("ambientMap","diffuseMap","specularMap","specularLevelMap","glossinessMap","selfillumMap","opacityMap","filterMap","bumpMap","reflectionMap","refractionMap","displacementMap")

And then made this loop.

for j = 1 to mapTypesArray.count do
(
execute ("if chk_"+(mapTypesArray[j])+".state then activeMaterial.materialList[i]."+(maptypesArray[j])+" = Bitmaptexture filename:(mapList[iter])")
)

Which when I print rather than execute, gives me exactly the same code that I had in the top section.
BUT, when I execute it I get lots of 'undefined' errors. The code is in the same spot as the long version, so I don't understand that now some variables are now undefined. I'm guessing that the execute command handles variable scope differently, but I don't know how to solve the issue. Can anyone elighten me on how execute alters variable scope?

Cheers,

Cg.

davestewart
05-24-2008, 10:06 AM
Hey Chris,

The reason why your execute is failing is because

"chk_"+(MapTypesArray Array[j])

is resolving correctly to

chk_ambientMap

for example, but you actually want

myRollout.chk_ambientMap

So you just need to include the "myRollout." in your execute.

Remember, execute runs in global scope. What that actually means is (in layman's terms), even if you use an execute in your rollout code, when max pieces together all your strings and variables, it does so NOT in the rollout, but in the scene as it were, just as if you'd called the code yourself from the listener.

So, if you were attempting to reference "chk_ambientMap", max woudln't know where that was, UNLESS you told it, by adding the rollout reference to the expression.

With regards to your code, I might go about solving the problem slightly differently, by grabbing the controls into an array first:

Grab your controls into an array using execute

controls = for map in MapTypesArray collect execute ("myRollout.chk_" + map)


OR, filter the controls property of the rollout

controls = for control in myRollout.controls where substring control.name 1 4 == "chk_" collect control


OR, in fact the easiest option is to just to declare an array that references your controls in in the first place

controls = #(chk_ambientMap, chk_diffuseMap, chk_specularMap, chk_specularLevelMap, chk_glossinessMap, chk_selfillumMap, chk_opacityMap, chk_filterMap, chk_bumpMap, chk_reflectionMap, chk_refractionMap, chk_displacementMap)


Then, run your script:

for i = 1 to MapTypesArray .count do
(
local control = controls[i]
local mapType = MapTypesArray [i]
if control.state then activeMaterial.materialList[i][mapType] = Bitmaptexture filename:mapList[i]
)


Hope that helps,
Dave

3rd Dimentia
05-24-2008, 12:37 PM
Thanks Dave. I now understand the fact that execute works in global scope Thanks. I guess that's one of the reasons that people say that it's not that good to use it. As oyu have to start declaring a lot of global variables and that can be risky right?. And I've heard that it's slow. Is this correct?

Adding the rolloutname is working for the UI elements. But I also have other variables in the execute that I tried to add the rolloutname to, but it doesn't seem to work the same way that it does with UI elements. Is there a way to not have to declare these variables as global for the execute to be able to see them?

I do like your last example that works without the use of "execute" though. I think I'll head down that path.

I'm very greatful for your lengthy reply... That you've given me an alternative to execute and a new coding structure that I would have never come up with myself.
:buttrock:

Cheers,

Cg.

magicm
05-24-2008, 01:03 PM
I now understand the fact that execute works in global scope Thanks. I guess that's one of the reasons that people say that it's not that good to use it. As oyu have to start declaring a lot of global variables and that can be risky right?. And I've heard that it's slow. Is this correct?
Using global variables is not necessarily risky, unless you use very common names in which case an existing global might get overwritten. Having said that, you really should only use globals when there's no other way (just like the "execute" method). Locals are better in terms of memory management (the garbage collector destroys them when the scope in which they were created is no longer active).

But I also have other variables in the execute that I tried to add the rolloutname to, but it doesn't seem to work the same way that it does with UI elements.
This all depends on the scope in which these variables where created. In case they were declared at the top of the rollout definition:
rollout test "test"
(
local myVar = 1

...
)you should be able to access these variables outside the rollout's scope by using test.myVar, unless of course the rollout definition is not known to scope you're currently in. Hope that makes any sense!

Be sure to check out the "Scope of Variables" topic in the online reference to learn more about them.

Cheers,
Martijn

3rd Dimentia
05-24-2008, 01:44 PM
I'm still having trouble getting it working.. I'm getting a rollout handler exception saying:
-- No ""put"" function for material#64:standard

I think it's the maptype that's messing it up. I've tried all sorts of ways to define the array of mapTypes. But nothing has worked yet.


And I'm assuming that in your last example which I'm trying to copy that you didn't mean to leave the ") on the end of the last line?

davestewart
05-24-2008, 02:05 PM
Alright,


And I'm assuming that in your last example which I'm trying to copy that you didn't mean to leave the ") on the end of the last line?

Sorry about that. It was meant more to be an illustration on what you'd code than actual code. You'd also need to take off the trailing quote which I left on as well :rolleyes:

if control.state then activeMaterial.materialList[i][mapType] = Bitmaptexture filename:mapList[i]


The point is - you don't need to use execute. You just need to stick your controls in an array so you have a reference to them, then run some straight (unexecuted) code in a loop.

As you said, it might be your values in the array.

Test with one control in the listener to get it right:

control = rollout.chk_whatever
mapType = #specularMap
filename = "image.jpg"

activeMaterial.materialList[1][mapType]<do you need something here? Like "bitmap"> = Bitmaptexture filename:filename


Hope that helps,
Dave

3rd Dimentia
05-24-2008, 02:58 PM
Yeah that's what I've been doing for the past few hours... Trying ot figure out how I can use a variable to replace the .ambientMap .diffuseMap etc parts with emements of an array that I can call with the [maptype] but I don't know if I just haven't hit the right combo or it's just not possible. But I just haven't been able to find it yet. Thanks so much for your time. I really appreciate it. I have got all the controls stuff working great along the lines of how you suggested, I'm just running in circles trying to get the other bit going now.

davestewart
05-24-2008, 04:09 PM
but I don't know if I just haven't hit the right combo


Use the macro recorder to check the expression ;)

Plus: there's always setProperty.

setProperty map #filename filename

3rd Dimentia
05-25-2008, 01:00 AM
I've definitely been using the macro recorder. It's how I originally arrived at the verbose-repetitive way of assigning the maps.

if chk_ambientMap.state then activeMaterial.materialList[i].ambientMap = Bitmaptexture filename:(mapFileList[iter])
if chk_diffuseMap.state then activeMaterial.materialList[i].diffuseMap = Bitmaptexture filename:(mapFileList[iter])
if chk_specularMap.state then activeMaterial.materialList[i].specularMap = Bitmaptexture filename:(mapFileList[iter])

From what I can see it doesn't give me any tips on how to replace the maptype section of the code with a variable. I've also looked into te get/set properties but have also failed to find a way to do what I want. I might just have to stick with the long winded clunky way that I had originally. It works, but it's just not that elegant. I've spent way too much time getting nowhere with this part of the script.

Huge thanks for your efforts. Although I haven't solved all the issues I'm having, you really have helped me look at things a bit differently.

I appologise for my lack of programming background. I don't have that 'base' knowlege of programming techniques to call on, so I understand that it can get a bit frustrating for someone trying to help me when things seem so obvious and I'm just not "getting it".

Cheers,

Cg.

davestewart
05-25-2008, 09:25 AM
From what I can see it doesn't give me any tips on how to replace the maptype section of the code with a variable.

Try this:

files = #("C:\\Temp\\sphere.jpg", "C:\\Temp\\box.jpg")
mapTypes = #(#diffuseMap,#opacityMap)

mat = meditMaterials[1].material1
map = mat.diffuseMap

setProperty mat #diffuseMap (Bitmaptexture filename:(files[1]))

Also, you may want to look at the section "Map Channels for Standard Material Shaders" in the "StandardMaterial : Material" page in the MaxScript help. It's another way to access map channels

The help should be your first port of call with most programming problems. It can sometimes be difficult to understand at first if you're a non-programmer (for example all the <datatype>function Type argument: stuff) but if you read thorugh the page relating to the class you're dealing with (in this case StandardMaterial and BitmapTexture) you'll normally come out with the answer, and have found some useful stuff you didn't know as well!


I appologise for my lack of programming background. I don't have that 'base' knowlege of programming techniques to call on, so I understand that it can get a bit frustrating for someone trying to help me when things seem so obvious and I'm just not "getting it".

Not at all! Don't worry about it. When I first started I was on here all the time. The reason I still come on here is that you're always learning. By helping you, I actually get to find out about bits of max maybe I haven't played with for a while, so it's a win-win situation.

It's only annoyying when someone blatently doesn't want to help themselves, but that isn't you ;)

Cheers,
Dave

LoneRobot
05-25-2008, 09:48 AM
Just thought i'd add to Dave's excellent reply that if you are trying to loop through all the controls on a rollout, MXS already has a property for this - typing RolloutName.controls will return an array containg all the controls. this is also useful for performing a loop to enable/disable parts of the UI.

3rd Dimentia
05-27-2008, 12:42 PM
I finally got what I wanted working thanks to your patient help. Thanks.

The code that came out of all this is:

local chkTypesArray = #(chk_ambientMap,chk_diffuseMap,chk_specularMap,chk_specularLevelMap,chk_glossinessMap,chk_selfillumMap,chk_opacityMap,chk_filterMap,chk_bumpMap,chk_reflectionMap,chk_refractionMap,chk_displacementMap)
local MapTypesArray = #(#ambientMap,#diffuseMap,#specularMap,#specularLevelMap,#glossinessMap,#selfillumMap,#opacityMap,#filterMap,#bumpMap,#reflectionMap,#refractionMap,#displacementMap)

for j = 1 to mapTypesArray.count do
(
if chkTypesArray[j].state then (setproperty activeMaterial.materialList[i] (MapTypesArray[j]) (bitmaptexture filename:(mapFileList[iter])))
)


Thanks for your time and insight,

Cg.

magicm
05-27-2008, 01:39 PM
I'm not sure if this is what you want, but since you're assigning the same bitmap to all slots, you could create instances of the bitmapTexture instead of individual copies:

local chkTypesArray = #(chk_ambientMap,chk_diffuseMap,chk_specularMap,chk_specularLevelMap,chk_glossinessMap,chk_selfillumMap,chk_opacityMap,chk_filterMap,chk_bumpMap,chk_reflectionMap,chk_refractionMap,chk_displacementMap)
local MapTypesArray = #(#ambientMap,#diffuseMap,#specularMap,#specularLevelMap,#glossinessMap,#selfillumMap,#opacityMap,#filterMap,#bumpMap,#reflectionMap,#refractionMap,#displacementMap)

local b = bitmaptexture filename:mapFileList[iter]

for j = 1 to mapTypesArray.count do
(
if chkTypesArray[j].state then (setproperty activeMaterial.materialList[i] MapTypesArray[j] b)
)
Cheers,
Martijn

CGTalk Moderation
05-27-2008, 01:39 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.