=begin
###########################################################################
TIG (c) 2010-2011
All Rights Reserved.
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES,INCLUDING,WITHOUT LIMITATION,THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
###########################################################################
OBJexporter.rb
###########################################################################
Usage: menu File > 'OBJexporter...'
It Exports the Model in OBJ Format with an associated MTL file and a folder 
of image-files [..._Textures] if appropriate.
By default the files use the SKP's name with spaces etc squeezed out.
By default the files and sub-folder are put into the SKP's folder.
A starting dialog allows you to give an alternative filename/folder.
By default everything in the SKP that is not Hidden and that is on visible 
Layers is Exported.
By default the Units are in 'meters'.
By default All Exported Faces are Triangulated .
By default the Y & Z axes are swapped.
Note that 'distorted textures' are exported as new unique texture-files, 
distorted to match and re-UVmapped, like the Pro-OBJexporter - any scaled 
or rotated textures are UVmapped appropriately using the main texture-file.
###########################################################################
To do: Options Dialog for Model/Selection, Units, Triangulation, YZ-swap...
###########################################################################
Donations:
  By Paypal.com to info @ revitrev.org
###########################################################################
Version:
1.0 20101216 First issue.
1.1 20110106 Image class method extensions only load if not already defined.
1.2 20110224 Distorted textures are now exported correctly, with their own 
             distorted 'unique texture' files [like the Pro-OBJexporter].
1.3 20110225 Glitch with some distorted textures 'flipping' addressed.  
             Materials and textures applied within and on to Groups or 
             Instances now properly defined and UV-mapped.
1.4 20110228 The new Filename now has spaces etc squeezed out.
             Startup dialog added to allow Filename/Folder to be changed.
             Glitches with reversals of some smoothed faces and materials 
             occasionally missing from complex faces now addressed.
             General speed and Status-Bar progress-reporting improved.
1.5 20110323 Glitch with 'smoothed normals' addressed.
1.6 20110402 Option to export all Texture files in PNG format added.
###########################################################################
=end
###
require 'sketchup.rb'
###

class Sketchup::Image
	if not Sketchup::Image.method_defined?(:definition)
      def definition()
        if not self.valid?
            puts "Image "+self.to_s+" is no longer valid."
            return false
        end#if
		self.model.definitions.each { |d| return d if d.image? && d.instances.include?(self)}
        return nil
	  end#def
    end#if

    if not Sketchup::Image.method_defined?(:transformation)
	  def transformation()
        if not self.valid?
            puts "Image "+self.to_s+" is no longer valid."
            return false
        end#if
		origin = self.origin
		axes = self.normal.axes
		tr = Geom::Transformation.axes(ORIGIN, axes.at(0), axes.at(1), axes.at(2))
		tr = tr*Geom::Transformation.rotation(ORIGIN, Z_AXIS, self.zrotation)
		tr = (tr*Geom::Transformation.scaling(ORIGIN, self.width/self.pixelwidth, self.height/self.pixelheight, 1)).to_a
		tr[12] = origin.x
		tr[13] = origin.y
		tr[14] = origin.z
		return Geom::Transformation.new(tr)
	  end#def
    end#if

	if not Sketchup::Image.method_defined?(:transformation=)
      def transformation=(tr)
        if not self.valid?
            puts "Image "+self.to_s+" is no longer valid."
            return false
        end#if
        if tr.class==Array
          tr=Geom::Transformation.new(tr)
        end#if
		status=self.transform!(self.transformation.inverse * tr)
        if status
          return self
        else
          return nil
        end#if
	  end
    end#if
end# Image class

class Sketchup::Group
    # Sometimes the group.entities.parent refer to the wrong definition.
    # This checks for error and locates the correct parent definition.
    if not Sketchup::Group.method_defined?(:definition)
        def definition()
          if self.entities.parent.instances.include?(self)
            return self.entities.parent
          else
            Sketchup.active_model.definitions.each { |definition|
                return definition if definition.instances.include?(self)
            }
          end
          return nil # Should not happen.
        end
    end#if
end# group class

###########

