Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshCubes.java @ 4f81e0c8

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 org.distorted.library.type.Static4D;
23

    
24
import java.util.ArrayList;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27
/**
28
 * Create a 3D grid composed of Cubes.
29
 * <p>
30
 * Any subset of a MxNx1 cuboid is possible. (repeated arbitrary number of times into Z-dir)
31
 */
32
public class MeshCubes extends MeshBase
33
   {
34
   private static final float R = 0.0f;
35

    
36
   private static final int FRONT = 0;
37
   private static final int BACK  = 1;
38
   private static final int LEFT  = 2;
39
   private static final int RIGHT = 3;
40
   private static final int TOP   = 4;
41
   private static final int BOTTOM= 5;
42

    
43
   private static final int NORTH = 0;
44
   private static final int WEST  = 1;
45
   private static final int EAST  = 2;
46
   private static final int SOUTH = 3;
47

    
48
   private static final float[] mNormalX = new float[4];
49
   private static final float[] mNormalY = new float[4];
50
   private static final float[] mNormalZ = new float[4];
51

    
52
   private static class Edge
53
     {
54
     final int side; 
55
     final int row;
56
     final int col;
57
     
58
     Edge(int s, int r, int c)
59
       {
60
       side= s; 
61
       row = r;
62
       col = c;
63
       }
64
     }
65

    
66
   private float[] mTexMappingX,mTexMappingY, mTexMappingW, mTexMappingH;
67

    
68
   private int mCols, mRows, mSlices;
69
   private int[][] mCubes;
70
   private byte[][] mInflateX, mInflateY;
71
   private ArrayList<Edge> mEdges = new ArrayList<>();
72

    
73
   private int currVert;
74
   private int numVertices;
75
   private int mSideBends;
76
   private int mEdgeNum;
77
   private int mSideWalls;
78

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

    
83
   private boolean isNE(int row,int col)
84
     {
85
     return ( (2*row<mRows)^(2*col<mCols) );
86
     }
87

    
88
///////////////////////////////////////////////////////////////////////////////////////////////////
89
// fill per-side texture mappings. Default: all 6 sides map to the whole texture.
90
// Each Static4D describes the way its side will map. Format:
91
//
92
// 1st float: X-coord of the texture point that our top-left corner of the side maps to
93
// 2nd float: Y-coord of the texture point that our top-left corner of the side maps to
94
// 3rd float: X-coord of the texture point that our bot-right corner of the side maps to
95
// 4th float: Y-coord of the texture point that our bot-right corner of the side maps to
96

    
97
   private void fillTexMappings(Static4D front, Static4D back, Static4D left, Static4D right, Static4D top, Static4D bottom)
98
     {
99
     if( mTexMappingX==null ) mTexMappingX = new float[6];
100
     if( mTexMappingY==null ) mTexMappingY = new float[6];
101
     if( mTexMappingW==null ) mTexMappingW = new float[6];
102
     if( mTexMappingH==null ) mTexMappingH = new float[6];
103

    
104
     mTexMappingX[FRONT]  = front.get0();
105
     mTexMappingY[FRONT]  = front.get1();
106
     mTexMappingW[FRONT]  = front.get2() - front.get0();
107
     mTexMappingH[FRONT]  = front.get3() - front.get1();
108

    
109
     mTexMappingX[BACK]   = back.get0();
110
     mTexMappingY[BACK]   = back.get1();
111
     mTexMappingW[BACK]   = back.get2() - back.get0();
112
     mTexMappingH[BACK]   = back.get3() - back.get1();
113

    
114
     mTexMappingX[LEFT]   = left.get0();
115
     mTexMappingY[LEFT]   = left.get1();
116
     mTexMappingW[LEFT]   = left.get2() - left.get0();
117
     mTexMappingH[LEFT]   = left.get3() - left.get1();
118

    
119
     mTexMappingX[RIGHT]  = right.get0();
120
     mTexMappingY[RIGHT]  = right.get1();
121
     mTexMappingW[RIGHT]  = right.get2() - right.get0();
122
     mTexMappingH[RIGHT]  = right.get3() - right.get1();
123

    
124
     mTexMappingX[TOP]    = top.get0();
125
     mTexMappingY[TOP]    = top.get1();
126
     mTexMappingW[TOP]    = top.get2() - top.get0();
127
     mTexMappingH[TOP]    = top.get3() - top.get1();
128

    
129
     mTexMappingX[BOTTOM] = bottom.get0();
130
     mTexMappingY[BOTTOM] = bottom.get1();
131
     mTexMappingW[BOTTOM] = bottom.get2() - bottom.get0();
132
     mTexMappingH[BOTTOM] = bottom.get3() - bottom.get1();
133
     }
134

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136
// return the number of vertices our grid will contain
137

    
138
   private int computeDataLength()
139
      {
140
      int frontWalls=0, frontSegments=0, triangleShifts=0, windingShifts=0;
141
      int shiftCol = (mCols-1)/2;
142

    
143
      boolean lastBlockIsNE=false;
144
      boolean thisBlockIsNE;        // the block we are currently looking at is split into
145
                                    // two triangles along the NE-SW line (rather than NW-SE)
146
      for(int row=0; row<mRows; row++)
147
        {
148
        if( mCols>=2 && (mCubes[row][shiftCol]%2 == 1) && (mCubes[row][shiftCol+1]%2 == 1) ) triangleShifts++;
149

    
150
        for(int col=0; col<mCols; col++)
151
          {
152
          if( mCubes[row][col]%2 == 1 )  // land
153
            {
154
            thisBlockIsNE = isNE(row,col);
155
            if( thisBlockIsNE^lastBlockIsNE ) windingShifts++;
156
            lastBlockIsNE = thisBlockIsNE;
157
            frontWalls++;
158
            if( col==mCols-1 || mCubes[row][col+1]%2 == 0 ) frontSegments++;
159
            }
160
          }
161
        }
162

    
163
      int frontVert       = 2*( frontWalls + 2*frontSegments - 1) +2*triangleShifts + windingShifts;
164
      int sideVertOneSlice= 2*( mSideWalls + mSideBends + mEdgeNum -1);
165
      int sideVert        = 2*(mSlices-1) + mSlices*sideVertOneSlice;
166
      int firstWinding    = (mSlices>0 && (frontVert+1)%2==1 ) ? 1:0;
167
      int dataL           = mSlices==0 ? frontVert : (frontVert+1) +firstWinding+ (1+sideVert+1) + (1+frontVert);
168

    
169
      return dataL<0 ? 0:dataL;
170
      }
171

    
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173

    
174
   private void prepareDataStructures(int cols, String desc, int slices)
175
     {
176
     mRows       =0;
177
     mCols       =0;
178
     mSlices     =slices;
179
     numVertices =0;
180

    
181
     if( cols>0 && desc.contains("1") )
182
       {
183
       mCols = cols;
184
       mRows = desc.length()/cols;
185

    
186
       mCubes    = new int[mRows][mCols];
187
       mInflateX = new byte[mRows+1][mCols+1];
188
       mInflateY = new byte[mRows+1][mCols+1];
189

    
190
       for(int col=0; col<mCols; col++)
191
         for(int row=0; row<mRows; row++)
192
           mCubes[row][col] = (desc.charAt(row * mCols + col) == '1' ? 1 : 0);
193

    
194
       for(int col=0; col<mCols+1; col++)
195
         for(int row=0; row<mRows+1; row++)
196
           {
197
           fillInflate(row,col);
198
           }
199

    
200
       markRegions();
201
       numVertices = computeDataLength();
202
       currVert = 0;
203
       }
204
     }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207
// full grid
208

    
209
   private void prepareDataStructures(int cols, int rows, int slices)
210
     {
211
     mRows        =rows;
212
     mCols        =cols;
213
     mSlices      =slices;
214
     numVertices  =0;
215

    
216
     if( cols>0 && rows>0 )
217
       {
218
       mCubes    = new int[mRows][mCols];
219
       mInflateX = new byte[mRows+1][mCols+1];
220
       mInflateY = new byte[mRows+1][mCols+1];
221

    
222
       for(int col=0; col<mCols; col++)
223
         for(int row=0; row<mRows; row++)
224
           mCubes[row][col] = 1;
225

    
226
       for(int col=0; col<mCols+1; col++)
227
         for(int row=0; row<mRows+1; row++)
228
           {
229
           fillInflate(row,col);
230
           }
231

    
232
       markRegions();
233
       numVertices = computeDataLength();
234
       currVert = 0;
235
       }
236
     }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239
// Mark all the 'regions' of our grid  - i.e. separate pieces of 'land' (connected blocks that will 
240
// be rendered) and 'water' (connected holes in between) with integers. Each connected block of land
241
// gets a unique odd integer, each connected block of water a unique even integer.
242
//
243
// Water on the edges of the grid is also considered connected to itself!   
244
//   
245
// This function also creates a list of 'Edges'. Each Edge is a data structure from which later on we
246
// will start building the side walls of each connected block of land (and sides of holes of water
247
// inside). Each Edge needs to point from Land to Water (thus the '(SOUTH,row-1,col)' below) - otherwise
248
// later on setting up normal vectors wouldn't work.
249
   
250
  private void markRegions()
251
     {
252
     int row, col, numWater=1, numLand=0;
253
     
254
     for(row=0; row<mRows; row++) if( mCubes[    row][      0]==0 ) markRegion((short)2,    row,       0);
255
     for(row=0; row<mRows; row++) if( mCubes[    row][mCols-1]==0 ) markRegion((short)2,    row, mCols-1);
256
     for(col=0; col<mCols; col++) if( mCubes[0      ][    col]==0 ) markRegion((short)2,      0,     col);
257
     for(col=0; col<mCols; col++) if( mCubes[mRows-1][    col]==0 ) markRegion((short)2,mRows-1,     col);
258
           
259
     for(row=0; row<mRows; row++)
260
        for(col=0; col<mCols; col++)
261
           {
262
           if( mCubes[row][col] == 0 ) { numWater++; markRegion( (short)(2*numWater ),row,col); mEdges.add(new Edge(SOUTH,row-1,col)); }
263
           if( mCubes[row][col] == 1 ) { numLand ++; markRegion( (short)(2*numLand+1),row,col); mEdges.add(new Edge(NORTH,row  ,col)); }
264
           }
265
     
266
     // now we potentially need to kick out some Edges . Otherwise the following does not work:
267
     //
268
     // 0 1 0
269
     // 1 0 1
270
     // 0 1 0
271
     
272
     mEdgeNum= mEdges.size();
273
     int initCol, initRow, initSide, lastSide;
274
     Edge e1,e2;
275
     
276
     for(int edge=0; edge<mEdgeNum; edge++)
277
       {
278
       e1 = mEdges.get(edge);
279
       initRow= e1.row;
280
       initCol= e1.col;
281
       initSide=e1.side;
282

    
283
       do
284
         {
285
         mSideWalls++;
286

    
287
         if( e1.side==NORTH || e1.side==SOUTH )
288
           {
289
           for(int j=edge+1;j<mEdgeNum;j++)
290
             {
291
             e2 = mEdges.get(j);
292

    
293
             if( e2.side==e1.side && e2.row==e1.row && e2.col==e1.col )
294
               {
295
               mEdges.remove(j);
296
               mEdgeNum--;
297
               j--;
298
               }
299
             }
300
           }
301

    
302
         lastSide = e1.side;
303
         e1 = getNextEdge(e1);
304
         if( e1.side!=lastSide ) mSideBends++;
305
         }
306
       while( e1.col!=initCol || e1.row!=initRow || e1.side!=initSide );
307
       }
308
     }
309

    
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311
// when calling, make sure that newVal != val
312
   
313
  private void markRegion(short newVal, int row, int col)
314
     {
315
     int val = mCubes[row][col];
316
     mCubes[row][col] = newVal;
317
     
318
     if( row>0       && mCubes[row-1][col  ]==val ) markRegion(newVal, row-1, col  );
319
     if( row<mRows-1 && mCubes[row+1][col  ]==val ) markRegion(newVal, row+1, col  );
320
     if( col>0       && mCubes[row  ][col-1]==val ) markRegion(newVal, row  , col-1);
321
     if( col<mCols-1 && mCubes[row  ][col+1]==val ) markRegion(newVal, row  , col+1);
322
     }
323
   
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325
   
326
  private void createNormals(boolean front, int row, int col)
327
     {
328
     int td,lr; 
329
      
330
     int nw = (col>0       && row>0      ) ? (mCubes[row-1][col-1]%2) : 0;
331
     int w  = (col>0                     ) ? (mCubes[row  ][col-1]%2) : 0;
332
     int n  = (               row>0      ) ? (mCubes[row-1][col  ]%2) : 0;
333
     int c  =                                (mCubes[row  ][col  ]%2);
334
     int sw = (col>0       && row<mRows-1) ? (mCubes[row+1][col-1]%2) : 0;
335
     int s  = (               row<mRows-1) ? (mCubes[row+1][col  ]%2) : 0;
336
     int ne = (col<mCols-1 && row>0      ) ? (mCubes[row-1][col+1]%2) : 0;
337
     int e  = (col<mCols-1               ) ? (mCubes[row  ][col+1]%2) : 0;
338
     int se = (col<mCols-1 && row<mRows-1) ? (mCubes[row+1][col+1]%2) : 0;
339

    
340
     if(front)
341
       {
342
       mNormalZ[0] = 1.0f;
343
       mNormalZ[1] = 1.0f;
344
       mNormalZ[2] = 1.0f;
345
       mNormalZ[3] = 1.0f;
346
       }
347
     else
348
       {
349
       mNormalZ[0] =-1.0f;
350
       mNormalZ[1] =-1.0f;
351
       mNormalZ[2] =-1.0f;
352
       mNormalZ[3] =-1.0f;
353
       }
354

    
355
     td = nw+n-w-c;
356
     lr = c+n-w-nw;
357
     if( td<0 ) td=-1;
358
     if( td>0 ) td= 1;
359
     if( lr<0 ) lr=-1;
360
     if( lr>0 ) lr= 1;
361
     mNormalX[0] = lr*R;
362
     mNormalY[0] = td*R;
363
     
364
     td = w+c-sw-s;
365
     lr = c+s-w-sw;
366
     if( td<0 ) td=-1;
367
     if( td>0 ) td= 1;
368
     if( lr<0 ) lr=-1;
369
     if( lr>0 ) lr= 1;
370
     mNormalX[1] = lr*R;
371
     mNormalY[1] = td*R;
372
     
373
     td = n+ne-c-e;
374
     lr = e+ne-c-n;
375
     if( td<0 ) td=-1;
376
     if( td>0 ) td= 1;
377
     if( lr<0 ) lr=-1;
378
     if( lr>0 ) lr= 1;
379
     mNormalX[2] = lr*R;
380
     mNormalY[2] = td*R;
381
     
382
     td = c+e-s-se;
383
     lr = e+se-c-s;
384
     if( td<0 ) td=-1;
385
     if( td>0 ) td= 1;
386
     if( lr<0 ) lr=-1;
387
     if( lr>0 ) lr= 1;
388
     mNormalX[3] = lr*R;
389
     mNormalY[3] = td*R;
390
     }
391

    
392
///////////////////////////////////////////////////////////////////////////////////////////////////
393

    
394
  private void buildFrontBackGrid(boolean front, float[] attribs1, float[] attribs2)
395
     {
396
     int last, current;
397
     boolean seenLand=false;
398
     boolean lastBlockIsNE = false;
399
     boolean currentBlockIsNE;
400
     float vectZ = (front ? 0.5f : -0.5f);
401

    
402
     for(int row=0; row<mRows; row++)
403
       {
404
       last =0;
405
         
406
       for(int col=0; col<mCols; col++)
407
         {
408
         current = mCubes[row][col];
409

    
410
         if( current%2 == 1 )
411
           {
412
           currentBlockIsNE = isNE(row,col);
413

    
414
           if( !seenLand && !front && ((currVert%2==1)^currentBlockIsNE) )
415
             {
416
             repeatLast(attribs1,attribs2);
417
             }
418

    
419
           createNormals(front,row,col);
420

    
421
           if( currentBlockIsNE )
422
             {
423
             if( (last!=current) || !lastBlockIsNE )
424
               {
425
               if( seenLand  && (last != current) ) repeatLast(attribs1,attribs2);
426
               addFrontVertex( 0, vectZ, col, row, attribs1,attribs2);
427
               if( seenLand  && (last != current) ) repeatLast(attribs1,attribs2);
428
               if( !lastBlockIsNE || (!front && !seenLand) ) repeatLast(attribs1,attribs2);
429
               addFrontVertex( 1, vectZ, col, row+1, attribs1,attribs2);
430
               }
431
             addFrontVertex( 2, vectZ, col+1, row  , attribs1,attribs2);
432
             addFrontVertex( 3, vectZ, col+1, row+1, attribs1,attribs2);
433
             }
434
           else
435
             {
436
             if( (last!=current) || lastBlockIsNE )
437
               {
438
               if( seenLand  && (last != current) ) repeatLast(attribs1,attribs2);
439
               addFrontVertex( 1, vectZ, col, row+1, attribs1,attribs2);
440
               if( seenLand  && (last != current) ) repeatLast(attribs1,attribs2);
441
               if( lastBlockIsNE || (!front && !seenLand) ) repeatLast(attribs1,attribs2);
442
               addFrontVertex( 0, vectZ, col, row, attribs1,attribs2);
443
               }
444
             addFrontVertex( 3, vectZ, col+1, row+1, attribs1,attribs2);
445
             addFrontVertex( 2, vectZ, col+1, row  , attribs1,attribs2);
446
             }
447

    
448
           seenLand = true;
449
           lastBlockIsNE = currentBlockIsNE;
450
           }
451
            
452
         last = current;
453
         }
454
       }
455
     }
456

    
457
///////////////////////////////////////////////////////////////////////////////////////////////////
458

    
459
  private void buildSideGrid(float[] attribs1,float[] attribs2)
460
     {
461
     for(int i=0; i<mEdgeNum; i++)
462
       {
463
       buildIthSide(mEdges.get(i), attribs1, attribs2);
464
       }
465
     }
466

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

    
469
  private void buildIthSide(Edge curr, float[] attribs1, float[] attribs2)
470
     {
471
     Edge prev, next;
472
     int col, row, side;
473

    
474
     if( curr.side==NORTH ) // water outside
475
       {
476
       prev = new Edge(WEST,curr.row,curr.col);
477
       }
478
     else                   // land outside; we need to move forward one link because we are
479
       {                    // going in opposite direction and we need to start from a bend.
480
       prev = curr;
481
       curr = new Edge(EAST,curr.row+1,curr.col-1);
482
       }
483

    
484
     for(int slice=0; slice<mSlices; slice++)
485
       {
486
       col = curr.col;
487
       row = curr.row;
488
       side= curr.side;
489
       next = getNextEdge(curr);
490
     
491
       addSideVertex(curr,true,slice+1,prev.side,attribs1,attribs2);
492

    
493
       do
494
         {
495
         if( prev.side!=curr.side )
496
           {
497
           addSideVertex(curr,true,slice+1,prev.side,attribs1,attribs2);
498
           addSideVertex(curr,true,slice  ,prev.side,attribs1,attribs2);
499
           }
500
       
501
         addSideVertex(curr,false,slice+1,next.side,attribs1,attribs2);
502
         addSideVertex(curr,false,slice  ,next.side,attribs1,attribs2);
503
       
504
         prev = curr;
505
         curr = next;
506
         next = getNextEdge(curr);
507
         }
508
       while( curr.col!=col || curr.row!=row || curr.side!=side );
509
     
510
       repeatLast(attribs1,attribs2);
511
       }
512
     }
513

    
514
///////////////////////////////////////////////////////////////////////////////////////////////////
515

    
516
  private Edge getNextEdge(Edge curr)
517
     {
518
     int col = curr.col;
519
     int row = curr.row;
520

    
521
     switch(curr.side) 
522
       {
523
       case NORTH: if( col==mCols-1 ) 
524
                     return new Edge(EAST,row,col);
525
                   if( row>0 && mCubes[row-1][col+1]==mCubes[row][col] )
526
                     return new Edge(WEST,row-1,col+1);
527
                   if( mCubes[row][col+1]==mCubes[row][col] )
528
                     return new Edge(NORTH,row,col+1);
529
                   else  
530
                     return new Edge(EAST,row,col);
531
                   
532
       case SOUTH: if( col==0 ) 
533
                     return new Edge(WEST,row,col);
534
                   if( (row<mRows-1) && mCubes[row+1][col-1]==mCubes[row][col] )
535
                     return new Edge(EAST,row+1,col-1); 
536
                   if( mCubes[row][col-1]==mCubes[row][col] )
537
                     return new Edge(SOUTH,row,col-1);
538
                   else
539
                     return new Edge(WEST,row,col); 
540
                     
541
       case EAST : if( row==mRows-1 ) 
542
                     return new Edge(SOUTH,row,col);
543
                   if( (col<mCols-1) && mCubes[row+1][col+1]==mCubes[row][col] )
544
                     return new Edge(NORTH,row+1,col+1);
545
                   if( mCubes[row+1][col]==mCubes[row][col] )
546
                     return new Edge(EAST,row+1,col);
547
                   else 
548
                     return new Edge(SOUTH,row,col);
549
                   
550
       default   : if( row==0 )
551
                     return new Edge(NORTH,row,col);
552
                   if( col>0 && mCubes[row-1][col-1]==mCubes[row][col] )
553
                     return new Edge(SOUTH,row-1,col-1);
554
                   if( mCubes[row-1][col]==mCubes[row][col] )
555
                     return new Edge(WEST,row-1,col);
556
                   else
557
                     return new Edge(NORTH,row,col);     
558
       }
559
     }
560

    
561
///////////////////////////////////////////////////////////////////////////////////////////////////
562

    
563
  private void fillInflate(int row, int col)
564
    {
565
    int diff;
566

    
567
         if( col==0     ) mInflateX[row][col] = -1;
568
    else if( col==mCols ) mInflateX[row][col] = +1;
569
    else
570
      {
571
      if( row==0 )
572
        {
573
        diff = mCubes[0][col-1]-mCubes[0][col];
574
        }
575
      else if( row==mRows )
576
        {
577
        diff = mCubes[mRows-1][col-1]-mCubes[mRows-1][col];
578
        }
579
      else
580
        {
581
        diff = (mCubes[row  ][col-1]-mCubes[row  ][col]) +
582
               (mCubes[row-1][col-1]-mCubes[row-1][col]) ;
583

    
584
        if( diff==-2 ) diff=-1;
585
        if( diff== 2 ) diff= 1;
586
        }
587

    
588
      mInflateX[row][col] = (byte)diff;
589
      }
590

    
591
         if( row==0     ) mInflateY[row][col] = +1;
592
    else if( row==mRows ) mInflateY[row][col] = -1;
593
    else
594
      {
595
      if( col==0 )
596
        {
597
        diff = mCubes[row][0]-mCubes[row-1][0];
598
        }
599
      else if( col==mCols )
600
        {
601
        diff = mCubes[row][mCols-1]-mCubes[row-1][mCols-1];
602
        }
603
      else
604
        {
605
        diff = (mCubes[row  ][col-1]+mCubes[row  ][col]) -
606
               (mCubes[row-1][col-1]+mCubes[row-1][col]) ;
607

    
608
        if( diff==-2 ) diff=-1;
609
        if( diff== 2 ) diff= 1;
610
        }
611

    
612
      mInflateY[row][col] = (byte)diff;
613
      }
614
    }
615

    
616
///////////////////////////////////////////////////////////////////////////////////////////////////
617

    
618
  private void addFrontVertex(int index, float vectZ, int col, int row, float[] attribs1, float[] attribs2)
619
     {
620
     float x = (float)col/mCols;
621
     float y = (float)row/mRows;
622

    
623
     attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB  ] = x-0.5f;
624
     attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+1] = 0.5f-y;
