svn merge -r 12607:12653 https://svn.blender.org/svnroot/bf-blender/trunk/blender...
authorDaniel Genrich <daniel.genrich@gmx.net>
Thu, 22 Nov 2007 20:28:24 +0000 (20:28 +0000)
committerDaniel Genrich <daniel.genrich@gmx.net>
Thu, 22 Nov 2007 20:28:24 +0000 (20:28 +0000)
62 files changed:
CMakeLists.txt
intern/elbeem/CMakeLists.txt
intern/elbeem/extern/elbeem.h
intern/elbeem/intern/attributes.cpp
intern/elbeem/intern/loop_tools.h
intern/elbeem/intern/ntl_vector3dim.h
intern/elbeem/intern/paraloop.h [deleted file]
intern/elbeem/intern/paraloopend.h
intern/elbeem/intern/paraloopstart.h [deleted file]
intern/elbeem/intern/particletracer.cpp
intern/elbeem/intern/simulation_object.cpp
intern/elbeem/intern/solver_class.h
intern/elbeem/intern/solver_init.cpp
intern/elbeem/intern/solver_interface.cpp
intern/elbeem/intern/solver_interface.h
intern/elbeem/intern/solver_main.cpp
intern/elbeem/intern/solver_util.cpp
intern/elbeem/intern/utilities.cpp
intern/elbeem/intern/utilities.h
projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj
release/scripts/bpymodules/BPyMessages.py
release/scripts/flt_export.py
release/scripts/flt_filewalker.py
release/scripts/flt_import.py
release/scripts/import_dxf.py
release/scripts/mesh_skin.py
release/scripts/mesh_wire.py
release/scripts/weightpaint_average.py
source/blender/blenkernel/BKE_lattice.h
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/key.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/object.c
source/blender/blenlib/BLI_fnmatch.h [new file with mode: 0644]
source/blender/blenlib/intern/fnmatch.c [new file with mode: 0644]
source/blender/blenloader/intern/readfile.c
source/blender/include/BSE_sequence.h
source/blender/makesdna/DNA_armature_types.h
source/blender/makesdna/DNA_key_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_sequence_types.h
source/blender/python/api2_2x/Mesh.c
source/blender/python/api2_2x/Window.c
source/blender/python/api2_2x/doc/Curve.py
source/blender/python/api2_2x/doc/Text3d.py
source/blender/python/api2_2x/doc/Texture.py
source/blender/python/api2_2x/doc/Window.py
source/blender/python/api2_2x/sceneSequence.c
source/blender/src/buttons_editing.c
source/blender/src/buttons_shading.c
source/blender/src/drawarmature.c
source/blender/src/drawimage.c
source/blender/src/drawseq.c
source/blender/src/edit.c
source/blender/src/editarmature.c
source/blender/src/editimasel.c
source/blender/src/editseq.c
source/blender/src/filesel.c
source/blender/src/poseobject.c
source/blender/src/sequence.c
source/blender/src/transform_conversions.c
source/gameengine/Converter/BL_SkinDeformer.cpp

index 0227c51f39d17a3ff8fbc28324e14e4af3805016..eabcdde1dde6ab84b8a6b08c361b6cd4f3ba8bcf 100644 (file)
@@ -65,8 +65,9 @@ OPTION(WITH_ELBEEM            "Enable Elbeem (Fluid Simulation)"                      ON)
 OPTION(WITH_QUICKTIME          "Enable Quicktime Support"                              OFF)
 OPTION(WITH_OPENEXR            "Enable OpenEXR Support (http://www.openexr.com)"       OFF)
 OPTION(WITH_FFMPEG             "Enable FFMPeg Support (http://ffmpeg.mplayerhq.hu/)"   OFF)
-OPTION(WITH_OPENAL             "Enable OpenAL Support (http://www.openal.org)" ON)
-OPTION(YESIAMSTUPID            "Enable execution on 64-bit platforms"                                  OFF)
+OPTION(WITH_OPENAL             "Enable OpenAL Support (http://www.openal.org)"         ON)
+OPTION(YESIAMSTUPID            "Enable execution on 64-bit platforms"                  OFF)
+OPTION(WITH_OPENMP             "Enable OpenMP (has to be supported by the compiler)"   OFF)
 
 IF(NOT WITH_GAMEENGINE AND WITH_PLAYER)
   MESSAGE("WARNING: WITH_PLAYER needs WITH_GAMEENGINE")
@@ -186,6 +187,12 @@ IF(UNIX)
 
   SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -DXP_UNIX -Wno-char-subscripts")
 
+  IF(WITH_OPENMP)
+    SET(LLIBS ${LLIBS} gomp)
+    SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-fopenmp")
+    SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fopenmp")
+  ENDIF(WITH_OPENMP)
+
   SET(PLATFORM_LINKFLAGS "-pthread")
 
   INCLUDE_DIRECTORIES(/usr/include /usr/local/include)
@@ -270,6 +277,11 @@ IF(WIN32)
   SET(CMAKE_C_FLAGS_MINSIZEREL "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O1 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE)
   SET(CMAKE_C_FLAGS_RELWITHDEBINFO "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /Zi /J" CACHE STRING "MSVC MT flags " FORCE)
 
+  IF(WITH_OPENMP)
+    SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "/openmp")
+    SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "/openmp")
+  ENDIF(WITH_OPENMP)
+
   SET(SDL ${LIBDIR}/sdl)
   SET(SDL_INC ${SDL}/include)
   SET(SDL_LIB SDL)
@@ -347,6 +359,12 @@ IF(APPLE)
   SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
   SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime")
 
+  IF(WITH_OPENMP)
+    SET(LLIBS ${LLIBS} gomp)
+    SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-fopenmp")
+    SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fopenmp")
+  ENDIF(WITH_OPENMP)
+
   SET(SDL ${LIBDIR}/sdl)
   SET(SDL_INC ${SDL}/include)
   SET(SDL_LIB SDL)
index 86a60180b053225eb81c1625687e8649be07878d..ac35b8ce00f04c2d483afecd6c38f9972eedd731 100644 (file)
@@ -36,5 +36,9 @@ IF(WINDOWS)
     ADD_DEFINITIONS(-DUSE_MSVC6FIXES)
 ENDIF(WINDOWS)
 
+IF(WITH_OPENMP)
+    ADD_DEFINITIONS(-DPARALLEL)
+ENDIF(WITH_OPENMP)
+
 BLENDERLIB_NOLIST(bf_elbeem "${SRC}" "${INC}")
 #, libtype='blender', priority=0 )
index b3feda8bbe8be0dee4385b1112080fdda6875707..2a594dd07e65147fd443513bba72b9207009f0ad 100644 (file)
@@ -154,7 +154,7 @@ typedef struct elbeemMesh {
        short volumeInitType;
 
        /* name of the mesh, mostly for debugging */
-       char *name;
+       const char *name;
 } elbeemMesh;
 
 // API functions
index 8e337a92a4e61648629372332d84d488b4b3e4f2..464486f2500ea1b995de7bfcc940d7838d1fa0ac 100644 (file)
@@ -103,7 +103,7 @@ void AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string sou
 
 // set that a parameter can be given, and will be ignored...
 bool AttributeList::ignoreParameter(string name, string source) {
-       name=source=(""); // remove warning
+       name = source = ("");
        return false;
 }
                
index 3c15a6092103ad1ec2f65a61f720b40d16441264..70ecb9ce3e080cec9fc77b4f042b607d050e6c7e 100644 (file)
 
 
        
-#define unused_GRID_REGION_END() \
-       } /* main_region */  \
-       // end unusedGRID_REGION_END
-
 
 //  -----------------------------------------------------------------------------------
 #else // PARALLEL==1
 
-#include "paraloop.h"
+//#include "paraloop.h"
+#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, calcMaxVlen, calcMxvx,calcMxvy,calcMxvz);
+#define LIST_EMPTY(x)    calcListEmpty.push_back( x );
+#define LIST_FULL(x)     calcListFull.push_back( x );
+#define FSGR_ADDPART(x)  calcListParts.push_back( x );
+
+
+// parallel region
+//was: # pragma omp parallel default(shared) 
+#if COMPRESSGRIDS!=1
+       // requires compressed grids...!
+       ERROR!
+#endif
+
+// loop start
+#define  GRID_REGION_START()  \
+       { \
+        \
+        \
+       if(mSizez<2) { \
+       mPanic = 1; \
+       errFatal("ParaLoop::2D","Not valid...!", SIMWORLD_GENERICERROR); \
+       } \
+        \
+        \
+       vector<LbmPoint> calcListFull; \
+       vector<LbmPoint> calcListEmpty; \
+       vector<ParticleObject> calcListParts; \
+       LbmFloat calcMxvx, calcMxvy, calcMxvz, calcMaxVlen; \
+       calcMxvx = calcMxvy = calcMxvz = calcMaxVlen = 0.0; \
+       calcListEmpty.reserve(mListEmpty.capacity() / omp_get_num_threads() ); \
+       calcListFull.reserve( mListFull.capacity()  / omp_get_num_threads() ); \
+       calcListParts.reserve(mSizex); \
+        \
+        \
+       const int id = omp_get_thread_num(); \
+       const int Nthrds = omp_get_num_threads(); \
+        \
+        \
+        \
+        \
+        \
+       int kdir = 1; \
+        \
+       int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \
+       if(gridLoopBound>0){ kstart=getForZMin1(); kend=getForZMax1(mMaxRefine); } \
+       LbmFloat *ccel = NULL, *tcel = NULL; \
+       CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \
+        \
+        \
+       if(mLevel[mMaxRefine].setCurr==1) { \
+       kdir = -1; \
+       int temp = kend; \
+       kend = kstart-1; \
+       kstart = temp-1; \
+       } \
+        \
+       const int Nj = mLevel[mMaxRefine].lSizey; \
+       int jstart = 0+( id * (Nj / Nthrds) ); \
+       int jend   = 0+( (id+1) * (Nj / Nthrds) ); \
+       if( ((Nj/Nthrds) *Nthrds) != Nj) { \
+       errMsg("LbmFsgrSolver","Invalid domain size Nj="<<Nj<<" Nthrds="<<Nthrds); \
+       } \
+        \
+       if(jstart<gridLoopBound) jstart = gridLoopBound; \
+       if(jend>mLevel[mMaxRefine].lSizey-gridLoopBound) jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \
+        \
+       debMsgStd("ParaLoop::OMP",DM_MSG,"Thread:"<<id<<" i:"<<istart<<"-"<<iend<<" j:"<<jstart<<"-"<<jend<<", k:"<<kstart<<"-"<<kend<<"  ", 1); \
+        \
+
+
+
+
+// para GRID LOOP END is parainc3 
 
 #endif // PARALLEL==1
 
 
 
 
+
 // old loop for COMPRESSGRIDS==0
 #define old__GRID_LOOP_START() \
   for(int k=kstart;k<kend;++k) { \
          for(int j=1;j<mLevel[lev].lSizey-1;++j) { \
                for(int i=0;i<mLevel[lev].lSizex-2;   ) {
 
+
index 912a37350c127f2b0c984787a60ea2663b4d660e..27c3be0d71f143758b8e8ec3e1f53738bd115a31 100644 (file)
@@ -22,6 +22,7 @@
 #include <math.h>
 #include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 // hack for MSVC6.0 compiler
 #ifdef _MSC_VER
diff --git a/intern/elbeem/intern/paraloop.h b/intern/elbeem/intern/paraloop.h
deleted file mode 100644 (file)
index fba0ae4..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-
-#define PERFORM_USQRMAXCHECK \
-_Pragma("omp critical") {\
-USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz); \
-} \
-
-
-#define LIST_EMPTY(x) \
-_Pragma("omp critical") {\
-mListEmpty.push_back( x ); }
-
-#define LIST_FULL(x) \
-_Pragma("omp critical") {\
-mListFull.push_back( x ); }
-
-#define FSGR_ADDPART(x)  \
-_Pragma("omp critical") { \
-mpParticles->addFullParticle( x ); } \
-
-
-#define MAX_THREADS 2
-
-#define  GRID_REGION_START()  \
-{ /* main_region */ \
-       int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \
-       if(gridLoopBound>0){ kstart=getForZMin1(), kend=getForZMax1(mMaxRefine); } \
-       int kdir = 1; \
-       const int id=omp_get_thread_num(); \
-       int jstart = (id*((mLevel[mMaxRefine].lSizey-gridLoopBound) / MAX_THREADS))+gridLoopBound; \
-       int jend   = (id+1)*((mLevel[mMaxRefine].lSizey-gridLoopBound)/ MAX_THREADS); \
-       if(id+1 == MAX_THREADS) \
-       { \
-       jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \
-       } \
-       LbmFloat *ccel = NULL, *tcel = NULL; \
-       CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \
-       if(mLevel[mMaxRefine].setCurr==1) { \
-       kdir = -1; \
-       int temp = kend; \
-       kend = kstart-1; \
-       kstart = temp-1; \
-       temp = id; /* dummy remove warning */ \
-} \
-
-// if(jstart<1) jstart = 1; 
-
-#define unused_GRID_REGION_END() \
-} /* main_region */  \
-       // end unusedGRID_REGION_END
-
index 889e29308182e8b720f91d09774dada618c56e2c..81fc329d159a07d7cb2ae76b6e5400cea7ec2fff 100644 (file)
@@ -7,7 +7,7 @@
        /* COMPRESSGRIDS!=1 */ 
        /* int i=0;  */ 
        /* ADVANCE_POINTERS(mLevel[lev].lSizex*2);  */ 
-} /* all cell loop k,j,i */ 
+} /* all cell loop k,j,i */
        if(doReduce) { } /* dummy remove warning */ 
 } /* main_region */ 
 
diff --git a/intern/elbeem/intern/paraloopstart.h b/intern/elbeem/intern/paraloopstart.h
deleted file mode 100644 (file)
index e594081..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-#pragma omp parallel num_threads(MAX_THREADS) \
-reduction(+: calcCurrentMass, calcCurrentVolume, calcCellsFilled, calcCellsEmptied, calcNumUsedCells) 
index c9da808543a0a9f8acc77430a9c71e43fa1f31f2..819fcdd0b9aacd25b868276bd5a43f5094decde9 100644 (file)
@@ -325,7 +325,7 @@ void ParticleTracer::getTriangles(double time, vector<ntlTriangle> *triangles,
        // suppress warnings...
        vertices = NULL; triangles = NULL;
        normals = NULL; objectId = 0;
-       time = 0.0;
+       time = 0.;
 #else // ELBEEM_PLUGIN
        int pcnt = 0;
        // currently not used in blender
index 2ff600a36d4ee07324db1acfa997da8059371b48..9b47ae696afff4a2d784e0a00f23406d59034da1 100644 (file)
@@ -15,7 +15,6 @@
 #include "solver_interface.h"
 #include "particletracer.h"
 #include "elbeem.h"
-#include <stdlib.h> /* exit(3) - also in linux */
 
 #ifdef _WIN32
 #else
@@ -69,6 +68,7 @@ SimulationObject::~SimulationObject()
 /*! init tree for certain geometry init */
 /*****************************************************************************/
 void SimulationObject::initGeoTree() {
+       // unused!! overriden by solver interface       
        if(mpGlob == NULL) { 
                errFatal("SimulationObject::initGeoTree error","Requires globals!", SIMWORLD_INITERROR); 
                return;
@@ -80,7 +80,7 @@ void SimulationObject::initGeoTree() {
        char treeFlag = (1<<(mGeoInitId+4));
        mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
                                                                                                scene, treeFlag );
-       exit(1); // unused!? overriden by solver interface      
+       // unused!! overriden by solver interface       
 }
 
 /*****************************************************************************/
@@ -310,7 +310,7 @@ void SimulationObject::step( void )
                // dont advance for stopped time
                mpLbm->step();
                mTime += mpParam->getTimestep();
-//if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); exit(1); } // PROFILE DEBUG TEST!
+               //if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); xit(1); } // PROFILE DEBUG TEST!
        }
        if(mpLbm->getPanic()) mPanic = true;
 
index 930c1863aa7bce2948be79753fa38a0bb22ddb0a..d46f065adfd6632ed9aa4b58479ce0a510b42c1a 100644 (file)
 // sirdude fix for solaris
 #if !defined(linux) && defined(sun)
 #ifndef expf
-#define expf(a)                exp((double)(a))
+#define expf(x) exp((double)(x))
 #endif
 #endif
 
index abec4a89c89b1f4abb726769c77caa29f3bee58c..b0ce130c13684b330360ee57a6c27aa39c593aea 100644 (file)
@@ -655,6 +655,7 @@ bool LbmFsgrSolver::initializeSolverMemory()
        int orgSz = mSizez;
        double sizeReduction = 1.0;
        double memEstFromFunc = -1.0;
+       double memEstFine = -1.0;
        string memreqStr("");   
        bool firstMInit = true;
        int minitTries=0;
@@ -672,7 +673,7 @@ bool LbmFsgrSolver::initializeSolverMemory()
                firstMInit=false;
 
                calculateMemreqEstimate( mSizex, mSizey, mSizez, 
-                               mMaxRefine, mFarFieldSize, &memEstFromFunc, &memreqStr );
+                               mMaxRefine, mFarFieldSize, &memEstFromFunc, &memEstFine, &memreqStr );
                
                double memLimit;
                string memLimStr("-");
@@ -685,13 +686,36 @@ bool LbmFsgrSolver::initializeSolverMemory()
                        memLimit = 16.0* 1024.0*1024.0*1024.0;
                        memLimStr = string("16GB");
                }
-               if(memEstFromFunc>memLimit) {
+
+               // restrict max. chunk of 1 mem block to 1GB for windos
+               bool memBlockAllocProblem = false;
+               double maxWinMemChunk = 1100.*1024.*1024.;
+               double maxMacMemChunk = 1200.*1024.*1024.;
+               double maxDefaultMemChunk = 2.*1024.*1024.*1024.;
+               //std::cerr<<" memEstFine "<< memEstFine <<" maxWin:" <<maxWinMemChunk <<" maxMac:" <<maxMacMemChunk ; // DEBUG
+#ifdef WIN32
+               if(memEstFine> maxWinMemChunk) {
+                       memBlockAllocProblem = true;
+               }
+#endif // WIN32
+#ifdef __APPLE__
+               if(memEstFine> maxMacMemChunk) {
+                       memBlockAllocProblem = true;
+               }
+#endif // Mac
+               if(sizeof(int)==4 && memEstFine>maxDefaultMemChunk) {
+                       // max memory chunk for 32bit systems 2gig
+                       memBlockAllocProblem = true;
+               }
+
+               if(memEstFromFunc>memLimit || memBlockAllocProblem) {
                        sizeReduction *= 0.9;
                        mSizex = (int)(orgSx * sizeReduction);
                        mSizey = (int)(orgSy * sizeReduction);
                        mSizez = (int)(orgSz * sizeReduction);
                        debMsgStd("LbmFsgrSolver::initialize",DM_WARNING,"initGridSizes: memory limit exceeded "<<
                                        //memEstFromFunc<<"/"<<memLimit<<", "<<
+                                       //memEstFine<<"/"<<maxWinMemChunk<<", "<<
                                        memreqStr<<"/"<<memLimStr<<", "<<
                                        "retrying: "<<PRINT_VEC(mSizex,mSizey,mSizez)<<" org:"<<PRINT_VEC(orgSx,orgSy,orgSz)
                                        , 3 );
@@ -778,10 +802,6 @@ bool LbmFsgrSolver::initializeSolverMemory()
        mLevel[ mMaxRefine ].simCellSize = mpParam->getCellSize();
        mLevel[ mMaxRefine ].lcellfactor = 1.0;
        LONGINT rcellSize = ((mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez) *dTotalNum);
-       // +4 for safety ?
-       mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
-       mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
-       ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4);
 
 #if COMPRESSGRIDS==0
        mLevel[ mMaxRefine ].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
@@ -789,11 +809,34 @@ bool LbmFsgrSolver::initializeSolverMemory()
        ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4);
 #else // COMPRESSGRIDS==0
        LONGINT compressOffset = (mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*dTotalNum*2);
+       // D int tmp = ( (rcellSize +compressOffset +4)/(1024*1024) )*4;
+       // D printf("Debug MEMMMM excee: %d\n", tmp);
        mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +compressOffset +4 ];
        mLevel[ mMaxRefine ].mprsCells[0] = mLevel[ mMaxRefine ].mprsCells[1]+compressOffset;
        ownMemCheck += sizeof(LbmFloat) * (rcellSize +compressOffset +4);
 #endif // COMPRESSGRIDS==0
 
