Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshCubes.java @ 554ce72b

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.mesh;
21

    
22
import java.util.ArrayList;
23

    
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25
/**
26
 * Create a 3D grid composed of Cubes.
27
 * <p>
28
 * Any subset of a MxNx1 cuboid is possible.
29
 */
30
public class MeshCubes extends MeshBase
31
   {
32
   private static final float R = 0.0f;//0.2f;
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 float[] mNormalX = new float[4];
40
   private static final float[] mNormalY = new float[4];
41
   private static final float[] mNormalZ = new float[4];
42

    
43
   private class Edge
44
     {
45
     final int side; 
46
     final int row;
47
     final int col;
48
     
49
     Edge(int s, int r, int c)
50
       {
51
       side= s; 
52
       row = r;
53
       col = c;
54
       }
55
     }
56
   
57
   private int mCols, mRows, mSlices;
58
   private int[][] mCubes;
59
   private byte[][] mInflateX, mInflateY;
60
   private float mInfCorrX, mInfCorrY, mInfCorrZ;
61
   private ArrayList<Edge> mEdges = new ArrayList<>();
62

    
63
   private int currVert;
64
   private int numVertices;
65
   private int mSideBends;
66
   private int mEdgeNum;
67
   private int mSideWalls;
68

    
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70
// a Block is split into two triangles along the NE-SW line iff it is in the top-right
71
// or bottom-left quadrant of the grid.
72

    
73
   private boolean isNE(int row,int col)
74
     {
75
     return ( (2*row<mRows)^(2*col<mCols) );
76
     }
77

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79
// return the number of vertices our grid will contain
80

    
81
   private int computeDataLength()
82
      {
83
      int frontWalls=0, frontSegments=0, triangleShifts=0, windingShifts=0;
84
      int shiftCol = (mCols-1)/2;
85

    
86
      boolean lastBlockIsNE=false;
87
      boolean thisBlockIsNE;        // the block we are currently looking at is split into
88
                                    // two triangles along the NE-SW line (rather than NW-SE)
89
      for(int row=0; row<mRows; row++)
90
        {
91
        if( mCols>=2 && (mCubes[row][shiftCol]%2 == 1) && (mCubes[row][shiftCol+1]%2 == 1) ) triangleShifts++;
92

    
93
        for(int col=0; col<mCols; col++)
94
          {
95
          if( mCubes[row][col]%2 == 1 )  // land
96
            {
97
            thisBlockIsNE = isNE(row,col);
98
            if( thisBlockIsNE^lastBlockIsNE ) windingShifts++;
99
            lastBlockIsNE = thisBlockIsNE;
100
            frontWalls++;
101
            if( col==mCols-1 || mCubes[row][col+1]%2 == 0 ) frontSegments++;
102
            }
103
          }
104
        }
105

    
106
      int frontVert       = 2*( frontWalls + 2*frontSegments - 1) +2*triangleShifts + windingShifts;
107
      int sideVertOneSlice= 2*( mSideWalls + mSideBends + mEdgeNum -1);
108
      int sideVert        = 2*(mSlices-1) + mSlices*sideVertOneSlice;
109
      int firstWinding    = (mSlices>0 && (frontVert+1)%2==1 ) ? 1:0;
110
      int dataL           = mSlices==0 ? frontVert : (frontVert+1) +firstWinding+ (1+sideVert+1) + (1+frontVert);
111
/*
112
      android.util.Log.e("CUBES","triangleShifts="+triangleShifts+" windingShifts="+windingShifts+" winding1="+firstWinding+" frontVert="+frontVert+" sideVert="+sideVert);
113
      android.util.Log.e("CUBES", "frontW="+frontWalls+" fSegments="+frontSegments+" sWalls="+mSideWalls+" sSegments="+mEdgeNum+" sideBends="+mSideBends+" dataLen="+dataL );
114
*/
115
      return dataL<0 ? 0:dataL;
116
      }
117

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119
/*
120
   private static String debug(short[] val)
121
     {
122
     String ret="";j
123
     
124
     for(int i=0; i<val.length; i++) ret+=(" "+val[i]); 
125
     
126
     return ret;
127
     }
128
*/
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
   private static String debug(float[] val, int stop)
132
     {
133
     String ret="";
134
     float v;
135
     boolean neg;
136
     int mod;
137

    
138
     for(int i=0; i<val.length; i++) 
139
        {
140
        if( i%stop==0 ) ret+="\n";
141

    
142
        mod = i%stop;
143

    
144
        if( mod==0 || mod==3 || mod==6 ) ret+=" (";
145

    
146
        v = val[i];
147
        if( v==-0.0f ) v=0.0f;
148

    
149

    
150
        neg = v<0;
151
        v = (v<0 ? -v:v);
152

    
153
        ret+=((neg? " -":" +")+v);
154

    
155
        if( mod==2 || mod==5 || mod==7 ) ret+=")";
156
        }
157

    
158
     return ret;
159
     }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162
/*
163
   private static String debug(Edge e)
164
     {
165
     String d = "";
166
     
167
     switch(e.side)
168
       {
169
       case NORTH: d+="NORTH "; break;
170
       case SOUTH: d+="SOUTH "; break;
171
       case WEST : d+="WEST  "; break;
172
       case EAST : d+="EAST  "; break;
173
       }
174
     
175
     d+=("("+e.row+","+e.col+")");
176
     
177
     return d;
178
     }   
179
*/
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

    
182
   private void prepareDataStructures(int cols, String desc, int slices)
183
     {
184
     mRows       =0;
185
     mCols       =0;
186
     mSlices     =slices;
187
     numVertices =0;
188

    
189
     if( cols>0 && desc.contains("1") )
190
       {
191
       mCols = cols;
192
       mRows = desc.length()/cols;
193

    
194
       int max = mRows>mCols ? mRows:mCols;
195
       max = mSlices>max ? mSlices : max;
196

    
197
       mInfCorrX = (float)max/mCols;
198
       mInfCorrY = (float)max/mRows;
199
       mInfCorrZ = (float)max/mSlices;
200

    
201
       mCubes    = new int[mRows][mCols];
202
       mInflateX = new byte[mRows+1][mCols+1];
203
       mInflateY = new byte[mRows+1][mCols+1];
204

    
205
       for(int col=0; col<mCols; col++)
206
         for(int row=0; row<mRows; row++)
207
           mCubes[row][col] = (desc.charAt(row * mCols + col) == '1' ? 1 : 0);
208

    
209
       for(int col=0; col<mCols+1; col++)
210
         for(int row=0; row<mRows+1; row++)
211
           {
212
           fillInflate(row,col);
213
           }
214

    
215
       markRegions();
216
       numVertices = computeDataLength();
217
       currVert = 0;
218
       }
219
     }
220

    
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222
// full grid
223

    
224
   private void prepareDataStructures(int cols, int rows, int slices)
225
     {
226
     mRows        =rows;
227
     mCols        =cols;
228
     mSlices      =slices;
229
     numVertices  =0;
230

    
231
     if( cols>0 && rows>0 )
232
       {
233
       mCubes    = new int[mRows][mCols];
234
       mInflateX = new byte[mRows+1][mCols+1];
235
       mInflateY = new byte[mRows+1][mCols+1];
236

    
237
       int max = mRows>mCols ? mRows:mCols;
238
       max = mSlices>max ? mSlices : max;
239

    
240
       mInfCorrX = (float)max/mCols;
241
       mInfCorrY = (float)max/mRows;
242
       mInfCorrZ = (float)max/mSlices;
243

    
244
       for(int col=0; col<mCols; col++)
245
         for(int row=0; row<mRows; row++)
246
           mCubes[row][col] = 1;
247

    
248
       for(int col=0; col<mCols+1; col++)
249
         for(int row=0; row<mRows+1; row++)
250
           {
251
           fillInflate(row,col);
252
           }
253

    
254
       markRegions();
255
       numVertices = computeDataLength();
256
       currVert = 0;
257
       }
258
     }
259

    
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261
// Mark all the 'regions' of our grid  - i.e. separate pieces of 'land' (connected blocks that will 
262
// be rendered) and 'water' (connected holes in between) with integers. Each connected block of land
263
// gets a unique odd integer, each connected block of water a unique even integer.
264
//
265
// Water on the edges of the grid is also considered connected to itself!   
266
//   
267
// This function also creates a list of 'Edges'. Each Edge is a data structure from which later on we
268
// will start building the side walls of each connected block of land (and sides of holes of water
269
// inside). Each Edge needs to point from Land to Water (thus the '(SOUTH,i-1,j)' below) - otherwise
270
// later on setting up normal vectors wouldn't work.
271
   
272
  private void markRegions()
273
     {
274
     int i, j, numWater=1, numLand=0;
275
     
276
     for(i=0; i<mRows;i++) if( mCubes[      i][      0]==0 ) markRegion((short)2,      i,       0);
277
     for(i=0; i<mRows;i++) if( mCubes[      i][mCols-1]==0 ) markRegion((short)2,      i, mCols-1);
278
     for(i=0; i<mCols;i++) if( mCubes[0      ][      i]==0 ) markRegion((short)2,      0,       i);
279
     for(i=0; i<mCols;i++) if( mCubes[mRows-1][      i]==0 ) markRegion((short)2,mRows-1,       i);
280
           
281
     for(i=0; i<mRows; i++)
282
        for(j=0; j<mCols; j++)
283
           {
284
           if( mCubes[i][j] == 0 ) { numWater++; markRegion( (short)(2*numWater ),i,j); mEdges.add(new Edge(SOUTH,i-1,j)); }
285
           if( mCubes[i][j] == 1 ) { numLand ++; markRegion( (short)(2*numLand+1),i,j); mEdges.add(new Edge(NORTH,i  ,j)); }
286
           }
287
     
288
     // now we potentially need to kick out some Edges . Otherwise the following does not work:
289
     //
290
     // 0 1 0
291
     // 1 0 1
292
     // 0 1 0
293
     
294
     mEdgeNum= mEdges.size();
295
     int initCol, initRow, initSide, lastSide;
296
     Edge e1,e2;
297
     
298
     for(i=0; i<mEdgeNum; i++)
299
       {
300
       e1 = mEdges.get(i);
301
       initRow= e1.row;
302
       initCol= e1.col;
303
       initSide=e1.side;
304

    
305
       do
306
         {
307
         //android.util.Log.d("CUBES", "checking edge "+debug(e1));
308

    
309
         mSideWalls++;
310

    
311
         if( e1.side==NORTH || e1.side==SOUTH )
312
           {
313
           for(j=i+1;j<mEdgeNum;j++)
314
             {
315
             e2 = mEdges.get(j);
316

    
317
             if( e2.side==e1.side && e2.row==e1.row && e2.col==e1.col )
318
               {
319
               mEdges.remove(j);
320
               mEdgeNum--;
321
               j--;
322

    
323
               //android.util.Log.e("CUBES", "removing edge "+debug(e2));
324
               }
325
             }
326
           }
327

    
328
         lastSide = e1.side;
329
         e1 = getNextEdge(e1);
330
         if( e1.side!=lastSide ) mSideBends++;
331
         }
332
       while( e1.col!=initCol || e1.row!=initRow || e1.side!=initSide );
333
       }
334
     }
335

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

    
366
     if(front)
367
       {
368
       mNormalZ[0] = 1.0f;
369
       mNormalZ[1] = 1.0f;
370
       mNormalZ[2] = 1.0f;
371
       mNormalZ[3] = 1.0f;
372
       }
373
     else
374
       {
375
       mNormalZ[0] =-1.0f;
376
       mNormalZ[1] =-1.0f;
377
       mNormalZ[2] =-1.0f;
378
       mNormalZ[3] =-1.0f;
379
       }
380

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

    
425
///////////////////////////////////////////////////////////////////////////////////////////////////
426

    
427
  private void buildFrontBackGrid(boolean front, float[] attribs)
428
     {
429
     int last, current;
430
     boolean seenLand=false;
431
     boolean lastBlockIsNE = false;
432
     boolean currentBlockIsNE;
433
     float vectZ = (front ? 0.5f : -0.5f);
434

    
435
     //android.util.Log.d("CUBES", "buildFrontBack");
436

    
437
     for(int row=0; row<mRows; row++)
438
       {
439
       last =0;
440
         
441
       for(int col=0; col<mCols; col++)
442
         {
443
         current = mCubes[row][col];
444

    
445
         if( current%2 == 1 )
446
           {
447
           currentBlockIsNE = isNE(row,col);
448

    
449
           if( !seenLand && !front && ((currVert%2==1)^currentBlockIsNE) )
450
             {
451
             //android.util.Log.d("CUBES","repeating winding2 vertex");
452

    
453
             repeatLast(attribs);
454
             }
455

    
456
           createNormals(front,row,col);
457

    
458
           if( currentBlockIsNE )
459
             {
460
             if( (last!=current) || !lastBlockIsNE )
461
               {
462
               if( seenLand  && (last != current) ) repeatLast(attribs);
463
               addFrontVertex( 0, vectZ, col, row, attribs);
464
               if( seenLand  && (last != current) ) repeatLast(attribs);
465
               if( !lastBlockIsNE || (!front && !seenLand) ) repeatLast(attribs);
466
               addFrontVertex( 1, vectZ, col, row+1, attribs);
467
               }
468
             addFrontVertex( 2, vectZ, col+1, row, attribs);
469
             addFrontVertex( 3, vectZ, col+1, row+1, attribs);
470
             }
471
           else
472
             {
473
             if( (last!=current) || lastBlockIsNE )
474
               {
475
               if( seenLand  && (last != current) ) repeatLast(attribs);
476
               addFrontVertex( 1, vectZ, col, row+1, attribs);
477
               if( seenLand  && (last != current) ) repeatLast(attribs);
478
               if( lastBlockIsNE || (!front && !seenLand) ) repeatLast(attribs);
479
               addFrontVertex( 0, vectZ, col, row, attribs);
480
               }
481
             addFrontVertex( 3, vectZ, col+1, row+1, attribs);
482
             addFrontVertex( 2, vectZ, col+1, row  , attribs);
483
             }
484

    
485
           seenLand = true;
486
           lastBlockIsNE = currentBlockIsNE;
487
           }
488
            
489
         last = current;
490
         }
491
       }
492
     }
493

    
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495

    
496
  private void buildSideGrid(float[] attribs)
497
     {
498
     //android.util.Log.d("CUBES", "buildSide");
499

    
500
     for(int i=0; i<mEdgeNum; i++)
501
       {
502
       buildIthSide(mEdges.get(i), attribs);
503
       }
504
     }
505

    
506
///////////////////////////////////////////////////////////////////////////////////////////////////
507

    
508
  private void buildIthSide(Edge curr, float[] attribs)
509
     {
510
     Edge prev, next;
511
     int col, row, side;
512

    
513
     if( curr.side==NORTH ) // water outside
514
       {
515
       prev = new Edge(WEST,curr.row,curr.col);
516
       }
517
     else                   // land outside; we need to move forward one link because we are
518
       {                    // going in opposite direction and we need to start from a bend.
519
       prev = curr;
520
       curr = new Edge(EAST,curr.row+1,curr.col-1);
521
       }
522

    
523
     for(int slice=0; slice<mSlices; slice++)
524
       {
525
       col = curr.col;
526
       row = curr.row;
527
       side= curr.side;
528
       next = getNextEdge(curr);
529
     
530
       addSideVertex(curr,true,slice+1,prev.side,attribs);
531

    
532
       do
533
         {
534
         if( prev.side!=curr.side )
535
           {
536
           addSideVertex(curr,true,slice+1,prev.side,attribs);
537
           addSideVertex(curr,true,slice  ,prev.side,attribs);
538
           }
539
       
540
         addSideVertex(curr,false,slice+1,next.side,attribs);
541
         addSideVertex(curr,false,slice  ,next.side,attribs);
542
       
543
         prev = curr;
544
         curr = next;
545
         next = getNextEdge(curr);
546
         }
547
       while( curr.col!=col || curr.row!=row || curr.side!=side );
548
     
549
       repeatLast(attribs);
550
       }
551
     }
552

    
553
///////////////////////////////////////////////////////////////////////////////////////////////////
554

    
555
  private Edge getNextEdge(Edge curr)
556
     {
557
     int col = curr.col;
558
     int row = curr.row;
559
      
560
     //android.util.Log.e("CUBES", "row="+row+" col="+col+" mRows="+mRows+" mCols="+mCols);
561
                       
562
     switch(curr.side) 
563
       {
564
       case NORTH: if( col==mCols-1 ) 
565
                     return new Edge(EAST,row,col);
566
                   if( row>0 && mCubes[row-1][col+1]==mCubes[row][col] )
567
                     return new Edge(WEST,row-1,col+1);
568
                   if( mCubes[row][col+1]==mCubes[row][col] )
569
                     return new Edge(NORTH,row,col+1);
570
                   else  
571
                     return new Edge(EAST,row,col);
572
                   
573
       case SOUTH: if( col==0 ) 
574
                     return new Edge(WEST,row,col);
575
                   if( (row<mRows-1) && mCubes[row+1][col-1]==mCubes[row][col] )
576
                     return new Edge(EAST,row+1,col-1); 
577
                   if( mCubes[row][col-1]==mCubes[row][col] )
578
                     return new Edge(SOUTH,row,col-1);
579
                   else
580
                     return new Edge(WEST,row,col); 
581
                     
582
       case EAST : if( row==mRows-1 ) 
583
                     return new Edge(SOUTH,row,col);
584
                   if( (col<mCols-1) && mCubes[row+1][col+1]==mCubes[row][col] )
585
                     return new Edge(NORTH,row+1,col+1);
586
                   if( mCubes[row+1][col]==mCubes[row][col] )
587
                     return new Edge(EAST,row+1,col);
588
                   else 
589
                     return new Edge(SOUTH,row,col);
590
                   
591
       default   : if( row==0 )
592
                     return new Edge(NORTH,row,col);
593
                   if( col>0 && mCubes[row-1][col-1]==mCubes[row][col] )
594
                     return new Edge(SOUTH,row-1,col-1);
595
                   if( mCubes[row-1][col]==mCubes[row][col] )
596
                     return new Edge(WEST,row-1,col);
597
                   else
598
                     return new Edge(NORTH,row,col);     
599
       }
600
     }
601

    
602
///////////////////////////////////////////////////////////////////////////////////////////////////
603

    
604
  private void fillInflate(int row, int col)
605
    {
606
    int diff;
607

    
608
         if( col==0     ) mInflateX[row][col] = -1;
609
    else if( col==mCols ) mInflateX[row][col] = +1;
610
    else
611
      {
612
      if( row==0 )
613
        {
614
        diff = mCubes[0][col-1]-mCubes[0][col];
615
        }
616
      else if( row==mRows )
617
        {
618
        diff = mCubes[mRows-1][col-1]-mCubes[mRows-1][col];
619
        }
620
      else
621
        {
622
        diff = (mCubes[row  ][col-1]-mCubes[row  ][col]) +
623
               (mCubes[row-1][col-1]-mCubes[row-1][col]) ;
624

    
625
        if( diff==-2 ) diff=-1;
626
        if( diff== 2 ) diff= 1;
627
        }
628

    
629
      mInflateX[row][col] = (byte)diff;
630
      }
631

    
632
         if( row==0     ) mInflateY[row][col] = +1;
633
    else if( row==mRows ) mInflateY[row][col] = -1;
634
    else
635
      {
636
      if( col==0 )
637
        {
638
        diff = mCubes[row][0]-mCubes[row-1][0];
639
        }
640
      else if( col==mCols )
641
        {
642
        diff = mCubes[row][mCols-1]-mCubes[row-1][mCols-1];
643
        }
644
      else
645
        {
646
        diff = (mCubes[row  ][col-1]+mCubes[row  ][col]) -
647
               (mCubes[row-1][col-1]+mCubes[row-1][col]) ;
648

    
649
        if( diff==-2 ) diff=-1;
650
        if( diff== 2 ) diff= 1;
651
        }
652

    
653
      mInflateY[row][col] = (byte)diff;
654
      }
655

    
656
    //android.util.Log.e("mesh","col="+col+" row="+row+" inflateX="+mInflateX[col][row]+" InflateY="+mInflateY[col][row]);
657
    }
658

    
659
///////////////////////////////////////////////////////////////////////////////////////////////////
660

    
661
  private void addFrontVertex(int index, float vectZ, int col, int row, float[] attribs)
662
     {
663
     float x = (float)col/mCols;
664
     float y = (float)row/mRows;
665

    
666
     attribs[VERT_ATTRIBS*currVert + POS_ATTRIB  ] = x-0.5f;
667
     attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+1] = 0.5f-y;
668
     attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+2] = vectZ;