class OBJexporter

    def initialize()
        @model=Sketchup.active_model
        path=@model.path.tr("\\", "/")
        if not path or path==""
            UI.messagebox("OBJExporter:\n\nSave the SKP before Exporting it as OBJ\n")
            return nil
        end#if
        @project_path=File.dirname(path)
        @title=@model.title.gsub(/[^\-_0-9A-Za-z]/, "_")
        @base_name=@title
        @sel=@model.selection
        ### save dialog
        result=UI.savepanel("OBJexporter - File Name ?", @project_path, @base_name+".obj")
        return nil if not result or result==""
        ### PNG?
        if UI.messagebox("OBJExporter:\n\nConevrt ALL Texture Files to PNG ?\n",MB_YESNO,"")==6 ### 6=YES
          @png=true
        else
          @png=false
        end#if
        ###
        @base_name=File.basename(result, ".*").gsub(/[^\-_0-9A-Za-z]/, "_")
        @project_path=File.dirname(result)
        ### set up mat list
        @all_mats=[nil] ### for 'default'
        mats=@model.materials.to_a
        @mats=[]
        @saved_names=[]
        mats.each{|mat|
          mat_name=mat.display_name.gsub(/ /, '_').gsub(/[^_0-9A-Za-z]/, '')
          saved_name=File.basename(mat_name)
          saved_name_uniq=self.make_name_unique(@saved_names, saved_name)
		  @saved_names << saved_name_uniq
          @mats << [mat, saved_name_uniq]
          @all_mats << mat
        }
        defns=@model.definitions
        img_mats=[]; @imgs=[]
        defns.each{|defn|
          next if not defn.image?
          face=nil
          defn.entities.each{|e|
            if e.class==Sketchup::Face
              face=e
              break
            end#if
          }
          next if not face
		  mat=face.material
          mat_name=mat.display_name.gsub(/ /, '_').gsub(/[^_0-9A-Za-z]/, '')
          saved_name=File.basename(mat_name)
          saved_name_uniq=self.make_name_unique(@saved_names, saved_name)
		  @saved_names << saved_name_uniq
          @imgs << [mat, saved_name_uniq]
          @all_mats << mat
        }
        ### get settings etc...
        self.export()
        ###
    end

    def export()
        @obj_name=@base_name+".obj"
        Sketchup.set_status_text(@obj_name)
        @obj_filepath=File.join(@project_path, @obj_name)
        @mtllib=@base_name+".mtl"
        @mtl_file=File.join(@project_path, @mtllib)
		@textures_name=@base_name+"_Textures"
        @textures_path=File.join(@project_path, @textures_name)
		@v_counter=0
		@used_materials=[]
        @distorted=[]
        @dmats=[]
        #@smedges=[]
        #@soedges=[]
        @msg="OBJExporter: Exporting OBJ & MTL Files"
        Sketchup.set_status_text(@msg)
        puts @msg
		start_time=Time.now.to_f
        self.export_start()
		end_time=(((Time.now.to_f - start_time)*10000).to_i/10000.0).to_f.to_s
		@msg="OBJexporter: Completed in #{end_time} seconds"
        Sketchup.set_status_text(@msg)
        UI.beep; puts @msg
        ###
	end
    
    def export_start()
		@obj_file=File.new(@obj_filepath, "w")
        @obj_file.puts "# Alias Wavefront OBJ File Exported from SketchUp"
        @obj_file.puts "# with OBJexporter (c) 2010-2011 TIG"
        @obj_file.puts "# Units = meters"
        @obj_file.puts ""
		@obj_file.puts "mtllib #{@mtllib}"
        @obj_file.puts ""
        @msg<<'. '
        Sketchup.set_status_text(@msg)
		self.export_obj()
        @obj_file.flush if @obj_file
		@obj_file.close if @obj_file
        @msg<<'. '
        Sketchup.set_status_text(@msg)
		self.export_textures()
        @msg<<'. '
        Sketchup.set_status_text(@msg)
		self.export_mtl_material()
        @msg<<'. '
        Sketchup.set_status_text(@msg)
        #@smedges.each{|e|e.smooth=true}
        #@msg<<'. '
        #Sketchup.set_status_text(@msg)
        #@soedges.each{|e|e.soft=true}
        ### done
	end

	def export_obj()
        @img_mats=[]
		title=@title
		ents=@model.entities.to_a
		objname=title+"_Main"
        faces=ents.find_all{|e|e.class==Sketchup::Face}
	    if faces[0]
            @msg<<'. '
            Sketchup.set_status_text(@msg)
		    self.export_faces(faces, objname)
		end#if
        ### default trans ???
        tr=Geom::Transformation.axes(ORIGIN, X_AXIS, Y_AXIS, Z_AXIS)
        @msg<<'. '
        Sketchup.set_status_text(@msg)
        ents.find_all{|e|e.class==Sketchup::Image}.each{|ci| self.export_image(ci, title, tr) }
        @msg<<'. '
        Sketchup.set_status_text(@msg)
	    ents.find_all{|e|e.class==Sketchup::Group}.each{|gp| self.export_group(gp, title, tr) }
        @msg<<'. '
        Sketchup.set_status_text(@msg)
	    ents.find_all{|e|e.class==Sketchup::ComponentInstance}.each{|ci| self.export_component_instance(ci, title, tr) }
        ###
	end

	def export_group(gp, title="", tr=Geom::Transformation.new, mat=nil)
		return if gp.hidden? == true or gp.layer.visible? == false
		ot=tr * gp.transformation
		defmat=mat
		defmat=gp.material if gp.material
		@used_materials << defmat
		id=gp.entityID
		name="#{id}"
        name=name + "-" + gp.name if gp.name or gp.name=""
		name.gsub!(/[^\-_0-9A-Za-z]/, "_")
		objname=title + "_g_" + name
		if gp.entities.find{|e|e.class==Sketchup::Face}
			self.export_faces(gp.entities.find_all{|e|e.class==Sketchup::Face}, objname, ot, defmat)
		end
        ###
        gp.entities.find_all{|e|e.class==Sketchup::Image}.each{|f| self.export_image(f, title, ot) }
		gp.entities.find_all{|e| e.class==Sketchup::Group}.each{|f| self.export_group(f, title, ot, defmat) }
	    gp.entities.find_all{|e| e.class==Sketchup::ComponentInstance}.each{|f| self.export_component_instance(f, title, ot, defmat) }
        ###
	end
     
	def export_component_instance(ci, title="", tr=Geom::Transformation.new, mat=nil)
		return if ci.hidden? or not ci.layer.visible?
		ot=tr * ci.transformation
		defmat=mat
		defmat=ci.material if ci.material
		@used_materials << defmat
		id=ci.entityID
		name=ci.definition.name
		name="#{id}" if name.length == 0
		name.gsub!(/[^\-_0-9A-Za-z]/, "_")
		objname=title + "_c_" + name
		if ci.definition.entities.find{|e| e.class==Sketchup::Face }
			self.export_faces(ci.definition.entities.find_all{|e|e.class==Sketchup::Face}, objname, ot, defmat)
		end
		(ci.definition.entities.find_all{|e| e.class==Sketchup::Image}).each{|f| self.export_image(f, title, ot) }
        (ci.definition.entities.find_all{|e| e.class==Sketchup::Group}).each{|f| self.export_group(f, title, ot, defmat) }
	    (ci.definition.entities.find_all{|e| e.class==Sketchup::ComponentInstance}).each{|f| self.export_component_instance(f, title, ot, defmat) }
	end
    
    def export_image(img, title="", tr=Geom::Transformation.new)
		return if img.hidden? == true or img.layer.visible? == false
        defn=img.definition
        return if not defn
        face=nil
        defn.entities.each{|e|
          if e.class==Sketchup::Face
            face=e
            break
          end#if
        }
        return if not face
		ot=tr * img.transformation
		defmat=face.material
		@used_materials << defmat
		id=img.entityID
		name="#{id}"
		name.gsub!(/[^\-_0-9A-Za-z]/, "_")
		objname=title + "_i_" + name
        self.export_faces([face], objname, ot, defmat)
        ###
	end

	def export_faces(all_faces=[], objname="", tr=Geom::Transformation.new, defmat=nil)
        ### do it by material per object
        @msg<<'.'
        Sketchup.set_status_text(@msg)
		@all_mats.each{|mat|
			faces=all_faces.find_all{|face|face.material==mat}
			next if not faces[0]
            all_faces=all_faces-faces
            @used_materials << mat
            vs=[]
			nos=[]
			uvs=[]
			meshes=[]
			faces.each{|face|
				next if face.hidden? or not face.layer.visible?
                next if self.distorted?(face, objname, tr)
                #### we temporarily unsmooth/unsoft face edges to mesh it
                #face.edges.each{|e|
                  #if e.smooth?
                    #@smedges << e
                    #e.smooth=false
                  #end
                  #if e.soft?
                    #@soedges << e
                    #e.soft=false
                  #end
                #}
				mesh=face.mesh(5)###7=backs too
                ### reset smooth/soft at the end
				next if not mesh
                f_uvs=(1..mesh.count_points).map{|i|mesh.uv_at(i,1)}####1=front
                f_vs=[]
                f_vs=(1..mesh.count_points).map{|i|mesh.points[i-1]}
				f_nos=[]
                f_nos=(1..mesh.count_points).map{|i|mesh.normal_at(i)}
                f_vcount=1; f_vcount=vs.length + 1 if vs[0]
				meshes.concat(mesh.polygons.map{|p| [p.map{|px|(f_vs.index(mesh.points[(px.abs-1)]) + f_vcount)}] })
                vs.concat(f_vs) if f_vs
				uvs.concat(f_uvs) if f_uvs
				nos.concat(f_nos) if f_nos
			}#faces.each
			@meshes=meshes
			@nos=nos
            @vs=vs
			@uvs=uvs
            defn=faces[0].parent
            if not mat
              mat=defmat
              if defn != @model and defmat and defmat.texture
                ### re-map - it's on an Instance/Group
                ### we make exploded copy of it and map textures...
                tgp=@model.active_entities.add_group()
                tents=tgp.entities
                inst=tents.add_instance(defn, Geom::Transformation.new())
                inst.explode
                tents.to_a.each{|e|e.erase! if e.class==Sketchup::Face and e.material}
                tents.to_a.each{|e|e.material=mat if e.class==Sketchup::Face}
                self.export_faces(tents.find_all{|e|e.class==Sketchup::Face}, objname, tr, nil)
                tgp.erase!
              else
                self.export_obj_file(objname, tr, mat)
              end#if
            else
			  self.export_obj_file(objname, tr, mat)
            end#if
		}#@mats.each
        ###
        self.process_distorted() if @distorted
        ###
	end
    
    def distorted?(face=nil, objname="", tr=nil)
        return false if not face
        mat=face.material
        return false if not mat
        texture=mat.texture
        return false if not texture
        ### check for distortion
        mesh=face.mesh(5)###7=backs too
        uvs=[]
        f_uvs=(1..mesh.count_points).map{|i|mesh.uv_at(i,1)}####1=front
        uvs.concat(f_uvs) if f_uvs
        disto=false
        uvs.each{|uvq| disto=true if ((uvq.z.to_f)*100000).round != 100000 }
        @distorted << [face, objname, tr, mat] if disto
        return disto
    end#distorted?
    
    def process_distorted()
        @msg<<'.'
        Sketchup.set_status_text(@msg)
        @distorted.each{|a|
          face=a[0]
          objname=a[1]
          tr=a[2]
          mat=a[3]
          next if not face or not mat
          mesh=face.mesh(5)###7=backs too
		  next if not mesh
          vs=[]
		  nos=[]
		  uvs=[]
		  meshes=[]
          f_uvs=(1..mesh.count_points).map{|i|mesh.uv_at(i,1)}####1=front
          f_vs=[]
          f_vs=(1..mesh.count_points).map{|i|mesh.points[i-1]}
          f_nos=[]
          f_nos=(1..mesh.count_points).map{|i|mesh.normal_at(i)}
          f_vcount=1; f_vcount=vs.length + 1 if vs[0]
          meshes.concat(mesh.polygons.map{|p| [p.map{|px|(f_vs.index(mesh.points[(px.abs-1)]) + f_vcount)}] })
          ###
          vs.concat(f_vs) if f_vs
          #vs.each_with_index{|v,i|@model.entities.add_text(i.to_s, v)}
          uvs.concat(f_uvs) if f_uvs
         if uvs
          i=0; uvs.each{
            next if not uvs[i]
            j=i
            while j > 3
              j=j-4
            end
            uvs[i].z=1
            if j==0
              uvs[i].x= 1
              uvs[i].y= 1
            elsif j==1
              uvs[i].x= 0
              uvs[i].y= 0
            elsif j==2
              uvs[i].x= 1
              uvs[i].y= 0
            else
              uvs[i].x= 0
              uvs[i].y= 1
            end#if
            i+=1
          } if (vs[0].z >= vs[1].z and vs[0].z >= vs[2].z) or (vs[0].z <= vs[1].z and vs[0].z <= vs[2].z)
          i=0; uvs.each{
            next if not uvs[i]
            j=i
            while j > 3
              j=j-4
            end
            uvs[i].z=1
            if j==0
              uvs[i].x= 0
              uvs[i].y= 1
            elsif j==1
              uvs[i].x= 1
              uvs[i].y= 0
            elsif j==2
              uvs[i].x= 1
              uvs[i].y= 1
            else
              uvs[i].x= 0
              uvs[i].y= 0
            end#if
            i+=1
          } if (vs[0].z >= vs[1].z and vs[0].z <= vs[2].z)
          i=0; uvs.each{
            next if not uvs[i]
            j=i
            while j > 3
              j=j-4
            end
            uvs[i].z=1
            if j==0
              uvs[i].x= 1
              uvs[i].y= 0
            elsif j==1
              uvs[i].x= 0
              uvs[i].y= 1
            elsif j==2
              uvs[i].x= 0
              uvs[i].y= 0
            else
              uvs[i].x= 1
              uvs[i].y= 1
            end#if
            i+=1
          } if (vs[0].z <= vs[1].z and vs[0].z >= vs[2].z)
         end#if
          nos.concat(f_nos) if f_nos
          @vs=vs
		  @nos=nos
          @uvs=uvs
          @meshes=meshes
          dmatname = self.export_distorted_obj(objname, tr, mat)
          @dmats << [face, mat, dmatname]
        }#end distorted.each
        @distorted=[]
    end#process_distorted

	def export_obj_file(objname="", tr=nil, mat=nil)
		ot=Geom::Transformation.new
		ot=tr if tr
        if mat
		  mat_name="";(@mats+@imgs).each{|ar|(mat_name=ar[1];break) if ar[0]==mat}
        else
          mat_name="Default_Material"
		end
		return if not @meshes
		objname=objname.gsub(/ /, '_').gsub(/[^_0-9A-Za-z]/, '')
		if @meshes.length != 0 and @vs.length != 0
            ###
			@obj_file.puts "g #{objname}-#{mat_name}"
		    @obj_file.puts "usemtl #{mat_name}"
            ###
		    @v_counter=0 if not @v_counter
			@vs.each{|v|
				v=ot * v
				@obj_file.puts "v #{"%.6f" % v.x.to_m.to_f} #{"%.6f" % v.z.to_m.to_f} #{"%.6f" % (-v.y.to_m.to_f)}"
			}
			@nos.each{|vnor|
				nor=ot * vnor
				nor.normalize!
				@obj_file.puts "vn #{"%.6f" % (nor.x)} #{"%.6f" % (nor.z)} #{"%.6f" % (-nor.y)}"
			}
			@uvs.each{|uv|
				@obj_file.puts "vt #{"%.6f" % (uv.x)} #{"%.6f" % (uv.y)}"
			}
			@meshes.each{|mesh|
				f_str="f"
				mesh.each do |pg|
					pg.each{|j|
						k=j+@v_counter
						f_str += " #{k}/#{k}/#{k}"
					}
					@obj_file.puts f_str
				end
			}
			@obj_file.puts ""
			@v_counter += @vs.length if @vs[0]
		end
		@meshes=nil
		@uvs=nil
		@nos=nil
		@vs=nil
	end
    
    def export_distorted_obj(objname="", tr=nil, mat=nil)
        @msg<<'.'
        Sketchup.set_status_text(@msg)
		ot=Geom::Transformation.new
		ot=tr if tr 
        if mat
			mat_name=mat.display_name.gsub(/ /, '_').gsub(/[^_0-9A-Za-z]/, '')
            saved_name=File.basename(mat_name)
			saved_name_uniq=self.make_name_unique(@saved_names, saved_name)
			@saved_names << saved_name_uniq
            matname=saved_name_uniq # we always uniquify distorts
        else
            matname="Default_Material" ### should never happen !
		end
		return if not @meshes
		objname=objname.gsub(/ /, '_').gsub(/[^_0-9A-Za-z]/, '')
		if @vs.length != 0
            ###
			@obj_file.puts "g #{objname}-#{matname}"
			@obj_file.puts "usemtl #{matname}"
			###
		    @v_counter=0 if not @v_counter
			@vs.each{|v|
				v=ot * v
				@obj_file.puts "v #{"%.6f" % v.x.to_m.to_f} #{"%.6f" % v.z.to_m.to_f} #{"%.6f" % (-v.y.to_m.to_f)}"
			}
			@nos.each{|vnor|
				nor=ot * vnor
				nor.normalize!
				@obj_file.puts "vn #{"%.6f" % (nor.x)} #{"%.6f" % (nor.z)} #{"%.6f" % (-nor.y)}"
			}
			@uvs.each{|uv|
				@obj_file.puts "vt #{"%.6f" % (uv.x)} #{"%.6f" % (uv.y)}"
			}
			@meshes.each{|mesh|
				f_str="f"
				mesh.each do |pg|
					pg.each{|j|
						k=j+@v_counter
						f_str += " #{k}/#{k}/#{k}"
					}
					@obj_file.puts f_str
				end
			}
			@obj_file.puts ""
			@v_counter += @vs.length if @vs[0]
		end
		@meshes=nil
		@uvs=nil
		@nos=nil
		@vs=nil
        return matname
	end
    
	def make_texture_folder()
        begin
          Dir.mkdir(@textures_path) if not File.exist?(@textures_path)
        rescue
          UI.messagebox(@textures_path+" ??")
        end
	end
    
	def export_textures()
		self.make_texture_folder()
		temp_group=@model.active_entities.add_group()
        tw=Sketchup.create_texture_writer
        @all_mats.each{|mat|
            next if not mat
			if mat.texture
                ### don't export unused & invisible materials for speed
                next if not @used_materials.include?(mat)
                @msg<<'.'
                Sketchup.set_status_text(@msg)
				temp_group.material=mat
                mat_texture_file=mat.texture.filename.tr("\\", "/")
                if @png
                  mat_texture_extn='.PNG'
                else
                  mat_texture_extn=File.extname(mat_texture_file)
                end#if
                mat_name="";(@mats+@imgs).each{|ar|(mat_name=ar[1];break) if ar[0]==mat}
                mat_texture_name=mat_name+mat_texture_extn
                tpath=File.join(@textures_path, mat_texture_name)
                tw.load(temp_group)
                tw.write(temp_group, tpath)
                ###
			end#if
		}#end.each
		temp_group.erase! if temp_group.valid?
	end

	def export_mtl_material()
        @msg<<'.'
        Sketchup.set_status_text(@msg)
        ffcol=@model.rendering_options["FaceFrontColor"]
		mtl_file=File.new(@mtl_file,"w")
        mtl_file.puts "# Alias Wavefront MTL File Exported from SketchUp"
        mtl_file.puts "# with OBJexporter (c) 2010-2011 TIG"
        mtl_file.puts "# Made for '"+@obj_name+"'"
        mtl_file.puts ""
		mtl_file.puts "newmtl Default_Material"
		mtl_file.puts "Ka 0.000000 0.000000 0.000000"
		mtl_file.puts "Kd " + ffcol.to_a[0..2].collect{|c| "%.6f" % ((c.to_f/255)) }.join(" ")
		mtl_file.puts "Ks 0.000000 0.000000 0.000000"
        mtl_file.puts "d 1.000000"
		mtl_file.puts ""
        saved_names=[]
		@used_materials.uniq!
		@used_materials.each{|mat|
			next if not mat
            @msg<<'.'
            Sketchup.set_status_text(@msg)
            matname="";(@mats+@imgs).each{|ar|(matname=ar[1];break) if ar[0]==mat}
			if mat and mat.texture
                if @png
                  texture_extn='.PNG'
                else
                  texture_extn=File.extname(mat.texture.filename)
                end#if
				texture_path=File.join(@textures_name, matname + texture_extn)
			end
			mtl_file.puts "newmtl #{matname}"
			if not mat.use_alpha?
				mtl_file.puts "Ka 0.000000 0.000000 0.000000"
				mtl_file.puts "Kd " + mat.color.to_a[0..2].collect{|c| "%.6f" % ((c.to_f/255)) }.join(" ")
				mtl_file.puts "Ks 0.000000 0.000000 0.000000"
				mtl_file.puts "d 1.000000"
				mtl_file.puts "map_Kd #{texture_path}" if texture_path
			else ### it's transparent
				mtl_file.puts "Ka 0.000000 0.000000 0.000000"
				mtl_file.puts "Kd " + mat.color.to_a[0..2].collect{|c| "%.6f" % ((c.to_f/255)) }.join(" ")
				mtl_file.puts "Ks 0.000000 0.000000 0.000000"
				mtl_file.puts "d #{"%.6f" % mat.alpha }"### it's NOT (1 - mat.alpha) !!!
				mtl_file.puts "map_Kd #{texture_path}" if texture_path
			end#if
            mtl_file.puts ""
		}
        ### do any distorts
        self.distorted_mtl(mtl_file)
        ###
		mtl_file.puts "#EOF"
        ###
		mtl_file.flush
		mtl_file.close
	end
    
    def distorted_mtl(mtl_file)
        return nil if not @dmats[0]
        ###
        mtl_file.puts "#Distorted-Textures\n"
        ###
        @dmats.each{|ar|
            @msg<<'.'
            Sketchup.set_status_text(@msg)
            face=ar[0]
            mat=ar[1]
            matname=ar[2]
			if mat and mat.texture
                if @png
                  texture_extn='.PNG'
                else
                  texture_extn=File.extname(mat.texture.filename)
                end#if
				texture_path=File.join(@textures_name, matname + texture_extn)
			end
			mtl_file.puts "newmtl #{matname}"
			if not mat.use_alpha?
				mtl_file.puts "Ka 0.000000 0.000000 0.000000"
				mtl_file.puts "Kd " + mat.color.to_a[0..2].collect{|c| "%.6f" % ((c.to_f/255)) }.join(" ")
				mtl_file.puts "Ks 0.000000 0.000000 0.000000"
				mtl_file.puts "d 1.000000"
				mtl_file.puts "map_Kd #{texture_path}" if texture_path
			else ### it's transparent
				mtl_file.puts "Ka 0.000000 0.000000 0.000000"
				mtl_file.puts "Kd " + mat.color.to_a[0..2].collect{|c| "%.6f" % ((c.to_f/255)) }.join(" ")
				mtl_file.puts "Ks 0.000000 0.000000 0.000000"
				mtl_file.puts "d #{"%.6f" % mat.alpha }"### it's NOT (1 - mat.alpha) !!!
				mtl_file.puts "map_Kd #{texture_path}" if texture_path
			end#if
            mtl_file.puts ""
            ###
            self.export_distorted_texture(face, texture_path)
            ###
        }
    end#distorted_mtl
    
    def export_distorted_texture(face, texture_path)
        tpath=File.join(@project_path, texture_path)
        tw=Sketchup.create_texture_writer
        tw.load(face, true)
        tw.write(face, true, tpath)
    end#export_distorted_texture
    
	def make_name_unique(saved_names=[], saved_name="")
		if saved_names.include?(saved_name)
			counter=1
			while counter < 10000
				new_name=File.basename(saved_name, ".*") + counter.to_s + File.extname(saved_name)
				return new_name if not saved_names.include?(new_name)
				counter+=1
			end
		end
		return saved_name
	end
############## end of exporter code #########################

end#class OBJexporter ##########################################################
###

### make shortcut to tool #################################################
def objexporter()
  Sketchup.active_model.select_tool(OBJexporter.new())
end#def octane
###


### add menu item etc #####################################################
if not file_loaded?(File.basename(__FILE__))
  UI.menu("File").add_item("OBJexporter..."){OBJexporter.new()}
end#if
file_loaded(File.basename(__FILE__))
###