# Sketchup Ogre Exporter Version 1.3.1
# Written by Kojack
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
# 
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA, or go to
# http://www.gnu.org/copyleft/lesser.txt.

# 1.3.1 - 110605 - Bastien Bourineau
# - Update from the last version from Kojack
# - Added dialog box for file destination
# - Added simple scene format for the exported mesh
# - change material alpha detection

# 1.3.2 - 110607 - Bastien Bourineau
# - Manage multi mesh export
# - merge components enabled

# 1.3.3 - 110609 - Bastien Bourineau
# - Rewrite materials and textures export
# - correction on quaternion taking the node scale in count

# 1.3.4 - 110923 - Bastien Bourineau
# - Ignore hidden layers
# - correction on group prs

module OgreExport
class NodeInfo
	attr_reader :father, :name, :globalTrans, :trans, :mats, :sons
	attr_writer :father, :name, :globalTrans, :trans, :mats, :sons
	
	def initialize(f, n, t)
	  @father = f
		@name = n
	  @globalTrans = if f then t * f.trans else t end
		@trans = t
		@mats = {}
		@sons = []
	end
end

    @@tw = nil
    @@countTriangles = 0
    @@countVertices = 0
    @@countMaterials = 0
    @@countTextures = 0
    @@countNodes = 0
    @@materialList = {}
    @@exportedMesh = {}
    @@nodes = nil
    @@textures = []
    @@optionsDialog = nil
    @@tempFace = nil
    
    module_function
    
    def extract_filename(s)
        i = s.rindex(/[:\/\\]/)
        if i
            s.slice(i+1..-1)
        else
            s
        end  
    end

    def remove_badchar(s)
        s = s.tr('(', '_')
        s = s.tr(')', '_')
        s = s.tr('*', '')
        s = s.tr('{', '_')
        s = s.tr('}', '_')
        s = s.tr('[', '_')
        s = s.tr(']', '_')
        s = s.tr('=', '')
        s = s.tr('?', '')
        s = s.tr('&', '')
        s = s.tr(':', '')
        s = s.tr('<', '_')
        s = s.tr(',', '_')
        s = s.tr('>', '_')
        s = s.tr('^', '_')
        s = s.tr('%', '_')
        s = s.tr('"', '_')
        s = s.tr('#', '_')
        s = s.tr(' ', '_')
        s = s.tr('/', '_')
        s = s.tr('\\', '_')
    end

    def append_paths(p,f)
        if p[-1,1] == "\\" or p[-1,1] == "/"
            p.gsub(/[\\]/, '/')+f
        else
            p.gsub(/[\\]/, '/')+"/"+f
        end
    end
    
    def quaterionFromMatrix(trans)
      matrix = trans.to_a
      
      # Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
      # article "Quaternion Calculus and Fast Animation".
      cquat = [1, 0, 0, 0]
      
      scalex=Math.sqrt(matrix[0]**2+matrix[1]**2+matrix[2]**2)
      scaley=Math.sqrt(matrix[4]**2+matrix[5]**2+matrix[6]**2)
      scalez=Math.sqrt(matrix[8]**2+matrix[9]**2+matrix[10]**2)

      #look at the scale sign
      scalex = if trans.zaxis.cross(trans.yaxis).dot(trans.xaxis) > 0 then -scalex else scalex end
      scaley = if trans.xaxis.cross(trans.zaxis).dot(trans.yaxis) > 0 then -scaley else scaley end
      scalez = if trans.yaxis.cross(trans.xaxis).dot(trans.zaxis) > 0 then -scalez else scalez end

      kRot = [[matrix[0]/scalex, matrix[4]/scaley, matrix[8]/scalez], [matrix[1]/scalex, matrix[5]/scaley, matrix[9]/scalez], [matrix[2]/scalex, matrix[6]/scaley, matrix[10]/scalez]]
      fTrace = kRot[0][0]+kRot[1][1]+kRot[2][2]
      fRoot = nil

      if ( fTrace > 0.0 )
          # |w| > 1/2, may as well choose w > 1/2
          fRoot = Math.sqrt(fTrace + 1.0)
          cquat[0] = 0.5*fRoot
          fRoot = 0.5/fRoot
          cquat[1] = (kRot[2][1]-kRot[1][2])*fRoot
          cquat[2] = (kRot[0][2]-kRot[2][0])*fRoot
          cquat[3] = (kRot[1][0]-kRot[0][1])*fRoot
      else
          # |w| <= 1/2
          s_iNext = [1, 2, 0]
          i = 0
          if ( kRot[1][1] > kRot[0][0] )
              i = 1
          end
          if ( kRot[2][2] > kRot[i][i] )
              i = 2
          end
          j = s_iNext[i]
          k = s_iNext[j]

          fRoot = Math.sqrt(kRot[i][i]-kRot[j][j]-kRot[k][k] + 1.0)
          cquat[i+1] = 0.5*fRoot
          fRoot = 0.5/fRoot
          cquat[0] = (kRot[k][j]-kRot[j][k])*fRoot
          cquat[j+1] = (kRot[j][i]+kRot[i][j])*fRoot
          cquat[k+1] = (kRot[k][i]+kRot[i][k])*fRoot
      end

      #cquat[1] = if trans.zaxis.cross(trans.yaxis).dot(trans.xaxis) > 0 then -cquat[1] else cquat[1] end
      #cquat[2] = if trans.xaxis.cross(trans.zaxis).dot(trans.yaxis) > 0 then -cquat[2] else cquat[2] end
      #cquat[3] = if trans.yaxis.cross(trans.xaxis).dot(trans.zaxis) > 0 then -cquat[3] else cquat[3] end

      return [cquat[0], cquat[1], cquat[3], -cquat[2]]
    end
    
    def exportDialog()
        load "ogre/ogre_config.rb"

      	#
      	# Ask export path
      	#
        OgreConfig::Paths.project = UI.savepanel "Save Scene File", "", "myscene.scene"
      	if OgreConfig::Paths.project.empty?
      		return
      	end
      	
      	OgreConfig.name = File.basename(OgreConfig::Paths.project, ".scene")
        OgreConfig::Paths.project = File.dirname(OgreConfig::Paths.project) + File::Separator
        OgreConfig::Paths.scene = OgreConfig.name + ".scene"
        
        if @@optionsDialog == nil
            @@optionsDialog = UI::WebDialog.new("Ogre Exporter Settings", true, "OgreSketchupExport", 740, 660, 150, 150, true);
            @@optionsDialog.set_file(Sketchup.find_support_file("ogre_export.htm","plugins/ogre"),nil)
        end
        @@optionsDialog.show_modal {
#            @@optionsDialog.execute_script("setExportOptionSelect(\"SelectStyle\",#{OgreConfig.SelectStyle.inspect})")
            @@optionsDialog.execute_script("setExportOption(\"FileProject\",#{OgreConfig::Paths.project.inspect})") 
            @@optionsDialog.execute_script("setExportOption(\"FileScene\",#{OgreConfig::Paths.scene.inspect})") 
            @@optionsDialog.execute_script("setExportOption(\"FileMaterial\",#{OgreConfig::Paths.materials.inspect})") 
            @@optionsDialog.execute_script("setExportOption(\"FileMesh\",#{OgreConfig::Paths.meshes.inspect})") 
            @@optionsDialog.execute_script("setExportOption(\"FileTexture\",#{OgreConfig::Paths.textures.inspect})") 
            @@optionsDialog.execute_script("setExportOption(\"FileXMLConverter\",#{OgreConfig::Paths.converter.inspect})")
            @@optionsDialog.execute_script("setExportOption(\"ExportName\",#{OgreConfig.name.inspect})")
            @@optionsDialog.execute_script("setExportOption(\"TextScale\",\"#{OgreConfig.scale}\")")
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxScene\",#{OgreConfig.exportScene})") 
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxMaterial\",#{OgreConfig.exportMaterials})") 
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxMesh\",#{OgreConfig.exportMeshes})") 
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxTexture\",#{OgreConfig.copyTextures})") 
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxXMLConverter\",#{OgreConfig.convertXML})")
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxDefaultMaterials\",#{OgreConfig.exportDefaultMaterials})")
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxBackFace\",#{OgreConfig.exportBackFaces})")
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxFrontFace\",#{OgreConfig.exportFrontFaces})")
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxRoot\",#{OgreConfig.exportRootFaces})")
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxMergeComponents\",#{OgreConfig.mergeComponents})")
            @@optionsDialog.execute_script("setExportOptionCheckbox(\"CheckboxSelectionOnly\",#{OgreConfig.selectionOnly})")
            @@optionsDialog.add_action_callback("on_export") {|d,p| grabDialogData; saveConfig; export; d.close} 
            @@optionsDialog.add_action_callback("on_cancel") {|d,p| d.close} 
        }
    end

    def getDialogCheckbox(checkbox)
        @@optionsDialog.execute_script("getExportOptionCheckbox(\"#{checkbox}\")")
        if @@optionsDialog.get_element_value("HiddenInput") == "true"
            true
        else
            false
        end
    end

    def getDialogSelect(select)
        @@optionsDialog.execute_script("getExportOptionSelect(\"#{select}\")")
        @@optionsDialog.get_element_value("HiddenInput")
    end

    def grabDialogData()
        if @@optionsDialog.visible?
            OgreConfig::Paths.project = @@optionsDialog.get_element_value("FileProject")
            OgreConfig::Paths.scene = @@optionsDialog.get_element_value("FileScene")
            OgreConfig::Paths.materials = @@optionsDialog.get_element_value("FileMaterial")
            OgreConfig::Paths.meshes = @@optionsDialog.get_element_value("FileMesh")
            OgreConfig::Paths.textures = @@optionsDialog.get_element_value("FileTexture")
            OgreConfig::Paths.converter = @@optionsDialog.get_element_value("FileXMLConverter")
            OgreConfig.exportScene = getDialogCheckbox("CheckboxScene")
            OgreConfig.exportMaterials = getDialogCheckbox("CheckboxMaterial")
            OgreConfig.exportMeshes = getDialogCheckbox("CheckboxMesh")
            OgreConfig.copyTextures = getDialogCheckbox("CheckboxTexture")
            OgreConfig.exportBackFaces = getDialogCheckbox("CheckboxBackFace")
            OgreConfig.exportFrontFaces = getDialogCheckbox("CheckboxFrontFace")
            OgreConfig.exportRootFaces = getDialogCheckbox("CheckboxRoot")
            OgreConfig.mergeComponents = getDialogCheckbox("CheckboxMergeComponents")
            OgreConfig.convertXML = getDialogCheckbox("CheckboxXMLConverter")
            OgreConfig.selectionOnly = getDialogCheckbox("CheckboxSelectionOnly")
            OgreConfig.exportDefaultMaterials = getDialogCheckbox("CheckboxDefaultMaterials")
            OgreConfig.name = @@optionsDialog.get_element_value("ExportName")
