From fc0ac44e30a56c87c7cf39fe66f6b3178732f1b6 Mon Sep 17 00:00:00 2001
From: Normand Briere <nbriere@noware.ca>
Date: Sun, 01 Oct 2017 20:17:17 -0400
Subject: [PATCH] Klein + billboard + rigging "seuil"

---
 ObjEditor.java     |   80 ++++
 Grid.java          |    9 
 Bone.java          |    2 
 HiddenObject.java  |   39 ++
 Mocap.java         |    1 
 BiparamEditor.java |    4 
 Klein.java         |  200 ++++++++++++++
 cMesh.java         |    4 
 BoundaryRep.java   |  122 +++++++-
 CameraPane.java    |    3 
 GroupEditor.java   |  122 +++++++-
 cSpring.java       |    3 
 Object3D.java      |   49 +++
 KleinEditor.java   |  123 ++++++++
 BillboardNode.java |   54 +++
 15 files changed, 753 insertions(+), 62 deletions(-)

diff --git a/BillboardNode.java b/BillboardNode.java
new file mode 100644
index 0000000..ea1cb8e
--- /dev/null
+++ b/BillboardNode.java
@@ -0,0 +1,54 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/**
+ *
+ * @author nbriere
+ */
+public class BillboardNode extends Composite implements java.io.Serializable
+{
+    static final long serialVersionUID = 0;
+    
+    BillboardNode()
+    {
+        super("Billboard");
+        
+        toParent = LA.newMatrix();
+        fromParent = LA.newMatrix();
+    }
+    
+    cVector pos = new cVector();
+        
+    void draw(CameraPane display, Object3D /*Composite*/ root, boolean selected, boolean blocked)
+    {
+        cVector eye = display.eyeCamera.location;
+        
+        GlobalTransformInv();
+
+        pos.x = parent.globalTransform[3][0];
+        pos.y = parent.globalTransform[3][1];
+        pos.z = parent.globalTransform[3][2];
+        
+        pos.x -= eye.x;
+        pos.y -= eye.y;
+        pos.z -= eye.z;
+        
+        double angle = Math.atan2(pos.x, pos.z);
+        
+        LA.matIdentity(toParent);
+        LA.matIdentity(fromParent);
+        LA.matYRotate(toParent, angle);
+        LA.matYRotate(fromParent, -angle);
+        
+        super.draw(display, root, selected, blocked);
+    }
+    
+    Object3D deepCopy()
+    {
+            Composite comp = new BillboardNode();
+            deepCopySelf(comp);
+            return comp;
+    }
+}
diff --git a/BiparamEditor.java b/BiparamEditor.java
index 9598f9c..6fde80f 100644
--- a/BiparamEditor.java
+++ b/BiparamEditor.java
@@ -261,8 +261,8 @@
 	}
 	
     Biparam biparam;
-    JLabel uDivsLabel;
-    JLabel vDivsLabel;
+    //JLabel uDivsLabel;
+    //JLabel vDivsLabel;
     NumberSlider uDivsField;
     NumberSlider vDivsField;
     JCheckBox optionCB;
diff --git a/Bone.java b/Bone.java
index 5daf945..93c1188 100755
--- a/Bone.java
+++ b/Bone.java
@@ -26,7 +26,7 @@
  */
 
 import javax.media.j3d.*;
-import javax.vecmath.*;
+//import javax.vecmath.*;
 
 import java.util.*;
 
diff --git a/BoundaryRep.java b/BoundaryRep.java
index 7fc9789..9cf899c 100644
--- a/BoundaryRep.java
+++ b/BoundaryRep.java
@@ -497,10 +497,10 @@
         return dist2;
     }
     
-    static Vertex vertextemp = new Vertex();
-    static Vertex vertextemp2 = new Vertex();
+    static Vertex vertextemp = new Vertex(true);
+    static Vertex vertextemp2 = new Vertex(true);
     
-    static double SEUIL = 0.1; // 0.1 for rag doll; 0.07;
+    static double SEUIL = 0.1f; // 0.1 for rag doll; 0.07;
         
     // Compute weight of point w/r to this
     float ComputeWeight(Vertex v, double[][] toRoot, int k)
@@ -570,8 +570,10 @@
         
 if (dot > distmax)
     dot = distmax;
+    //return 0; // patch for strange behavior
 if (dot < -distmax)
     dot = -distmax;
+    //return 0; // patch for strange behavior
         
 //        v3 = GetVertex(this.startvertices[subsupport] + 16);
 //        
@@ -609,10 +611,12 @@
         
         float dist2 = (float)Distance2(v, v2, 1E10, toRoot, k);
         
-        if (dist2 >= 2 * SEUIL*SEUIL) // && !CameraPane.CROWD) // weightmode
+        double seuil = SEUIL * 2;
+        
+        if (dist2 >= 2 * seuil*seuil) // && !CameraPane.CROWD) // weightmode
             return 0;
         
-        dist2 /= 2 * SEUIL*SEUIL; // multiplied by two because center of support
+        dist2 /= 2 * seuil*seuil; // multiplied by two because center of support
                                   // could be far from closest point
         
 //        dist2 = Math.pow(dist2, 2);
@@ -946,7 +950,7 @@
         
         int nbsupports;
         
