Revision 4a014840
Added by Leszek Koltunski 6 months ago
src/main/java/org/distorted/objectlib/main/TwistyLayerRotations.java | ||
---|---|---|
10 | 10 |
package org.distorted.objectlib.main; |
11 | 11 |
|
12 | 12 |
import org.distorted.library.effect.VertexEffectRotate; |
13 |
import org.distorted.library.main.DistortedEffects; |
|
13 | 14 |
import org.distorted.library.message.EffectListener; |
14 | 15 |
import org.distorted.library.type.Dynamic1D; |
15 | 16 |
import org.distorted.library.type.Static1D; |
... | ... | |
30 | 31 |
private int mCurrentRotAxis; |
31 | 32 |
|
32 | 33 |
private final int mMaxNumLayers; |
33 |
private final int mGhostAngle; |
|
34 | 34 |
private final Static3D mRotationAxis; |
35 | 35 |
private final VertexEffectRotate mRotateEffect; |
36 | 36 |
private final Dynamic1D mRotationAngle; |
37 | 37 |
private final Static1D mRotationAngleStatic, mRotationAngleMiddle, mRotationAngleFinal; |
38 | 38 |
private final TwistyObject mParent; |
39 | 39 |
|
40 |
// ghost angle |
|
41 |
private final float mGhostAngle; |
|
42 |
private final int mNumLayer0; |
|
43 |
private final boolean[] mGhostIsUp; |
|
44 |
private int mUpLeft, mUpRight; |
|
45 |
private final int mNumLeft, mNumRight; |
|
46 |
private VertexEffectRotate mGhostEffect1; |
|
47 |
private Static1D mGhostAngleN; |
|
48 |
private int mGhostN; |
|
49 |
|
|
40 | 50 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
41 | 51 |
|
42 |
TwistyLayerRotations(TwistyObject parent, int maxLayers, int ghostAngle)
|
|
52 |
TwistyLayerRotations(TwistyObject parent, Static3D ax, int[] numLayers, int ghostAngle, DistortedEffects effect)
|
|
43 | 53 |
{ |
44 | 54 |
mParent = parent; |
55 |
mGhostAngle = (float)(Math.PI*ghostAngle/180); |
|
56 |
|
|
57 |
int maxLayers = -1; |
|
58 |
for(int numLayer : numLayers) if(maxLayers<numLayer) maxLayers = numLayer; |
|
45 | 59 |
mMaxNumLayers = maxLayers; |
46 |
mGhostAngle = ghostAngle; |
|
60 |
mNumLayer0 = numLayers[0]; |
|
61 |
mGhostIsUp = (mGhostAngle==0) ? null : new boolean[mNumLayer0]; |
|
62 |
mUpLeft = mUpRight = 0; |
|
63 |
mNumLeft = mNumLayer0/2; |
|
64 |
mNumRight= mNumLayer0-mNumLeft; |
|
47 | 65 |
|
48 | 66 |
mRotationState = STATE_NOTHING; |
49 | 67 |
|
... | ... | |
54 | 72 |
mRotationAngle= new Dynamic1D(); |
55 | 73 |
mRotationAxis = new Static3D(1,0,0); |
56 | 74 |
mRotateEffect = new VertexEffectRotate(mRotationAngle, mRotationAxis, CENTER); |
75 |
|
|
76 |
effect.apply(mRotateEffect); |
|
77 |
|
|
78 |
if( mGhostAngle!=0 ) |
|
79 |
{ |
|
80 |
mGhostN = 0; |
|
81 |
Static1D ghostAngle1= new Static1D( (float)(Math.PI*mGhostAngle/180) ); |
|
82 |
mGhostAngleN= new Static1D(0); |
|
83 |
VertexEffectRotate ghostEffectN = new VertexEffectRotate(mGhostAngleN, ax, CENTER); |
|
84 |
mGhostEffect1 = new VertexEffectRotate( ghostAngle1, ax, CENTER); |
|
85 |
effect.apply(ghostEffectN); |
|
86 |
effect.apply(mGhostEffect1); |
|
87 |
} |
|
57 | 88 |
} |
58 | 89 |
|
90 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
91 |
// GHOST |
|
59 | 92 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
60 | 93 |
|
61 |
private int computeNearestAngle(int basicAngle, float angle, float speed)
|
|
94 |
private boolean angleIsGhost(int angle, int basicAngle)
|
|
62 | 95 |
{ |
63 |
int nearestAngle = 360/basicAngle; |
|
64 |
int tmp = (int)((angle+nearestAngle/2)/nearestAngle); |
|
65 |
if( angle< -(nearestAngle*0.5) ) tmp-=1; |
|
96 |
return angle%(360/basicAngle)!=0; |
|
97 |
} |
|
66 | 98 |
|
67 |
if( tmp!=0 ) return nearestAngle*tmp;
|
|
99 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
68 | 100 |
|
69 |
return speed> 1.2f ? nearestAngle*(angle>0 ? 1:-1) : 0; |
|
101 |
private int computeGhostAngle(int row, int basicAngle, float angle, float speed) |
|
102 |
{ |
|
103 |
boolean left = row<mNumLayer0/2; |
|
104 |
|
|
105 |
if( left ) |
|
106 |
{ |
|
107 |
if( angle<0 ) // if we are looking at the 0th axis (x axis) from the front, this is 'up' rot |
|
108 |
{ |
|
109 |
if( mUpRight==mNumRight && !mGhostIsUp[row] ) |
|
110 |
{ |
|
111 |
int a = computeGhostAngle(basicAngle,angle,speed); |
|
112 |
if( angleIsGhost(a,basicAngle) ) |
|
113 |
{ |
|
114 |
changeRow(row,true); |
|
115 |
if( mUpLeft==0 ) enableGhostAxis(false); |
|
116 |
mUpLeft++; |
|
117 |
|
|
118 |
if( mUpLeft==mNumLeft ) |
|
119 |
{ |
|
120 |
for( int i=0; i<mNumLayer0; i++ ) changeRow(i,false); |
|
121 |
mUpLeft = 0; |
|
122 |
mUpRight= 0; |
|
123 |
changeTotalGhostAngle(1); |
|
124 |
} |
|
125 |
} |
|
126 |
return a; |
|
127 |
} |
|
128 |
else return computeNearestAngle(basicAngle,angle,speed); |
|
129 |
} |
|
130 |
else |
|
131 |
{ |
|
132 |
if( mGhostIsUp[row] ) |
|
133 |
{ |
|
134 |
int a = computeGhostAngle(basicAngle,angle,speed); |
|
135 |
if( angleIsGhost(a,basicAngle) ) |
|
136 |
{ |
|
137 |
changeRow(row,false); |
|
138 |
if( mUpLeft==1 ) enableGhostAxis(true); |
|
139 |
mUpLeft--; |
|
140 |
} |
|
141 |
return a; |
|
142 |
} |
|
143 |
else if( mUpLeft==0 && mUpRight==0 ) |
|
144 |
{ |
|
145 |
int a = computeGhostAngle(basicAngle,angle,speed); |
|
146 |
if( angleIsGhost(a,basicAngle) ) |
|
147 |
{ |
|
148 |
mUpLeft = mNumLeft-1; |
|
149 |
mUpRight= mNumRight; |
|
150 |
for( int i=0; i<mNumLayer0; i++ ) |
|
151 |
if( i!=row) changeRow(i,true); |
|
152 |
if( mNumLeft==1 ) enableGhostAxis(true); |
|
153 |
changeTotalGhostAngle(-1); |
|
154 |
} |
|
155 |
return a; |
|
156 |
} |
|
157 |
else return computeNearestAngle(basicAngle,angle,speed); |
|
158 |
} |
|
159 |
} |
|
160 |
else |
|
161 |
{ |
|
162 |
if( angle<0 ) |
|
163 |
{ |
|
164 |
if( !mGhostIsUp[row] ) |
|
165 |
{ |
|
166 |
int a = computeGhostAngle(basicAngle,angle,speed); |
|
167 |
if( angleIsGhost(a,basicAngle) ) |
|
168 |
{ |
|
169 |
changeRow(row,true); |
|
170 |
mUpRight++; |
|
171 |
if( mUpRight==mNumRight ) enableGhostAxis(true); |
|
172 |
} |
|
173 |
return a; |
|
174 |
} |
|
175 |
else return computeNearestAngle(basicAngle,angle,speed); |
|
176 |
} |
|
177 |
else |
|
178 |
{ |
|
179 |
if( mGhostIsUp[row] ) |
|
180 |
{ |
|
181 |
int a = computeGhostAngle(basicAngle,angle,speed); |
|
182 |
if( angleIsGhost(a,basicAngle) ) |
|
183 |
{ |
|
184 |
changeRow(row,false); |
|
185 |
mUpRight--; |
|
186 |
if( mNumRight==1 ) enableGhostAxis(false); |
|
187 |
} |
|
188 |
return a; |
|
189 |
} |
|
190 |
else return computeNearestAngle(basicAngle,angle,speed); |
|
191 |
} |
|
192 |
} |
|
70 | 193 |
} |
71 | 194 |
|
72 | 195 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
73 | 196 |
|
74 |
private float getAngle()
|
|
197 |
private int computeRowBitmap(boolean[] up)
|
|
75 | 198 |
{ |
76 |
int pointNum = mRotationAngle.getNumPoints(); |
|
77 |
return pointNum>=1 ? mRotationAngle.getPoint(pointNum-1).get0() : 0; |
|
199 |
int ret = 0; |
|
200 |
int tmp = 1; |
|
201 |
|
|
202 |
for(int l=0; l<mNumLayer0; l++) |
|
203 |
{ |
|
204 |
if( up[l] ) ret += tmp; |
|
205 |
tmp *= 2; |
|
206 |
} |
|
207 |
|
|
208 |
return ret; |
|
209 |
} |
|
210 |
|
|
211 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
212 |
|
|
213 |
private void enableGhostAxis(boolean enable) |
|
214 |
{ |
|
215 |
mParent.enableGhostAxis(enable); |
|
216 |
} |
|
217 |
|
|
218 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
219 |
|
|
220 |
private void changeTotalGhostAngle(int diff) |
|
221 |
{ |
|
222 |
mGhostN += diff; |
|
223 |
mGhostN %= 360; |
|
224 |
mGhostAngleN.set0(mGhostN*mGhostAngle); |
|
225 |
} |
|
226 |
|
|
227 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
228 |
|
|
229 |
private void changeRow(int row, boolean up) |
|
230 |
{ |
|
231 |
mGhostIsUp[row] = up; |
|
232 |
int rowBitmap = computeRowBitmap(mGhostIsUp); |
|
233 |
mGhostEffect1.setMeshAssociation( rowBitmap , -1); |
|
234 |
} |
|
235 |
|
|
236 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
237 |
// TODO |
|
238 |
|
|
239 |
private int computeGhostAngle(int basicAngle, float angle, float speed) |
|
240 |
{ |
|
241 |
int basicDeg = 360/basicAngle; |
|
242 |
int numRot = (int)(angle/basicDeg + 0.5f); |
|
243 |
if( angle< -(basicDeg*0.5) ) numRot-=1; |
|
244 |
if( numRot==0 && speed>1.1f ) numRot = (angle>0 ? 1:-1); |
|
245 |
return basicDeg*numRot; |
|
246 |
} |
|
247 |
|
|
248 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
249 |
// END GHOST |
|
250 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
251 |
|
|
252 |
private int computeNearestAngle(int basicAngle, float angle, float speed) |
|
253 |
{ |
|
254 |
int basicDeg = 360/basicAngle; |
|
255 |
int numRot = (int)(angle/basicDeg + 0.5f); |
|
256 |
if( angle< -(basicDeg*0.5) ) numRot-=1; |
|
257 |
if( numRot==0 && speed>1.1f ) numRot = (angle>0 ? 1:-1); |
|
258 |
return basicDeg*numRot; |
|
259 |
} |
|
260 |
|
|
261 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
262 |
|
|
263 |
private int computeNearestAngle(int axisIndex, int row, int basicAngle, float angle, float speed) |
|
264 |
{ |
|
265 |
if( mGhostAngle==0 || axisIndex!=0 ) return computeNearestAngle(basicAngle,angle,speed); |
|
266 |
else return computeGhostAngle(row,basicAngle,angle,speed); |
|
78 | 267 |
} |
79 | 268 |
|
80 | 269 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
81 | 270 |
|
82 |
VertexEffectRotate getEffect()
|
|
271 |
private float getAngle()
|
|
83 | 272 |
{ |
84 |
return mRotateEffect; |
|
273 |
int pointNum = mRotationAngle.getNumPoints(); |
|
274 |
return pointNum>=1 ? mRotationAngle.getPoint(pointNum-1).get0() : 0; |
|
85 | 275 |
} |
86 | 276 |
|
87 | 277 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
88 | 278 |
// API |
89 | 279 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
280 |
// the rotation has fully finished (everything including the last mini 'come back'). Delete it. |
|
90 | 281 |
|
91 |
synchronized float removeRotationNow()
|
|
282 |
synchronized float removeRotation() |
|
92 | 283 |
{ |
93 | 284 |
float angle = getAngle(); |
94 | 285 |
|
... | ... | |
101 | 292 |
} |
102 | 293 |
|
103 | 294 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
295 |
// we have just lifted the finger |
|
104 | 296 |
|
105 |
long finishRotationNow(EffectListener listener, int basicAngle, float finishAngle, float avgSpeed)
|
|
297 |
long finishRotation(EffectListener listener, int axisIndex, int row, int basicAngle, float finishAngle, float avgSpeed)
|
|
106 | 298 |
{ |
107 |
int nearestAngleInDegrees = computeNearestAngle(basicAngle,finishAngle,avgSpeed); |
|
299 |
int nearestAngleInDegrees = computeNearestAngle(axisIndex,row,basicAngle,finishAngle,avgSpeed);
|
|
108 | 300 |
|
109 | 301 |
mRotationState = STATE_FINISH; |
110 | 302 |
float angle = getAngle(); |
... | ... | |
124 | 316 |
} |
125 | 317 |
|
126 | 318 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
319 |
// rotation has begun and we have just moved the finger a bit |
|
127 | 320 |
|
128 | 321 |
void continueRotation(float angleInDegrees) |
129 | 322 |
{ |
... | ... | |
131 | 324 |
} |
132 | 325 |
|
133 | 326 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
327 |
// this is 'programmatic' rotation - i.e. for example the one induced by the 'backMove' button. |
|
134 | 328 |
|
135 |
synchronized long addNewRotation(EffectListener listener, Static3D axis, int axisIndex, int rowBitmap, int angle, long durationMillis )
|
|
329 |
synchronized long addRotation(EffectListener listener, Static3D axis, int axisIndex, int rowBitmap, int angle, long durationMillis ) |
|
136 | 330 |
{ |
137 | 331 |
int mult = 1; |
138 | 332 |
|
139 | 333 |
if( mRotationState==STATE_ROTATE ) return 0; |
140 |
if( mRotationState==STATE_FINISH ) { removeRotationNow(); mult = -1; }
|
|
334 |
if( mRotationState==STATE_FINISH ) { removeRotation(); mult = -1; } |
|
141 | 335 |
|
142 | 336 |
mRotationState = STATE_ROTATE; |
143 |
mCurrentRotAxis = axisIndex;
|
|
144 |
mRotRowBitmap= mParent.computeBandagedBitmap(rowBitmap,axisIndex); |
|
337 |
mCurrentRotAxis= axisIndex; |
|
338 |
mRotRowBitmap = mParent.computeBandagedBitmap(rowBitmap,axisIndex);
|
|
145 | 339 |
mRotationAngleStatic.set0(0.0f); |
146 | 340 |
mRotationAxis.set(axis); |
147 | 341 |
mRotationAngle.setDuration(durationMillis); |
... | ... | |
155 | 349 |
} |
156 | 350 |
|
157 | 351 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
352 |
// i.e. we just touched the screen, moved it a little bit and the TouchControl has figured out |
|
353 |
// along which axis we are going to rotate. |
|
158 | 354 |
|
159 |
synchronized boolean beginNewRotation(Static3D axis, int axisIndex, int row )
|
|
355 |
synchronized boolean beginRotation(Static3D axis, int axisIndex, int row ) |
|
160 | 356 |
{ |
161 | 357 |
if( mRotationState==STATE_ROTATE ) return false; |
162 |
if( mRotationState==STATE_FINISH ) removeRotationNow();
|
|
358 |
if( mRotationState==STATE_FINISH ) removeRotation(); |
|
163 | 359 |
|
164 | 360 |
mRotationState = STATE_ROTATE; |
165 |
mCurrentRotAxis = axisIndex;
|
|
166 |
mRotRowBitmap= mParent.computeBandagedBitmap( (1<<row),axisIndex ); |
|
361 |
mCurrentRotAxis= axisIndex; |
|
362 |
mRotRowBitmap = mParent.computeBandagedBitmap( (1<<row),axisIndex );
|
|
167 | 363 |
mRotationAngleStatic.set0(0.0f); |
168 | 364 |
mRotationAxis.set(axis); |
169 | 365 |
mRotationAngle.add(mRotationAngleStatic); |
Also available in: Unified diff
progress with Ghost rotations.