Module: TT::Material

Defined in:
TT_Lib2/materials.rb

Overview

Collection of Material methods.

Since:

  • 2.5.0

Class Method Summary collapse

Class Method Details

.get_current(model = Sketchup.active_model) ⇒ Sketchup::Material

Note:

Do not use within a start_operation block. This method uses a temporary operation which will break any already initiated operations.

Because SketchUp will bugsplat if a material selected from the library is used this method attempts to add the material to the model.

Parameters:

  • model (Sketchup::Model) (defaults to: Sketchup.active_model)

Returns:

  • (Sketchup::Material)

Since:

  • 2.7.0



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'TT_Lib2/materials.rb', line 45

def self.get_current( model = Sketchup.active_model )
  materials = model.materials
  m = materials.current
  return m if m.nil?
  # Check if material already exists. If it does - reuse it.
  name = m.name
  if x = materials[ name ]
    if x.color.to_i == m.color.to_i && x.alpha == m.alpha
      # No texture applied.
      if x.texture.nil? && m.texture.nil?
        materials.current = x
        return x
      end
      x_basename = File.basename( x.texture.filename )
      m_basename = File.basename( m.texture.filename )
      if m_basename == m.texture.filename
        # If the texture only have a filename - not a path.
        if x_basename == m.texture.filename &&
            x.texture.width == m.texture.width &&
            x.texture.height == m.texture.height
          materials.current = x
          return x
        end
      else
        # If the texture only have a filename with full path.
        if x.texture.filename == m.texture.filename &&
            x.texture.width == m.texture.width &&
            x.texture.height == m.texture.height
          materials.current = x
          return x
        end
      end
    else
    end
  end
  # Transfer name and colour.
  new_material = materials.add( name )
  new_material.color = m.color
  new_material.alpha = m.alpha
  # Any textures require special attention. If the filename contains a valid
  # path to an existing file nothing special needs to be done.
  #
  # But if the filename refers to a non-existing file it needs to be written
  # out to a temp file. This is where things become a bit risky and hacky.
  # Because TextureWriter doesn't accept Material objects the orphan material
  # needs to be temporarily applied to the model (risky).
  #
  # Materials from SketchUp's default library only contains the name of the
  # file without any paths. This is because the texture is located only within
  # the.skm.
  if m.texture
    filename = m.texture.filename
    if File.exist?( filename )
      new_material.texture = filename
    else
      # Create temp file to write the texture to.
      temp_path = TT::System.temp_path
      temp_folder = File.join( temp_path, 'tt_su_tmp_mtl' )
      temp_filename = File.basename( filename )
      temp_file = File.join( temp_folder, temp_filename )
      unless File.exist?( temp_folder )
        Dir.mkdir( temp_folder )
      end
      # Create temp group with the orphan material and write it out.
      #
      # Wrap within start_operation and clean up with abort_operation so it
      # doesn't end up in the undo stack.
      #
      # (!) This means this method should not occur within any other 
      #     start_operation blocks - as operations cannot be nested.
      tw = Sketchup.create_texture_writer
      model.start_operation( 'Extract Orphan Material' )
      begin
        g = model.entities.add_group
        g.material = m
        tw.load( g )
        tw.write( g, temp_file )
      ensure
        model.abort_operation
      end
      # Load texture to material and clean up.
      new_material.texture = temp_file
      File.delete( temp_file )
    end
    new_material.texture.size = [ m.texture.width, m.texture.height ]
  end
  materials.current = new_material
  new_material
end

.in_model?(material, model = Sketchup.active_model) ⇒ Boolean

When the user clicks on a material in the materials browser model.materials.current will return a material that does not exist in the model. It is possible to apply this material to entities in the model, but it will evetually BugSplat.

This method checks if a given material exist in the model and is safe to use.

Parameters:

  • material (Sketchup::Material)
  • model (Sketchup::Model) (defaults to: Sketchup.active_model)

Returns:

  • (Boolean)

Since:

  • 2.5.0



28
29
30
31
32
# File 'TT_Lib2/materials.rb', line 28

def self.in_model?( material, model = Sketchup.active_model )
  #model.materials.any? { |m| m == material }
  # This is probably just as good to write. Is this wrapper method needed?
  model.materials.include?( material )
end

.remove(material, model = Sketchup.active_model) ⇒ Boolean

Safely removes a material from a model.

Parameters:

  • material (Sketchup::Material)
  • model (Sketchup::Model) (defaults to: Sketchup.active_model)

Returns:

  • (Boolean)

Since:

  • 2.5.0



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'TT_Lib2/materials.rb', line 143

def self.remove( material, model = Sketchup.active_model )
  # SketchUp 8.0M1 introduced model.materials.remove, which turned out to be
  # bugged. It didn't remove the material from the entities in the model - 
  # leaving the model with rouge invalid materials.
  # To work around this all entities are processed before the method is called.
  # The workaround for older versions also require this to be done.
  for e in model.entities
    e.material = nil if e.respond_to?( :material ) && e.material == material
    e.back_material = nil if e.respond_to?( :back_material ) && e.back_material == material
  end
  for d in model.definitions
    next if d.image?
    for e in d.entities
      e.material = nil if e.respond_to?( :material ) && e.material == material
      e.back_material = nil if e.respond_to?( :back_material ) && e.back_material == material
    end
  end
  materials = model.materials
  if materials.respond_to?( :remove )
    materials.remove( material )
  else
    # Workaround for SketchUp versions older than 8.0M1. Add all materials
    # except the one to be removed to temporary groups and purge the materials.
    temp_group = model.entities.add_group
    for m in model.materials
      next if m == material
      g = temp_group.add_group
      g.material = material
    end
    materials.purge_unused
    temp_group.erase!
    true
  end
end