-        SEUIL = 0.1; // aout 2013
+        // sept 2017 SEUIL = 0.1; // aout 2013
         
         supports = InitConnections(other);
         
@@ -982,7 +986,7 @@
             
             int subsupports = 0;
             
-            SEUIL = 0.1; // aout 2013
+            // sept 2017 SEUIL = 0.1; // aout 2013
             
             while (subsupports == 0)
             {
@@ -1006,6 +1010,26 @@
 
                     vect.set(v);
                     vect.sub(vect2);
+                    
+//        vertextemp.x = other.averagepoints[c*3];
+//        vertextemp.y = other.averagepoints[c*3+1];
+//        vertextemp.z = other.averagepoints[c*3+2];
+//        
+//        Vertex v3 = vertextemp2;
+//        v3.x = other.extremepoints[c*3];
+//        v3.y = other.extremepoints[c*3+1];
+//        v3.z = other.extremepoints[c*3+2];
+//
+//        vect3.set(v3); // "X" axis apex
+//        vect3.sub(vertextemp); // origin (center)
+//        
+//        double distmax = vect3.length();
+//
+//        vect3.set(v2); // "X" axis apex
+//        vect3.sub(vertextemp); // origin (center)
+//        
+//        if (vect3.length() >= distmax)
+//            continue;
 
                     if (mindistance > vect.dot(vect))
                     {
@@ -1017,7 +1041,9 @@
 
                 subsupports = v.closestsupport==-1 ? 0 : supports[v.closestsupport].Length();
                 
-                SEUIL *= 2;
+                // previously for "contains", now for weights.
+                assert(subsupports > 0);
+                //SEUIL *= 2;
             }
             
             assert(subsupports > 0);
@@ -3776,10 +3802,19 @@
         for (int i = 0; i < VertexCount(); i++)
         {
             Vertex v = GetVertex(i);
+            
+            vertextemp.set(v);
+            
             //if (v.norm.x == 0 && v.norm.y == 0 && v.norm.z == 0)
             {
-                GenerateNormal(i, v);
-                SetVertex(v, i);
+                if (!GenerateNormal(i, vertextemp))
+                    continue;
+                
+                if (v.norm.dot(vertextemp.norm) < 0)
+                    vertextemp.norm.mul(-1);
+                    
+                if (v.norm.dot(vertextemp.norm) < 0.9)
+                    SetVertex(vertextemp, i);
             }
         }
 
@@ -3790,7 +3825,7 @@
     static cVector temp2 = new cVector();
     static cVector temp3 = new cVector();
 
-    void GenerateNormal(int index, Vertex v)
+    boolean GenerateNormal(int index, Vertex v)
     {
         //System.out.println("Old normal = " + v.norm);
         LA.setVector(v.norm, 0, 0, 0);
@@ -3819,6 +3854,10 @@
                 LA.vecSub(p/*.pos*/, v/*.pos*/, temp1);
                 LA.vecSub(q/*.pos*/, v/*.pos*/, temp2);
             }
+            else
+            {
+                continue;
+            }
 
             //LA.vecNormalize(temp1);
             //LA.vecNormalize(temp2);
@@ -3829,17 +3868,25 @@
             double s = temp3.length();
             //double c = temp2.dot(temp1);
 
+            if (s == 0)
+                return false;
+            
             float angle = 1; // (float) Math.atan2(s, c);
             //if(angle < 0) angle = -angle;
 
             //LA.vecNormalize(temp3);
             LA.vecScale(temp3, angle / s);
 
+//            if (temp3.dot(v.norm) < 0)
+//                assert(temp3.dot(v.norm) >= 0);
+            
             LA.vecAdd(temp3, v.norm, v.norm);
         }
 
         LA.vecNormalize(v.norm);
     //System.out.println("New normal = " + v.norm);
+        
+        return true;
     }
 
     double Arccos(double x)
@@ -4926,7 +4973,7 @@
             }
         }
 
-        System.out.println("done.");
+        //System.out.println("done.");
 
         cp.renderCamera = keep;
         
@@ -7075,6 +7122,7 @@
             assert(f2.contains(i));
             assert(f3.contains(i));
             
+            // when r is the "center", p is along the boundary
             while (f0.r != i)
             {
                 int t = f0.p;
@@ -7131,60 +7179,90 @@
                 f0 = f3;
                 f3 = t;
             }
-            atleastone = true;
             
+            int va = f0.q;
+            int vb = f0.r;
+            int vc = -1;
+            
+            Face toremove1 = null;
+            Face toremove2 = null;
+                    
+            // f0 is the buffer for the first new triangle,
+            // and otherf is the other upper one.
             Face otherf = null;
             
             if (f1.contains(f0.p))
             {
                 if (f1.p == f0.p)
                 {
+                    assert(false);
                     f0.r = f1.q;
                 }
                 else
                 {
                     assert(f1.q == f0.p);
-                    f0.r = f1.p;
+                    vc = f1.p;
                 }
                 
                 otherf = f2;
-                faces.remove(f1);
-                faces.remove(f3);
+                toremove1 = f1;
+                toremove2 = f3;
             }
             else
             if (f2.contains(f0.p))
             {
                 if (f2.p == f0.p)
                 {
+                    assert(false);
                     f0.r = f2.q;
                 }
                 else
                 {
                     assert(f2.q == f0.p);
-                    f0.r = f2.p;
+                    vc = f2.p;
                 }
                 
                 otherf = f3;
-                faces.remove(f1);
-                faces.remove(f2);
+                toremove1 = f1;
+                toremove2 = f2;
             }
             if (f3.contains(f0.p))
             {
                 if (f3.p == f0.p)
                 {
+                    assert(false);
                     f0.r = f3.q;
                 }
                 else
                 {
                     assert(f3.q == f0.p);
-                    f0.r = f3.p;
+                    vc = f3.p;
                 }
                 
                 otherf = f1;
-                faces.remove(f2);
-                faces.remove(f3);
+                toremove1 = f2;
+                toremove2 = f3;
             }
             