+       if(!mLevel[ mMaxRefine ].mprsCells[1] || !mLevel[ mMaxRefine ].mprsCells[0]) {
+               errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (1)! Aborting...",SIMWORLD_INITERROR);
+               return false;
+       }
+
+       // +4 for safety ?
+       mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
+       mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
+       ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4);
+       if(!mLevel[ mMaxRefine ].mprsFlags[1] || !mLevel[ mMaxRefine ].mprsFlags[0]) {
+               errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (2)! Aborting...",SIMWORLD_INITERROR);
+
+#if COMPRESSGRIDS==0
+               delete[] mLevel[ mMaxRefine ].mprsCells[0];
+               delete[] mLevel[ mMaxRefine ].mprsCells[1];
+#else // COMPRESSGRIDS==0
+               delete[] mLevel[ mMaxRefine ].mprsCells[1];
+#endif // COMPRESSGRIDS==0
+               return false;
+       }
+
        LbmFloat lcfdimFac = 8.0;
        if(LBMDIM==2) lcfdimFac = 4.0;
        for(int i=mMaxRefine-1; i>=0; i--) {
index 2539556617bb4752e6d81b4f07e4c3e4ba92ad25..d25850a003be81de8a3894110a15b789a8c55070 100644 (file)
@@ -17,7 +17,6 @@
 #include "ntl_world.h"
 #include "elbeem.h"
 
-#include <stdlib.h> /* getenv(3) - also in linux */
 
 
 
@@ -142,7 +141,7 @@ void initGridSizes(int &sizex, int &sizey, int &sizez,
 
 void calculateMemreqEstimate( int resx,int resy,int resz, 
                int refine, float farfield,
-               double *reqret, string *reqstr) {
+               double *reqret, double *reqretFine, string *reqstr) {
        // debug estimation?
        const bool debugMemEst = true;
        // COMPRESSGRIDS define is not available here, make sure it matches
@@ -150,6 +149,7 @@ void calculateMemreqEstimate( int resx,int resy,int resz,
        // make sure we can handle bid numbers here... all double
        double memCnt = 0.0;
        double ddTotalNum = (double)dTotalNum;
+       if(reqretFine) *reqretFine = -1.;
 
        double currResx = (double)resx;
        double currResy = (double)resy;
@@ -159,10 +159,12 @@ void calculateMemreqEstimate( int resx,int resy,int resz,
        if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"res:"<<PRINT_VEC(currResx,currResy,currResz)<<" rcellSize:"<<rcellSize<<" mc:"<<memCnt, 10);
   if(!useGridComp) {
                memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
+               if(reqretFine) *reqretFine = (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
                if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG," no-comp, mc:"<<memCnt, 10);
        } else {
                double compressOffset = (double)(currResx*currResy*ddTotalNum*2.0);
                memCnt += (double)(sizeof(LbmFloat) * (rcellSize+compressOffset +4.0));
+               if(reqretFine) *reqretFine = (double)(sizeof(LbmFloat) * (rcellSize+compressOffset +4.0));
                if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG," w-comp, mc:"<<memCnt, 10);
        }
        for(int i=refine-1; i>=0; i--) {
index 1dfdf156ee50b6d28436694f4d52d038c0d4cbeb..c3dc4983cac33c221b7fb160e59b9731834918a0 100644 (file)
@@ -21,7 +21,7 @@
 #if LBM_USE_GUI==1
 #define USE_GLUTILITIES
 // for debug display
-#include <GL/gl.h>
+//#include <GL/gl.h>
 #include "../gui/guifuncs.h"
 #endif
 
@@ -596,8 +596,10 @@ class LbmSolverInterface
 void initGridSizes(int &mSizex, int &mSizey, int &mSizez,
                ntlVec3Gfx &mvGeoStart, ntlVec3Gfx &mvGeoEnd, 
                int mMaxRefine, bool parallel);
+// return the amount of memory required in total (reqret)
+// and for the finest grid only (reqretFine, can be NULL)
 void calculateMemreqEstimate(int resx,int resy,int resz, int refine,
-               float farfieldsize, double *reqret, string *reqstr);
+               float farfieldsize, double *reqret, double *reqretFine, string *reqstr);
 
 //! helper function to convert flag to string (for debuggin)
 string convertCellFlagType2String( CellFlagType flag );
index 270e8867b3cea2a6e7f4986143cb7bd407ea8bb9..afc883972e2326fa212d0832b0bee5bda3837779 100644 (file)
@@ -7,11 +7,11 @@
  *
  *****************************************************************************/
 
-#include <stdlib.h> /* rand(3) - also in linux */
 #include "solver_class.h"
 #include "solver_relax.h"
 #include "particletracer.h"
 #include "loop_tools.h"
+#include <stdlib.h>
 
 /*****************************************************************************/
 /*! perform a single LBM step */
@@ -375,7 +375,11 @@ LbmFsgrSolver::mainLoop(int lev)
        const int gridLoopBound=1;
        GRID_REGION_INIT();
 #if PARALLEL==1
-#include "paraloopstart.h"
+#pragma omp parallel default(shared) \
+  reduction(+: \
+         calcCurrentMass,calcCurrentVolume, \
+               calcCellsFilled,calcCellsEmptied, \
+               calcNumUsedCells )
        GRID_REGION_START();
 #else // PARALLEL==1
        GRID_REGION_START();
@@ -1112,7 +1116,11 @@ LbmFsgrSolver::preinitGrids()
        
                GRID_REGION_INIT();
 #if PARALLEL==1
-#include "paraloopstart.h"
+#pragma omp parallel default(shared) \
+  reduction(+: \
+         calcCurrentMass,calcCurrentVolume, \
+               calcCellsFilled,calcCellsEmptied, \
+               calcNumUsedCells )
 #endif // PARALLEL==1
                GRID_REGION_START();
                GRID_LOOP_START();
@@ -1145,7 +1153,11 @@ LbmFsgrSolver::standingFluidPreinit()
 
        GRID_REGION_INIT();
 #if PARALLEL==1
-#include "paraloopstart.h"
+#pragma omp parallel default(shared) \
+  reduction(+: \
+         calcCurrentMass,calcCurrentVolume, \
+               calcCellsFilled,calcCellsEmptied, \
+               calcNumUsedCells )
 #endif // PARALLEL==1
        GRID_REGION_START();
 
index 65cc2200d4e624a436f41a596631e16defdbf167..a6685babe680b22aafc992d605b4c41b77846169 100644 (file)
@@ -15,8 +15,7 @@
 #include "ntl_world.h"
 #include "simulation_object.h"
 
-#include <stdlib.h> /* rand(3) */
-
+#include <stdlib.h>
 #include <zlib.h>
 #ifndef sqrtf
 #define sqrtf sqrt
index 332052e91b62ba3450dbc19d7c3f1a7429e77c98..551c4d0d3842769ee065de69df065cfd53988847 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <iostream>
 #include <sstream>
-#include <stdlib.h> /* getenv(3), strtol(3) */
 #ifdef WIN32
 // for timing
 #include <windows.h>
@@ -482,7 +481,7 @@ double elbeemEstimateMemreq(int res,
        double memreq = -1.0;
        string memreqStr("");   
        // ignore farfield for now...
-       calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, &memreqStr );
+       calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, NULL, &memreqStr );
 
        if(retstr) { 
                // copy at max. 32 characters
index 0f65408d23c7c0bd033a8437c60483909397c5ff..825e92251fe5d4d7705fb06b3878631ce3648730 100644 (file)
@@ -9,11 +9,6 @@
 #ifndef UTILITIES_H
 #include "ntl_vector3dim.h"
 
-// Solaris requires ieeefp.h for finite(3C)
-#if !defined(linux) && defined(sun)
-#include <ieeefp.h>
-#endif
-
 
 /* debugging outputs , debug level 0 (off) to 10 (max) */
 #ifdef ELBEEM_PLUGIN
index f7038e610f1d22427687acae631be71ee8945ef9..0951c40d89184b3ccd9fb741a591a21f52b9d5a0 100644 (file)
                        <File
                                RelativePath="..\..\..\source\blender\blenlib\intern\fileops.c">
                        </File>
+                       <File
+                               RelativePath="..\..\..\source\blender\blenlib\intern\fnmatch.c">
+                       </File>
                        <File
                                RelativePath="..\..\..\source\blender\blenlib\intern\freetypefont.c">
                        </File>
                        <File
                                RelativePath="..\..\..\source\blender\blenlib\intern\BLI_fileops.h">
                        </File>
+                       <File
+                               RelativePath="..\..\..\source\blender\blenlib\BLI_fnmatch.h">
+                       </File>
                        <File
                                RelativePath="..\..\..\source\blender\blenlib\BLI_ghash.h">
                        </File>
index 0ff8e178ac1c66b9b986a5950992e0b75afc8c37..8ee1aa6c7070f8c07ee61f2102ba535597d76ded 100644 (file)
@@ -11,6 +11,8 @@ def Error_NoMeshUvActive():
        Draw.PupMenu('Error%t|Active object is not a mesh with texface')
 def Error_NoMeshMultiresEdit():
        Draw.PupMenu('Error%t|Unable to complete action with multires enabled')
+def Error_NoMeshFaces():
+       Draw.PupMenu('Error%t|Mesh has no faces')
 
 # File I/O messages
 def Error_NoFile(path):
index 283c24a3ad01dbc08bc49fa701979a1c7120107b..d2e90bc27b8cb6ef98cd6ea6c954b1818b2f1246 100644 (file)
@@ -1,45 +1,25 @@
 #!BPY
 """ Registration info for Blender menus:
 Name: 'OpenFlight (.flt)...'
-Blender: 237
+Blender: 245
 Group: 'Export'
 Tip: 'Export to OpenFlight v16.0 (.flt)'
 """
 
-__author__ = "Greg MacDonald"
-__version__ = "1.2 10/20/05"
+__author__ = "Greg MacDonald, Geoffrey Bantle"
+__version__ = "2.0 11/21/07"
 __url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/")
 __bpydoc__ = """\
 This script exports v16.0 OpenFlight files.  OpenFlight is a
 registered trademark of MultiGen-Paradigm, Inc.
 
-Run from "File->Export" menu. 
-
-Options are available from Blender's "Scripts Config Editor," accessible through
-the "Scripts->System" menu from the scripts window.
-
-Features:<br>
-* Heirarchy retained.<br>
-* Normals retained.<br>
-* First texture exported.<br>
-* Diffuse material color is exported as the face color, material color, or both
-depending on the option settings.<br>
-* Double sided faces are exported as two faces.<br>
-* Object transforms exported.
-
-Things To Be Aware Of:<br>
-* Object names are exported, not mesh or data names.
-* Material indices that don't have a material associated with them will confuse the
-exporter. If a warning appears about this, correct it by deleting the offending
-material indices in Blender.
-
-What's Not Handled:<br>
-* Animations.<br>
-* Vetex colors.<br>
+Feature overview and more availible at:
+http://wiki.blender.org/index.php/Scripts/Manual/Export/openflight_flt
 """
 
 # flt_export.py is an OpenFlight exporter for blender.
-# Copyright (C) 2005 Greg MacDonald
+#
+# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation.
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -56,29 +36,87 @@ What's Not Handled:<br>
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 import Blender
+from Blender import Modifier
+import os.path
+import flt_properties
+import flt_defaultp as defaultp
 from flt_filewalker import FltOut
+from flt_filewalker import FileFinder
+from flt_properties import *
+import shutil
+
+FF = FileFinder()
+records = process_recordDefs()
 
 class ExporterOptions:
        def __init__(self):
-               self.defaults = { 'Diffuse Color To OpenFlight Material': False,
-                                                 'Diffuse Color To OpenFlight Face': True}
+               self.verbose = 1
+               self.tolerance = 0.001
+               self.writevcol = True
                
-               d = Blender.Registry.GetKey('flt_export', True)
+               #new stuff
+               self.export_shading = 0
+               self.shading_default = 45.0
+               self.basepath = os.path.dirname(Blender.Get('filename'))
+               self.scale = 1.0
                
-               if d == None or d.keys() != self.defaults.keys():
-                       d = self.defaults
-                       Blender.Registry.SetKey('flt_export', d, True)
+               #set externals path
+               if(os.path.exists(os.path.join(self.basepath,'externals'))):
+                       self.externalspath = os.path.join(self.basepath,'externals')
+               else:
+                       self.externalspath = self.basepath 
                
-               self.verbose = 1
-               self.tolerance = 0.001
-               self.use_mat_color = d['Diffuse Color To OpenFlight Material']
-               self.use_face_color = d['Diffuse Color To OpenFlight Face']
+               self.doxrefs = 1
+               
+               #texture options
+               if(os.path.exists(os.path.join(self.basepath,'textures'))):
+                       self.texturespath = os.path.join(self.basepath,'textures')
+               else:
+                       self.texturespath = self.basepath
+               
+               #misc
+               self.write_attrib_files = 0
+               self.copy_textures = 0
+               self.export_transform = 0
+               self.flattenmesh = False
                
+               self.xapp = 1
+               reg = Blender.Registry.GetKey('flt_export',1)
+               if(reg and 'xappath' in reg.keys()):
+                       self.xappath = reg['xappath']
+               else:
+                       self.xappath = ''
 options = ExporterOptions()
+tex_files = dict() #a list of (possibly) modified texture path names
+
+tex_layers = ['Layer0', 'Layer1', 'Layer2', 'Layer3', 'Layer4', 'Layer5', 'Layer6', 'Layer7']
+mask = 2147483648
+mtexmasks = []
+for i in xrange(7):
+       mtexmasks.append(mask)
+       mask = mask / 2
 
 FLOAT_TOLERANCE = options.tolerance
 
+#need to move all this stuff to flt_properties.py.
 identity_matrix = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]
+alltypes = [2,4,11,73,63,111]
+childtypes = { 
+       2 : [111,2,73,4,14,63],
+       4 : [111],
+       73 : [111,2,73,4,14,63],
+       63 : [],
+       14 : [111,2,73,4,14,63],
+       111 : []
+}
+recordlen = {
+       2: 44,
+       4: 28,
+       73: 80,
+       63: 216,
+       14: 384,
+       111: 156
+}
 
 def is_identity(m):
        for i in xrange(4):
@@ -102,13 +140,47 @@ class MaterialDesc:
                self.alpha = 1.0 # Range is [0.0, 1.0]
 
 class VertexDesc:
-       def __init__(self, co=None, no=None, uv=None):
+       def __init__(self, co=None, no=None, uv=None, fltindex=None,cindex=None):
                if co: self.x, self.y, self.z = tuple(co)
                else: self.x = self.y = self.z = 0.0
                if no: self.nx, self.ny, self.nz = tuple(no)
                else: self.nx = self.ny = self.nz = 0.0
                if uv: self.u, self.v = tuple(uv)
                else: self.u = self.v = 0.0
+               if cindex: self.cindex = cindex
+               else: self.cindex = 127
+               self.fltindex = fltindex
+               self.accum = 0
+
+class shadowVert:
+       def __init__(self,bvert,object,world,normal):
+                global options
+               
+               self.co = Blender.Mathutils.Vector(bvert.co[0],bvert.co[1],bvert.co[2])
+                #if world:
+               #       vec = self.co
+               #       vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale
+               #       self.co =  Blender.Mathutils.TranslationMatrix(vec) * (self.co * object.getMatrix('worldspace'))
+               
+               if normal:
+                        #if world:
+                       #       self.no = Blender.Mathutils.Vector(normal * object.getMatrix('worldspace')).normalize()
+                       #else:
+                       self.no = Blender.Mathutils.Vector(normal[0],normal[1],normal[2])
+                       
+               else:
+                       #if world:
+                               #self.no = Blender.Mathutils.Vector(bvert.no * object.getMatrix('worldspace')).normalize() 
+                       #else:
+                       self.no = Blender.Mathutils.Vector(bvert.no[0],bvert.no[1],bvert.no[2])
+                       
+               #do scaling factor
+               #if options.scale != 1.0:
+                       #self.co[0] = self.co[0] * options.scale
+                       #self.co[1] = self.co[1] * options.scale
+                       #self.co[2] = self.co[2] * options.scale
+                       
+               self.index = bvert.index
 
 class GlobalResourceRepository:
        def new_face_name(self):
@@ -121,44 +193,98 @@ class GlobalResourceRepository:
        def request_vertex_desc(self, i):
                return self.vertex_lst[i]
 
-       def request_vertex_index(self, desc):
-               match = None
-               for i, v in enumerate(self.vertex_lst):
-                       if\
-                       abs(v.x - desc.x) > FLOAT_TOLERANCE or\
-                       abs(v.y - desc.y) > FLOAT_TOLERANCE or\
-                       abs(v.z - desc.z) > FLOAT_TOLERANCE or\
-                       abs(v.nx - desc.nx) > FLOAT_TOLERANCE or\
-                       abs(v.ny - desc.ny) > FLOAT_TOLERANCE or\
-                       abs(v.nz - desc.nz) > FLOAT_TOLERANCE or\
-                       abs(v.u - desc.u) > FLOAT_TOLERANCE or\
-                       abs(v.v - desc.v) > FLOAT_TOLERANCE:
-                               pass
-                       else:
-                               match = i
-                               break
+       def request_vertex_index(self, object, mesh, face, vfindex, uvok,cindex):
 
-               if match != None:
-                       return match
+               flatShadeNorm = None
+               
+               if type(face) is list:
+                       vertex = face[vfindex]
+               elif str(type(face)) == "<type " + "'Blender MVert'>": 
+                       vertex = face
+               elif str(type(face)) == "<type " + "'Blender MEdge'>":
+                       if vfindex == 1:
+                               vertex = face.v1
+                       elif vfindex == 2:
+                               vertex = face.v2
+               elif str(type(face)) == "<type " + "'Blender MFace'>":
+                        if not face.smooth:
+                                flatShadeNorm = face.no
+                       vertex = face.v[vfindex]
+               else: 
+                       return None
+                                               
+               if not self.namehash.has_key(object.name):
+                       self.namehash[object.name] = dict()
+               indexhash = self.namehash[object.name]
+               
+               #export in global space? THIS HAS BEEN MADE REDUNDANT... REMOVE ME
+               if not options.export_transform:
+                       vertex = shadowVert(vertex,object,True,flatShadeNorm)
                else:
-                       self.vertex_lst.append(desc)
-                       return len(self.vertex_lst) - 1
-
-       def request_texture_index(self, filename):
+                        vertex = shadowVert(vertex,object,False,flatShadeNorm)
+        
+                
+               #Check to see if this vertex has been visited before. If not, add
+               if not indexhash.has_key(vertex.index):
+                       if uvok:
+                               newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex)
+                       else:
+                               newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex)
+                       
+                       indexhash[vertex.index] = [newvdesc]
+                       self.vertex_lst.append(newvdesc)
+                       self.nextvindex = self.nextvindex + 1
+                       return newvdesc.fltindex
+               
+               else:
+                       desclist = indexhash[vertex.index]
+                       if uvok: 
+                               faceu = face.uv[vfindex][0]
+                               facev = face.uv[vfindex][1]
+                       else:
+                               faceu = 0.0
+                               facev = 0.0
+                       for vdesc in desclist:
+                               if\
+                               abs(vdesc.x - vertex.co[0]) > FLOAT_TOLERANCE or\
+                               abs(vdesc.y - vertex.co[1]) > FLOAT_TOLERANCE or\
+                               abs(vdesc.z - vertex.co[2]) > FLOAT_TOLERANCE or\
+                               abs(vdesc.nx - vertex.no[0]) > FLOAT_TOLERANCE or\
+                               abs(vdesc.ny - vertex.no[1]) > FLOAT_TOLERANCE or\
+                               abs(vdesc.nz - vertex.no[2]) > FLOAT_TOLERANCE or\
+                               vdesc.cindex != cindex or\
+                               abs(vdesc.u - faceu) > FLOAT_TOLERANCE or\
+                               abs(vdesc.v - facev) > FLOAT_TOLERANCE:
+                                       pass
+                               else:
+                                       return vdesc.fltindex
+                               
+                       #if we get this far, we didnt find a match. Add a new one and return
+                       if uvok:
+                               newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex)
+                       else:
+                               newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex)
+                       indexhash[vertex.index].append(newvdesc)
+                       self.vertex_lst.append(newvdesc)
+                       self.nextvindex = self.nextvindex + 1
+                       return newvdesc.fltindex
+                                       
+                       
+       def request_texture_index(self, image):
                match = None
                for i in xrange(len(self.texture_lst)):
-                       if self.texture_lst[i] != filename:
+                       if self.texture_lst[i] != image:
                                continue
                        match = i
                        break
                if match != None:
                        return match
                else:
-                       self.texture_lst.append(filename)
+                       self.texture_lst.append(image)
                        return len(self.texture_lst) - 1
 
        def request_texture_filename(self, index):
-               return self.texture_lst[index]
+               return Blender.sys.expandpath(self.texture_lst[index].getFilename())
 
        def texture_count(self):
                return len(self.texture_lst)
@@ -239,7 +365,11 @@ class GlobalResourceRepository:
                return len(self.color_lst)
 
        def __init__(self):
+               #Vertex handling
                self.vertex_lst = []
+               self.nextvindex = 0
+               self.namehash = dict()
+               
                self.texture_lst = []
                self.material_lst = []
                self.color_lst = [[255, 255, 255]]
@@ -253,7 +383,6 @@ class Node:
                if self.object:
                        if options.verbose >= 2:
                                print '\t' * level[0], self.name, self.object.type
-
                level[0] += 1
                
                for child in self.children:
@@ -288,183 +417,530 @@ class Node:
                        self.header.fw.write_ushort(length+5)       # Length of record
                        self.header.fw.write_string(name, length+1) # name + zero terminator
 
+       def write_comment(self,comment):
+               length = len(comment)
+               if length >= 65535:
+                       comment = comment[:65530]
+                       length = len(comment)
+               
+               pad = (length % 4) - 1
+               if pad < 0: 
+                       pad = None
+                       reclength = length + 5
+               else:
+                       reclength = length + 5 + pad
+               
+               self.header.fw.write_short(31)                                  # Comment Opcode
+               self.header.fw.write_ushort(reclength)                  # Length of record is 4 + comment length + null terminator + pad
+               self.header.fw.write_string(comment,length+1)   # comment + zero terminator
+               if pad:
+                       self.header.fw.pad(pad)                                         # pad to multiple of 4 bytes
+               
        # Initialization sets up basic tree structure.
-       def __init__(self, parent, header, object, object_lst):
+       def __init__(self, parent, header, object,props):
+               global options
+               
                self.header = header
                self.object = object
                if object:
                        self.name = self.object.name
-                       self.matrix = self.object.getMatrix('localspace')
+                       if not options.export_transform:
+                               oloc = Blender.Mathutils.Vector(object.getLocation('worldspace'))
+                               vec = Blender.Mathutils.Vector(oloc[0] * options.scale, oloc[1] * options.scale, oloc[2] * options.scale) #scale
+                               self.matrix =  self.object.getMatrix('worldspace') *  Blender.Mathutils.TranslationMatrix(vec - oloc)                   
+                       else:
+                               self.matrix = self.object.getMatrix('localspace') #do matrix mult here.
+                       self.props = props
+                       self.child_objects = self.header.parenthash[object.name]
                else:
                        self.name = 'no name'
                        self.matrix = None
-
+                       self.props = None
+                       self.child_objects = self.header.child_objects
+               
                self.children = []
                self.parent = parent
                if parent:
                        parent.children.append(self)
-
-               left_over = object_lst[:]
-               self.child_objects = []
-
-               # Add children to child list and remove from left_over list.
                
-               # Pop is faster then remove
-               i = len(object_lst)
-               while i:
-                       i-=1
-                       if object_lst[i].parent == object:
-                               self.child_objects.append(left_over.pop(i))
-                       
                # Spawn children.
-               self.has_object_child = False # For Database class.
                for child in self.child_objects:                        
-                       if child.type == 'Mesh':
-                               BlenderMesh(self, header, child, left_over)
-                               self.has_object_child = True
-                       else: # Treat all non meshes as emptys
-                               BlenderEmpty(self, header, child, left_over)
-
+                       if(not child.restrictDisplay):
+                               childprops = None
+                               type = None
+                               if not child.properties.has_key('FLT'):
+                                       if child.type == 'Empty':
+                                               if child.DupGroup:
+                                                       childprops = FLTXRef.copy()
+                                                       type = 63
+                                               else:
+                                                       childprops = FLTGroup.copy()
+                                                       type = 2
+                                       elif child.type == 'Mesh':
+                                               if self.header.childhash[child.name] or not child.parent:
+                                                       childprops = FLTGroup.copy()
+                                                       type = 2
+                                               else:
+                                                       childprops = FLTObject.copy()
+                                                       type = 4
+                                                       
+                               else:
+                                       childprops = dict()
+                                       for prop in child.properties['FLT']:
+                                               childprops[prop] = child.properties['FLT'][prop]
+                                       type = child.properties['FLT']['type']
+                               
+                               if type in self.childtypes and type in alltypes:
+                                       Newnode = FLTNode(self,header,child,childprops,type)
+                                       if child.type == 'Mesh':
+                                               self.header.mnodes.append(Newnode)
 class FaceDesc:
        def __init__(self):
                self.vertex_index_lst = []
+               self.mface = None
                self.texture_index = -1
                self.material_index = -1
                self.color_index = 127
-       
-class BlenderMesh(Node):
-       def blender_export(self):
-               Node.blender_export(self)
-
-               mesh = self.object.getData()
-               mesh_hasuv = mesh.hasFaceUV()
-               # Gather materials and textures.
-               tex_index_lst = []
-               mat_index_lst = []
-               color_index_lst = []
-               materials = mesh.getMaterials()
-               
-               if not materials:
-                       materials = [Blender.Material.New()]
-               
-               for mat in materials:
-                       # Gather Color.
-                       if options.use_face_color:
-                               color_index_lst.append(self.header.GRR.request_color_index(mat.getRGBCol()))
+               self.renderstyle = 0
+               self.twoside = 0
+               self.name = None #uses next FLT name if not set... fix resolution of conflicts!
+               
+               #Multi-Tex info. Dosn't include first UV Layer!
+               self.uvlayer = list() #list of list of tuples for UV coordinates.
+               self.images = list()  #list of texture indices for seperate UV layers
+               self.mtex = list()
+               self.subface = None #can either be 'Push' or 'Pop'
+
+def edge_get_othervert(vert, edge):
+       if edge.v1 == vert:
+               return edge.v2
+       elif edge.v2 == vert:
+               return edge.v1
+       return None
+
+class FLTNode(Node):
+       def walkLoop(self, targetvert, startvert, startedge, edgelist, visited, vedges, closeloop):
+               loop = [targetvert]
+               
+               curvert = startvert
+               curedge = startedge
+               visited[curedge] = True
+               found = False
+               
+               while not found:
+                       loop.append(curvert)
+                       disk = vedges[curvert.index]
+                       if not closeloop:
+                               if len(disk) == 1:
+                                       visited[curedge] = True
+                                       break
                        else:
-                               color_index_lst.append(127) # white
-                       # Gather Texture.
-                       mtex_lst = mat.getTextures()
-
-                       index = -1
-                       mtex = mtex_lst[0] # Not doing multi-texturing at the moment.
-                       if mtex != None:
-                               tex = mtex_lst[0].tex
-                               if tex != None:
-                                       image = tex.getImage()
-                                       if image != None:
-                                               filename = image.getFilename()
-                                               index = self.header.GRR.request_texture_index(filename)
-
-                       tex_index_lst.append(index)
-
-                       # Gather Material
-                       mat_desc = MaterialDesc()
-                       mat_desc.name = mat.name
-                       mat_desc.alpha = mat.getAlpha()
-                       mat_desc.shininess = mat.getSpec() * 64.0   # 2.0 => 128.0
-                       if options.use_mat_color:
-                               mat_desc.diffuse = mat.getRGBCol()
+                               if len(disk) < 2: #what?
+                                       visited[curedge] = True
+                                       return None
+                       
+                       if disk[0] == curedge:
+                               curedge = disk[1]
                        else:
-                               mat_desc.diffuse = [1.0, 1.0, 1.0]
+                               curedge = disk[0]
+                       if curedge.v1.index == curvert.index:
+                               curvert = curedge.v2
+                       else:
+                               curvert = curedge.v1
 
-                       mat_desc.specular = mat.getSpecCol()
-                       amb = mat.getAmb()
-                       mat_desc.ambient = [amb, amb, amb]
-                       emit = mat.getEmit()
-                       mat_desc.emissive = [emit, emit, emit]
+                       visited[curedge] = True
+                       
+                       if(curvert == targetvert):
+                               found = True
+               
+               return loop
+       
+       def buildVertFaces(self,vertuse):
+               for vert in self.exportmesh.verts:
+                       if vertuse[vert.index][0] == False and vertuse[vert.index][1] == 0:
+                               face_desc = FaceDesc()
+                               face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, vert, 0,0,0))
+                               face_desc.renderstyle = 3
+                               face_desc.color_index = 227
+                               self.face_lst.append(face_desc)
 
