Project

General

Profile

Download (29.7 KB) Statistics
| Branch: | Revision:

library / src / main / java / org / distorted / library / DistortedCubesGrid.java @ ce7f3833

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.library;
21

    
22
import java.nio.ByteBuffer;
23
import java.nio.ByteOrder;
24
import java.util.ArrayList;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27

    
28
class DistortedCubesGrid extends DistortedObjectGrid
29
   {
30
   private static final float R = 0.2f;
31
   private static final float FRONTZ = 0.5f;
32
   private static final float BACKZ  =-0.5f;
33
   
34
   private static final int NORTH = 0;
35
   private static final int WEST  = 1;
36
   private static final int EAST  = 2;
37
   private static final int SOUTH = 3;
38

    
39
   private static final int NW = 0;
40
   private static final int NE = 1;
41
   private static final int SW = 2;
42
   private static final int SE = 3;
43

    
44
   private static final boolean BACK  = true;
45
   private static final boolean FRONT = false;
46
   private static final boolean UPPER = false;
47
   private static final boolean LOWER = true;
48
   
49
   private static final float[] mNormalX = new float[4];
50
   private static final float[] mNormalY = new float[4];
51
   private static final float[] mNormalZ = new float[4];
52

    
53
   private class Edge
54
     {
55
     final int side; 
56
     final int row;
57
     final int col;
58
     
59
     public Edge(int s, int r, int c)
60
       {
61
       side= s; 
62
       row = r;
63
       col = c;
64
       }
65
     }
66
   
67
   private int mCols, mRows;
68
   private short[][] mCubes;
69
   private ArrayList<Edge> mEdges = new ArrayList<>();
70

    
71
   private boolean addEmpty1; // add an initial empty vertex? ( that would be because the initial block
72
                              // of land is in the top-right quarter (or bottom-left) and thus the very
73
                              // first triangle is counter-clockwise)
74
   private boolean addEmpty2; // add an empty vertex when shifting from front to the side (that happens
75
                              // iff the last front block is in the front-left or bottom-right quarter)
76
   private boolean addEmpty3; // add an empty vertex when shifting from the side to the back. (that
77
                              // happens iff the first back block is in the top right or bottom-left
78
                              // quarter, i.e. actually addEmpty3 = addEmpty1.
79

    
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81
// a Block is split into two triangles along the NE-SW line iff it is in the top-right
82
// or bottom-left quadrant of the grid.
83

    
84
   private boolean isNE(int row,int col)
85
     {
86
     return ( (row<=(mRows-1)/2)^(col<=(mCols-1)/2) );
87
     }
88

    
89
///////////////////////////////////////////////////////////////////////////////////////////////////
90

    
91
   private int computeDataLength(boolean frontOnly)
92
      {
93
      int frontWalls=0, frontSegments=0, sideWalls=0, sideBends=0, triangleShifts=0, rowJumpShifts=0;
94
      int shiftCol = (mCols-1)/2;
95

    
96
      boolean seenLand=false;
97
      boolean lastBlockIsNE=false;
98
      boolean seenBlockInRow;
99
      boolean thisBlockIsNE;        // the block we are currently looking at is split into
100
                                    // two triangles along the NE-SW line (rather than NW-SE)
101

    
102
      for(int i=0; i<mRows; i++)
103
         {
104
         if( mCols>=2 && (mCubes[i][shiftCol]%2 == 1) && (mCubes[i][shiftCol+1]%2 == 1) ) triangleShifts++;
105

    
106
         seenBlockInRow=false;
107

    
108
         for(int j=0; j<mCols; j++)
109
            {
110
            if( mCubes[i][j]%2 == 1 )  // land
111
              {
112
              thisBlockIsNE = isNE(i,j);
113

    
114
              if( !seenBlockInRow )
115
                {
116
                if( thisBlockIsNE^lastBlockIsNE ) rowJumpShifts++;
117
                seenBlockInRow=true;
118
                }
119

    
120
              lastBlockIsNE = thisBlockIsNE;
121

    
122
              if( !seenLand )
123
                {
124
                addEmpty1 = addEmpty3 = lastBlockIsNE;
125
                seenLand=true;
126
                }
127

    
128
              frontWalls++;
129
              if( j==mCols-1 || mCubes[i][j+1]%2 == 0 ) frontSegments++;
130
              }
131
              
132
            if( (i==0 && mCubes[i][j]!=2) || (i!=0 && mCubes[i][j] != mCubes[i-1][j  ]) ) sideWalls++; // up
133
            if( (j==0 && mCubes[i][j]!=2) || (j!=0 && mCubes[i][j] != mCubes[i  ][j-1]) ) sideWalls++; // left
134
            if( i==mRows-1 && mCubes[i][j]!=2                                           ) sideWalls++; // bottom
135
            if( j==mCols-1 && mCubes[i][j]!=2                                           ) sideWalls++; // right
136
            }
137
         }
138

    
139
      addEmpty2 = !lastBlockIsNE;
140

    
141
      int edges= mEdges.size();
142
      
143
      for(int i=0; i<edges; i++) 
144
        {
145
        Edge curr = mEdges.get(i);
146
        Edge next = getNextEdge(curr);
147
        int startX = curr.col;
148
        int startY = curr.row;
149
        int startS = curr.side;
150
        
151
        do
152
          {
153
          if( next.side != curr.side ) sideBends++; 
154
          curr  = next; 
155
          next = getNextEdge(curr);
156
          }
157
        while( curr.col!=startX || curr.row!=startY || curr.side!=startS );
158
        }
159

    
160
      int frontVert = 2*( frontWalls + 2*frontSegments - 1) +3*triangleShifts + rowJumpShifts;
161
      int sideVert  = 2*( sideWalls + sideBends + edges -1);
162

    
163
      // no we don't add addEmpty1 because this is already included in the rowJumpShifts
164
      int dataL = frontOnly ? frontVert : (frontVert+1) + (1+sideVert+1) + (1+frontVert) +(addEmpty2?1:0) + (addEmpty3?1:0);
165

    
166
      android.util.Log.e("CUBES","triangleShifts="+triangleShifts+" rowJumpShifts="+rowJumpShifts);
167
      android.util.Log.e("CUBES","addEmpty1="+addEmpty1+" addEmpty2="+addEmpty2+" addEmpty3="+addEmpty3);
168
      android.util.Log.e("CUBES","frontVert="+frontVert+" sideVert="+sideVert);
169
      android.util.Log.e("CUBES", "frontW="+frontWalls+" fSegments="+frontSegments+" sWalls="+sideWalls+" sSegments="+edges+" sideBends="+sideBends+" dataLen="+dataL );
170
      
171
      return dataL<0 ? 0:dataL;
172
      }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175
/*
176
   private static String debug(short[] val)
177
     {
178
     String ret="";j
179
     
180
     for(int i=0; i<val.length; i++) ret+=(" "+val[i]); 
181
     
182
     return ret;
183
     }
184
*/
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186
/*
187
   private static String debug(float[] val, int stop)
188
     {
189
     String ret="";
190

    
191
     for(int i=0; i<val.length; i++) 
192
        {
193
        if( i%stop==0 ) ret+="\n";
194
        ret+=(" "+val[i]);
195
        }
196

    
197
     return ret;
198
     }
199
*/  
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201
/*
202
   private static String debug(Edge e)
203
     {
204
     String d = "";
205
     
206
     switch(e.side)
207
       {
208
       case NORTH: d+="NORTH "; break;
209
       case SOUTH: d+="SOUTH "; break;
210
       case WEST : d+="WEST  "; break;
211
       case EAST : d+="EAST  "; break;
212
       }
213
     
214
     d+=("("+e.row+","+e.col+")");
215
     
216
     return d;
217
     }   
218
*/ 
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220
// desc is guaranteed to be padded with 0s in the end (DistortedCubes constructor does it)
221

    
222
   private void prepareDataStructures(int cols, String desc, boolean frontOnly)
223
     {
224
     mRows     =0;
225
     mCols     =0;
226
     dataLength=0;
227
     
228
     if( cols>0 && desc.contains("1") )
229
       {
230
       mCols = cols;
231
       mRows = desc.length()/cols;
232

    
233
       mCubes = new short[mRows][mCols];
234
       
235
       for(int j=0; j<mCols; j++)
236
         for(int i=0; i<mRows; i++)
237
           mCubes[i][j] = (short)(desc.charAt(i*mCols+j) == '1' ? 1:0);
238
       
239
       markRegions();
240
       dataLength = computeDataLength(frontOnly);
241
       }
242
     }
243
 
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245
// Mark all the 'regions' of our grid  - i.e. separate pieces of 'land' (connected blocks that will 
246
// be rendered) and 'water' (connected holes in between) with integers. Each connected block of land
247
// gets a unique odd integer, each connected block of water a unique even integer.
248
//
249
// Water on the edges of the grid is also considered connected to itself!   
250
//   
251
// This function also creates a list of 'Edges'. Each Edge is a data structure from which later on we
252
// will start building the side walls of each connected block of land (and sides of holes of water
253
// inside)   
254
   
255
   private void markRegions()
256
     {
257
     int i, j, numWater=1, numLand=0;
258
     
259
     for(i=0; i<mRows;i++) if( mCubes[      i][      0]==0 ) markRegion((short)2,      i,       0);
260
     for(i=0; i<mRows;i++) if( mCubes[      i][mCols-1]==0 ) markRegion((short)2,      i, mCols-1);
261
     for(i=0; i<mCols;i++) if( mCubes[0      ][      i]==0 ) markRegion((short)2,      0,       i);
262
     for(i=0; i<mCols;i++) if( mCubes[mRows-1][      i]==0 ) markRegion((short)2,mRows-1,       i);
263
           
264
     for(i=0; i<mRows; i++)
265
        for(j=0; j<mCols; j++)
266
           {
267
           if( mCubes[i][j] == 0 ) { numWater++; markRegion( (short)(2*numWater ),i,j); mEdges.add(new Edge(NORTH,i,j)); }
268
           if( mCubes[i][j] == 1 ) { numLand ++; markRegion( (short)(2*numLand+1),i,j); mEdges.add(new Edge(NORTH,i,j)); }
269
           }
270
     
271
     // now we potentially need to kick out some Edges - precisely the edges with water inside -
272
     // which are surrounded by more than one type of land. Otherwise the following does not work:
273
     //
274
     // 0 1 0
275
     // 1 0 1
276
     // 0 1 0
277
     //
278
     // The 'water inside' edges that did not get kicked out by this procedure need to be transformed
279
     // with Edge(NORTH,row,col) -> Edge(SOUTH,row-1,col) so that later on normals work correctly
280
     // (Edge always needs to point out from land to water for that)
281
     
282
     int numEdges= mEdges.size();
283
     short initLand;
284
     int initCol, initRow;
285
     boolean kicked;
286
     Edge e;
287
     
288
     for(i=0; i<numEdges; i++) 
289
       {
290
       e = mEdges.get(i);
291
       initRow= e.row;
292
       initCol= e.col;
293
         
294
       //android.util.Log.e("CUBES", "checking edge "+debug(e));
295
             
296
       if( mCubes[initRow][initCol]%2==0 )
297
         {
298
         kicked = false; 
299
         initLand = mCubes[initRow-1][initCol];
300
         
301
         do
302
           {
303
           e = getNextEdge(e); 
304
           //android.util.Log.e("CUBES", " next edge "+debug(e));   
305
       
306
           switch(e.side)
307
             {
308
             case NORTH: if( initLand!=mCubes[e.row-1][e.col  ] ) kicked=true; break;
309
             case SOUTH: if( initLand!=mCubes[e.row+1][e.col  ] ) kicked=true; break;
310
             case WEST:  if( initLand!=mCubes[e.row  ][e.col-1] ) kicked=true; break;
311
             case EAST:  if( initLand!=mCubes[e.row  ][e.col+1] ) kicked=true; break;
312
             }
313
           
314
           if( kicked )
315
             {
316
             //android.util.Log.e("CUBES", "kicking out edge!");
317
             mEdges.remove(i);
318
             i--;
319
             numEdges--; 
320
             }
321
           }
322
         while( kicked==false && (e.col!=initCol || e.row!=initRow || e.side!=NORTH) );
323
         
324
         if( kicked==false )
325
           {
326
           mEdges.set(i, new Edge(SOUTH,e.row-1,e.col)); 
327
           }
328
         }
329
       }
330
     }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333
// when calling, make sure that newVal != val
334
   
335
   private void markRegion(short newVal, int row, int col)
336
     {
337
     short val = mCubes[row][col];
338
     mCubes[row][col] = newVal;
339
     
340
     if( row>0       && mCubes[row-1][col  ]==val ) markRegion(newVal, row-1, col  );
341
     if( row<mRows-1 && mCubes[row+1][col  ]==val ) markRegion(newVal, row+1, col  );
342
     if( col>0       && mCubes[row  ][col-1]==val ) markRegion(newVal, row  , col-1);
343
     if( col<mCols-1 && mCubes[row  ][col+1]==val ) markRegion(newVal, row  , col+1);
344
     }
345
   
346
///////////////////////////////////////////////////////////////////////////////////////////////////
347
   
348
   private void createNormals(boolean front, int row, int col)
349
     {
350
     int td,lr; 
351
      
352
     int nw = (col>0       && row>0      ) ? (mCubes[row-1][col-1]%2) : 0;
353
     int w  = (col>0                     ) ? (mCubes[row  ][col-1]%2) : 0;
354
     int n  = (               row>0      ) ? (mCubes[row-1][col  ]%2) : 0;
355
     int c  =                                (mCubes[row  ][col  ]%2);
356
     int sw = (col>0       && row<mRows-1) ? (mCubes[row+1][col-1]%2) : 0;
357
     int s  = (               row<mRows-1) ? (mCubes[row+1][col  ]%2) : 0;
358
     int ne = (col<mCols-1 && row>0      ) ? (mCubes[row-1][col+1]%2) : 0;
359
     int e  = (col<mCols-1               ) ? (mCubes[row  ][col+1]%2) : 0;
360
     int se = (col<mCols-1 && row<mRows-1) ? (mCubes[row+1][col+1]%2) : 0;
361

    
362
     if(front)
363
       {
364
       mNormalZ[0] = 1.0f;
365
       mNormalZ[1] = 1.0f;
366
       mNormalZ[2] = 1.0f;
367
       mNormalZ[3] = 1.0f;
368
       }
369
     else
370
       {
371
       mNormalZ[0] =-1.0f;
372
       mNormalZ[1] =-1.0f;
373
       mNormalZ[2] =-1.0f;
374
       mNormalZ[3] =-1.0f;
375
       }
376

    
377
     td = nw+n-w-c;
378
     lr = c+n-w-nw;
379
     if( td<0 ) td=-1;
380
     if( td>0 ) td= 1;
381
     if( lr<0 ) lr=-1;
382
     if( lr>0 ) lr= 1;
383
     mNormalX[0] = lr*R;
384
     mNormalY[0] = td*R;
385
     
386
     td = w+c-sw-s;
387
     lr = c+s-w-sw;
388
     if( td<0 ) td=-1;
389
     if( td>0 ) td= 1;
390
     if( lr<0 ) lr=-1;
391
     if( lr>0 ) lr= 1;
392
     mNormalX[1] = lr*R;
393
     mNormalY[1] = td*R;
394
     
395
     td = n+ne-c-e;
396
     lr = e+ne-c-n;
397
     if( td<0 ) td=-1;
398
     if( td>0 ) td= 1;
399
     if( lr<0 ) lr=-1;
400
     if( lr>0 ) lr= 1;
401
     mNormalX[2] = lr*R;
402
     mNormalY[2] = td*R;
403
     
404
     td = c+e-s-se;
405
     lr = e+se-c-s;
406
     if( td<0 ) td=-1;
407
     if( td>0 ) td= 1;
408
     if( lr<0 ) lr=-1;
409
     if( lr>0 ) lr= 1;
410
     mNormalX[3] = lr*R;
411
     mNormalY[3] = td*R;
412
     /*
413
     android.util.Log.d("CUBES", "row="+row+" col="+col);
414
     android.util.Log.d("CUBES", mNormalX[0]+" "+mNormalY[0]);
415
     android.util.Log.d("CUBES", mNormalX[1]+" "+mNormalY[1]);
416
     android.util.Log.d("CUBES", mNormalX[2]+" "+mNormalY[2]);
417
     android.util.Log.d("CUBES", mNormalX[3]+" "+mNormalY[3]);
418
     */
419
     }
420
   
421
///////////////////////////////////////////////////////////////////////////////////////////////////
422

    
423
   private int addFrontVertex(int corner, int vertex, float centerX, float centerY, float vectZ, int col, int row, float[] position, float[] normal, float[] texture)
424
     {
425
     switch(corner)
426
       {
427
       case NW: position[3*vertex  ] = (centerX-0.5f)/mCols;
428
                position[3*vertex+1] = (centerY+0.5f)/mRows;
429
                position[3*vertex+2] = vectZ;
430
                normal[3*vertex  ]   = mNormalX[0];
431
                normal[3*vertex+1]   = mNormalY[0];
432
                normal[3*vertex+2]   = mNormalZ[0];
433
                texture[2*vertex  ]  = (float)col/mCols;
434
                texture[2*vertex+1]  = (float)row/mRows;
435
                return vertex+1;
436
       case SW: position[3*vertex  ] = (centerX-0.5f)/mCols;
437
                position[3*vertex+1] = (centerY-0.5f)/mRows;
438
                position[3*vertex+2] = vectZ;
439
                normal[3*vertex  ]   = mNormalX[1];
440
                normal[3*vertex+1]   = mNormalY[1];
441
                normal[3*vertex+2]   = mNormalZ[1];
442
                texture[2*vertex  ]  = (float)col/mCols;
443
                texture[2*vertex+1]  = (float)(row+1)/mRows;
444
                return vertex+1;
445
       case NE: position[3*vertex  ] = (centerX+0.5f)/mCols;
446
                position[3*vertex+1] = (centerY+0.5f)/mRows;
447
                position[3*vertex+2] = vectZ;
448
                normal[3*vertex  ]   = mNormalX[2];
449
                normal[3*vertex+1]   = mNormalY[2];
450
                normal[3*vertex+2]   = mNormalZ[2];
451
                texture[2*vertex  ]  = (float)(col+1)/mCols;
452
                texture[2*vertex+1]  = (float)row/mRows;
453
                return vertex+1;
454
       case SE: position[3*vertex  ] = (centerX+0.5f)/mCols;
455
                position[3*vertex+1] = (centerY-0.5f)/mRows;
456
                position[3*vertex+2] = vectZ;
457
                normal[3*vertex  ]   = mNormalX[3];
458
                normal[3*vertex+1]   = mNormalY[3];
459
                normal[3*vertex+2]   = mNormalZ[3];
460
                texture[2*vertex  ]  = (float)(col+1)/mCols;
461
                texture[2*vertex+1]  = (float)(row+1)/mRows;
462
       }
463

    
464
     return vertex;
465
     }
466

    
467
///////////////////////////////////////////////////////////////////////////////////////////////////
468

    
469
   private int buildFrontBackGrid(boolean front, int vertex, float[] position, float[] normal, float[] texture)
470
     {
471
     short last, current;
472
     boolean seenLand=false;
473
     boolean lastBlockIsNE = false;
474
     boolean currentBlockIsNE;
475
     float centerX, centerY;
476
     float vectZ = front?FRONTZ:BACKZ;
477

    
478
     for(int i=0; i<mRows; i++)
479
       {
480
       last =0;
481
         
482
       for(int j=0; j<mCols; j++)
483
         {
484
         current = mCubes[i][j];
485

    
486
         if( current%2 == 1 )
487
           {
488
           currentBlockIsNE = isNE(i,j);
489
           centerX = j-(mCols-1.0f)/2.0f;
490
           centerY = (mRows-1.0f)/2.0f-i;
491
      
492
           createNormals(front,i,j);
493

    
494
           if( (last!=current) || (lastBlockIsNE^currentBlockIsNE) )
495
             {
496
             if( seenLand  && (last != current) ) vertex = repeatLast(vertex,position,normal,texture);
497
             vertex= addFrontVertex( currentBlockIsNE ? NW:SW, vertex, centerX, centerY, vectZ, j, i, position, normal, texture);
498
             if( seenLand  && (last != current) ) vertex = repeatLast(vertex,position,normal,texture);
499
             if( lastBlockIsNE^currentBlockIsNE ) vertex = repeatLast(vertex,position,normal,texture);
500
             vertex= addFrontVertex( currentBlockIsNE ? SW:NW, vertex, centerX, centerY, vectZ, j, i, position, normal, texture);
501
             }
502
           vertex= addFrontVertex( currentBlockIsNE ? NE:SE, vertex, centerX, centerY, vectZ, j, i, position, normal, texture);
503
           vertex= addFrontVertex( currentBlockIsNE ? SE:NE, vertex, centerX, centerY, vectZ, j, i, position, normal, texture);
504

    
505
           seenLand = true;
506
           lastBlockIsNE = currentBlockIsNE;
507
           }
508
            
509
         last = current;
510
         }
511
       }
512
     
513
     return vertex;
514
     }
515

    
516
///////////////////////////////////////////////////////////////////////////////////////////////////
517

    
518
   private int repeatLast(int vertex, float[] position, float[] normal, float[] texture)
519
     {
520
     if( vertex>0 )
521
       {
522
       position[3*vertex  ] = position[3*vertex-3];
523
       position[3*vertex+1] = position[3*vertex-2];
524
       position[3*vertex+2] = position[3*vertex-1];
525

    
526
       normal[3*vertex  ]   = normal[3*vertex-3];
527
       normal[3*vertex+1]   = normal[3*vertex-2];
528
       normal[3*vertex+2]   = normal[3*vertex-1];
529

    
530
       texture[2*vertex  ]  = texture[2*vertex-2];
531
       texture[2*vertex+1]  = texture[2*vertex-1];
532
         
533
       vertex++;     
534
       }
535
     
536
     return vertex;
537
     }
538
   
539
///////////////////////////////////////////////////////////////////////////////////////////////////
540

    
541
   private int buildSideGrid(int vertex, float[] position, float[] normal, float[] texture)
542
     {
543
     int edges= mEdges.size();
544

    
545
     if( addEmpty2 ) vertex = repeatLast(vertex,position,normal,texture);
546

    
547
     for(int i=0; i<edges; i++) 
548
       {
549
       vertex = buildIthSide(mEdges.get(i), vertex, position, normal, texture);  
550
       } 
551
      
552
     return vertex;
553
     }
554

    
555
///////////////////////////////////////////////////////////////////////////////////////////////////
556

    
557
   private int buildIthSide(Edge curr, int vertex, float[] position, float[] normal, float[] texture)
558
     {
559
     Edge prev; 
560
     
561
     if( curr.side==NORTH ) // water outside
562
       {
563
       prev = new Edge(WEST,curr.row,curr.col);
564
       }
565
     else                   // land outside; we need to move forward one link because we are going in opposite direction and we need to start from a bend.
566
       {
567
       prev = curr;
568
       curr = new Edge(EAST,curr.row+1,curr.col-1);
569
       }
570
     
571
     int col = curr.col;
572
     int row = curr.row;
573
     int side= curr.side;  
574
     Edge next = getNextEdge(curr);
575
     
576
     addVertex(curr,BACK,LOWER,prev.side,vertex,position,normal,texture);
577
     vertex++;
578
     
579
     do
580
       {
581
       if( prev.side!=curr.side )
582
         {
583
         addVertex(curr,BACK,LOWER,prev.side,vertex,position,normal,texture);
584
         vertex++;
585
         addVertex(curr,BACK,UPPER,prev.side,vertex,position,normal,texture);
586
         vertex++;
587
         }
588
       
589
       addVertex(curr,FRONT,LOWER,next.side,vertex,position,normal,texture);
590
       vertex++;
591
       addVertex(curr,FRONT,UPPER,next.side,vertex,position,normal,texture);
592
       vertex++;
593
       
594
       prev = curr;
595
       curr = next; 
596
       next = getNextEdge(curr);
597
       }
598
     while( curr.col!=col || curr.row!=row || curr.side!=side );
599
     
600
     vertex = repeatLast(vertex,position,normal,texture);
601
     
602
     return vertex;
603
     }
604

    
605
///////////////////////////////////////////////////////////////////////////////////////////////////
606

    
607
   private Edge getNextEdge(Edge curr)
608
     {
609
     int col = curr.col;
610
     int row = curr.row;
611
      
612
     //android.util.Log.e("CUBES", "row="+row+" col="+col+" mRows="+mRows+" mCols="+mCols);
613
                       
614
     switch(curr.side) 
615
       {
616
       case NORTH: if( col==mCols-1 ) 
617
                     return new Edge(EAST,row,col);
618
                   if( row>0 && mCubes[row-1][col+1]==mCubes[row][col] )
619
                     return new Edge(WEST,row-1,col+1);
620
                   if( mCubes[row][col+1]==mCubes[row][col] )
621
                     return new Edge(NORTH,row,col+1);
622
                   else  
623
                     return new Edge(EAST,row,col);
624
                   
625
       case SOUTH: if( col==0 ) 
626
                     return new Edge(WEST,row,col);
627
                   if( (row<mRows-1) && mCubes[row+1][col-1]==mCubes[row][col] )
628
                     return new Edge(EAST,row+1,col-1); 
629
                   if( mCubes[row][col-1]==mCubes[row][col] )
630
                     return new Edge(SOUTH,row,col-1);
631
                   else
632
                     return new Edge(WEST,row,col); 
633
                     
634
       case EAST : if( row==mRows-1 ) 
635
                     return new Edge(SOUTH,row,col);
636
                   if( (col<mCols-1) && mCubes[row+1][col+1]==mCubes[row][col] )
637
                     return new Edge(NORTH,row+1,col+1);
638
                   if( mCubes[row+1][col]==mCubes[row][col] )
639
                     return new Edge(EAST,row+1,col);
640
                   else 
641
                     return new Edge(SOUTH,row,col);
642
                   
643
       case WEST : if( row==0 )
644
                     return new Edge(NORTH,row,col);
645
                   if( col>0 && mCubes[row-1][col-1]==mCubes[row][col] )
646
                     return new Edge(SOUTH,row-1,col-1);
647
                   if( mCubes[row-1][col]==mCubes[row][col] )
648
                     return new Edge(WEST,row-1,col);
649
                   else
650
                     return new Edge(NORTH,row,col);     
651
       }
652
     
653
     return null;
654
     }
655

    
656
///////////////////////////////////////////////////////////////////////////////////////////////////
657
   
658
   private void addVertex(Edge curr, boolean back, boolean lower,int side, int vertex, float[] position, float[] normal, float[] texture)
659
     {
660
     float centerX = curr.col-(mCols-1.0f)/2.0f;
661
     float centerY = (mRows-1.0f)/2.0f-curr.row;
662
  
663
     switch(curr.side)
664
       {
665
       case NORTH: position[3*vertex  ] = (back ? (centerX-0.5f) : (centerX+0.5f))/mCols;
666
                   position[3*vertex+1] = (centerY+0.5f)/mRows;
667
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
668

    
669
                   normal[3*vertex  ]   = side==NORTH ? 0.0f : (side==WEST?-R:R);
670
                   normal[3*vertex+1]   = 1.0f;
671
                   normal[3*vertex+2]   = lower ? -R:R;
672

    
673
                   texture[2*vertex  ]  = (float)(back ? (curr.col  ):(curr.col+1))/mCols;
674
                   texture[2*vertex+1]  = (float)(lower? (curr.row-1):(curr.row  ))/mRows;  
675
                   break;
676
       case SOUTH: position[3*vertex  ] = (back ? (centerX+0.5f) : (centerX-0.5f))/mCols;
677
                   position[3*vertex+1] = (centerY-0.5f)/mRows;
678
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;  
679
            
680
                   normal[3*vertex  ]   = side==SOUTH ? 0.0f: (side==EAST?-R:R);
681
                   normal[3*vertex+1]   =-1.0f;
682
                   normal[3*vertex+2]   = lower ? -R:R;
683

    
684
                   texture[2*vertex  ]  = (float)(back ? (curr.col+1):(curr.col  ))/mCols;
685
                   texture[2*vertex+1]  = (float)(lower? (curr.row+2):(curr.row+1))/mRows;
686
                   break;
687
       case WEST : position[3*vertex  ] = (centerX-0.5f)/mCols;
688
                   position[3*vertex+1] = (back ? (centerY-0.5f):(centerY+0.5f))/mRows;
689
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
690

    
691
                   normal[3*vertex  ]   =-1.0f;
692
                   normal[3*vertex+1]   = side==WEST ? 0.0f : (side==NORTH?-R:R);
693
                   normal[3*vertex+2]   = lower ? -R:R;
694
 
695
                   texture[2*vertex  ]  = (float)(lower ? (curr.col-1):(curr.col  ))/mCols;
696
                   texture[2*vertex+1]  = (float)(back  ? (curr.row+1):(curr.row  ))/mRows;
697
                   break;
698
       case EAST : position[3*vertex  ] = (centerX+0.5f)/mCols;
699
                   position[3*vertex+1] = (back ? (centerY+0.5f):(centerY-0.5f))/mRows;
700
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
701

    
702
                   normal[3*vertex  ]   = 1.0f;
703
                   normal[3*vertex+1]   = side==EAST ? 0.0f : (side==SOUTH?-R:R);
704
                   normal[3*vertex+2]   = lower ? -R:R; 
705

    
706
                   texture[2*vertex  ]  = (float)(lower ? (curr.col+2):(curr.col+1))/mCols;
707
                   texture[2*vertex+1]  = (float)(back  ? (curr.row  ):(curr.row+1))/mRows;
708
                   break;
709
       }
710
     
711
     if(texture[2*vertex  ]>1.0f) texture[2*vertex  ] =2.0f-texture[2*vertex  ];
712
     if(texture[2*vertex  ]<0.0f) texture[2*vertex  ] =    -texture[2*vertex  ];
713
     if(texture[2*vertex+1]>1.0f) texture[2*vertex+1] =2.0f-texture[2*vertex+1];
714
     if(texture[2*vertex+1]<0.0f) texture[2*vertex+1] =    -texture[2*vertex+1];
715
     }
716

    
717
///////////////////////////////////////////////////////////////////////////////////////////////////
718
// PUBLIC API
719
///////////////////////////////////////////////////////////////////////////////////////////////////
720
   
721
/**
722
 * Creates the underlying grid of vertices, normals, texture coords and colors.
723
 *    
724
 * @param cols      See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
725
 * @param desc      See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
726
 * @param frontOnly See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
727
 */
728
   public DistortedCubesGrid(int cols, String desc, boolean frontOnly)
729
      {
730
      prepareDataStructures(cols,desc,frontOnly);
731
       
732
      int numVertices=0;
733
      float[] positionData= new float[POSITION_DATA_SIZE*dataLength];
734
      float[] normalData  = new float[NORMAL_DATA_SIZE  *dataLength];
735
      float[] textureData = new float[TEX_DATA_SIZE     *dataLength];
736

    
737
      numVertices = buildFrontBackGrid(true, numVertices,positionData,normalData,textureData);
738
      
739
      if( !frontOnly )
740
        {
741
        numVertices = repeatLast(numVertices,positionData,normalData,textureData);
742
        numVertices = buildSideGrid (numVertices,positionData,normalData,textureData);
743
        numVertices = buildFrontBackGrid (false,numVertices,positionData,normalData,textureData);
744
        }
745
      
746
      /*
747
      android.util.Log.e("CUBES","dataLen="+dataLength+" vertex="+numVertices);
748
      android.util.Log.d("CUBES", "position: "+debug(positionData,3) );
749
      android.util.Log.d("CUBES", "normal: "  +debug(  normalData,3) );
750
      android.util.Log.d("CUBES", "texture: " +debug( textureData,2) );
751
      */
752

    
753
      mGridPositions = ByteBuffer.allocateDirect(POSITION_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();                                                        
754
      mGridPositions.put(positionData).position(0); 
755
      
756
      mGridNormals = ByteBuffer.allocateDirect(NORMAL_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();                                                        
757
      mGridNormals.put(normalData).position(0); 
758

    
759
      mGridTexture = ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();                                                        
760
      mGridTexture.put(textureData).position(0); 
761
      }
762
   }
763
///////////////////////////////////////////////////////////////////////////////////////////////////
764

    
(5-5/18)