669

    
670
     attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB  ] = mNormalX[index];
671
     attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+1] = mNormalY[index];
672
     attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+2] = mNormalZ[index];
673

    
674
     attribs[VERT_ATTRIBS*currVert + INF_ATTRIB  ] = mInfCorrX*mInflateX[row][col]/2.0f;
675
     attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInfCorrY*mInflateY[row][col]/2.0f;
676
     attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = mInfCorrZ*vectZ;
677

    
678
     attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = x;
679
     attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 1.0f-y;
680

    
681
     currVert++;
682
     }
683

    
684
///////////////////////////////////////////////////////////////////////////////////////////////////
685
   
686
  private void addSideVertex(Edge curr, boolean back, int slice, int side, float[] attribs)
687
     {
688
     //android.util.Log.e("CUBES", "adding Side vertex!");
689
     float x, y, z;
690
     int row, col;
691

    
692
     switch(curr.side)
693
       {
694
       case NORTH: row = curr.row;
695
                   col = (back ? (curr.col  ):(curr.col+1));
696
                   x = (float)col/mCols;
697
                   y = 0.5f - (float)row/mRows;
698
                   z = 0.5f - (float)slice/mSlices;
699

    
700
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB  ] = x - 0.5f;
701
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+1] = y;
702
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+2] = z;
703

    
704
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB  ] = side==NORTH ? 0.0f : (side==WEST?-R:R);
705
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+1] = 1.0f;
706
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+2] = (slice==0 ? R : (slice==mSlices ? -R:0) );
707

    
708
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB  ] = mInfCorrX*mInflateX[row][col]/2.0f;
709
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInfCorrY*mInflateY[row][col]/2.0f;
710
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = mInfCorrZ*z;
711

    
712
                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = x;