-                       mat_index_lst.append(self.header.GRR.request_material_index(mat_desc))
+       def buildEdgeFaces(self,vertuse):
+               for edge in self.exportmesh.edges:
+                       v1 = vertuse[edge.v1.index]
+                       v2 = vertuse[edge.v2.index]
+                       if v1[0] == False and v2[0] == False:
+                               if v1[1] == 1 and v2[1] == 1:
+                                       face_desc = FaceDesc()
+                                       face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 1, 0,0))
+                                       face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 2, 0,0))                                     
+                                       face_desc.renderstyle = 3
+                                       face_desc.color_index = 227
+                                       self.face_lst.append(face_desc)
+
+
+       def vertwalk(self, startvert, loop, disk, visited):
+               visited[startvert] = True
+               for edge in disk[startvert]:
+                       othervert = edge_get_othervert(startvert, edge)
+                       if not visited[othervert]:
+                               loop.append(othervert)
+                               self.vertwalk(othervert,loop,disk,visited)
+
+       def buildOpenFacesNew(self, vertuse):
+               wireverts = list()
+               wiredges = list()
+               visited = dict()
+               disk = dict()
+               loops = list()
+               
+               for edge in self.exportmesh.edges:
+                       v1 = vertuse[edge.v1.index]
+                       v2 = vertuse[edge.v2.index]
+                       if v1[0] == False and v2[0] == False:
+                               if v1[1] < 3 and v2[1] < 3:
+                                       wireverts.append(edge.v1)
+                                       wireverts.append(edge.v2)
+                                       wiredges.append(edge)
+                               
+               #build disk data
+               for vert in wireverts:
+                       visited[vert] = False
+                       disk[vert] = list()
+               for edge in wiredges:
+                       disk[edge.v1].append(edge)
+                       disk[edge.v2].append(edge)
+               
+               #first pass: do open faces
+               for vert in wireverts:
+                       if not visited[vert] and vertuse[vert.index][1] == 1:
+                               visited[vert] = True
+                               loop = [vert]
+                               othervert = edge_get_othervert(vert, disk[vert][0])
+                               self.vertwalk(othervert, loop, disk, visited)
+                               if len(loop) > 2: loops.append( ('Open', loop) )
+
+               for vert in wireverts:
+                       if not visited[vert]:
+                               visited[vert] = True
+                               loop = [vert]
+                               othervert = edge_get_othervert(vert,disk[vert][0])
+                               self.vertwalk(othervert, loop, disk, visited)
+                               if len(loop) > 2: loops.append( ('closed', loop) )
+                               
+               #now go through the loops and append.
+               for l in loops:
+                       (type, loop) = l
+                       face_desc = FaceDesc()
+                       for i,vert in enumerate(loop):
+                               face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,loop,i,0,0))
+                               if type  == 'closed':
+                                       face_desc.renderstyle = 2
+                               else:
+                                       face_desc.renderstyle = 3
+                               face_desc.color_index = 227
+                       self.face_lst.append(face_desc)
 
-               # Faces described as lists of indices into the GRR's vertex_lst.
-               for face in mesh.faces:
-                       
-                       face_v = face.v # Faster access
-                       
-                       # Create vertex description list for each face.
-                       if mesh_hasuv:
-                               vertex_lst = [VertexDesc(v.co, v.no, face.uv[i]) for i, v in enumerate(face_v)]
-                       else:
-                               vertex_lst = [VertexDesc(v.co, v.no) for i, v in enumerate(face_v)]
+       def sortFLTFaces(self,a,b):
+               aindex = a.getProperty("FLT_ORIGINDEX")
+               bindex = b.getProperty("FLT_ORIGINDEX")
+               
+               if aindex > bindex:
+                       return 1
+               elif aindex < bindex:
+                       return -1
+               return 0
+
+       def buildNormFaces(self):
+               
+               global options
+               meshlayers = self.exportmesh.getUVLayerNames()
+               oldlayer = self.exportmesh.activeUVLayer
+               uvok = 0
+               subfaceok = 0
+               subfacelevel = 0
+               
+               #special case
+               if self.exportmesh.faceUV and len(meshlayers) == 1:
+                       uvok = 1
+               elif self.exportmesh.faceUV and tex_layers[0] in meshlayers:
+                       self.exportmesh.activeUVLayer = tex_layers[0] 
+                       uvok = 1
+               
+               #Sort faces according to the subfaces/FLT indices
+               if "FLT_ORIGINDEX" in self.exportmesh.faces.properties and "FLT_SFLEVEL" in self.exportmesh.faces.properties:
+                       exportfaces = list()
+                       for face in self.exportmesh.faces:
+                               exportfaces.append(face)
+                       exportfaces.sort(self.sortFLTFaces)
+                       subfaceok = 1
+               else:
+                       exportfaces = self.exportmesh.faces
                        
+               # Faces described as lists of indices into the GRR's vertex_lst.
+               for face in exportfaces:
+                       descs = list()
+                       #first we export the face as normal
                        index_lst = []
-                       for vert_desc in vertex_lst:
-                               index_lst.append(self.header.GRR.request_vertex_index(vert_desc))
-                       
+                       face_v = face.verts
+                       for i, v in enumerate(face_v):
+                               index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,face,i,uvok,0))
                        face_desc = FaceDesc()
                        face_desc.vertex_index_lst = index_lst
+                       face_desc.mface = face
+                       descs.append(face_desc)
                        
-                       if face.materialIndex < len(materials):
-                               face_desc.color_index    = color_index_lst[face.materialIndex]
-                               face_desc.texture_index  = tex_index_lst[face.materialIndex]
-                               face_desc.material_index = mat_index_lst[face.materialIndex]
-                       else:
-                               if options.verbose >=1:
-                                       print 'Warning: Missing material for material index. Materials will not be imported correctly. Fix by deleting abandoned material indices in Blender.'
+                       #deal with subfaces                     
+                       if subfaceok:
+                               fsflevel = face.getProperty("FLT_SFLEVEL")
+                               for face_desc in descs:
+                                       if fsflevel > subfacelevel:
+                                               face_desc.subface = 'Push'
+                                               subfacelevel = fsflevel
+                                       elif fsflevel < subfacelevel:
+                                               face_desc.subface = 'Pop'
+                                               subfacelevel = fsflevel
+               
+                       
+                       if uvok and (face.mode & Blender.Mesh.FaceModes.TWOSIDE):
+                               face_desc.renderstyle = 1
+                       for face_desc in descs: 
+                               if "FLT_COL" in self.exportmesh.faces.properties:
+                                       color_index = face.getProperty("FLT_COL")
+#                                      if(color_index < 127):
+#                                              color_index = 127 #sanity check for face color indices
+                                       if(color_index == 0):
+                                               color_index = 127
+                                       face_desc.color_index = color_index
+                               else:
+                                       face_desc.color_index = 127
+                               if "FLT_ID" in self.exportmesh.faces.properties:
+                                       face_desc.name = face.getProperty("FLT_ID") #need better solution than this.
+                               
+                               self.face_lst.append(face_desc)
+               if uvok:                
+                       self.exportmesh.activeUVLayer = oldlayer
 
-                       self.face_lst.append(face_desc)
+       def buildTexData(self):
+               
+               meshlayers = self.exportmesh.getUVLayerNames()
+               oldlayer = self.exportmesh.activeUVLayer
+               uvok = 0
+               
+               if self.exportmesh.faceUV and len(meshlayers) == 1:
+                       uvok = 1
+               if self.exportmesh.faceUV and tex_layers[0] in meshlayers:
+                       self.exportmesh.activeUVLayer = tex_layers[0] 
+                       uvok = 1
+               
+               if uvok: 
+                       #do base layer. UVs have been stored on vertices directly already.
+                       for i, face in enumerate(self.face_lst):
+                               if face.mface:
+                                       mface = face.mface
+                                       image = mface.image
+                                       if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]:
+                                               index = self.header.GRR.request_texture_index(image)
+                                       else:
+                                               index = -1
+                                       face.texture_index = index
+
+                       for i, face in enumerate(self.face_lst):
+                               if face.mface:
+                                       mface_v = face.mface.v
+                                       for v in mface_v:
+                                               face.uvlayer.append([])
                        
-                       # Export double sided face as 2 faces with opposite orientations.
-                       if mesh_hasuv and face.mode & Blender.NMesh.FaceModes['TWOSIDE']:
-                               # Create vertex description list for each face. they have a face mode, so we know they have a UV too.
-                               vertex_lst = [VertexDesc(v.co, -v.no, face.uv[i]) for i, v in enumerate(face_v)]
-                               vertex_lst.reverse() # Reversing flips the face.
+                       for layername in tex_layers[1:]:
+                               if layername in meshlayers:
+                                       self.exportmesh.activeUVLayer=layername
+                                       for i, face in enumerate(self.face_lst):
+                                               if face.mface:
+
+                                                       face.mtex.append(layername)
+                                                       mface = face.mface
+                                                       mface_v = mface.v
+                                                       image = mface.image
+                                               
+                                                       if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]:
+                                                               index = self.header.GRR.request_texture_index(image)
+                                                               face.images.append(index)
+                                                       else:
+                                                               face.images.append(-1)
+
+                                                       for j, v in enumerate(mface_v):
+                                                               face.uvlayer[j].append(tuple(mface.uv[j]))
+               if uvok:
+                       self.exportmesh.activeUVLayer = oldlayer
+       def blender_export(self):
+               global options
+               Node.blender_export(self)
+               if self.opcode == 111:
+                       self.exportmesh = Blender.Mesh.New()
+                       self.exportmesh.getFromObject(self.object.name)                 
+
+                       for vert in self.exportmesh.verts:
+                               if not options.export_transform:
+                                       vec = vert.co
+                                       vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale
+                                       vert.co =  Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace'))                                           
                                
-                               index_lst = []
-                               for vert_desc in vertex_lst:
-                                       index_lst.append(self.header.GRR.request_vertex_index(vert_desc))
+                               if options.scale != 1.0:
+                                       vert.co = vert.co * options.scale
+
+                       if("FLT_VCOL") in self.mesh.verts.properties:
+                               for v in self.exportmesh.verts:
+                                       self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,v,0,0,v.getProperty("FLT_VCOL")))
+                       else:
+                               for v in self.mesh.verts:
+                                       self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.mesh,v,0,0,127))
+                       
+               
+               
+               elif self.mesh:
+                        orig_mesh = self.object.getData(mesh=True)
+                       self.exportmesh = Blender.Mesh.New()
+                       default = None
+
+
+                       if options.export_shading:
+                               mods = self.object.modifiers
+                               hasedsplit = False
+                               for mod in mods:
+                                       if mod.type == Blender.Modifier.Types.EDGESPLIT:
+                                               hasedsplit = True
+                                               break
+                               if not hasedsplit:
+                                       default = mods.append(Modifier.Types.EDGESPLIT)
+                                       default[Modifier.Settings.EDGESPLIT_ANGLE] = options.shading_default
+                                       default[Modifier.Settings.EDGESPLIT_FROM_ANGLE] = True
+                                       default[Modifier.Settings.EDGESPLIT_FROM_SHARP] = False
+                                       self.object.makeDisplayList()
+
+                       self.exportmesh.getFromObject(self.object.name)
+
+                       #recalculate vertex positions
+                       for vert in self.exportmesh.verts:
+                               if not options.export_transform:
+                                       vec = vert.co
+                                       vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale
+                                       vert.co =  Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace'))                                           
                                
-                               face_desc = FaceDesc()
-                               face_desc.vertex_index_lst = index_lst
-                               if face.materialIndex < len(materials):
-                                       face_desc.color_index = color_index_lst[face.materialIndex]
-                                       face_desc.texture_index = tex_index_lst[face.materialIndex]
-                                       face_desc.material_index = mat_index_lst[face.materialIndex]
-                               else:
-                                       if options.verbose >=1:
-                                               print 'Error: No material for material index. Delete abandoned material indices in Blender.'
-       
-                               self.face_lst.append(face_desc)
+                               if options.scale != 1.0:
+                                       vert.co = vert.co * options.scale                       
+                       
+                       flipped = self.object.getMatrix('worldspace').determinant()
+                       
+                       if not options.export_transform:
+                               self.exportmesh.calcNormals()
+                       
+
+                       if default:
+                                #remove modifier from list
+                               mods.remove(default)
+                               self.object.makeDisplayList()
+                               
+                       #build some adjacency data
+                       vertuse = list()
+                       wiredges = list()
+                       openends = list()
+                       for v in self.exportmesh.verts:
+                               vertuse.append([False,0])
+                       
+                       #build face incidence data
+                       for face in self.exportmesh.faces:
+                               for i, v in enumerate(face.verts):
+                                       vertuse[v.index][0] = True
+
+                       for edge in self.exportmesh.edges: #count valance
+                               vertuse[edge.v1.index][1] = vertuse[edge.v1.index][1] + 1
+                               vertuse[edge.v2.index][1] = vertuse[edge.v2.index][1] + 1
+
+                       #create all face types
+                       self.buildVertFaces(vertuse)
+                       self.buildEdgeFaces(vertuse)
+                       self.buildOpenFacesNew(vertuse)
+                       self.buildNormFaces()
+                       self.buildTexData()
+                       
+                       if not options.export_transform:
+                               if flipped < 0:
+                                       for vdesc in self.header.GRR.vertex_lst:
+                                               vdesc.accum = 0
+                                       for face in self.face_lst:
+                                               face.vertex_index_lst.reverse()
+                                               for vert in face.vertex_index_lst:
+                                                       self.header.GRR.vertex_lst[vert].accum = 1
+                                                       
+                                       for vdesc in self.header.GRR.vertex_lst:
+                                               if vdesc.accum:
+                                                       vdesc.nx = vdesc.nx * -1
+                                                       vdesc.ny = vdesc.ny * -1
+                                                       vdesc.nz = vdesc.nz * -1
+
 
        def write_faces(self):
+               sublevel = 0
                for face_desc in self.face_lst:
-                       face_name = self.header.GRR.new_face_name()
+                       if face_desc.name:
+                               face_name = face_desc.name
+                       else:
+                               face_name = self.header.GRR.new_face_name()
                        
+                       #grab the alpha value.
+                       alpha = 0
+                       if face_desc.texture_index > -1:
+                               try:
+                                       typestring = os.path.splitext(self.header.GRR.texture_lst[face_desc.texture_index].getFilename())[1]
+                                       if typestring == '.inta' or typestring == '.rgba':
+                                               alpha = 1
+                               except:
+                                       pass
+                                       
+                       if not alpha:
+                               for index in face_desc.images:
+                                       try:
+                                               typestring = os.path.splitext(self.header.GRR.texture_lst[index].getFilename())[1]
+                                               if typestring == '.inta' or typestring == '.rgba':
+                                                       alpha = 1
+                                       except:
+                                               pass
+                               
+                       if face_desc.subface:
+                               if face_desc.subface == 'Push':
+                                       self.header.fw.write_short(19)
+                                       self.header.fw.write_ushort(4)
+                                       sublevel += 1
+                               else:
+                                       self.header.fw.write_short(20)
+                                       self.header.fw.write_ushort(4)
+                                       sublevel -= 1
                        self.header.fw.write_short(5)                                   # Face opcode
                        self.header.fw.write_ushort(80)                                 # Length of record
                        self.header.fw.write_string(face_name, 8)                       # ASCII ID
                        self.header.fw.write_int(-1)                                    # IR color code
-                       self.header.fw.write_short(0)                                   # Relative priority
-                       self.header.fw.write_char(0)                                    # Draw type
+                       self.header.fw.write_short(0)                                                                   # Relative priority
+                       self.header.fw.write_char(face_desc.renderstyle)                # Draw type
                        self.header.fw.write_char(0)                                    # Draw textured white.
                        self.header.fw.write_ushort(0)                                  # Color name index
                        self.header.fw.write_ushort(0)                                  # Alt color name index
                        self.header.fw.write_char(0)                                    # Reserved
-                       self.header.fw.write_char(1)                                    # Template
+                       self.header.fw.write_char(alpha)                                    # Template
                        self.header.fw.write_short(-1)                                  # Detail tex pat index
                        self.header.fw.write_short(face_desc.texture_index)             # Tex pattern index
                        self.header.fw.write_short(face_desc.material_index)            # material index
                        self.header.fw.write_short(0)                                   # SMC code
-                       self.header.fw.write_short(0)                                   # Feature code
+                       self.header.fw.write_short(0)                                   # Feature                                       code
                        self.header.fw.write_int(0)                                     # IR material code
                        self.header.fw.write_ushort(0)                                  # transparency 0 = opaque
                        self.header.fw.write_uchar(0)                                   # LOD generation control
                        self.header.fw.write_uchar(0)                                   # line style index
-                       self.header.fw.write_int(0x00000000)                            # Flags
+                       self.header.fw.write_int(0)                            # Flags
                        self.header.fw.write_uchar(2)                                   # Light mode
+                       #self.header.fw.write_uchar(3)                                   # Light mode
+
                        self.header.fw.pad(7)                                           # Reserved
-                       self.header.fw.write_uint(-1)                                   # Packed color
-                       self.header.fw.write_uint(-1)                                   # Packed alt color
+                       self.header.fw.write_uint(0)                                   # Packed color
+                       self.header.fw.write_uint(0)                                   # Packed alt color
                        self.header.fw.write_short(-1)                                  # Tex map index
                        self.header.fw.write_short(0)                                   # Reserved
                        self.header.fw.write_uint(face_desc.color_index)                # Color index
@@ -473,7 +949,24 @@ class BlenderMesh(Node):
                        self.header.fw.write_short(-1)                                  # Shader index
 
                        self.write_longid(face_name)
-
+                       
+                       
+                       #Write Multitexture field if appropriate
+                       mtex = len(face_desc.mtex)
+                       if mtex:
+                               uvmask = 0
+                               for layername in face_desc.mtex:
+                                       mask = mtexmasks[tex_layers.index(layername)-1]
+                                       uvmask |= mask
+                               self.header.fw.write_ushort(52)                                                                 # MultiTexture Opcode
+                               self.header.fw.write_ushort(8 + (mtex * 8))             # Length
+                               self.header.fw.write_uint(uvmask)                                                               # UV mask
+                               for i in xrange(mtex):
+                                       self.header.fw.write_ushort(face_desc.images[i])                        # Tex pattern index
+                                       self.header.fw.write_ushort(0)                                                          # Tex effect
+                                       self.header.fw.write_ushort(0)                                                          # Tex Mapping index
+                                       self.header.fw.write_ushort(0)                                                          # Tex data. User defined
+                       
                        self.write_push()
 
                        # Vertex list record
@@ -484,72 +977,95 @@ class BlenderMesh(Node):
                        for vert_index in face_desc.vertex_index_lst:
                                # Offset into vertex palette
                                self.header.fw.write_int(vert_index*64+8)
-
+                       
+                       #UV list record
+                       if mtex:
+                               #length = 8 + (numverts * multitex * 8)
+                               self.header.fw.write_ushort(53)                                                                 # UV List Ocode
+                               self.header.fw.write_ushort(8 + (num_verts*mtex*8))                             # Record Length
+                               self.header.fw.write_uint(uvmask)                                                               # UV mask
+                               for i, vert_index in enumerate(face_desc.vertex_index_lst):
+                                       for uv in face_desc.uvlayer[i]:
+                                               self.header.fw.write_float(uv[0])                                               #U coordinate
+                                               self.header.fw.write_float(uv[1])                                               #V coordinate                           
                        self.write_pop()
+               #clean up faces at the end of meshes....
+               if sublevel:
+                       self.header.fw.write_short(20)
+                       self.header.fw.write_ushort(4)
+
+       def write_lps(self):
+               # Vertex list record
+               self.write_push()
+               self.header.fw.write_short(72)                        # Vertex list opcode
+               num_verts = len(self.vert_lst)
+               self.header.fw.write_ushort(4*num_verts+4)            # Length of record
 
+               for vert_index in self.vert_lst:
+                       # Offset into vertex palette
+                       self.header.fw.write_int(vert_index*64+8)
+               self.write_pop()
        def write(self):
-               if self.open_flight_type == 'Object':
-                       self.header.fw.write_short(4)               # Object opcode
-                       self.header.fw.write_ushort(28)             # Length of record
-                       self.header.fw.write_string(self.name, 8)   # ASCII ID
-                       self.header.fw.pad(16)
-       
-                       self.write_longid(self.name)
+               self.header.fw.write_short(self.opcode)
+               self.header.fw.write_ushort(recordlen[self.opcode])
+               exportdict = FLT_Records[self.opcode].copy()
+               for key in exportdict.keys():
+                       if self.props.has_key(key):
+                               exportdict[key] = self.props[key]
+
+                if self.opcode == 63 and options.externalspath:
+                               try:
+                                       exportdict['3t200!filename'] = os.path.join(options.externalspath,self.object.DupGroup.name+'.flt')
+                                       self.header.xrefnames.append(self.object.DupGroup.name)
+                               except:
+                                       pass
+               
+               for key in records[self.opcode]:
+                       (type,length,propname) = records[self.opcode][key]
+                       write_prop(self.header.fw,type,exportdict[propname],length)
+               
+               if self.props.has_key('comment'):
+                       self.write_comment(self.props['comment'])
                        
+               self.write_longid(self.name) #fix this!
+               
+               if options.export_transform or self.opcode == 63:
+                       #writing transform matrix....
                        self.write_matrix()
-                       
+
+               if self.opcode == 111:
+                       self.write_lps()
+               elif self.face_lst != [] or self.children:
+                       self.write_push()
                        if self.face_lst != []:
-                               self.write_push()
-               
+                               #self.write_push()
                                self.write_faces()
+                               #self.write_pop()
                
-                               self.write_pop()
-               else:
-                       self.header.fw.write_short(2)               # Group opcode
-                       self.header.fw.write_ushort(44)             # Length of record
-                       self.header.fw.write_string(self.name, 8)   # ASCII ID
-                       self.header.fw.pad(32)
-       
-                       self.write_longid(self.name)
-                       
-                       # Because a group can contain faces as well as children.
-                       self.write_push() 
-                       
-                       self.write_faces()
-                       
-                       for child in self.children:
-                               child.write()
-                       
+                       if self.children:
+                               #self.write_push()
+                               for child in self.children:
+                                       child.write()
+                               #self.write_pop()
                        self.write_pop()
-
-       def __init__(self, parent, header, object, object_lst):
-               Node.__init__(self, parent, header, object, object_lst)
-               self.face_lst = []
-               
-               if self.children:
-                       self.open_flight_type= 'Group'
-               else: # Empty list.
-                       self.open_flight_type = 'Object'
                        
-
-class BlenderEmpty(Node):
-       def write(self):
-               self.header.fw.write_short(2)               # Group opcode
-               self.header.fw.write_ushort(44)             # Length of record
-               self.header.fw.write_string(self.name, 8)   # ASCII ID
-               self.header.fw.pad(32)
-
-               self.write_longid(self.name)
-               
-               self.write_matrix()
+       def __init__(self, parent, header, object,props,type):
+               self.opcode = type #both these next two lines need to be in the node class....
+               self.childtypes = childtypes[self.opcode]
+               Node.__init__(self, parent, header, object,props)
+               self.face_lst = []
+               self.vert_lst = [] #for light points.
+               self.mesh = None
+               self.uvlayer = 0
+               self.flipx = False
+               self.flipy = False
+               self.flipz = False
                
-               if self.children: # != []
-                       self.write_push()
-       
-                       for child in self.children:
-                               child.write()
                                
-                       self.write_pop()
+               if self.object.type == 'Mesh':
+                       self.mesh = self.object.getData(mesh=True)
+                       if(self.mesh.faceUV):
+                               self.uvLayer = len(self.mesh.getUVLayerNames())
 
 class Database(Node):
        def write_header(self):
@@ -568,8 +1084,19 @@ class Database(Node):
                self.fw.write_int(0)            # projection type, 0 = flat earth
                self.fw.pad(30)
                self.fw.write_short(1)          # double precision
-               self.fw.pad(140)
+               self.fw.write_int(100)                  # database origin type
+               self.fw.pad(88)
+               try:
+                       self.fw.write_double(self.header.scene.properties['FLT']['origin lat']) #database origin lattitude
+               except:
+                       self.fw.write_double(0)
+               try:
+                       self.fw.write_double(self.header.scene.properties['FLT']['origin lon']) #database origin longitude
+               except:
+                       self.fw.write_double(0)
+               self.fw.pad(32)
                self.fw.write_int(0)            # ellipsoid model, 0 = WSG 1984
+               
                self.fw.pad(52)
 
        def write_vert_pal(self):
@@ -579,14 +1106,13 @@ class Database(Node):
                self.fw.write_short(67)                             # Vertex palette opcode.
                self.fw.write_short(8)                              # Length of record
                self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything.
-
                # Write records for individual vertices.
                for i in xrange(self.GRR.vertex_count()):
                        desc = self.GRR.request_vertex_desc(i)
                        self.fw.write_short(70)                         # Vertex with color normal and uv opcode.
                        self.fw.write_ushort(64)                        # Length of record
-                       self.fw.write_ushort(0)                         # Color name index
-                       self.fw.write_short(0x2000)                     # Flags set to no color
+                       self.fw.write_ushort(0)                                                 # Color name index
+                       self.fw.write_short(0x20000000)                                 # Flags
                        self.fw.write_double(desc.x)
                        self.fw.write_double(desc.y)
                        self.fw.write_double(desc.z)
@@ -595,16 +1121,19 @@ class Database(Node):
                        self.fw.write_float(desc.nz)
                        self.fw.write_float(desc.u)
                        self.fw.write_float(desc.v)
-                       self.fw.pad(12)
+                       self.fw.pad(4)
+                       self.fw.write_uint(desc.cindex)
+                       self.fw.pad(4)
 
        def write_tex_pal(self):
                if options.verbose >= 2:
                        print 'Writing texture palette.'
                # Write record for texture palette
-               for i in xrange(self.GRR.texture_count()):
+               for i, img in enumerate(self.GRR.texture_lst):
+                       filename = tex_files[img.name]
                        self.fw.write_short(64)                                         # Texture palette opcode.
                        self.fw.write_short(216)                                        # Length of record
-                       self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename
+                       self.fw.write_string(filename, 200) # Filename
                        self.fw.write_int(i)                                            # Texture index
                        self.fw.write_int(0)                                            # X
                        self.fw.write_int(0)                                            # Y
@@ -641,13 +1170,17 @@ class Database(Node):
                self.fw.write_short(32)                     # Color palette opcode.
                self.fw.write_short(4228)                   # Length of record
                self.fw.pad(128)