625
     attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+2] = vectZ;
626

    
627
     attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB  ] = mNormalX[index];
628
     attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+1] = mNormalY[index];
629
     attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+2] = mNormalZ[index];
630

    
631
     attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB  ] = mInflateX[row][col]/2.0f;
632
     attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
633
     attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+2] = vectZ;
634

    
635
     if( vectZ>0 )
636
       {
637
       attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[FRONT] +       x  * mTexMappingW[FRONT];
638
       attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[FRONT] + (1.0f-y) * mTexMappingH[FRONT];
639
       }
640
     else
641
       {
642
       attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[BACK]  +       x  * mTexMappingW[BACK];
643
       attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[BACK]  + (1.0f-y) * mTexMappingH[BACK];
644
       }
645

    
646
     attribs2[VERT2_ATTRIBS*currVert + ASS_ATTRIB] = DEFAULT_ASSOCIATION;
647

    
648
     currVert++;
649
     }
650

    
651
///////////////////////////////////////////////////////////////////////////////////////////////////
652

    
653
  private void addSideVertex(Edge curr, boolean back, int slice, int side, float[] attribs1, float[] attribs2)
654
     {
655
     float x, y, z;
656
     int row, col;
657

    
658
     switch(curr.side)
659
       {
660
       case NORTH: row = curr.row;
661
                   col = (back ? (curr.col  ):(curr.col+1));
662
                   x = (float)col/mCols;
663
                   y = 0.5f - (float)row/mRows;
664
                   z = 0.5f - (float)slice/mSlices;
665

    
666
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB  ] = x - 0.5f;
667
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+1] = y;
668
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+2] = z;
669

    
670
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB  ] = side==NORTH ? 0.0f : (side==WEST?-R:R);
671
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+1] = 1.0f;
672
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+2] = (slice==0 ? R : (slice==mSlices ? -R:0) );
673

    
674
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB  ] = mInflateX[row][col]/2.0f;
675
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
676
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+2] = z;
677

    
678
                   attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[TOP] +       x  * mTexMappingW[TOP];
