Merged 15771:15912 from trunk
authorIan Thompson <quornian@googlemail.com>
Fri, 1 Aug 2008 23:39:52 +0000 (23:39 +0000)
committerIan Thompson <quornian@googlemail.com>
Fri, 1 Aug 2008 23:39:52 +0000 (23:39 +0000)
139 files changed:
1  2 
bin/.blender/.Blanguages
intern/boolop/intern/BOP_Edge.cpp
intern/boolop/intern/BOP_Edge.h
intern/boolop/intern/BOP_Face.cpp
intern/boolop/intern/BOP_Face.h
intern/boolop/intern/BOP_Interface.cpp
intern/boolop/intern/BOP_Merge.cpp
intern/boolop/intern/BOP_Merge.h
intern/boolop/intern/BOP_Merge2.cpp
intern/boolop/intern/BOP_Merge2.h
intern/boolop/intern/BOP_Mesh.cpp
intern/boolop/intern/BOP_Mesh.h
intern/boolop/intern/BOP_Misc.h
intern/boolop/intern/BOP_Tag.h
intern/boolop/intern/BOP_Vertex.cpp
intern/boolop/intern/BOP_Vertex.h
projectfiles_vc7/gameengine/blenderhook/KX_blenderhook.vcproj
release/scripts/rvk1_torvk2.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/BKE_texture.h
source/blender/blenkernel/bad_level_call_stubs/stubs.c
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/collision.c
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/texture.c
source/blender/blenlib/intern/freetypefont.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/include/BDR_gpencil.h
source/blender/include/BIF_editarmature.h
source/blender/include/BIF_editview.h
source/blender/makesdna/DNA_armature_types.h
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_customdata_types.h
source/blender/makesdna/DNA_gpencil_types.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_object_types.h
source/blender/python/api2_2x/Armature.c
source/blender/python/api2_2x/Bone.c
source/blender/python/api2_2x/doc/Armature.py
source/blender/python/api2_2x/sceneRender.c
source/blender/src/buttons_editing.c
source/blender/src/buttons_logic.c
source/blender/src/buttons_object.c
source/blender/src/drawgpencil.c
source/blender/src/drawview.c
source/blender/src/editarmature.c
source/blender/src/editipo.c
source/blender/src/editobject.c
source/blender/src/editview.c
source/blender/src/gpencil.c
source/blender/src/header_info.c
source/blender/src/header_ipo.c
source/blender/src/header_view3d.c
source/blender/src/interface.c
source/blender/src/meshlaplacian.c
source/blender/src/outliner.c
source/blender/src/poseobject.c
source/blender/src/sequence.c
source/blender/src/space.c
source/blender/src/transform_conversions.c
source/blender/src/transform_manipulator.c
source/creator/creator.c
source/gameengine/BlenderRoutines/KX_BlenderGL.cpp
source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp
source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h
source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp
source/gameengine/Converter/BL_ActionActuator.cpp
source/gameengine/Converter/BL_ArmatureObject.cpp
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/KX_ConvertSensors.cpp
source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp
source/gameengine/GameLogic/SCA_ActuatorEventManager.h
source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp
source/gameengine/GameLogic/SCA_AlwaysEventManager.h
source/gameengine/GameLogic/SCA_EventManager.cpp
source/gameengine/GameLogic/SCA_EventManager.h
source/gameengine/GameLogic/SCA_IObject.cpp
source/gameengine/GameLogic/SCA_ISensor.cpp
source/gameengine/GameLogic/SCA_ISensor.h
source/gameengine/GameLogic/SCA_JoystickManager.cpp
source/gameengine/GameLogic/SCA_JoystickManager.h
source/gameengine/GameLogic/SCA_KeyboardManager.cpp
source/gameengine/GameLogic/SCA_KeyboardManager.h
source/gameengine/GameLogic/SCA_LogicManager.cpp
source/gameengine/GameLogic/SCA_LogicManager.h
source/gameengine/GameLogic/SCA_MouseManager.cpp
source/gameengine/GameLogic/SCA_MouseManager.h
source/gameengine/GameLogic/SCA_PropertyEventManager.cpp
source/gameengine/GameLogic/SCA_PropertyEventManager.h
source/gameengine/GameLogic/SCA_RandomEventManager.cpp
source/gameengine/GameLogic/SCA_RandomEventManager.h
source/gameengine/GameLogic/SCA_TimeEventManager.cpp
source/gameengine/GameLogic/SCA_TimeEventManager.h
source/gameengine/Ketsji/BL_BlenderShader.cpp
source/gameengine/Ketsji/BL_BlenderShader.h
source/gameengine/Ketsji/BL_Material.h
source/gameengine/Ketsji/BL_Texture.cpp
source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp
source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h
source/gameengine/Ketsji/KX_BlenderMaterial.cpp
source/gameengine/Ketsji/KX_BlenderMaterial.h
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
source/gameengine/Ketsji/KX_NearSensor.cpp
source/gameengine/Ketsji/KX_NearSensor.h
source/gameengine/Ketsji/KX_PolygonMaterial.cpp
source/gameengine/Ketsji/KX_PolygonMaterial.h
source/gameengine/Ketsji/KX_RayEventManager.cpp
source/gameengine/Ketsji/KX_RayEventManager.h
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_TouchEventManager.cpp
source/gameengine/Ketsji/KX_TouchEventManager.h
source/gameengine/Ketsji/KX_TouchSensor.cpp
source/gameengine/Ketsji/KX_TouchSensor.h
source/gameengine/Ketsji/KX_TrackToActuator.cpp
source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp
source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp
source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h
source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
source/gameengine/Rasterizer/RAS_BucketManager.cpp
source/gameengine/Rasterizer/RAS_BucketManager.h
source/gameengine/Rasterizer/RAS_CameraData.h
source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
source/gameengine/Rasterizer/RAS_IRasterizer.h
source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
source/gameengine/Rasterizer/RAS_MaterialBucket.h
source/gameengine/Rasterizer/RAS_MeshObject.cpp
source/gameengine/Rasterizer/RAS_MeshObject.h
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
source/gameengine/Rasterizer/RAS_Polygon.cpp

index 0f98ce02247dc87107f9aa8409740cbf25b02788,0f98ce02247dc87107f9aa8409740cbf25b02788..de8d8c44550e709fa8850792a3ec96331ecc462b
@@@ -20,3 -20,3 +20,4 @@@ Romanian:r
  Arabic:ar
  Bulgarian:bg
  Greek:el
++Korean:kr
index ac302b530dfa3eefca4d0b7419211de791be1300,ac302b530dfa3eefca4d0b7419211de791be1300..44e7d5cb5676c3e00e86ebad220e984be0e96b43
@@@ -75,4 -75,4 +75,47 @@@ void BOP_Edge::replaceVertexIndex(BOP_I
        else if (m_vertexs[1] == oldIndex) m_vertexs[1] = newIndex;
  }
  
++#ifdef BOP_NEW_MERGE
++
++/**
++ * Returns if this edge contains the specified face index.
++ * @param i face index
++ * @return true if this edge contains the specified face index, false otherwise
++ */
++bool BOP_Edge::removeFace(BOP_Index i)
++{
++      int pos=0;
++      for(BOP_IT_Indexs it = m_faces.begin();it!=m_faces.end();pos++,it++) {
++              if ((*it) == i) {
++                      m_faces.erase(it);
++                      return true;
++              }
++      }
++      
++      return false;
++}
++
++#endif
++
++#ifdef BOP_DEBUG
++
++#include <iostream>
++using namespace std;
++
++/**
++ * Implements operator <<.
++ */
++ostream &operator<<(ostream &stream, BOP_Edge *e)
++{
++      stream << "Edge[" << e->getVertex1() << "," << e->getVertex2();
++#ifdef BOP_NEW_MERGE
++      if(e->m_used)
++              stream << "] (used)";
++      else
++              stream << "] (unused)";
++#endif
++      return stream;
++}
++#endif
++
  
index 13426f6e63ce935d69230ff1dc98e233b1d3b846,13426f6e63ce935d69230ff1dc98e233b1d3b846..a817b3d624fde33c1b79d6afb4f298c437bd7237
  #define BOP_EDGE_H
  
  #include "BOP_Indexs.h"
++#include "BOP_Misc.h"
  
  class BOP_Edge
  {
  private:
        BOP_Index  m_vertexs[2];
        BOP_Indexs m_faces;
++#ifdef BOP_NEW_MERGE
++      bool m_used;
++#endif
  
        bool containsFace(BOP_Index i);
  
@@@ -47,6 -47,6 +51,15 @@@ public
        inline unsigned int getNumFaces(){return m_faces.size();};
        inline BOP_Indexs &getFaces(){return m_faces;};
        void addFace(BOP_Index face);
++#ifdef BOP_NEW_MERGE
++      bool removeFace(BOP_Index i);
++      bool getUsed() { return m_used;};
++      void setUsed(bool setting) { m_used=setting;};
++#endif
++#ifdef BOP_DEBUG
++      friend ostream &operator<<(ostream &stream, BOP_Edge *e);
++#endif
++
  };
  
  #endif
index 12c94624517d3555d791608781d336a84a49ec0d,12c94624517d3555d791608781d336a84a49ec0d..01308de3e5de50c867287877ec7226eca9195830
@@@ -402,6 -402,6 +402,7 @@@ bool BOP_Face4::getEdgeIndex(BOP_Index 
        return  true;
  }  
  
++#ifdef BOP_DEBUG
  /**
   * Implements operator <<.
   */
@@@ -421,3 -421,3 +422,4 @@@ ostream &operator<<(ostream &stream, BO
  
        return stream;
  }
++#endif
index e16425f78b320d2f07c84ec9c6ce1749e0817f4d,e16425f78b320d2f07c84ec9c6ce1749e0817f4d..965882db7320b200654670f49eb2970f7c6da614
@@@ -32,6 -32,6 +32,7 @@@
  #include "MT_Plane3.h"
  #include "BOP_Indexs.h"
  #include "BOP_BBox.h"
++#include "BOP_Misc.h"
  #include <iostream>
  #include <vector>
  using namespace std;
@@@ -80,7 -80,7 +81,9 @@@ public
        virtual void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) = 0;
        virtual bool containsVertex(BOP_Index v) = 0;
                
++#ifdef BOP_DEBUG
        friend ostream &operator<<(ostream &stream, BOP_Face *f);
++#endif
  };
  
  class BOP_Face3: public BOP_Face 
index 2a1981039311645d9c2b6ebbad985d564f613639,2a1981039311645d9c2b6ebbad985d564f613639..898ca708204168a097b1a4015fef5f34edda25af
  #include "BOP_Mesh.h"
  #include "BOP_Face2Face.h"
  #include "BOP_Merge.h"
++#include "BOP_Merge2.h"
  #include "BOP_Chrono.h"
  
--//#define DEBUG
++#if defined(BOP_ORIG_MERGE) && defined(BOP_NEW_MERGE) 
++#include "../../source/blender/blenkernel/BKE_global.h"
++#endif
  
  BoolOpState BOP_intersectionBoolOp(BOP_Mesh*  meshC,
                                                                   BOP_Faces* facesA,
@@@ -208,7 -208,7 +211,32 @@@ BoolOpState BOP_intersectionBoolOp(BOP_
        #endif
  
        // Merge faces
++#ifdef BOP_ORIG_MERGE
++#ifndef BOP_NEW_MERGE
        BOP_Merge::getInstance().mergeFaces(meshC,numVertices);
++#endif
++#endif
++
++#ifdef BOP_NEW_MERGE
++#ifndef BOP_ORIG_MERGE
++      BOP_Merge2::getInstance().mergeFaces(meshC,numVertices);
++#else
++      static int state = -1;
++      if (G.rt == 100) {
++              if( state != 1 ) {
++                      cout << "Boolean code using old merge technique." << endl;
++                      state = 1;
++              }
++              BOP_Merge::getInstance().mergeFaces(meshC,numVertices);
++      } else {
++              if( state != 0 ) {
++                      cout << "Boolean code using new merge technique." << endl;
++                      state = 0;
++              }
++              BOP_Merge2::getInstance().mergeFaces(meshC,numVertices);
++      }
++#endif
++#endif
  
        #ifdef DEBUG
        c = chrono.stamp(); t += c;
index 1e4139ab971318a7914b2c32e27b7554cea00dd8,1e4139ab971318a7914b2c32e27b7554cea00dd8..012d34091877f5648fe913f6309986ba41f5cc4a
@@@ -30,6 -30,6 +30,7 @@@
   
  #include "BOP_Merge.h"
  
++#ifdef BOP_ORIG_MERGE
  
  #ifdef _MSC_VER
  #if _MSC_VER < 1300
@@@ -802,3 -802,3 +803,5 @@@ void BOP_Merge::getFaces(BOP_LFaces &fa
        }
        }
  }
++
++#endif  /* BOP_ORIG_MERGE */
index 88999b2e734a194b7249dd098fd23f033b8f56ba,88999b2e734a194b7249dd098fd23f033b8f56ba..ceb8ec10690eecc9ca82ebbb8029ee9d0256770f
@@@ -28,6 -28,6 +28,9 @@@
  #ifndef BOP_MERGE_H
  #define BOP_MERGE_H
  
++#include "BOP_Misc.h"
++
++#ifdef BOP_ORIG_MERGE
  #include "BOP_Mesh.h"
  #include "BOP_Tag.h"
  #include "BOP_MathUtils.h"
@@@ -68,4 -68,4 +71,6 @@@ class BOP_Merge 
                void mergeFaces(BOP_Mesh *m, BOP_Index v);
  };
  