-               count = self.GRR.color_count()
+               try:
+                       cpalette = self.scene.properties['FLT']['Color Palette']
+               except:
+                       cpalette = defaultp.pal
+               count = len(cpalette)
                for i in xrange(count):
-                       col = self.GRR.request_max_color(i)
-                       self.fw.write_uchar(255)                  # alpha
-                       self.fw.write_uchar(col[2])               # b
-                       self.fw.write_uchar(col[1])               # g
-                       self.fw.write_uchar(col[0])               # r
+                       color = struct.unpack('>BBBB',struct.pack('>I',cpalette[i]))
+                       self.fw.write_uchar(color[3])               # alpha
+                       self.fw.write_uchar(color[2])               # b
+                       self.fw.write_uchar(color[1])               # g
+                       self.fw.write_uchar(color[0])               # r
                self.fw.pad(max(4096-count*4, 0))
 
        def write(self):
@@ -657,66 +1190,428 @@ class Database(Node):
                self.write_mat_pal()
                self.write_col_pal()
 
-               # Wrap everything in a group if it has an object child.
-               if self.has_object_child:
-                       self.header.fw.write_short(2)          # Group opcode
-                       self.header.fw.write_ushort(44)        # Length of record
-                       self.header.fw.write_string('g1', 8)   # ASCII ID
-                       self.header.fw.pad(32)
-               
                self.write_push()
-
-               for child in self.children:
-                       child.write()
-
+               
+               if options.flattenmesh:
+                       self.mnodes.reverse()
+                       for mnode in self.mnodes:
+                               mnode.write_faces()
+               else:
+                       for child in self.children:
+                               child.write()
                self.write_pop()
+       
+       def export_textures(self,texturepath):
+               for i in xrange(self.GRR.texture_count()):
+                       texture = self.GRR.texture_lst[i]
+                       
+                       if options.copy_textures:
+                               filename = os.path.normpath(os.path.join(options.texturespath, os.path.basename(self.GRR.request_texture_filename(i))))
+                       else:
+                               filename = os.path.normpath(self.GRR.request_texture_filename(i))
+                       
+                       tex_files[texture.name] = filename
 
+       def blender_export(self):
+               Node.blender_export(self)
+               self.export_textures(self)
+               return self.xrefnames
        def __init__(self, scene, fw):
                self.fw = fw
+               self.opcode = 1
+               self.childtypes = [73,14,2,63]
                self.scene = scene
-               self.all_objects = list(scene.objects)
-               self.GRR = GlobalResourceRepository()
+               self.childhash = dict()
+               self.parenthash = dict()
+               self.child_objects = list()
+               self.mnodes = list()
+               self.xrefnames = list()
+               for i in self.scene.objects:
+                       self.parenthash[i.name] = list()
+                       self.childhash[i.name] = False
+               for i in self.scene.objects:
+                       if i.parent:
+                               self.childhash[i.parent.name] = True
+                               self.parenthash[i.parent.name].append(i)
+                       else:
+                               self.child_objects.append(i)
 
-               Node.__init__(self, None, self, None, self.all_objects)
+               self.GRR = GlobalResourceRepository()
+               Node.__init__(self, None, self, None,None)
 
-def fs_callback(filename):
-       Blender.Window.WaitCursor(True)
-       
-       if Blender.sys.exists(filename):
-               r = Blender.Draw.PupMenu('Overwrite ' + filename + '?%t|Yes|No')
-               if r != 1:
-                       if options.verbose >= 1:
-                               print 'Export cancelled.'
-                       return
-       
-       time1 = Blender.sys.time() # Start timing
+def write_attribute_files():
+       for imgname in tex_files:
+               blentex = Blender.Image.Get(imgname)
+               exportdict = FLT_Records['Image'].copy()
+               
+               if blentex.properties.has_key('FLT'):
+                       for key in exportdict.keys():
+                               if blentex.properties.has_key(key):
+                                       exportdict[key] = blentex.properties['FLT'][key]
+               
+               # ClampX/Y override
+               if blentex.clampX:
+                       exportdict['11i!WrapU'] = 1
+               if blentex.clampY:
+                       exportdict['12i!WrapV'] = 1 
+               
+               exportdict['16i!Enviorment'] = 0 
+               
+               # File type
+               typecode = 0
+               try:
+                       typestring = os.path.splitext(blentex.getFilename())[1]
+                       
+                       if typestring == '.rgba':
+                               typecode = 5
+                       elif typestring == '.rgb':
+                               typecode = 4
+                       elif typestring == '.inta':
+                               typecode = 3
+                       elif typestring == '.int':
+                               typecode = 2
+               except:
+                       pass
+               
+               exportdict['7i!File Format'] = typecode
+
+               fw = FltOut(tex_files[imgname] + '.attr')
+               size = blentex.getSize()
+               fw.write_int(size[0])
+               fw.write_int(size[1])
+               for key in records['Image']:
+                       (type,length,propname) = records['Image'][key]
+                       write_prop(fw,type,exportdict[propname],length)
+               fw.close_file()
+
+#globals used by the scene export function
+exportlevel = None
+xrefsdone = None
+
+def dbexport_internal(scene):
+       global exportlevel
+       global xrefsdone
+       global options
+
+       if exportlevel == 0 or not options.externalspath:
+               fname = os.path.join(options.basepath,scene.name + '.flt')
+       else:
+               fname = os.path.join(options.externalspath,scene.name + '.flt')
        
-       fw = FltOut(filename)
-
-       db = Database(Blender.Scene.GetCurrent(), fw)
+       fw = FltOut(fname)
+       db = Database(scene,fw)
        
        if options.verbose >= 1:
-               print 'Pass 1: Exporting from Blender.\n'
-       
-       db.blender_export()
+               print 'Pass 1: Exporting ', scene.name,'.flt from Blender.\n'
        
+       xreflist = db.blender_export()
        if options.verbose >= 1:
-               print 'Pass 2: Writing %s\n' % filename
-               
+               print 'Pass 2: Writing %s\n' % fname
        db.write()
-
        fw.close_file()
+       
+       if options.doxrefs:
+               for xname in xreflist:
+                       try:
+                               xrefscene = Blender.Scene.Get(xname)
+                       except:
+                               xrefscene = None
+                       if xrefscene and xname not in xrefsdone:
+                               xrefsdone.append(xname)
+                               exportlevel+=1
+                               dbexport_internal(xrefscene)
+                               exportlevel-=1
+       return fname
+#main database export function
+def dbexport():
+       global exportlevel
+       global xrefsdone
+       exportlevel = 0
+       xrefsdone = list()
+       
+       Blender.Window.WaitCursor(True)
+       time1 = Blender.sys.time() # Start timing
+       
        if options.verbose >= 1:
+               print '\nOpenFlight Exporter'
+               print 'Version:', __version__
+               print 'Author: Greg MacDonald, Geoffrey Bantle'
+               print __url__[2]
+               print
+       
+       fname = dbexport_internal(Blender.Scene.GetCurrent())
+       if options.verbose >=1:
                print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1)
-               
        Blender.Window.WaitCursor(False)
+       
+       #optional: Copy textures
+       if options.copy_textures:
+               for imgname in tex_files:
+                       #Check to see if texture exists in target directory
+                       if not os.path.exists(tex_files[imgname]):
+                               #Get original Blender file name
+                               origpath = Blender.sys.expandpath(Blender.Image.Get(imgname).getFilename())
+                               #copy original to new
+                               shutil.copyfile(origpath,tex_files[imgname])
+       
+       #optional: Write attribute files
+       if options.write_attrib_files:
+               write_attribute_files()
+
+       if options.xapp:
+               cmd= options.xappath + " " + fname 
+               status = os.system(cmd)
+       
+
+#Begin UI code
+FLTExport = None
+FLTClose = None
+FLTLabel = None
+
+FLTBaseLabel = None
+FLTTextureLabel = None
+FLTXRefLabel = None
+
+FLTBaseString = None
+FLTTextureString = None
+FLTXRefString = None
+
+FLTBasePath = None
+FLTTexturePath = None
+FLTXRefPath = None
+
+FLTShadeExport = None
+FLTShadeDefault = None
+
+FLTCopyTex = None
+FLTDoXRef = None
+FLTGlobal = None
+
+FLTScale = None
+
+FLTXAPP = None
+FLTXAPPath = None
+FLTXAPPString = None
+FLTXAPPLabel = None
+FLTXAPPChooser = None
+
+FLTAttrib = None
+
+def setshadingangle(ID,val):
+       global options
+       options.shading_default = val
+def setBpath(fname):
+       global options
+       options.basepath = os.path.dirname(fname)
+       #update xref and textures path too....
+       if(os.path.exists(os.path.join(options.basepath,'externals'))):
+               options.externalspath = os.path.join(options.basepath,'externals')
+       if(os.path.exists(os.path.join(options.texturespath,'textures'))):
+               options.texturespath = os.path.join(options.basepath,'textures')
+def setexportscale(ID,val):
+       global options
+       options.scale = val
+
+def setTpath(fname):
+       global options
+       options.texturespath = os.path.dirname(fname)
+def setXpath(fname):
+       global options
+       options.externalspath = os.path.dirname(fname)
+def setXApath(fname):
+       global options
+       options.xappath = fname
+       d = dict()
+       d['xappath'] = options.xappath
+       Blender.Registry.SetKey('flt_export', d, 1) 
+def event(evt, val):
+       x = 1
+def but_event(evt):
+       global options
+       
+       global FLTExport
+       global FLTClose 
+       global FLTLabel
+       
+       global FLTBaseLabel
+       global FLTTextureLabel
+       global FLTXRefLabel
+
+       global FLTBaseString
+       global FLTTextureString
+       global FLTXRefString
+       
+       global FLTBasePath
+       global FLTTexturePath
+       global FLTXRefPath
+       
+       global FLTShadeExport
+       global FLTShadeDefault
+       
+       global FLTCopyTex
+       global FLTDoXRef
+       global FLTGlobal
+       
+       global FLTScale
+       
+       
+       global FLTXAPP
+       global FLTXAPPath
+       global FLTXAPPString
+       global FLTXAPPLabel     
+       global FLTXAPPChooser
+
+       global FLTAttrib
+       
+       
+       
+       #choose base path for export
+       if evt == 4:
+               Blender.Window.FileSelector(setBpath, "DB Root", options.basepath)
+               
+       #choose XREF path
+       if evt == 6:
+               Blender.Window.FileSelector(setXpath,"DB Externals",options.externalspath)
+
+       #choose texture path
+       if evt == 8:
+               Blender.Window.FileSelector(setTpath,"DB Textures",options.texturespath)
+
+       #export shading toggle
+       if evt == 9:
+               options.export_shading = FLTShadeExport.val
+       #export Textures
+       if evt == 11:
+               options.copy_textures = FLTCopyTex.val
+       #export XRefs
+       if evt == 13:
+               options.doxrefs = FLTDoXRef.val
+       #export Transforms
+       if evt == 12:
+               options.export_transform = FLTGlobal.val
+               
+       if evt == 14:
+               options.xapp = FLTXAPP.val
+       if evt == 16:
+               Blender.Window.FileSelector(setXApath,"External Application",options.xappath)
+       if evt == 20:
+               options.write_attrib_files = FLTAttrib.val
+       
+       #Export DB
+       if evt == 1:
+               dbexport()
+       
+       #exit
+       if evt == 2:
+               Draw.Exit()
+
+from Blender.BGL import *
+from Blender import Draw
+def gui():
+       
+       global options
+       
+       global FLTExport
+       global FLTClose 
+       global FLTLabel
+       
+       global FLTBaseLabel
+       global FLTTextureLabel
+       global FLTXRefLabel
+
+       global FLTBaseString
+       global FLTTextureString
+       global FLTXRefString
+       
+       global FLTBasePath
+       global FLTTexturePath
+       global FLTXRefPath
+       
+       global FLTShadeExport
+       global FLTShadeDefault
+       
+       global FLTCopyTex
+       global FLTDoXRef
+       global FLTGlobal
+       
+       global FLTScale
+       
+       global FLTXAPP
+       global FLTXAPPath
+       global FLTXAPPString
+       global FLTXAPPLabel
+       global FLTXAPPChooser   
+       
+       global FLTAttrib
+       
+       glClearColor(0.880,0.890,0.730,1.0 )
+       glClear(GL_COLOR_BUFFER_BIT)
+       
+       areas = Blender.Window.GetScreenInfo()
+       curarea = Blender.Window.GetAreaID()
+       curRect = None
+       
+       for area in areas:
+               if area['id'] == curarea:
+                       curRect = area['vertices']
+                       break
+       
+       width = curRect[2] - curRect[0]
+       height = curRect[3] - curRect[1]
+       #draw from top to bottom....
+       cx = 50
+       #Draw Title Bar...
+       #glRasterPos2d(cx, curRect[3]-100)
+       #FLTLabel = Draw.Text("FLT Exporter V2.0",'large')
+       cy = height - 80
+       
+       #base path
+       FLTBaseLabel = Draw.Label("Base Path:",cx,cy,100,20)
+       FLTBaseString = Draw.String("",3,cx+100,cy,300,20,options.basepath,255,"Folder to export to")
+       FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder")
+       
+       cy = cy-40
+       
+       #externals path
+       FLTXRefLabel = Draw.Label("XRefs:",cx,cy,100,20)
+       FLTXRefString = Draw.String("",5,cx+100,cy,300,20,options.externalspath,255,"Folder for external references")
+       FLTXRefChooser = Draw.PushButton("...",6,cx+400,cy,20,20,"Choose Folder")
+       cy = cy-40
+       #Textures path
+       FLTTextureLabel = Draw.Label("Textures:",cx,cy,100,20)
+       FLTTextureString = Draw.String("",7,cx+100,cy,300,20,options.texturespath,255,"Folder for texture files")
+       FLTTextureChooser = Draw.PushButton("...",8,cx+400,cy,20,20,"Choose Folder")
+       cy=cy-40
+       #External application path
+       FLTXAPPLabel = Draw.Label("XApp:",cx,cy,100,20)
+       FLTXAPPString = Draw.String("",15,cx+100,cy,300,20,options.xappath,255,"External application to launch when done")
+       FLTXAPPChooser = Draw.PushButton("...",16,cx+400, cy,20,20,"Choose Folder")
+       
+       cy = cy-60
+       #Shading Options
+       FLTShadeExport = Draw.Toggle("Default Shading",9,cx,cy,100,20,options.export_shading,"Turn on export of custom shading")
+       FLTShadDefault = Draw.Number("",10,cx + 120,cy,100,20,options.shading_default,0.0,180.0,"Default shading angle for objects with no custom shading assigned",setshadingangle)
+       
+       cy = cy-40
+       FLTScale = Draw.Number("Export Scale",14,cx,cy,220,20,options.scale,0.0,100.0,"Export scaling factor",setexportscale)
+       
+       cy = cy-40
+       #misc Options
+       FLTCopyTex = Draw.Toggle("Copy Textures",11,cx,cy,220,20,options.copy_textures,"Copy textures to folder indicated above")
+       cy = cy-40
+       FLTGlobal = Draw.Toggle("Export Transforms",12,cx,cy,220,20,options.export_transform,"If unchecked, Global coordinates are used (recommended)")
+       cy = cy-40
+       FLTDoXRef = Draw.Toggle("Export XRefs", 13,cx,cy,220,20,options.doxrefs,"Export External references (only those below current scene!)")
+       cy = cy-40
+       FLTXAPP = Draw.Toggle("Launch External App", 14, cx,cy,220,20,options.xapp,"Launch External Application on export")
+       cy = cy-40
+       FLTAttrib = Draw.Toggle("Write Attribute Files", 20, cx, cy, 220,20,options.write_attrib_files, "Write Texture Attribute files")
+       #FLTXAPPATH = Draw.String("",15,cx,cy,300,20,options.xappath,255,"External application path")
+       
 
-if options.verbose >= 1:
-       print '\nOpenFlight Exporter'
-       print 'Version:', __version__
-       print 'Author: Greg MacDonald'
-       print __url__[2]
-       print
+       #Draw export/close buttons
+       FLTExport = Draw.PushButton("Export",1,cx,20,100,20,"Export to FLT")
+       FLTClose = Draw.PushButton("Close", 2, cx+120,20,100,20,"Close window")
        
-fname = Blender.sys.makename(ext=".flt")
-Blender.Window.FileSelector(fs_callback, "Export OpenFlight v16.0", fname)
+
+Draw.Register(gui,event,but_event)
\ No newline at end of file
index 442c9728e911fa838eebdf35d7cd499493d33d50..4a9b86c45d242441c3a6c6b0bc0929880c707ad8 100644 (file)
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
+__bpydoc__ ="""\
+File read/write module used by OpenFlight I/O and tool scripts. OpenFlight is a
+registered trademark of MultiGen-Paradigm, Inc.
+"""
+
 import Blender
 from struct import *
 import re
@@ -199,7 +204,9 @@ class FltOut:
         self.file.close()
 
     def __init__(self, filename):
-        self.file = open(filename, 'wb')
+               self.file = open(filename, 'wb')
+               self.filename = filename
+               
 
 class FileFinder:
     def add_file_to_search_path(self, filename):
index ca0db650447d0c684ce60bde59a6b5f851d88aa6..220fc9f355c2439044f632a63057964314275b92 100644 (file)
@@ -1,72 +1,26 @@
 #!BPY
 """ Registration info for Blender menus:
 Name: 'OpenFlight (.flt)...'
-Blender: 238
+Blender: 245
 Group: 'Import'
 Tip: 'Import OpenFlight (.flt)'
 """
 
-__author__ = "Greg MacDonald, Campbell Barton"
-__version__ = "1.2 10/20/05"
+__author__ = "Greg MacDonald, Campbell Barton, Geoffrey Bantle"
+__version__ = "2.0 11/21/07"
 __url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/")
 __bpydoc__ = """\
 This script imports OpenFlight files into Blender. OpenFlight is a
 registered trademark of MultiGen-Paradigm, Inc.
 
-Run from "File->Import" menu.
-
-Options are available from Blender's "Scripts Config Editor," accessible through
-the "Scripts->System" menu from the scripts window.
-
-All global_prefs are toggle switches that let the user choose what is imported. Most
-are straight-forward, but one option could be a source of confusion. The 
-"Diffuse Color From Face" option when set pulls the diffuse color from the face
-colors. Otherwise the diffuse color comes from the material. What may be
-confusing is that this global_prefs only works if the "Diffuse Color" option is set.
-
-New Features:<br>
-* Importer is 14 times faster.<br>
-* External triangle module is no longer required, but make sure the importer
-has a 3d View screen open while its running or triangulation won't work.<br>
-* Should be able to import all versions of flight files.
-
-Features:<br>
-* Heirarchy retained.<br>
-* First texture imported.<br>
-* Colors imported from face or material.<br>
-* LOD seperated out into different layers.<br>
-* Asks for location of unfound textures or external references.<br>
-* Searches Blender's texture directory in the user preferences panel.<br>
-* Triangles with more than 4 verts are triangulated if the Triangle python
-module is installed.<br>
-* Matrix transforms imported.<br>
-* External references to whole files are imported.
-
-Things To Be Aware Of:<br>
-* Each new color and face attribute creates a new material and there are only a maximum of 16
-materials per object.<br>
-* For triangulated faces, normals must be recomputed outward manually by typing
-CTRL+N in edit mode.<br>
-* You can change global_prefs only after an initial import.<br>
-* External references are imported as geometry and will be exported that way.<br>
-* A work around for not using the Triangle python module is to simply to 
-triangulate in Creator before importing. This is only necessary if your
-model contains 5 or more vertices.<br>
-* You have to manually blend the material color with the texture color.
-
-What's Not Handled:<br>
-* Special texture repeating modes.<br>
-* Replications and instancing.<br>
-* Comment and attribute fields.<br>
-* Light points.<br>
-* Animations.<br>
-* External references to a node within a file.<br>
-* Multitexturing.<br>
-* Vetex colors.<br>
+Feature overview and more availible at:
+http://wiki.blender.org/index.php/Scripts/Manual/Import/openflight_flt
+
+Note: This file is a grab-bag of old and new code. It needs some cleanup still.
 """
 
 # flt_import.py is an OpenFlight importer for blender.
-# Copyright (C) 2005 Greg MacDonald
+# Copyright (C) 2005 Greg MacDonald, 2007  Blender Foundation
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -87,15 +41,33 @@ import os
 import BPyMesh
 import BPyImage
 import flt_filewalker 
+import flt_properties
+reload(flt_properties)
+from flt_properties import *
 
-Vector= Blender.Mathutils.Vector
+#Globals. Should Clean these up and minimize their usage.
 
-def col_to_gray(c):
-       return 0.3*c[0] + 0.59*c[1] + 0.11*c[2]
+typecodes = ['c','C','s','S','i','I','f','d','t']
+records = dict()
+
+FLTBaseLabel = None
+FLTBaseString = None
+FLTBaseChooser = None
+FLTExport = None
+FLTClose = None
+FLTDoXRef = None
+FLTScale = None
+FLTShadeImport = None
+FLTAttrib = None
+
+Vector= Blender.Mathutils.Vector
+FLOAT_TOLERANCE = 0.01
 
+FF = flt_filewalker.FileFinder()
+current_layer = 0x01
 
 global_prefs = dict()
-global_prefs['verbose']= 1
+global_prefs['verbose']= 4
 global_prefs['get_texture'] = True
 global_prefs['get_diffuse'] = True
 global_prefs['get_specular'] = False
@@ -105,8 +77,41 @@ global_prefs['get_ambient'] = False
 global_prefs['get_shininess'] = True
 global_prefs['color_from_face'] = True
 global_prefs['fltfile']= ''
+global_prefs['smoothshading'] = 1
+global_prefs['doxrefs'] = 1
+global_prefs['scale'] = 1.0
+global_prefs['attrib'] = 0
 msg_once = False
 
+throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63,111] # Opcodes that indicate its time to return control to parent.
+do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125]
+
+#Process FLT record definitions
+for record in FLT_Records:
+       props = dict()
+       for prop in FLT_Records[record]:
+               position = ''
+               slice = 0
+               (format,name) = prop.split('!')
+               for i in format:
+                       if i not in typecodes:
+                               position = position + i
+                               slice = slice + 1
+                       else:
+                               break
+               type = format[slice:]
+               length = type[1:] 
+               if len(length) == 0:
+                       length = 1
+               else:
+                       type = type[0]
+                       length = int(length)
+               
+               props[int(position)] = (type,length,prop)
+       records[record] = props
+
+def col_to_gray(c):
+       return 0.3*c[0] + 0.59*c[1] + 0.11*c[2]
 class MaterialDesc:
        # Was going to use int(f*1000.0) instead of round(f,3), but for some reason
        # round produces better results, as in less dups.
@@ -185,16 +190,14 @@ class VertexDesc:
                self.y = 0.0
                self.z = 0.0
                
-               ''' # IGNORE_NORMALS
+               
                self.nx = 0.0
-               self.ny = 1.0
+               self.ny = 0.0
                self.nz = 0.0
-               '''
+               
                self.uv= Vector(0,0)
-               self.r = 1.0
-               self.g = 1.0
-               self.b = 1.0
-               self.a = 1.0        
+               self.cindex = 127 #default/lowest
+               self.cnorm = False        
 
 class LightPointAppDesc:
        def make_key(self):
@@ -222,7 +225,7 @@ class LightPointAppDesc:
                self.props.update({'LOD scale': 0.0})
 
 class GlobalResourceRepository:
-       def request_lightpoint_app(self, desc):
+       def request_lightpoint_app(self, desc, scene):
                match = self.light_point_app.get(desc.make_key())
                
                if match:
@@ -231,7 +234,7 @@ class GlobalResourceRepository:
                        # Create empty and fill with properties.
                        name = desc.props['type'] + ': ' + desc.props['id']
                        object = Blender.Object.New('Empty', name)
-                       scene.link(object)
+                       scene.objects.link(object)
                        object.Layers= current_layer
                        object.sel= 1
                        
@@ -306,6 +309,9 @@ class GlobalResourceRepository:
                return tex
                
        def __init__(self):
+               
+               #list of scenes xrefs belong to.
+               self.xrefs = dict()
                # material
                self.mat_dict = dict()
                mat_lst = Blender.Material.Get()
@@ -341,108 +347,6 @@ class GlobalResourceRepository:
                # light point
                self.light_point_app = dict()
                