713
                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 1.0f-(float)(row-slice)/mRows;
714
                   break;
715
       case SOUTH: row = curr.row+1;
716
                   col = (back ? (curr.col+1):(curr.col));
717
                   x = (float)col/mCols;
718
                   y = 0.5f - (float)row/mRows;
719
                   z = 0.5f - (float)slice/mSlices;
720

    
721
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB  ] = x - 0.5f;
722
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+1] = y;
723
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+2] = z;
724

    
725
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB  ] = side==SOUTH ? 0.0f: (side==EAST?-R:R);
726
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+1] =-1.0f;
727
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+2] = (slice==0 ? R : (slice==mSlices ? -R:0) );
728

    
729
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB  ] = mInfCorrX*mInflateX[row][col]/2.0f;
730
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInfCorrY*mInflateY[row][col]/2.0f;
731
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = mInfCorrZ*z;
732

    
733
                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = x;
734
                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 1.0f - (float)(row+slice)/mRows;
735
                   break;
736
       case WEST : row = (back  ? (curr.row+1):(curr.row));
737
                   col = curr.col;
738
                   x = (float)col/mCols -0.5f;
739
                   y = (float)row/mRows;
740
                   z = 0.5f - (float)slice/mSlices;
741

    
742
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB  ] = x;
743
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+1] = 0.5f - y;
744
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+2] = z;
745

    
746
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB  ] =-1.0f;
747
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+1] = side==WEST ? 0.0f : (side==NORTH?-R:R);
748
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+2] = (slice==0 ? R : (slice==mSlices ? -R:0) );
749

    
750
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB  ] = mInfCorrX*mInflateX[row][col]/2.0f;
751
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInfCorrY*mInflateY[row][col]/2.0f;
752
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = mInfCorrZ*z;
753

    
754
                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = (float)(col-slice)/mCols;