#            OgreConfig.SelectStyle = getDialogSelect("SelectStyle")
            OgreConfig.scale = @@optionsDialog.get_element_value("TextScale").to_f
        end
    end

    def saveConfig()
        out = open(Sketchup.find_support_file("plugins/ogre")+"/ogre_config.rb", "w")
        out.print "module OgreConfig\n"
        out.print "  @@scale = #{OgreConfig.scale}\n"
        out.print "  @@copyTextures = #{OgreConfig.copyTextures}\n"
        out.print "  @@exportMeshes = #{OgreConfig.exportMeshes}\n"
        out.print "  @@exportScene = #{OgreConfig.exportScene}\n"
        out.print "  @@exportMaterials = #{OgreConfig.exportMaterials}\n"
        out.print "  @@exportDefaultMaterials = #{OgreConfig.exportDefaultMaterials}\n"
        out.print "  @@exportStyle = #{OgreConfig.exportStyle}\n"
        out.print "  @@exportBackFaces = #{OgreConfig.exportBackFaces}\n"
        out.print "  @@exportFrontFaces = #{OgreConfig.exportFrontFaces}\n"
        out.print "  @@convertXML = #{OgreConfig.convertXML}\n"
        out.print "  @@exportRootFaces = #{OgreConfig.exportRootFaces}\n"
        out.print "  @@mergeComponents = #{OgreConfig.mergeComponents}\n"
        out.print "  @@name = #{OgreConfig.name.inspect}\n"