679
                   attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[TOP] + (0.5f-z) * mTexMappingH[TOP];
680
                   attribs2[VERT2_ATTRIBS*currVert + ASS_ATTRIB  ] = DEFAULT_ASSOCIATION;
681

    
682
                   break;
683
       case SOUTH: row = curr.row+1;
684
                   col = (back ? (curr.col+1):(curr.col));
685
                   x = (float)col/mCols;
686
                   y = 0.5f - (float)row/mRows;
687
                   z = 0.5f - (float)slice/mSlices;
688

    
689
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB  ] = x - 0.5f;
690
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+1] = y;
691
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+2] = z;
692

    
693
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB  ] = side==SOUTH ? 0.0f: (side==EAST?-R:R);
694
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+1] =-1.0f;
695
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+2] = (slice==0 ? R : (slice==mSlices ? -R:0) );
696

    
697
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB  ] = mInflateX[row][col]/2.0f;
698
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
699
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+2] = z;
700

    
701
                   attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[BOTTOM] +       x  * mTexMappingW[BOTTOM];
702
                   attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[BOTTOM] + (0.5f-z) * mTexMappingH[BOTTOM];
703
                   attribs2[VERT2_ATTRIBS*currVert + ASS_ATTRIB  ] = DEFAULT_ASSOCIATION;
