PageRenderTime 52ms CodeModel.GetById 17ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/advanced/puzzle/PuzzleFactory.java

http://mt4j.googlecode.com/
Java | 519 lines | 369 code | 77 blank | 73 comment | 49 complexity | 7e222085732de38cf9f6fb4452a3e1ad MD5 | raw file
  1package advanced.puzzle;
  2
  3import java.util.ArrayList;
  4import java.util.List;
  5
  6import org.mt4j.MTApplication;
  7import org.mt4j.components.MTComponent;
  8import org.mt4j.components.TransformSpace;
  9import org.mt4j.components.bounds.BoundsZPlaneRectangle;
 10import org.mt4j.components.interfaces.IMTComponent3D;
 11import org.mt4j.components.visibleComponents.shapes.AbstractShape;
 12import org.mt4j.components.visibleComponents.shapes.MTComplexPolygon;
 13import org.mt4j.components.visibleComponents.shapes.MTPolygon;
 14import org.mt4j.input.gestureAction.InertiaDragAction;
 15import org.mt4j.input.inputData.InputCursor;
 16import org.mt4j.input.inputProcessors.IGestureEventListener;
 17import org.mt4j.input.inputProcessors.MTGestureEvent;
 18import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragProcessor;
 19import org.mt4j.input.inputProcessors.componentProcessors.lassoProcessor.IdragClusterable;
 20import org.mt4j.input.inputProcessors.componentProcessors.rotateProcessor.RotateEvent;
 21import org.mt4j.input.inputProcessors.componentProcessors.rotateProcessor.RotateProcessor;
 22import org.mt4j.input.inputProcessors.componentProcessors.scaleProcessor.ScaleProcessor;
 23import org.mt4j.util.MT4jSettings;
 24import org.mt4j.util.MTColor;
 25import org.mt4j.util.math.Tools3D;
 26import org.mt4j.util.math.ToolsGeometry;
 27import org.mt4j.util.math.ToolsMath;
 28import org.mt4j.util.math.Vector3D;
 29import org.mt4j.util.math.Vertex;
 30import org.mt4j.util.opengl.GLTexture;
 31import org.mt4j.util.xml.svg.SVGLoader;
 32
 33import processing.core.PApplet;
 34import processing.core.PImage;
 35
 36public class PuzzleFactory {
 37	//TODO
 38	/*
 39	 - show mini picture of original picture for orientation
 40	 - snap pieces together? - how to break them apart again?
 41	 - clusterable tiles? 
 42	 - if solved - set all tiles noStroke(true) to see image clearly 
 43	 */
 44
 45	public enum TileSide{
 46		pinOut,
 47		pinIn,
 48		linear
 49	}
 50	
 51	private float tileHeight;
 52	private float tileWidth;
 53	private Vertex[] downUpOrderVerticalRightOut;
 54	private Vertex[] upDownOrderVerticalLeftOut;
 55	private Vertex[] downUpOrderVerticalLeftOut;
 56	private Vertex[] leftRightHorizontalUpOut;
 57	private Vertex[] rightLeftHorizontalUpOut;
 58	private Vertex[] rightLeftOrderHorizontalDownOut;
 59	private Vertex[] leftRightOrderHorizontalDownOut;
 60	private Vertex[] upDownOrderVerticalRightOut;
 61	private PImage image;
 62	private float horizontalTileCount;
 63	private PApplet app;
 64	private float verticalTileCount;
 65	public static String svgPath =  "advanced"+MTApplication.separator+"puzzle"+MTApplication.separator+"data"+MTApplication.separator ;
 66	public static String svgname = "knobOutRight.svg";
 67	
 68	public PuzzleFactory(MTApplication app) {
 69		this.app = app;
 70	}
 71
 72//	public PuzzleFactory(PApplet app, float tileWidth, float tileHeight){
 73//
 74//	}
 75	
 76	private void init(float tileWidth, float tileHeight){
 77		this.tileWidth = tileWidth;
 78		this.tileHeight = tileHeight;
 79		initTiles();
 80	}
 81	
 82	private void init(PImage p, int horizontalTileCount){
 83//		if (MT4jSettings.getInstance().isOpenGlMode() && !(p instanceof GLTexture)){
 84//			GLTexture tex = new GLTexture(app, p);
 85//			this.image = tex;
 86//		}else{
 87//			this.image = p;
 88//		}
 89//		
 90//		this.horizontalTileCount = horizontalTileCount;
 91//		this.verticalTileCount = horizontalTileCount; //TODO
 92//		this.tileWidth = (float)p.width/horizontalTileCount;
 93//		this.tileHeight = (float)p.height/verticalTileCount; 
 94//		initTiles();
 95		this.init(p, horizontalTileCount, horizontalTileCount);
 96	}
 97	
 98	private void init(PImage p, int horizontalTileCount, int verticalTileCount){
 99		if (MT4jSettings.getInstance().isOpenGlMode() && !(p instanceof GLTexture)){
100			GLTexture tex = new GLTexture(app, p);
101			this.image = tex;
102		}else{
103			this.image = p;
104		}
105		
106		this.horizontalTileCount = horizontalTileCount;
107		this.verticalTileCount = verticalTileCount; //TODO
108		this.tileWidth = (float)p.width/(float)horizontalTileCount;
109		this.tileHeight = (float)p.height/(float)verticalTileCount; 
110		initTiles();
111	}
112	
113	private void initTiles(){
114		SVGLoader l = new SVGLoader(app);
115		MTComponent knob = l.loadSvg(svgPath + svgname);
116		MTPolygon knobRight = (MTPolygon) knob.getChildByIndex(0).getChildByIndex(0);
117		knobRight.setNoFill(false);
118		knobRight.setUseDisplayList(false);
119		float origHeight = knobRight.getHeightXY(TransformSpace.LOCAL);
120		
121		//Snap to upper left 0,0
122		Vertex[] originalVerts = knobRight.getVerticesLocal();
123		originalVerts = Vertex.translateArray(originalVerts, Vector3D.ZERO_VECTOR.getSubtracted(new Vector3D(originalVerts[0])));
124		
125		upDownOrderVerticalRightOut = Vertex.getDeepVertexArrayCopy(originalVerts);
126		//Scale to desired height
127		Vertex.scaleVectorArray(upDownOrderVerticalRightOut, Vector3D.ZERO_VECTOR, (1f/origHeight) * tileHeight, (1f/origHeight) * tileHeight, 1);
128				
129		downUpOrderVerticalRightOut = getInvertOrderCopy(upDownOrderVerticalRightOut);
130//		MTPolygon p1 = new MTPolygon(getMTApplication(), downUpOrderVerticalRightOut);
131//		getCanvas().addChild(p1);
132		
133		upDownOrderVerticalLeftOut = Vertex.getDeepVertexArrayCopy(upDownOrderVerticalRightOut);
134		Vertex.scaleVectorArray(upDownOrderVerticalLeftOut, new Vector3D(0,origHeight/2f), -1, 1, 1);
135//		MTPolygon p2 = new MTPolygon(getMTApplication(), vertsVerticalLeftOut);
136//		getCanvas().addChild(p2);
137		
138		downUpOrderVerticalLeftOut = getInvertOrderCopy(upDownOrderVerticalLeftOut);
139		
140		leftRightHorizontalUpOut = Vertex.getDeepVertexArrayCopy(originalVerts);
141		Vertex.rotateZVectorArray(leftRightHorizontalUpOut, Vector3D.ZERO_VECTOR, -90);
142		//Scale to desired width
143		Vertex.scaleVectorArray(leftRightHorizontalUpOut, Vector3D.ZERO_VECTOR, (1f/origHeight) * tileWidth, (1f/origHeight) * tileWidth, 1);
144//		MTPolygon p3 = new MTPolygon(getMTApplication(), leftRightHorizontalUpOut);
145//		getCanvas().addChild(p3);
146		
147		rightLeftHorizontalUpOut = getInvertOrderCopy(leftRightHorizontalUpOut);
148		
149		leftRightOrderHorizontalDownOut = Vertex.getDeepVertexArrayCopy(leftRightHorizontalUpOut);
150		Vertex.scaleVectorArray(leftRightOrderHorizontalDownOut, new Vector3D(origHeight/2f,0), 1, -1, 1);
151//		MTPolygon p4 = new MTPolygon(getMTApplication(), leftRightOrderHorizontalDownOut);
152//		getCanvas().addChild(p4);
153		
154		rightLeftOrderHorizontalDownOut = getInvertOrderCopy(leftRightOrderHorizontalDownOut);
155	}
156	
157	
158	public AbstractShape[] createTiles(PImage p, int horizontalTileCount){
159		return createTiles(p, horizontalTileCount, horizontalTileCount);
160	}
161	
162	public AbstractShape[] createTiles(PImage p, int horizontalTileCount, int verticalTileCount){
163		this.init(p, horizontalTileCount, verticalTileCount);
164		
165		List<AbstractShape> tiles = new ArrayList<AbstractShape>();
166		TileSide[] sides = new TileSide[]{TileSide.pinIn, TileSide.pinOut};
167		
168		for (int i = 0; i < verticalTileCount; i++) {
169			for (int j = 0; j < horizontalTileCount; j++) {
170				TileSide top = TileSide.pinOut, right = TileSide.pinOut, bottom = TileSide.pinOut, left = TileSide.pinIn;
171				
172				//left und top have to be checked against the previous tiles, right and bottom can be random (if not linear)
173				right = sides[Math.round(ToolsMath.getRandom(0, sides.length-1))];
174				bottom = sides[Math.round(ToolsMath.getRandom(0, sides.length-1))];
175				
176				if (j == 0){
177					//Left side has to be linear
178					left = TileSide.linear;
179					
180					if (i == 0){
181						//top side has to be linear
182						top = TileSide.linear;
183//						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
184					}else if (i == verticalTileCount -1){
185						//Bottom side has to be linear
186						bottom = TileSide.linear;
187						top = getFittingTileSideTo(getBottomOfUpperTile(tiles, i, j));
188//						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
189					}else{
190						//in a middle vetical - up or bottom side have to have a pin
191						top = getFittingTileSideTo(getBottomOfUpperTile(tiles, i, j));
192//						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
193					}
194				}else if (j == horizontalTileCount -1){
195					right = TileSide.linear;
196					
197					//Right side has to be linear
198					if (i == 0){
199						//top side has to be linear
200						top = TileSide.linear;
201						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
202					}else if (i == verticalTileCount -1){
203						//Bottom side has to be linear
204						bottom = TileSide.linear;
205						top = getFittingTileSideTo(getBottomOfUpperTile(tiles, i, j));
206						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
207					}else{
208						//in a middle vetical - up or bottom side have to have a pin
209						top = getFittingTileSideTo(getBottomOfUpperTile(tiles, i, j));
210						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
211					}
212				}else{
213					//in a middle horizontal, left or right side have to have a pin
214					
215					if (i == 0){
216						//top side has to be linear
217						top = TileSide.linear;
218						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
219					}else if (i == verticalTileCount -1){
220						//Bottom side has to be linear
221						bottom = TileSide.linear;
222						top = getFittingTileSideTo(getBottomOfUpperTile(tiles, i, j));
223						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
224					}else{
225						//in a middle vetical - up or bottom side have to have a pin
226						top = getFittingTileSideTo(getBottomOfUpperTile(tiles, i, j));
227						left = getFittingTileSideTo(getRightOfLeftTile(tiles, i, j));
228					}
229				}
230				
231				MTComplexPolygon tile = getPolygon(app, top, right, bottom, left, this.tileWidth, this.tileHeight);
232				tile.setName(i + "" + j);
233				tile.setUserData("i", i);
234				tile.setUserData("j", j);
235				tile.setUserData("top", top);
236				tile.setUserData("right", right);
237				tile.setUserData("bottom", bottom);
238				tile.setUserData("left", left);
239				//Create some default texture coords
240				tile.setBounds(new BoundsZPlaneRectangle(tile));
241				if (tile != null && tile.hasBounds() && tile.getBounds() instanceof BoundsZPlaneRectangle){
242					BoundsZPlaneRectangle bounds = (BoundsZPlaneRectangle) tile.getBounds();
243					
244//					float width = bounds.getWidthXY(TransformSpace.LOCAL);
245//					float height = bounds.getHeightXY(TransformSpace.LOCAL);
246//					float upperLeftX = bounds.getVectorsLocal()[0].x;
247//					float upperLeftY = bounds.getVectorsLocal()[0].y;
248					
249//					float upperLeftX = bounds.getVectorsLocal()[0].x  + j* tileWidth ;
250//					float upperLeftY = bounds.getVectorsLocal()[0].y  + i * tileHeight;
251					Vertex[] verts = tile.getVerticesLocal();
252                    for (Vertex vertex : verts) {
253                        //						vertex.setTexCoordU((vertex.x-upperLeftX )/width);
254//						vertex.setTexCoordV((vertex.y-upperLeftY)/height);
255//						vertex.setTexCoordU((vertex.x - upperLeftX  + (j * tileWidth)) / p.width);
256//						vertex.setTexCoordV((vertex.y - upperLeftY + (i * tileHeight)) / p.height);
257
258                        vertex.setTexCoordU((vertex.x + (j * tileWidth)) / p.width);
259                        vertex.setTexCoordV((vertex.y + (i * tileHeight)) / p.height);
260
261                        //System.out.println("TexU:" + vertex.getTexCoordU() + " TexV:" + vertex.getTexCoordV());
262                    }
263					tile.getGeometryInfo().updateTextureBuffer(tile.isUseVBOs());
264					
265					//Set the texture
266					tile.setTexture(p);
267//					tile.setNoStroke(true);
268//					tile.setStrokeColor(MTColor.GREY);
269					tile.setStrokeColor(new MTColor(80,80,80));
270					tile.setStrokeWeight(0.7f);
271					
272					tiles.add(tile);
273				}
274				
275			}
276		}
277		
278		return tiles.toArray(new AbstractShape[tiles.size()]);
279	}
280	
281	
282	private TileSide getBottomOfUpperTile(List<AbstractShape> list, int currentI, int currentJ){
283		if (currentI-1 < 0){
284			return TileSide.linear;
285		}
286        for (AbstractShape tile : list) {
287            int i = (Integer) tile.getUserData("i");
288            int j = (Integer) tile.getUserData("j");
289            if (i == currentI - 1 && j == currentJ) {
290                return (TileSide) tile.getUserData("bottom");
291            }
292        }
293		return TileSide.linear;
294	}
295	
296	private TileSide getRightOfLeftTile(List<AbstractShape> list, int currentI, int currentJ){
297		if (currentJ-1 < 0){
298			return TileSide.linear;
299		}
300        for (AbstractShape tile : list) {
301            int i = (Integer) tile.getUserData("i");
302            int j = (Integer) tile.getUserData("j");
303            if (i == currentI && j == currentJ - 1) {
304                return (TileSide) tile.getUserData("right");
305            }
306        }
307		return TileSide.linear;
308	}
309	
310	private TileSide getFittingTileSideTo(TileSide otherSide){
311		TileSide fitting = TileSide.linear;
312		switch (otherSide) {
313		case linear:
314			fitting = TileSide.linear;
315			break;
316		case pinIn:
317			fitting = TileSide.pinOut;
318			break;
319		case pinOut:
320			fitting = TileSide.pinIn;
321			break;
322		default:
323			break;
324		}
325		return fitting;
326	}
327	
328	
329	public MTComplexPolyClusterable getPolygon(final PApplet app, TileSide top, TileSide right, TileSide bottom, TileSide left, float tileWidth, float tileHeight){
330		this.init(tileWidth, tileHeight);
331		Vertex[] v = getTile(top, right, bottom, left);
332		MTComplexPolyClusterable poly = new MTComplexPolyClusterable(app, v);
333		poly.removeAllGestureEventListeners(ScaleProcessor.class);
334		poly.addGestureListener(DragProcessor.class, new InertiaDragAction());
335		
336		//FIXME TEST
337		poly.removeAllGestureEventListeners(RotateProcessor.class);
338		poly.addGestureListener(RotateProcessor.class, new RotationListener(poly));
339		return poly;
340	}
341	
342	
343	//FIXME TEST
344	private class RotationListener implements IGestureEventListener{
345		Vector3D startP1;
346		InputCursor oldC1;
347		InputCursor oldC2;
348		Vector3D planeNormal;
349		private Vector3D lastMiddle;
350		
351		public RotationListener(IMTComponent3D comp){
352			planeNormal = new Vector3D(0,0,1);
353		}
354		
355		public boolean processGestureEvent(MTGestureEvent ge) {
356			IMTComponent3D comp = ge.getTarget();
357			RotateEvent re = (RotateEvent)ge;
358			float deg = re.getRotationDegrees();
359			InputCursor c1 = re.getFirstCursor();
360			InputCursor c2 = re.getSecondCursor();
361			
362			switch (re.getId()) {
363			case RotateEvent.GESTURE_STARTED:{
364				oldC1 = c1;
365				oldC2 = c2;
366				startP1 = comp.getIntersectionGlobal(Tools3D.getCameraPickRay(app, comp, c1));
367				Vector3D i1 = ToolsGeometry.getRayPlaneIntersection(Tools3D.getCameraPickRay(app, comp, c1), planeNormal, startP1);
368				Vector3D i2 = ToolsGeometry.getRayPlaneIntersection(Tools3D.getCameraPickRay(app, comp, c2), planeNormal, startP1);
369				lastMiddle = i1.getAdded(i2.getSubtracted(i1).scaleLocal(0.5f));
370			}break;
371			case RotateEvent.GESTURE_UPDATED:
372				if (!oldC1.equals(c1) || !oldC2.equals(c2)){ //Because c1 and/or c2 can change if a finger with greater distance enters -> prevent jump
373					Vector3D i1 = ToolsGeometry.getRayPlaneIntersection(Tools3D.getCameraPickRay(app, comp, c1), planeNormal, startP1);
374					Vector3D i2 = ToolsGeometry.getRayPlaneIntersection(Tools3D.getCameraPickRay(app, comp, c2), planeNormal, startP1);
375					lastMiddle = i1.getAdded(i2.getSubtracted(i1).scaleLocal(0.5f));
376					oldC1 = c1;
377					oldC2 = c2;
378				}
379				
380				Vector3D i1 = ToolsGeometry.getRayPlaneIntersection(Tools3D.getCameraPickRay(app, comp, c1), planeNormal, startP1);
381				Vector3D i2 = ToolsGeometry.getRayPlaneIntersection(Tools3D.getCameraPickRay(app, comp, c2), planeNormal, startP1);
382				Vector3D middle = i1.getAdded(i2.getSubtracted(i1).scaleLocal(0.5f));
383				
384				Vector3D middleDiff = middle.getSubtracted(lastMiddle);
385				comp.rotateZGlobal(middle, deg);
386				comp.translateGlobal(middleDiff);
387				lastMiddle = middle;
388				break;
389			case RotateEvent.GESTURE_ENDED:
390				break;
391			default:
392				break;
393			}
394			return false;
395		}
396	}
397	
398	private class MTComplexPolyClusterable extends MTComplexPolygon implements IdragClusterable{
399		public MTComplexPolyClusterable(PApplet app, Vertex[] vertices) {
400			super(app, vertices);
401		}
402
403		public boolean isSelected() {
404			return false;
405		}
406
407		public void setSelected(boolean selected) {
408		}
409		
410	}
411	
412	private Vertex[] getTile(TileSide top, TileSide right, TileSide bottom, TileSide left){
413		List<Vertex> list = new ArrayList<Vertex>();
414		
415		switch (top) {
416		case linear:
417			list.add(new Vertex(0,0));
418			list.add(new Vertex(tileWidth, 0));
419			break;
420		case pinIn:
421			addAll(Vertex.getDeepVertexArrayCopy(leftRightOrderHorizontalDownOut), list);
422			break;
423		case pinOut:
424			addAll(Vertex.getDeepVertexArrayCopy(leftRightHorizontalUpOut), list);
425			break;
426		default:
427			break;
428		}
429		
430		switch (right) {
431		case linear:
432//			list.add(new Vertex(tileWidth,0));
433			list.add(new Vertex(tileWidth, tileHeight));
434			break;
435		case pinIn:
436			addAll(getCopyOffset(this.upDownOrderVerticalLeftOut, tileWidth, 0), list);
437			break;
438		case pinOut:
439			addAll(getCopyOffset(this.upDownOrderVerticalRightOut, tileWidth, 0), list);
440			break;
441		default:
442			break;
443		}
444		
445		
446		switch (bottom) {
447		case linear:
448//			list.add(new Vertex(tileWidth, tileHeight));
449			list.add(new Vertex(0, tileHeight));
450			break;
451		case pinIn:
452			addAll(getCopyOffset(this.rightLeftHorizontalUpOut, 0, tileHeight), list);
453			break;
454		case pinOut:
455			addAll(getCopyOffset(this.rightLeftOrderHorizontalDownOut, 0, tileHeight), list);
456			break;
457		default:
458			break;
459		}
460		
461		switch (left) {
462		case linear:
463//			list.add(new Vertex(0, tileHeight));
464			list.add(new Vertex(0, 0));
465			break;
466		case pinIn:
467			addAll(Vertex.getDeepVertexArrayCopy(this.downUpOrderVerticalRightOut), list);
468			break;
469		case pinOut:
470			addAll(Vertex.getDeepVertexArrayCopy(this.downUpOrderVerticalLeftOut), list);
471			break;
472		default:
473			break;
474		}
475		
476		return list.toArray(new Vertex[list.size()]);
477	}
478	
479	
480	private void addAll(Vertex[] vertices, List<Vertex> list){
481        for (Vertex vertex : vertices) {
482            list.add(vertex);
483        }
484	}
485	
486	
487	private Vertex[] getCopyOffset(Vertex[] verts, float xOffset, float yOffset){
488		Vertex[] copy = new Vertex[verts.length];
489//		Vertex[] copy = Vertex.getDeepVertexArrayCopy(verts);
490		for (int i = 0; i < copy.length; i++) {
491			copy[i] = (Vertex) new Vertex(verts[i]).addLocal(new Vertex(xOffset, yOffset));
492		}
493		return copy;
494	}
495	
496	private Vertex[] getInvertOrderCopyOffset(Vertex[] verts, float xOffset, float yOffset){
497		Vertex[] copy = new Vertex[verts.length];
498//		Vertex[] copy = Vertex.getDeepVertexArrayCopy(verts);
499		for (int i = 0; i < copy.length; i++) {
500			copy[i] = (Vertex) new Vertex(verts[verts.length -i -1]).addLocal(new Vertex(xOffset, yOffset));
501		}
502		return copy;
503	}
504	
505	
506	private Vertex[] getInvertOrderCopy(Vertex[] verts){
507		Vertex[] copy = new Vertex[verts.length];
508//		Vertex[] copy = Vertex.getDeepVertexArrayCopy(verts);
509		for (int i = 0; i < verts.length; i++) {
510//			copy[i] = copy[copy.length -i -1];
511			copy[i] = new Vertex(verts[verts.length -i -1]);
512		}
513		return copy;
514	}
515	
516	
517	
518
519}