++#endif        /* BOP_ORIG_MERGE */
++
  #endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bbf3f8ba702a5e803666e9c3d21a6c130bc7dcac
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,944 @@@
++/**
++ *
++ * $Id: BOP_Merge22.cpp 14444 2008-04-16 22:40:48Z hos $
++ *
++ * ***** BEGIN GPL LICENSE BLOCK *****
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
++ * All rights reserved.
++ *
++ * The Original Code is: all of this file.
++ *
++ * Contributor(s): Marc Freixas, Ken Hughes
++ *
++ * ***** END GPL LICENSE BLOCK *****
++ */
++ 
++#include "BOP_Merge2.h"
++
++#ifdef BOP_NEW_MERGE
++
++static void deleteFace(BOP_Mesh *m, BOP_Face *face);
++
++/**
++ * SINGLETON (use method BOP_Merge2.getInstance).
++ */
++BOP_Merge2 BOP_Merge2::SINGLETON;
++
++#ifdef BOP_DEBUG
++void dumpmesh ( BOP_Mesh *m, bool force )
++{
++      unsigned int nonmanifold = 0;
++      {
++      BOP_Edges edges = m->getEdges();
++      int count = 0;
++    for (BOP_IT_Edges edge = edges.begin(); edge != edges.end();
++              ++count, ++edge) {
++              if (!(*edge)->getUsed() && (*edge)->getFaces().size() == 0 ) continue;
++              BOP_Vertex * v1 = m->getVertex((*edge)->getVertex1());
++              BOP_Vertex * v2 = m->getVertex((*edge)->getVertex2());
++
++              if(v1->getTAG()!= BROKEN || v2->getTAG()!= BROKEN ) {
++                      int fcount = 0;
++                      BOP_Indexs faces = (*edge)->getFaces();
++                      for (BOP_IT_Indexs face = faces.begin(); face != faces.end(); face++) {
++                              BOP_Face *f = m->getFace(*face);
++                              if(f->getTAG()== UNCLASSIFIED) ++fcount;
++                      }
++
++
++                      if(fcount !=0 && fcount !=2 ) {
++                              ++nonmanifold;
++                      }
++              }
++      }
++      if (!force && nonmanifold == 0) return;
++      }
++      if( nonmanifold )
++              cout << nonmanifold << " edges detected" << endl;
++#ifdef DEBUG
++      cout << "---------------------------" << endl;
++
++      BOP_Edges edges = m->getEdges();
++      int count = 0;
++    for (BOP_IT_Edges edge = edges.begin(); edge != edges.end();
++              ++count, ++edge) {
++              BOP_Vertex * v1 = m->getVertex((*edge)->getVertex1());
++              BOP_Vertex * v2 = m->getVertex((*edge)->getVertex2());
++
++              if(v1->getTAG()!= BROKEN || v2->getTAG()!= BROKEN ) {
++                      int fcount = 0;
++                      BOP_Indexs faces = (*edge)->getFaces();
++                      cout << count << ", " << (*edge) << ", " << faces.size() << endl;
++                      for (BOP_IT_Indexs face = faces.begin(); face != faces.end(); face++) {
++                              BOP_Face *f = m->getFace(*face);
++                              if(f->getTAG()== UNCLASSIFIED) ++fcount;
++                              cout << "  face " << f << endl;
++                      }
++
++
++                      if(fcount !=0 && fcount !=2 )
++                              cout << "    NON-MANIFOLD" << endl;
++              }
++      }
++
++      BOP_Faces faces = m->getFaces();
++      count = 0;
++    for (BOP_IT_Faces face = faces.begin(); face != faces.end(); face++) {
++              if( count < 12*2 || (*face)->getTAG() != BROKEN ) {
++                      cout << count << ", " << *face << endl;
++              }
++              ++count;
++      }
++
++      BOP_Vertexs verts = m->getVertexs();
++      count = 0;
++    for (BOP_IT_Vertexs vert = verts.begin(); vert != verts.end(); vert++) {
++              cout << count++ << ", " << *vert << " " << (*vert)->getNumEdges() << endl;
++              BOP_Indexs edges = (*vert)->getEdges();
++          for( BOP_IT_Indexs it = edges.begin(); it != edges.end(); ++it) {
++                      BOP_Edge *edge = m->getEdge(*it);
++                      cout << "   " << edge << endl;
++              }
++      }
++      cout << "===========================" << endl;
++#endif
++}
++#endif
++
++/**
++ * Simplifies a mesh, merging its faces.
++ * @param m mesh
++ * @param v index of the first mergeable vertex (can be removed by merge) 
++ */
++
++void BOP_Merge2::mergeFaces(BOP_Mesh *m, BOP_Index v)
++{
++      m_mesh = m;
++
++#ifdef DEBUG
++      cout << "##############################" << endl;
++#endif
++      cleanup( );
++
++      m_firstVertex = v;
++      bool cont = false;
++
++      // Merge faces
++      mergeFaces();   
++
++      do {
++              // Add quads ...
++              cont = createQuads();
++              // ... and merge new faces
++              if( cont ) cont = mergeFaces();
++
++#ifdef DEBUG
++              cout << "called mergeFaces " << cont << endl;
++#endif
++              // ... until the merge is not succesful
++      } while(cont);
++}
++
++void clean_nonmanifold( BOP_Mesh *m )
++{
++      return;
++
++      BOP_Edges nme;
++      BOP_Edges e = m->getEdges();
++      for( BOP_IT_Edges it = e.begin(); it != e.end(); ++it ) {
++              BOP_Indexs faces = (*it)->getFaces();
++              if( faces.size() & ~2 )
++                      nme.push_back(*it);
++      }
++      if (nme.size() == 0) return;
++      for( BOP_IT_Edges it = nme.begin(); it != nme.end(); ++it ) {
++              if( (*it)->getFaces().size() > 1 ) {
++                      BOP_Indexs faces = (*it)->getFaces();
++                      for( BOP_IT_Indexs face = faces.begin(); face != faces.end(); ++face ) {
++                              MT_Point3 vertex1 = m->getVertex(m->getFace(*face)->getVertex(0))->getPoint();
++                              MT_Point3 vertex2 = m->getVertex(m->getFace(*face)->getVertex(1))->getPoint();
++                              MT_Point3 vertex3 = m->getVertex(m->getFace(*face)->getVertex(2))->getPoint();
++                              if (BOP_collinear(vertex1,vertex2,vertex3)) // collinear triangle
++                                      deleteFace(m,m->getFace(*face));
++                      }
++                      continue;
++              }
++              BOP_Face *oface1 = m->getFace((*it)->getFaces().front());
++              BOP_Face *oface2, *tmpface;
++              BOP_Index first =(*it)->getVertex1();
++              BOP_Index next =(*it)->getVertex2();
++              BOP_Index last = first;
++              unsigned short facecount = 0;
++              bool found = false;
++              BOP_Indexs vertList;
++#ifdef DEBUG
++              cout << "  first edge is " << (*it) << endl;
++#endif
++              vertList.push_back(first);
++              BOP_Edge *edge;
++              while(true) {
++                      BOP_Vertex *vert = m->getVertex(next);
++                      BOP_Indexs edges = vert->getEdges();
++                      edge = NULL;
++                      for( BOP_IT_Indexs eit = edges.begin(); eit != edges.end(); ++eit) {
++                              edge = m->getEdge(*eit);
++                              if( edge->getFaces().size() > 1) {
++                                      edge = NULL;
++                                      continue;
++                              }
++                              if( edge->getVertex1() == next && edge->getVertex2() != last ) {
++                                      last = next;
++                                      next = edge->getVertex2();
++                                      break;
++                              }
++                              if( edge->getVertex2() == next && edge->getVertex1() != last ) {
++                                      last = next;
++                                      next = edge->getVertex1();
++                                      break;
++                              }
++                              edge = NULL;
++                      }
++                      if( !edge ) break;
++#ifdef DEBUG
++                      cout << "   next edge is " << edge << endl;
++#endif
++                      tmpface = m->getFace(edge->getFaces().front());
++                      if( oface1->getOriginalFace() != tmpface->getOriginalFace() )
++                              oface2 = tmpface;
++                      else
++                              ++facecount;
++                      vertList.push_back(last);
++                      if( vertList.size() > 3 ) break;
++                      if( next == first ) {
++                              found = true;
++                              break;
++                      }
++              }
++              if(found) {
++                      edge = *it;
++#ifdef DEBUG
++                      cout << "   --> found a loop" << endl;
++#endif
++                      if( vertList.size() == 3 ) {
++                              BOP_Face3 *face = (BOP_Face3 *)m->getFace(edge->getFaces().front());
++                              face->getNeighbours(first,last,next);
++                      } else if( vertList.size() == 4 ) {
++                              BOP_Face4 *face = (BOP_Face4 *)m->getFace(edge->getFaces().front());
++                              face->getNeighbours(first,last,next,last);
++                      } else {
++#ifdef DEBUG
++                              cout << "loop has " << vertList.size() << "verts"; 
++#endif
++                              continue;
++                      }
++                      if(facecount == 1) oface1 = oface2;
++                      next = vertList[1];
++                      last = vertList[2];
++                      if( edge->getVertex2() == next ) { 
++                              BOP_Face3 *f = new BOP_Face3(next,first,last,
++                                      oface1->getPlane(),oface1->getOriginalFace());
++                              m->addFace( f );
++#ifdef DEBUG
++                              cout << "   face is backward: " << f << endl;
++#endif
++                              
++                      } else {
++                              BOP_Face3 *f = new BOP_Face3(last,first,next,
++                                      oface1->getPlane(),oface1->getOriginalFace());
++                              m->addFace( f );
++#ifdef DEBUG
++                              cout << "   face is forward: " << f << endl;
++#endif
++                      }
++              }
++      }
++}
++
++/**
++ * Runs through mesh and makes sure vert/face/edge data is consistent.  Most
++ * importantly:
++ * (1) mark edges which are no longer used
++ * (2) remove broken faces from edges
++ * (3) remove faces from mesh which have a single edge belonging to no other
++ *     face (non-manifold edges)
++ */
++
++void BOP_Merge2::cleanup( void )
++{
++      BOP_Edges edges = m_mesh->getEdges();
++      for (BOP_IT_Edges edge = edges.begin(); edge != edges.end(); ++edge) {
++              BOP_Indexs faces = (*edge)->getFaces();
++              for (BOP_IT_Indexs face = faces.begin(); face != faces.end(); ++face) {
++                      BOP_Face *f = m_mesh->getFace(*face);
++                      if(f->getTAG()== UNCLASSIFIED) ;
++                      else (*edge)->removeFace(*face);
++              }
++              if( (*edge)->getFaces().size() == 0) (*edge)->setUsed(false);
++      }
++
++      BOP_Vertexs v = m_mesh->getVertexs();
++      for( BOP_IT_Vertexs it = v.begin(); it != v.end(); ++it ) {
++              if( (*it)->getTAG() != BROKEN) {
++                      BOP_Indexs edges = (*it)->getEdges();
++                      for(BOP_IT_Indexs i = edges.begin();i!=edges.end();i++)
++                              if( m_mesh->getEdge((*i))->getUsed( ) == false) (*it)->removeEdge( *i );
++                      if( (*it)->getEdges().size() == 0 ) (*it)->setTAG(BROKEN);
++              }
++      }
++      // clean_nonmanifold( m_mesh );
++}
++
++/**
++ * Simplifies a mesh, merging its faces.
++ */
++bool BOP_Merge2::mergeFaces()
++{
++      BOP_Indexs mergeVertices;
++      BOP_Vertexs vertices = m_mesh->getVertexs();
++      BOP_IT_Vertexs v = vertices.begin();
++      const BOP_IT_Vertexs verticesEnd = vertices.end();
++
++      // Advance to first mergeable vertex
++      advance(v,m_firstVertex);
++      BOP_Index pos = m_firstVertex;
++
++      // Add unbroken vertices to the list
++      while(v!=verticesEnd) {
++              if ((*v)->getTAG() != BROKEN) {
++                      mergeVertices.push_back(pos);
++              }
++
++              v++;
++              pos++;
++      }
++
++      // Merge faces with that vertices
++      return mergeFaces(mergeVertices);
++}
++
++/**
++ * remove edges from vertices when the vertex is removed
++ */
++void BOP_Merge2::freeVerts(BOP_Index v, BOP_Vertex *vert)
++{
++      BOP_Indexs edges = vert->getEdges();
++      BOP_Vertex *other;
++
++      for( BOP_IT_Indexs it = edges.begin(); it != edges.end(); ++it) {
++              BOP_Edge *edge = m_mesh->getEdge(*it);
++              BOP_Indexs edges2;
++              if( edge->getVertex1() != v )
++                      other = m_mesh->getVertex( edge->getVertex1() );
++              else
++                      other = m_mesh->getVertex( edge->getVertex2() );
++              other->removeEdge(*it);
++              vert->removeEdge(*it);
++      }
++}
++
++/**
++ * Simplifies a mesh, merging the faces with the specified vertices.
++ * @param mergeVertices vertices to test
++ * @return true if a face merge was performed
++ */
++bool BOP_Merge2::mergeFaces(BOP_Indexs &mergeVertices)
++{
++      // Check size > 0!
++      if (mergeVertices.size() == 0) return false;
++      bool didMerge = false;
++
++      for( BOP_Index i = 0; i < mergeVertices.size(); ++i ) {
++              BOP_LFaces facesByOriginalFace;
++              BOP_Index v = mergeVertices[i];
++              BOP_Vertex *vert = m_mesh->getVertex(v);
++#ifdef DEBUG
++              cout << "i = " << i << ", v = " << v << ", vert = " << vert << endl;
++              if (v==48)
++                      cout << "found vert 48" << endl;
++#endif
++              if ( vert->getTAG() != BROKEN ) {
++                      getFaces(facesByOriginalFace,v);
++
++                      switch (facesByOriginalFace.size()) {
++                      case 0:
++                              // v has no unbroken faces (so it's a new BROKEN vertex)
++                              freeVerts( v, vert );
++                              vert->setTAG(BROKEN);
++                              break;
++                      case 2: {
++#ifdef DEBUG
++                              cout << "size of fBOF = " << facesByOriginalFace.size() << endl;
++#endif
++                              BOP_Faces ff = facesByOriginalFace.front();
++                              BOP_Faces fb = facesByOriginalFace.back();
++                              BOP_Index eindexs[2];
++                              int ecount = 0;
++
++                              // look for two edges adjacent to v which contain both ofaces
++                              BOP_Indexs edges = vert->getEdges();
++#ifdef DEBUG
++                              cout << "   ff has " << ff.size() << " faces" << endl;
++                              cout << "   fb has " << fb.size() << " faces" << endl;
++                              cout << "   v  has " << edges.size() << " edges" << endl;
++#endif
++                              for(BOP_IT_Indexs it = edges.begin(); it != edges.end(); 
++                                              ++it ) {
++                                      BOP_Edge *edge = m_mesh->getEdge(*it);
++                                      BOP_Indexs faces = edge->getFaces();
++#ifdef DEBUG
++                                      cout << "  " << edge << " has " << edge->getFaces().size() << " faces" << endl;
++#endif
++                                      if( faces.size() == 2 ) {
++                                              BOP_Face *f0 = m_mesh->getFace(faces[0]);
++                                              BOP_Face *f1 = m_mesh->getFace(faces[1]);
++                                              if( f0->getOriginalFace() != f1->getOriginalFace() ) {
++#ifdef DEBUG
++                                                      cout << "   " << f0 << endl;
++                                                      cout << "   " << f1 << endl;
++#endif
++                                                      eindexs[ecount++] = (*it);
++                                              }
++                                      }
++                              }
++                              if(ecount == 2) {
++#ifdef DEBUG
++                                      cout << "   edge indexes are " << eindexs[0];
++                                      cout << " and " << eindexs[1] << endl;
++#endif
++                                      BOP_Edge *edge = m_mesh->getEdge(eindexs[0]);
++                                      BOP_Index N = edge->getVertex1();
++                                      if(N == v) N = edge->getVertex2();
++#ifdef DEBUG
++                                      cout << "    ## OK, replace "<<v<<" with "<<N << endl;
++#endif
++                                      mergeVertex(ff , v, N );
++                                      mergeVertex(fb , v, N );
++// now remove v and its edges
++                                      vert->setTAG(BROKEN);
++                                      for(BOP_IT_Indexs it = edges.begin(); it != edges.end(); 
++                                                      ++it ) {
++                                              BOP_Edge *edge = m_mesh->getEdge(*it);
++                                              edge->setUsed(false);
++                                      }
++                                      didMerge = true;
++                              }       
++#ifdef DEBUG
++                              else {
++                                      cout << "   HUH: ecount was " << ecount << endl;
++                              }
++#endif
++                              }
++                              break;
++                      default:
++                              break;
++                      }
++              }
++      }
++
++      return didMerge;
++}
++
++void BOP_Merge2::mergeVertex(BOP_Faces &faces, BOP_Index v1, BOP_Index v2)
++{
++      for(BOP_IT_Faces face=faces.begin();face!=faces.end();face++) {
++              if( (*face)->size() == 3)
++                      mergeVertex((BOP_Face3 *) *face, v1, v2);
++              else
++                      mergeVertex((BOP_Face4 *) *face, v1, v2);
++              (*face)->setTAG(BROKEN);
++#ifdef DEBUG
++              cout << "  breaking " << (*face) << endl;
++#endif
++      }
++}
++
++/*
++ * Remove a face from the mesh and from each edges's face list
++ */
++
++static void deleteFace(BOP_Mesh *m, BOP_Face *face)
++{
++      BOP_Index l2 = face->getVertex(0);
++      BOP_Faces faces = m->getFaces();
++      for(int i = face->size(); i-- ; ) {
++              BOP_Indexs edges = m->getVertex(l2)->getEdges();
++              BOP_Index l1 = face->getVertex(i);
++              for(BOP_IT_Indexs it1 = edges.begin(); it1 != edges.end(); ++it1 ) {
++                      BOP_Edge *edge = m->getEdge(*it1);
++                      if( ( edge->getVertex1() == l1 && edge->getVertex2() == l2 ) ||
++                              ( edge->getVertex1() == l2 && edge->getVertex2() == l1 ) ) {
++                              BOP_Indexs ef = edge->getFaces();
++                              for(BOP_IT_Indexs it = ef.begin(); it != ef.end(); ++it ) {
++                                      if( m->getFace(*it) == face) {
++                                              edge->removeFace(*it);
++                                              break;
++                                      }
++                              }
++                              break;
++                      }
++              }
++              l2 = l1;
++      }
++      face->setTAG(BROKEN);
++}
++
++void BOP_Merge2::mergeVertex(BOP_Face3 *face, BOP_Index v1, BOP_Index v2)
++{
++      BOP_Index next, prev;
++      face->getNeighbours(v1,prev,next);
++
++      // if new vertex is not already in the tri, make a new tri
++      if( prev != v2 && next != v2 ) {
++              m_mesh->addFace( new BOP_Face3(prev,v2,next,
++                                      face->getPlane(),face->getOriginalFace()) );
++#ifdef DEBUG
++              cout << "mv3: add " << prev << "," << v2 << "," << next << endl;
++      } else {
++              cout << "mv3: vertex already in tri: doing nothing" << endl;
++#endif
++      }
++      deleteFace(m_mesh, face);
++}
++
++void BOP_Merge2::mergeVertex(BOP_Face4 *face, BOP_Index v1, BOP_Index v2)
++{
++      BOP_Index next, prev, opp;
++      face->getNeighbours(v1,prev,next,opp);
++
++      // if new vertex is already in the quad, replace quad with new tri
++      if( prev == v2 || next == v2 ) {
++              m_mesh->addFace( new BOP_Face3(prev,next,opp,
++                                      face->getPlane(),face->getOriginalFace()) );
++#ifdef DEBUG
++              cout << "mv4a: add " << prev << "," << next << "," << opp << endl;
++#endif
++      }
++      // otherwise make a new quad
++      else {
++              m_mesh->addFace( new BOP_Face4(prev,v2,next,opp,
++                                      face->getPlane(),face->getOriginalFace()) );
++#ifdef DEBUG
++              cout << "mv4b: add "<<prev<<","<<v2<<","<<next<<","<<opp<<endl;
++#endif
++      }
++      deleteFace(m_mesh, face);
++}
++
++// #define OLD_QUAD
++
++/** 
++ * Simplifies the mesh, merging the pairs of triangles that come frome the
++ * same original face and define a quad.
++ * @return true if a quad was added, false otherwise
++ */
++bool BOP_Merge2::createQuads()
++{
++  
++      BOP_Faces quads;
++      
++      // Get mesh faces
++      BOP_Faces faces = m_mesh->getFaces();
++      
++    // Merge mesh triangles
++      const BOP_IT_Faces facesIEnd = (faces.end()-1);
++      const BOP_IT_Faces facesJEnd = faces.end();
++      for(BOP_IT_Faces faceI=faces.begin();faceI!=facesIEnd;faceI++) {
++#ifdef OLD_QUAD
++              if ((*faceI)->getTAG() == BROKEN || (*faceI)->size() != 3) continue;
++              for(BOP_IT_Faces faceJ=(faceI+1);faceJ!=facesJEnd;faceJ++) {
++                      if ((*faceJ)->getTAG() == BROKEN || (*faceJ)->size() != 3 ||
++                              (*faceJ)->getOriginalFace() != (*faceI)->getOriginalFace()) continue;
++
++
++                      BOP_Face *faceK = createQuad((BOP_Face3*)*faceI,(BOP_Face3*)*faceJ);
++                      if (faceK != NULL) {
++                              // Set triangles to BROKEN
++                              deleteFace(m_mesh, *faceI);
++                              deleteFace(m_mesh, *faceJ);
++#ifdef DEBUG
++                      cout << "createQuad: del " << *faceI << endl;
++                      cout << "createQuad: del " << *faceJ << endl;
++                      cout << "createQuad: add " << faceK << endl;
++#endif
++                              quads.push_back(faceK);
++                              break;
++                      }
++              }
++#else
++              if ((*faceI)->getTAG() == BROKEN ) continue;
++              for(BOP_IT_Faces faceJ=(faceI+1);faceJ!=facesJEnd;faceJ++) {
++                      if ((*faceJ)->getTAG() == BROKEN ||
++                              (*faceJ)->getOriginalFace() != (*faceI)->getOriginalFace()) continue;
++
++                      BOP_Face *faceK = NULL;
++                      if((*faceI)->size() == 3) {
++                              if((*faceJ)->size() == 3)
++                                      faceK = createQuad((BOP_Face3*)*faceI,(BOP_Face3*)*faceJ);
++                              else
++                                      faceK = createQuad((BOP_Face3*)*faceI,(BOP_Face4*)*faceJ);
++                      } else {
++                              if((*faceJ)->size() == 3)
++                                      faceK = createQuad((BOP_Face3*)*faceJ,(BOP_Face4*)*faceI);
++                              else
++                                      faceK = createQuad((BOP_Face4*)*faceI,(BOP_Face4*)*faceJ);
++                      }
++
++                      if (faceK != NULL) {
++                              // Set triangles to BROKEN
++                              deleteFace(m_mesh, *faceI);
++                              deleteFace(m_mesh, *faceJ);
++#ifdef DEBUG
++                      cout << "createQuad: del " << *faceI << endl;
++                      cout << "createQuad: del " << *faceJ << endl;
++                      cout << "createQuad: add " << faceK << endl;
++#endif
++                              quads.push_back(faceK);
++                              break;
++                      }
++              }
++#endif
++      }
++
++    // Add quads to mesh
++      const BOP_IT_Faces quadsEnd = quads.end();
++      for(BOP_IT_Faces quad=quads.begin();quad!=quadsEnd;quad++) m_mesh->addFace(*quad);
++      return (quads.size() > 0);
++}
++
++/** 
++ * Returns a new quad (convex) from the merge of two triangles that share the
++ * vertex index v.
++ * @param faceI mesh triangle
++ * @param faceJ mesh triangle
++ * @param v vertex index shared by both triangles
++ * @return a new convex quad if the merge is possible
++ */
++BOP_Face* BOP_Merge2::createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ)
++{
++      // Test if both triangles share a vertex index
++      BOP_Index v;
++      unsigned int i;
++      for(i=0;i<3 ;i++) {
++              v = faceI->getVertex(i);
++              if( faceJ->containsVertex(v) ) break;
++      }
++      if (i == 3) return NULL;
++
++      BOP_Face *faceK = NULL;
++
++      // Get faces data
++      BOP_Index prevI, nextI, prevJ, nextJ;
++      faceI->getNeighbours(v,prevI,nextI);
++      faceJ->getNeighbours(v,prevJ,nextJ);
++      MT_Point3 vertex = m_mesh->getVertex(v)->getPoint();
++      MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint();
++      MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint();
++      MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint();
++      MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint();
++
++      // Quad test
++      if (prevI == nextJ) {
++              if (!BOP_collinear(vNextI,vertex,vPrevJ) && !BOP_collinear(vNextI,vPrevI,vPrevJ) &&
++                      BOP_convex(vertex,vNextI,vPrevI,vPrevJ)) {
++                              faceK = new BOP_Face4(v,nextI,prevI,prevJ,faceI->getPlane(),faceI->getOriginalFace());
++                              faceK->setTAG(faceI->getTAG());
++                              BOP_Index edge;
++                              m_mesh->getIndexEdge(v,prevI,edge);
++                              m_mesh->getVertex(v)->removeEdge(edge);
++                              m_mesh->getVertex(prevI)->removeEdge(edge);
++              }
++      }
++      else if (nextI == prevJ) {
++              if (!BOP_collinear(vPrevI,vertex,vNextJ) && !BOP_collinear(vPrevI,vNextI,vNextJ) &&
++                      BOP_convex(vertex,vNextJ,vNextI,vPrevI)) {
++                              faceK = new BOP_Face4(v,nextJ,nextI,prevI,faceI->getPlane(),faceI->getOriginalFace());
++                              faceK->setTAG(faceI->getTAG());
++                              BOP_Index edge;
++                              m_mesh->getIndexEdge(v,nextI,edge);
++                              m_mesh->getVertex(v)->removeEdge(edge);
++                              m_mesh->getVertex(nextI)->removeEdge(edge);
++                      }
++      }
++      return faceK;
++}
++
++/** 
++ * Returns a new quad (convex) from the merge of two triangles that share the
++ * vertex index v.
++ * @param faceI mesh triangle
++ * @param faceJ mesh triangle
++ * @param v vertex index shared by both triangles
++ * @return a new convex quad if the merge is possible
++ */
++BOP_Face* BOP_Merge2::createQuad(BOP_Face3 *faceI, BOP_Face4 *faceJ)
++{
++      // Test if triangle and quad share a vertex index
++      BOP_Index v;
++      unsigned int i;
++      for(i=0;i<3 ;i++) {
++              v = faceI->getVertex(i);
++              if( faceJ->containsVertex(v) ) break;
++      }
++      if (i == 3) return NULL;
++
++      BOP_Face *faceK = NULL;
++
++      // Get faces data
++      BOP_Index prevI, nextI, prevJ, nextJ, oppJ;
++      faceI->getNeighbours(v,prevI,nextI);
++      faceJ->getNeighbours(v,prevJ,nextJ,oppJ);
++
++      // Quad test
++      BOP_Index edge;
++      if (nextI == prevJ) {
++              if (prevI == nextJ) {   // v is in center
++                      faceK = new BOP_Face3(nextJ,oppJ,prevJ,faceI->getPlane(),faceI->getOriginalFace());
++                      faceK->setTAG(faceI->getTAG());
++                      m_mesh->getIndexEdge(v,prevI,edge);
++                      m_mesh->getVertex(v)->removeEdge(edge);
++                      m_mesh->getVertex(prevI)->removeEdge(edge);
++                      m_mesh->getIndexEdge(v,nextI,edge);
++                      m_mesh->getVertex(v)->removeEdge(edge);
++                      m_mesh->getVertex(nextI)->removeEdge(edge);
++                      freeVerts(v, m_mesh->getVertex(v));
++              } else if (prevI == oppJ) {     // nextI is in center
++                      faceK = new BOP_Face3(v,nextJ,oppJ,faceI->getPlane(),faceI->getOriginalFace());
++                      faceK->setTAG(faceI->getTAG());
++                      m_mesh->getIndexEdge(v,nextI,edge);
++                      m_mesh->getVertex(v)->removeEdge(edge);
++                      m_mesh->getVertex(nextI)->removeEdge(edge);
++                      m_mesh->getIndexEdge(prevI,nextI,edge);
++                      m_mesh->getVertex(prevI)->removeEdge(edge);
++                      m_mesh->getVertex(nextI)->removeEdge(edge);
++                      freeVerts(nextI, m_mesh->getVertex(nextI));
++              }
++      } else if (nextI == oppJ && prevI == nextJ ) { // prevI is in center
++              faceK = new BOP_Face3(prevJ,v,oppJ,faceI->getPlane(),faceI->getOriginalFace());
++              faceK->setTAG(faceI->getTAG());
++              m_mesh->getIndexEdge(v,prevI,edge);
++              m_mesh->getVertex(v)->removeEdge(edge);
++              m_mesh->getVertex(prevI)->removeEdge(edge);
++              m_mesh->getIndexEdge(nextI,prevI,edge);
++              m_mesh->getVertex(nextI)->removeEdge(edge);
++              m_mesh->getVertex(prevI)->removeEdge(edge);
++              freeVerts(prevI, m_mesh->getVertex(prevI));
++      }
++      return faceK;
++}
++
++/** 
++ * Returns a new quad (convex) from the merge of two triangles that share the
++ * vertex index v.
++ * @param faceI mesh triangle
++ * @param faceJ mesh triangle
++ * @param v vertex index shared by both triangles
++ * @return a new convex quad if the merge is possible
++ */
++BOP_Face* BOP_Merge2::createQuad(BOP_Face4 *faceI, BOP_Face4 *faceJ)
++{
++      BOP_Face *faceK = NULL;
++      //
++      // Test if both quads share a vertex index
++      //
++      BOP_Index v;
++      unsigned int i;
++      for(i=0;i<4 ;i++) {
++              v = faceI->getVertex(i);
++              if( faceJ->containsVertex(v) ) break;
++      }
++      if (i == 3) return NULL;
++
++
++      // Get faces data
++      BOP_Index prevI, nextI, oppI, prevJ, nextJ, oppJ;
++      faceI->getNeighbours(v,prevI,nextI,oppI);
++      faceJ->getNeighbours(v,prevJ,nextJ,oppJ);
++
++      // Quad test
++      BOP_Index edge;
++      if (nextI == prevJ) {
++              if (prevI == nextJ) {   // v is in center
++                      faceK = new BOP_Face4(nextI,oppI,nextJ,oppJ,faceI->getPlane(),faceI->getOriginalFace());
++                      faceK->setTAG(faceI->getTAG());
++                      m_mesh->getIndexEdge(v,prevI,edge);
++                      m_mesh->getVertex(v)->removeEdge(edge);
++                      m_mesh->getVertex(prevI)->removeEdge(edge);
++                      m_mesh->getIndexEdge(v,nextI,edge);
++                      m_mesh->getVertex(v)->removeEdge(edge);
++                      m_mesh->getVertex(nextI)->removeEdge(edge);
++                      freeVerts(v, m_mesh->getVertex(v));
++              } else if (oppI == oppJ) {      // nextI is in center
++                      faceK = new BOP_Face4(v,nextJ,oppJ,prevI,faceI->getPlane(),faceI->getOriginalFace());
++                      faceK->setTAG(faceI->getTAG());
++                      m_mesh->getIndexEdge(v,nextI,edge);
++                      m_mesh->getVertex(v)->removeEdge(edge);
++                      m_mesh->getVertex(nextI)->removeEdge(edge);
++                      m_mesh->getIndexEdge(prevI,nextI,edge);
++                      m_mesh->getVertex(prevI)->removeEdge(edge);
++                      m_mesh->getVertex(nextI)->removeEdge(edge);
++                      freeVerts(nextI, m_mesh->getVertex(nextI));
++              }
++      } else if (prevI == nextJ && oppI == oppJ) { // prevI is in center
++              faceK = new BOP_Face4(v,nextI,oppJ,prevJ,faceI->getPlane(),faceI->getOriginalFace());
++              faceK->setTAG(faceI->getTAG());
++              m_mesh->getIndexEdge(v,prevI,edge);
++              m_mesh->getVertex(v)->removeEdge(edge);
++              m_mesh->getVertex(prevI)->removeEdge(edge);
++              m_mesh->getIndexEdge(nextI,prevI,edge);
++              m_mesh->getVertex(nextI)->removeEdge(edge);
++              m_mesh->getVertex(prevI)->removeEdge(edge);
++              freeVerts(prevI, m_mesh->getVertex(prevI));
++      }
++      return faceK;
++}
++
++/**
++ * Returns if a index is inside a set of indexs.
++ * @param indexs set of indexs
++ * @param i index
++ * @return true if the index is inside the set, false otherwise
++ */
++bool BOP_Merge2::containsIndex(BOP_Indexs indexs, BOP_Index i)
++{
++  const BOP_IT_Indexs indexsEnd = indexs.end();
++      for(BOP_IT_Indexs it=indexs.begin();it!=indexsEnd;it++) {
++              if (*it == i) return true;
++      }
++      return false;
++}
++
++/**
++ * Creates a list of lists L1, L2, ... LN where
++ *   LX = mesh faces with vertex v that come from the same original face
++ * @param facesByOriginalFace list of faces lists
++ * @param v vertex index
++ */
++void BOP_Merge2::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Index v)
++{
++      // Get edges with vertex v
++
++      BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges();
++      const BOP_IT_Indexs edgeEnd = edgeIndexs.end();
++      for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) {    
++              // For each edge, add its no broken faces to the output list
++              BOP_Edge* edge = m_mesh->getEdge(*edgeIndex);
++              BOP_Indexs faceIndexs = edge->getFaces();
++              const BOP_IT_Indexs faceEnd = faceIndexs.end();
++              for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) {
++                      BOP_Face* face = m_mesh->getFace(*faceIndex);
++                      if (face->getTAG() != BROKEN) {
++                              bool found = false;
++                              // Search if we already have created a list for the 
++                              // faces that come from the same original face
++                              const BOP_IT_LFaces lfEnd = facesByOriginalFace.end();
++                              for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin();
++                              facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) {
++                                      if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) {
++                                              // Search that the face has not been added to the list before
++                                              for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) {
++                                                      if ((*facesByOriginalFaceX)[i] == face) {
++                                                              found = true;
++                                                              break;
++                                                      }
++                                              }
++                                              if (!found) {
++                                                      // Add the face to the list
++                                                if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face);
++                                                else facesByOriginalFaceX->push_back(face);
++                                                found = true;
++                                              }
++                                              break;
++                                      }
++                              }
++                              if (!found) {
++                                      // Create a new list and add the current face
++                                      BOP_Faces facesByOriginalFaceX;
++                                      facesByOriginalFaceX.push_back(face);
++                                      facesByOriginalFace.push_back(facesByOriginalFaceX);
++                              }
++                      }
++              }
++      }
++}
++
++/**
++ * Creates a list of lists L1, L2, ... LN where
++ *   LX = mesh faces with vertex v that come from the same original face
++ *        and without any of the vertices that appear before v in vertices
++ * @param facesByOriginalFace list of faces lists
++ * @param vertices vector with vertices indexs that contains v
++ * @param v vertex index
++ */
++void BOP_Merge2::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v)
++{
++      // Get edges with vertex v
++      BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges();
++      const BOP_IT_Indexs edgeEnd = edgeIndexs.end();
++      for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) {    
++              // Foreach edge, add its no broken faces to the output list
++              BOP_Edge* edge = m_mesh->getEdge(*edgeIndex);
++              BOP_Indexs faceIndexs = edge->getFaces();
++              const BOP_IT_Indexs faceEnd = faceIndexs.end();
++              for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) {
++                      BOP_Face* face = m_mesh->getFace(*faceIndex);
++                      if (face->getTAG() != BROKEN) {
++                              // Search if the face contains any of the forbidden vertices
++                              bool found = false;
++                              for(BOP_IT_Indexs vertex = vertices.begin();*vertex!= v;vertex++) {
++                                      if (face->containsVertex(*vertex)) {
++                                              // face contains a forbidden vertex!
++                                              found = true;
++                                              break;
++                              }
++                      }
++                      if (!found) {
++                              // Search if we already have created a list with the 
++                              // faces that come from the same original face
++                        const BOP_IT_LFaces lfEnd = facesByOriginalFace.end();
++                              for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin();
++                                      facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) {
++                                      if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) {
++                                              // Search that the face has not been added to the list before
++                                              for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) {
++                                                      if ((*facesByOriginalFaceX)[i] == face) {
++                                                              found = true;
++                                                              break;
++                                                      }
++                                              }
++                                              if (!found) {
++                                                // Add face to the list
++                                                if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face);
++                                                else facesByOriginalFaceX->push_back(face);
++                                                found = true;
++                                              }
++                                              break;
++                                      }
++                              }
++                              if (!found) {
++                                      // Create a new list and add the current face
++                                      BOP_Faces facesByOriginalFaceX;
++                                      facesByOriginalFaceX.push_back(face);
++                                      facesByOriginalFace.push_back(facesByOriginalFaceX);
++                              }
++                      }
++              }
++      }
++      }
++}
++
++#endif  /* BOP_NEW_MERGE */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1e5945a889f99a8472eda7a2bf23c463d9c6482b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,99 @@@
++/**
++ * ***** BEGIN GPL LICENSE BLOCK *****
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
++ * All rights reserved.
++ *
++ * The Original Code is: all of this file.
++ *
++ * Contributor(s): none yet.
++ *
++ * ***** END GPL LICENSE BLOCK *****
++ */
++ 
++#ifndef BOP_MERGE2_H
++#define BOP_MERGE2_H
++
++#include "BOP_Misc.h"
++
++#ifdef BOP_NEW_MERGE
++
++#include "BOP_Mesh.h"
++#include "BOP_Tag.h"
++#include "BOP_MathUtils.h"
++#include "MEM_SmartPtr.h"
++
++typedef vector< BOP_Faces > BOP_LFaces;
++typedef vector< BOP_Faces >::iterator BOP_IT_LFaces;
++
++class BOP_Merge2 {
++      private:
++              BOP_Mesh* m_mesh;
++              BOP_Index m_firstVertex;
++              static BOP_Merge2 SINGLETON;
++
++              BOP_Merge2() {};
++              bool mergeFaces();
++              bool mergeFaces(BOP_Indexs &mergeVertices);
++              bool mergeFaces(BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v);
++              bool mergeFaces(BOP_Faces &faces, BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v);
++              BOP_Face *mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v);
++              BOP_Face *mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Indexs &pending, BOP_Index v);
++              BOP_Face *mergeFaces(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v);
++              BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Index v);
++              BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Indexs &pending, BOP_Index v);
++              BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face4 *faceJ, BOP_Indexs &pending, BOP_Index v);
++              bool createQuads();
++              bool containsIndex(BOP_Indexs indexs, BOP_Index index);
++              void getFaces(BOP_LFaces &facesByOriginalFace, BOP_Index v);
++              void getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v);
++              BOP_Face *createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ);
++              BOP_Face *createQuad(BOP_Face3 *faceI, BOP_Face4 *faceJ);
++              BOP_Face *createQuad(BOP_Face4 *faceI, BOP_Face4 *faceJ);
++
++              bool mergeVertex(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v,
++                              BOP_Indexs &mergeVertices);
++              bool mergeVertex(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v,
++                              BOP_Indexs &pending, BOP_Faces &oldFaces, BOP_Faces &newFaces );
++              BOP_Face *find3Neighbor(BOP_Face *faceI, BOP_Face *faceJ,
++                              BOP_Index X, BOP_Index I, BOP_Index P, BOP_Index N );
++              BOP_Face *find4Neighbor(BOP_Face *faceI, BOP_Face *faceJ,
++                              BOP_Index X, BOP_Index I, BOP_Index P, BOP_Index N,
++                      BOP_Face **faceL, BOP_Index &O);
++              BOP_Face3 *collapse(BOP_Face4 *faceC, BOP_Index X);
++              void mergeFaces(BOP_Face *A, BOP_Face *B, BOP_Index X,
++                      BOP_Index I, BOP_Index N, BOP_Index P, BOP_Faces &newFaces );
++              void freeVerts(BOP_Index v, BOP_Vertex *vert);
++
++              void mergeVertex(BOP_Faces&, BOP_Index, BOP_Index);
++              void mergeVertex(BOP_Face3 *, BOP_Index, BOP_Index);
++              void mergeVertex(BOP_Face4 *, BOP_Index, BOP_Index);
++              void cleanup( void );
++
++      public:
++
++              static BOP_Merge2 &getInstance() {
++                      return SINGLETON;
++              }
++
++              void mergeFaces(BOP_Mesh *m, BOP_Index v);
++};
++
++void dumpmesh(BOP_Mesh *, bool);
++
++#endif        /* BOP_NEW_MERGE2 */
++#endif
index 5659cd62a3ff00f4e5d955e8b7fc388bd8db3eea,5659cd62a3ff00f4e5d955e8b7fc388bd8db3eea..075884a19202c4de0b6a81e19ad35b7538419e43
@@@ -449,6 -449,6 +449,13 @@@ bool BOP_Mesh::getIndexEdge(BOP_Index v
                        printf ("found edge (%d %d)\n",v1,v2);
  #endif
                        e = edge->index;
++#ifdef BOP_NEW_MERGE
++                      if( m_edges[e]->getUsed() == false ) {
++                              m_edges[e]->setUsed(true);
++                              m_vertexs[v1]->addEdge(e);
++                              m_vertexs[v2]->addEdge(e);
++                      }
++#endif
                        return true;
                }
  #ifdef HASH_PRINTF_DEBUG