755
                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 1.0f - y;
756
                   break;
757
       case EAST : row = (back  ? (curr.row):(curr.row+1));
758
                   col = (curr.col+1);
759
                   x = (float)col/mCols -0.5f;
760
                   y = (float)row/mRows;
761
                   z = 0.5f - (float)slice/mSlices;
762

    
763
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB  ] = x;
764
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+1] = 0.5f - y;
765
                   attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+2] = z;
766

    
767
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB  ] = 1.0f;
768
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+1] = side==EAST ? 0.0f : (side==SOUTH?-R:R);
769
                   attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+2] = (slice==0 ? R : (slice==mSlices ? -R:0) );
770

    
771
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB  ] = mInfCorrX*mInflateX[row][col]/2.0f;
772
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInfCorrY*mInflateY[row][col]/2.0f;
773
                   attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = mInfCorrZ*z;
774

    
775
                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = (float)(col+slice)/mCols;
776
                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 1.0f - y;
777
                   break;
778
       }
779

    
780
     float tex0 =  attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ];
781
     float tex1 =  attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1];
782

    
783
     if(tex0>1.0f) attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = 2.0f-tex0;
784
     if(tex0<0.0f) attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] =     -tex0;
785
     if(tex1>1.0f) attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 2.0f-tex1;
786
     if(tex1<0.0f) attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] =     -tex1;