-# Globals
-GRR = GlobalResourceRepository()
-FF = flt_filewalker.FileFinder()
-scene = Blender.Scene.GetCurrent() # just hope they dont chenge scenes once the file selector pops up.
-current_layer = 0x01
-
-
-# Opcodes that indicate its time to return control to parent.
-throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63]
-do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125]
-
-opcode_name = { 0: 'db',
-                               1: 'head',
-                               2: 'grp',
-                               4: 'obj',
-                               5: 'face',
-                               10: 'push',
-                               11: 'pop',
-                               14: 'dof',
-                               19: 'push sub',
-                               20: 'pop sub',
-                               21: 'push ext',
-                               22: 'pop ext',
-                               23: 'cont',
-                               31: 'comment',
-                               32: 'color pal',
-                               33: 'long id',
-                               49: 'matrix',
-                               50: 'vector',
-                               52: 'multi-tex',
-                               53: 'uv lst',
-                               55: 'bsp',
-                               60: 'rep',
-                               61: 'inst ref',
-                               62: 'inst def',
-                               63: 'ext ref',
-                               64: 'tex pal',
-                               67: 'vert pal',
-                               68: 'vert w col',
-                               69: 'vert w col & norm',
-                               70: 'vert w col, norm & uv',
-                               71: 'vert w col & uv',
-                               72: 'vert lst',
-                               73: 'lod',
-                               74: 'bndin box',
-                               76: 'rot edge',
-                               78: 'trans',
-                               79: 'scl',
-                               80: 'rot pnt',
-                               81: 'rot and/or scale pnt',
-                               82: 'put',
-                               83: 'eyepoint & trackplane pal',
-                               84: 'mesh',
-                               85: 'local vert pool',
-                               86: 'mesh prim',
-                               87: 'road seg',
-                               88: 'road zone',
-                               89: 'morph vert lst',
-                               90: 'link pal',
-                               91: 'snd',
-                               92: 'rd path',
-                               93: 'snd pal',
-                               94: 'gen matrix',
-                               95: 'txt',
-                               96: 'sw',
-                               97: 'line styl pal',
-                               98: 'clip reg',
-                               100: 'ext',
-                               101: 'light src',
-                               102: 'light src pal',
-                               103: 'reserved',
-                               104: 'reserved',
-                               105: 'bndin sph',
-                               106: 'bndin cyl',
-                               107: 'bndin hull',
-                               108: 'bndin vol cntr',
-                               109: 'bndin vol orient',
-                               110: 'rsrvd',
-                               111: 'light pnt',
-                               112: 'tex map pal',
-                               113: 'mat pal',
-                               114: 'name tab',
-                               115: 'cat',
-                               116: 'cat dat',
-                               117: 'rsrvd',
-                               118: 'rsrvd',
-                               119: 'bounding hist',
-                               120: 'rsrvd',
-                               121: 'rsrvd',
-                               122: 'push attrib',
-                               123: 'pop attrib',
-                               124: 'rsrvd',
-                               125: 'rsrvd',
-                               126: 'curv',
-                               127: 'road const',
-                               128: 'light pnt appear pal',
-                               129: 'light pnt anim pal',
-                               130: 'indexed lp',
-                               131: 'lp sys',
-                               132: 'indx str',
-                               133: 'shdr pal'}
-
 class Handler:
        def in_throw_back_lst(self, opcode):
                return opcode in self.throw_back_lst
@@ -487,11 +391,11 @@ class Node:
                        print '-', self.props['comment'],
 
                        print
-
+                
                for child in self.children:
                        child.blender_import()
-               
-               # Import comment.
+                       
+# Import comment.
 #        if self.props['comment'] != '':
 #            name = 'COMMENT: ' + self.props['id']
 #            t = Blender.Text.New(name)
@@ -568,8 +472,8 @@ class Node:
                                else:
                                        if global_prefs['verbose'] >= 3:
                                                print p + ' ignored'
-                                       elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name:
-                                               print opcode_name[opcode], 'not handled'                        
+                                       elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name:   
+                                               print 'not handled'
                                        
        def get_level(self):
                return self.level
@@ -581,7 +485,19 @@ class Node:
        def parse_comment(self):
                self.props['comment'] = self.header.fw.read_string(self.header.fw.get_length()-4)
                return True
-
+       
+       def parse_record(self):
+               self.props['type'] = self.opcode
+               props = records[self.opcode]
+               propkeys = props.keys()
+               propkeys.sort()
+               for position in propkeys:
+                       (type,length,name) = props[position]
+                       self.props[name] = read_prop(self.header.fw,type,length)
+               try: #remove me!
+                       self.props['id'] = self.props['3t8!id']
+               except:
+                       pass
        def __init__(self, parent, header):
                self.root_handler = Handler()
                self.child_handler = Handler()
@@ -647,20 +563,16 @@ class VertexPalette(Node):
                return v
 
        def parse_vertex_post_common(self, v):
-               if not v.flags & 0x2000: # 0x2000 = no color
-                       if v.flags & 0x1000: # 0x1000 = packed color
-                               v.a = self.header.fw.read_uchar()
-                               v.b = self.header.fw.read_uchar()
-                               v.g = self.header.fw.read_uchar()
-                               v.r = self.header.fw.read_uchar()
-                       else:
-                               self.header.fw.read_ahead(4)
-                       
-                       color_index = self.header.fw.read_uint()
-                       v.r, v.g, v.b, v.a= self.header.get_color(color_index)
-               
+               #if not v.flags & 0x2000: # 0x2000 = no color
+                       #if v.flags & 0x1000: # 0x1000 = packed color
+                       #       v.a = self.header.fw.read_uchar()
+                       #       v.b = self.header.fw.read_uchar()
+                       #       v.g = self.header.fw.read_uchar()
+                       #       v.r = self.header.fw.read_uchar()
+                       #else:
+               self.header.fw.read_ahead(4) #skip packed color
+               v.cindex = self.header.fw.read_uint()
                self.vert_desc_lst.append(v)
-               
                return True
 
        def parse_vertex_c(self):
@@ -672,16 +584,10 @@ class VertexPalette(Node):
 
        def parse_vertex_cn(self):
                v = self.parse_vertex_common()
-               
-               '''
+               v.cnorm = True
                v.nx = self.header.fw.read_float()
                v.ny = self.header.fw.read_float()
                v.nz = self.header.fw.read_float()
-               '''
-               # Just to advance
-               self.header.fw.read_float()
-               self.header.fw.read_float()
-               self.header.fw.read_float()
                
                self.parse_vertex_post_common(v)
                
@@ -698,15 +604,10 @@ class VertexPalette(Node):
 
        def parse_vertex_cnuv(self):
                v = self.parse_vertex_common()
-               '''
+               v.cnorm = True
                v.nx = self.header.fw.read_float()
                v.ny = self.header.fw.read_float()
                v.nz = self.header.fw.read_float()
-               '''
-               # Just to advance
-               self.header.fw.read_float()
-               self.header.fw.read_float()
-               self.header.fw.read_float()
                
                v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float()
 
@@ -721,89 +622,370 @@ class InterNode(Node):
        def __init__(self):
                self.object = None
                self.mesh = None
-               self.isMesh = False
+               self.hasMesh = False
                self.faceLs= []
                self.matrix = None
-       
-       def blender_import_my_faces(self):
+               self.vis = True
+               self.hasmtex = False
+               self.uvlayers = dict()
+               self.blayernames = dict()
+               self.subfacelevel = 0
+               
+               mask = 2147483648
+               for i in xrange(7):
+                       self.uvlayers[mask] = False
+                       mask = mask / 2
                
+
+       def blender_import_my_faces(self):
+
                # Add the verts onto the mesh
-               mesh = self.mesh
                blender_verts= self.header.vert_pal.blender_verts
                vert_desc_lst= self.header.vert_pal.vert_desc_lst
                
-               vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices]
-               
-               mesh.verts.extend([blender_verts[i] for i in vert_list])
-               
+               vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] #splitting faces apart. Is this a good thing?
+               face_edges= []
+               face_verts= []
+               self.mesh.verts.extend([blender_verts[i] for i in vert_list])
                
                new_faces= []
                new_faces_props= []
                ngon= BPyMesh.ngon
                vert_index= 1
+               
+               #add vertex color layer for baked face colors.
+               self.mesh.addColorLayer("FLT_Fcol")
+               self.mesh.activeColorLayer = "FLT_Fcol"
+               
+               FLT_OrigIndex = 0
                for flt_face in self.faceLs:
-                       material_index= flt_face.blen_mat_idx
-                       image= flt_face.blen_image
-                       
+                       if flt_face.tex_index != -1:
+                               try:
+                                       image= self.header.tex_pal[flt_face.tex_index][1]
+                               except KeyError:
+                                       image= None
+                       else:
+                               image= None
                        face_len= len(flt_face.indices)
                        
+                       #create dummy uvert dicts
+                       if len(flt_face.uverts) == 0:
+                               for i in xrange(face_len):
+                                       flt_face.uverts.append(dict())
+                       #May need to patch up MTex info
+                       if self.hasmtex:
+                               #For every layer in mesh, there should be corresponding layer in the face
+                               for mask in self.uvlayers.keys():
+                                       if self.uvlayers[mask]:
+                                               if not flt_face.uvlayers.has_key(mask): #Does the face have this layer?
+                                                       #Create Layer info for this face
+                                                       flt_face.uvlayers[mask] = dict()
+                                                       flt_face.uvlayers[mask]['texture index'] = -1
+                                                       flt_face.uvlayers[mask]['texture enviorment'] = 3
+                                                       flt_face.uvlayers[mask]['texture mapping'] = 0
+                                                       flt_face.uvlayers[mask]['texture data'] = 0
+                                                       
+                                                       #now go through and create dummy uvs for this layer
+                                                       for uvert in flt_face.uverts:
+                                                                       uv = Vector(0.0,0.0)
+                                                                       uvert[mask] = uv
+
                        # Get the indicies in reference to the mesh.
-                       
                        uvs= [vert_desc_lst[j].uv for j in flt_face.indices]
-                       if face_len <=4: # tri or quad
+                       if face_len == 1:
+                               pass
+                       elif face_len == 2:
+                               face_edges.append((vert_index, vert_index+1))
+                       elif flt_face.props['draw type'] == 2 or flt_face.props['draw type'] == 3:
+                               i = 0
+                               while i < (face_len-1):
+                                       face_edges.append((vert_index + i, vert_index + i + 1))
+                                       i = i + 1
+                               if flt_face.props['draw type'] == 2:
+                                       face_edges.append((vert_index + i,vert_index)) 
+                       elif face_len == 3 or face_len == 4: # tri or quad
+                               #if face_len == 1:
+                               #       pass
+                               #if face_len == 2:
+                               #       face_edges.append((vert_index, vert_index+1))
                                new_faces.append( [i+vert_index for i in xrange(face_len)] )
-                               new_faces_props.append((material_index, image, uvs))
+                               new_faces_props.append((None, image, uvs, flt_face.uverts, flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,0, flt_face.subfacelevel))
                        
                        else: # fgon
                                mesh_face_indicies = [i+vert_index for i in xrange(face_len)]
-                               tri_ngons= ngon(mesh, mesh_face_indicies)
+                               tri_ngons= ngon(self.mesh, mesh_face_indicies)
                                new_faces.extend([ [mesh_face_indicies[t] for t in tri] for tri in tri_ngons])
-                               new_faces_props.extend( [ (material_index, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]) ) for tri in tri_ngons ] )
+                               new_faces_props.extend( [ (None, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]), [flt_face.uverts[tri[0]], flt_face.uverts[tri[1]], flt_face.uverts[tri[2]]], flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,1, flt_face.subfacelevel) for tri in tri_ngons ])
                        
                        vert_index+= face_len
-               
-               mesh.faces.extend(new_faces)
-               
-               try:    mesh.faceUV= True
-               except: pass
-               
-               for i, f in enumerate(mesh.faces):
-                       f.mat, f.image, f.uv= new_faces_props[i]
-       
+                       FLT_OrigIndex+=1
+               
+               self.mesh.faces.extend(new_faces)
+               self.mesh.edges.extend(face_edges)
+               
+               #add in the FLT_ORIGINDEX layer
+               if len(self.mesh.faces):
+                       try:    self.mesh.faceUV= True
+                       except: pass
+               
+                       if self.mesh.faceUV == True:
+                               self.mesh.renameUVLayer(self.mesh.activeUVLayer, 'Layer0')
+               
+                       #create name layer for faces
+                       self.mesh.faces.addPropertyLayer("FLT_ID",Blender.Mesh.PropertyTypes["STRING"])
+                       #create layer for face color indices
+                       self.mesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"])
+                       #create index layer for faces. This is needed by both FGONs and subfaces
+                       self.mesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"])
+                       #create temporary FGON flag layer. Delete after remove doubles
+                       self.mesh.faces.addPropertyLayer("FLT_FGON",Blender.Mesh.PropertyTypes["INT"])
+                       self.mesh.faces.addPropertyLayer("FLT_SFLEVEL", Blender.Mesh.PropertyTypes["INT"])
+                       
+                       for i, f in enumerate(self.mesh.faces):
+                               f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"] #fix this!
+                               f.mode |= Blender.Mesh.FaceModes["LIGHT"]
+                               props = new_faces_props[i]
+                               #f.mat = props[0]
+                               f.image = props[1]
+                               f.uv = props[2]
+                               #set vertex colors
+                               color = self.header.get_color(props[5])
+                               if not color:
+                                       color = [255,255,255,255]
+                               for mcol in f.col:
+                                       mcol.a = color[3]
+                                       mcol.r = color[0]
+                                       mcol.g = color[1]
+                                       mcol.b = color[2]
+                               
+                               f.setProperty("FLT_SFLEVEL", props[9])
+                               f.setProperty("FLT_ORIGINDEX",i)
+                               f.setProperty("FLT_ID",props[6]['id'])
+                               #if props[5] > 13199:
+                               #       print "Warning, invalid color index read in! Using default!"
+                               #       f.setProperty("FLT_COL",127)
+                               #else:
+                               if(1):                  #uh oh....
+                                       value = struct.unpack('>i',struct.pack('>I',props[5]))[0]
+                                       f.setProperty("FLT_COL",value)
+                               
+                               #if props[8]: 
+                               #       f.setProperty("FLT_FGON",1)
+                               #else:
+                               #       f.setProperty("FLT_FGON",0)
+                       
+                       
+                       #Create multitex layers, if present.
+                       actuvlayer = self.mesh.activeUVLayer
+                       if(self.hasmtex):
+                               #For every multi-tex layer, we have to add a new UV layer to the mesh
+                               for i,mask in enumerate(reversed(sorted(self.uvlayers))):
+                                       if self.uvlayers[mask]:
+                                               self.blayernames[mask] = "Layer" + str(i+1)
+                                               self.mesh.addUVLayer(self.blayernames[mask])
+                               
+                               #Cycle through availible multi-tex layers and add face UVS
+                               for mask in self.uvlayers:
+                                       if self.uvlayers[mask]:
+                                               self.mesh.activeUVLayer = self.blayernames[mask]
+                                               for j, f in enumerate(self.mesh.faces):
+                                                       f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"]
+                                                       f.mode |= Blender.Mesh.FaceModes["LIGHT"]
+                                                       props = new_faces_props[j]
+                                                       uvlayers = props[4]
+                                                       if uvlayers.has_key(mask): #redundant
+                                                               uverts = props[3]
+                                                               for k, uv in enumerate(f.uv):
+                                                                       uv[0] = uverts[k][mask][0]
+                                                                       uv[1] = uverts[k][mask][1]
+                               
+                                                               uvlayer = uvlayers[mask]
+                                                               tex_index = uvlayer['texture index']
+                                                               if tex_index != -1:
+                                                                       try:
+                                                                               f.image = self.header.tex_pal[tex_index][1]
+                                                                       except KeyError:
+                                                                               f.image = None
+                                                                       
+                       if global_prefs['smoothshading'] == True and len(self.mesh.faces):
+                               #We need to store per-face vertex normals in the faces as UV layers and delete them later.
+                               self.mesh.addUVLayer("FLTNorm1")
+                               self.mesh.addUVLayer("FLTNorm2")
+                               self.mesh.activeUVLayer = "FLTNorm1"
+                               for f in self.mesh.faces:
+                                       f.smooth = 1
+                                       #grab the X and Y components of normal and store them in UV 
+                                       for i, uv in enumerate(f.uv):
+                                               vert = f.v[i].index
+                                               vert_desc = vert_desc_lst[vert_list[vert-1]]
+                                               if vert_desc.cnorm:
+                                                       uv[0] = vert_desc.nx
+                                                       uv[1] = vert_desc.ny
+                                               else:
+                                                       uv[0] = 0.0
+                                                       uv[1] = 0.0
+                               
+                               #Now go through and populate the second UV Layer with the z component
+                               self.mesh.activeUVLayer = "FLTNorm2"
+                               for f in self.mesh.faces:
+                                       for i, uv in enumerate(f.uv):
+                                               vert = f.v[i].index
+                                               vert_desc = vert_desc_lst[vert_list[vert-1]]
+                                               if vert_desc.cnorm:
+                                                       uv[0] = vert_desc.nz
+                                                       uv[1] = 0.0
+                                               else:
+                                                       uv[0] = 0.0
+                                                       uv[1] = 0.0
+                       
+                               
+                               
+                       #Finally, go through, remove dummy vertex, remove doubles and add edgesplit modifier.
+                       Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX'])
+                       self.mesh.verts.delete(0) # remove the dummy vert
+                       self.mesh.sel= 1
+                       self.header.scene.update(1) #slow!
+                       self.mesh.remDoubles(0.0001)
+                       
+                       edgeHash = dict()
+
+                       for edge in self.mesh.edges:
+                               edgeHash[edge.key] = edge.index
+
+
+                       if global_prefs['smoothshading'] == True and len(self.mesh.faces):
+                               
+                               #rip out the custom vertex normals from the mesh and place them in a face aligned list. Easier to compare this way.
+                               facenorms = []
+                               self.mesh.activeUVLayer = "FLTNorm1"
+                               for face in self.mesh.faces:
+                                       facenorm = []
+                                       for uv in face.uv:
+                                               facenorm.append(Vector(uv[0],uv[1],0.0))
+                                       facenorms.append(facenorm)
+                               self.mesh.activeUVLayer = "FLTNorm2"
+                               for i, face in enumerate(self.mesh.faces):
+                                       facenorm = facenorms[i]
+                                       for j, uv in enumerate(face.uv):
+                                               facenorm[j][2] = uv[0]
+                               self.mesh.removeUVLayer("FLTNorm1")
+                               self.mesh.removeUVLayer("FLTNorm2")
+
+                               #find hard edges
+                               #store edge data for lookup by faces
+                               #edgeHash = dict()
+                               #for edge in self.mesh.edges:
+                               #       edgeHash[edge.key] = edge.index
+
+                               edgeNormHash = dict()
+                               #make sure to align the edgenormals to key value!
+                               for i, face in enumerate(self.mesh.faces):
+                                       
+                                       facenorm = facenorms[i]
+                                       faceEdges = []
+                                       faceEdges.append((face.v[0].index,face.v[1].index,facenorm[0],facenorm[1],face.edge_keys[0]))
+                                       faceEdges.append((face.v[1].index,face.v[2].index,facenorm[1],facenorm[2],face.edge_keys[1]))
+                                       if len(face.v) == 3:
+                                               faceEdges.append((face.v[2].index,face.v[0].index,facenorm[2],facenorm[0],face.edge_keys[2]))
+                                       elif len(face.v) == 4:
+                                               faceEdges.append((face.v[2].index,face.v[3].index,facenorm[2],facenorm[3],face.edge_keys[2]))
+                                               faceEdges.append((face.v[3].index,face.v[0].index,facenorm[3],facenorm[0],face.edge_keys[3]))
+                                       
+                                       #check to see if edgeNormal has been placed in the edgeNormHash yet
+                                       #this is a redundant test, and should be optimized to not be called as often as it is.
+                                       for j, faceEdge in enumerate(faceEdges):
+                                               #the value we are looking for is (faceEdge[2],faceEdge[3])
+                                               hashvalue = (faceEdge[2],faceEdge[3])
+                                               if (faceEdge[0],faceEdge[1]) != faceEdge[4]:
+                                                       hashvalue = (hashvalue[1],hashvalue[0])
+                                                       assert (faceEdge[1],faceEdge[0]) == faceEdge[4]
+                                               if edgeNormHash.has_key(faceEdge[4]):
+                                                       #compare value in the hash, if different, mark as sharp
+                                                       edgeNorm = edgeNormHash[faceEdge[4]]
+                                                       if\
+                                                       abs(hashvalue[0][0] - edgeNorm[0][0]) > FLOAT_TOLERANCE or\
+                                                       abs(hashvalue[0][1] - edgeNorm[0][1]) > FLOAT_TOLERANCE or\
+                                                       abs(hashvalue[0][2] - edgeNorm[0][2]) > FLOAT_TOLERANCE or\
+                                                       abs(hashvalue[1][0] - edgeNorm[1][0]) > FLOAT_TOLERANCE or\
+                                                       abs(hashvalue[1][1] - edgeNorm[1][1]) > FLOAT_TOLERANCE or\
+                                                       abs(hashvalue[1][2] - edgeNorm[1][2]) > FLOAT_TOLERANCE:
+                                                               edge = self.mesh.edges[edgeHash[faceEdge[4]]]
+                                                               edge.flag |= Blender.Mesh.EdgeFlags.SHARP
+                                                               
+                                               else:
+                                                       edgeNormHash[faceEdge[4]] = hashvalue
+                               
+                               #add in edgesplit modifier
+                               mod = self.object.modifiers.append(Blender.Modifier.Types.EDGESPLIT)
+                               mod[Blender.Modifier.Settings.EDGESPLIT_FROM_SHARP] = True
+                               mod[Blender.Modifier.Settings.EDGESPLIT_FROM_ANGLE] = False
+
+                       if(actuvlayer):
+                               self.mesh.activeUVLayer = actuvlayer
+               
        def blender_import(self):
-#        name = self.props['type'] + ': ' + self.props['id']
+               if self.vis and self.parent:
+                       self.vis = self.parent.vis
                name = self.props['id']
-               if self.isMesh:
-                       self.object = Blender.Object.New('Mesh', name)
-                       #self.mesh = self.object.getData()
+               
+               if self.hasMesh:
                        self.mesh = Blender.Mesh.New()
-                       self.mesh.verts.extend( Vector() ) # DUMMYVERT
-                       self.object.link(self.mesh)
+                       self.mesh.name = 'FLT_FaceList'
+                       self.mesh.fakeUser = True
+                       self.mesh.verts.extend( Vector()) #DUMMYVERT
+                       self.object = self.header.scene.objects.new(self.mesh)
                else:
-                       self.object = Blender.Object.New('Empty', name)
+                       self.object = self.header.scene.objects.new('Empty')
 
-               if self.parent:
-                       self.parent.object.makeParent([self.object])
+               self.object.name = name
+               self.header.group.objects.link(self.object)
 
-               scene.link(self.object)
-               self.object.Layer = current_layer
-               self.object.sel = 1
+               #id props import
+               self.object.properties['FLT'] = dict()
+               for key in self.props:
+                       try:
+                               self.object.properties['FLT'][key] = self.props[key]
+                       except: #horrible...
+                               pass
                
+               if self.parent and self.parent.object and (self.header.scene == self.parent.header.scene):
+                               self.parent.object.makeParent([self.object])
+
+               if self.vis == False:
+                       self.object.restrictDisplay = True
+                       self.object.restrictRender = True
+               
+               else: #check for LOD children and set the proper flags
+                       lodlist = list()
+                       for child in self.children:
+                               if child.props.has_key('type') and child.props['type'] == 73:
+                                       lodlist.append(child)
+               
+                       def LODmin(a,b):
+                               if a.props['5d!switch in'] < b.props['5d!switch in']:
+                                       return a 
+                               return b
+               
+                       min= None
+                       if len(lodlist) > 1:
+                               for lod in lodlist:
+                                       lod.vis = False
+                               min = lodlist[0]
+                               for i in xrange(len(lodlist)):
+                                       min= LODmin(min,lodlist[i])
+                               min.vis = True
+                               
+               if self.matrix:
+                       self.object.setMatrix(self.matrix)
+                       
                Node.blender_import(self) # Attach faces to self.faceLs
                
-               if self.isMesh:
+               if self.hasMesh:
                        # Add all my faces into the mesh at once
                        self.blender_import_my_faces()
-               
-               if self.matrix:
-                       self.object.setMatrix(self.matrix)
-               
-               # Attach properties
-               #for name, value in self.props.items():
-               #    self.object.addProperty(name, value)
-               
+                       
        def parse_face(self):
-               child = Face(self)
+               child = Face(self, self.subfacelevel)
                child.parse()
                return True
 
@@ -838,6 +1020,11 @@ class InterNode(Node):
                child.parse()
                return True
 
+       def parse_dof(self):
+               child = DOF(self)
+               child.parse()
+               return True
+
        def parse_indexed_light_point(self):
                child = IndexedLightPoint(self)
                child.parse()
@@ -857,32 +1044,42 @@ class InterNode(Node):
                                m[i].append(f)
                self.matrix = Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3])
                
-EDGE_FGON= Blender.Mesh.EdgeFlags['FGON']
-FACE_TEX= Blender.Mesh.FaceModes['TEX']
+       def parse_subpush(self):
+               self.parse_push()
+               self.subfacelevel+= 1
+               return True
+       def  parse_subpop(self):
+               self.parse_pop()
+               self.subfacelevel -= 1
+               return True
 
+               
+               
 class Face(Node):
-       def __init__(self, parent):
+       def __init__(self, parent,subfacelevel):
                Node.__init__(self, parent, parent.header)
                self.root_handler.set_handler({31: self.parse_comment,
-                                                                          10: self.parse_push})
+                                                                          10: self.parse_push,
+                                                                          52: self.parse_multitex})
                self.root_handler.set_throw_back_lst(throw_back_opcodes)
                
                self.child_handler.set_handler({72: self.parse_vertex_list,
                                                                                10: self.parse_push,
-                                                                               11: self.parse_pop})
+                                                                               11: self.parse_pop,
+                                                                               53: self.parse_uvlist})
                
                if parent:
-                       parent.isMesh = True
+                       parent.hasMesh = True
 