@@@ -794,7 -794,7 +801,8 @@@ bool BOP_Mesh::isClosedMesh(
  }
  
  
--/** ***************************************************************************
++#ifdef BOP_DEBUG
++/******************************************************************************
   * DEBUG METHODS                                                              * 
   * This functions are used to test the mesh state and debug program errors.   *
   ******************************************************************************/
@@@ -1075,3 -1075,3 +1083,4 @@@ void BOP_Mesh::updatePlanes(
        }
  }
  
++#endif
index 9abff52545fe8457dd009cfc41e901f3cda7463c,9abff52545fe8457dd009cfc41e901f3cda7463c..46c8fa53d2086fbb26d7c77c6d187f6e3ec34f30
@@@ -1,10 -1,10 +1,3 @@@
--/*
-- * TEMPORARY defines to enable hashing support
-- */
--
--#define HASH(x) ((x) >> 5)            /* each "hash" covers 32 indices */
--// #define HASH_PRINTF_DEBUG  /* uncomment to enable debug output */
--
  /**
   *
   * $Id$
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d021579d1619cf718234df74bef893194c82a932
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,54 @@@
++/**
++ *
++ * $Id: BOP_Misc.h 14444 2008-04-16 22:40:48Z khughes $
++ *
++ * ***** BEGIN GPL LICENSE BLOCK *****
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
++ * All rights reserved.
++ *
++ * The Original Code is: all of this file.
++ *
++ * Contributor(s): Ken Hughes
++ *
++ * ***** END GPL LICENSE BLOCK *****
++ */
++ 
++/*
++ * This file contains various definitions used across the modules
++ */
++
++/*
++ * define operator>> for faces, edges and vertices, and also add some
++ * debugging functions for displaying various internal data structures
++ */
++
++// #define    BOP_DEBUG
++
++#define HASH(x) ((x) >> 5)            /* each "hash" covers 32 indices */
++// #define HASH_PRINTF_DEBUG  /* uncomment to enable debug output */
++
++/*
++ * temporary: control which method is used to merge final triangles and
++ * quads back together after an operation.  If both methods are included,
++ * the "rt" debugging button on the Scene panel (F10) is used to control
++ * which is active.  Setting it to 100 enables the original method, any
++ * other value enables the new method.
++ */
++
++#define BOP_ORIG_MERGE                        /* include original merge code */
++#define BOP_NEW_MERGE                 /* include new merge code */
index 705f4885866b2147000425dde613c3a824dc19bd,705f4885866b2147000425dde613c3a824dc19bd..ead10fa60402b32a5b7a5e0fe908b53e165d3520
@@@ -39,7 -39,7 +39,7 @@@
  #define OUTON_TAG        0x11  // Above and on the plane  
  #define UNCLASSIFIED_TAG 0x0F  // Expecting to be classified
  
--#define PHANTOM_TAG      0x0C  // Phantom face
++#define PHANTOM_TAG      0x0C  // Phantom face: verts form collinear triangle
  #define OVERLAPPED_TAG   0x0D  // Overlapped face
  #define BROKEN_TAG       0x0B  // Splitted and unused ... 
  
index a429c26d204bc94b775fd0ef5fd132b694c8dc53,a429c26d204bc94b775fd0ef5fd132b694c8dc53..edb53ea6a59c06da697530ee8690827c0fc48604
@@@ -89,3 -89,3 +89,22 @@@ bool BOP_Vertex::containsEdge(BOP_Inde
        
        return false;
  }
++
++#ifdef BOP_DEBUG
++/**
++ * Implements operator <<.
++ */
++#include <iomanip>
++
++ostream &operator<<(ostream &stream, BOP_Vertex *v)
++{
++      char aux[20];
++      BOP_stringTAG(v->m_tag,aux);
++      MT_Point3 point = v->getPoint();
++      stream << setprecision(6) << showpoint << fixed;
++      stream << "Vertex[" << point[0] << "," << point[1] << ",";
++      stream << point[2] << "] ("  <<  aux  <<  ")";
++      return stream;
++}
++#endif
++
index 3a9895df6d3abb28cfcb0b231a3ac823c74f32a2,3a9895df6d3abb28cfcb0b231a3ac823c74f32a2..18b2f168f8c0f710401dff67b4411882dd4720e9
@@@ -31,6 -31,6 +31,7 @@@
  #include "BOP_Tag.h"
  #include "BOP_Indexs.h"
  #include "MT_Point3.h"
++#include "BOP_Misc.h"
  
  class BOP_Vertex 
  {
@@@ -52,6 -52,6 +53,10 @@@ public
        inline MT_Point3 getPoint() const { return m_point;};
        inline BOP_TAG getTAG() { return m_tag;};
        inline void setTAG(BOP_TAG t) { m_tag = t;};
++#ifdef BOP_DEBUG
++      friend ostream &operator<<(ostream &stream, BOP_Vertex *v);
++#endif
++
  };
  
  #endif
index b020d88b2b36570c1a249197e5fa84efd0ab7882,b020d88b2b36570c1a249197e5fa84efd0ab7882..edf0faf4ab7d5117459bd16096ce46236fc0ab1f
                        <File
                                RelativePath="..\..\..\source\gameengine\BlenderRoutines\KX_BlenderMouseDevice.cpp">
                        </File>
--                      <File
--                              RelativePath="..\..\..\source\gameengine\BlenderRoutines\KX_BlenderPolyMaterial.cpp">
--                      </File>
                        <File
                                RelativePath="..\..\..\source\gameengine\BlenderRoutines\KX_BlenderRenderTools.cpp">
                        </File>
                        <File
                                RelativePath="..\..\..\source\gameengine\BlenderRoutines\KX_BlenderMouseDevice.h">
                        </File>
--                      <File
--                              RelativePath="..\..\..\source\gameengine\BlenderRoutines\KX_BlenderPolyMaterial.h">
--                      </File>
                        <File
                                RelativePath="..\..\..\source\gameengine\BlenderRoutines\KX_BlenderRenderTools.h">
                        </File>
