[APIBug] Applying current material might cause bugsplat
-
I documented a cause of bugsplat on video.
[flash=640,505:39uk3dmx]http://www.youtube.com/v/Rv4KmpEMP5M?fs=1&hl=en_US[/flash:39uk3dmx]
Snippets used in video:
Sketchup.active_model.materials.length
Sketchup.active_model.selection[0].material = Sketchup.active_model.materials.current
Issue:
It appears that when the user has selected a material from the libraries in the material browser, and you try to apply that material via the Ruby API before it exists in the model, then SketchUp becomes unstable and will eventually crash shortly after. I noticed other odd behaviour, but didn't manage to catch that on camera.I haven't found a way to safely apply current material if it's not already in the model.
Avoidance:
So far I've only managed to find a way to avoid using materials that are not in the model:
current_materia = Sketchup.active_model.materials.current Sketchup.active_model.materials.any? { |m| m == current_material }
-
A question here:
This condition occurs only when you have the Ruby Console open, and in the video it appears you are applying it as input to the console and not in the model space?
Could the material, or the program be looking for a defined face in its "code" on activation? Is this condition unique to any particular version of Sketchup? -
@mitcorb said:
This condition occurs only when you have the Ruby Console open,
No - I ran into it when testing a plugin I was working on. I used the Ruby Console in this example because it shows the simplest case to reproduce it.
@mitcorb said:
and in the video it appears you are applying it as input to the console and not in the model space?
Sorry, but what?
@mitcorb said:
Could the material, or the program be looking for a defined face in its "code" on activation?
Still not quite sure what you mean here, but my snippet which I used in the Ruby Console applied the current material to the selected entity. The bugsplat occurs when the current material does not yet exist in the model, but is picked from the model library - as shown in the video.
@mitcorb said:
Is this condition unique to any particular version of Sketchup?
I have only tested SketchUp8 under Windows. Don't know the other versions.
-
ThomThom:
mitcorb wrote:and in the video it appears you are applying it as input to the console and not in the model space?
Sorry, but what?Here, what I mean is you selected the material from its browser, then clicked on the input line of the console, not on anything in the model space, as far as I can tell. (didn't know you could do that)
mitcorb wrote:Could the material, or the program be looking for a defined face in its "code" on activation?
Here, what I mean is: As part of Selection of Material and placement, you have to tell Sketchup, or whatever what surface you will apply it to.
I really do not have any Ruby experience. I was just looking at this from a conceptual point of view, with the intent to help discover an idea, if it was lurking there.
-
I can reproduce the problem.
If you have a library-material picked that should become themodel.materials.current
after it's used once BUT SUp changes the model.materials.current too soon to be the library-material when it isn't part of model.materials [except that it returns as 'current'], you can then use that 'current' material in the SKP... BUT it is not yet added to materials [the length ofmodel.materials
remains the same,materials.to_a
doesn't include this library-material [yet], and the material-browser model-window doesn't show it either]... later doing something to the materials list will cause a Bugsplat as something is cross-threaded in the data-base.
The clunky trap is to get the current_material before this library step (current_material0=model.materials.current
) then reset itcurrent_material=model.materials.current if model.materials.to_a.include?(model.materials.current)
then reset the current_material withcurrent_material=current_material0 if not current_material; model.materials.current=current_material
- then you can't cross-thread things???
Surely a selected library-material should not pass themodel.materials.current
until it has been used.
It is taking the material in the top pane of the material-browser rather than the true 'current-material' - which is the "[last] selected material that is in the model" ???
Of course using my 'SKMtools' would let you import the SKM into the model's materials and then set it current without this mess... -
@mitcorb said:
Here, what I mean is you selected the material from its browser, then clicked on the input line of the console, not on anything in the model space, as far as I can tell. (didn't know you could do that)
Yes, I applied the material to the selected face via the Ruby API. It makes the whole difference. Using the Paint Bucket tool does not have this problem. The problem comes when you write a plugin that makes use of the user-selected material.
@mitcorb said:
you have to tell Sketchup, or whatever what surface you will apply it to.
Yes, which is what this line does:
Sketchup.active_model.selection[0].material = Sketchup.active_model.materials.current
It applied the current material to the selected entity. -
@tig said:
Surely a selected library-material should not pass the
model.materials.current
until it has been used.
It is taking the material in the top pane of the material-browser rather than the true 'current-material' - which is the "[last] selected material that is in the model" ???It would be ok if SU ensured to add the material to the model when used. Which is what I'd prefer so you could get seamless experienced with the material browser and plugins.
-
@tig said:
The clunky trap is to get the current_material before this library step (
current_material0=model.materials.current
) then reset itcurrent_material=model.materials.current if model.materials.to_a.include?(model.materials.current)
then reset the current_material withcurrent_material=current_material0 if not current_material; model.materials.current=current_material
- then you can't cross-thread things???
Surely a selected library-material should not pass themodel.materials.current
until it has been used.That would be:
current_material0=model.materials.current current_material=model.materials.current if model.materials.to_a.include?(model.materials.current) current_material=current_material0 if not current_material model.materials.current=current_material
Doesn't that just move the material reference around to different variables? I can't get that to make the material be added to the in-model list.
-
@thomthom said:
@tig said:
The clunky trap is to get the current_material before this library step (
current_material0=model.materials.current
) then reset itcurrent_material=model.materials.current if model.materials.to_a.include?(model.materials.current)
then reset the current_material withcurrent_material=current_material0 if not current_material; model.materials.current=current_material
- then you can't cross-thread things???
Surely a selected library-material should not pass themodel.materials.current
until it has been used.That would be:
current_material0=model.materials.current current_material=model.materials.current if model.materials.to_a.include?(model.materials.current) current_material=current_material0 if not current_material model.materials.current=current_material
Doesn't that just move the material reference around to different variables?
I can't get that to make the material be added to the in-model list.You can't force a library-material into the
model.materials
proper unless you physically add it manually.
The way to do it in code is to use my SKMtools -SKM.import(path_skm)
.
You can perhaps get the temporary limboedmaterial.current.name
to find the SKM name ?
Then find it in Materials ?
If you make an array ofmodel.materials
before andafterward the SKM import you get the reference to the new material - although you could get it by name preexisting names might screw that up... Then set themodel.material.current=that_new_material
to complete...Alternatively you could try to get all of the properties of the 'current-material-in-limbo' half-baked on it's way in from the library and make a completely new material in the model based on all of it's properties and then set that as current. However you need to get it's texture which requires it to be applied to something temporarily at least for a texturewriter... which would probably splat too ???
-
Thom
I have a clunky work round to force a selected material from the library into the
model.materials
without a Bugsplat.
You need my SKMtools,material_class.rb
loaded as it uses thematerial.name="newname"
method
Here are the basic steps...mats=Sketchup.active_model.materials #<Sketchup;;Materials;0xa93a9cc> cmat=mats.current ### let's assume if is a library material not really in the model yet... #<Sketchup;;Material;0xa77e084> cname=cmat.display_name Brick_Antique cmat=(cmat.name=cname+"x") #<Sketchup;;Material;0xa77e098> cmat.name=cname Brick_Antique
The material hovering in limbo when is selected from the library materials-browser but not yet used in the model itself is briefly renamed and then named back again... forcing it to become part of the model's materials, so it keeps its name and is kept as the current-material too. I haven't got a Bugsplat [yet
]...
-
Here's a short code snippet
<span class="syntaxdefault"></span><span class="syntaxkeyword">=</span><span class="syntaxdefault">begin<br /></span><span class="syntaxkeyword">(</span><span class="syntaxdefault">c</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> TIG 2011<br /></span><span class="syntaxkeyword">=</span><span class="syntaxdefault">end<br />require </span><span class="syntaxstring">'sketchup.rb'<br /></span><span class="syntaxdefault">require </span><span class="syntaxstring">'SKMtools/material_class.rb'<br /></span><span class="syntaxcomment">###<br /></span><span class="syntaxdefault">def material_from_limbo</span><span class="syntaxkeyword">()<br /></span><span class="syntaxdefault"> mats </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">materials<br /> cmat </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> mats</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">current </span><span class="syntaxcomment">### the limbo one<br /></span><span class="syntaxdefault"> cname </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> cmat</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">display_name<br /> cmat</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">name </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> cname</span><span class="syntaxkeyword">+</span><span class="syntaxstring">"x"<br /></span><span class="syntaxdefault"> cmat </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> mats</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">current<br /> cmat</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">name </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> cname<br /> cmat </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> mats</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">current<br /> return cmat </span><span class="syntaxcomment">### now safely added to model<br /></span><span class="syntaxdefault">end<br /></span><span class="syntaxcomment">### usage; cmat = material_from_limbo<br /></span><span class="syntaxdefault"> </span>
If you select a material from the library and then immediately run the 'usage' example you will have a reference to the new current material that is added to the model [but currently unused]. The active tool will stay as the paintbucket unless you code an alternative 'tool' change...
Advertisement