704

    
705
                   break;
706
       case WEST : row = (back  ? (curr.row+1):(curr.row));
707
                   col = curr.col;
708
                   x = (float)col/mCols -0.5f;
709
                   y = (float)row/mRows;
710
                   z = 0.5f - (float)slice/mSlices;
711

    
712
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB  ] = x;
713
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+1] = 0.5f - y;
714
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+2] = z;
715

    
716
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB  ] =-1.0f;
717
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+1] = side==WEST ? 0.0f : (side==NORTH?-R:R);
718
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+2] = (slice==0 ? R : (slice==mSlices ? -R:0) );
719

    
720
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB  ] = mInflateX[row][col]/2.0f;
721
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
722
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+2] = z;
723

    
724
                   attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[LEFT] + (0.5f-z) * mTexMappingW[LEFT];
725
                   attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[LEFT] + (1.0f-y) * mTexMappingH[LEFT];
726
                   attribs2[VERT2_ATTRIBS*currVert + ASS_ATTRIB  ] = DEFAULT_ASSOCIATION;
727

    
728
                   break;
729
       case EAST : row = (back  ? (curr.row):(curr.row+1));
730
                   col = (curr.col+1);
731
                   x = (float)col/mCols -0.5f;
732
                   y = (float)row/mRows;
733
                   z = 0.5f - (float)slice/mSlices;