+            vertextemp.set(vertices.get(va));
+            vertextemp.sub(vertices.get(vb));
+            vertextemp.normalize();
+            vertextemp2.set(vertices.get(vc));
+            vertextemp2.sub(vertices.get(vb));
+            vertextemp2.normalize();
+
+            if (vertextemp.dot(vertextemp2) > -0.95)
+            {
+                continue;
+            }
+            
+            atleastone = true;
+            
+            f0.r = vc;
+            
+            faces.remove(toremove1);
+            faces.remove(toremove2);
+            
             if (!f0.contains(otherf.p))
             {
                 otherf.r = otherf.p;
diff --git a/CameraPane.java b/CameraPane.java
index 8fe82ec..091d05a 100644
--- a/CameraPane.java
+++ b/CameraPane.java
@@ -13257,7 +13257,8 @@
                 FlipTransform();
                 break;
             case ENTER:
-                object.editWindow.ScreenFit(); // Edit();
+                // object.editWindow.ScreenFit(); // Edit();
+                ToggleLive();
                 break;
             case DELETE:
                 ClearSelection();
diff --git a/Grid.java b/Grid.java
index 8a2d40b..f607c0d 100644
--- a/Grid.java
+++ b/Grid.java
@@ -4,6 +4,11 @@
 
     Grid()
     {
+        this(35, 34);
+    }
+
+    Grid(int u, int v)
+    {
 		super(false);
 		//this(true);
 	//}
@@ -12,8 +17,8 @@
 	//{
         inPnt = new cVector();
         name = "Grid";
-        uDivs = 35;
-        vDivs = 34;
+        uDivs = u;
+        vDivs = v;
         minUDivs = 1;
 		minVDivs = 1;
         center = new cVector();
diff --git a/GroupEditor.java b/GroupEditor.java
index 4fa02b1..d7a1c3e 100644
--- a/GroupEditor.java
+++ b/GroupEditor.java
@@ -219,6 +219,8 @@
 		resetsupportItem.addActionListener(this);
 		linkverticesItem = menu.add(new MenuItem("Link to Support"));
 		linkverticesItem.addActionListener(this);
+		relinkverticesItem = menu.add(new MenuItem("Re-link to Support"));
+		relinkverticesItem.addActionListener(this);
 		setMasterItem = menu.add(new MenuItem("Set Master Mesh"));
 		setMasterItem.addActionListener(this);
                 
@@ -231,6 +233,10 @@
 		frontItem.addActionListener(this);
 		compositeItem = menu.add(new MenuItem("Composite"));
 		compositeItem.addActionListener(this);
+		hideItem = menu.add(new MenuItem("Hide"));
+		hideItem.addActionListener(this);
+		ungroupItem = menu.add(new MenuItem("Ungroup"));
+		ungroupItem.addActionListener(this);
 		menu.add("-");
 		randomItem = menu.add(new MenuItem("Random"));
 		randomItem.addActionListener(this);
@@ -252,6 +258,8 @@
 		oe.menuBar.add(menu = new Menu("Object"));
 		textureItem = menu.add(new MenuItem("Texture"));
 		textureItem.addActionListener(this);
+		billboardItem = menu.add(new MenuItem("Billboard"));
+		billboardItem.addActionListener(this);
 		csgItem = menu.add(new MenuItem("CSG"));
 		csgItem.addActionListener(this);
                 shadowXItem = menu.add(new MenuItem("Shadow X"));
@@ -269,14 +277,12 @@
 		pointflowItem = menu.add(new MenuItem("Point Flow"));
 		pointflowItem.addActionListener(this);
 		menu.add("-");
-		transformgeometryItem = menu.add(new MenuItem("Transform Geometry"));
-		transformgeometryItem.addActionListener(this);
 		resetTransformItem = menu.add(new MenuItem("Reset Transform"));
 		resetTransformItem.addActionListener(this);
 		resetCentroidItem = menu.add(new MenuItem("Reset Centroid"));
 		resetCentroidItem.addActionListener(this);
-		ungroupItem = menu.add(new MenuItem("Ungroup"));
-		ungroupItem.addActionListener(this);
+		transformgeometryItem = menu.add(new MenuItem("Transform Geometry"));
+		transformgeometryItem.addActionListener(this);
                 
 		oe.menuBar.add(menu = new Menu("Geometry"));
 		genUVItem = menu.add(new MenuItem("Generate UV"));
@@ -287,6 +293,8 @@
 		genNormalsCADItem.addActionListener(this);
 		genNormalsMESHItem = menu.add(new MenuItem("Mesh Normals"));
 		genNormalsMESHItem.addActionListener(this);
+		genNormalsMINEItem = menu.add(new MenuItem("My Normals"));
+		genNormalsMINEItem.addActionListener(this);
 		stripifyItem = menu.add(new MenuItem("Stripify"));
 		stripifyItem.addActionListener(this);
 		unstripifyItem = menu.add(new MenuItem("Unstripify"));
@@ -1035,6 +1043,8 @@
 		torusItem.addActionListener(this);
 		superItem = menu.add(new MenuItem("Superellipsoid"));
 		superItem.addActionListener(this);
+		kleinItem = menu.add(new MenuItem("Klein Bottle"));
+		kleinItem.addActionListener(this);
 		particleItem = menu.add(new MenuItem("Particle system"));
 		particleItem.addActionListener(this);
 		ragdollItem = menu.add(new MenuItem("Rag Walk"));
@@ -1595,6 +1605,10 @@
 		{
 			makeSomething(new Superellipsoid());
 		} else
+		if (event.getSource() == kleinItem)
+		{
+			makeSomething(new Klein());
+		} else
 		if (event.getSource() == blobItem)
 		{
 			Blob blob = new Blob();
@@ -2003,23 +2017,28 @@
                     if (group.selection.size() == 1)
                         one = true;
 
+                    Object3D merge = null;
+                    
                     Object3D content = new cGroup();
                     
                     for (int i=0; i<group.selection.size(); i++)
                     {
-                        Object3D sel = new Merge(group.selection.get(i));
+                        merge = new Merge(group.selection.get(i));
                         
                         if (one)
-                            makeSomething(sel, false);
+                            makeSomething(merge, false);
                         else
-                            content.addChild(sel);
+                            content.addChild(merge);
                     }
                     
                     if (!one)
-                        makeSomething(content, false);
-                    
-                    ResetModel();
-                    refreshContents();
+                        makeSomething(content, true);
+                    else
+                    {
+                        ResetModel();
+                        Select(merge.GetTreePath(), true, false); // unselect... false);
+                        refreshContents();
+                    }
 		} else
 		if (event.getSource() == mergeGeometriesItem)
 		{
@@ -2096,6 +2115,15 @@
 
                     refreshContents();
 		} else
+		if (event.getSource() == relinkverticesItem)
+		{
+                    boolean random = CameraPane.RANDOM;
+                    CameraPane.RANDOM = false; // parse all random nodes
+                    group.selection.RelinkToSupport();
+                    CameraPane.RANDOM = random;
+
+                    refreshContents();
+		} else
 		if (event.getSource() == resetreferencesItem)
 		{
                     for (int i=0; i<group.selection.size(); i++)
@@ -2164,6 +2192,10 @@
 		if (event.getSource() == grabItem)
 		{
 			group(new cGroup(), true);
+		} else
+		if (event.getSource() == hideItem)
+		{
+			group(new HiddenObject());
 		} else
 		if (event.getSource() == frontItem)
 		{
@@ -2287,6 +2319,10 @@
 		{
 			group(new TextureNode());
 		} else
+		if (event.getSource() == billboardItem)
+		{
+			group(new BillboardNode());
+		} else
 		if (event.getSource() == shadowXItem)
 		{
 			CastShadow(0);
@@ -2301,7 +2337,15 @@
 		} else
 		if (event.getSource() == ungroupItem)
 		{
-			ungroup();
+			//ungroup();
+                    for (int i=0; i<group.selection.size(); i++)
+                    {
+                        Ungroup(group.selection.get(i));
+                    }
+
+                    ClearSelection(false);
+                    
+                    refreshContents();
 		} else
 		if (event.getSource() == genUVItem)
                 {
@@ -2318,6 +2362,10 @@
 		if (event.getSource() == genNormalsORGANItem)
                 {
 			GenNormals(false);
+		} else
+		if (event.getSource() == genNormalsMINEItem)
+                {
+			GenNormalsMINE();
 		} else
 		if (event.getSource() == stripifyItem)
                 {
@@ -3179,6 +3227,13 @@
 		refreshContents();
 	}
 	
+	void GenNormalsMINE()
+	{
+		group.selection.GenNormalsMINE();
+		
+		refreshContents();
+	}
+	
 	void Stripify()
 	{
 		group.StripifyS();
@@ -3447,12 +3502,26 @@
         
 	void Align()
 	{
+            if (group.selection.size() == 0)
+                return;
+            
+            cVector bbmin = new cVector();
+            cVector bbmax = new cVector();
+            
+            group.selection.get(0).getBounds(bbmin, bbmax, true);
+            
+            double dx = bbmax.x - bbmin.x;
+            double dy = bbmax.y - bbmin.y;
+            double dz = bbmax.z - bbmin.z;
+            
+            double scale = Math.sqrt(dx*dx + dy*dy + dz*dz);
+            
             for (int i=0; i<group.selection.size(); i++)
             {
 		Object3D obj = group.selection.get(i);
                 
-                LA.matTranslate(obj.toParent, i/2f, 0, 0);
-                LA.matTranslateInv(obj.fromParent, -i/2f, 0, 0);
+                LA.matTranslate(obj.toParent, i * scale, 0, 0);
+                LA.matTranslateInv(obj.fromParent, -i * scale, 0, 0);
             }
             
             refreshContents();
@@ -4474,6 +4543,26 @@
 		makeSomething(csg);
 	}
 	
+        void Ungroup(Object3D g)
+        {
+            if (g instanceof HiddenObject)
+            {
+                HiddenObject h = (HiddenObject) g;
+                
+                for (int i=0; i<h.ActualSize(); i++)
+                {
+                    objEditor.makeSomething(h.get(i), false);
+                }
+            }
+            else
+            {
+                for (int i=0; i<g.Size(); i++)
+                {
+                    objEditor.makeSomething(g.get(i), false);
+                }
+            }
+        }
+        
 	void ungroup()
 	{
             /*
@@ -4833,6 +4922,7 @@
 	private MenuItem resetsupportItem;
 	private MenuItem resetreferencesItem;
 	private MenuItem linkverticesItem;
+	private MenuItem relinkverticesItem;
 	private MenuItem setMasterItem;
 	private MenuItem resetMeshItem;
 	private MenuItem stepAllItem;
@@ -4854,6 +4944,7 @@
 	private MenuItem genNormalsMESHItem;
 	private MenuItem genNormalsCADItem;
 	private MenuItem genNormalsORGANItem;
+	private MenuItem genNormalsMINEItem;
 	private MenuItem stripifyItem;
 	private MenuItem unstripifyItem;
 	private MenuItem trimItem;
@@ -4895,6 +4986,7 @@
 	private MenuItem resetCentroidItem;
 	private MenuItem transformgeometryItem;
 	private MenuItem resetTransformItem;
+	private MenuItem hideItem;
 	private MenuItem grabItem;
 	private MenuItem backItem;
 	private MenuItem frontItem;
@@ -4935,6 +5027,7 @@
 	private MenuItem coneItem;
 	private MenuItem torusItem;
 	private MenuItem superItem;
+	private MenuItem kleinItem;
 	private MenuItem blobItem;
 	private MenuItem latheItem;
 	private MenuItem bezierItem;
@@ -4947,6 +5040,7 @@
 	private MenuItem csgItem;
 	private MenuItem templateItem;
 	private MenuItem textureItem;
+	private MenuItem billboardItem;
 	private MenuItem shadowXItem;
 	private MenuItem shadowYItem;
 	private MenuItem shadowZItem;
diff --git a/HiddenObject.java b/HiddenObject.java
new file mode 100644
index 0000000..4baa8fe
--- /dev/null
+++ b/HiddenObject.java
@@ -0,0 +1,39 @@
+
+class HiddenObject extends Object3D
+{
+static final long serialVersionUID = 0;
+
+static int globalcount = 1;
+
+    HiddenObject()
+    {
+        this("Hidden" + globalcount++);
+    }
+    
+    HiddenObject(String name)
+    {
+        super(name);
+    }
+
+    public int size()
+    {
+        return 0;
+    }
+    
+    public int Size()
+    {
+        return 0;
+    }
+    
+    public int ActualSize()
+    {
+        return super.size();
+    }
+    
+    HiddenObject deepCopy()
+    {
+        HiddenObject comp = new HiddenObject();
+        deepCopySelf(comp);
+        return comp;
+    }
+}
diff --git a/Klein.java b/Klein.java
new file mode 100644
index 0000000..601ff95
--- /dev/null
+++ b/Klein.java
@@ -0,0 +1,200 @@
+
+class Klein extends Biparam implements java.io.Serializable
+{
+//    void DrawNode(CameraPane display, Object3D /*Composite*/ root, boolean selected) {}
+    
+    static final long serialVersionUID = 0;
+
+    double radius = 4;
+    
+    Klein()
+    {
+        this(true);
+    }
+
+    Klein(Klein s)
+    {
+        s.deepCopySelf(this);
+    }
+
+    public Klein(boolean recalc)
+    {
+        toParent = LA.newMatrix();
+        fromParent = LA.newMatrix();
+        
+        name = "Klein";
+        //uDivs = vDivs = 16;
+        uDivs = 32;
+        vDivs = 32;
+        minUDivs = 3;
+        minVDivs = 2;
+        //center = new cVector();
+        if (recalc)
+        {
+            retile();
+            recalculate();
+        }
+    }
+
+    void refreshCenter(cVector c)
+    {
+        /**/
+        toParent[3][0] = c.x; // - center.x;
+        toParent[3][1] = c.y; // - center.y;
+        toParent[3][2] = c.z; // - center.z;
+
+        fromParent[3][0] = -c.x; // + center.x;
+        fromParent[3][1] = -c.y; // + center.y;
+        fromParent[3][2] = -c.z; // + center.z;
+    /**/
+    //center.set(0,0,0);
+    }
+
+    cVector getCenter()
+    {
+        //assert(center.x == 0);
+        //assert(center.y == 0);
+        //assert(center.z == 0);
+        
+     //   if (center == null)
+     //       center = new cVector();
+        
+        cVector c = new cVector(center);
+
+        for (int i=GetTransformCount(); --i>=0;)
+            LA.xformPos(c, toParent, c);
+
+        return c;
+    }
+
+    Object3D deepCopy()
+    {
+        Sphere e = new Sphere();
+        deepCopySelf(e);
+        return e;
+    }
+
+    protected void deepCopySelf(Object3D other)
+    {
+        super.deepCopySelf(other);
+        Klein e = (Klein) other;
+        if (center != null)
+        {
+            e.center = new cVector(center);
+            //LA.vecCopy(center, e.center);
+        }
+        e.radius = radius;
+    }
+
+    void generatePOV(StringBuffer buffer)
+    {
+        generateNameComment(buffer);
+        generateIndent(buffer);
+        buffer.append("sphere { ");
+     //   LA.toPOVRay(center, buffer);
+        buffer.append(", ");
+     //   buffer.append(radius);
+        buffer.append("\n");
+        generateTransform(buffer);
+        generateIndent(buffer);
+        buffer.append("}\n");
+    }
+
+    Vertex biparamFunction(double u, double v)
+    {
+        // KLEIN #!
+        /*
+        double uAng = LA.toRadians(-180*(1-u) + 180*u);
+        double vAng = LA.toRadians(-180*(1-v) + 180*v);
+        
+        // x = cos(u) (a + sin(v) cos(u/2) - sin(2v) sin(u/2)/2)
+        // y = sin(u) (a + sin(v) cos(u/2) - sin(2v) sin(u/2)/2)
+        // z = sin(u/2) sin(v) + cos(u/2) sin(2v)/2
+        //where
+        //   -pi <= u <= pi
+        //and
+        //   -pi <= v <= pi
+        double cosu  = Math.cos(uAng);
+        double sinu  = Math.sin(uAng);
+        double cosu2 = Math.cos(uAng/2);
+        double sinu2 = Math.sin(uAng/2);
+        double sinv  = Math.sin(vAng);
+        double sin2v = Math.sin(vAng/2);
+
+        double x = cosu * (handle + sinv * cosu2 - sin2v * sinu2 / 2);
+        double y = sinu * (handle + sinv * cosu2 - sin2v * sinu2 / 2);
+        double z = sinu2 * sinv + cosu2 * sin2v / 2;
+         */
+        
+        double uAng = LA.toRadians(u*360);
+        double vAng = LA.toRadians(v*360);
+        
+        double cosu  = Math.cos(uAng);
+        double sinu  = Math.sin(uAng);
+        double cosv  = Math.cos(vAng);
+        double sinv  = Math.sin(vAng);
+
+        double r = radius * (1 - cosu / 2);
+        
+        double x = 6 * cosu * (1 + sinu);
+        double y = 16 * sinu;
+        double z = r * sinv;
+        
+        if (u < 0.5)
+        {
+            x += r * cosu * cosv;
+            y += r * sinu * cosv;
+        }
+        else
+        {
+            x += r * Math.cos(vAng + Math.PI);
+        }
+        
+        // y = -16 .. 20
+        r = radius * (20 - y)/36 * (1 - cosu / 2);
+        
+        x = 6 * cosu * (1 + sinu);
+        y = 16 * sinu;
+        z = r * sinv;
+        
+        if (u < 0.5)
+        {
+            x += r * cosu * cosv;
+            y += r * sinu * cosv;
+        }
+        else
+        {
+            x += r * Math.cos(vAng + Math.PI);
+        }
+        
+        Vertex temp = new Vertex();
+        temp.norm = LA.newVector(x, y, z);
+        //temp.pos = new cVector();
+        if (center != null)
+            LA.vecAdd(temp.norm, center, temp/*.pos*/);
+        else
+            LA.vecCopy(temp.norm, temp/*.pos*/);
+        LA.vecNormalize(temp.norm);
+        
+        return temp;
+    }
+
+    void createEditWindow(GroupEditor callee, boolean newWindow)
+    {
+        //editWindow = (new SphereEditor(this, deepCopy(), callee)).GetEditor();
+        if (newWindow)
+        {
+            objectUI = new KleinEditor(this, deepCopy(), callee);
+        } else
+        {
+            objectUI = new KleinEditor(this, callee);
+        }
+        
+        editWindow = objectUI.GetEditor();
+    }
+
+    boolean inside(double x, double y, double z, boolean xform)
+    {
+        return false;
+    }
+}
diff --git a/KleinEditor.java b/KleinEditor.java
new file mode 100644
index 0000000..d5fbd4a
--- /dev/null
+++ b/KleinEditor.java
@@ -0,0 +1,123 @@
+// Decompiled by Jad v1.5.7b. Copyright 1997-99 Pavel Kouznetsov.
+// Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
+// Decompiler options: packimports(3) 
+// Source File Name:   SphereEditor.java
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+class KleinEditor extends BiparamEditor implements ActionListener, ObjectUI
+{
+    KleinEditor(Klein inSph, GroupEditor callee)
+    {
+        super(inSph, callee); // false);
+        //objEditor = new BiparamEditor(inSph, this, callee); // false);
+        objEditor = callee.GetEditor();
+		//parent = this;
+        klein = inSph;
+        
+	SetupUI2(objEditor);
+    }
+	
+    KleinEditor(Klein inSph, Object3D copy, GroupEditor callee)
+    {
+        super(inSph, copy, null, callee); // false);
+        //objEditor = new BiparamEditor(inSph, copy, this, callee); // false);
+		//parent = this;
+        objEditor = this;
+        klein = (Klein) copy;
+		
+		//SetupUI(objEditor);
+    }
+	
+	void SetupUI2(ObjEditor oe)
+	{
+            super.SetupUI2(oe);
+            
+            radiusField = AddSlider(oe.ctrlPanel, "Radius:", 0, 20.0, klein.radius, 1);
+            Return();
+        }
+        
+	void Clear()
+	{
+		objEditor.Clear();
+		
+		klein = null;
+	}
+	
+    /*
+    public void doLayout()
+    {
+        super.doLayout();
+        labelAndField(centerLabel, centerField);
+        labelAndField(radiusLabel, radiusField);
+        widgetPos += 5;
+    }
+    */
+
+	/**/    
+//    public void actionPerformed(ActionEvent e)
+//    {
+//	    if (e.getSource() == centerField ||
+//	        e.getSource() == radiusField)
+//	    {
+//		    applySelf();
+//		    refreshContents();
+//	    }
+//	    else
+//		    super.actionPerformed(e);
+//    }
+	/**/
+    
+	public void stateChanged(ChangeEvent e)
+	{
+	    //System.out.println("Klein :: stateChanged");
+		if (e.getSource() == radiusField)
+		{
+			applySelf();
+			//super.applySelf();
+			objEditor.refreshContents();
+			//Refresh();
+		}
+		else
+			super.stateChanged(e);
+	}
+	
+    public void applySelf()
+    {
+        super.applySelf();
+
+        klein.radius = radiusField.getFloat();
+        klein.recalculate();
+    }
+
+    Klein klein;
+    NumberSlider radiusField;
+
+	public ObjEditor GetEditor()
+	{
+            //new Exception().printStackTrace();
+		return objEditor; // .GetEditor();
+	}
+	
+	public void closeUI2()
+	{
+		objEditor.closeUI();
+	}
+
+	public void closeUI()
+	{
+                Remove(radiusField);
+		
+		super.closeUI();
+	}
+        
+	void refreshContents2()
+	{
+		objEditor.refreshContents();
+	}
+	
+	//BiparamEditor objEditor;
+}
diff --git a/Mocap.java b/Mocap.java
index 8af85a4..99ef9dc 100644
--- a/Mocap.java
+++ b/Mocap.java
@@ -2854,6 +2854,7 @@
         if (lastframetest == 0)
             lastframetest = bvh.animation.getNumFrames();
         
+        // WARNING: RESET DESTROYS EVERYTHING
         if (baseframe >= lastframetest) // july 2013 // - GetFirstFrame())
         {
             System.out.println("MOCAP reset: " + this.GetFileRoot() +
diff --git a/ObjEditor.java b/ObjEditor.java
index 228f57c..1140321 100644
--- a/ObjEditor.java
+++ b/ObjEditor.java
@@ -1859,19 +1859,21 @@
             }
 
             // Images/textures
-            if (textures
-                    && (filename.toLowerCase().endsWith(".jpg")
-                    || filename.toLowerCase().endsWith(".jpeg")
-                    || filename.toLowerCase().endsWith(".gif")
-                    || filename.toLowerCase().endsWith(".png")
-                    || filename.toLowerCase().endsWith(".tre")
-                    || filename.toLowerCase().endsWith(".bmp")
-                    || filename.toLowerCase().endsWith(".tga")
-                    || filename.toLowerCase().endsWith(".sgi")
-                    || filename.toLowerCase().endsWith(".tif")
-                    || filename.toLowerCase().endsWith(".tiff")))
+            if (filename.toLowerCase().endsWith(".jpg")
+                || filename.toLowerCase().endsWith(".jpeg")
+                || filename.toLowerCase().endsWith(".gif")
+                || filename.toLowerCase().endsWith(".png")
+                || filename.toLowerCase().endsWith(".tre")
+                || filename.toLowerCase().endsWith(".bmp")
+                || filename.toLowerCase().endsWith(".tga")
+                || filename.toLowerCase().endsWith(".sgi")
+                || filename.toLowerCase().endsWith(".tif")
+                || filename.toLowerCase().endsWith(".tiff"))
             {
-                DropTexture(filename);
+                if (textures)
+                    DropTexture(filename);
+                else
+                    CreateBillboard(filename);
                 continue;
             }
 
@@ -1882,6 +1884,60 @@
         ResetModel();
     }
     
+    void CreateBillboard(String filename)
+    {
+        Object3D source = null;
+        Object3D group = copy;
+
+        if (group.selection.size() > 0)
+        {
+            source = group.selection.get(0);
+        }
+
+        Grid grid = new Grid(1,1);
+        grid.material = null;
+        
+        grid.toParent = LA.newMatrix();
+        grid.fromParent = LA.newMatrix();
+        LA.matYRotate(grid.toParent, Math.PI/2);
+        LA.matXRotate(grid.toParent, -Math.PI/2);
+        LA.matXRotate(grid.fromParent, Math.PI/2);
+        LA.matYRotate(grid.fromParent, -Math.PI/2);
+        
+        BillboardNode bb = new BillboardNode();
+        bb.addChild(grid);
+        
+        Object3D newgroup = new Object3D();
+        newgroup.CreateMaterial();
+        
+        File file = new File(filename);
+        newgroup.name = file.getName();
+        newgroup.addChild(bb);
+        
+        Object3D main = newgroup;
+        
+        main.SetPigmentTexture(filename);
+        
+        if (source != null)
+        {
+            main.material = new cMaterial(source.material);
+            if (main.projectedVertices.length < source.projectedVertices.length)
+            {
+                main.projectedVertices = new Object3D.cVector2[source.projectedVertices.length];
+            }
+            
+            for (int i=0; i<source.projectedVertices.length; i++)
+            {
+                main.projectedVertices[i].x = source.projectedVertices[i].x;
+                main.projectedVertices[i].y = source.projectedVertices[i].y;
+            }
+            
+            main.texres = source.texres;
+        }
+        
+        makeSomething(newgroup, false);
+    }
+    
     Point location;
 
     void DropTexture(String filename)
diff --git a/Object3D.java b/Object3D.java
index ebab7df..f6cf69b 100644
--- a/Object3D.java
+++ b/Object3D.java
@@ -355,7 +355,7 @@
     
     int MemorySize()
     {
-        if (memorysize == 0)
+        if (true) // memorysize == 0)
         {
             try
             {
@@ -1446,7 +1446,16 @@
     //    if (other == null)
     //        return;
         
-        System.out.println("Link support this = " + this + "; other = " + other);
+        if (other != null)
+        {
+            BoundaryRep.SEUIL = other.material.cameralight;
+
+            // Set default to 0.1
+            BoundaryRep.SEUIL /= 2;
+            System.out.println("SEUIL = " + BoundaryRep.SEUIL);
+        }
+        
+        System.out.println("Link this = " + this + "; support = " + other);
         
         //if (bRep != null)
         //    bRep.linkVerticesThis(other.bRep);
@@ -1816,8 +1825,9 @@
             if (obj.name == null)
                 continue; // can't be a null one
             
-            //if (n.contains(obj.name)) // dec 2013  name.split(":")[0])) // Poser generates a count
-            if (n.startsWith(obj.name))
+            String name = obj.name.split(":")[0]; // Poser generates a count
+            //if (n.startsWith(obj.name))
+            if (n.contains(name))
             {
                 theobj = obj;
                 count++;
@@ -2732,6 +2742,24 @@
         blockloop = false;
     }
 
+    void GenNormalsMINE()
+    {
+        if (blockloop)
+            return;
+        
+        blockloop = true;
+        GenNormalsMINE0();
+        for (int i = 0; i < Children().Size(); i++)
+        {
+            Object3D child = (Object3D) Children().get(i); // reserve(i);
+            if (child == null)
+                continue;
+            child.GenNormalsMINE();
+//            Children().release(i);
+        }
+        blockloop = false;
+    }
+
     void ClearColors()
     {
         if (blockloop)
@@ -2876,6 +2904,15 @@
         if (bRep != null)
         {
             bRep.GenerateNormals(crease);
+            Touch();
+        }
+    }
+
+    void GenNormalsMINE0()
+    {
+        if (bRep != null)
+        {
+            bRep.GenerateNormalsMINE();
             Touch();
         }
     }
@@ -4111,7 +4148,7 @@
         if (blockloop)
             return;
         
-        for (int i=0; i<size(); i++)
+        for (int i=0; i<Size(); i++)
         {
             if (get(i).parent != this)
             {
@@ -7733,7 +7770,7 @@
         if (parent == null)
         {
             System.out.println("NULL PARENT");
-            new Exception().printStackTrace();
+            //new Exception().printStackTrace();
         } else
         {
             if (parent instanceof BezierPatch)
diff --git a/cMesh.java b/cMesh.java
index af52c25..942d155 100644
--- a/cMesh.java
+++ b/cMesh.java
@@ -355,7 +355,9 @@
         //        DynamicNode handle = new DynamicNode(center.x, center.y, center.z, 0 /*0 , 1 or Float.MAX_VALUE*/, 0);
         //        Phys.addHandle(handle);
                 
-            for (int k=Phys.allNodes.size(); --k>=0;) // warning: "add handle" adds a node
+            int size = Phys.allNodes.size();
+            
+            for (int k=0; k < size; k++) // warning: "add handle" adds a node
             {
                 DynamicNode dn = Phys.allNodes.get(k);
                 DynamicNode handle = new DynamicNode(dn.position.x, dn.position.y, dn.position.z, 0 /*0 , 1 or Float.MAX_VALUE*/, 0);
diff --git a/cSpring.java b/cSpring.java
index 6bebd0f..2986693 100644
--- a/cSpring.java
+++ b/cSpring.java
@@ -1057,7 +1057,7 @@
                 vect1.set(v);
                 LA.xformPos(vect1,toRoot,vect1);
             
-                handles.get(usedrep.VertexCount()-1-i).set(vect1);
+                handles.get(i).set(vect1);
             }
         }
         
@@ -2325,6 +2325,7 @@
 
         abstract Point3D forceOn(DynamicNode N);
     }
+    
     Point3D force = new Point3D();
     Point3D dir = new Point3D();
 

--
Gitblit v1.6.2