787

    
788
     currVert++;
789
     }
790

    
791
///////////////////////////////////////////////////////////////////////////////////////////////////
792

    
793
   private void repeatLast(float[] attribs)
794
     {
795
     //android.util.Log.e("CUBES", "repeating last vertex!");
796

    
797
     attribs[VERT_ATTRIBS*currVert + POS_ATTRIB  ] = attribs[VERT_ATTRIBS*(currVert-1) + POS_ATTRIB  ];
798
     attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+1] = attribs[VERT_ATTRIBS*(currVert-1) + POS_ATTRIB+1];
799
     attribs[VERT_ATTRIBS*currVert + POS_ATTRIB+2] = attribs[VERT_ATTRIBS*(currVert-1) + POS_ATTRIB+2];
800

    
801
     attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB  ] = attribs[VERT_ATTRIBS*(currVert-1) + NOR_ATTRIB  ];
802
     attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+1] = attribs[VERT_ATTRIBS*(currVert-1) + NOR_ATTRIB+1];
803
     attribs[VERT_ATTRIBS*currVert + NOR_ATTRIB+2] = attribs[VERT_ATTRIBS*(currVert-1) + NOR_ATTRIB+2];
804

    
805
     attribs[VERT_ATTRIBS*currVert + INF_ATTRIB  ] = attribs[VERT_ATTRIBS*(currVert-1) + INF_ATTRIB  ];