734

    
735
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB  ] = x;
736
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+1] = 0.5f - y;
737
                   attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+2] = z;
738

    
739
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB  ] = 1.0f;
740
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+1] = side==EAST ? 0.0f : (side==SOUTH?-R:R);
741
                   attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+2] = (slice==0 ? R : (slice==mSlices ? -R:0) );
742

    
743
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB  ] = mInflateX[row][col]/2.0f;
744
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
745
                   attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+2] = z;
746

    
747
                   attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[RIGHT] + (0.5f-z) * mTexMappingW[RIGHT];
748
                   attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[RIGHT] + (1.0f-y) * mTexMappingH[RIGHT];
749
                   attribs2[VERT2_ATTRIBS*currVert + ASS_ATTRIB  ] = DEFAULT_ASSOCIATION;
750

    
751
                   break;
752
       }
753

    
754
     currVert++;
755
     }
756

    
757
///////////////////////////////////////////////////////////////////////////////////////////////////
758

    
759
   private void repeatLast(float[] attribs1, float[] attribs2)
760
     {
761
     attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB  ] = attribs1[VERT1_ATTRIBS*(currVert-1) + POS_ATTRIB  ];
762
     attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+1] = attribs1[VERT1_ATTRIBS*(currVert-1) + POS_ATTRIB+1];
