1 /* BurrTools
2  *
3  * BurrTools is the legal property of its developers, whose
4  * names are listed in the COPYRIGHT file, which is included
5  * within the source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11 
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16 
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  */
21 #include "disasmtomoves.h"
22 
23 #include "disassembly.h"
24 #include "disassemblernode.h"
25 
disasmToMoves_c(const separation_c * tr,unsigned int sz,unsigned int max)26 disasmToMoves_c::disasmToMoves_c(const separation_c * tr, unsigned int sz, unsigned int max) : size(sz), maxPieceName(max) {
27 
28   tree = new separation_c(tr);
29 
30   moves = new float[maxPieceName*4];
31   mv = new bool[maxPieceName];
32 }
33 
~disasmToMoves_c()34 disasmToMoves_c::~disasmToMoves_c() {
35   delete [] moves;
36   delete [] mv;
37   delete tree;
38 }
39 
setStep(float step,bool fadeOut,bool center_active)40 void disasmToMoves_c::setStep(float step, bool fadeOut, bool center_active) {
41 
42   int s = int(step);
43   float frac = step - s;
44 
45   // a temporary array, used to save the 2nd placement for the interpolation */
46   float * moves2 = new float[maxPieceName*4];
47 
48   for (unsigned int i = 0; i < 4 * maxPieceName; i++) {
49     moves[i] = moves2[i] = 0;
50   }
51 
52   /* what we do is go twice through the tree and linearly interpolate between
53    * the 2 states that we have in in the two nodes that we are currently in between
54    *
55    * this is done with the weight value (1-frac and frac)
56    */
57   if (tree) {
58 
59     /* get the 2 possible positions between we have to interpolate */
60     doRecursive(tree, s  , moves, center_active, 0, 0, 0);
61     doRecursive(tree, s+1, moves2, center_active, 0, 0, 0);
62 
63     // interpolate and check, which piece moves right now
64     for (unsigned int i = 0; i < maxPieceName; i++) {
65       mv[i] = ((moves[4*i+0] != moves2[4*i+0]) || (moves[4*i+1] != moves2[4*i+1]) || (moves[4*i+2] != moves2[4*i+2]));
66       moves[4*i+0] = (1-frac)*moves[4*i+0] + frac*moves2[4*i+0];
67       moves[4*i+1] = (1-frac)*moves[4*i+1] + frac*moves2[4*i+1];
68       moves[4*i+2] = (1-frac)*moves[4*i+2] + frac*moves2[4*i+2];
69       moves[4*i+3] = (1-frac)*moves[4*i+3] + frac*moves2[4*i+3];
70     }
71 
72     if (!fadeOut)
73       for (unsigned int i = 0; i < maxPieceName; i++)
74         if (moves[4*i+3] > 0) moves[4*i+3] = 1;
75 
76   }
77 
78   delete [] moves2;
79 }
80 
getX(unsigned int piece)81 float disasmToMoves_c::getX(unsigned int piece) {
82   bt_assert(piece < maxPieceName);
83   return moves[4*piece+0];
84 }
getY(unsigned int piece)85 float disasmToMoves_c::getY(unsigned int piece) {
86   bt_assert(piece < maxPieceName);
87   return moves[4*piece+1];
88 }
getZ(unsigned int piece)89 float disasmToMoves_c::getZ(unsigned int piece) {
90   bt_assert(piece < maxPieceName);
91   return moves[4*piece+2];
92 }
getA(unsigned int piece)93 float disasmToMoves_c::getA(unsigned int piece) {
94   bt_assert(piece < maxPieceName);
95   return moves[4*piece+3];
96 }
moving(unsigned int piece)97 bool disasmToMoves_c::moving(unsigned int piece) {
98   bt_assert(piece < maxPieceName);
99   return mv[piece];
100 }
101 
mabs(int a)102 static int mabs(int a) {
103   if (a > 0)
104     return a;
105   else
106     return -a;
107 }
108 
mmax(int a,int b)109 static int mmax(int a, int b) {
110   if (a>b)
111     return a;
112   else
113     return b;
114 }
115 
116 /* this is the core function that walks through the tree, let's see if I can
117  * describe what's going on in here
118  *
119  * let's start with the parameters:
120  *    tree is the current subtree to walk through
121  *    step is the step to show inside this tree, if step is negative or bigger than
122  *                the steps required for this tree we are somewhere outside the tree
123  *    weight is used for the linear interpolation it is a value between 0 and 1 including
124  *                values are multiplied by this value and then the 2 end points are added
125  *    cx, cy, cz are the centre to display the current tree
126  */
doRecursive(const separation_c * tree,int step,float * array,bool center_active,int cx,int cy,int cz)127 int disasmToMoves_c::doRecursive(const separation_c * tree, int step, float * array, bool center_active, int cx, int cy, int cz) {
128 
129   bt_assert(tree);
130 
131   /* first check, if we are inside this tree node, this is the case when
132    * the number of steps is between 0 and the number of steps in this node
133    *
134    * we do need to include "=" here because the last move will be the separation and
135    * we don't want to display that move as said in the state but rather a bit
136    * more adequate for the screen
137    *
138    * in the state the removed part would be removed by 10000 units
139    */
140   if ((step >= 0) && ((unsigned int)step >= tree->getMoves())) {
141 
142     /* so, this is the path for after the current node, the first thing
143      * is to find out in which directions the pieces that are removed
144      * are removed, then define the new centre for the removed
145      * part and call the subtrees
146      *
147      * we can be sure that we have disassembled the current subpuzzle,
148      * so we need to display both subparts separated. It is possible that
149      * one or both subparts are only one piece. In this case the tree
150      * doesn't contain the subtrees
151      *
152      * take the last state, in this state the removed pieces have a
153      * distance grater 1000
154      */
155     const state_c * s = tree->getState(tree->getMoves());
156 
157     /* find one of the removed pieces and one of the left pieces */
158     unsigned int pc, pc2;
159 
160     for (pc = 0; pc < tree->getPieceNumber(); pc++)
161       if (s->pieceRemoved(pc))
162         break;
163 
164     for (pc2 = 0; pc2 < tree->getPieceNumber(); pc2++)
165       if (!s->pieceRemoved(pc2))
166         break;
167 
168     /* find out the direction the piece is removed */
169     int dx, dy, dz;
170 
171     dx = dy = dz = 0;
172 
173     if (s->getX(pc) >  10000) dx = size;
174     if (s->getX(pc) < -10000) dx = - size;
175     if (s->getY(pc) >  10000) dy = size;
176     if (s->getY(pc) < -10000) dy = - size;
177     if (s->getZ(pc) >  10000) dz = size;
178     if (s->getZ(pc) < -10000) dz = - size;
179 
180     int steps, steps2;
181 
182     /* place the removed pieces with the new centre */
183     if (tree->getRemoved()) {
184 
185       /* if we use the center_active option we need to keep the removed part stationary
186        * and place the pieces where they belong,
187        *
188        * otherwise we place the removed part somewhere out of the way
189        */
190       if (center_active)
191         steps = doRecursive(tree->getRemoved(), step - (int)tree->getMoves(), array, center_active,
192             tree->getState(tree->getMoves()-1)->getX(pc) + cx - tree->getRemoved()->getState(0)->getX(0),
193             tree->getState(tree->getMoves()-1)->getY(pc) + cy - tree->getRemoved()->getState(0)->getY(0),
194             tree->getState(tree->getMoves()-1)->getZ(pc) + cz - tree->getRemoved()->getState(0)->getZ(0));
195       else
196         steps = doRecursive(tree->getRemoved(), step - (int)tree->getMoves(), array, center_active, cx+dx, cy+dy, cz+dz);
197 
198     } else {
199 
200       const state_c * s2 = tree->getState(tree->getMoves()-1);
201 
202       /* if there is no removed tree, the pieces need to vanish */
203       if (array)
204         for (unsigned int p = 0; p < tree->getPieceNumber(); p++)
205           if (s->pieceRemoved(p)) {
206             array[4*tree->getPieceName(p)+0] += dx+cx+((mabs(s->getX(p))<10000)?(s->getX(p)):(s2->getX(p)));
207             array[4*tree->getPieceName(p)+1] += dy+cy+((mabs(s->getY(p))<10000)?(s->getY(p)):(s2->getY(p)));
208             array[4*tree->getPieceName(p)+2] += dz+cz+((mabs(s->getZ(p))<10000)?(s->getZ(p)):(s2->getZ(p)));
209             array[4*tree->getPieceName(p)+3] += 0;
210           }
211 
212       steps = 0;
213     }
214 
215     /* place the left over pieces in the old centre */
216     if (tree->getLeft()) {
217 
218       /* if we use center_active switch, we first display the removed part and need to move the left
219        * over part out of the way, this is done via the d. values in the negative direction of the
220        * removal of the pieces
221        *
222        * if we don't use the center_active option, the left over part stays in the middle
223        */
224       if (center_active && (step - (int)tree->getMoves() < steps) && (tree->getRemoved()))
225         steps2 = doRecursive(tree->getLeft(), step - (int)tree->getMoves() - steps, array, center_active, cx-dx, cy-dy, cz-dz);
226       else
227         steps2 = doRecursive(tree->getLeft(), step - (int)tree->getMoves() - steps, array, center_active, cx, cy, cz);
228 
229       /* if the steps tell us that we are currenlty animating the removed part
230        * and there actually _is_ a removed animation, we hide all
231        * pieces that are not removed
232        */
233       if (array && center_active && (step - (int)tree->getMoves() < steps) && (tree->getRemoved())) {
234         for (unsigned int p = 0; p < tree->getPieceNumber(); p++)
235           if (!s->pieceRemoved(p)) {
236             array[4*tree->getPieceName(p)+3] = 0;
237           }
238       }
239 
240     } else {
241 
242       if (array)
243         for (unsigned int p = 0; p < tree->getPieceNumber(); p++)
244           if (!s->pieceRemoved(p)) {
245             array[4*tree->getPieceName(p)+0] += cx+s->getX(p);
246             array[4*tree->getPieceName(p)+1] += cy+s->getY(p);
247             array[4*tree->getPieceName(p)+2] += cz+s->getZ(p);
248             array[4*tree->getPieceName(p)+3] += 0;
249           }
250 
251       steps2 = 0;
252     }
253 
254     return tree->getMoves() + steps + steps2;
255   }
256 
257   /* all right the number of steps shows us that we have the task to disassemble
258    * this node, so get the state and place the pieces at the right position
259    *
260    * we also have to place the pieces at their initial position, when we are
261    * before the current node
262    */
263   const state_c * s = tree->getState(mmax(step, 0));
264 
265   if (array)
266     for (unsigned int i = 0; i < tree->getPieceNumber(); i++) {
267       array[4*tree->getPieceName(i)+0] += cx+s->getX(i);
268       array[4*tree->getPieceName(i)+1] += cy+s->getY(i);
269       array[4*tree->getPieceName(i)+2] += cz+s->getZ(i);
270       array[4*tree->getPieceName(i)+3] += 1;
271     }
272 
273   int steps  = tree->getRemoved() ? doRecursive(tree->getRemoved(), step - tree->getMoves()        , 0, center_active, 0, 0, 0) : 0;
274   int steps2 = tree->getLeft()    ? doRecursive(tree->getLeft()   , step - tree->getMoves() - steps, 0, center_active, 0, 0, 0) : 0;
275 
276   return tree->getMoves() + steps + steps2;
277 }
278 
279 
280 
281 
282 
283 
284 
fixedPositions_c(const disassemblerNode_c * nd,const std::vector<unsigned int> & pc,unsigned int pcs)285 fixedPositions_c::fixedPositions_c(const disassemblerNode_c * nd, const std::vector<unsigned int> & pc, unsigned int pcs) {
286 
287   pieces = pcs;
288   x = new int[pieces];
289   y = new int[pieces];
290   z = new int[pieces];
291   visible = new bool[pieces];
292 
293   for (unsigned int p = 0; p < pieces; p++) {
294     visible[p] = false;
295     x[p] = y[p] = z[p] = 0;
296   }
297 
298   for (unsigned int p = 0; p < pc.size(); p++) {
299 
300     unsigned int pi = pc[p];
301 
302     bt_assert(pi < pieces);
303 
304     x[pi] = (int)nd->getX(p);
305     y[pi] = (int)nd->getY(p);
306     z[pi] = (int)nd->getZ(p);
307 
308     visible[pi] = true;
309   }
310 }
311 
fixedPositions_c(const fixedPositions_c * nd)312 fixedPositions_c::fixedPositions_c(const fixedPositions_c * nd) {
313 
314   pieces = nd->pieces;
315   x = new int[pieces];
316   y = new int[pieces];
317   z = new int[pieces];
318   visible = new bool[pieces];
319 
320   for (unsigned int p = 0; p < pieces; p++) {
321     x[p] = nd->x[p];
322     y[p] = nd->y[p];
323     z[p] = nd->z[p];
324     visible[p] = nd->visible[p];
325   }
326 }
327 
~fixedPositions_c(void)328 fixedPositions_c::~fixedPositions_c(void) {
329   delete [] x;
330   delete [] y;
331   delete [] z;
332   delete [] visible;
333 }
334 
getX(unsigned int piece)335 float fixedPositions_c::getX(unsigned int piece) { bt_assert(piece < pieces); return x[piece]; }
getY(unsigned int piece)336 float fixedPositions_c::getY(unsigned int piece) { bt_assert(piece < pieces); return y[piece]; }
getZ(unsigned int piece)337 float fixedPositions_c::getZ(unsigned int piece) { bt_assert(piece < pieces); return z[piece]; }
getA(unsigned int piece)338 float fixedPositions_c::getA(unsigned int piece) { return visible[piece] ? 1 : 0; }
moving(unsigned int)339 bool fixedPositions_c::moving(unsigned int /*piece*/) { return false; }
340 
341