806
     attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = attribs[VERT_ATTRIBS*(currVert-1) + INF_ATTRIB+1];
807
     attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = attribs[VERT_ATTRIBS*(currVert-1) + INF_ATTRIB+2];
808

    
809
     attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = attribs[VERT_ATTRIBS*(currVert-1) + TEX_ATTRIB  ];
810
     attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = attribs[VERT_ATTRIBS*(currVert-1) + TEX_ATTRIB+1];
811

    
812
     currVert++;
813
     }
814

    
815
///////////////////////////////////////////////////////////////////////////////////////////////////
816

    
817
  private void build()
818
     {
819
     float[] attribs= new float[VERT_ATTRIBS*numVertices];
820

    
821
     buildFrontBackGrid(true,attribs);
822

    
823
     if( mSlices>0 )
824
       {
825
       repeatLast(attribs);
826
       if( currVert%2==1 ) repeatLast(attribs);
827
       buildSideGrid(attribs);
828
       buildFrontBackGrid(false,attribs);
829
       }
830

    
831
     mEdges.clear();
832
     mEdges = null;
833
     mCubes = null;
834
     mInflateX = null;
835
     mInflateY = null;
836

    
837
     if( currVert!=numVertices )
838
       android.util.Log.e("MeshCubes", "currVert " +currVert+" numVertices="+numVertices );
839

    
840
     setAttribs(attribs);
841
     }