763
     attribs1[VERT1_ATTRIBS*currVert + POS_ATTRIB+2] = attribs1[VERT1_ATTRIBS*(currVert-1) + POS_ATTRIB+2];
764

    
765
     attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB  ] = attribs1[VERT1_ATTRIBS*(currVert-1) + NOR_ATTRIB  ];
766
     attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+1] = attribs1[VERT1_ATTRIBS*(currVert-1) + NOR_ATTRIB+1];
767
     attribs1[VERT1_ATTRIBS*currVert + NOR_ATTRIB+2] = attribs1[VERT1_ATTRIBS*(currVert-1) + NOR_ATTRIB+2];
768

    
769
     attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB  ] = attribs1[VERT1_ATTRIBS*(currVert-1) + INF_ATTRIB  ];
770
     attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+1] = attribs1[VERT1_ATTRIBS*(currVert-1) + INF_ATTRIB+1];
771
     attribs1[VERT1_ATTRIBS*currVert + INF_ATTRIB+2] = attribs1[VERT1_ATTRIBS*(currVert-1) + INF_ATTRIB+2];
772

    
773
     attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB  ] = attribs2[VERT2_ATTRIBS*(currVert-1) + TEX_ATTRIB  ];
774
     attribs2[VERT2_ATTRIBS*currVert + TEX_ATTRIB+1] = attribs2[VERT2_ATTRIBS*(currVert-1) + TEX_ATTRIB+1];