index c723efb61a7df2e0be3395e3ab850e061a5163d5,c723efb61a7df2e0be3395e3ab850e061a5163d5..a48d065813a51e62b5cfeef0eecc347ed345ba19
@@@ -14,7 -14,7 +14,7 @@@ __url__ = ("blender", "blenderartists.o
  __version__ = "2007/04/27"
  
  __bpydoc__ = """\
--"DEFORM to RVK2" copies deform data (except EDGESPLIT,DECIMATE,SUBSURF,BOOLEAN, 
++"DEFORM to RVK2" copies deform data (except EDGESPLIT,DECIMATE,SUBSURF,BOOLEAN,
  BUILD,MIRROR,ARRAY) of the active object to the RVK (relative vertex key) of
  the other selected object.
  
@@@ -25,7 -25,7 +25,7 @@@ key
  The new version of this scrit (Blender 2.43) manages the modifier changes.
  There are a lot of modifiers but only the ones which just deforms the shape
  can be used : LATTICE, CURVE, WAVE, ARMATURE. You can unset these modifiers
--from the script. 
++from the script.
  
  Usage:
  
@@@ -35,7 -35,7 +35,7 @@@ the 3d View.  If the active object has 
  level, the script will ask if it should change that.  Before copying data to
  the rvk it will also ask whether it should replace or add a new vertex group.
  
-- 
++
  """
  
  #----------------------------------------------
@@@ -70,7 -70,7 +70,7 @@@ GNU General Public License for more det
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
--Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
++Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  """
  # Copy the rvk (1, or armature, lattice, or
  # any mesh deformation except surface
@@@ -83,7 -83,7 +83,7 @@@
  # download the script :
  # http://jmsoler.free.fr/util/blenderfile/py/rvk1_torvk2.py
  # Communicate upon problems or errors:
--# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender 
++# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
  #----------------------------------------------
  # Page officielle :
  #   http://jmsoler.free.fr/util/blenderfile/py/rvk1_torvk2.py
@@@ -101,22 -101,22 +101,22 @@@ def Value(t)
        exec "t=Modifier.Types.%s"%t
        return t
  
--def deform2rvk():  
++def deform2rvk():
        POSSMOD_list=['EDGESPLIT',
                                                                'DECIMATE',
--                                                              'SUBSURF', 
--                                                              'BOOLEAN', 
++                                                              'SUBSURF',
++                                                              'BOOLEAN',
                                                                'BUILD',
--                                                              'MIRROR', 
++                                                              'MIRROR',
                                                                'ARRAY']
  
        AUTHMOD_list=['LATTICE',
--                    'CURVE', 
++                    'CURVE',
                      'WAVE',
                      'ARMATURE']
  
        MODIFIERS=0
--      
++
        BMOD=[['Possible Modifiers'],
                                ['Allowed Modifiers']]
  
                # =============================================================
                # must be 2 meshes ============================================
                # =============================================================
--              if RVK1.getType()=='Mesh' and RVK2.getType()=='Mesh': 
--                      FRAME=Blender.Get('curframe') 
++              if RVK1.getType()=='Mesh' and RVK2.getType()=='Mesh':
++                      FRAME=Blender.Get('curframe')
                        DATA2=RVK2.getData()
                        if DEBUG: print DATA2.getKey()
                        # ============================================================
                                        # ===  Bloc Menu Modifiers ===1 doc =================
                                        # ===================================================
                                        m=0
--                                      for mod in  MODRVK1: 
++                                      for mod in  MODRVK1:
                                                if DEBUG: print mod.type
                                                if mod.type in POSSMOD:
                                                        BMOD[0].append([Draw.Create(0),mod.type,
                                        retval = Blender.Draw.PupBlock("MESH 2 RVK", block)
                                        # ===================================================
                                        # ===  unset Modifiers  =============================
--                                      # ===================================================   
++                                      # ===================================================
                                        for     B in BMOD[0][1:]:
                                                if DEBUG: print B[2]
                                                MODRVK1[B[2]][Modifier.Settings.RENDER]=0
                                        # ===================================================
                                        # ===  update Modifiers =============================
                                        # ===================================================
--                                      RVK1.makeDisplayList()                                                                  
++                                      #RVK1.makeDisplayList()
                                # =======================================================
                                # ===  get deformed mesh ================================
                                # =======================================================
                                RVK1NAME=Object.GetSelected()[0].getName()
--                              meshrvk1=NMesh.GetRawFromObject(RVK1NAME)  
++                              meshrvk1=NMesh.GetRawFromObject(RVK1NAME)
                                if DEBUG: print len(meshrvk1.verts)
                                # =======================================================
                                # ===  get normal mesh for vertex group =================
                                # =======================================================
                                DATA2=RVK2.getData()
                                if DEBUG: print len(meshrvk1.verts)
--                              if DEBUG: print len(DATA2.verts)                                                        
++                              if DEBUG: print len(DATA2.verts)
                                # ========================================================
                                # ===== is there the same number of vertices =============
                                # ========================================================
--                              if len(meshrvk1.verts)==len(DATA2.verts): 
--                                      name = "Do you want to replace or add vertex groups ? %t| YES %x1| NO ? %x2 " 
++                              if len(meshrvk1.verts)==len(DATA2.verts):
++                                      name = "Do you want to replace or add vertex groups ? %t| YES %x1| NO ? %x2 "
                                        result = Draw.PupMenu(name)
--                                      if result==1:       
++                                      if result==1:
                                                # =====================================================
                                                # ===== Do we save vertex groups ?  ===================
                                                # =====================================================
--                                              GROUPNAME2=DATA2.getVertGroupNames() 
++                                              GROUPNAME2=DATA2.getVertGroupNames()
                                                if len(GROUPNAME2)!=0:
                                                        for GROUP2 in GROUPNAME2:
                                                                DATA2.removeVertGroup(GROUP2)
                                        # ===== now copy the vertices coords =====================
                                        # ========================================================
                                        for v in meshrvk1.verts:
--                                              i= meshrvk1.verts.index(v) 
++                                              i= meshrvk1.verts.index(v)
                                                v1=DATA2.verts[i]
                                                for n in [0,1,2]:
                                                        v1.co[n]=v.co[n]
--                                      DATA2.update() 
++                                      DATA2.update()
                                        DATA2.insertKey(FRAME,'relative')
                                        DATA2.update()
                                        RVK2.makeDisplayList()
                                                        if not B[1]:
                                                                MODRVK1[B[2]][Modifier.Settings.RENDER]|=B[-2]
                                else:
--                                      name = "Meshes Objects must the same number of vertices %t| Ok. %x1" 
++                                      name = "Meshes Objects must the same number of vertices %t| Ok. %x1"
                                        result = Draw.PupMenu(name)
                                        return
                        else:
--                              name = "Second Object must have  at least a shape key %t| Ok. %x1" 
++                              name = "Second Object must have  at least a shape key %t| Ok. %x1"
                                result = Draw.PupMenu(name)
                                return
--              else:   
--                      name = "Object must be Meshes %t| Ok. %x1" 
++              else:
++                      name = "Object must be Meshes %t| Ok. %x1"
                        result = Draw.PupMenu(name)
--                      return 
++                      return
        else :
--              name = "At least 2 Meshes as to be selected %t| Ok. %x1" 
++              name = "At least 2 Meshes as to be selected %t| Ok. %x1"
                result = Draw.PupMenu(name)
                return
--      Blender.Redraw()  
++      Blender.Redraw()
  EDITMODE=Blender.Window.EditMode()
  Blender.Window.EditMode(0)
  deform2rvk()
--Blender.Window.EditMode(EDITMODE)
++Blender.Window.EditMode(EDITMODE)
index f61b300f708e09dd3870a86f56a257d40a6742ed,f61b300f708e09dd3870a86f56a257d40a6742ed..7dc10c53e22909e1a3548259879112b2de818a03
@@@ -437,5 -437,5 +437,7 @@@ void weight_to_rgb(float input, float *
  /* determines required DerivedMesh data according to view and edit modes */
  CustomDataMask get_viewedit_datamask();
  
++void DM_add_tangent_layer(DerivedMesh *dm);
++
  #endif
  
index f76cdbc64b7081778938a51de291a3a0fe2e66c9,f76cdbc64b7081778938a51de291a3a0fe2e66c9..d951c8401e3b27a60bbaa5f9109ff0d979f4cb8c
@@@ -41,7 -41,7 +41,7 @@@ struct ListBase
  struct MemFile;
  
  #define BLENDER_VERSION                       246
--#define BLENDER_SUBVERSION            0
++#define BLENDER_SUBVERSION            1
  
  #define BLENDER_MINVERSION            245
  #define BLENDER_MINSUBVERSION 15
index 78a8f60caeb70cb8b40b33e41dddffeb877dc280,78a8f60caeb70cb8b40b33e41dddffeb877dc280..fade0f8cbaa4a1b1555b7c85894c2658e076a859
@@@ -62,6 -62,6 +62,7 @@@ struct Tex *copy_texture(struct Tex *te
  void make_local_texture(struct Tex *tex);
  void autotexname(struct Tex *tex);
  struct Tex *give_current_texture(struct Object *ob, int act);
++struct Tex *give_current_world_texture(void);
  
  struct TexMapping *add_mapping(void);
  void init_mapping(struct TexMapping *texmap);
index 0feb055eec93cb5298b36178651a96e8511f09d8,c913820205b4ac8cadb66fb6174f2b40414fe355..3ad11a61de33125e6a08cc76b2ae8805c6cfb462
@@@ -354,9 -355,7 +354,8 @@@ TimeMarker *get_frame_marker(int frame)
  
  /* editseq.c */
  Sequence *get_forground_frame_seq(int frame){return 0;};
--void set_last_seq(Sequence *seq){};
 +void clear_last_seq(Sequence *seq){};
 +    
  
  /* modifier.c stub */
  void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd,
index 4d3f9143b851699cb13e45f61795e768542895d7,4d3f9143b851699cb13e45f61795e768542895d7..67cf89d5ee26de6b964e499eedfd6975b05a9e83
@@@ -59,6 -59,6 +59,7 @@@
  #include "BLI_edgehash.h"
  #include "BLI_editVert.h"
  #include "BLI_linklist.h"
++#include "BLI_memarena.h"
  
  #include "BKE_cdderivedmesh.h"
  #include "BKE_customdata.h"
@@@ -2844,6 -2844,6 +2845,127 @@@ int editmesh_get_first_deform_matrices(
        return numleft;
  }
  
++void DM_add_tangent_layer(DerivedMesh *dm)
++{
++      /* mesh vars */
++      MTFace *mtface, *tf;
++      MFace *mface, *mf;
++      MVert *mvert, *v1, *v2, *v3, *v4;
++      MemArena *arena= NULL;
++      VertexTangent **vtangents= NULL;
++      float (*orco)[3]= NULL, (*tangent)[3];
++      float *uv1, *uv2, *uv3, *uv4, *vtang;
++      float fno[3], tang[3], uv[4][2];
++      int i, j, len, mf_vi[4], totvert, totface;
++
++      if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) != -1)
++              return;
++
++      /* check we have all the needed layers */
++      totvert= dm->getNumVerts(dm);
++      totface= dm->getNumFaces(dm);
++
++      mvert= dm->getVertArray(dm);
++      mface= dm->getFaceArray(dm);
++      mtface= dm->getFaceDataArray(dm, CD_MTFACE);
++
++      if(!mtface) {
++              orco= dm->getVertDataArray(dm, CD_ORCO);
++              if(!orco)
++                      return;
++      }
++      
++      /* create tangent layer */
++      DM_add_face_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
++      tangent= DM_get_face_data_layer(dm, CD_TANGENT);
++      
++      /* allocate some space */
++      arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
++      BLI_memarena_use_calloc(arena);
++      vtangents= MEM_callocN(sizeof(VertexTangent*)*totvert, "VertexTangent");
++      
++      /* sum tangents at connected vertices */
++      for(i=0, tf=mtface, mf=mface; i < totface; mf++, tf++, i++) {
++              v1= &mvert[mf->v1];
++              v2= &mvert[mf->v2];
++              v3= &mvert[mf->v3];
++
++              if (mf->v4) {
++                      v4= &mvert[mf->v4];
++                      CalcNormFloat4(v4->co, v3->co, v2->co, v1->co, fno);
++              }
++              else {
++                      v4= NULL;
++                      CalcNormFloat(v3->co, v2->co, v1->co, fno);
++              }
++              
++              if(mtface) {
++                      uv1= tf->uv[0];
++                      uv2= tf->uv[1];
++                      uv3= tf->uv[2];
++                      uv4= tf->uv[3];
++              }
++              else {
++                      uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
++                      spheremap(orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2], &uv[0][0], &uv[0][1]);
++                      spheremap(orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2], &uv[1][0], &uv[1][1]);
++                      spheremap(orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2], &uv[2][0], &uv[2][1]);
++                      if(v4)
++                              spheremap(orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2], &uv[3][0], &uv[3][1]);
++              }
++              
++              tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, fno, tang);
++              sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
++              sum_or_add_vertex_tangent(arena, &vtangents[mf->v2], tang, uv2);
++              sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
++              
++              if(mf->v4) {
++                      v4= &mvert[mf->v4];
++                      
++                      tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, fno, tang);
++                      sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
++                      sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
++                      sum_or_add_vertex_tangent(arena, &vtangents[mf->v4], tang, uv4);
++              }
++      }
++      
++      /* write tangent to layer */
++      for(i=0, tf=mtface, mf=mface; i < totface; mf++, tf++, i++, tangent+=4) {
++              len= (mf->v4)? 4 : 3; 
++              
++              if(mtface) {
++                      uv1= tf->uv[0];
++                      uv2= tf->uv[1];
++                      uv3= tf->uv[2];
++                      uv4= tf->uv[3];
++              }
++              else {
++                      uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
++                      spheremap(orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2], &uv[0][0], &uv[0][1]);
++                      spheremap(orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2], &uv[1][0], &uv[1][1]);
++                      spheremap(orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2], &uv[2][0], &uv[2][1]);
++                      if(len==4)
++                              spheremap(orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2], &uv[3][0], &uv[3][1]);
++              }
++              
++              mf_vi[0]= mf->v1;
++              mf_vi[1]= mf->v2;
++              mf_vi[2]= mf->v3;
++              mf_vi[3]= mf->v4;
++              
++              for(j=0; j<len; j++) {
++                      vtang= find_vertex_tangent(vtangents[mf_vi[j]], mtface ? tf->uv[j] : uv[j]);
++
++                      VECCOPY(tangent[j], vtang);
++                      Normalize(tangent[j]);
++              }
++      }
++      
++      BLI_memarena_free(arena);
++      MEM_freeN(vtangents);
++}
++
++
  /* ************************* fluidsim bobj file handling **************************** */
  
  #ifndef DISABLE_ELBEEM
index 6dfb77504fb3d7cf6babdf2104fc0dd07fc620f0,6dfb77504fb3d7cf6babdf2104fc0dd07fc620f0..5b3cec2577258b6282bc514c3fe893be87f47a34
@@@ -1547,7 -1547,7 +1547,7 @@@ int cloth_bvh_objcollision ( Object *ob
  {
        Cloth *cloth=NULL;
        BVHTree *cloth_bvh=NULL;
--      long i=0, numfaces = 0, numverts = 0;
++      int i=0, numfaces = 0, numverts = 0;
        int rounds = 0; // result counts applied collisions; ic is for debug output;
        ClothVertex *verts = NULL;
        int ret = 0, ret2 = 0;
index 068501780bced5d66ca6816daa008425ac1c3e93,068501780bced5d66ca6816daa008425ac1c3e93..f13fd5f99635a2baebf7066299b36e207abe4ad3
@@@ -558,8 -558,8 +558,8 @@@ static void contarget_get_mesh_mat (Obj
        if (dgroup < 0) return;
        
        /* get DerivedMesh */
--      if (G.obedit && G.editMesh) {
--              /* we are in editmode, so get a special derived mesh */
++      if ((G.obedit == ob) && (G.editMesh)) {
++              /* target is in editmode, so get a special derived mesh */
                dm = CDDM_from_editmesh(G.editMesh, ob->data);
        }
        else {
index 501293ecd814970d8ddc9a4e2a64cd4edc08a439,501293ecd814970d8ddc9a4e2a64cd4edc08a439..9012adb09b7a4c428cd8c375bfd7533304b615f0
@@@ -532,13 -532,13 +532,14 @@@ const LayerTypeInfo LAYERTYPEINFO[CD_NU
        {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
        {sizeof(MTexPoly), "MTexPoly", 1, "Face Texture", NULL, NULL, NULL, NULL, NULL},
        {sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL},
--      {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol} 
++      {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol},
++      {sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}
  };
  
  const char *LAYERTYPENAMES[CD_NUMTYPES] = {
        "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace",
        "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty",
--      "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV", "CDMloopCol"};
++      "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent"};
  
  const CustomDataMask CD_MASK_BAREMESH =
        CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
@@@ -552,7 -552,7 +553,7 @@@ const CustomDataMask CD_MASK_EDITMESH 
  const CustomDataMask CD_MASK_DERIVEDMESH =
        CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
        CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
--      CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO;
++      CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT;
  const CustomDataMask CD_MASK_BMESH = 
        CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
  const CustomDataMask CD_MASK_FACECORNERS =
index 37804bf68ac84ad20b934dee4dd8a6d680bb6d9b,37804bf68ac84ad20b934dee4dd8a6d680bb6d9b..ad139220785679c33887bf8f297e34c7a4c9f8be
@@@ -53,6 -53,6 +53,7 @@@
  #include "DNA_world_types.h"
  #include "DNA_brush_types.h"
  #include "DNA_node_types.h"
++#include "DNA_scene_types.h"
  
  #include "IMB_imbuf_types.h"
  #include "IMB_imbuf.h"
@@@ -731,7 -731,7 +732,7 @@@ Tex *give_current_texture(Object *ob, i
        bNode *node;
        
        if(ob==0) return 0;
--      if(ob->totcol==0) return 0;
++      if(ob->totcol==0 && !(ob->type==OB_LAMP)) return 0;
        
        if(ob->type==OB_LAMP) {
                la=(Lamp *)ob->data;
        return tex;
  }
  
++Tex *give_current_world_texture(void)
++{
++      MTex *mtex = 0;
++      Tex *tex = 0;
++      
++      if(!(G.scene->world)) return 0;
++      
++      mtex= G.scene->world->mtex[(int)(G.scene->world->texact)];
++      if(mtex) tex= mtex->tex;
++      
++      return tex;
++}
  
  /* ------------------------------------------------------------------------- */
  
index 8b979f9ed2330f6e6a012d0e9bf922077925c313,8b979f9ed2330f6e6a012d0e9bf922077925c313..74f152ac635ffb206158edf5d551be5e6a0a883c
@@@ -405,7 -405,7 +405,7 @@@ static VFontData *objfnt_to_ftvfontdata
                lcode = charcode;
        }
        
--      err = FT_Set_Charmap( face, (FT_CharMap) FT_ENCODING_UNICODE );
++      err = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
  
        return vfd;     
  }
index ad004dd5c8216509e59c967dec8cadf947351978,090b1d7c6b6a13f283b798d2af5604c83ab37871..ad19cde3c9ba963ad5700bd4cdb848b396056286
@@@ -4870,6 -4855,6 +4870,49 @@@ void idproperties_fix_group_lengths(Lis
        }
  }
  
++void alphasort_version_246(FileData *fd, Library *lib, Mesh *me)
++{
++      Material *ma;
++      MFace *mf;
++      MTFace *tf;
++      int a, b, texalpha;
++
++      /* verify we have a tface layer */
++      for(b=0; b<me->fdata.totlayer; b++)
++              if(me->fdata.layers[b].type == CD_MTFACE)
++                      break;
++      
++      if(b == me->fdata.totlayer)
++              return;
++
++      /* if we do, set alpha sort if the game engine did it before */
++      for(a=0, mf=me->mface; a<me->totface; a++, mf++) {
++              if(mf->mat_nr < me->totcol) {
++                      ma= newlibadr(fd, lib, me->mat[mf->mat_nr]);
++                      texalpha = 0;
++
++                      for(b=0; ma && b<MAX_MTEX; b++)
++                              if(ma->mtex && ma->mtex[b] && ma->mtex[b]->mapto & MAP_ALPHA)
++                                      texalpha = 1;
++              }
++              else {
++                      ma= NULL;
++                      texalpha = 0;
++              }
++
++              for(b=0; b<me->fdata.totlayer; b++) {
++                      if(me->fdata.layers[b].type == CD_MTFACE) {
++                              tf = ((MTFace*)me->fdata.layers[b].data) + a;
++
++                              tf->mode &= ~TF_ALPHASORT;
++                              if(ma && (ma->mode & MA_ZTRA))
++                                      if(ELEM(tf->transp, TF_ALPHA, TF_ADD) || (texalpha && (tf->transp != TF_CLIP)))
++                                              tf->mode |= TF_ALPHASORT;
++                      }
++              }
++      }
++}
++
  static void do_versions(FileData *fd, Library *lib, Main *main)
  {
        /* WATCH IT!!!: pointers from libdata have not been converted */
        }
  
        /* sun/sky */
--      if ((main->versionfile < 246) ){
++      if(main->versionfile < 246) {
                Lamp *la;
++
                for(la=main->lamp.first; la; la= la->id.next) {
                        la->sun_effect_type = 0;
                        la->horizon_brightness = 1.0;
                }
        }
  
++      if(main->versionfile <= 246 && main->subversionfile < 1){
++              Mesh *me;
++
++              for(me=main->mesh.first; me; me= me->id.next)
++                      alphasort_version_246(fd, lib, me);
++      }
++
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
        /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
  
index 73abf362d12d9d0875c8660ac76f01f488fab08b,b59dd851dfe462b4bcb8e3394a0ca905ff3a2257..3a70438dd136d7197b611a7eebaea2510c473ded
@@@ -2275,7 -2274,7 +2275,7 @@@ static int handle_append_runtime(int ha
        unsigned char buf[1024];
        int count, progfd= -1;
  
--      if (!runtime) {
++      if (!BLI_exists(runtime)) {
                cause= "Unable to find runtime";
                goto cleanup;
        }
index d2fc7be29ea14b219494af2431c82ec8b53b2d0f,d0ebd096ecba44b7c37e729f0f15d6356e13f2cf..eb749cf28ec656d8953fa2c72738529b6df79ac0
@@@ -38,6 -38,6 +38,15 @@@ struct bGPdata
  struct bGPDlayer;
  struct bGPDframe;
  
++/* ------------- Grease-Pencil Helpers -------------- */
++
++/* Temporary 'Stroke Point' data */
++typedef struct tGPspoint {
++      short x, y;                             /* x and y coordinates of cursor (in relative to area) */
++      float xf, yf;                   /* same as x and y, but as floats */
++      float pressure;                 /* pressure of tablet at this point */
++} tGPspoint;
++
  /* ------------ Grease-Pencil API ------------------ */
  
  void free_gpencil_strokes(struct bGPDframe *gpf);
index 24112c7f11afd2664d69804428f2748f19aaa5e5,24112c7f11afd2664d69804428f2748f19aaa5e5..da98eb3d4f1a8beb122345ccf11669cdaf6aad36
@@@ -134,6 -134,6 +134,7 @@@ void       transform_armature_mirror_update(v
  void  hide_selected_armature_bones(void);
  void  hide_unselected_armature_bones(void);
  void  show_all_armature_bones(void);
++void  set_locks_armature_bones(short lock);
  
  #define       BONESEL_ROOT    0x10000000
  #define       BONESEL_TIP             0x20000000
index 4ed3d0df367fc9eb8b2b9b05506a9e4a7f13a0a6,4ed3d0df367fc9eb8b2b9b05506a9e4a7f13a0a6..d2c6c56d01a2da3258b2c4fbfc82e9a33d317ebd
@@@ -34,9 -34,9 +34,12 @@@ struct Base
  struct Object;
  struct Camera;
  struct View3D;
++struct rcti;
  
  void  arrows_move_cursor(unsigned short event);
++void  lasso_select_boundbox(struct rcti *rect, short mcords[][2], short moves);
  int           lasso_inside(short mcords[][2], short moves, short sx, short sy);
++int   lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1);
  void  borderselect(void);
  void  circle_select(void);
  void  deselectall(void);
index 673855a6932009f7c3da12ede50fdc5acdd42260,673855a6932009f7c3da12ede50fdc5acdd42260..0648c53535374c2190a9967463c25132924e260e
@@@ -154,7 -154,7 +154,8 @@@ typedef enum eBone_Flag 
        BONE_NO_SCALE                           = (1<<15),      /* No parent scale */
        BONE_HIDDEN_PG                          = (1<<16),      /* hidden bone when drawing PoseChannels (for ghost drawing) */
        BONE_DRAWWIRE                           = (1<<17),      /* bone should be drawn as OB_WIRE, regardless of draw-types of view+armature */
--      BONE_NO_CYCLICOFFSET            = (1<<18)       /* when no parent, bone will not get cyclic offset */
++      BONE_NO_CYCLICOFFSET            = (1<<18),      /* when no parent, bone will not get cyclic offset */
++      BONE_EDITMODE_LOCKED            = (1<<19),      /* bone transforms are locked in EditMode */
  } eBone_Flag;
  
  #endif
index 0fe0dace016d6dc45af43fce8f0c9106270d86f8,0fe0dace016d6dc45af43fce8f0c9106270d86f8..fa5b5a759414b34161335644522721dcd4fc9a8d
@@@ -375,11 -375,11 +375,13 @@@ typedef enum B_CONSTRAINT_SPACETYPES 
                /* for objects (relative to parent/without parent influence), 
                 * for bones (along normals of bone, without parent/restpositions) 
                 */
--      CONSTRAINT_SPACE_LOCAL,
++      CONSTRAINT_SPACE_LOCAL, /* = 1 */
                /* for posechannels - pose space  */
--      CONSTRAINT_SPACE_POSE,
--              /* for posechannels - local with parent  */
--      CONSTRAINT_SPACE_PARLOCAL,
++      CONSTRAINT_SPACE_POSE, /* = 2 */
++              /* for posechannels - local with parent  */
++      CONSTRAINT_SPACE_PARLOCAL, /* = 3 */
++              /* for files from between 2.43-2.46 (should have been parlocal) */
++      CONSTRAINT_SPACE_INVALID, /* = 4. do not exchange for anything! */
  } B_CONSTRAINT_SPACETYPES;
  
  /* bConstraintChannel.flag */
index 72557145270427b75c28c44365355b576224311f,72557145270427b75c28c44365355b576224311f..6c098e220bbbd316e6f9579461eacbcadfa789a0
@@@ -71,7 -71,7 +71,8 @@@ typedef struct CustomData 
  #define CD_MTEXPOLY           15
  #define CD_MLOOPUV            16
  #define CD_MLOOPCOL           17
--#define CD_NUMTYPES           18
++#define CD_TANGENT            18
++#define CD_NUMTYPES           19
  
  /* Bits for CustomDataMask */
  #define CD_MASK_MVERT         (1 << CD_MVERT)
@@@ -92,6 -92,6 +93,7 @@@
  #define CD_MASK_MTEXPOLY      (1 << CD_MTEXPOLY)
  #define CD_MASK_MLOOPUV               (1 << CD_MLOOPUV)
  #define CD_MASK_MLOOPCOL      (1 << CD_MLOOPCOL)
++#define CD_MASK_TANGENT               (1 << CD_TANGENT)
  
  
  /* CustomData.flag */
index b88dd698c3f638ad0f55120c979f2b4d00a6baac,eafd886981b0032b89ddb85812d9585dc7f7105c..dca4e28688dcab1991234abc616807fa542d6a8f
@@@ -125,7 -123,7 +125,7 @@@ typedef struct bGPdata 
         */
        short sbuffer_size;                     /* number of elements currently in cache */
        short sbuffer_sflag;            /* flags for stroke that cache represents */
--      bGPDspoint *sbuffer;            /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
++      void *sbuffer;                          /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
  } bGPdata;
  
  /* bGPdata->flag */
index 6d025839ac8bc5e324ecac9824de743de0f1574f,6d025839ac8bc5e324ecac9824de743de0f1574f..4e427ed733ce1dfb5682f3fcf33647f5ae627526
@@@ -228,7 -228,7 +228,7 @@@ typedef struct PartialVisibility 
  
  /* mtface->mode */
  #define TF_DYNAMIC            1
--#define TF_DEPRECATED 2
++#define TF_ALPHASORT  2
  #define TF_TEX                        4
  #define TF_SHAREDVERT 8
  #define TF_LIGHT              16
index c4e8cb4925b83aeff9bace19c457583f853a626e,c4e8cb4925b83aeff9bace19c457583f853a626e..85c49a03569b2f8c330dac2b9a8ec6165d4c449a
@@@ -466,9 -466,9 +466,11 @@@ extern Object workob
  #define OB_LOCK_ROTX  8
  #define OB_LOCK_ROTY  16
  #define OB_LOCK_ROTZ  32
++#define OB_LOCK_ROT           56
  #define OB_LOCK_SCALEX        64
  #define OB_LOCK_SCALEY        128
  #define OB_LOCK_SCALEZ        256
++#define OB_LOCK_SCALE 448
  
  /* ob->softflag in DNA_object_force.h */
  
index e9dff0987738138bbbc088583ecce5e050a03a97,e9dff0987738138bbbc088583ecce5e050a03a97..0db87c00dd24c1709544c02f96e1af5bbd09c212
@@@ -1469,6 -1469,6 +1469,8 @@@ PyObject *Armature_Init(void
                PyConstant_NewInt("BONE_SELECTED", BONE_SELECTED));
        PyModule_AddObject(module, "TIP_SELECTED", 
                PyConstant_NewInt("TIP_SELECTED", BONE_TIPSEL));
++      PyModule_AddObject(module, "LOCKED_EDIT", 
++              PyConstant_NewInt("LOCKED_EDIT", BONE_EDITMODE_LOCKED));
  
        PyModule_AddObject(module, "OCTAHEDRON", 
                PyConstant_NewInt("OCTAHEDRON", ARM_OCTA));
index 84faf416c5f726304138f48f9ea50472272518f7,84faf416c5f726304138f48f9ea50472272518f7..948eb007803d25bb3e07ac249fe98d04f5f2ab74
@@@ -368,6 -368,6 +368,10 @@@ static PyObject *EditBone_getOptions(BP
                        if (PyList_Append(list, 
                                EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1)
                                goto RuntimeError;
++              if(self->editbone->flag & BONE_EDITMODE_LOCKED)
++                      if (PyList_Append(list, 
++                              EXPP_GetModuleConstant("Blender.Armature", "LOCKED_EDIT")) == -1)
++                              goto RuntimeError;
        }else{
                if(self->flag & BONE_CONNECTED)
                        if (PyList_Append(list, 
                        if (PyList_Append(list, 
                                EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1)
                                goto RuntimeError;
++              if(self->flag & BONE_EDITMODE_LOCKED)
++                      if (PyList_Append(list, 
++                              EXPP_GetModuleConstant("Blender.Armature", "LOCKED_EDIT")) == -1)
++                              goto RuntimeError;
        }
  
        return list;
@@@ -422,7 -422,7 +430,7 @@@ static int EditBone_CheckValidConstant(
                                return 0;
                        if (!STREQ3(PyString_AsString(name), "CONNECTED", "HINGE", "NO_DEFORM") &&
                                !STREQ3(PyString_AsString(name), "ROOT_SELECTED", "BONE_SELECTED", "TIP_SELECTED")      &&
--                              !STREQ2(PyString_AsString(name), "MULTIPLY", "HIDDEN_EDIT"))
++                              !STREQ3(PyString_AsString(name), "MULTIPLY", "HIDDEN_EDIT", "LOCKED_EDIT"))
                                return 0;
                        else
                                return 1;
index 68916af6166e16c944e96abeca49259027b5844d,68916af6166e16c944e96abeca49259027b5844d..9aceb0105e36c86adba576d637a0f80687719692
@@@ -89,6 -89,6 +89,8 @@@ Example:
  @type BONE_SELECTED: Constant
  @var TIP_SELECTED: Tip of the Bone is selected
  @type TIP_SELECTED: Constant
++@var LOCKED_EDIT: Prevents the bone from being transformed in editmode
++@type LOCKED_EDIT: Constant
  @var OCTAHEDRON: Bones drawn as octahedrons
  @type OCTAHEDRON: Constant
  @var STICK: Bones drawn as a line
@@@ -286,6 -286,6 +288,7 @@@ class Bone
                         - Armature.ROOT_SELECTED: Selection of root ball of bone
                         - Armature.BONE_SELECTED: Selection of bone
                         - Armature.TIP_SELECTED: Selection of tip ball of bone
++                       - Armature.LOCKED_EDIT: Prevents the bone from being transformed in editmode
        @type options: List of Constants
        @ivar subdivision: The number of bone subdivisions.
        @type subdivision: Int
index 8f251fc84525dcddffb73393d633e0cc5c319442,6fc3a2b18d12ec9bc67b2e0d7e1af0d3b6c169af..22e165cbe9fc96b31bb3d909bd6f738d73d99ecc
@@@ -56,6 -56,6 +56,7 @@@ struct View3D; /* keep me up here *
  #include "gen_utils.h"
  #include "gen_library.h"
  
++#include "../BPY_extern.h" /* for BPY_do_all_scripts() */
  #include "Scene.h"
  #include "Group.h"
  
@@@ -469,19 -469,19 +470,20 @@@ PyObject *M_Render_EnableDispWin( PyObj
  PyObject *RenderData_Render( BPy_RenderData * self )
  {
        Scene *oldsce;
++      /* unlock to prevent a deadlock when there are pynodes: */
++      PyThreadState *tstate = NULL;
  
        if (!G.background) {
                oldsce = G.scene;
                set_scene( self->scene );
++              tstate = PyEval_SaveThread();
                BIF_do_render( 0 );
                set_scene( oldsce );
        }
--
        else { /* background mode (blender -b file.blend -P script) */
++              int slink_flag = 0;
                Render *re= RE_NewRender(G.scene->id.name);
  
--
--
                int end_frame = G.scene->r.efra;
  
                if (G.scene != self->scene)
  
                G.scene->r.efra = G.scene->r.sfra;
  
++              if (G.f & G_DOSCRIPTLINKS) {
++                      BPY_do_all_scripts(SCRIPT_RENDER);
++                      G.f &= ~G_DOSCRIPTLINKS; /* avoid FRAMECHANGED events*/
++                      slink_flag = 1;
++              }
++
++              tstate = PyEval_SaveThread();
++
                RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
  
++              if (slink_flag) {
++                      G.f |= G_DOSCRIPTLINKS;
++                      BPY_do_all_scripts(SCRIPT_POSTRENDER);
++              }
++
                G.scene->r.efra = end_frame;
        }
  
++      PyEval_RestoreThread(tstate);
        Py_RETURN_NONE;
  }
  
@@@ -565,12 -565,10 +581,13 @@@ PyObject *RenderData_SaveRenderedImage 
  PyObject *RenderData_RenderAnim( BPy_RenderData * self )
  {
        Scene *oldsce;
-       /* this prevents a deadlock when there are pynodes: */
-       PyThreadState *tstate = PyEval_SaveThread();
--
++      /* unlock to prevent a deadlock when there are pynodes: */
++      PyThreadState *tstate = NULL;
++              
        if (!G.background) {
                oldsce = G.scene;
                set_scene( self->scene );
++              tstate = PyEval_SaveThread();
                BIF_do_render( 1 );
                set_scene( oldsce );
        }
                if (G.scene->r.sfra > G.scene->r.efra)
                        return EXPP_ReturnPyObjError (PyExc_RuntimeError,
                                "start frame must be less or equal to end frame");
 -              
++
++              if (G.f & G_DOSCRIPTLINKS)
++                      BPY_do_all_scripts(SCRIPT_RENDER);
++
++              tstate = PyEval_SaveThread();
                RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
++
++              if (G.f & G_DOSCRIPTLINKS)
++                      BPY_do_all_scripts(SCRIPT_POSTRENDER);
        }
++
 +      PyEval_RestoreThread(tstate);
        Py_RETURN_NONE;
  }
  
index 4a4eaf3c81faf0da2c4b50a45ae1364fe3d0a0a4,529a795a101e90c7167b07838b04ae01e5d1e48f..b26c52a92e2dcbec6f68479ff8fa6455fcba1044
@@@ -4371,11 -4371,11 +4371,12 @@@ static void editing_panel_armature_bone
                        uiDefButF(block, NUM,B_ARM_RECALCDATA, "Weight:", 225, by-19,105, 18, &curBone->weight, 0.0F, 1000.0F, 10.0F, 0.0F, "Bone deformation weight");
                        
                        /* bone types */
--                      uiDefButBitI(block, TOG, BONE_HINGE, B_ARM_RECALCDATA, "Hinge",         -10,by-38,80,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit rotation or scale from parent Bone");
--                      uiDefButBitI(block, TOG, BONE_NO_SCALE, B_ARM_RECALCDATA, "S",          70,by-38,20,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit scale from parent Bone");
--                      uiDefButBitI(block, TOGN, BONE_NO_DEFORM, B_ARM_RECALCDATA, "Deform",   90, by-38, 80, 18, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "Indicate if Bone deforms geometry");
--                      uiDefButBitI(block, TOG, BONE_MULT_VG_ENV, B_ARM_RECALCDATA, "Mult", 170,by-38,80,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Multiply Bone Envelope with VertexGroup");
--                      uiDefButBitI(block, TOG, BONE_HIDDEN_A, REDRAWVIEW3D, "Hide",   250,by-38,80,18, &curBone->flag, 0, 0, 0, 0, "Toggles display of this bone in Edit Mode");
++                      uiDefButBitI(block, TOG, BONE_HINGE, B_ARM_RECALCDATA, "Hinge",         -10,by-38,60,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit rotation or scale from parent Bone");
++                      uiDefButBitI(block, TOG, BONE_NO_SCALE, B_ARM_RECALCDATA, "S",          50,by-38,20,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit scale from parent Bone");
++                      uiDefButBitI(block, TOGN, BONE_NO_DEFORM, B_ARM_RECALCDATA, "Deform",   70, by-38, 80, 18, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "Indicate if Bone deforms geometry");
++                      uiDefButBitI(block, TOG, BONE_MULT_VG_ENV, B_ARM_RECALCDATA, "Mult", 150,by-38,60,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Multiply Bone Envelope with VertexGroup");
++                      uiDefButBitI(block, TOG, BONE_HIDDEN_A, REDRAWVIEW3D, "Hide",   210,by-38,60,18, &curBone->flag, 0, 0, 0, 0, "Toggles display of this bone in Edit Mode");
++                      uiDefButBitI(block, TOG, BONE_EDITMODE_LOCKED, REDRAWVIEW3D, "Lock",    270,by-38,60,18, &curBone->flag, 0, 0, 0, 0, "Prevents this bone from being transformed in Edit Mode");
                        
                        /* layers */
                        uiBlockBeginAlign(block);
@@@ -6188,6 -6188,6 +6189,7 @@@ static void editing_panel_mesh_texface(
                uiDefButBitS(block, TOG, TF_BILLBOARD2, B_TFACE_BILLB, "Billboard",660,110,60,19, &tf->mode, 0, 0, 0, 0, "Billboard with Z-axis constraint");
                uiDefButBitS(block, TOG, TF_SHADOW, REDRAWVIEW3D, "Shadow", 720,110,60,19, &tf->mode, 0, 0, 0, 0, "Face is used for shadow");
                uiDefButBitS(block, TOG, TF_BMFONT, REDRAWVIEW3D, "Text", 780,110,60,19, &tf->mode, 0, 0, 0, 0, "Enable bitmap text on face");
++              uiDefButBitS(block, TOG, TF_ALPHASORT, REDRAWVIEW3D, "Sort", 840,110,60,19, &tf->mode, 0, 0, 0, 0, "Enable sorting of faces for correct alpha drawing (slow, use Clip Alpha instead when possible)");
  
                uiBlockBeginAlign(block);
                uiBlockSetCol(block, TH_BUT_SETTING1);
index 498edc0dfed3f3214ecb6f43e6ec8e79aa2629ba,6b29a05bd22145dcfce622b0d4e46a5d2b14e142..5cf1958678e5ad99cb6c22efebac2c517becf380
@@@ -1654,53 -1654,53 +1654,66 @@@ static short draw_actuatorbuttons(Objec
                        wval = (width-100)/3;
                        if (oa->type == ACT_OBJECT_NORMAL)
                        {
--                              ysize= 175;
--                              
++                              if ( ob->gameflag & OB_DYNAMIC )
++                              {
++                                      ysize= 175;
++                              }
++                              else
++                              {
++                                      ysize= 72;
++                              }
++
                                glRects(xco, yco-ysize, xco+width, yco);
                                uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
                                
--                              uiDefBut(block, LABEL, 0, "Force",      xco, yco-45, 55, 19, NULL, 0, 0, 0, 0, "Sets the force");
--                              uiDefButF(block, NUM, 0, "",            xco+45, yco-45, wval, 19, oa->forceloc, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-45, wval, 19, oa->forceloc+1, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-45, wval, 19, oa->forceloc+2, -10000.0, 10000.0, 10, 0, "");
--                              
--                              uiDefBut(block, LABEL, 0, "Torque", xco, yco-64, 55, 19, NULL, 0, 0, 0, 0, "Sets the torque");
--                              uiDefButF(block, NUM, 0, "",            xco+45, yco-64, wval, 19, oa->forcerot, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-64, wval, 19, oa->forcerot+1, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-64, wval, 19, oa->forcerot+2, -10000.0, 10000.0, 10, 0, "");
++                              uiDefBut(block, LABEL, 0, "Loc",        xco, yco-45, 45, 19, NULL, 0, 0, 0, 0, "Sets the location");
++                              uiDefButF(block, NUM, 0, "",            xco+45, yco-45, wval, 19, oa->dloc, -10000.0, 10000.0, 10, 0, "");
++                              uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-45, wval, 19, oa->dloc+1, -10000.0, 10000.0, 10, 0, "");
++                              uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-45, wval, 19, oa->dloc+2, -10000.0, 10000.0, 10, 0, "");
                                
--                              uiDefBut(block, LABEL, 0, "dLoc",       xco, yco-87, 45, 19, NULL, 0, 0, 0, 0, "Sets the dLoc");
--                              uiDefButF(block, NUM, 0, "",            xco+45, yco-87, wval, 19, oa->dloc, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-87, wval, 19, oa->dloc+1, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-87, wval, 19, oa->dloc+2, -10000.0, 10000.0, 10, 0, "");
--                              
--                              uiDefBut(block, LABEL, 0, "dRot",       xco, yco-106, 45, 19, NULL, 0, 0, 0, 0, "Sets the dRot");
--                              uiDefButF(block, NUM, 0, "",            xco+45, yco-106, wval, 19, oa->drot, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-106, wval, 19, oa->drot+1, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-106, wval, 19, oa->drot+2, -10000.0, 10000.0, 10, 0, "");
++                              uiDefBut(block, LABEL, 0, "Rot",        xco, yco-64, 45, 19, NULL, 0, 0, 0, 0, "Sets the rotation");
++                              uiDefButF(block, NUM, 0, "",            xco+45, yco-64, wval, 19, oa->drot, -10000.0, 10000.0, 10, 0, "");
++                              uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-64, wval, 19, oa->drot+1, -10000.0, 10000.0, 10, 0, "");
++                              uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-64, wval, 19, oa->drot+2, -10000.0, 10000.0, 10, 0, "");
++
++                              uiDefButBitS(block, TOG, ACT_DLOC_LOCAL, 0, "L",                xco+45+3*wval, yco-45, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
++                              uiDefButBitS(block, TOG, ACT_DROT_LOCAL, 0, "L",                xco+45+3*wval, yco-64, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
++      
++                              if ( ob->gameflag & OB_DYNAMIC )
++                              {
++                                      uiDefBut(block, LABEL, 0, "Force",      xco, yco-87, 55, 19, NULL, 0, 0, 0, 0, "Sets the force");
++                                      uiDefButF(block, NUM, 0, "",            xco+45, yco-87, wval, 19, oa->forceloc, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-87, wval, 19, oa->forceloc+1, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-87, wval, 19, oa->forceloc+2, -10000.0, 10000.0, 10, 0, "");
                                
--                              uiDefBut(block, LABEL, 0, "linV",       xco, yco-129, 45, 19, NULL, 0, 0, 0, 0, "Sets the linear velocity");
--                              uiDefButF(block, NUM, 0, "",            xco+45, yco-129, wval, 19, oa->linearvelocity, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-129, wval, 19, oa->linearvelocity+1, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-129, wval, 19, oa->linearvelocity+2, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefBut(block, LABEL, 0, "Torque", xco, yco-106, 55, 19, NULL, 0, 0, 0, 0, "Sets the torque");
++                                      uiDefButF(block, NUM, 0, "",            xco+45, yco-106, wval, 19, oa->forcerot, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-106, wval, 19, oa->forcerot+1, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-6106, wval, 19, oa->forcerot+2, -10000.0, 10000.0, 10, 0, "");                               
++                              }
                                
--                              uiDefBut(block, LABEL, 0, "angV",       xco, yco-148, 45, 19, NULL, 0, 0, 0, 0, "Sets the angular velocity");
--                              uiDefButF(block, NUM, 0, "",            xco+45, yco-148, wval, 19, oa->angularvelocity, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-148, wval, 19, oa->angularvelocity+1, -10000.0, 10000.0, 10, 0, "");
--                              uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-148, wval, 19, oa->angularvelocity+2, -10000.0, 10000.0, 10, 0, "");
++                              if ( ob->gameflag & OB_DYNAMIC )
++                              {
++                                      uiDefBut(block, LABEL, 0, "LinV",       xco, yco-129, 45, 19, NULL, 0, 0, 0, 0, "Sets the linear velocity");
++                                      uiDefButF(block, NUM, 0, "",            xco+45, yco-129, wval, 19, oa->linearvelocity, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-129, wval, 19, oa->linearvelocity+1, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-129, wval, 19, oa->linearvelocity+2, -10000.0, 10000.0, 10, 0, "");
                                
--                              uiDefBut(block, LABEL, 0, "damp",       xco, yco-171, 45, 19, NULL, 0, 0, 0, 0, "Number of frames to reach the target velocity");
--                              uiDefButS(block, NUM, 0, "",            xco+45, yco-171, wval, 19, &oa->damping, 0.0, 1000.0, 100, 0, "");
--
--                              uiDefButBitS(block, TOG, ACT_FORCE_LOCAL, 0, "L",               xco+45+3*wval, yco-45, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
--                              uiDefButBitS(block, TOG, ACT_TORQUE_LOCAL, 0, "L",              xco+45+3*wval, yco-64, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
--                              uiDefButBitS(block, TOG, ACT_DLOC_LOCAL, 0, "L",                xco+45+3*wval, yco-87, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
--                              uiDefButBitS(block, TOG, ACT_DROT_LOCAL, 0, "L",                xco+45+3*wval, yco-106, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
--                              uiDefButBitS(block, TOG, ACT_LIN_VEL_LOCAL, 0, "L",             xco+45+3*wval, yco-129, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
--                              uiDefButBitS(block, TOG, ACT_ANG_VEL_LOCAL, 0, "L",             xco+45+3*wval, yco-148, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
++                                      uiDefBut(block, LABEL, 0, "AngV",       xco, yco-148, 45, 19, NULL, 0, 0, 0, 0, "Sets the angular velocity");
++                                      uiDefButF(block, NUM, 0, "",            xco+45, yco-148, wval, 19, oa->angularvelocity, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefButF(block, NUM, 0, "",            xco+45+wval, yco-148, wval, 19, oa->angularvelocity+1, -10000.0, 10000.0, 10, 0, "");
++                                      uiDefButF(block, NUM, 0, "",            xco+45+2*wval, yco-148, wval, 19, oa->angularvelocity+2, -10000.0, 10000.0, 10, 0, "");
                                
--                              uiDefButBitS(block, TOG, ACT_ADD_LIN_VEL, 0, "add",xco+45+3*wval+15, yco-129, 35, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between ADD and SET linV");
++                                      uiDefBut(block, LABEL, 0, "Damp",       xco, yco-171, 45, 19, NULL, 0, 0, 0, 0, "Number of frames to reach the target velocity");
++                                      uiDefButS(block, NUM, 0, "",            xco+45, yco-171, wval, 19, &oa->damping, 0.0, 1000.0, 100, 0, "");
++
++                                      uiDefButBitS(block, TOG, ACT_FORCE_LOCAL, 0, "L",               xco+45+3*wval, yco-87, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
++                                      uiDefButBitS(block, TOG, ACT_TORQUE_LOCAL, 0, "L",              xco+45+3*wval, yco-106, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
++                                      uiDefButBitS(block, TOG, ACT_LIN_VEL_LOCAL, 0, "L",             xco+45+3*wval, yco-129, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
++                                      uiDefButBitS(block, TOG, ACT_ANG_VEL_LOCAL, 0, "L",             xco+45+3*wval, yco-148, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
                                
++                                      uiDefButBitS(block, TOG, ACT_ADD_LIN_VEL, 0, "add",xco+45+3*wval+15, yco-129, 35, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between ADD and SET linV");
++                              }                               
                        } else if (oa->type == ACT_OBJECT_SERVO)
                        {
                                ysize= 172;
index ebe770c89e77de2cc8c1546d8c00a7d2e61becdd,ebe770c89e77de2cc8c1546d8c00a7d2e61becdd..2c7802c3302dcd61028112a58e9b6cc05c218407
@@@ -480,7 -480,7 +480,7 @@@ static void draw_constraint_spaceselec
        
        /* Target-Space */
        if (target == 1) {
--              uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1", 
++              uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
                                                                                                tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
        }
        else if (target == 0) {
        
        /* Owner-Space */
        if (owner == 1) {
--              uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1", 
++              uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
                                                                                                ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
        }
        else if (owner == 0) {
index aacae08d972ad6faca8b6dc83498684daf72e363,55d0464b9af1a47764d4ae7244044b395d68dc47..733310bfda7c61b74956ba1ea345660d4cf71380
@@@ -170,27 -175,33 +170,32 @@@ static void gp_drawui_layer (uiBlock *b
                uiDefIconButBitI(block, ICONTOG, GP_LAYER_LOCKED, B_REDR, ICON_UNLOCKED,        *xco-7, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Layer cannot be modified");
        }
        
 -      /* when layer is locked or hidden, don't draw the rest of its settings */
 +      /* when layer is locked or hidden, only draw header */
        if (gpl->flag & (GP_LAYER_LOCKED|GP_LAYER_HIDE)) {
 -              height= 26;
 +              char name[256]; /* gpl->info is 128, but we need space for 'locked/hidden' as well */
                
 -              /* draw rest of header */
 -              {
 -                      /* visibility button (only if hidden but not locked!) */
 -                      if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED))
 -                              uiDefIconButBitI(block, ICONTOG, GP_LAYER_HIDE, B_REDR, ICON_RESTRICT_VIEW_OFF, *xco+12, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Visibility of layer");
 -                      
 -                      /* name */
 -                      uiDefBut(block, LABEL, 1, gpl->info,    *xco+35, *yco, 240, 20, NULL, 0.0, 0.0, 0, 0, "Short description of what this layer is for (optional)");
 -              }
 +              height= 26;
                
 -              /* draw backdrop */
 -              uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-8, *yco-height, width, height-1, NULL, 5.0, 0.0, 12, rb_col, ""); 
 +              /* visibility button (only if hidden but not locked!) */
 +              if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED))
 +                      uiDefIconButBitI(block, ICONTOG, GP_LAYER_HIDE, B_REDR, ICON_RESTRICT_VIEW_OFF, *xco+12, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Visibility of layer");
                
 -              /* draw settings... (i.e. just warning for this one) */
 +              /* name */
                if (gpl->flag & GP_LAYER_HIDE)
 -                      uiDefBut(block, LABEL, 1, "Grease Pencil Layer Hidden", *xco+60, *yco-26, 205, 20, NULL, 0.0, 0.0, 0, 0, "");
 +                      sprintf(name, "%s (Hidden)", gpl->info);
                else
 -                      uiDefBut(block, LABEL, 1, "Grease Pencil Layer Locked", *xco+60, *yco-26, 205, 20, NULL, 0.0, 0.0, 0, 0, "");
 +                      sprintf(name, "%s (Locked)", gpl->info);
 +              uiDefBut(block, LABEL, 1, name, *xco+35, *yco, 240, 20, NULL, 0.0, 0.0, 0, 0, "Short description of what this layer is for (optional)");
                        
++              /* delete button (only if hidden but not locked!) */
++              if ((gpl->flag & GP_LAYER_HIDE) & !(gpl->flag & GP_LAYER_LOCKED)) {
++                      but= uiDefIconBut(block, BUT, B_REDR, ICON_X, *xco+(width-30), *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete layer");
++                      uiButSetFunc(but, gp_ui_dellayer_cb, gpd, NULL);
++              }       
                uiBlockSetEmboss(block, UI_EMBOSS);
        }
        else {
--              height= 100;
++              height= 97;
                
                /* draw rest of header */
                {
                        /* stroke thickness */
                        uiDefButS(block, NUMSLI, B_REDR, "Thickness:",  *xco, *yco-75, 150, 20, &gpl->thickness, 1, 10, 0, 0, "Thickness of strokes (in pixels)");
                        
++                      /* debugging options */
++                      if (G.f & G_DEBUG) {
++                              uiDefButBitI(block, TOG, GP_LAYER_DRAWDEBUG, B_REDR, "Show Points", *xco, *yco-95, 150, 20, &gpl->flag, 0, 0, 0, 0, "Show points which form the strokes");
++                      }
                        
                        /* onion-skinning */
                        uiBlockBeginAlign(block);
                        uiBlockEndAlign(block);
                        
                        /* options */
 -                      but= uiDefBut(block, BUT, B_REDR, "Del Active Frame", *xco+160, *yco-75, 140, 20, NULL, 0, 0, 0, 0, "Erases the the active frame for this layer");
 -                      uiButSetFunc(but, gp_ui_delframe_cb, gpd, gpl);
 -                      
 -                      but= uiDefBut(block, BUT, B_REDR, "Del Last Stroke", *xco+160, *yco-95, 140, 20, NULL, 0, 0, 0, 0, "Erases the last stroke from the active frame");
 -                      uiButSetFunc(but, gp_ui_delstroke_cb, gpd, gpl);
 -                      
 -                      //uiDefButBitI(block, TOG, GP_LAYER_DRAWDEBUG, B_REDR, "Show Points", *xco+160, *yco-75, 130, 20, &gpl->flag, 0, 0, 0, 0, "Show points which form the strokes");
 +                      uiBlockBeginAlign(block);
 +                              but= uiDefBut(block, BUT, B_REDR, "Del Active Frame", *xco+160, *yco-75, 140, 20, NULL, 0, 0, 0, 0, "Erases the the active frame for this layer (Hotkey = Alt-XKEY/DEL)");
 +                              uiButSetFunc(but, gp_ui_delframe_cb, gpd, gpl);
 +                              
 +                              but= uiDefBut(block, BUT, B_REDR, "Del Last Stroke", *xco+160, *yco-95, 140, 20, NULL, 0, 0, 0, 0, "Erases the last stroke from the active frame (Hotkey = Alt-XKEY/DEL)");
 +                              uiButSetFunc(but, gp_ui_delstroke_cb, gpd, gpl);
 +                      uiBlockEndAlign(block);
-                       
-                       //uiDefButBitI(block, TOG, GP_LAYER_DRAWDEBUG, B_REDR, "Show Points", *xco+160, *yco-75, 130, 20, &gpl->flag, 0, 0, 0, 0, "Show points which form the strokes");
                }
        }
        
@@@ -271,14 -280,8 +278,18 @@@ short draw_gpencil_panel (uiBlock *bloc
                uiButSetFunc(but, gp_ui_addlayer_cb, gpd, NULL);
                
                
 -              /* show override lmb-clicks button */
 -              uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 150, 20, &gpd->flag, 0, 0, 0, 0, "Interpret LMB-click as new strokes (same as holding Shift-Key per stroke)");
 +              /* show override lmb-clicks button + painting lock */
 +              uiBlockBeginAlign(block);
-                       uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 130, 20, &gpd->flag, 0, 0, 0, 0, "Interpret LMB-click as new strokes (same as holding Shift-Key per stroke)");
-                       
-                       uiBlockSetCol(block, TH_BUT_SETTING);
-                               uiDefIconButBitI(block, ICONTOG, GP_DATA_LMBPLOCK, B_REDR, ICON_UNLOCKED,       300, 225, 20, 20, &gpd->flag, 0.0, 0.0, 0, 0, "Painting cannot occur with Shift-LMB (when making selections)");
-                       uiBlockSetCol(block, TH_AUTO);
++                      if ((gpd->flag & GP_DATA_EDITPAINT)==0) {
++                              uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 130, 20, &gpd->flag, 0, 0, 0, 0, "Interpret click-drag as new strokes");
++                              
++                              uiBlockSetCol(block, TH_BUT_SETTING);
++                                      uiDefIconButBitI(block, ICONTOG, GP_DATA_LMBPLOCK, B_REDR, ICON_UNLOCKED,       300, 225, 20, 20, &gpd->flag, 0.0, 0.0, 0, 0, "Painting cannot occur with Shift-LMB (when making selections)");
++                              uiBlockSetCol(block, TH_AUTO);
++                      }
++                      else
++                              uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 150, 20, &gpd->flag, 0, 0, 0, 0, "Interpret click-drag as new strokes");
 +              uiBlockEndAlign(block);
                
                /* 'view align' button (naming depends on context) */
                if (sa->spacetype == SPACE_VIEW3D)
@@@ -306,6 -313,6 +317,66 @@@ enum 
        GP_DRAWDATA_ONLYV2D             = (1<<2),       /* only draw 'canvas' strokes */
  };
  
++/* draw stroke in buffer */
++static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
++{
++      tGPspoint *pt;
++      int i;
++      
++      /* error checking */
++      if ((points == NULL) || (totpoints <= 0))
++              return;
++      
++      /* check if buffer can be drawn */
++      if (dflag & (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_ONLYV2D))
++              return;
++      
++      /* if drawing a single point, draw it larger */ 
++      if (totpoints == 1) {           
++              /* draw point */
++              glBegin(GL_POINTS);
++                      glVertex2f(points->x, points->y);
++              glEnd();
++      }
++      else if (sflag & GP_STROKE_ERASER) {
++              /* draw stroke curve - just standard thickness */
++              setlinestyle(4);
++              glLineWidth(1.0f);
++              
++              glBegin(GL_LINE_STRIP);
++              for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
++                      glVertex2f(pt->x, pt->y);
++              }
++              glEnd();
++              
++              setlinestyle(0);
++      }
++      else {
++              float oldpressure = 0.0f;
++              
++              /* draw stroke curve */
++              setlinestyle(2);
++              
++              glBegin(GL_LINE_STRIP);
++              for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
++                      if (fabs(pt->pressure - oldpressure) > 0.2f) {
++                              glEnd();
++                              glLineWidth(pt->pressure * thickness);
++                              glBegin(GL_LINE_STRIP);
++                              
++                              glVertex2f(pt->x, pt->y);
++                              
++                              oldpressure = pt->pressure;
++                      }
++                      else
++                              glVertex2f(pt->x, pt->y);
++              }
++              glEnd();
++              
++              setlinestyle(0);
++      }
++}
++
  /* draw a given stroke */
  static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy)
  {
        }
  }
  
-               /* handle 'eraser' strokes differently */
-               if (gps->flag & GP_STROKE_ERASER) {
-                       // FIXME: this method is a failed experiment
- #if 0
-                       /* draw stroke twice, first time with 'white' to set a mask to invert
-                        * contents of framebuffer, then second-time the same again but to restore
-                        * the contents
-                        */
-                       glEnable(GL_COLOR_LOGIC_OP); 
-                       glLogicOp(GL_XOR);
-                       
-                       glColor4f(1, 1, 1, 1); /* white */
-                       
-                       gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, 0, winx, winy);
-                       gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, 0, winx, winy);
-                       
-                       glDisable(GL_COLOR_LOGIC_OP);
-                       
-                       /* reset color for drawing next stroke */
-                       glColor4f(color[0], color[1], color[2], color[3]);
- #endif
-               }
-               else {
-                       /* just draw the stroke once */
-                       gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
-               }
 +/* draw a set of strokes */
 +static void gp_draw_strokes (bGPDframe *gpf, int winx, int winy, int dflag, short debug, 
 +                                                       short lthick, float color[4])
 +{
 +      bGPDstroke *gps;
 +      
 +      /* set color first (may need to reset it again later too) */
 +      glColor4f(color[0], color[1], color[2], color[3]);
 +      
 +      for (gps= gpf->strokes.first; gps; gps= gps->next) {    
++              /* just draw the stroke once */
++              gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
 +      }
 +}
 +
  /* draw grease-pencil datablock */
  static void gp_draw_data (bGPdata *gpd, int winx, int winy, int dflag)
  {
                                        /* check if frame is drawable */
                                        if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
                                                /* alpha decreases with distance from curframe index */
-                                               tcolor[3] = color[3] - (i * 0.7);
-                                               gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
 -                                              glColor4f(color[0], color[1], color[2], (color[3]-(i*0.7)));
 -                                              
 -                                              for (gps= gf->strokes.first; gps; gps= gps->next) {     
 -                                                      gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
 -                                              }
++                                              tcolor[3] = color[3] - (i/gpl->gstep);
++                                              gp_draw_strokes(gf, winx, winy, dflag, debug, lthick, tcolor);
                                        }
                                        else 
                                                break;
                                        /* check if frame is drawable */
                                        if ((gf->framenum - gpf->framenum) <= gpl->gstep) {
                                                /* alpha decreases with distance from curframe index */
-                                               tcolor[3] = color[3] - (i * 0.7);
-                                               gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
 -                                              glColor4f(color[0], color[1], color[2], (color[3]-(i*0.7)));
 -                                              
 -                                              for (gps= gf->strokes.first; gps; gps= gps->next) {                                                             
 -                                                      gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
 -                                              }
++                                              tcolor[3] = color[3] - (i/gpl->gstep);
++                                              gp_draw_strokes(gf, winx, winy, dflag, debug, lthick, tcolor);
                                        }
                                        else 
                                                break;
                        }
                        else {
                                /* draw the strokes for the ghost frames (at half of the alpha set by user) */
 -                              glColor4f(color[0], color[1], color[2], (color[3] / 7));
 -                              
                                if (gpf->prev) {
 -                                      for (gps= gpf->prev->strokes.first; gps; gps= gps->next) {
 -                                              gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
 -                                      }
 +                                      tcolor[3] = (color[3] / 7);
-                                       gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
++                                      gp_draw_strokes(gpf->prev, winx, winy, dflag, debug, lthick, tcolor);
                                }
                                
 -                              glColor4f(color[0], color[1], color[2], (color[3] / 4));
                                if (gpf->next) {
 -                                      for (gps= gpf->next->strokes.first; gps; gps= gps->next) {      
 -                                              gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
 -                                      }
 +                                      tcolor[3] = (color[3] / 4);
-                                       gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
++                                      gp_draw_strokes(gpf->next, winx, winy, dflag, debug, lthick, tcolor);
                                }
                                
                                /* restore alpha */
                }
                
                /* draw the strokes already in active frame */
 -              for (gps= gpf->strokes.first; gps; gps= gps->next) {    
 -                      gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
 -              }
 +              tcolor[3]= color[3];
 +              gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
                
                /* Check if may need to draw the active stroke cache, only if this layer is the active layer
--               * that is being edited. (Stroke cache is currently stored in gp-data)
++               * that is being edited. (Stroke buffer is currently stored in gp-data)
                 */
                if ((G.f & G_GREASEPENCIL) && (gpl->flag & GP_LAYER_ACTIVE) &&
                        (gpf->flag & GP_FRAME_PAINT)) 
                {
                        /* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */
--                      setlinestyle(2);
--                      gp_draw_stroke(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, debug, winx, winy);
--                      setlinestyle(0);
++                      gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
                }
        }
        
index 8c7c78de83735b584930676475cbd1678f7baef1,14434504e7aa8338fc0b1682ea2b38f31d3db327..2030eb658dec077dec3cf7a64dc6498f16876bb7
@@@ -1995,6 -1987,6 +1995,8 @@@ static void v3d_editarmature_buts(uiBlo
        tfp->ob_eul[0]= 180.0*ebone->roll/M_PI;
        uiDefButF(block, NUM, B_ARMATUREPANEL1, "Roll:",        10, 100, 140, 19, tfp->ob_eul, -lim, lim, 1000, 3, "");
  
++      uiDefButBitI(block, TOG, BONE_EDITMODE_LOCKED, REDRAWVIEW3D, "Lock", 160, 100, 140, 19, &(ebone->flag), 0, 0, 0, 0, "Prevents bone from being transformed in edit mode");
++      
        uiBlockBeginAlign(block);
        uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailRadius:",  10, 150, 140, 19, &ebone->rad_tail, 0, lim, 10, 3, "");
        if (ebone->parent && ebone->flag & BONE_CONNECTED )
index 6310dd0a262c8e6a85bd0139af08c004d19b36f3,6310dd0a262c8e6a85bd0139af08c004d19b36f3..3d0f26960d60091ae5303adffe38f2cbf2e0c30c
@@@ -2709,6 -2709,6 +2709,32 @@@ void show_all_armature_bones(void
        BIF_undo_push("Reveal Bones");
  }
  
++/* Sets editmode transform locks for bones (adds if lock==1, clears otherwise) */
++void set_locks_armature_bones(short lock)
++{
++      bArmature *arm= G.obedit->data;
++      EditBone *ebone;
++      
++      for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
++              if (arm->layer & ebone->layer) {
++                      if (ebone->flag & BONE_SELECTED) {
++                              if (lock)
++                                      ebone->flag |= BONE_EDITMODE_LOCKED;
++                              else    
++                                      ebone->flag &= ~BONE_EDITMODE_LOCKED;
++                      }
++              }
++      }
++      countall();
++      allqueue(REDRAWVIEW3D, 0);
++      allqueue(REDRAWBUTSEDIT, 0);
++      
++      if (lock)
++              BIF_undo_push("Lock Bones");
++      else
++              BIF_undo_push("Unlock Bones");
++}
++
  /* check for null, before calling! */
  static void bone_connect_to_existing_parent(EditBone *bone)
  {
index c5dd41e16d55fd519ed9aad28bbcccbe1edc21cd,c5dd41e16d55fd519ed9aad28bbcccbe1edc21cd..63c301658f2232e9c85db24a5a40b48f7d20434b
@@@ -82,6 -82,6 +82,7 @@@
  #include "BKE_group.h"
  #include "BKE_ipo.h"
  #include "BKE_key.h"
++#include "BKE_main.h"
  #include "BKE_material.h"
  #include "BKE_particle.h"
  #include "BKE_texture.h"
@@@ -933,6 -933,6 +934,9 @@@ static void make_editipo(void
                        ob->ipowin= ID_TE;
                        make_texture_editipo(G.sipo);
                }
++              else if(G.scene->world && give_current_world_texture()) {
++                      make_texture_editipo(G.sipo);
++              }
        }
        else if(G.sipo->blocktype==ID_CA) {
                if (ob) {
@@@ -1120,6 -1120,6 +1124,11 @@@ static void get_ipo_context(short block
                        *from= (ID *)tex;
                        if(tex) *ipo= tex->ipo;
                }
++              else if(G.scene->world) {
++                      Tex *tex= give_current_world_texture();
++                      *from= (ID *)tex;
++                      if(tex) *ipo= tex->ipo;
++              }
        }
        else if(blocktype==ID_MA) {
                if(ob) {
@@@ -6002,4 -6002,4 +6011,4 @@@ void move_to_frame(void
                }
        }
        BIF_undo_push("Set frame to selected Ipo vertex");
--}
++}
index 6af4f47ed11cdbc91e0a55b4087716014eec7444,6af4f47ed11cdbc91e0a55b4087716014eec7444..cbf7691754dfcd78fa92fd63854fbd2cdfaf4a02
@@@ -2760,7 -2760,7 +2760,7 @@@ void special_editmenu(void
                DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
        }
        else if(G.obedit->type==OB_ARMATURE) {
--              nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Flip Left-Right Names%x3|%l|AutoName Left-Right%x4|AutoName Front-Back%x5|AutoName Top-Bottom%x6");
++              nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Flip Left-Right Names%x3|%l|AutoName Left-Right%x4|AutoName Front-Back%x5|AutoName Top-Bottom%x6|%l|Lock%x7|Unlock%x8");
                if(nr==1)
                        subdivide_armature(1);
                if(nr==2) {
                else if(ELEM3(nr, 4, 5, 6)) {
                        armature_autoside_names(nr-4);
                }
++              else if(nr==7)
++                      set_locks_armature_bones(1);
++              else if(nr==8)
++                      set_locks_armature_bones(0);
        }
        else if(G.obedit->type==OB_LATTICE) {
                static float weight= 1.0f;
@@@ -3502,6 -3502,6 +3506,17 @@@ void copy_attr(short event
                                        base->object->damping= ob->damping;
                                        base->object->rdamping= ob->rdamping;
                                }
++                              else if(event==11) {    /* all physical attributes */
++                                      base->object->gameflag = ob->gameflag;
++                                      base->object->inertia = ob->inertia;
++                                      base->object->formfactor = ob->formfactor;
++                                      base->object->damping= ob->damping;
++                                      base->object->rdamping= ob->rdamping;
++                                      base->object->mass= ob->mass;
++                                      if (ob->gameflag & OB_BOUNDS) {
++                                              base->object->boundtype = ob->boundtype;
++                                      }
++                              }
                                else if(event==17) {    /* tex space */
                                        copy_texture_space(base->object, ob);
                                }
@@@ -3688,7 -3688,7 +3703,7 @@@ void copy_attr_menu(
         * view3d_edit_object_copyattrmenu() and in toolbox.c
         */
        
--      strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|Time Offset%x5|Dupli%x6|%l|Mass%x7|Damping%x8|Properties%x9|Logic Bricks%x10|Protected Transform%x29|%l");
++      strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|Time Offset%x5|Dupli%x6|%l|Mass%x7|Damping%x8|All Physical Attributes%x11|Properties%x9|Logic Bricks%x10|Protected Transform%x29|%l");
        
        strcat (str, "|Object Constraints%x22");
        strcat (str, "|NLA Strips%x26");
index e3ec69975deeb056ff4d5ef0ad67c2b2c572afee,e3ec69975deeb056ff4d5ef0ad67c2b2c572afee..a3fcad7885c2869386302afa93f96a53914107b1
@@@ -298,7 -298,7 +298,7 @@@ int lasso_inside(short mcords[][2], sho
  }
  
  /* edge version for lasso select. we assume boundbox check was done */
--static int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
++int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
  {
        short v1[2], v2[2];
        int a;
@@@ -371,7 -371,7 +371,7 @@@ static void do_lasso_select_objects(sho
        }
  }
  
--static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
++void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
  {
        short a;
        
index 6deea5e1e8172ef13dac60a7e3c9cc3d695eacc8,fa32b0ac7d4dc300b4c12ab21bb1f5e8a368b53f..eef21323a44c3a1d7e90351a2582f362d194037f
@@@ -48,6 -48,6 +48,7 @@@
  #include "DNA_screen_types.h"
  #include "DNA_space_types.h"
  #include "DNA_userdef_types.h"
++#include "DNA_vec_types.h"
  #include "DNA_view3d_types.h"
  
  #include "BKE_global.h"
@@@ -57,6 -57,6 +58,7 @@@
  #include "BIF_gl.h"
  #include "BIF_glutil.h"
  #include "BIF_butspace.h"
++#include "BIF_editview.h"
  #include "BIF_graphics.h"
  #include "BIF_interface.h"
  #include "BIF_mywindow.h"
@@@ -662,7 -763,7 +664,14 @@@ void gpencil_delete_menu (void
  /* ---------- 'Globals' and Defines ----------------- */
  
  /* maximum sizes of gp-session buffer */
--#define GP_STROKE_BUFFER_MAX  500     
++#define GP_STROKE_BUFFER_MAX  5000
++
++/* Hardcoded sensitivity thresholds... */
++// TODO: one day, these might be added to the UI if it is necessary
++      /* minimum number of pixels mouse should move before new point created */
++#define MIN_MANHATTEN_PX              3       
++      /* minimum length of new segment before new point can be added */
++#define MIN_EUCLIDEAN_PX              20
  
  /* ------ */
  
@@@ -676,7 -777,7 +685,7 @@@ typedef struct tGPsdata 
        bGPDframe *gpf;         /* frame we're working on */
        
        short status;           /* current status of painting */
--      short paintmode;        /* mode for painting (L_MOUSE or R_MOUSE for now) */
++      short paintmode;        /* mode for painting */
  } tGPsdata;
  
  /* values for tGPsdata->status */
@@@ -686,6 -787,6 +695,12 @@@ enum 
        GP_STATUS_DONE                  /* painting done */
  };
  
++/* values for tGPsdata->paintmode */
++enum {
++      GP_PAINTMODE_DRAW = 0,
++      GP_PAINTMODE_ERASER
++};
++
  /* Return flags for adding points to stroke buffer */
  enum {
        GP_STROKEADD_INVALID    = -2,           /* error occurred - insufficient info to do so */
@@@ -703,9 -804,9 +718,9 @@@ static void gp_session_validatebuffer (
        
        /* clear memory of buffer (or allocate it if starting a new session) */
        if (gpd->sbuffer)
--              memset(gpd->sbuffer, 0, sizeof(bGPDspoint)*GP_STROKE_BUFFER_MAX);
++              memset(gpd->sbuffer, 0, sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX);
        else
--              gpd->sbuffer= MEM_callocN(sizeof(bGPDspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
++              gpd->sbuffer= MEM_callocN(sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
        
        /* reset indices */
        gpd->sbuffer_size = 0;
@@@ -843,6 -944,6 +858,25 @@@ static void gp_session_cleanup (tGPsdat
        gpd->sbuffer_sflag= 0;
  }
  
++/* check if the current mouse position is suitable for adding a new point */
++static short gp_stroke_filtermval (tGPsdata *p, short mval[2], short pmval[2])
++{
++      short dx= abs(mval[0] - pmval[0]);
++      short dy= abs(mval[1] - pmval[1]);
++      
++      /* check if mouse moved at least certain distance on both axes (best case) */
++      if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
++              return 1;
++      
++      /* check if the distance since the last point is significant enough */
++      else if (sqrt(dx*dx + dy*dy) > MIN_EUCLIDEAN_PX)
++              return 1;
++      
++      /* mouse 'didn't move' */
++      else
++              return 0;
++}
++
  /* convert screen-coordinates to buffer-coordinates */
  static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[])
  {
  }
  
  /* add current stroke-point to buffer (returns whether point was successfully added) */
--static short gp_stroke_addpoint (tGPsdata *p, short mval[], float pressure)
++static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure)
  {
        bGPdata *gpd= p->gpd;
--      bGPDspoint *pt;
++      tGPspoint *pt;
        
        /* check if still room in buffer */
        if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
                return GP_STROKEADD_OVERFLOW;
        
--      
        /* get pointer to destination point */
--      pt= gpd->sbuffer + gpd->sbuffer_size;
--      
--      /* convert screen-coordinates to appropriate coordinates (and store them) */
--      gp_stroke_convertcoords(p, mval, &pt->x);
++      pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
        
--      /* store other settings */
++      /* store settings */
++      pt->x= mval[0];
++      pt->y= mval[1];
++      pt->xf= (float)mval[0];
++      pt->yf= (float)mval[0];
        pt->pressure= pressure;
        
        /* increment counters */
                return GP_STROKEADD_NORMAL;
  }
  
--/* smooth a stroke (in buffer) before storing it */
--static void gp_stroke_smooth (tGPsdata *p)
--{
--      bGPdata *gpd= p->gpd;
--      int i=0, cmx=gpd->sbuffer_size;
--      
--      /* don't try if less than 2 points in buffer */
--      if ((cmx <= 2) || (gpd->sbuffer == NULL))
--              return;
--      
--      /* apply weighting-average (note doing this along path sequentially does introduce slight error) */
--      for (i=0; i < gpd->sbuffer_size; i++) {
--              bGPDspoint *pc= (gpd->sbuffer + i);
--              bGPDspoint *pb= (i-1 > 0)?(pc-1):(pc);
--              bGPDspoint *pa= (i-2 > 0)?(pc-2):(pb);
--              bGPDspoint *pd= (i+1 < cmx)?(pc+1):(pc);
--              bGPDspoint *pe= (i+2 < cmx)?(pc+2):(pd);
--              
--              pc->x= (0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x);
--              pc->y= (0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y);
--      }
--}
--
  /* make a new stroke from the buffer data */
  static void gp_stroke_newfrombuffer (tGPsdata *p)
  {
        bGPdata *gpd= p->gpd;
        bGPDstroke *gps;
--      bGPDspoint *pt, *ptc;
++      bGPDspoint *pt;
++      tGPspoint *ptc;
        int i, totelem;
        
        /* get total number of points to allocate space for */
        
        /* copy points from the buffer to the stroke */
        for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) {
--              memcpy(pt, ptc, sizeof(bGPDspoint));
++              /* convert screen-coordinates to appropriate coordinates (and store them) */
++              gp_stroke_convertcoords(p, &ptc->x, &pt->x);
++              
++              /* copy pressure */
++              pt->pressure= ptc->pressure;
++              
                pt++;
        }
        
        BLI_addtail(&p->gpf->strokes, gps);
  }
  
++/* --- 'Eraser' for 'Paint' Tool ------ */
++/* User should draw 'circles' around the parts of the sketches they wish to 
++ * delete instead of drawing squiggles over existing lines. This should be 
++ * easier to manage than if it was done otherwise.
++ */
++
++/* convert gp-buffer stroke into mouse-coordinates array */
++static short (*gp_stroke_eraser_2mco (bGPdata *gpd))[2]
++{
++      tGPspoint *pt;
++      short (*mcoords)[2]; 
++      int i;
++      
++      /* allocate memory for coordinates array */
++      mcoords= MEM_mallocN(sizeof(*mcoords)*gpd->sbuffer_size,"gp_buf_mcords");
++      
++      /* copy coordinates */
++      for (pt=gpd->sbuffer, i=0; i < gpd->sbuffer_size; i++, pt++) {
++              mcoords[i][0]= pt->x;
++              mcoords[i][1]= pt->y;
++      }
++      
++      /* return */
++      return mcoords;
++}
++
++/* eraser tool - remove segment from stroke/split stroke (after lasso inside) */
++static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i)
++{
++      bGPDspoint *pt_tmp= gps->points;
++      bGPDstroke *gsn = NULL;
++
++      /* if stroke only had two points, get rid of stroke */
++      if (gps->totpoints == 2) {
++              /* free stroke points, then stroke */
++              MEM_freeN(pt_tmp);
++              BLI_freelinkN(&gpf->strokes, gps);
++              
++              /* nothing left in stroke, so stop */
++              return 1;
++      }
++
++      /* if last segment, just remove segment from the stroke */
++      else if (i == gps->totpoints - 2) {
++              /* allocate new points array, and assign most of the old stroke there */
++              gps->totpoints--;
++              gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
++              memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints);
++              
++              /* free temp buffer */
++              MEM_freeN(pt_tmp);
++              
++              /* nothing left in stroke, so stop */
++              return 1;
++      }
++
++      /* if first segment, just remove segment from the stroke */
++      else if (i == 0) {
++              /* allocate new points array, and assign most of the old stroke there */
++              gps->totpoints--;
++              gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
++              memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints);
++              
++              /* free temp buffer */
++              MEM_freeN(pt_tmp);
++              
++              /* no break here, as there might still be stuff to remove in this stroke */
++              return 0;
++      }
++
++      /* segment occurs in 'middle' of stroke, so split */
++      else {
++              /* duplicate stroke, and assign 'later' data to that stroke */
++              gsn= MEM_dupallocN(gps);
++              gsn->prev= gsn->next= NULL;
++              BLI_insertlinkafter(&gpf->strokes, gps, gsn);
++              
++              gsn->totpoints= gps->totpoints - i;
++              gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points");
++              memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints);
++              
++              /* adjust existing stroke  */
++              gps->totpoints= i;
++              gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
++              memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i);
++              
++              /* free temp buffer */
++              MEM_freeN(pt_tmp);
++              
++              /* nothing left in stroke, so stop */
++              return 1;
++      }
++}
++
++/* eraser tool - evaluation per stroke */
++static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short moves, rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
++{
++      bGPDspoint *pt1, *pt2;
++      short x0=0, y0=0, x1=0, y1=0;
++      short xyval[2];
++      int i;
++      
++      if (gps->totpoints == 0) {
++              /* just free stroke */
++              if (gps->points) 
++                      MEM_freeN(gps->points);
++              BLI_freelinkN(&gpf->strokes, gps);
++      }
++      else if (gps->totpoints == 1) {
++              /* get coordinates */
++              if (gps->flag & GP_STROKE_3DSPACE) {
++                      // FIXME: this may not be the correct correction
++                      project_short(&gps->points->x, xyval);
++                      x0= xyval[0];
++                      x1= xyval[1];
++              }
++              else if (gps->flag & GP_STROKE_2DSPACE) {                       
++                      ipoco_to_areaco_noclip(p->v2d, &gps->points->x, xyval);
++                      x0= xyval[0];
++                      y0= xyval[1];
++              }
++              else {
++                      x0= (gps->points->x / 1000 * p->sa->winx);
++                      y0= (gps->points->y / 1000 * p->sa->winy);
++              }
++              
++              /* do boundbox check first */
++              if (BLI_in_rcti(rect, x0, y0)) {
++                      /* only check if point is inside */
++                      if (lasso_inside(mcoords, moves, x0, y0)) {
++                              /* free stroke */
++                              MEM_freeN(gps->points);
++                              BLI_freelinkN(&gpf->strokes, gps);
++                      }
++              }
++      }
++      else {  
++              /* loop over the points in the stroke, checking for intersections 
++               *      - an intersection will require the stroke to be split
++               */
++              for (i=0; (i+1) < gps->totpoints; i++) {
++                      /* get points to work with */
++                      pt1= gps->points + i;
++                      pt2= gps->points + i + 1;
++                      
++                      /* get coordinates */
++                      if (gps->flag & GP_STROKE_3DSPACE) {
++                              // FIXME: may not be correct correction
++                              project_short(&gps->points->x, xyval);
++                              x0= xyval[0];
++                              x1= xyval[1];
++                      }
++                      else if (gps->flag & GP_STROKE_2DSPACE) {
++                              ipoco_to_areaco_noclip(p->v2d, &pt1->x, xyval);
++                              x0= xyval[0];
++                              y0= xyval[1];
++                              
++                              ipoco_to_areaco_noclip(p->v2d, &pt2->x, xyval);
++                              x1= xyval[0];
++                              y1= xyval[1];
++                      }
++                      else {
++                              x0= (pt1->x / 1000 * p->sa->winx);
++                              y0= (pt1->y / 1000 * p->sa->winy);
++                              x1= (pt2->x / 1000 * p->sa->winx);
++                              y1= (pt2->y / 1000 * p->sa->winy);
++                      }
++                      
++                      /* check that point segment of the boundbox of the eraser stroke */
++                      if (BLI_in_rcti(rect, x0, y0) || BLI_in_rcti(rect, x1, y1)) {
++                              /* check if point segment of stroke had anything to do with
++                               * eraser region  (either within stroke painted, or on its lines)
++                               *      - this assumes that linewidth is irrelevant
++                               *      - handled using the lasso-select checking code
++                               */
++                              if (lasso_inside_edge(mcoords, moves, x0, y0, x1, x1)) {
++                                      /* if function returns true, break this loop (as no more point to check) */
++                                      if (gp_stroke_eraser_splitdel(gpf, gps, i))
++                                              break;
++                              }
++                      }
++              }
++      }
++}
++
++/* -------- */
++
++/* erase strokes which fall under the eraser strokes */
++static void gp_stroke_doeraser (tGPsdata *p)
++{
++      bGPdata *gpd= p->gpd;
++      bGPDframe *gpf= p->gpf;
++      bGPDstroke *gps, *gpn;
++      short (*mcoords)[2];
++      rcti rect;
++      
++      /* get buffer-stroke coordinates as shorts array, and then get bounding box */
++      mcoords= gp_stroke_eraser_2mco(gpd);
++      lasso_select_boundbox(&rect, mcoords, gpd->sbuffer_size);
++      
++      /* loop over strokes, checking segments for intersections */
++      for (gps= gpf->strokes.first; gps; gps= gpn) {
++              gpn= gps->next;
++              gp_stroke_eraser_dostroke(p, mcoords, gpd->sbuffer_size, &rect, gpf, gps);
++      }
++      
++      /* free mcoords array */
++      MEM_freeN(mcoords);
++}
++
  /* ---------- 'Paint' Tool ------------ */
  
  /* init new stroke */
- static void gp_paint_initstroke (tGPsdata *p, short mousebutton)
 -static void gp_paint_initstroke (tGPsdata *p)
++static void gp_paint_initstroke (tGPsdata *p, short paintmode)
  {     
        /* get active layer (or add a new one if non-existent) */
        p->gpl= gpencil_layer_getactive(p->gpd);
        }
        else
                p->gpf->flag |= GP_FRAME_PAINT;
 -              
 -      /* check if points will need to be made in 3d-space */
 +      
-       /* set 'eraser' for this stroke if using eraser or right-mouse in action */
-       if ( get_activedevice() == 2 || (mousebutton & R_MOUSE) ) {
++      /* set 'eraser' for this stroke if using eraser */
++      p->paintmode= paintmode;
++      if (p->paintmode == GP_PAINTMODE_ERASER)
 +              p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
-               
-               // for now: eraser isn't ready for prime-time yet, so no painting available here yet
-               p->status= GP_STATUS_ERROR;
-               return;
-       }
 +      
 +      /* check if points will need to be made in view-aligned space */
        if (p->gpd->flag & GP_DATA_VIEWALIGN) {
                switch (p->sa->spacetype) {
                        case SPACE_VIEW3D:
  /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
  static void gp_paint_strokeend (tGPsdata *p)
  {
--      /* sanitize stroke-points in buffer */
--      gp_stroke_smooth(p);
--      
--      /* transfer stroke to frame */
--      gp_stroke_newfrombuffer(p);
++      /* check if doing eraser or not */
++      if (p->gpd->sbuffer_sflag & GP_STROKE_ERASER) {
++              /* get rid of relevant sections of strokes */
++              gp_stroke_doeraser(p);
++      }
++      else {
++              /* transfer stroke to frame */
++              gp_stroke_newfrombuffer(p);
++      }
        
        /* clean up buffer now */
        gp_session_validatebuffer(p);
@@@ -1065,7 -1157,7 +1292,7 @@@ static void gp_paint_cleanup (tGPsdata 
  /* -------- */
  
  /* main call to paint a new stroke */
--short gpencil_paint (short mousebutton)
++short gpencil_paint (short mousebutton, short paintmode)
  {
        tGPsdata p;
        short prevmval[2], mval[2];
                gp_session_cleanup(&p);
                return 0;
        }
-       gp_paint_initstroke(&p, mousebutton);
 -      gp_paint_initstroke(&p);
++      gp_paint_initstroke(&p, paintmode);
        if (p.status == GP_STATUS_ERROR) {
                gp_session_cleanup(&p);
                return 0;
                pressure = get_pressure();
                
                /* only add current point to buffer if mouse moved (otherwise wait until it does) */
--              if ((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
++              if (gp_stroke_filtermval(&p, mval, prevmval)) {
                        /* try to add point */
                        ok= gp_stroke_addpoint(&p, mval, pressure);
                        
        setcursor_space(p.sa->spacetype, CURSOR_STD);
        
        /* check size of buffer before cleanup, to determine if anything happened here */
--      ok= p.gpd->sbuffer_size;
++      if (paintmode == GP_PAINTMODE_ERASER)
++              ok= (p.gpd->sbuffer_size > 1);
++      else
++              ok= p.gpd->sbuffer_size;
        
        /* cleanup */
        gp_paint_cleanup(&p);
  /* All event (loops) handling checking if stroke drawing should be initiated
   * should call this function.
   */
- short gpencil_do_paint (ScrArea *sa, short mousebutton)
 -short gpencil_do_paint (ScrArea *sa)
++short gpencil_do_paint (ScrArea *sa, short mbut)
  {
        bGPdata *gpd = gpencil_data_getactive(sa);
 -      short mousebutton = L_MOUSE; /* for now, this is always on L_MOUSE*/
        short retval= 0;
        
        /* check if possible to do painting */
        if (gpd == NULL) 
                return 0;
        
--      /* currently, we will only paint if:
++      /* currently, we will only 'paint' if:
         *      1. draw-mode on gpd is set (for accessibility reasons)
         *              (single 'dots' are only available via this method)
         *      2. if shift-modifier is held + lmb -> 'quick paint'
++       *
++       *      OR
++       * 
++       * draw eraser stroke if:
++       *      1. using the eraser on a tablet
++       *      2. draw-mode on gpd is set (for accessiblity reasons)
++       *              (eraser is mapped to right-mouse)
++       *      3. Alt + 'select' mouse-button
++       *              i.e.  if LMB = select: Alt-LMB
++       *                        if RMB = select: Alt-RMB
         */
--      if (gpd->flag & GP_DATA_EDITPAINT) {
--              /* try to paint */
--              retval = gpencil_paint(mousebutton);
++      if (get_activedevice() == 2) {
++              /* eraser on a tablet - always try to erase strokes */
++              retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
 +      }
-       else if (!(gpd->flag & GP_DATA_LMBPLOCK) && (G.qual == LR_SHIFTKEY)) {
-               /* try to paint */
-               retval = gpencil_paint(mousebutton);
++      else if (gpd->flag & GP_DATA_EDITPAINT) {
++              /* try to paint/erase */
++              if (mbut == L_MOUSE)
++                      retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW);
++              else if (mbut == R_MOUSE)
++                      retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
+       }
 -      else if (G.qual == LR_SHIFTKEY) {
 -              /* try to paint */
 -              retval = gpencil_paint(mousebutton);
++      else if (!(gpd->flag & GP_DATA_LMBPLOCK)) {
++              /* try to paint/erase as not locked */
++              if ((G.qual == LR_SHIFTKEY) && (mbut == L_MOUSE)) {
++                      retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW);
++              }
++              else if (G.qual == LR_ALTKEY) {
++                      if ((U.flag & USER_LMOUSESELECT) && (mbut == L_MOUSE))
++                              retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
++                      else if (!(U.flag & USER_LMOUSESELECT) && (mbut == R_MOUSE))
++                              retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
++              }
        }
        
        /* return result of trying to paint */
index dac7c7bc2c6f390c500edb0833f96f82a8d943c3,dac7c7bc2c6f390c500edb0833f96f82a8d943c3..c14e88770f9f11b4b1ccef75383d72e4b946c1e3
@@@ -1078,9 -1078,9 +1078,9 @@@ static uiBlock *info_filemenu(void *arg
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Screenshot Subwindow|Ctrl F3",                   0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 24, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Screenshot All|Ctrl Shift F3",                   0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 25, "");
  #if GAMEBLENDER == 1
--      uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Runtime...",                        0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 22, "");
++      uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Game As Runtime...",                        0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 22, "");
  #ifdef _WIN32
--      uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Dynamic Runtime...",                0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 23, "");
++//     uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Dynamic Runtime...",               0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 23, "");
  #endif
  #endif
        uiDefBut(block, SEPR, 0, "",                                    0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
index 15caf325ec60ad4b32329e45e63d09dffb6a57cf,15caf325ec60ad4b32329e45e63d09dffb6a57cf..59d542e72ec01e9222fe0537a9e36f9172128432
@@@ -970,7 -970,7 +970,7 @@@ static char *ipo_modeselect_pup(void
        if(ob && ob->type==OB_LAMP)
                str += sprintf(str,formatstring, "Lamp",ID_LA, ICON_LAMP);
  
--      if(ob && give_current_texture(ob, ob->actcol))
++      if((ob && give_current_texture(ob, ob->actcol))||(give_current_world_texture()))
                str += sprintf(str,formatstring, "Texture",ID_TE, ICON_TEXTURE);
  
        if(ob){
index 71bf0cd9bd4a4b21f19aeaf78bb9728221043e0c,71bf0cd9bd4a4b21f19aeaf78bb9728221043e0c..0b48db461e6adfd7bbee614084babd33b148c737
@@@ -2196,6 -2196,6 +2196,7 @@@ static uiBlock *view3d_edit_object_copy
        
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mass|Ctrl C, 7",                 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Damping|Ctrl C, 8",                      0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
++      uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "All Physical Attributes|Ctrl C, 11",                     0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Properties|Ctrl C, 9",                   0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Logic Bricks|Ctrl C, 10",                        0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Protected Transform |Ctrl C",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 29, "");
index 18e596abcc7ef68d6907b2e91eac6caad1a619b2,ba8649eaa8654eeff83075c032b33fc0dd5b35b8..e7b5b1769794c278f502bdd807c172baf47e7794
@@@ -532,7 -532,7 +532,7 @@@ static int ui_but_copy_paste(uiBut *but
                        /* give butfunc the original text too */
                        /* feature used for bone renaming, channels, etc */
                        if(but->func_arg2==NULL) {
--                              strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
++                              strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
                                but->func_arg2= backstr;
                        }
                        strncpy(but->poin, but_copypaste_str, but->max);
index 4d84672185a9746cb4ab6fdfa5324ecda997c46a,4d84672185a9746cb4ab6fdfa5324ecda997c46a..60f569ecf0ea8ffa11c90be78db483718d164920
@@@ -1281,9 -1281,9 +1281,9 @@@ static int meshdeform_inside_cage(MeshD
                outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f)*MESHDEFORM_OFFSET[i][1];
                outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f)*MESHDEFORM_OFFSET[i][2];
  
++              VECCOPY(start, co);
                VECSUB(dir, outside, start);
                Normalize(dir);
--              VECCOPY(start, co);
                
                isect = meshdeform_ray_tree_intersect(mdb, start, outside);
                if(isect && !isect->facing)
index a8409c43b902d8d283045a38a0f252ecee8774c8,683b06aafc41d3ab90bf951279bea4445678cb31..3f328a0cfb2303d72cf2802a2c1cc0d774cf6dbe
@@@ -3654,7 -3631,7 +3654,7 @@@ static void outliner_draw_restrictbuts(
        uiBut *bt;
        TreeElement *te;
        TreeStoreElem *tselem;
--      Object *ob;
++      Object *ob = NULL;
        
        for(te= lb->first; te; te= te->next) {
                tselem= TREESTORE(te);
                        /* objects have toggle-able restriction flags */
                        if(tselem->type==0 && te->idcode==ID_OB) {
                                ob = (Object *)tselem->id;
--
++                              
                                uiBlockSetEmboss(block, UI_EMBOSSN);
                                bt= uiDefIconButBitS(block, ICONTOG, OB_RESTRICT_VIEW, REDRAWALL, ICON_RESTRICT_VIEW_OFF, 
                                                (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(ob->restrictflag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
                                
                                uiBlockSetEmboss(block, UI_EMBOSS);
                        }
-                               /*
-                               bt= uiDefIconButBitI(block, ICONTOGN, eModifierMode_Editmode, REDRAWALL, VICON_EDIT, 
-                                               (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_SELECTX, te->ys, 17, OL_H-1, &(md->mode), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
-                               uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL);
-                               uiButSetFlag(bt, UI_NO_HILITE);
-                               */
-                               
 +                      else if(tselem->type==TSE_MODIFIER)  {
 +                              ModifierData *md= (ModifierData *)te->directdata;
 +                              ob = (Object *)tselem->id;
 +                              
 +                              uiBlockSetEmboss(block, UI_EMBOSSN);
 +                              bt= uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, REDRAWALL, ICON_RESTRICT_VIEW_OFF, 
 +                                              (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
 +                              uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL);
 +                              uiButSetFlag(bt, UI_NO_HILITE);
 +                              
-                               
 +                              bt= uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, REDRAWALL, ICON_RESTRICT_RENDER_OFF, 
 +                                              (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_RENDERX, te->ys, 17, OL_H-1, &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability");
 +                              uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL);
 +                              uiButSetFlag(bt, UI_NO_HILITE);
 +                      }
 +                      else if(tselem->type==TSE_POSE_CHANNEL)  {
 +                              bPoseChannel *pchan= (bPoseChannel *)te->directdata;
 +                              Bone *bone = pchan->bone;
-                               uiButSetFunc(bt, restrictbutton_bone_cb, ob, NULL);
++
 +                              uiBlockSetEmboss(block, UI_EMBOSSN);
 +                              bt= uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, REDRAWALL, ICON_RESTRICT_VIEW_OFF, 
 +                                              (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
-                               
++                              uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL);
 +                              uiButSetFlag(bt, UI_NO_HILITE);
 +                      }
 +                      else if(tselem->type==TSE_EBONE)  {
 +                              EditBone *ebone= (EditBone *)te->directdata;
-                               uiButSetFunc(bt, restrictbutton_bone_cb, ob, NULL);
++
 +                              uiBlockSetEmboss(block, UI_EMBOSSN);
 +                              bt= uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, REDRAWALL, ICON_RESTRICT_VIEW_OFF, 
 +                                              (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
++                              uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL);
 +                              uiButSetFlag(bt, UI_NO_HILITE);
 +                      }
                }
                
                if((tselem->flag & TSE_CLOSED)==0) outliner_draw_restrictbuts(block, soops, &te->subtree);
index cc08bf53a72a439c7ea4f5ae4bff13304015a5d5,cc08bf53a72a439c7ea4f5ae4bff13304015a5d5..b054b4350020e5a7ed69ccbf720f290b84507378
@@@ -180,27 -180,27 +180,26 @@@ bPoseChannel *get_active_posechannel (O
        return NULL;
  }
  
--/* if a selected or active bone is protected, throw error and return 1 */
++/* if a selected or active bone is protected, throw error (oonly if warn==1) and return 1 */
  /* only_selected==1 : the active bone is allowed to be protected */
--static int pose_has_protected_selected(Object *ob, int only_selected)
++static short pose_has_protected_selected(Object *ob, short only_selected, short warn)
  {
--      
        /* check protection */
--      if(ob->proxy) {
++      if (ob->proxy) {
                bPoseChannel *pchan;
                bArmature *arm= ob->data;
                
--              for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
--                      if(pchan->bone && (pchan->bone->layer & arm->layer)) {
--                              if(pchan->bone->layer & arm->layer_protected) {
--                                      if(only_selected && (pchan->bone->flag & BONE_ACTIVE));
--                                      else if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) 
++              for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
++                      if (pchan->bone && (pchan->bone->layer & arm->layer)) {
++                              if (pchan->bone->layer & arm->layer_protected) {
++                                      if (only_selected && (pchan->bone->flag & BONE_ACTIVE));
++                                      else if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) 
                                           break;
                                }
                        }
                }
--              if(pchan) {
--                      error("Cannot change Proxy protected bones");
++              if (pchan) {
++                      if (warn) error("Cannot change Proxy protected bones");
                        return 1;
                }
        }
@@@ -540,7 -540,7 +539,7 @@@ void pose_clear_IK(void
        if(!ob && !ob->pose) return;
        if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
        
--      if(pose_has_protected_selected(ob, 0))
++      if(pose_has_protected_selected(ob, 0, 1))
                return;
        
        if(okee("Remove IK constraint(s)")==0) return;
@@@ -581,7 -581,7 +580,7 @@@ void pose_clear_constraints(void
        if(!ob && !ob->pose) return;
        if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
        
--      if(pose_has_protected_selected(ob, 0))
++      if(pose_has_protected_selected(ob, 0, 1))
                return;
        
        if(okee("Remove Constraints")==0) return;
@@@ -612,38 -612,38 +611,49 @@@ void pose_copy_menu(void
        Object *ob= OBACT;
        bArmature *arm= ob->data;
        bPoseChannel *pchan, *pchanact;
--      short nr;
++      short nr=0;
        int i=0;
        
        /* paranoia checks */
--      if(!ob && !ob->pose) return;
--      if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
++      if (ELEM(NULL, ob, ob->pose)) return;
++      if ((ob==G.obedit) || (ob->flag & OB_POSEMODE)==0) return;
        
        /* find active */
--      for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
--              if(pchan->bone->flag & BONE_ACTIVE) break;
++      for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
++              if (pchan->bone->flag & BONE_ACTIVE) 
++                      break;
        }
        
--      if(pchan==NULL) return;
--      
--      if(pose_has_protected_selected(ob, 1))
--              return;
--
++      if (pchan==NULL) return;
        pchanact= pchan;
        
--      i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
--      if (i<25)
--              nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
--      else
--              nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
++      /* if proxy-protected bones selected, some things (such as locks + displays) shouldn't be changable, 
++       * but for constraints (just add local constraints)
++       */
++      if (pose_has_protected_selected(ob, 1, 0)) {
++              i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
++              if (i < 25)
++                      nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5");
++              else
++                      nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4");
++      }
++      else {
++              i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
++              if (i < 25)
++                      nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
++              else
++                      nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
++      }
        
--      if(nr==-1) return;
--      if(nr!=5)  {
--              for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
--                      if(     (arm->layer & pchan->bone->layer) &&
--                              (pchan->bone->flag & BONE_SELECTED) &&
--                              (pchan!=pchanact)
--                      ) {
++      if (nr <= 0) 
++              return;
++      
++      if (nr != 5)  {
++              for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
++                      if ( (arm->layer & pchan->bone->layer) &&
++                               (pchan->bone->flag & BONE_SELECTED) &&
++                               (pchan != pchanact) ) 
++                      {
                                switch (nr) {
                                        case 1: /* Local Location */
                                                VECCOPY(pchan->loc, pchanact->loc);
                                                break;
                                        case 4: /* All Constraints */
                                        {
--                                              free_constraints(&pchan->constraints);
--                                              copy_constraints(&pchan->constraints, &pchanact->constraints);
--                                              pchan->constflag = pchanact->constflag;
++                                              ListBase tmp_constraints = {NULL, NULL};
                                                
--                                              if (ob->pose) {
--                                                      ob->pose->flag |= POSE_RECALC;
++                                              /* copy constraints to tmpbase and apply 'local' tags before 
++                                               * appending to list of constraints for this channel
++                                               */
++                                              copy_constraints(&tmp_constraints, &pchanact->constraints);
++                                              if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
++                                                      bConstraint *con;
++                                                      
++                                                      /* add proxy-local tags */
++                                                      for (con= tmp_constraints.first; con; con= con->next)
++                                                              con->flag |= CONSTRAINT_PROXY_LOCAL;
                                                }
++                                              addlisttolist(&pchan->constraints, &tmp_constraints);
++                                              
++                                              /* update flags (need to add here, not just copy) */
++                                              pchan->constflag |= pchanact->constflag;
++                                              
++                                              if (ob->pose)
++                                                      ob->pose->flag |= POSE_RECALC;
                                        }
                                                break;
                                        case 6: /* Transform Locks */
                                }
                        }
                }
--      } else { /* constraints, optional */
++      } 
++      else { /* constraints, optional (note: max we can have is 24 constraints) */
                bConstraint *con, *con_back;
                int const_toggle[24];
--              ListBase const_copy={0, 0};
++              ListBase const_copy = {NULL, NULL};
                
--              duplicatelist (&const_copy, &(pchanact->constraints));
++              duplicatelist(&const_copy, &(pchanact->constraints));
                
                /* build the puplist of constraints */
                for (con = pchanact->constraints.first, i=0; con; con=con->next, i++){
                
                /* now build a new listbase from the options selected */
                for (i=0, con=const_copy.first; con; i++) {
++                      /* if not selected, free/remove it from the list */
                        if (!const_toggle[i]) {
                                con_back= con->next;
                                BLI_freelinkN(&const_copy, con);
                                con= con_back;
--                      } else {
++                      } 
++                      else
                                con= con->next;
--                      }
                }
                
                /* Copy the temo listbase to the selected posebones */
--              for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
--                      if(     (arm->layer & pchan->bone->layer) &&
--                              (pchan->bone->flag & BONE_SELECTED) &&
--                              (pchan!=pchanact)
--                      ) {
--                              free_constraints(&pchan->constraints);
--                              copy_constraints(&pchan->constraints, &const_copy);
--                              pchan->constflag = pchanact->constflag;
++              for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
++                      if ( (arm->layer & pchan->bone->layer) &&
++                               (pchan->bone->flag & BONE_SELECTED) &&
++                               (pchan!=pchanact) ) 
++                      {
++                              ListBase tmp_constraints = {NULL, NULL};
++                              
++                              /* copy constraints to tmpbase and apply 'local' tags before 
++                               * appending to list of constraints for this channel
++                               */
++                              copy_constraints(&tmp_constraints, &const_copy);
++                              if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
++                                      bConstraint *con;
++                                      
++                                      /* add proxy-local tags */
++                                      for (con= tmp_constraints.first; con; con= con->next)
++                                              con->flag |= CONSTRAINT_PROXY_LOCAL;
++                              }
++                              addlisttolist(&pchan->constraints, &tmp_constraints);
++                              
++                              /* update flags (need to add here, not just copy) */
++                              pchan->constflag |= pchanact->constflag;
                        }
                }
                BLI_freelistN(&const_copy);
                update_pose_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
                
--              if (ob->pose) {
++              if (ob->pose)
                        ob->pose->flag |= POSE_RECALC;
--              }
        }
        
        DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);   // and all its relations
@@@ -808,7 -808,7 +846,7 @@@ void paste_posebuf (int flip
        
        /*
        // disabled until protected bones in proxies follow the rules everywhere else!
--      if(pose_has_protected_selected(ob, 1))
++      if(pose_has_protected_selected(ob, 1, 1))
                return;
        */
        
@@@ -1249,7 -1249,7 +1287,7 @@@ void pose_flip_names(void
        if(!ob && !ob->pose) return;
        if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
        
--      if(pose_has_protected_selected(ob, 0))
++      if(pose_has_protected_selected(ob, 0, 1))
                return;
        
        for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
@@@ -1282,7 -1282,7 +1320,7 @@@ void pose_autoside_names(short axis
        if (ELEM(NULL, ob, ob->pose)) return;
        if (ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
        
--      if (pose_has_protected_selected(ob, 0))
++      if (pose_has_protected_selected(ob, 0, 1))
                return;
        
        for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
@@@ -1415,7 -1415,7 +1453,7 @@@ void pose_movetolayer(void
                /* pose-channel layers */
                bPoseChannel *pchan;
                
--              if (pose_has_protected_selected(ob, 0))
++              if (pose_has_protected_selected(ob, 0, 1))
                        return;
                
                for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
index 9426548dc38c952be12b74fdb1506facb9cb7deb,9426548dc38c952be12b74fdb1506facb9cb7deb..7e2ffc3ba63e9f76efb99516ec141748ccc0246f
@@@ -1473,8 -1473,8 +1473,8 @@@ static void input_preprocess(Sequence 
                dy = sy;
  
                if (seq->flag & SEQ_USE_TRANSFORM) {
--                      dx = seqrectx;
--                      dy = seqrecty;
++                      dx = G.scene->r.xsch;
++                      dy = G.scene->r.ysch;
                }
  
                if (c.top + c.bottom >= se->ibuf->y ||
index 454d50bd208f3bb0d4565c78d3e72066a82b1320,92efb477095fe300202eafe4f6b3f0209e73c4a8..c59faa3685331764749532af6ea93f032f4c9d9e
@@@ -5119,7 -5107,7 +5119,10 @@@ static void winqreadseqspace(ScrArea *s
                }       
        }
  
--      if(doredraw) scrarea_queue_winredraw(curarea);
++      if(doredraw) {
++              scrarea_queue_winredraw(curarea);
++              scrarea_queue_headredraw(curarea);
++      }
  }
  
  
index 706b079432cfb000b2e7ca178de36d3db1a8e1b8,706b079432cfb000b2e7ca178de36d3db1a8e1b8..8f83434e52873883e2031ac21dd49e4fe7a4c8e7
@@@ -1089,6 -1089,6 +1089,8 @@@ static void createTransArmatureVerts(Tr
                                        VECCOPY (td->center, td->iloc);
                                        td->loc= ebo->tail;
                                        td->flag= TD_SELECTED;
++                                      if (ebo->flag & BONE_EDITMODE_LOCKED)
++                                              td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
  
                                        Mat3CpyMat3(td->smtx, smtx);
                                        Mat3CpyMat3(td->mtx, mtx);
                                        VECCOPY (td->center, td->iloc);
                                        td->loc= ebo->head;
                                        td->flag= TD_SELECTED;
++                                      if (ebo->flag & BONE_EDITMODE_LOCKED)
++                                              td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
  
                                        Mat3CpyMat3(td->smtx, smtx);
                                        Mat3CpyMat3(td->mtx, mtx);
index 050360887b4d1f3a73d1ec0880d774b4805f2842,050360887b4d1f3a73d1ec0880d774b4805f2842..709879f142bb552fe23418453ceba66e1f716359
@@@ -170,6 -170,6 +170,13 @@@ static void stats_pose(View3D *v3d, bPo
        }
  }
  
++/* for editmode*/
++static void stats_editbone(View3D *v3d, EditBone *ebo)
++{
++      if (ebo->flag & BONE_EDITMODE_LOCKED)
++              protectflag_to_drawflags(OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE, &v3d->twdrawflag);
++}
++
  /* only counts the parent selection, and tags transform flag */
  /* bad call... should re-use method from transform_conversion once */
  static void count_bone_select(TransInfo *t, bArmature *arm, ListBase *lb, int do_it) 
@@@ -258,6 -258,6 +265,9 @@@ int calc_manipulator_stats(ScrArea *sa
                                                calc_tw_center(ebo->head);
                                                totsel++;
                                        }
++                                      if (ebo->flag & BONE_SELECTED) {
++                                              stats_editbone(v3d, ebo);
++                                      }
                                }
                        }
                }
index 9589f1e3e94c62da13f1f79af9830c5d7441a9ae,9589f1e3e94c62da13f1f79af9830c5d7441a9ae..e17b0f669778780d74c324381217681a5d995adf
@@@ -618,8 -618,8 +618,23 @@@ int main(int argc, char **argv
                                if (G.scene) {
                                        if (a < argc) {
                                                int frame= MIN2(MAXFRAME, MAX2(1, atoi(argv[a])));
++                                              int slink_flag= 0;
                                                Render *re= RE_NewRender(G.scene->id.name);
++
++                                              if (G.f & G_DOSCRIPTLINKS) {
++                                                      BPY_do_all_scripts(SCRIPT_RENDER);
++                                                      /* avoid FRAMECHANGED slink event
++                                                       * (should only be triggered in anims): */
++                                                      G.f &= ~G_DOSCRIPTLINKS;
++                                                      slink_flag= 1;
++                                              }
++
                                                RE_BlenderAnim(re, G.scene, frame, frame);
++
++                                              if (slink_flag) {
++                                                      G.f |= G_DOSCRIPTLINKS;
++                                                      BPY_do_all_scripts(SCRIPT_POSTRENDER);
++                                              }
                                        }
                                } else {
                                        printf("\nError: no blend loaded. cannot use '-f'.\n");
                        case 'a':
                                if (G.scene) {
                                        Render *re= RE_NewRender(G.scene->id.name);
++
++                                      if (G.f & G_DOSCRIPTLINKS)
++                                              BPY_do_all_scripts(SCRIPT_RENDER);
++
                                        RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
++
++                                      if (G.f & G_DOSCRIPTLINKS)
++                                              BPY_do_all_scripts(SCRIPT_POSTRENDER);
                                } else {
                                        printf("\nError: no blend loaded. cannot use '-a'.\n");
                                }
index ed6ea7c5f6ae6b2bc52b59cc2e6751ba70183a29,ed6ea7c5f6ae6b2bc52b59cc2e6751ba70183a29..da52be56d1b415525c83ad1cee11377a45abbb45
@@@ -170,6 -170,6 +170,7 @@@ void BL_RenderText(int mode,const char
  void DisableForText()
  {
        if(glIsEnabled(GL_BLEND)) glDisable(GL_BLEND);
++      if(glIsEnabled(GL_ALPHA_TEST)) glDisable(GL_ALPHA_TEST);
  
        if(glIsEnabled(GL_LIGHTING)) {
                glDisable(GL_LIGHTING);
diff --cc source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp
index d173b1c66d9827b12a0e3dfc80515c80c423fbb3,d173b1c66d9827b12a0e3dfc80515c80c423fbb3..0000000000000000000000000000000000000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,114 -1,114 +1,0 @@@
--/**
-- * $Id$
-- * ***** BEGIN GPL LICENSE BLOCK *****
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public License
-- * as published by the Free Software Foundation; either version 2
-- * of the License, or (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- * GNU General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, write to the Free Software Foundation,
-- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-- *
-- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
-- * All rights reserved.
-- *
-- * The Original Code is: all of this file.
-- *
-- * Contributor(s): none yet.
-- *
-- * ***** END GPL LICENSE BLOCK *****
-- */
--
--#include "KX_BlenderPolyMaterial.h"
--#include "BKE_mesh.h"
--
--#ifdef HAVE_CONFIG_H
--#include <config.h>
--#endif
--#if 0
--KX_BlenderPolyMaterial::KX_BlenderPolyMaterial(const STR_String &texname,
--                                                                                         bool ba,
--                                                                                         const STR_String& matname,
--                                                                                         int tile,
--                                                                                         int tilexrep,
--                                                                                         int tileyrep,
--                                                                                         int mode,
--                                                                                         bool transparant,
--                                                                                         bool zsort,
--                                                                                         int lightlayer,
--                                                                                         bool bIsTriangle,
--                                                                                         void* clientobject,
--                                                                                         struct MTFace* tface)
--              : RAS_IPolyMaterial(texname,
--                                                      false,
--                                                      matname,
--                                                      tile,
--                                                      tilexrep,
--                                                      tileyrep,
--                                                      mode,
--                                                      transparant,
--                                                      zsort,
--                                                      lightlayer,
--                                                      bIsTriangle,
--                                                      clientobject),
--              m_tface(tface)
--{
--}
--
--void KX_BlenderPolyMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const 
--{
--
--      
--      if (GetCachingInfo() != cachingInfo)
--      {
--              if (!cachingInfo)
--              {
--                      set_tpage(NULL);
--              }
--              cachingInfo = GetCachingInfo();
--
--              if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED))
--              {
--                      update_realtime_texture((struct MTFace*) m_tface, rasty->GetTime());
--                      set_tpage(m_tface);
--                      rasty->EnableTextures(true);
--              }
--              else
--              {
--                      set_tpage(NULL);
--                      rasty->EnableTextures(false);
--              }
--              
--              if(m_drawingmode & RAS_IRasterizer::KX_TWOSIDE)
--              {
--                      rasty->SetCullFace(false);
--              }
--              else
--              {
--                      rasty->SetCullFace(true);
--              }
--
--              if (m_drawingmode & RAS_IRasterizer::KX_LINES) {
--                      rasty->SetLines(true);
--              }
--              else {
--                      rasty->SetLines(false);
--              }
--      }
--
--      rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity);
--      rasty->SetShinyness(m_shininess);
--      rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0);
--}
--
--
--#endif
--
--
diff --cc source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h
index 35823b2125b3e54f21a43c1da7472c9e10a435b4,35823b2125b3e54f21a43c1da7472c9e10a435b4..0000000000000000000000000000000000000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,99 -1,99 +1,0 @@@
--/**
-- * $Id$
-- *
-- * ***** BEGIN GPL LICENSE BLOCK *****
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public License
-- * as published by the Free Software Foundation; either version 2
-- * of the License, or (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- * GNU General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, write to the Free Software Foundation,
-- * Inc., 59 Temple Place -