-               self.indices =  list() # face verts here
+               self.subfacelevel = subfacelevel
+               self.indices =  list()  # face verts here
+               self.uvlayers = dict()  # MultiTexture layers keyed to layer bitmask.
+               self.uverts = list()    # Vertex aligned list of dictionaries keyed to layer bitmask.
+               self.uvmask = 0                 # Bitfield read from MTex record
                
                self.comment = ''
-               self.props = dict.fromkeys(['ir color', 'priority', 
-                                                                       'draw type', 'texture white', 'template billboard',
-                                                                       'smc', 'fid', 'ir material', 'lod generation control',
-                                                                       'flags', 'light mode'])
-               
-               self.header.fw.read_ahead(8) # face id
+               self.props = dict()             
+               self.props['id'] = self.header.fw.read_string(8)
                # Load face.
                self.props['ir color'] = self.header.fw.read_int()
                self.props['priority'] = self.header.fw.read_short()
@@ -919,186 +1116,14 @@ class Face(Node):
                self.alt_color_index = self.header.fw.read_uint()
                #self.header.fw.read_ahead(2)
                #self.shader_index = self.header.fw.read_short()
-       
-       
-       """
-       def blender_import_face(self, material_index, image):
-               
-               
-               mesh = self.parent.mesh
-               face_len= len(self.indices)
-               
-               mesh_vert_len_orig= len(mesh.verts)
-               mesh.verts.extend([ self.header.vert_pal.blender_verts[i] for i in self.indices])
-               
-               # Exception for an edge
-               if face_len==2:
-                       mesh.edges.extend((mesh.verts[-1], mesh.verts[-2]))
-                       return
-               
-               
-               mesh_face_indicies = range(mesh_vert_len_orig, mesh_vert_len_orig+face_len)
-               
-               #print mesh_face_indicies , 'mesh_face_indicies '
-               
-               # First we need to triangulate NGONS
-               if face_len>4:
-                       tri_indicies = [[i+mesh_vert_len_orig for i in t] for t in BPyMesh.ngon(mesh, mesh_face_indicies) ]   # use range because the verts are in order.
-               else:
-                       tri_indicies= [mesh_face_indicies] # can be a quad but thats ok
-               
-               # Extend face or ngon
-               
-               mesh.faces.extend(tri_indicies)
-               #print mesh.faces, 'mesh.faces'
-               mesh.faceUV= True
-               
-               # Now set UVs
-               for i in xrange(len(mesh.faces)-len(tri_indicies), len(mesh.faces)):
-                       f= mesh.faces[i]
-                       f_v= f.v
-                       for j, uv in enumerate(f.uv):
-                               vertex_index_flt= self.indices[f_v[j].index - mesh_vert_len_orig]
-                               
-                               vert_desc = self.header.vert_pal.vert_desc_lst[vertex_index_flt]
-                               uv.x, uv.y= vert_desc.u, vert_desc.v
-                       
-                       # Only a bug in 2.42, fixed in cvs
-                       for c in f.col:
-                               c.r=c.g=c.b= 255
-                       
-                       f.mat = material_index
-                       if image:
-                               f.image = image
-                       else:
-                               f.mode &= ~FACE_TEX
-               
-               # FGon
-               
-               if face_len>4:
-                       # Add edges we know are not fgon
-                       end_index= len(mesh.verts)
-                       start_index= end_index - len(self.indices)
-                       edge_dict= dict([ ((i, i+1), None) for i in xrange(start_index, end_index-1)])
-                       edge_dict[(start_index, end_index)]= None # wish this was a set
-                       
-                       fgon_edges= {}
-                       for tri in tri_indicies:
-                               for i in (0,1,2):
-                                       i1= tri[i]
-                                       i2= tri[i-1]
-                                       
-                                       # Sort
-                                       if i1>i2:
-                                               i1,i2= i2,i1
-                                       
-                                       if not edge_dict.has_key( (i1,i2) ): # if this works its an edge vert
-                                               fgon_edges[i1,i2]= None
-                       
-                       
-                       # Now set fgon flags
-                       for ed in mesh.edges:
-                               i1= ed.v1.index
-                               i2= ed.v2.index
-                               if i1>i2:
-                                       i1,i2= i2,i1
-                               
-                               if fgon_edges.has_key( (i1,i2) ):
-                                       # This is an edge tagged for fgonning?
-                                       fgon_edges[i1, i2]
-                                       ed.flag |= EDGE_FGON
-                                       del fgon_edges[i1, i2] # make later searches faster?
-                               
-                               if not fgon_edges:
-                                       break
-       """
-       
+
        def parse_comment(self):
                self.comment = self.header.fw.read_string(self.header.fw.get_length()-4)
                return True
                
-       # returns a tuple (material, image) where material is the blender material and
-       # image is the blender image or None.
-       def create_blender_material(self):
-                # Create face material.
-               mat_desc = MaterialDesc()
-               
-               if self.mat_index != -1:
-                       if not self.mat_index in self.header.mat_desc_pal:
-                               if global_prefs['verbose'] >= 1:
-                                       #print 'Warning: Material index', self.mat_index, 'not in material palette.'
-                                       pass
-                       else:
-                               mat_pal_desc = self.header.mat_desc_pal[self.mat_index]
-                               mat_desc.alpha = mat_pal_desc.alpha * self.alpha # combine face and mat alphas
-                               mat_desc.ambient = mat_pal_desc.ambient
-                               mat_desc.diffuse = mat_pal_desc.diffuse
-                               mat_desc.specular = mat_pal_desc.specular
-                               mat_desc.emissive = mat_pal_desc.emissive
-                               mat_desc.shininess = mat_pal_desc.shininess
-               else:
-                       # if no material get alpha from just face.
-                       mat_desc.alpha = self.alpha
-
-               # Color.
-               if global_prefs['color_from_face']:
-                       color = None
-                       if not self.props['flags'] & 0x40000000:
-                               if self.props['flags'] & 0x10000000: # packed color
-                                       color = self.packed_color
-                               else:
-                                       color = self.header.get_color(self.color_index)
-
-                       if color:
-                               r = float(color[0])/255.0
-                               g = float(color[1])/255.0
-                               b = float(color[2])/255.0
-                               mat_desc.diffuse = [r, g, b]
-
-               # Texture
-               image = None
-               if self.tex_index != -1 and self.tex_index in self.header.bl_tex_pal:
-                       mat_desc.tex0 = self.header.bl_tex_pal[self.tex_index]
-                       if mat_desc.tex0:
-                               mat_desc.name = FF.strip_path(self.header.tex_pal[self.tex_index])
-                               image = mat_desc.tex0.image
-
-               # OpenFlight Face Attributes
-               mat_desc.face_props = self.props
-               
-               # Get material.
-               mat = GRR.request_mat(mat_desc)
-               
-               # Add material to mesh.
-               mesh = self.parent.mesh
-               
-               # Return where it is in the mesh for faces.
-               mesh_materials= mesh.materials
-               
-               material_index= -1
-               for i,m in enumerate(mesh_materials):
-                       if m.name==mat.name:
-                               material_index= i
-                               break
-               
-               if material_index==-1:
-                       material_index= len(mesh_materials)
-                       if material_index==16:
-                               material_index= 15
-                               if global_prefs['verbose'] >= 1:
-                                       print 'Warning: Too many materials per mesh object. Only a maximum of 16 ' + \
-                                                 'allowed. Using 16th material instead.'
-                       
-                       else:
-                               mesh_materials.append(mat)
-                               mesh.materials= mesh_materials
-               
-               return (material_index, image)
-       
-       
        def blender_import(self):
                vert_count = len(self.indices)
-               if vert_count < 3:
+               if vert_count < 1:
                        if global_prefs['verbose'] >= 2:
                                print 'Warning: Ignoring face with no vertices.'
                        return
@@ -1106,18 +1131,21 @@ class Face(Node):
                # Assign material and image
                
                self.parent.faceLs.append(self)
-               self.blen_mat_idx, self.blen_image= self.create_blender_material()
-               
-               
-               
+               #need to store comment in mesh prop layer!
                
                # Store comment info in parent.
-               if self.comment != '':
-                       if self.parent.props['comment'] != '':
-                               self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment
-                       else:
-                               self.parent.props['comment'] = self.comment
-               
+               #if self.comment != '':
+               #       if self.parent.props['comment'] != '':
+               #               self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment
+               #       else:
+               #               self.parent.props['comment'] = self.comment
+               
+               if self.uvlayers:
+                       #Make sure that the mesh knows about the layers that this face uses
+                       self.parent.hasmtex = True
+                       for mask in self.uvlayers.keys():
+                               self.parent.uvlayers[mask] = True
+                       
        def parse_vertex_list(self):
                length = self.header.fw.get_length()
                fw = self.header.fw