775
     attribs2[VERT2_ATTRIBS*currVert + ASS_ATTRIB  ] = DEFAULT_ASSOCIATION;
776

    
777
     currVert++;
778
     }
779

    
780
///////////////////////////////////////////////////////////////////////////////////////////////////
781

    
782
  private void build()
783
     {
784
     float[] attribs1= new float[VERT1_ATTRIBS*numVertices];
785
     float[] attribs2= new float[VERT2_ATTRIBS*numVertices];
786

    
787
     buildFrontBackGrid(true,attribs1,attribs2);
788

    
789
     if( mSlices>0 )
790
       {
791
       repeatLast(attribs1,attribs2);
792
       if( currVert%2==1 ) repeatLast(attribs1,attribs2);
793
       buildSideGrid(attribs1,attribs2);
794
       buildFrontBackGrid(false,attribs1,attribs2);
795
       }
796

    
797
     mEdges.clear();
798
     mEdges = null;
799
     mCubes = null;
800
     mInflateX = null;
801
     mInflateY = null;
802

    
803
     if( currVert!=numVertices )
804
       android.util.Log.e("MeshCubes", "currVert " +currVert+" numVertices="+numVertices );
805

    
806
     setAttribs(attribs1,attribs2);
807
     }
808

    
809
///////////////////////////////////////////////////////////////////////////////////////////////////
810
// PUBLIC API
811
///////////////////////////////////////////////////////////////////////////////////////////////////
812
/**
813
 * Creates the underlying mesh of vertices, normals, texture coords.
814
 *    
815
 * @param cols   Integer helping to parse the next parameter.
816
 * @param desc   String describing the subset of a MxNx1 cuboid that we want to create.
817
 *               Its MxN characters - all 0 or 1 - decide of appropriate field is taken or not.
818
 *               <p></p>
819
 *               <p>
820
 *               <pre>
821
 *               For example, (cols=2, desc="111010", slices=1) describes the following shape:
822
 *
823
 *               XX
824
 *               X
825
 *               X
826
 *
827
 *               whereas (cols=2,desc="110001", slices=1) describes
828
 *
829
 *               XX
830
 *
831
 *                X
832
 *               </pre>
833
 *               </p>
834
 * @param slices Number of slices, i.e. 'depth' of the Mesh.
835
 */
836
 public MeshCubes(int cols, String desc, int slices)
837
   {
838
   super();
839
   Static4D map = new Static4D(0.0f,0.0f,1.0f,1.0f);
840
   fillTexMappings(map,map,map,map,map,map);
841
   prepareDataStructures(cols,desc,slices);
842
   build();
843
   }