#        out.print "  @@SelectStyle = #{OgreConfig.SelectStyle.inspect}\n"
        out.print "  @@selectionOnly = #{OgreConfig.selectionOnly}\n"
        out.print "  def self.scale; @@scale; end\n"
        out.print "  def self.copyTextures; @@copyTextures; end\n"
        out.print "  def self.exportMeshes; @@exportMeshes; end\n"
        out.print "  def self.exportScene; @@exportScene; end\n"
        out.print "  def self.exportMaterials; @@exportMaterials; end\n"
        out.print "  def self.exportDefaultMaterials; @@exportDefaultMaterials; end\n"
        out.print "  def self.exportStyle; @@exportStyle; end\n"
        out.print "  def self.exportBackFaces; @@exportBackFaces; end\n"
        out.print "  def self.exportFrontFaces; @@exportFrontFaces; end\n"
        out.print "  def self.exportRootFaces; @@exportRootFaces; end\n"
        out.print "  def self.mergeComponents; @@mergeComponents; end\n"
        out.print "  def self.convertXML; @@convertXML; end\n"
        out.print "  def self.selectionOnly; @@selectionOnly; end\n"
        out.print "  def self.name; @@name; end\n"
#        out.print "  def self.SelectStyle; @@SelectStyle; end\n"
        out.print "  def self.scale=(v); @@scale=v; end\n"
        out.print "  def self.copyTextures=(v); @@copyTextures=v; end\n"
        out.print "  def self.exportMeshes=(v); @@exportMeshes=v; end\n"
        out.print "  def self.exportScene=(v); @@exportScene=v; end\n"
        out.print "  def self.exportMaterials=(v); @@exportMaterials=v; end\n"
        out.print "  def self.exportDefaultMaterials=(v); @@exportDefaultMaterials=v; end\n"
        out.print "  def self.exportStyle=(v); @@exportStyle=v; end\n"
        out.print "  def self.exportBackFaces=(v); @@exportBackFaces=v; end\n"
        out.print "  def self.exportFrontFaces=(v); @@exportFrontFaces=v; end\n"
        out.print "  def self.exportRootFaces=(v); @@exportRootFaces=v; end\n"
        out.print "  def self.mergeComponents=(v); @@mergeComponents=v; end\n"
        out.print "  def self.convertXML=(v); @@convertXML=v; end\n"
        out.print "  def self.selectionOnly=(v); @@selectionOnly=v; end\n"
        out.print "  def self.name=(v); @@name=v; end\n"
        out.print "  module Paths\n"
        out.print "    @@project = #{OgreConfig::Paths.project.inspect}\n"
        out.print "    @@scene = #{OgreConfig::Paths.scene.inspect}\n"
        out.print "    @@meshes = #{OgreConfig::Paths.meshes.inspect}\n"
        out.print "    @@materials = #{OgreConfig::Paths.materials.inspect}\n"
        out.print "    @@textures = #{OgreConfig::Paths.textures.inspect}\n"
        out.print "    @@converter = #{OgreConfig::Paths.converter.inspect}\n"
        out.print "    def self.project; @@project; end\n"
        out.print "    def self.scene; @@scene; end\n"
        out.print "    def self.meshes; @@meshes; end\n"
        out.print "    def self.materials; @@materials; end\n"
        out.print "    def self.textures; @@textures; end\n"
        out.print "    def self.converter; @@converter; end\n"
        out.print "    def self.project=(v); @@project=v; end\n"
        out.print "    def self.scene=(v); @@scene=v; end\n"
        out.print "    def self.meshes=(v); @@meshes=v; end\n"
        out.print "    def self.materials=(v); @@materials=v; end\n"
        out.print "    def self.textures=(v); @@textures=v; end\n"
        out.print "    def self.converter=(v); @@converter=v; end\n"
        out.print "  end\n"
        out.print "end\n"
        out.close
    end
    
    
    def collectData(node, matlist, ents, trans, inherited_mat, root)
        for e in ents
            case e
              when Sketchup::Face
                if (not root) or OgreConfig.exportRootFaces and e.layer.visible? and e.visible?
                    if OgreConfig.exportFrontFaces
                        inheritmat = false
                        if e.material
                            mat = e.material
                            if !matlist[mat]
                                handle = @@tw.load(e, true)
                            end
                        else
                            if inherited_mat
                                mat = inherited_mat[0]
                                inheritmat = true
                                if !matlist[mat]
                                    handle = @@tw.load(inherited_mat[1], true)
                                end
                            else
                                mat = nil
                                handle = 0
                            end
                        end
                        
                        #create the subentity
                        if !node.mats[mat]
                          node.mats[mat] = []
                        end

                        if !matlist[mat]
                          matlist[mat] = [if inheritmat then 1 else 0 end, if inheritmat then inherited_mat[1] else e end, true]
                        end
                        
                        #add face on the subentity
                        node.mats[mat].push([e, if OgreConfig.mergeComponents then trans else Geom::Transformation.new end, true])
                    end
                    if OgreConfig.exportBackFaces
                        inheritmat = false
                        if e.back_material
                            mat = e.back_material
                            if !matlist[mat]
                                handle = @@tw.load(e, false)
                            end
                        else
                            if inherited_mat
                                mat = inherited_mat[0]
                                inheritmat = true
                                if !matlist[mat]
                                    handle = @@tw.load(inherited_mat[1],false)
                                end
                            else
                                mat = nil
                                handle = 0
                            end
                        end
                        
                        #create the subentity
                        if !node.mats[mat]
                          node.mats[mat] = []
                        end
                        
                        if !matlist[mat]
                          matlist[mat] = [if inheritmat then 1 else 0 end, if inheritmat then inherited_mat[1] else e end, false]
                        end
                        
                        #add face on the subentity             
                        node.mats[mat].push([e, if OgreConfig.mergeComponents then trans else Geom::Transformation.new end, false])
                    end
                end
            when Sketchup::Group
                if e.layer.visible? and e.visible?
                    @@countNodes = @@countNodes + 1
                    nname = if e.name.empty? then "Group_#{@@countNodes}" else e.name + "_#{@@countNodes}" end
                    nnode = node.sons[node.sons.length] = NodeInfo.new(node, nname, trans*e.transformation)
                    collectData(nnode, matlist, e.entities, Geom::Transformation.new, if e.material then [e.material,e,e.transformation] else inherited_mat end, root)
                #else
                #    collectData(node, matlist, e.entities, trans*e.transformation, if e.material then [e.material,e,e.transformation] else inherited_mat end, root)
                end
            when Sketchup::Model
                if e.layer.visible? and e.visible?
                    @@countNodes = @@countNodes + 1
                    #load model materials
                    for nm in e.materials
                        @@tempface.material = nm
                        if !matlist[nm]
                            matlist[nm] = [[@@tw.load(@@tempface,true),[]]]
                        end
                    end
                    
                    nname = if e.name.empty? then "Model_#{@@countNodes}" else e.name + "_#{@@countNodes}" end
                    nnode = node.sons[node.sons.length] = NodeInfo.new(node, nname, trans*e.transformation)
                    collectData(nnode, matlist, e.entities, Geom::Transformation.new, if e.material then [e.material,e,e.transformation] else inherited_mat end, root)
                #else
                #    collectData(node, matlist, e.entities, trans*e.transformation, if e.material then [e.material,e,e.transformation] else inherited_mat end, root)
                end
              
            when Sketchup::ComponentInstance
                if e.layer.visible? and e.visible?
                    if !OgreConfig.mergeComponents
                        @@countNodes = @@countNodes + 1
                        nname = if e.name.empty? then "Component_#{@@countNodes}" else e.name + "_#{@@countNodes}" end
                        # priority for intantiated meshs
                        nname = if e.definition.name.empty? then nname else e.definition.name end
                        nnode = node.sons[node.sons.length] = NodeInfo.new(node, nname, trans*e.transformation)
                        collectData(nnode, matlist, e.definition.entities, Geom::Transformation.new, if e.material then [e.material,e,e.transformation] else inherited_mat end, false)
                    else
                        nnode = node
                        collectData(nnode, matlist, e.definition.entities, trans*e.transformation, if e.material then [e.material,e,e.transformation] else inherited_mat end, false)
                    end
                #else
                #   collectData(node, matlist, e.definition.entities, trans*e.transformation, if e.material then [e.material,e,e.transformation] else inherited_mat end, root)
                end
            end
        end
    end

    def writeMaterials(matlist)
        $materialpath = append_paths(OgreConfig::Paths.project, OgreConfig::Paths.materials)
        $texturepath = append_paths(OgreConfig::Paths.project, OgreConfig::Paths.textures)
        Dir::mkdir($materialpath) unless FileTest::directory?($materialpath)
        if OgreConfig.copyTextures
          Dir::mkdir($texturepath) unless FileTest::directory?($texturepath)
        end
        
        file_material = open(append_paths($materialpath, OgreConfig.name+".material"),"w")
        for m,handle in matlist
            if m
                @@countMaterials = @@countMaterials + 1
                mat_name = remove_badchar(m.display_name)
                file_material.print "material #{mat_name}\n"
                file_material.print "{\n"
                file_material.print "   technique\n"
                file_material.print "   {\n"
                file_material.print "      pass\n"
                file_material.print "      {\n"
                # enable alpha only on png files since other tga or tiff format are most used without alpha
                # this limit the case of textures without alpha but with use_alpha enabled be sketchup
                textureext = ""
                if m.texture
                  textureext = File.extname(File.basename(m.texture.filename))
                end
                if (m.use_alpha? && (textureext == ".png") || (textureext == ".PNG")) || m.alpha < 1.0
                    file_material.print "         scene_blend alpha_blend\n"
                    file_material.print "         depth_check on\n"
                    file_material.print "         depth_write off\n"
                end
                if m.texture
                    #if extract_filename(m.texture.filename).index(/[ ]/)
                        #puts "Bad texture name: #{extract_filename(m.texture.filename)}"
                    #end
                    filename = remove_badchar(File.basename(m.texture.filename))
                    file_material.print "         diffuse 1 1 1 #{m.alpha}\n"
                    file_material.print "         texture_unit\n"
                    file_material.print "         {\n"
                    file_material.print "            texture #{filename}\n"
                    file_material.print "         }\n"
                    if OgreConfig.copyTextures
                        @@countTextures = @@countTextures + 1
                        if handle[0] == 1
                            t = @@tw.write handle[1], append_paths($texturepath, filename)
                        else
                            t = @@tw.write handle[1], handle[2], append_paths($texturepath, filename)
                        end
                    end
                else
                    file_material.print "         diffuse #{m.color.red/255.0} #{m.color.green/255.0} #{m.color.blue/255.0} #{m.alpha}\n"
                    file_material.print "         ambient #{m.color.red/255.0} #{m.color.green/255.0} #{m.color.blue/255.0} #{m.alpha}\n"
                end
                file_material.print "      }\n"
                file_material.print "   }\n"
                file_material.print "}\n\n"
            end
        end
        if matlist[nil] and OgreConfig.exportDefaultMaterials
            @@countMaterials = @@countMaterials + 2
            file_material.print "material SketchupDefault\n"
            file_material.print "{\n"
            file_material.print "   technique\n"
            file_material.print "   {\n"
            file_material.print "      pass\n"
            file_material.print "      {\n"
            colour = Sketchup.active_model.rendering_options["FaceFrontColor"]
            file_material.print "         diffuse #{colour.red/255.0} #{colour.green/255.0} #{colour.blue/255.0}\n"
            file_material.print "         ambient #{colour.red/255.0} #{colour.green/255.0} #{colour.blue/255.0}\n"
            file_material.print "      }\n"
            file_material.print "   }\n"
            file_material.print "}\n\n"
            file_material.print "material SketchupDefault_Back\n"
            file_material.print "{\n"
            file_material.print "   technique\n"
            file_material.print "   {\n"
            file_material.print "      pass\n"
            file_material.print "      {\n"
            colour = Sketchup.active_model.rendering_options["FaceBackColor"]
            file_material.print "         diffuse #{colour.red/255.0} #{colour.green/255.0} #{colour.blue/255.0}\n"
            file_material.print "         ambient #{colour.red/255.0} #{colour.green/255.0} #{colour.blue/255.0}\n"
            file_material.print "      }\n"
            file_material.print "   }\n"
            file_material.print "}\n"
        end
        file_material.close
    end

    def exportFaces(meshpath, node, exportedmesh)
        if node.mats.size > 0 && exportedmesh[node.name] == nil
          out = open(append_paths(meshpath, remove_badchar(node.name) + ".mesh.xml"), "w")
          out.print "<mesh>\n"
          out.print "   <submeshes>\n"
          for m, m2 in node.mats
              if m2.size > 0
                  if m or OgreConfig.exportDefaultMaterials
                      if m
                          mat_name = remove_badchar(m.display_name)
                          has_texture = m.texture != nil
                      else 
                          mat_name = "SketchupDefault"
                          has_texture = nil
                      end
                      meshes = []
                      tri_count = 0
                      vertex_count = 0
                      for face in m2
                          # 7 flag for all mesh informations
                          mesh = face[0].mesh 7
                          # mesh = mesh2.transform face[1]
                          mirrored = face[1].xaxis.cross(face[1].yaxis).dot(face[1].zaxis) < 0
                          # push mesh mirrored entity frontface
                          meshes.push([mesh,mirrored,face[0],face[1],face[2]])
                          tri_count = tri_count + mesh.count_polygons
                          vertex_count = vertex_count + mesh.count_points
                      end
                      @@countTriangles = @@countTriangles + tri_count
                      @@countVertices = @@countVertices + vertex_count
                      startindex = 0
                      out.print "      <submesh material = \"#{mat_name}\" usesharedvertices=\"false\" "
                      if vertex_count<65537 
                          out.print "use32bitindexes=\"false\">\n"
                      else
                          out.print "use32bitindexes=\"true\">\n"
                      end
                      out.print "         <faces count=\"#{tri_count}\">\n"
                      for mesh in meshes
                          for poly in mesh[0].polygons
                              v1 = (poly[0]>=0?poly[0]:-poly[0])+startindex
                              v2 = (poly[1]>=0?poly[1]:-poly[1])+startindex
                              v3 = (poly[2]>=0?poly[2]:-poly[2])+startindex
                              if mesh[1] == mesh[4]
                                  out.print "            <face v1=\"#{v2-1}\" v2=\"#{v1-1}\" v3=\"#{v3-1}\" />\n"
                              else
                                  out.print "            <face v1=\"#{v1-1}\" v2=\"#{v2-1}\" v3=\"#{v3-1}\" />\n"
                              end
                          end
                          startindex = startindex + mesh[0].count_points
                      end
                      out.print "         </faces>\n"
                      out.print "         <geometry vertexcount=\"#{vertex_count}\">\n"
                      out.print "            <vertexbuffer positions=\"true\" normals=\"true\" colours_diffuse=\"false\" "
                      if has_texture 
                          out.print "texture_coords=\"1\" texture_coord_dimensions_0=\"2\""
                      end
                      out.print " >\n"
    
                      for mesh in meshes
                          matrix = mesh[3]
                          for p in (1..mesh[0].count_points)
                              pos = (matrix*mesh[0].point_at(p)).to_a
                              norm = (matrix*mesh[0].normal_at(p)).to_a
                              out.print "               <vertex>\n"
                              out.print "                  <position x=\"#{pos[0]*OgreConfig.scale}\" y=\"#{pos[2]*OgreConfig.scale}\" z=\"#{pos[1]*-OgreConfig.scale}\" />\n"
                              if mesh[4]
                                  out.print "                  <normal x=\"#{norm[0]}\" y=\"#{norm[2]}\" z=\"#{-norm[1]}\" />\n"
                              else
                                  out.print "                  <normal x=\"#{-norm[0]}\" y=\"#{-norm[2]}\" z=\"#{norm[1]}\" />\n"
                              end
                              if has_texture
                                  if (mesh[2].material and mesh[4]) or (mesh[2].back_material and not mesh[4])
                                      texsize = Geom::Point3d.new(1, 1, 1)
                                  else
                                      texsize = Geom::Point3d.new(m.texture.width, m.texture.height, 1)
                                  end
                                  uvhelp = mesh[2].get_UVHelper true, true, @@tw
                                  #uv = [mesh[0].uv_at(p,1).x/texsize.x, mesh[0].uv_at(p,1).y/texsize.y, mesh[0].uv_at(p,1).z/texsize.z]
                                  #uv = [m.uv_at(p,1).x*1.0, m.uv_at(p,1).y*1.0, m.uv_at(p,1).z*1.0]
                                  if mesh[4]
                                      uv3d = uvhelp.get_front_UVQ mesh[0].point_at(p)
                                  else
                                      uv3d = uvhelp.get_back_UVQ mesh[0].point_at(p)
                                  end
                                  #uv3d = [mesh[0].uv_at(p,1).x, mesh[0].uv_at(p,1).y, mesh[0].uv_at(p,1).z]
                                  #out.print "                  <texcoord u=\"#{uv[0]}\" v=\"#{-uv[1]+1}\" />\n"
                                  out.print "                  <texcoord u=\"#{uv3d[0]/texsize.x}\" v=\"#{-uv3d[1]/texsize.y+1}\" />\n"
                              end
                                  out.print "               </vertex>\n"
                          end
                      end
                      out.print "            </vertexbuffer>\n"
                      out.print "         </geometry>\n"
                      out.print "      </submesh>\n"
                  end
              end
          end
          out.print "   </submeshes>\n"
          out.print "</mesh>\n"
          out.close
          
          exportedmesh[node.name] = append_paths(meshpath, remove_badchar(node.name)+".mesh.xml").inspect
        end
        for n in node.sons
          if n
            exportFaces(meshpath, n, exportedmesh)
          end
        end
    end
  
    def exportNodes(out, node)
        if node.name == (OgreConfig.name + if OgreConfig.mergeComponents then "" else "_root" end) && !OgreConfig.exportRootFaces && !OgreConfig.mergeComponents
         	for n in node.sons
        	  if n
            	exportNodes(out, n)
            end
          end          
        else
          trans=node.trans.to_a
          
          scalex=Math.sqrt(trans[0]**2+trans[1]**2+trans[2]**2)
          scaley=Math.sqrt(trans[4]**2+trans[5]**2+trans[6]**2)
          scalez=Math.sqrt(trans[8]**2+trans[9]**2+trans[10]**2)

          scalex = if node.trans.yaxis.cross(node.trans.zaxis).dot(node.trans.xaxis) < 0 then -scalex else scalex end
          scaley = if node.trans.xaxis.cross(node.trans.zaxis).dot(node.trans.yaxis) < 0 then scaley else -scaley end
          scalez = if node.trans.xaxis.cross(node.trans.yaxis).dot(node.trans.zaxis) < 0 then -scalez else scalez end

          
          quat = quaterionFromMatrix(node.trans)
          
          out.print "    <node name=\"#{node.name}\">\n"
          out.print "      <position x=\"#{trans[12]*OgreConfig.scale}\" y=\"#{trans[14]*OgreConfig.scale}\" z=\"#{trans[13]*-OgreConfig.scale}\" />\n"
          out.print "      <scale x=\"#{scalex}\" y=\"#{scalez}\" z=\"#{scaley}\" />\n"
          out.print "      <rotation qw=\"#{quat[0]}\" qx=\"#{quat[1]}\" qy=\"#{quat[2]}\" qz=\"#{quat[3]}\" />\n"
          if node.mats.size > 0
            out.print "      <entity name=\"#{node.name}\" castShadows=\"true\" receiveShadows=\"true\" meshFile=\"#{remove_badchar(node.name)}.mesh" + "\">\n"
            out.print "        <subentities>\n"
            subid = 0
            for m, m2 in node.mats
                if m or OgreConfig.exportDefaultMaterials
                    if m2.size > 0
                        if m
                            mat_name = remove_badchar(m.display_name)
                        else 
                            mat_name = "SketchupDefault"
                        end
                        out.print "          <subentity index=\"" + subid.to_s + "\" materialName=\"#{mat_name}\" />\n"
                    end
                    subid = subid + 1
                end
            end
          	out.print "        </subentities>\n"
            out.print "      </entity>\n"
          end
          
         	for n in node.sons
        	  if n
            	exportNodes(out, n)
            end
          end
          out.print "    </node>\n"
        end
    end

    def exportScene(node)
        out = open(append_paths(OgreConfig::Paths.project, OgreConfig::Paths.scene), "w")
      	out.print "<scene formatVersion=\"1.0\">\n"
      	out.print "  <resourceLocations>\n"
        out.print "    <resourceLocation type=\"FileSystem\" name=\"" + OgreConfig::Paths.project + OgreConfig::Paths.meshes + "\" recursive=\"false\" />\n"
        out.print "    <resourceLocation type=\"FileSystem\" name=\"" + OgreConfig::Paths.project + OgreConfig::Paths.textures + "\" recursive=\"false\" />\n"
        out.print "    <resourceLocation type=\"FileSystem\" name=\"" + OgreConfig::Paths.project + OgreConfig::Paths.materials + "\" recursive=\"false\" />\n"
        out.print "  </resourceLocations>\n"
      	out.print "  <nodes>\n"
      	
      	exportNodes(out, node)
      	
        out.print "  </nodes>\n"
        out.print "</scene>\n"
        out.close
    end

    def export()
        @@countTriangles = 0
        @@countVertices = 0
        @@countMaterials = 0
        @@countTextures = 0
        @@countNodes = 0
        @@materialList = {}
        @@exportedMesh = {}
        @@nodes = NodeInfo.new(nil, OgreConfig.name + if OgreConfig.mergeComponents then "" else "_root" end, Geom::Transformation.new)
        @@textures = []
        @@tw = Sketchup.create_texture_writer
        
        if OgreConfig.selectionOnly
            selection = Sketchup.active_model.selection
            if selection.count == 0
                UI.messagebox "Nothing selected"
                @@tw = nil
                @@materialList = nil
                @@textures = nil
                return
            end
        else
            selection = Sketchup.active_model.entities
        end        
        
        puts "Collecting data"        
        collectData(@@nodes, @@materialList, selection, Geom::Transformation.new, nil, true)
        Dir::mkdir(OgreConfig::Paths.project) unless FileTest::directory?(OgreConfig::Paths.project)
        
        if OgreConfig.exportMaterials
            writeMaterials(@@materialList)
        end
        if OgreConfig.exportMeshes
            meshpath = append_paths(OgreConfig::Paths.project, OgreConfig::Paths.meshes)
            Dir::mkdir(meshpath) unless FileTest::directory?(meshpath)

            exportFaces(meshpath, @@nodes, @@exportedMesh)
        end
        if OgreConfig.exportScene
            exportScene(@@nodes)
        end
        
        
        if OgreConfig.convertXML
            #Nor batch (admin rights) or multi command line (cmd && cmd ) works :/
          
            #ecmd = "cls"
            for m,mpath in @@exportedMesh
                if !system("#{OgreConfig::Paths.converter} #{mpath}")
                    puts "OgreXmlConversion failed with : " + mpath + "\n"
                end
                
                #ecmd = ecmd + " && #{OgreConfig::Paths.converter} #{mpath}"
            end
            #ecmd = ecmd + " && pause"
            #puts ecmd.inspect
            #if !system(ecmd)
            #  puts "OgreXmlConversion failed!\n"
            #end
        end
        
        @@tw = nil
        @@materialList = nil
        @@textures = nil
        
        puts "Triangles = #{@@countTriangles}\nVertices = #{@@countVertices}\nNodes = #{@@countNodes}\nMesh files = #{@@exportedMesh.size}\nMaterials = #{@@countMaterials}\nTextures = #{@@countTextures}"
    end
end

menu = UI.menu "Tools";
menu.add_separator
menu.add_item( "Export To Ogre") {OgreExport.exportDialog}