842

    
843
///////////////////////////////////////////////////////////////////////////////////////////////////
844
// PUBLIC API
845
///////////////////////////////////////////////////////////////////////////////////////////////////
846
/**
847
 * Creates the underlying mesh of vertices, normals, texture coords.
848
 *    
849
 * @param cols   Integer helping to parse the next parameter.
850
 * @param desc   String describing the subset of a MxNx1 cuboid that we want to create.
851
 *               Its MxN characters - all 0 or 1 - decide of appropriate field is taken or not.
852
 *               <p></p>
853
 *               <p>
854
 *               <pre>
855
 *               For example, (cols=2, desc="111010") describes the following shape:
856
 *
857
 *               XX
858
 *               X
859
 *               X
860
 *
861
 *               whereas (cols=2,desc="110001") describes
862
 *
863
 *               XX
864
 *
865
 *                X
866
 *               </pre>
867
 *               </p>
868
 * @param slices Number of slices, i.e. 'depth' of the Mesh.
869
 */
870
 public MeshCubes(int cols, String desc, int slices)
871
   {
872
   super( (float)slices/cols);
873
   prepareDataStructures(cols,desc,slices);
874
   build();
875
   }
876

    
877
///////////////////////////////////////////////////////////////////////////////////////////////////
878
/**
879
 * Creates a full, hole-less underlying mesh of vertices, normals, texture coords and colors.
880
 *
881
 * @param cols   Number of columns, i.e. 'width' of the Mesh.
882
 * @param rows   Number of rows, i.e. 'height' of the Mesh.
883
 * @param slices Number of slices, i.e. 'depth' of the Mesh.
884
 */
885
 public MeshCubes(int cols, int rows, int slices)
886
   {
887
   super( (float)slices/cols);
888
   prepareDataStructures(cols,rows,slices);
889
   build();
890
   }
891
 }
(2-2/3)