844

    
845
///////////////////////////////////////////////////////////////////////////////////////////////////
846
/**
847
 * Creates the underlying mesh of vertices, normals, texture coords with custom texture mappings.
848
 *
849
 * The mappings decide what part of the texture appears on a given side. Example:
850
 * front = (0.0,0.5,0.5,1.0) means that the front side of the grid will be textured with the
851
 * bottom-left quadrant of the texture.
852
 *
853
 * Default is: each of the 6 sides maps to the whole texture, i.e. (0.0,0.0,1.0,1.0)
854
 *
855
 * @param cols   Integer helping to parse the next parameter.
856
 * @param desc   String describing the subset of a MxNx1 cuboid that we want to create.
857
 *               Its MxN characters - all 0 or 1 - decide of appropriate field is taken or not.
858
 *               <p></p>
859
 *               <p>
860
 *               <pre>
861
 *               For example, (cols=2, desc="111010", slices=1) describes the following shape:
862
 *
863
 *               XX
864
 *               X
865
 *               X
866
 *
867
 *               whereas (cols=2,desc="110001", slices=1) describes
868
 *
869
 *               XX
870
 *
871
 *                X
872
 *               </pre>
873
 *               </p>
874
 * @param slices Number of slices, i.e. 'depth' of the Mesh.
875
 * @param front  Texture mapping the front side maps to.
876
 * @param back   Texture mapping the back side maps to.
877
 * @param left   Texture mapping the left side maps to.
878
 * @param right  Texture mapping the right side maps to.
879
 * @param top    Texture mapping the top side maps to.
880
 * @param bottom Texture mapping the bottom side maps to.
881
 */
882
 public MeshCubes(int cols, String desc, int slices, Static4D front, Static4D back, Static4D left, Static4D right, Static4D top, Static4D bottom)
883
   {
884
   super();
885
   fillTexMappings(front,back,left,right,top,bottom);
886
   prepareDataStructures(cols,desc,slices);
887
   build();
888
   }
889

    
890
///////////////////////////////////////////////////////////////////////////////////////////////////
891
/**
892
 * Creates a full, hole-less underlying mesh of vertices, normals, texture coords and colors.
893
 *
894
 * @param cols   Number of columns, i.e. 'width' of the Mesh.
895
 * @param rows   Number of rows, i.e. 'height' of the Mesh.
896
 * @param slices Number of slices, i.e. 'depth' of the Mesh.
897
 */
898
 public MeshCubes(int cols, int rows, int slices)
899
   {
900
   super();
901
   Static4D map = new Static4D(0.0f,0.0f,1.0f,1.0f);
902
   fillTexMappings(map,map,map,map,map,map);
903
   prepareDataStructures(cols,rows,slices);
904
   build();
905
   }
906

    
907
///////////////////////////////////////////////////////////////////////////////////////////////////
908
/**
909
 * Creates a full, hole-less underlying mesh of vertices, normals, texture coords and colors with
910
 * custom texture mappings.
911
 *
912
 * The mappings decide what part of the texture appears on a given side. Example:
913
 * front = (0.0,0.5,0.5,1.0) means that the front side of the grid will be textured with the
914
 * bottom-left quadrant of the texture.
915
 *
916
 * Default is: each of the 6 sides maps to the whole texture, i.e. (0.0,0.0,1.0,1.0)
917
 *
918
 * @param cols   Number of columns, i.e. 'width' of the Mesh.
919
 * @param rows   Number of rows, i.e. 'height' of the Mesh.
920
 * @param slices Number of slices, i.e. 'depth' of the Mesh.
921
 * @param front  Texture mapping the front side maps to.
922
 * @param back   Texture mapping the back side maps to.
923
 * @param left   Texture mapping the left side maps to.
924
 * @param right  Texture mapping the right side maps to.
925
 * @param top    Texture mapping the top side maps to.
926
 * @param bottom Texture mapping the bottom side maps to.
927
 */
928
 public MeshCubes(int cols, int rows, int slices, Static4D front, Static4D back, Static4D left, Static4D right, Static4D top, Static4D bottom)
929
   {
930
   super();
931
   fillTexMappings(front,back,left,right,top,bottom);
932
   prepareDataStructures(cols,rows,slices);
933
   build();
934
   }
935

    
936
///////////////////////////////////////////////////////////////////////////////////////////////////
937
/**
938
 * Copy constructor.
939
 */
940
 public MeshCubes(MeshCubes mesh, boolean deep)
941
   {
942
   super(mesh,deep);
943
   }
944

    
945
///////////////////////////////////////////////////////////////////////////////////////////////////
946
/**
947
 * Copy the Mesh.
948
 *
949
 * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
950
 *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
951
 *             coordinates and effect assocciations, is always deep copied).
952
 */
953
 public MeshCubes copy(boolean deep)
954
   {
955
   return new MeshCubes(this,deep);
956
   }
957
 }
(2-2/7)