@@ -1138,8 +1166,49 @@ class Face(Node):
                                          ' to vertex index.' % byte_offset
                '''
                return True
-
-
+       
+       def parse_multitex(self):
+               #Parse  MultiTex Record.
+               length = self.header.fw.get_length()
+               fw = self.header.fw
+               #num layers == (length - 8) / 4
+               uvmask = fw.read_uint()
+               mask = 2147483648
+               for i in xrange(7):
+                       if mask & uvmask:
+                               uvlayer = dict()
+                               self.uvlayers[mask] = uvlayer
+                       mask = mask / 2
+               
+               #read in record for each individual layer.
+               for key in reversed(sorted(self.uvlayers)):
+                       uvlayer = self.uvlayers[key]
+                       uvlayer['texture index'] = fw.read_ushort()
+                       uvlayer['texture enviorment'] = fw.read_ushort()
+                       uvlayer['texture mapping'] = fw.read_ushort()
+                       uvlayer['texture data'] = fw.read_ushort()
+               
+                       self.uvmask = uvmask
+               
+       def parse_uvlist(self):
+               #for each uvlayer, add uv vertices
+               length = self.header.fw.get_length()
+               fw = self.header.fw
+               uvmask = fw.read_uint()
+               if uvmask != self.uvmask: #This should never happen!
+                       fw.read_ahead(self.length -  4) #potentially unnessecary?
+               else:   
+                       #need to store in uvverts dictionary for each vertex.
+                       totverts = len(self.indices)
+                       for i in xrange(totverts):
+                               uvert = dict()
+                               for key in reversed(sorted(self.uvlayers)):
+                                       uv = Vector(0.0,0.0)
+                                       uv[0] = fw.read_float()
+                                       uv[1] = fw.read_float()
+                                       uvert[key] = uv
+                               self.uverts.append(uvert)
+                               
 class Object(InterNode):
        def __init__(self, parent):
                Node.__init__(self, parent, parent.header)
@@ -1152,15 +1221,15 @@ class Object(InterNode):
                self.root_handler.set_throw_back_lst(throw_back_opcodes)
                
                self.child_handler.set_handler({5: self.parse_face,
-                                                                               #130: self.parse_indexed_light_point,
-                                                                               #111: self.parse_inline_light_point,
+                                                                               19: self.parse_subpush,
+                                                                               20: self.parse_subpop,
+                                                                               111: self.parse_inline_light_point,
                                                                                10: self.parse_push,
                                                                                11: self.parse_pop})
 
-               self.props['type'] = 'Object'
-               self.props['id'] = self.header.fw.read_string(8)
-
-
+               self.props = dict()             
+               self.props['comment'] = ''
+               self.parse_record()
 
 class Group(InterNode):
        def __init__(self, parent):
@@ -1174,15 +1243,16 @@ class Group(InterNode):
                self.root_handler.set_throw_back_lst(throw_back_opcodes)
                
                self.child_handler.set_handler({5: self.parse_face,
-                                                                               #130: self.parse_indexed_light_point,
-                                                                               #111: self.parse_inline_light_point,
+                                                                               19: self.parse_subpush,
+                                                                               20: self.parse_subpop,
+                                                                               111: self.parse_inline_light_point,
                                                                                2: self.parse_group,
                                                                                73: self.parse_lod,
                                                                                4: self.parse_object,
                                                                                10: self.parse_push,
                                                                                11: self.parse_pop,
                                                                                96: self.parse_unhandled,
-                                                                               14: self.parse_unhandled,
+                                                                               14: self.parse_dof,
                                                                                91: self.parse_unhandled,
                                                                                98: self.parse_unhandled,
                                                                                63: self.parse_xref})
@@ -1190,20 +1260,48 @@ class Group(InterNode):
                                                                        'special2', 'significance', 'layer code', 'loop count',
                                                                        'loop duration', 'last frame duration'])
                
-               self.props['type'] = 'Group'
                self.props['comment'] = ''
-               self.props['id'] = self.header.fw.read_string(8)
-               self.props['priority'] = self.header.fw.read_short()
-               self.header.fw.read_ahead(2)
-               self.props['flags'] = self.header.fw.read_int()
-               self.props['special1'] = self.header.fw.read_short()
-               self.props['special2'] = self.header.fw.read_short()
-               self.props['significance'] = self.header.fw.read_short()
-               self.props['layer code'] = self.header.fw.read_char()
-               self.header.fw.read_ahead(5)
-               self.props['loop count'] = self.header.fw.read_int()
-               self.props['loop duration'] = self.header.fw.read_float()
-               self.props['last frame duration'] = self.header.fw.read_float()               
+               self.parse_record()
+               
+               #self.props['type'] = str(self.opcode) + ':' + opcode_name[self.opcode]
+               #props = records[self.opcode]
+               #propkeys = props.keys()
+               #propkeys.sort()
+               #for position in propkeys:
+               #       (type,length,name) = props[position]
+               #       self.props[name] = read_prop(self.header.fw,type,length)
+               #self.props['id'] = self.props['3t8!id']
+
+class DOF(InterNode):
+       def blender_import(self):
+               InterNode.blender_import(self)
+
+       def __init__(self, parent):
+               Node.__init__(self, parent, parent.header)
+               InterNode.__init__(self)
+               
+               self.root_handler.set_handler({33: self.parse_long_id,
+                                                                          31: self.parse_comment,
+                                                                          10: self.parse_push,
+                                                                          49: self.parse_matrix})
+               self.root_handler.set_throw_back_lst(throw_back_opcodes)
+               
+               self.child_handler.set_handler({#130: self.parse_indexed_light_point,
+                                                                               111: self.parse_inline_light_point,
+                                                                               2: self.parse_group,
+                                                                               73: self.parse_lod,
+                                                                               4: self.parse_object,
+                                                                               10: self.parse_push,
+                                                                               11: self.parse_pop,
+                                                                               96: self.parse_unhandled,
+                                                                               14: self.parse_dof,
+                                                                               91: self.parse_unhandled,
+                                                                               98: self.parse_unhandled,
+                                                                               63: self.parse_xref})
+               self.props = dict()             
+               self.props['comment'] = ''
+               self.parse_record()
+
 
 class XRef(InterNode):
        def parse(self):
@@ -1214,31 +1312,66 @@ class XRef(InterNode):
        def __init__(self, parent):
                Node.__init__(self, parent, parent.header)
                InterNode.__init__(self)
-
+               
                self.root_handler.set_handler({49: self.parse_matrix})
                self.root_handler.set_throw_back_lst(throw_back_opcodes)
                
-               xref_filename = self.header.fw.read_string(200)
-               filename = FF.find(xref_filename)
+               self.props = dict()             
+               self.props['comment'] = ''
+               self.parse_record()
 
-               self.props['type'] = 'XRef'
+               xref_filename = self.props['3t200!filename']
+               self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(xref_filename))[0] #this is really wrong as well....
                
-               if filename != None:
-                       self.xref = Database(filename, self)
-                       self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(filename))[0]
+               if global_prefs['doxrefs'] and os.path.exists(xref_filename) and not self.header.grr.xrefs.has_key(xref_filename):
+                       self.xref = Database(xref_filename, self.header.grr, self)
+                       self.header.grr.xrefs[xref_filename] = self.xref
                else:
                        self.xref = None
-                       self.props['id'] = 'X: broken'
+               
+
+       def blender_import(self):
+               #name = self.props['type'] + ': ' + self.props['id']
+               name = self.props['id']
+               self.object = self.header.scene.objects.new('Empty')
+               self.object.name = name
+               self.object.enableDupGroup = True
+               self.header.group.objects.link(self.object)
+               
+               #for broken links its ok to leave this empty! they purely for visual purposes anyway.....
+               try:
+                       self.object.DupGroup = self.header.grr.xrefs[self.props['3t200!filename']].group
+               except:
+                       pass
+                       
+               if self.parent and self.parent.object:
+                       self.parent.object.makeParent([self.object])
 
+               #id props import
+               self.object.properties['FLT'] = dict()
+               for key in self.props:
+                       try:
+                               self.object.properties['FLT'][key] = self.props[key]
+                       except: #horrible...
+                               pass
+
+               self.object.Layer = current_layer
+               self.object.sel = 1
+               if self.matrix:
+                       self.object.setMatrix(self.matrix)
+               Node.blender_import(self)
+               
+               
 class LOD(InterNode):
        def blender_import(self):
-               self.move_to_next_layer()
+               #self.move_to_next_layer()
                InterNode.blender_import(self)
-
+               #self.object.properties['FLT'] = self.props.copy()
+               
        def __init__(self, parent):
                Node.__init__(self, parent, parent.header)
                InterNode.__init__(self)
-               
+
                self.root_handler.set_handler({33: self.parse_long_id,
                                                                           31: self.parse_comment,
                                                                           10: self.parse_push,
@@ -1246,18 +1379,20 @@ class LOD(InterNode):
                self.root_handler.set_throw_back_lst(throw_back_opcodes)
                
                self.child_handler.set_handler({2: self.parse_group,
+                                                                               111: self.parse_inline_light_point,
                                                                                73: self.parse_lod,
                                                                                4: self.parse_object,
                                                                                10: self.parse_push,
                                                                                11: self.parse_pop,
                                                                                96: self.parse_unhandled, # switch
-                                                                               14: self.parse_unhandled, # DOF
+                                                                               14: self.parse_dof, # DOF
                                                                                91: self.parse_unhandled, # sound
                                                                                98: self.parse_unhandled, # clip
                                                                                63: self.parse_xref})
 
-               self.props['type'] = 'LOD'
-               self.props['id'] = self.header.fw.read_string(8)
+               self.props = dict()             
+               self.props['comment'] = ''
+               self.parse_record()
 
 class InlineLightPoint(InterNode):
        def __init__(self, parent):
@@ -1274,119 +1409,49 @@ class InlineLightPoint(InterNode):
                                                                                11: self.parse_pop})
 
                self.indices = list()
-                               
-               self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance'])
-               self.app_props = dict()
-               
+               self.props = dict()             
                self.props['comment'] = ''
-               self.props['type'] = 'Light Point'
-               self.props['id'] = self.header.fw.read_string(8)
-               
-               self.app_props.update({'smc': self.header.fw.read_short()})
-               self.app_props.update({'fid': self.header.fw.read_short()})
-               self.app_props.update({'back color: a': self.header.fw.read_uchar()})
-               self.app_props.update({'back color: b': self.header.fw.read_uchar()})
-               self.app_props.update({'back color: g': self.header.fw.read_uchar()})
-               self.app_props.update({'back color: r': self.header.fw.read_uchar()})
-               self.app_props.update({'display mode': self.header.fw.read_int()})
-               self.app_props.update({'intensity': self.header.fw.read_float()})
-               self.app_props.update({'back intensity': self.header.fw.read_float()})
-               self.app_props.update({'minimum defocus': self.header.fw.read_float()})
-               self.app_props.update({'maximum defocus': self.header.fw.read_float()})
-               self.app_props.update({'fading mode': self.header.fw.read_int()})
-               self.app_props.update({'fog punch mode': self.header.fw.read_int()})
-               self.app_props.update({'directional mode': self.header.fw.read_int()})
-               self.app_props.update({'range mode': self.header.fw.read_int()})
-               self.app_props.update({'min pixel size': self.header.fw.read_float()})
-               self.app_props.update({'max pixel size': self.header.fw.read_float()})
-               self.app_props.update({'actual size': self.header.fw.read_float()})
-               self.app_props.update({'trans falloff pixel size': self.header.fw.read_float()})
-               self.app_props.update({'trans falloff exponent': self.header.fw.read_float()})
-               self.app_props.update({'trans falloff scalar': self.header.fw.read_float()})
-               self.app_props.update({'trans falloff clamp': self.header.fw.read_float()})
-               self.app_props.update({'fog scalar': self.header.fw.read_float()})
-               self.app_props.update({'fog intensity': self.header.fw.read_float()})
-               self.app_props.update({'size threshold': self.header.fw.read_float()})
-               self.app_props.update({'directionality': self.header.fw.read_int()})
-               self.app_props.update({'horizontal lobe angle': self.header.fw.read_float()})
-               self.app_props.update({'vertical lobe angle': self.header.fw.read_float()})
-               self.app_props.update({'lobe roll angle': self.header.fw.read_float()})
-               self.app_props.update({'dir falloff exponent': self.header.fw.read_float()})
-               self.app_props.update({'dir ambient intensity': self.header.fw.read_float()})
-               self.header.fw.read_ahead(12) # Animation settings.        
-               self.app_props.update({'significance': self.header.fw.read_float()})
-               self.props['draw order'] = self.header.fw.read_int()
-               self.app_props.update({'flags': self.header.fw.read_int()})
-               #self.fw.read_ahead(12) # More animation settings.  
-       
-       # return dictionary: lp_app name => index list
-       def group_points(self, props):
-               
-               name_to_indices = {}
-               
-               for i in self.indices:
-                       vert_desc = self.header.vert_pal.vert_desc_lst[i]
-                       app_desc = LightPointAppDesc()
-                       app_desc.props.update(props)
-                       # add vertex normal and color
-                       app_desc.props.update({'nx': vert_desc.nx})
-                       app_desc.props.update({'ny': vert_desc.ny})
-                       app_desc.props.update({'nz': vert_desc.nz})
-                       
-                       app_desc.props.update({'r': vert_desc.r})
-                       app_desc.props.update({'g': vert_desc.g})
-                       app_desc.props.update({'b': vert_desc.b})
-                       app_desc.props.update({'a': vert_desc.a})
-                       
-                       app_name = GRR.request_lightpoint_app(app_desc)
+               self.parse_record()
 
-                       if name_to_indices.get(app_name):
-                               name_to_indices[app_name].append(i)
-                       else:
-                               name_to_indices.update({app_name: [i]})
-                       
-               return name_to_indices
                
        def blender_import(self):
-               name = '%s: %s' % (self.props['type'], self.props['id'])
+               
 
-               name_to_indices = self.group_points(self.app_props)
+               name = self.props['id']
+               self.mesh= Blender.Mesh.New()
+               self.mesh.name = 'FLT_LP'
+               self.object = self.header.scene.objects.new(self.mesh)
+               self.object.name = name
+               #self.mesh.verts.extend(Vector() ) # DUMMYVERT
+               self.object.Layer = current_layer
+               self.object.sel= 1
+       
+               self.object.properties['FLT'] = dict()
+               for key in self.props:
+                       try:
+                               self.object.properties['FLT'][key] = self.props[key]
+                       except: #horrible...
+                               pass
+
+               if self.parent and self.parent.object and self.header.scene == self.parent.header.scene:
+                       self.parent.object.makeParent([self.object])
 
-               for app_name, indices in name_to_indices.iteritems():
-                       self.object = Blender.Object.New('Mesh', name)
-                       #self.mesh = self.object.getData()
-                       self.mesh= Blender.Mesh.New()
-                       self.mesh.verts.extend( Vector() ) # DUMMYVERT
-                       self.object.link(self.mesh)
+               if self.matrix:
+                       self.object.setMatrix(self.matrix)
 
-                       if self.parent:
-                               self.parent.object.makeParent([self.object])
-                               
-                       for i in indices:
-                               vert = self.header.vert_pal.blender_verts[i]
-                               self.mesh.verts.append(vert)
-                       
-                       scene.link(self.object)
-                       self.object.Layer = current_layer
-                       self.object.sel= 1
-                       
-                       if self.matrix:
-                               self.object.setMatrix(self.matrix)
+               self.mesh.verts.extend([self.header.vert_pal.blender_verts[i] for i in self.indices])
+               
+               #add color index information.
+               self.mesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"])
+               for i, vindex in enumerate(self.indices):
+                       vdesc = self.header.vert_pal.vert_desc_lst[vindex]
+                       v = self.mesh.verts[i]
+                       v.setProperty("FLT_VCOL",vdesc.cindex)
+               #for i, v in enumerate(self.mesh.verts):
+               #       vdesc = self.header.vert_pal.vert_desc_lst[i]
+               #       v.setProperty("FLT_VCOL",vdesc.cindex)
+               self.mesh.update()
                                
-                       # Import comment.
-                       if self.props['comment'] != '':
-                               name = 'COMMENT: ' + self.props['id']
-                               t = Blender.Text.New(name)
-                               t.write(self.props['comment'])
-                               self.props['comment'] = name
-                               
-                       # Attach properties.
-                       self.props.update({'appearance': app_name})
-                       for name, value in self.props.iteritems():
-                               self.object.addProperty(name, value)
-                       
-                       self.mesh.update()
-                       
        def parse_vertex_list(self):
                length = self.header.fw.get_length()
                fw = self.header.fw
@@ -1432,7 +1497,7 @@ class IndexedLightPoint(InterNode):
                        app_desc.props.update({'b': vert_desc.b})
                        app_desc.props.update({'a': vert_desc.a})
                        
-                       app_name = GRR.request_lightpoint_app(app_desc)
+                       app_name = self.header.grr.request_lightpoint_app(app_desc, self.header.scene)
 
                        if name_to_indices.get(app_name):
                                name_to_indices[app_name].append(i)
@@ -1448,7 +1513,6 @@ class IndexedLightPoint(InterNode):
                
                for app_name, indices in name_to_indices.iteritems():        
                        self.object = Blender.Object.New('Mesh', name)
-                       #self.mesh = self.object.getData()
                        self.mesh= Blender.Mesh.New()
                        self.mesh.verts.extend( Vector() ) # DUMMYVERT
                        self.object.link(self.mesh)
@@ -1460,7 +1524,7 @@ class IndexedLightPoint(InterNode):
                                vert = self.header.vert_pal.blender_verts[i]
                                self.mesh.verts.append(vert)
                        
-                       scene.link(self.object)
+                       self.header.scene.objects.link(self.object)
        
                        self.object.Layer = current_layer
                        
@@ -1543,7 +1607,7 @@ class Unhandled(InterNode):
                                                                                10: self.parse_push,
                                                                                11: self.parse_pop,
                                                                                96: self.parse_unhandled, # switch
-                                                                               14: self.parse_unhandled, # DOF
+                                                                               14: self.parse_dof, # DOF
                                                                                91: self.parse_unhandled, # sound
                                                                                98: self.parse_unhandled, # clip
                                                                                63: self.parse_xref})
@@ -1552,30 +1616,31 @@ class Unhandled(InterNode):
 
 class Database(InterNode):
        def blender_import(self):
-               self.tex_pal = dict(self.tex_pal_lst)
-               del self.tex_pal_lst
-
-               # Setup Textures
-               bl_tex_pal_lst = list()
-               for i in self.tex_pal.iterkeys():
-                       path_filename = FF.find(self.tex_pal[i])
+               for key in self.tex_pal.keys():
+                       path_filename= FF.find(self.tex_pal[key][0])
                        if path_filename != None:
-                               img = GRR.request_image(path_filename)
+                               img = self.grr.request_image(path_filename)
                                if img:
-                                       tex = GRR.request_texture(img)
-                                       tex.setName(FF.strip_path(self.tex_pal[i]))
-                                       bl_tex_pal_lst.append( (i, tex) )
-                               else:
-                                       bl_tex_pal_lst.append( (i, None) )
+                                       self.tex_pal[key][1] = img
                        elif global_prefs['verbose'] >= 1:
-                               print 'Warning: Unable to find', self.tex_pal[i]
-
-               self.bl_tex_pal = dict(bl_tex_pal_lst)
-
-               # Setup Materials
-               self.mat_desc_pal = dict(self.mat_desc_pal_lst)
-
-               InterNode.blender_import(self)
+                               print 'Warning: Unable to find', self.tex_pal[key][0]
+               
+               self.scene.properties['FLT'] = dict()
+               for key in self.props:
+                       try:
+                               self.scene.properties['FLT'][key] = self.props[key]
+                       except: #horrible...
+                               pass
+               
+               self.scene.properties['FLT']['Main'] = 0
+               self.scene.properties['FLT']['Filename'] = self.bname
+               
+               #import color palette
+               carray = list()
+               for color in self.col_pal:
+                       carray.append(struct.unpack('>i',struct.pack('>BBBB',color[0],color[1],color[2],color[3]))[0])
+               self.scene.properties['FLT']['Color Palette'] = carray
+               Node.blender_import(self)
 
        def parse_appearance_palette(self):
                props = dict()
@@ -1696,9 +1761,10 @@ class Database(InterNode):
                return True
        
        def get_color(self, color_index):
+               color = None
                index = color_index / 128
                intensity = float(color_index - 128.0 * index) / 127.0
-
+               
                if index >= 0 and index <= 1023:
                        brightest = self.col_pal[index]
                        r = int(brightest[0] * intensity)
@@ -1707,7 +1773,7 @@ class Database(InterNode):
                        a = int(brightest[3])
                        
                        color = [r, g, b, a]
-                       
+               
                return color
        
        def parse_color_palette(self):
@@ -1728,15 +1794,56 @@ class Database(InterNode):
        def parse_texture_palette(self):
                name = self.fw.read_string(200)
                index = self.fw.read_int()
-               self.tex_pal_lst.append( (index, name) )
+               self.tex_pal[index]= [name, None]
                return True
-               
-       def __init__(self, filename, parent=None):
+       
+       def read_attribute_files(self):
+               for tex in self.tex_pal.keys():
+                       [name,image] = self.tex_pal[tex]
+                       basename = os.path.basename(name)
+                       if(image):
+                               basename = basename + ".attr"
+                               dirname = os.path.dirname(Blender.sys.expandpath(image.getFilename())) #can't rely on original info stored in pallette since it might be relative link
+                               newpath = os.path.join(dirname, basename)
+                               if os.path.exists(newpath) and not image.properties.has_key('FLT'):
+                                       fw = flt_filewalker.FltIn(newpath)
+                                       fw.read_ahead(8) #We dont care what the attribute file says about x/y dimensions
+                                       image.properties['FLT']={}
+                                       
+                                       #need to steal code from parse records....
+                                       props = records['Image']
+                                       propkeys = props.keys()
+                                       propkeys.sort()
+                                       for position in propkeys:
+                                               (type,length,name) = props[position]
+                                               image.properties['FLT'][name] = read_prop(fw,type,length)
+                                       fw.close_file()
+                                       
+                                       #copy clamp settings
+                                       wrap = image.properties['FLT']['10i!Wrap']
+                                       wrapu = image.properties['FLT']['11i!WrapU']
+                                       wrapv = image.properties['FLT']['12i!WrapV']
+                                       
+                                       if wrapu == 3 or wrapv == 3:
+                                               wrapuv = (wrap,wrap)
+                                       else:
+                                               wrapuv = (wrapu, wrapv)
+                                       image.clampX = wrapuv[0]
+                                       image.clampY = wrapuv[1]
+                                       
+                               elif not os.path.exists(newpath):
+                                       print "Cannot read attribute file:" + newpath
+                                       
+       def __init__(self, filename, grr, parent=None):
                if global_prefs['verbose'] >= 1:
                        print 'Parsing:', filename
                        print
                
                self.fw = flt_filewalker.FltIn(filename)
+               self.filename = filename
+               self.bname = os.path.splitext(os.path.basename(filename))[0]
+               self.grr = grr
+               
                Node.__init__(self, parent, self)
                InterNode.__init__(self)
                
@@ -1753,23 +1860,26 @@ class Database(InterNode):
                        self.root_handler.set_throw_back_lst(throw_back_opcodes)
 
                self.child_handler.set_handler({#130: self.parse_indexed_light_point,
-                                                                               #111: self.parse_inline_light_point,
+                                                                               111: self.parse_inline_light_point,
                                                                                2: self.parse_group,
                                                                                73: self.parse_lod,
                                                                                4: self.parse_object,
                                                                                10: self.parse_push,
                                                                                11: self.parse_pop,
                                                                                96: self.parse_unhandled,
-                                                                               14: self.parse_unhandled,
+                                                                               14: self.parse_dof,
                                                                                91: self.parse_unhandled,
                                                                                98: self.parse_unhandled,
                                                                                63: self.parse_xref})
                
+               self.scene = Blender.Scene.New(self.bname)
+               self.group = Blender.Group.New(self.bname)
+
                self.vert_pal = None
                self.lightpoint_appearance_pal = dict()
                self.tex_pal = dict()
-               self.tex_pal_lst = list()
-               self.bl_tex_pal = dict()
+               #self.tex_pal_lst = list()
+               #self.bl_tex_pal = dict()
                self.col_pal = list()
                self.mat_desc_pal_lst = list()
                self.mat_desc_pal = dict()
@@ -1778,7 +1888,70 @@ class Database(InterNode):
                        'sw lon', 'ne lat', 'ne lon', 'origin lat', 'origin lon', 'lambert lat1',
                        'lambert lat2', 'ellipsoid model', 'utm zone', 'radius', 'major axis', 'minor axis'])
 
-def select_file(filename):
+
+def clearparent(root,childhash):
+       for child in childhash[root]:
+               clearparent(child,childhash)
+       root.clrParent(2,0)
+
+def fixscale(root,childhash):  
+       for child in childhash[root]:
+               fixscale(child,childhash)
+       location = Blender.Mathutils.Vector(root.getLocation('worldspace'))
+       if location[0] != 0.0 and location[1] != 0.0 and location[2] != 0.0:
+               #direction = Blender.Mathutils.Vector(0-location[0],0-location[1],0-location[2]) #reverse vector
+               smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4)
+               root.setLocation(location * smat)
+       #if its a mesh, we need to scale all of its vertices too
+       if root.type == 'Mesh':
+               smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4)
+               rmesh = root.getData(mesh=True)
+               for v in rmesh.verts:
+                       v.co = v.co * smat
+       
+       
+def reparent(root,childhash,sce):
+       for child in childhash[root]:
+               reparent(child,childhash,sce)
+       
+       root.makeParent(childhash[root])
+       sce.update(1)
+       
+def update_scene(root,sdone):
+       for object in root.objects:
+               if object.DupGroup:
+                       try:
+                               child = Blender.Scene.Get(object.DupGroup.name)
+                       except:
+                               child = None
+                       if child and child not in sdone:
+                               update_scene(child,sdone)
+       root.makeCurrent()
+       #create a list of children for each object
+       childhash = dict()
+       for object in root.objects:
+               childhash[object] = list()
+               
+       for object in root.objects:
+               if object.parent:
+                       childhash[object.parent].append(object)
+       
+       for object in root.objects:
+               if not object.parent:
+                       #recursivley go through and clear all the children of their transformation, starting at deepest level first.
+                       clearparent(object,childhash)
+                       #now fix the location of everything
+                       fixscale(object,childhash)
+                       #now fix the parenting
+                       reparent(object,childhash,root)
+       
+       for object in root.objects:
+               object.makeDisplayList()
+       root.update(1)
+       sdone.append(root)
+
+
+def select_file(filename, grr):
        if not Blender.sys.exists(filename):
                msg = 'Error: File ' + filename + ' does not exist.'
                Blender.Draw.PupMenu(msg)
@@ -1801,13 +1974,12 @@ def select_file(filename):
        global_prefs['get_ambient'] = False
        global_prefs['get_shininess'] = True
        global_prefs['color_from_face'] = True
+       global_prefs['log to blender'] = True
+       
+       
        
-       # Start loading the file,
-       # first set the context
        Blender.Window.WaitCursor(True)
        Blender.Window.EditMode(0)
-       for ob in scene.objects:
-               ob.sel=0
        
        
        FF.add_file_to_search_path(filename)
@@ -1817,7 +1989,7 @@ def select_file(filename):
                print
 
        load_time = Blender.sys.time()    
-       db = Database(filename)
+       db = Database(filename,grr)
        db.parse()
        load_time = Blender.sys.time() - load_time
 
@@ -1828,23 +2000,15 @@ def select_file(filename):
 
        import_time = Blender.sys.time()
        db.blender_import()
-       import_time = Blender.sys.time() - import_time
-       
-       Blender.Window.ViewLayer(range(1,21))
-       
-       # FIX UP AFTER DUMMY VERT AND REMOVE DOUBLES
-       Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX'])
-       for ob in scene.objects.context:
-               if ob.type=='Mesh':
-                       me=ob.getData(mesh=1)
-                       me.verts.delete(0) # remove the dummy vert
-                       me.sel= 1
-                       me.remDoubles(0.0001)
        
+       if global_prefs['attrib']:
+               print "reading attribute files"
+               db.read_attribute_files()
        
+       Blender.Window.ViewLayer(range(1,21))
        
-       Blender.Window.RedrawAll()
-               
+       update_scene(db.scene,[])
+       import_time = Blender.sys.time() - import_time
        if global_prefs['verbose'] >= 1:
                print 'Done.'
                print
@@ -1854,37 +2018,112 @@ def select_file(filename):
        
        Blender.Window.WaitCursor(False)
 
+def setimportscale(ID,val):
+       global global_prefs
+       global_prefs['scale'] = val
+def setBpath(fname):
+       global_prefs['fltfile'] = fname
 
-if global_prefs['verbose'] >= 1:
-       print
-       print 'OpenFlight Importer'
-       print 'Version:', __version__
-       print 'Author: Greg MacDonald'
-       print __url__[2]
-       print
+def event(evt,val):
+       pass
+def but_event(evt):
+       
+       global FLTBaseLabel
+       global FLTBaseString
+       global FLTBaseChooser
 
+       global FLTExport
+       global FLTClose
+       
+       global FLTDoXRef
+       global FLTShadeImport
+       global FLTAttrib
+       
+       #Import DB
+       if evt == 1:
+               if global_prefs['verbose'] >= 1:
+                       print
+                       print 'OpenFlight Importer'
+                       print 'Version:', __version__
+                       print 'Author: Greg MacDonald, Campbell Barton, Geoffrey Bantle'
+                       print __url__[2]
+                       print
+               
+               GRR = GlobalResourceRepository()
+               select_file(global_prefs['fltfile'], GRR)
+       #choose base path for export
+       if evt == 4:
+               Blender.Window.FileSelector(setBpath, "DB Root", global_prefs['fltfile'])
+       #Import custom shading?
+       if evt == 9:
+               global_prefs['smoothshading'] = FLTShadeImport.val
+       #Import Image attribute files
+       if evt == 10:
+               global_prefs['attrib'] = FLTAttrib.val
+       #export XRefs
+       if evt == 13:
+               global_prefs['doxrefs'] = FLTDoXRef.val
+       
+       if evt == 2:
+               Draw.Exit()
+       
 
-if __name__ == '__main__':
-       Blender.Window.FileSelector(select_file, "Import OpenFlight", "*.flt")
-       #select_file('/fe/flt/helnwsflt/helnws.flt')
-       #select_file('/fe/flt/Container_006.flt')
-       #select_file('/fe/flt/NaplesORIGINALmesh.flt')
-       #select_file('/Anti_tank_D30.flt')
-       #select_file('/metavr/file_examples/flt/cherrypoint/CherryPoint_liter_runway.flt')
+       
 
+from Blender.BGL import *
+from Blender import Draw
+def gui():
+       
+       global FLTBaseLabel
+       global FLTBaseString
+       global FLTBaseChooser
 
-"""
-TIME= Blender.sys.time()
-import os
-PATH= 'c:\\flt_test'
-for FNAME in os.listdir(PATH):
-       if FNAME.lower().endswith('.flt'):
-               FPATH= os.path.join(PATH, FNAME)
-               newScn= Blender.Scene.New(FNAME)
-               newScn.makeCurrent()
-               scene= newScn
-               select_file(FPATH)
-
-print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
-"""
-       
\ No newline at end of file
+       global FLTExport
+       global FLTClose
+       
+       global FLTDoXRef
+       global FLTShadeImport
+       
+       global FLTAttrib
+       
+       
+       glClearColor(0.772,0.832,0.847,1.0)
+       glClear(GL_COLOR_BUFFER_BIT)
+       
+       areas = Blender.Window.GetScreenInfo()
+       curarea = Blender.Window.GetAreaID()
+       curRect = None
+       
+       for area in areas:
+               if area['id'] == curarea:
+                       curRect = area['vertices']
+                       break
+       
+       width = curRect[2] - curRect[0]
+       height = curRect[3] - curRect[1]
+       cx = 50
+       cy = height - 80
+
+       FLTBaseLabel = Draw.Label("Base file:",cx,cy,100,20)
+       FLTBaseString = Draw.String("",3,cx+100,cy,300,20,global_prefs['fltfile'],255,"Root DB file")
+       FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder")
+       
+       cy = cy-40
+       FLTScale = Draw.Number("Import Scale",14,cx,cy,220,20,global_prefs['scale'],0.0,100.0,"Export scaleing factor",setimportscale)
+       
+       cy = cy-40
+       FLTDoXRef = Draw.Toggle("Import XRefs", 13,cx,cy,220,20,global_prefs['doxrefs'],"Import External references")
+       
+       cy = cy-40
+       FLTShadeImport = Draw.Toggle("Import Custom Shading",9,cx,cy,220,20,global_prefs['smoothshading'],"Import custom shading via edgesplit modifiers")
+       
+       cy = cy-40
+       FLTAttrib = Draw.Toggle("Import Attribute Files", 10,cx,cy,220,20,global_prefs['attrib'],"Import Image Attribute files")
+       
+       cy = cy - 40
+       FLTExport = Draw.PushButton("Import",1,cx,20,100,20,"Import FLT Database")
+       FLTClose = Draw.PushButton("Close",2,cx+120,20,100,20,"Close Window")
+
+       
+       
+Draw.Register(gui,event,but_event)
\ No newline at end of file
index 3f2fef72aa2be89d39f4d45e4fd4bb099430196a..2a1081420e4b4c5fa7188a8ecaa5dc42e7a29f30 100644 (file)
@@ -7,7 +7,7 @@ Group: 'Import'
 Tooltip: 'Import for DXF geometry data (Drawing eXchange Format).'
 """
 __author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)'
-__version__ = '1.0.beta10 - 2007.09.09 by migius'
+__version__ = '1.0.11 - 2007.11.17 by migius'
 __url__ = ["http://blenderartists.org/forum/showthread.php?t=84319",
         "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"]
 __email__ = ["Kitsune_e(at)yahoo.com", "migius(at)4d-vectors.de"]
@@ -18,69 +18,96 @@ This script imports 2d and 3d Geometery from DXFr12 format files.
 This version is focused on import of 3d-objects.
 
 Supported DXF Objects:
-LINE
-POINT
-SOLID
-TRACE
-TEXT
-INSERT (=block)
-MINSERT (=array)
-CIRCLE
-ARC
-3DFACE
-2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline)
-3d-POLYLINE (=no-plane)
-3d-POLYMESH
+LINE,
+POINT,
+SOLID,
+TRACE,
+TEXT,
+INSERT (=block),
+MINSERT (=arrays of blocks),
+CIRCLE,
+ARC,
+3DFACE,
+2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline),
+3d-POLYLINE (=non-plane polylines),
+3d-POLYMESH,
 3d-POLYFACE
-under construction, partly supported DXF>r12:
+
+under construction, partly supported DXF>r12 Objects:
 LWPOLYLINE (LightWeight), MLINE, MTEXT, ELLIPSE
 
 Unsupported DXF Objects:
-DXF r12: DIMENSION, XREF (External Reference)
+DXF r12: DIMENSION, XREF (External Reference),
 DXF>r12: SPLINE, GROUP, RAY/XLINE, LEADER, 3DSOLID, BODY, REGION, dynamic BLOCK
 
 Supported Properties:
 Hierarchy: Entire DXF BLOCKs hierarchy is preserved after import into Blender
-visibility, frozen
-COLOR
-LAYER
-thickness
-width
+visibility, frozen,
+COLOR, LAYER,
+thickness, width,
 (todo: grouped, XDATA)
 It is recommended to use DXF-object properties for coding Blender materials.
 
 Notes:
 - Recommend that you run 'RemoveDoubles' on each imported mesh after using this script
 - Blocks are created on layer 19 then referenced at each insert point.
-* Big DXF-files (over 1500 objects) decrease import performance. The problem is not the inefficiency of python-scripting but Blenders performance in creating new objects in his database - probably a database management problem.
-* The Blender curves of imported ARCs and POLYLINE-arc-segments have light malformed ends.(to fix in beta10)
+- Big DXF-files (over 1500 objects) decrease import performance. The problem is not the inefficiency of python-scripting but Blenders performance in creating new objects in his database - probably a database management problem.
        
 TODO:  
 - the new style object visibility
-- support for Spline-curves, Besier-curves
 - support for real 3d-solids (ACIS)
 - (to see more, search for "-todo-" in script)
 
+"""
 
+"""
 History:
- v1.0 - 2007.09 by migius: "full 3d"-release
+ v1.0 - 2007.11. by migius: "full 3d"-release
  planned tasks:
+ -- command-line-mode/batch-mode
+ -- in-place-editing for dupliGroups
  -- filtering of unused/not-inserted BLOCKs
- -- human-formating of data in INI-File
- -- suport for MLine
- -- suport for Ellipse
- -- suport for Mtext
+ -- support for MLine
+ -- support for Ellipse
+ -- support for Mtext
  -- blender_object.ID.properties[dxf_layer_name]
+ -- better support for long dxf-layer-names 
  -- Configuration files(.ini) should/can handle various material setups
  -- added f_layerFilter
  -- to-check: obj/mat/group/_mapping-idea from ideasman42:
- -- better support for long dxf-layer-names 
- -- support width_force for LINEs/ARCs/CIRCLEs/ELLIPSEs = "solidify"
- -- curves: added fill/non-fill option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs
+ -- curves: added "fill/non-fill" option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs
  -- bug:? object = Object.Get(obname) -> = SCENE.getChildren(obname)
- -- command-line-mode/batch-mode
- -- fixed malformed endpoints of Blender curves of imported ARCs and POLYLINE-arc segments. 
- beta10: 2007.09.09 by migius
+ -- "normalize Z" option to correct non-planar figures
+ -- LINEs need "width" in 3d-space incl vGroups
+ -- support width_force for LINEs/ELLIPSEs = "solidify"
+ -- bug: dxf-files without layer-section missing layersmap{}
+ -- color BYLAYER=256,BYBLOCK=0 
+ -- blocknames conventions length
+ v1.0.11: 2007.11.17 by migius
+ c4 added "analyze DXF-file" UI-option: print LAYER/BLOCK-dependences into a textfile
+ c3 human-formating of data in INI-Files
+ c2 added "caps" for closed Bezier-curves
+ c2 added "set elevation" UI-option
+ c1 rewrite POLYLINE2d-arc-segments Bezier-interpreter
+ b9 many bugs fixed
+ b9 rewrite POLYLINE2d-arc-segments trimming (clean-trim)
+ b8 added "import from frozen layers" UI-option
+ b8 added "import from paper space" UI-option
+ b8 support Bezier curves for LINEs incl.thickness(0.0-10.0)
+ b8 added meshSmooth_on for circle/arc/polyline 
+ b8 added vertexGroups for circle/arc 
+ b7 added width_force for ARCs/CIRCLEs = "thin_box" option
+ b3 cleanup code, rename f_drawArc/Bulg->f_calcArc/Bulg
+ b2 fixing material assignment by LAYER+COLOR
+ b1 fixing Bezier curves representation of POLYLINEs-arc-segments
+ b0 added global_scale_presets: "yard/feet/inch to meter"
+ v1.0.10: 2007.10.18 by migius
+ a6 bugfix CircleDrawCaps for OSX 
+ a5 added two "curve_res" UI-buttons for Bezier curves representation
+ a5 improved Bezier curves representation of circles/arcs: correct handlers
+ a4 first try to fix malformed endpoints of Blender curves of imported ARCs and POLYLINE-arc segments. 
+ a3 bugfix: open POLYLINEs with end_point.loc==start_point.loc
+ a2 bugfix: f_transform for OCS=(0,0,-1) oriented objects
  a1 added "fill_on" option to draw top and bottom sides of CIRCLEs and ELLIPSEs
  a1 rewrite f_CIRCLE.Draw: from Mesh.Primitive to Mesh
  a1 bugfix "newScene"-mode: Cylinders/Arcs were drawn at <0,0,0>location
@@ -100,13 +127,13 @@ History:
  d4 added: f_set_thick(cntrolled by ini-parameters)
  d4 bugfix: face-normals in objects with minus thickness
  d4 added: placeholder'Empty'-size in f_Insert.draw
- d3 rewrite f_Text.Draw: added suport for all Text's parameters
+ d3 rewrite f_Text.Draw: added support for all Text's parameters
  d2 redesign: progressbar 
  e- tuning by ideasman42: better use of the Py API.
  c- tuning by ideasman42
  b- rewrite f_Text.Draw rotation/transform
  b- bugfix: POLYLINE-segment-intersection more reliable now
- b- bugfix: circle:_thic, 'Empties':no material_assignement
+ b- bugfix: circle:_thic, 'Empties':no material_assignment
  b- added material assignment (from layer and/or color)
  a- added empty, cylinder and UVsphere for POINTs
  a- added support for 2d-POLYLINE: splines, fitted curves, fitted surfaces
@@ -129,7 +156,7 @@ History:
  g- rewrote: insert-point-handle-object is a small tetrahedron
  e- bugfix: closed-polymesh3d
  - rewrote: startUI, type_map.keys, f_drawer, for all class_f_draw(added "settings" as attribut)
- - added 2d/3d-support for Polyline_Width incl. angleintersection
+ - added 2d/3d-support for Polyline_Width incl. angle intersection
  beta07: 2007.06.19 by migius
  - added 3d-support for LWPolylines
  - added 2d/3d-support for Points
@@ -140,7 +167,7 @@ History:
  - added 2d/3d-support for 3d-PolyLine, PolyMesh and PolyFace
  - added Global-Scale for size control of imported scenes
  beta04: 2007.06.12 by migius
- - rewrote the f_drawBulge for correct import the arc-segments of Polylines
+ - rewrote the f_calcBulge for correct import the arc-segments of Polylines
  beta03: 2007.06.10 by migius
  - rewrote interface
  beta02: 2007.06.09 by migius
@@ -186,30 +213,34 @@ History:
 # --------------------------------------------------------------------------
 
 import Blender
-import bpy
+#import bpy
 from Blender import *
 #from Blender.Mathutils import Vector, Matrix
 #import BPyMessages
 
-
-from dxfReader import readDXF    # get_name, get_layer
+from dxfReader import readDXF
+#from dxfReader import get_name, get_layer
 from dxfReader import Object as dxfObject
 from dxfColorMap import color_map
+
 from math import *
 
 try:
        import os
        if os.name:# != 'mac':
                import psyco
-               psyco.log()
+               psyco.log(Blender.Get('tempdir')+"/blender.log-psyco")
+               #psyco.log()
                psyco.full(memory=100)
                psyco.profile(0.05, memory=100)
                psyco.profile(0.2)
+               #print 'psyco imported'
 except ImportError:
+       #print 'psyco not imported'
        pass
 
 print '\n\n\n\n'
-print 'Import DXF to Blender *** START ***'   #---------------------
+print 'Import DXF to Blender *** start ***'   #---------------------
 
 SCENE = None
 WORLDX = Mathutils.Vector((1,0,0))
@@ -220,10 +251,14 @@ G_SCALE = 1.0        #(0.0001-1000) global scaling factor for all dxf data
 MIN_DIST = 0.001       #cut-off value for sort out short-distance polyline-"duoble_vertex"
 ARC_RESOLUTION = 64   #(4-500) arc/circle resolution - number of segments
 ARC_RADIUS = 1.0   #(0.01-100) arc/circle radius for number of segments algorithm
-THIN_RESOLUTION = 8   #(4-500) thin_cylinder arc_resolution - number of segments
+CURV_RESOLUTION = 12 #(3-50) Bezier curves resolution
+CURVARC_RESOLUTION = 4 #(3-32) resolution of circle represented as Bezier curve 
+THIN_RESOLUTION = 8   #(4-64) thin_cylinder arc_resolution - number of segments
 MIN_THICK = MIN_DIST * 10.0  #minimal thickness by forced thickness
 MIN_WIDTH = MIN_DIST * 10.0  #minimal width by forced width
-ANGLECUT_LIMIT = 3.0    #limit for anglecut of polylines-wide-segments (values:1.0 - 5.0)
+TRIM_LIMIT = 3.0        #limit for triming of polylines-wide-segments (values:0.0 - 5.0)
+ELEVATION = 0.0 #standard elevation = coordinate Z
+
 TARGET_LAYER = 3       #target blender_layer
 GROUP_BYLAYER = 0   #(0/1) all entities from same layer import into one blender-group
 
@@ -232,6 +267,7 @@ MAX_NAMELENGTH = 17   #max_effective_obnamelength in blender =21=17+(.001)
 INIFILE_DEFAULT_NAME = 'importDXF'
 INIFILE_EXTENSION = '.ini'
 INIFILE_HEADER = 'ImportDXF.py ver.1.0 config data'
+INFFILE_HEADER = 'ImportDXF.py ver.1.0 analyze of DXF-data'
 
 AUTO = BezTriple.HandleTypes.AUTO
 FREE = BezTriple.HandleTypes.FREE
@@ -252,8 +288,8 @@ cur_COUNTER = 0  #counter for progress_bar
 
 # from Stani's dxf writer v1.1 (c)www.stani.be (GPL)
 #---color values
-BYBLOCK=0
-BYLAYER=256
+BYBLOCK = 0
+BYLAYER = 256
 
 #---block-type flags (bit coded values, may be combined):
 ANONYMOUS                 =1  # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application
@@ -310,7 +346,7 @@ EXACT          = 2 #taller characters will not override
 
 
 class Layer:  #-----------------------------------------------------------------
-       """Class for objects representing dxf layers.
+       """Class for objects representing dxf LAYERs.
        """
        def __init__(self, obj, name=None, color=None, frozen=None):
                """Expects an object of type layer as input.
@@ -320,7 +356,7 @@ class Layer:  #-----------------------------------------------------------------
 
                if name:
                        self.name = name
-                       #self.bfname = name  #remi--todo-----------
+                       #self.bfname = name  #--todo---see layernamesmap in f_getLayersmap ---
                else:
                        self.name = obj.get_type(2)[0] #layer name of object
 
@@ -333,7 +369,7 @@ class Layer:  #-----------------------------------------------------------------
                        self.frozen = frozen
                else:
                        self.flags = obj.get_type(70)[0]
-                       self.frozen = self.flags&1
+                       self.frozen = self.flags & 1
 
 
        def __repr__(self):
@@ -353,7 +389,7 @@ def getit(obj, typ, default=None):  #------------------------------------------
                                        it = item[1]
                                        break  #as soon as the first found
                        except:
-                               # TODO - I found one case where item was a text instance
+                               # --todo-- I found one case where item was a text instance
                                # that failed with no __getitem__
                                pass
        else:   #else searching in Object with get_type-Methode
@@ -368,7 +404,7 @@ def getit(obj, typ, default=None):  #------------------------------------------
 def get_extrusion(data):        #-------------------------------------------------
        """Find the axis of extrusion.
 
-       Used to get from object_data the objects Object Coordinate System (ocs).
+       Used to get from object_data the objects Object_Coordinate_System (ocs).
        """
        #print 'deb:get_extrusion: data: \n', data  #---------------
        vec = [0,0,1]
@@ -380,10 +416,8 @@ def get_extrusion(data):    #-------------------------------------------------
 
 
 
-
-
 class Solid:  #-----------------------------------------------------------------
-       """Class for objects representing dxf solid or trace.
+       """Class for objects representing dxf SOLID or TRACE.
        """
        def __init__(self, obj):
                """Expects an entity object of type solid or trace as input.
@@ -418,7 +452,7 @@ class Solid:  #-----------------------------------------------------------------
                d = [0, 0, 0]
                a[0] = getit(data, 10, None) # 10 = x
                a[1] = getit(data, 20, None) # 20 = y
-               a[2] = getit(data, 30,  0) # 30 = z
+               a[2] = getit(data, 30,  0)   # 30 = z
                b[0] = getit(data, 11, None)
                b[1] = getit(data, 21, None)
                b[2] = getit(data, 31,  0)
@@ -492,7 +526,7 @@ class Solid:  #-----------------------------------------------------------------
 
                ob = SCENE.objects.new(me) # create a new mesh_object
                if settings.var['vGroup_on']:
-                       # each MeshSite becomes vertexGroup for easier material assignment ---------------------
+                       # each MeshSide becomes vertexGroup for easier material assignment ---------------------
                        replace = Blender.Mesh.AssignModes.ADD  #or .AssignModes.ADD/REPLACE
                        if vg_left: me.addVertGroup('side.left')  ; me.assignVertsToGroup('side.left',  vg_left, 1.0, replace)
                        if vg_right:me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace)
@@ -509,7 +543,7 @@ class Solid:  #-----------------------------------------------------------------
 
 
 class Line:  #-----------------------------------------------------------------
-       """Class for objects representing dxf lines.
+       """Class for objects representing dxf LINEs.
        """
        def __init__(self, obj):
                """Expects an entity object of type line as input.
@@ -558,66 +592,101 @@ class Line:  #-----------------------------------------------------------------
                #settings.var['curves_on']=False
 
                points = self.points
-
-               global activObjectLayer
-               global activObjectName
-               #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #---------------------
-
-               if activObjectLayer == self.layer and settings.var['one_mesh_on']:
-                       obname = activObjectName
-                       #print 'deb:line.draw obname from activObjectName: ', obname #---------------------
-                       ob = Object.Get(obname)  # open an existing mesh_object
-                       #ob = SCENE.getChildren(obname)  # open an existing mesh_object
-                       me = Mesh.Get(ob.name)   # open objects mesh data
-               else:
+               thic = set_thick(self.thic, settings)
+               width = 0.0
+               if settings.var['lines_as'] == 4: # as thin_box
+                       thic = settings.var['thick_min']
+                       width = settings.var['width_min']
+               if settings.var['lines_as'] == 3: # as thin cylinder
+                       cyl_rad = 0.5 * settings.var['width_min']
+
+               if settings.var['curves_on']: # LINE curve representation-------------------------
                        obname = 'li_%s' %self.layer  # create object name from layer name
                        obname = obname[:MAX_NAMELENGTH]
-                       me = Mesh.New(obname)             # create a new mesh
-                       ob = SCENE.objects.new(me) # create a new mesh_object
-                       activObjectName = ob.name
-                       activObjectLayer = self.layer
-                       #print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #---------------------
-
-               #if settings.var['width_force']: # -todo-----------
-
-               faces, edges = [], []
-               n = len(me.verts)
-               thic = set_thick(self.thic, settings)
-               if thic != 0:
-                       t, e = thic, self.extrusion
-                       #print 'deb:thic, extr: ', t, e #---------------------
-                       points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]])
-                       faces = [[0+n, 1+n, 3+n, 2+n]]
-               else:
-                       me.verts.extend(points) # add vertices to mesh
-                       edges = [[0+n, 1+n]]
-
-               me.verts.extend(points) # add vertices to mesh
-               if faces: me.faces.extend(faces)           # add faces to the mesh
-               if edges: me.edges.extend(edges)           # add faces to the mesh
 
-               if settings.var['vGroup_on']:
-                       # entities with the same color build one vertexGroup for easier material assignment ---------------------
-                       ob.link(me) # link mesh to that object
-                       vG_name = 'color_%s' %self.color_index
-                       if edges: faces = edges
-                       replace = Blender.Mesh.AssignModes.ADD  #or .AssignModes.REPLACE or ADD
-                       try:
-                               me.assignVertsToGroup(vG_name,  faces[0], 1.0, replace)
-                               #print 'deb: existed vGroup:', vG_name #---------------------
-                       except:
-                               me.addVertGroup(vG_name)
-                               me.assignVertsToGroup(vG_name,  faces[0], 1.0, replace)
-                               #print 'deb: create new vGroup:', vG_name #---------------------
+                       c = Curve.New(obname) # create new curve data
+                       curve = c.appendNurb(BezTriple.New(points[0]))
+                       curve.append(BezTriple.New(points[1]))
+                       for point in curve:
+                               point.handleTypes = [VECT, VECT]
+                       curve.flagU = 0 # 0 sets the curve not cyclic=open
+                       c.update() #important for handles calculation
+
+                       ob = SCENE.objects.new(c) # create a new curve_object
+
+                       #if False:  # --todo-- better support for 210-group
+                       if thic != 0.0: #hack: Blender2.45 curve-extrusion
+                               t = thic * 0.5
+                               if abs(t) > 5.0: t = 5.0 * cmp(t,0) # Blender2.45 accepts only (0.0 - 5.0)
+                               e = self.extrusion
+                               c.setExt1(abs(t))  # curve-extrusion
+                               ob.LocX += t * e[0]
+                               ob.LocY += t * e[1]
+                               ob.LocZ += t * e[2]
+                               #c.setExt1(1.0)  # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0)
+                               #ob.LocZ = t + self.loc[2]
+                               #ob.SizeZ *= abs(t)
+                       return ob
 
+               else:  # LINE mesh representation ------------------------------
+                       global activObjectLayer
+                       global activObjectName
+                       #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #---------------------
+       
+                       if activObjectLayer == self.layer and settings.var['one_mesh_on']:
+                               obname = activObjectName
+                               #print 'deb:line.draw obname from activObjectName: ', obname #---------------------
+                               ob = Object.Get(obname)  # open an existing mesh_object
+                               #ob = SCENE.getChildren(obname)  # open an existing mesh_object
+                               me = Mesh.Get(ob.name)   # open objects mesh data
+                       else:
+                               obname = 'li_%s' %self.layer  # create object name from layer name
+                               obname = obname[:MAX_NAMELENGTH]
+                               me = Mesh.New(obname)             # create a new mesh
+                               ob = SCENE.objects.new(me) # create a new mesh_object
+                               activObjectName = ob.name
+                               activObjectLayer = self.layer
+                               #print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #---------------------
+       
+                       faces, edges = [], []
+                       n = len(me.verts)
 
-               #print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #---------------------
-               return ob
+                       #if settings.var['width_force']: #--todo-----------
 
+                       if thic != 0:
+                               t, e = thic, self.extrusion
+                               #print 'deb:thic, extr: ', t, e #---------------------
+                               points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]])
+                               faces = [[0+n, 1+n, 3+n, 2+n]]
+                       else:
+                               edges = [[0+n, 1+n]]
+       
+                       me.verts.extend(points) # adds vertices to global mesh
+                       if faces: me.faces.extend(faces)           # add faces to the mesh
+                       if edges: me.edges.extend(edges)           # add faces to the mesh
+       
+                       if settings.var['vGroup_on']:
+                               # entities with the same color build one vertexGroup for easier material assignment ----
+                               ob.link(me) # link mesh to that object
+                               vG_name = 'color_%s' %self.color_index
+                               if edges: faces = edges
+                               replace = Blender.Mesh.AssignModes.ADD  #or .AssignModes.REPLACE or ADD
+                               try:
+                                       me.assignVertsToGroup(vG_name,  faces[0], 1.0, replace)
+                                       #print 'deb: existed vGroup:', vG_name #---------------------
+                               except:
+                                       me.addVertGroup(vG_name)
+                                       me.assignVertsToGroup(vG_name,  faces[0], 1.0, replace)
+                                       #print 'deb: create new vGroup:', vG_name #---------------------
+       
+       
+                       #print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #---------------------
+                       return ob
+       
 
 
 class Point:  #-----------------------------------------------------------------
-       """Class for objects representing dxf points.
+       """Class for objects representing dxf POINTs.
        """
        def __init__(self, obj):
                """Expects an entity object of type point as input.
@@ -700,7 +769,7 @@ class Point:  #-----------------------------------------------------------------
 
 
 class LWpolyline:  #-----------------------------------------------------------------
-       """Class for objects representing dxf LWpolylines.
+       """Class for objects representing dxf LWPOLYLINEs.
        """
        def __init__(self, obj):
                """Expects an entity object of type lwpolyline as input.
@@ -793,7 +862,7 @@ class LWpolyline:  #------------------------------------------------------------
                                else:
                                        point2 = self.points[i+1]
                                arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad'])
-                               verts = drawBulge(point, point2, arc_res)
+                               verts, center = calcBulge(point, point2, arc_res)
 #                         if i == len(self.points)-1:
 #                                 if self.closed:
 #                                         verts.pop() #remove last(=first) vertex
@@ -835,7 +904,7 @@ class LWpolyline:  #------------------------------------------------------------
 
 
 class Polyline:  #-----------------------------------------------------------------
-       """Class for objects representing dxf Polylines.
+       """Class for objects representing dxf POLYLINEs.
        """
        def __init__(self, obj):
                """Expects an entity object of type polyline as input.
@@ -910,7 +979,7 @@ class Polyline:  #--------------------------------------------------------------
                elif self.plmesh:  #---- 3dPolyMesh - mesh with ortogonal topology
                        ob = self.drawPlMesh(settings)
                #---- 2dPolyline - plane polyline with arc/wide/thic segments
-               #---- 3dPolyline - noplane polyline (thin segments = without arc/wide/thic)
+               #---- 3dPolyline - non-plane polyline (thin segments = without arc/wide/thic)
                elif  self.poly2d or self.poly3d:
                        if settings.var['curves_on']: # and self.spline:
                                ob = self.drawPolyCurve(settings)
@@ -944,9 +1013,12 @@ class Polyline:  #--------------------------------------------------------------
                me.verts.extend(points) # add vertices to mesh
                me.faces.extend(faces)   # add faces to the mesh
 
+               if settings.var['meshSmooth_on']:  # ----------------------
+                       for i in xrange(len(faces)):
+                               me.faces[i].smooth = True
+                       #me.Mode(AUTOSMOOTH)
                transform(self.extrusion, 0, ob)
                #print 'deb:polyface.draw.END:----------------' #------------------------
-
                return ob
 
 
@@ -987,6 +1059,11 @@ class Polyline:  #--------------------------------------------------------------
                me.verts.extend([point.loc for point in self.points]) # add vertices to mesh
                me.faces.extend(faces)   # add faces to the mesh
 
+               if settings.var['meshSmooth_on']:  # ----------------------
+                       for i in xrange(len(faces)):
+                               me.faces[i].smooth = True
+                       #me.Mode(AUTOSMOOTH)
+
                transform(self.extrusion, 0, ob)
                #print 'deb:polymesh.draw.END:----------------' #------------------------
                return ob
@@ -1006,14 +1083,19 @@ class Polyline:  #--------------------------------------------------------------
                obname = '%s_%s' %(pline_typ, self.layer)  # create object_name from layer name
                obname = obname[:MAX_NAMELENGTH]
                d_points = []
-               #for DXFr10-format: update all points[].loc[2] == None -> 0.0 
-               for point in self.points:
-                       if point.loc[2] == None:
+
+               if settings.var['Z_force_on']:
+                       self.elevation = settings.var['Z_elev']
+                       for point in self.points:
                                point.loc[2] = self.elevation
-                       d_points.append(point)
+                               d_points.append(point)
+               else: #for DXFr10-format: update all points[].loc[2] == None -> 0.0 
+                       for point in self.points:
+                               if point.loc[2] == None:
+                                       point.loc[2] = self.elevation
+                               d_points.append(point)
 
                thic = set_thick(self.thic, settings)
-
                if thic != 0.0:   #hack: Blender<2.45 curve-extrusion
                        LocZ = d_points[0].loc[2]
                        temp_points = []
@@ -1024,6 +1106,7 @@ class Polyline:  #--------------------------------------------------------------
                
                #print 'deb:polyline2dCurve.draw d_points=', d_points  #---------------
                pline = Curve.New(obname)   # create new curve data
+               #pline.setResolu(24) #--todo-----                                               
 
                if False: #self.spline:  # NURBSplines-----FAKE(with Bezier)-----
                        #print 'deb:polyline2dCurve.draw self.spline!' #---------------
@@ -1039,7 +1122,7 @@ class Polyline:  #--------------------------------------------------------------
                                curve[0].handleTypes = [FREE, ALIGN]   #remi--todo-----
                                curve[-1].handleTypes = [ALIGN, FREE]   #remi--todo-----
 
-               elif self.spline:  # NURBSplines-----TODO--:if curvQBspline: generate middlepoints---
+               elif self.spline:  # NURBSplines-----OK-----
                        #print 'deb:polyline2dCurve.draw self.spline!' #---------------
                        weight1 = 0.5
                        weight2 = 1.0
@@ -1111,33 +1194,99 @@ class Polyline:  #--------------------------------------------------------------
                                curve[0].handleTypes = [FREE, ALIGN]   #remi--todo-----
                                curve[-1].handleTypes = [ALIGN, FREE]   #remi--todo-----
 
-               else:   #--straight line/arc-segments----OK------
+               else:   #--straight line- and arc-segments----OK------
+                       #print 'deb:polyline2dCurve.draw curve:', curve #-----
                        points = []
-                       d_points.append(d_points[0])  #------ first vertex added -------------
+                       arc_res = settings.var['curve_arc']
+                       prevHandleType = VECT
+                       #d_points.append(d_points[0])  #------ first vertex added at the end of list --------
                        #curve.setType(0) #polygon_type of Blender_curve
-                       for i in xrange(len(d_points)-1):
+                       for i in xrange(len(d_points)):
                                point1 = d_points[i]
-                               point2 = d_points[i+1]
-                               if point1.bulge and (i < len(d_points)-2 or self.closed):
-                                       verts = drawBulge(point1, point2, arc_res=8, curve_on=True) #calculate additional points for bulge
-                                       if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0]))
-                                       else: curve.append(BezTriple.New(verts[0]))
-                                       curve[-1].handleTypes = [VECT, VECT]  #--todo--calculate bezier-tangents
-                                       for p in verts[1:]:
-                                               curve.append(BezTriple.New(p))
-                                               curve[-1].handleTypes = [AUTO, AUTO]  #--todo--calculate bezier-tangents
-#                                 curve[-1].handleTypes = [VECT, VECT]   #--todo--calculate bezier-tangents
-                               else:
-                                       if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc))
-                                       else: curve.append(BezTriple.New(point1.loc))
-                                       curve[-1].handleTypes = [VECT, VECT]   #--todo--calculate bezier-tangents
+                               #point2 = d_points[i+1]
+                               if False: #-----outdated!- standard calculation ----------------------------------
+                                       if point1.bulge and (i < len(d_points)-2 or self.closed):
+                                               verts, center = calcBulge(point1, point2, arc_res, triples=False)
+                                               if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0]))
+                                               else: curve.append(BezTriple.New(verts[0]))
+                                               curve[-1].handleTypes = [VECT, VECT]  #--todo--calculation of bezier-tangents
+                                               for p in verts[1:]:
+                                                       curve.append(BezTriple.New(p))
+                                                       curve[-1].handleTypes = [AUTO, AUTO]
+                                       else:
+                                               if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc))
+                                               else: curve.append(BezTriple.New(point1.loc))
+                                               curve[-1].handleTypes = [VECT, VECT]   #--todo--calculation of bezier-tangents
+
+                               elif True:   #----- optimised Bezier-Handles calculation --------------------------------
+                                       #print 'deb:drawPlineCurve: i:', i #---------
+                                       if point1.bulge and not (i == len(d_points)-1 and point1.bulge and not self.closed):
+                                               if i == len(d_points)-1: point2 = d_points[0]
+                                               else: point2 = d_points[i+1]
+
+
+                                               # calculate additional points for bulge
+                                               VectorTriples = calcBulge(point1, point2, arc_res, triples=True)
+
+                                               if prevHandleType == FREE:
+                                                       #print 'deb:drawPlineCurve: VectorTriples[0]:', VectorTriples[0] #---------
+                                                       VectorTriples[0][:3] = prevHandleVect
+                                                       #print 'deb:drawPlineCurve: VectorTriples[0]:', VectorTriples[0] #---------
+
+                                               if i == 0: curve = pline.appendNurb(BezTriple.New(VectorTriples[0]))
+                                               else: curve.append(BezTriple.New(VectorTriples[0]))
+                                               curve[-1].handleTypes = [prevHandleType, FREE]
+
+                                               for p in VectorTriples[1:-1]:
+                                                       curve.append(BezTriple.New(p))
+                                                       curve[-1].handleTypes = [FREE, FREE]
+
+                                               prevHandleVect = VectorTriples[-1][:3]
+                                               prevHandleType = FREE
+                                               #print 'deb:drawPlineCurve: prevHandleVect:', prevHandleVect #---------
+                                       else:
+                                               #print 'deb:drawPlineCurve: else' #----------
+                                               if prevHandleType == FREE:
+                                                       VectorTriples = prevHandleVect + list(point1) + list(point1)
+                                                       #print 'deb:drawPlineCurve: VectorTriples:', VectorTriples #---------
+                                                       curve.append(BezTriple.New(VectorTriples))
+                                                       curve[-1].handleTypes = [FREE, VECT]
+                                                       prevHandleType = VECT
+                                               else:
+                                                       if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc))
+                                                       else: curve.append(BezTriple.New(point1.loc))
+                                                       curve[-1].handleTypes = [VECT, VECT]
+                                                       
+
+
+                                       #print 'deb:drawPlineCurve: curve[-1].vec[0]', curve[-1].vec[0] #----------
+
                        if self.closed:
                                curve.flagU = 1 # Set curve cyclic=close
-#                         curve[0].handleTypes = [VECT, VECT]   #--todo--calculate bezier-tangents
-                       else:
+                               if prevHandleType == FREE:
+                                       #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #----------
+                                       #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #----------
+                                       prevHandleType2 = curve[0].handleTypes[1]
+                                       p0h1,p0,p0h2 = curve[0].vec 
+                                       #print 'deb:drawPlineCurve:closed p0h1:', p0h1 #----------
+                                       p0h1 = prevHandleVect
+                                       #p0h1 = [0,0,0]
+                                       #print 'deb:drawPlineCurve:closed p0h1:', p0h1 #----------
+                                       #curve[0].vec = [p0h1,p0,p0h2]
+                                       curve.__setitem__(0,BezTriple.New(p0h1+p0+p0h2))
+
+                                       curve[0].handleTypes = [FREE,prevHandleType2]
+                                       #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #----------
+                                       #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #----------
+                               else: 
+                                       curve[0].handleTypes[0] = VECT
+                       else: 
                                curve.flagU = 0 # Set curve not cyclic=open
-                               curve[0].handleTypes = [FREE, VECT]   #--todo--calculate bezier-tangents
-                               curve[-1].handleTypes = [VECT, FREE]  #--todo--calculate bezier-tangents
+
+               if settings.var['fill_on']:
+                       pline.setFlag(6) # 2+4 set top and button caps
+               else:
+                       pline.setFlag(pline.getFlag() & ~6) # dont set top and button caps
 
                pline.update()
                ob = SCENE.objects.new(pline) # create a new curve_object
@@ -1155,7 +1304,7 @@ class Polyline:  #--------------------------------------------------------------
                return ob
 
 
-       def drawPoly2d(self, settings):  #---- 2dPolyline - plane wide/thic lines
+       def drawPoly2d(self, settings):  #---- 2dPolyline - plane lines/arcs with wide/thic
                """Generate the geometery of regular polyline.
                """
                #print 'deb:polyline2d.draw.START:----------------' #------------------------
@@ -1170,28 +1319,39 @@ class Polyline:  #--------------------------------------------------------------
                elif self.curved: pline_typ = 'pc'
                else: pline_typ = 'pl'
            &n