Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedCubesGrid.java @ 84ee2a6a

1 d333eb6b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 6a06a912 Leszek Koltunski
package org.distorted.library;
21
22
import java.nio.ByteBuffer;
23
import java.nio.ByteOrder;
24
import java.util.ArrayList;
25
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27
28 e458a4ba Leszek Koltunski
class DistortedCubesGrid extends DistortedObjectGrid
29 6a06a912 Leszek Koltunski
   {
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 ce7f3833 Leszek Koltunski
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 6a06a912 Leszek Koltunski
   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 ce7f3833 Leszek Koltunski
   private static final float[] mNormalZ = new float[4];
52
53 6a06a912 Leszek Koltunski
   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 39cbf9dc Leszek Koltunski
     }
66 6a06a912 Leszek Koltunski
   
67
   private int mCols, mRows;
68
   private short[][] mCubes;
69 39cbf9dc Leszek Koltunski
   private ArrayList<Edge> mEdges = new ArrayList<>();
70 ce7f3833 Leszek Koltunski
71 84ee2a6a Leszek Koltunski
   private int remainingVert;
72 ce7f3833 Leszek Koltunski
73
///////////////////////////////////////////////////////////////////////////////////////////////////
74
// a Block is split into two triangles along the NE-SW line iff it is in the top-right
75
// or bottom-left quadrant of the grid.
76
77
   private boolean isNE(int row,int col)
78
     {
79
     return ( (row<=(mRows-1)/2)^(col<=(mCols-1)/2) );
80
     }
81
82 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
83 84ee2a6a Leszek Koltunski
// return the number of vertices our grid will contain
84 6a06a912 Leszek Koltunski
85
   private int computeDataLength(boolean frontOnly)
86
      {
87 84ee2a6a Leszek Koltunski
      int frontWalls=0, frontSegments=0, sideWalls=0, sideBends=0, triangleShifts=0, windingShifts=0;
88 ce7f3833 Leszek Koltunski
      int shiftCol = (mCols-1)/2;
89
90 84ee2a6a Leszek Koltunski
      //boolean seenLand=false;
91
      //boolean firstBlockIsNE=false;
92 ce7f3833 Leszek Koltunski
      boolean lastBlockIsNE=false;
93
      boolean thisBlockIsNE;        // the block we are currently looking at is split into
94
                                    // two triangles along the NE-SW line (rather than NW-SE)
95
96 6a06a912 Leszek Koltunski
      for(int i=0; i<mRows; i++)
97 ce7f3833 Leszek Koltunski
         {
98
         if( mCols>=2 && (mCubes[i][shiftCol]%2 == 1) && (mCubes[i][shiftCol+1]%2 == 1) ) triangleShifts++;
99
100 6a06a912 Leszek Koltunski
         for(int j=0; j<mCols; j++)
101
            {
102
            if( mCubes[i][j]%2 == 1 )  // land
103
              {
104 ce7f3833 Leszek Koltunski
              thisBlockIsNE = isNE(i,j);
105 84ee2a6a Leszek Koltunski
              if( thisBlockIsNE^lastBlockIsNE ) windingShifts++;
106 ce7f3833 Leszek Koltunski
              lastBlockIsNE = thisBlockIsNE;
107 84ee2a6a Leszek Koltunski
/*
108 ce7f3833 Leszek Koltunski
              if( !seenLand )
109
                {
110
                seenLand=true;
111 84ee2a6a Leszek Koltunski
                firstBlockIsNE = thisBlockIsNE;
112 ce7f3833 Leszek Koltunski
                }
113 84ee2a6a Leszek Koltunski
*/
114 6a06a912 Leszek Koltunski
              frontWalls++;
115
              if( j==mCols-1 || mCubes[i][j+1]%2 == 0 ) frontSegments++;
116
              }
117
              
118
            if( (i==0 && mCubes[i][j]!=2) || (i!=0 && mCubes[i][j] != mCubes[i-1][j  ]) ) sideWalls++; // up
119
            if( (j==0 && mCubes[i][j]!=2) || (j!=0 && mCubes[i][j] != mCubes[i  ][j-1]) ) sideWalls++; // left
120
            if( i==mRows-1 && mCubes[i][j]!=2                                           ) sideWalls++; // bottom
121
            if( j==mCols-1 && mCubes[i][j]!=2                                           ) sideWalls++; // right
122
            }
123 ce7f3833 Leszek Koltunski
         }
124
125 6a06a912 Leszek Koltunski
      int edges= mEdges.size();
126
      
127
      for(int i=0; i<edges; i++) 
128
        {
129
        Edge curr = mEdges.get(i);
130
        Edge next = getNextEdge(curr);
131
        int startX = curr.col;
132
        int startY = curr.row;
133
        int startS = curr.side;
134
        
135
        do
136
          {
137
          if( next.side != curr.side ) sideBends++; 
138
          curr  = next; 
139
          next = getNextEdge(curr);
140
          }
141
        while( curr.col!=startX || curr.row!=startY || curr.side!=startS );
142
        }
143 ce7f3833 Leszek Koltunski
144 84ee2a6a Leszek Koltunski
      int frontVert = 2*( frontWalls + 2*frontSegments - 1) +2*triangleShifts + windingShifts;
145 39cbf9dc Leszek Koltunski
      int sideVert  = 2*( sideWalls + sideBends + edges -1);
146 84ee2a6a Leszek Koltunski
      int firstWinding=0;
147
      //int secondWinding=0;
148 ce7f3833 Leszek Koltunski
149 84ee2a6a Leszek Koltunski
      if( !frontOnly )
150
        {
151
        if( (frontVert+1)%2==1 ) firstWinding=1;
152
        //if( (((frontVert+1)+firstWinding+(1+sideVert+1))%2==1)^firstBlockIsNE ) secondWinding=1;
153
        }
154 ce7f3833 Leszek Koltunski
155 84ee2a6a Leszek Koltunski
      int dataL = frontOnly ? frontVert : (frontVert+1) +firstWinding+ (1+sideVert+1) + (1+frontVert);
156
157
      //android.util.Log.e("CUBES","triangleShifts="+triangleShifts+" windingShifts="+windingShifts);
158
      //android.util.Log.e("CUBES","Winding1="+firstWinding+" Winding2="+secondWinding);
159
      //android.util.Log.e("CUBES","frontVert="+frontVert+" sideVert="+sideVert);
160
      //android.util.Log.e("CUBES", "frontW="+frontWalls+" fSegments="+frontSegments+" sWalls="+sideWalls+" sSegments="+edges+" sideBends="+sideBends+" dataLen="+dataL );
161 6a06a912 Leszek Koltunski
      
162
      return dataL<0 ? 0:dataL;
163
      }
164
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166
/*
167
   private static String debug(short[] val)
168
     {
169 ce7f3833 Leszek Koltunski
     String ret="";j
170 6a06a912 Leszek Koltunski
     
171
     for(int i=0; i<val.length; i++) ret+=(" "+val[i]); 
172
     
173
     return ret;
174
     }
175
*/
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177
/*
178
   private static String debug(float[] val, int stop)
179
     {
180
     String ret="";
181
182
     for(int i=0; i<val.length; i++) 
183
        {
184
        if( i%stop==0 ) ret+="\n";
185
        ret+=(" "+val[i]);
186
        }
187
188
     return ret;
189
     }
190
*/  
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192
/*
193
   private static String debug(Edge e)
194
     {
195
     String d = "";
196
     
197
     switch(e.side)
198
       {
199
       case NORTH: d+="NORTH "; break;
200
       case SOUTH: d+="SOUTH "; break;
201
       case WEST : d+="WEST  "; break;
202
       case EAST : d+="EAST  "; break;
203
       }
204
     
205
     d+=("("+e.row+","+e.col+")");
206
     
207
     return d;
208
     }   
209
*/ 
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211 0729bc41 Leszek Koltunski
// desc is guaranteed to be padded with 0s in the end (DistortedCubes constructor does it)
212 6a06a912 Leszek Koltunski
213 2e96ee72 Leszek Koltunski
   private void prepareDataStructures(int cols, String desc, boolean frontOnly)
214 6a06a912 Leszek Koltunski
     {
215
     mRows     =0;
216
     mCols     =0;
217
     dataLength=0;
218
     
219 0729bc41 Leszek Koltunski
     if( cols>0 && desc.contains("1") )
220 6a06a912 Leszek Koltunski
       {
221 0729bc41 Leszek Koltunski
       mCols = cols;
222
       mRows = desc.length()/cols;
223 6a06a912 Leszek Koltunski
224 0729bc41 Leszek Koltunski
       mCubes = new short[mRows][mCols];
225 6a06a912 Leszek Koltunski
       
226 0729bc41 Leszek Koltunski
       for(int j=0; j<mCols; j++)
227
         for(int i=0; i<mRows; i++)
228
           mCubes[i][j] = (short)(desc.charAt(i*mCols+j) == '1' ? 1:0);
229 6a06a912 Leszek Koltunski
       
230 0729bc41 Leszek Koltunski
       markRegions();
231
       dataLength = computeDataLength(frontOnly);
232 84ee2a6a Leszek Koltunski
233
       remainingVert = dataLength;
234 6a06a912 Leszek Koltunski
       }
235
     }
236
 
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238
// Mark all the 'regions' of our grid  - i.e. separate pieces of 'land' (connected blocks that will 
239
// be rendered) and 'water' (connected holes in between) with integers. Each connected block of land
240
// gets a unique odd integer, each connected block of water a unique even integer.
241
//
242
// Water on the edges of the grid is also considered connected to itself!   
243
//   
244
// This function also creates a list of 'Edges'. Each Edge is a data structure from which later on we
245 2e96ee72 Leszek Koltunski
// will start building the side walls of each connected block of land (and sides of holes of water
246 6a06a912 Leszek Koltunski
// inside)   
247
   
248
   private void markRegions()
249
     {
250
     int i, j, numWater=1, numLand=0;
251
     
252
     for(i=0; i<mRows;i++) if( mCubes[      i][      0]==0 ) markRegion((short)2,      i,       0);
253
     for(i=0; i<mRows;i++) if( mCubes[      i][mCols-1]==0 ) markRegion((short)2,      i, mCols-1);
254
     for(i=0; i<mCols;i++) if( mCubes[0      ][      i]==0 ) markRegion((short)2,      0,       i);
255
     for(i=0; i<mCols;i++) if( mCubes[mRows-1][      i]==0 ) markRegion((short)2,mRows-1,       i);
256
           
257
     for(i=0; i<mRows; i++)
258
        for(j=0; j<mCols; j++)
259
           {
260
           if( mCubes[i][j] == 0 ) { numWater++; markRegion( (short)(2*numWater ),i,j); mEdges.add(new Edge(NORTH,i,j)); }
261
           if( mCubes[i][j] == 1 ) { numLand ++; markRegion( (short)(2*numLand+1),i,j); mEdges.add(new Edge(NORTH,i,j)); }
262
           }
263
     
264
     // now we potentially need to kick out some Edges - precisely the edges with water inside -
265
     // which are surrounded by more than one type of land. Otherwise the following does not work:
266
     //
267
     // 0 1 0
268
     // 1 0 1
269
     // 0 1 0
270
     //
271
     // The 'water inside' edges that did not get kicked out by this procedure need to be transformed
272
     // with Edge(NORTH,row,col) -> Edge(SOUTH,row-1,col) so that later on normals work correctly
273
     // (Edge always needs to point out from land to water for that)
274
     
275
     int numEdges= mEdges.size();
276
     short initLand;
277
     int initCol, initRow;
278
     boolean kicked;
279
     Edge e;
280
     
281
     for(i=0; i<numEdges; i++) 
282
       {
283
       e = mEdges.get(i);
284
       initRow= e.row;
285
       initCol= e.col;
286
         
287
       //android.util.Log.e("CUBES", "checking edge "+debug(e));
288
             
289
       if( mCubes[initRow][initCol]%2==0 )
290
         {
291
         kicked = false; 
292
         initLand = mCubes[initRow-1][initCol];
293
         
294
         do
295
           {
296
           e = getNextEdge(e); 
297
           //android.util.Log.e("CUBES", " next edge "+debug(e));   
298
       
299
           switch(e.side)
300
             {
301
             case NORTH: if( initLand!=mCubes[e.row-1][e.col  ] ) kicked=true; break;
302
             case SOUTH: if( initLand!=mCubes[e.row+1][e.col  ] ) kicked=true; break;
303
             case WEST:  if( initLand!=mCubes[e.row  ][e.col-1] ) kicked=true; break;
304
             case EAST:  if( initLand!=mCubes[e.row  ][e.col+1] ) kicked=true; break;
305
             }
306
           
307
           if( kicked )
308
             {
309
             //android.util.Log.e("CUBES", "kicking out edge!");
310
             mEdges.remove(i);
311
             i--;
312
             numEdges--; 
313
             }
314
           }
315
         while( kicked==false && (e.col!=initCol || e.row!=initRow || e.side!=NORTH) );
316
         
317
         if( kicked==false )
318
           {
319
           mEdges.set(i, new Edge(SOUTH,e.row-1,e.col)); 
320
           }
321
         }
322
       }
323
     }
324
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326
// when calling, make sure that newVal != val
327
   
328
   private void markRegion(short newVal, int row, int col)
329
     {
330
     short val = mCubes[row][col];
331
     mCubes[row][col] = newVal;
332
     
333
     if( row>0       && mCubes[row-1][col  ]==val ) markRegion(newVal, row-1, col  );
334
     if( row<mRows-1 && mCubes[row+1][col  ]==val ) markRegion(newVal, row+1, col  );
335
     if( col>0       && mCubes[row  ][col-1]==val ) markRegion(newVal, row  , col-1);
336
     if( col<mCols-1 && mCubes[row  ][col+1]==val ) markRegion(newVal, row  , col+1);
337
     }
338
   
339
///////////////////////////////////////////////////////////////////////////////////////////////////
340
   
341 ce7f3833 Leszek Koltunski
   private void createNormals(boolean front, int row, int col)
342 6a06a912 Leszek Koltunski
     {
343
     int td,lr; 
344
      
345 2e96ee72 Leszek Koltunski
     int nw = (col>0       && row>0      ) ? (mCubes[row-1][col-1]%2) : 0;
346
     int w  = (col>0                     ) ? (mCubes[row  ][col-1]%2) : 0;
347
     int n  = (               row>0      ) ? (mCubes[row-1][col  ]%2) : 0;
348
     int c  =                                (mCubes[row  ][col  ]%2);
349
     int sw = (col>0       && row<mRows-1) ? (mCubes[row+1][col-1]%2) : 0;
350 6a06a912 Leszek Koltunski
     int s  = (               row<mRows-1) ? (mCubes[row+1][col  ]%2) : 0;
351
     int ne = (col<mCols-1 && row>0      ) ? (mCubes[row-1][col+1]%2) : 0;
352
     int e  = (col<mCols-1               ) ? (mCubes[row  ][col+1]%2) : 0;
353
     int se = (col<mCols-1 && row<mRows-1) ? (mCubes[row+1][col+1]%2) : 0;
354 ce7f3833 Leszek Koltunski
355
     if(front)
356
       {
357
       mNormalZ[0] = 1.0f;
358
       mNormalZ[1] = 1.0f;
359
       mNormalZ[2] = 1.0f;
360
       mNormalZ[3] = 1.0f;
361
       }
362
     else
363
       {
364
       mNormalZ[0] =-1.0f;
365
       mNormalZ[1] =-1.0f;
366
       mNormalZ[2] =-1.0f;
367
       mNormalZ[3] =-1.0f;
368
       }
369
370 6a06a912 Leszek Koltunski
     td = nw+n-w-c;
371
     lr = c+n-w-nw;
372
     if( td<0 ) td=-1;
373
     if( td>0 ) td= 1;
374
     if( lr<0 ) lr=-1;
375
     if( lr>0 ) lr= 1;
376
     mNormalX[0] = lr*R;
377
     mNormalY[0] = td*R;
378
     
379
     td = w+c-sw-s;
380
     lr = c+s-w-sw;
381
     if( td<0 ) td=-1;
382
     if( td>0 ) td= 1;
383
     if( lr<0 ) lr=-1;
384
     if( lr>0 ) lr= 1;
385
     mNormalX[1] = lr*R;
386
     mNormalY[1] = td*R;
387
     
388
     td = n+ne-c-e;
389
     lr = e+ne-c-n;
390
     if( td<0 ) td=-1;
391
     if( td>0 ) td= 1;
392
     if( lr<0 ) lr=-1;
393
     if( lr>0 ) lr= 1;
394
     mNormalX[2] = lr*R;
395
     mNormalY[2] = td*R;
396
     
397
     td = c+e-s-se;
398
     lr = e+se-c-s;
399
     if( td<0 ) td=-1;
400
     if( td>0 ) td= 1;
401
     if( lr<0 ) lr=-1;
402
     if( lr>0 ) lr= 1;
403
     mNormalX[3] = lr*R;
404
     mNormalY[3] = td*R;
405
     /*
406 2e96ee72 Leszek Koltunski
     android.util.Log.d("CUBES", "row="+row+" col="+col);
407
     android.util.Log.d("CUBES", mNormalX[0]+" "+mNormalY[0]);
408
     android.util.Log.d("CUBES", mNormalX[1]+" "+mNormalY[1]);
409
     android.util.Log.d("CUBES", mNormalX[2]+" "+mNormalY[2]);
410
     android.util.Log.d("CUBES", mNormalX[3]+" "+mNormalY[3]);
411 6a06a912 Leszek Koltunski
     */
412
     }
413
   
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415 ce7f3833 Leszek Koltunski
416
   private int addFrontVertex(int corner, int vertex, float centerX, float centerY, float vectZ, int col, int row, float[] position, float[] normal, float[] texture)
417
     {
418 84ee2a6a Leszek Koltunski
     remainingVert--;
419
     /*
420
     switch(corner)
421
       {
422
       case NW: android.util.Log.e("CUBES", "adding NW vertex!");
423
                break;
424
       case SW: android.util.Log.e("CUBES", "adding SW vertex!");
425
                break;
426
       case SE: android.util.Log.e("CUBES", "adding SE vertex!");
427
                break;
428
       case NE: android.util.Log.e("CUBES", "adding NE vertex!");
429
                break;
430
       }
431
     */
432 ce7f3833 Leszek Koltunski
     switch(corner)
433
       {
434
       case NW: position[3*vertex  ] = (centerX-0.5f)/mCols;
435
                position[3*vertex+1] = (centerY+0.5f)/mRows;
436
                position[3*vertex+2] = vectZ;
437
                normal[3*vertex  ]   = mNormalX[0];
438
                normal[3*vertex+1]   = mNormalY[0];
439
                normal[3*vertex+2]   = mNormalZ[0];
440
                texture[2*vertex  ]  = (float)col/mCols;
441
                texture[2*vertex+1]  = (float)row/mRows;
442
                return vertex+1;
443
       case SW: position[3*vertex  ] = (centerX-0.5f)/mCols;
444
                position[3*vertex+1] = (centerY-0.5f)/mRows;
445
                position[3*vertex+2] = vectZ;
446
                normal[3*vertex  ]   = mNormalX[1];
447
                normal[3*vertex+1]   = mNormalY[1];
448
                normal[3*vertex+2]   = mNormalZ[1];
449
                texture[2*vertex  ]  = (float)col/mCols;
450
                texture[2*vertex+1]  = (float)(row+1)/mRows;
451
                return vertex+1;
452
       case NE: position[3*vertex  ] = (centerX+0.5f)/mCols;
453
                position[3*vertex+1] = (centerY+0.5f)/mRows;
454
                position[3*vertex+2] = vectZ;
455
                normal[3*vertex  ]   = mNormalX[2];
456
                normal[3*vertex+1]   = mNormalY[2];
457
                normal[3*vertex+2]   = mNormalZ[2];
458
                texture[2*vertex  ]  = (float)(col+1)/mCols;
459
                texture[2*vertex+1]  = (float)row/mRows;
460
                return vertex+1;
461
       case SE: position[3*vertex  ] = (centerX+0.5f)/mCols;
462
                position[3*vertex+1] = (centerY-0.5f)/mRows;
463
                position[3*vertex+2] = vectZ;
464
                normal[3*vertex  ]   = mNormalX[3];
465
                normal[3*vertex+1]   = mNormalY[3];
466
                normal[3*vertex+2]   = mNormalZ[3];
467
                texture[2*vertex  ]  = (float)(col+1)/mCols;
468
                texture[2*vertex+1]  = (float)(row+1)/mRows;
469 84ee2a6a Leszek Koltunski
                return vertex+1;
470 ce7f3833 Leszek Koltunski
       }
471
472
     return vertex;
473
     }
474
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476
477 6a06a912 Leszek Koltunski
   private int buildFrontBackGrid(boolean front, int vertex, float[] position, float[] normal, float[] texture)
478
     {
479
     short last, current;
480 ce7f3833 Leszek Koltunski
     boolean seenLand=false;
481
     boolean lastBlockIsNE = false;
482
     boolean currentBlockIsNE;
483 6a06a912 Leszek Koltunski
     float centerX, centerY;
484 ce7f3833 Leszek Koltunski
     float vectZ = front?FRONTZ:BACKZ;
485
486 84ee2a6a Leszek Koltunski
     //android.util.Log.d("CUBES", "buildFrontBack");
487
488 6a06a912 Leszek Koltunski
     for(int i=0; i<mRows; i++)
489
       {
490
       last =0;
491
         
492
       for(int j=0; j<mCols; j++)
493
         {
494
         current = mCubes[i][j];
495 ce7f3833 Leszek Koltunski
496 6a06a912 Leszek Koltunski
         if( current%2 == 1 )
497
           {
498 ce7f3833 Leszek Koltunski
           currentBlockIsNE = isNE(i,j);
499 6a06a912 Leszek Koltunski
           centerX = j-(mCols-1.0f)/2.0f;
500
           centerY = (mRows-1.0f)/2.0f-i;
501 84ee2a6a Leszek Koltunski
502
           if( !seenLand && !front && ((vertex%2==1)^currentBlockIsNE) )
503
             {
504
             //android.util.Log.d("CUBES","repeating winding2 vertex");
505
506
             vertex = repeatLast(vertex,position,normal,texture);
507
             }
508
509 ce7f3833 Leszek Koltunski
           createNormals(front,i,j);
510
511
           if( (last!=current) || (lastBlockIsNE^currentBlockIsNE) )
512 6a06a912 Leszek Koltunski
             {
513 ce7f3833 Leszek Koltunski
             if( seenLand  && (last != current) ) vertex = repeatLast(vertex,position,normal,texture);
514
             vertex= addFrontVertex( currentBlockIsNE ? NW:SW, vertex, centerX, centerY, vectZ, j, i, position, normal, texture);
515
             if( seenLand  && (last != current) ) vertex = repeatLast(vertex,position,normal,texture);
516 84ee2a6a Leszek Koltunski
             if( (lastBlockIsNE^currentBlockIsNE)
517
                 || (!front && !seenLand)       ) vertex = repeatLast(vertex,position,normal,texture);
518 ce7f3833 Leszek Koltunski
             vertex= addFrontVertex( currentBlockIsNE ? SW:NW, vertex, centerX, centerY, vectZ, j, i, position, normal, texture);
519 6a06a912 Leszek Koltunski
             }
520 ce7f3833 Leszek Koltunski
           vertex= addFrontVertex( currentBlockIsNE ? NE:SE, vertex, centerX, centerY, vectZ, j, i, position, normal, texture);
521
           vertex= addFrontVertex( currentBlockIsNE ? SE:NE, vertex, centerX, centerY, vectZ, j, i, position, normal, texture);
522
523
           seenLand = true;
524
           lastBlockIsNE = currentBlockIsNE;
525 6a06a912 Leszek Koltunski
           }
526
            
527
         last = current;
528
         }
529
       }
530
     
531
     return vertex;
532
     }
533
534
///////////////////////////////////////////////////////////////////////////////////////////////////
535
536
   private int repeatLast(int vertex, float[] position, float[] normal, float[] texture)
537
     {
538 84ee2a6a Leszek Koltunski
     remainingVert--;
539
540
     //android.util.Log.e("CUBES", "repeating last vertex!");
541
542 6a06a912 Leszek Koltunski
     if( vertex>0 )
543
       {
544 39cbf9dc Leszek Koltunski
       position[3*vertex  ] = position[3*vertex-3];
545 6a06a912 Leszek Koltunski
       position[3*vertex+1] = position[3*vertex-2];
546
       position[3*vertex+2] = position[3*vertex-1];
547
548 39cbf9dc Leszek Koltunski
       normal[3*vertex  ]   = normal[3*vertex-3];
549 6a06a912 Leszek Koltunski
       normal[3*vertex+1]   = normal[3*vertex-2];
550
       normal[3*vertex+2]   = normal[3*vertex-1];
551
552 39cbf9dc Leszek Koltunski
       texture[2*vertex  ]  = texture[2*vertex-2];
553 6a06a912 Leszek Koltunski
       texture[2*vertex+1]  = texture[2*vertex-1];
554
         
555
       vertex++;     
556
       }
557
     
558
     return vertex;
559
     }
560
   
561
///////////////////////////////////////////////////////////////////////////////////////////////////
562
563
   private int buildSideGrid(int vertex, float[] position, float[] normal, float[] texture)
564
     {
565 84ee2a6a Leszek Koltunski
     //android.util.Log.d("CUBES", "buildSide");
566 ce7f3833 Leszek Koltunski
567 84ee2a6a Leszek Koltunski
     int edges= mEdges.size();
568 ce7f3833 Leszek Koltunski
569 6a06a912 Leszek Koltunski
     for(int i=0; i<edges; i++) 
570
       {
571
       vertex = buildIthSide(mEdges.get(i), vertex, position, normal, texture);  
572
       } 
573
      
574
     return vertex;
575
     }
576
577
///////////////////////////////////////////////////////////////////////////////////////////////////
578
579
   private int buildIthSide(Edge curr, int vertex, float[] position, float[] normal, float[] texture)
580
     {
581
     Edge prev; 
582
     
583
     if( curr.side==NORTH ) // water outside
584
       {
585
       prev = new Edge(WEST,curr.row,curr.col);
586
       }
587
     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.
588
       {
589
       prev = curr;
590
       curr = new Edge(EAST,curr.row+1,curr.col-1);
591
       }
592
     
593
     int col = curr.col;
594
     int row = curr.row;
595
     int side= curr.side;  
596
     Edge next = getNextEdge(curr);
597
     
598 84ee2a6a Leszek Koltunski
     addSideVertex(curr,BACK,LOWER,prev.side,vertex,position,normal,texture);
599 6a06a912 Leszek Koltunski
     vertex++;
600
     
601
     do
602
       {
603
       if( prev.side!=curr.side )
604
         {
605 84ee2a6a Leszek Koltunski
         addSideVertex(curr,BACK,LOWER,prev.side,vertex,position,normal,texture);
606 6a06a912 Leszek Koltunski
         vertex++;
607 84ee2a6a Leszek Koltunski
         addSideVertex(curr,BACK,UPPER,prev.side,vertex,position,normal,texture);
608 6a06a912 Leszek Koltunski
         vertex++;
609
         }
610
       
611 84ee2a6a Leszek Koltunski
       addSideVertex(curr,FRONT,LOWER,next.side,vertex,position,normal,texture);
612 6a06a912 Leszek Koltunski
       vertex++;
613 84ee2a6a Leszek Koltunski
       addSideVertex(curr,FRONT,UPPER,next.side,vertex,position,normal,texture);
614 6a06a912 Leszek Koltunski
       vertex++;
615
       
616
       prev = curr;
617
       curr = next; 
618
       next = getNextEdge(curr);
619
       }
620
     while( curr.col!=col || curr.row!=row || curr.side!=side );
621
     
622
     vertex = repeatLast(vertex,position,normal,texture);
623
     
624
     return vertex;
625
     }
626
627
///////////////////////////////////////////////////////////////////////////////////////////////////
628
629
   private Edge getNextEdge(Edge curr)
630
     {
631
     int col = curr.col;
632
     int row = curr.row;
633
      
634
     //android.util.Log.e("CUBES", "row="+row+" col="+col+" mRows="+mRows+" mCols="+mCols);
635
                       
636
     switch(curr.side) 
637
       {
638
       case NORTH: if( col==mCols-1 ) 
639
                     return new Edge(EAST,row,col);
640
                   if( row>0 && mCubes[row-1][col+1]==mCubes[row][col] )
641
                     return new Edge(WEST,row-1,col+1);
642
                   if( mCubes[row][col+1]==mCubes[row][col] )
643
                     return new Edge(NORTH,row,col+1);
644
                   else  
645
                     return new Edge(EAST,row,col);
646
                   
647
       case SOUTH: if( col==0 ) 
648
                     return new Edge(WEST,row,col);
649
                   if( (row<mRows-1) && mCubes[row+1][col-1]==mCubes[row][col] )
650
                     return new Edge(EAST,row+1,col-1); 
651
                   if( mCubes[row][col-1]==mCubes[row][col] )
652
                     return new Edge(SOUTH,row,col-1);
653
                   else
654
                     return new Edge(WEST,row,col); 
655
                     
656
       case EAST : if( row==mRows-1 ) 
657
                     return new Edge(SOUTH,row,col);
658
                   if( (col<mCols-1) && mCubes[row+1][col+1]==mCubes[row][col] )
659
                     return new Edge(NORTH,row+1,col+1);
660
                   if( mCubes[row+1][col]==mCubes[row][col] )
661
                     return new Edge(EAST,row+1,col);
662
                   else 
663
                     return new Edge(SOUTH,row,col);
664
                   
665
       case WEST : if( row==0 )
666
                     return new Edge(NORTH,row,col);
667
                   if( col>0 && mCubes[row-1][col-1]==mCubes[row][col] )
668
                     return new Edge(SOUTH,row-1,col-1);
669
                   if( mCubes[row-1][col]==mCubes[row][col] )
670
                     return new Edge(WEST,row-1,col);
671
                   else
672
                     return new Edge(NORTH,row,col);     
673
       }
674
     
675
     return null;
676
     }
677
678
///////////////////////////////////////////////////////////////////////////////////////////////////
679
   
680 84ee2a6a Leszek Koltunski
   private void addSideVertex(Edge curr, boolean back, boolean lower,int side, int vertex, float[] position, float[] normal, float[] texture)
681 6a06a912 Leszek Koltunski
     {
682 84ee2a6a Leszek Koltunski
     //android.util.Log.e("CUBES", "adding Side vertex!");
683
684
     remainingVert--;
685
686 6a06a912 Leszek Koltunski
     float centerX = curr.col-(mCols-1.0f)/2.0f;
687
     float centerY = (mRows-1.0f)/2.0f-curr.row;
688
  
689
     switch(curr.side)
690
       {
691 39cbf9dc Leszek Koltunski
       case NORTH: position[3*vertex  ] = (back ? (centerX-0.5f) : (centerX+0.5f))/mCols;
692 6a06a912 Leszek Koltunski
                   position[3*vertex+1] = (centerY+0.5f)/mRows;
693
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
694
695 39cbf9dc Leszek Koltunski
                   normal[3*vertex  ]   = side==NORTH ? 0.0f : (side==WEST?-R:R);
696 6a06a912 Leszek Koltunski
                   normal[3*vertex+1]   = 1.0f;
697
                   normal[3*vertex+2]   = lower ? -R:R;
698
699 39cbf9dc Leszek Koltunski
                   texture[2*vertex  ]  = (float)(back ? (curr.col  ):(curr.col+1))/mCols;
700 6a06a912 Leszek Koltunski
                   texture[2*vertex+1]  = (float)(lower? (curr.row-1):(curr.row  ))/mRows;  
701
                   break;
702 39cbf9dc Leszek Koltunski
       case SOUTH: position[3*vertex  ] = (back ? (centerX+0.5f) : (centerX-0.5f))/mCols;
703 6a06a912 Leszek Koltunski
                   position[3*vertex+1] = (centerY-0.5f)/mRows;
704
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;  
705
            
706 39cbf9dc Leszek Koltunski
                   normal[3*vertex  ]   = side==SOUTH ? 0.0f: (side==EAST?-R:R);
707 6a06a912 Leszek Koltunski
                   normal[3*vertex+1]   =-1.0f;
708
                   normal[3*vertex+2]   = lower ? -R:R;
709
710 39cbf9dc Leszek Koltunski
                   texture[2*vertex  ]  = (float)(back ? (curr.col+1):(curr.col  ))/mCols;
711 6a06a912 Leszek Koltunski
                   texture[2*vertex+1]  = (float)(lower? (curr.row+2):(curr.row+1))/mRows;
712
                   break;
713 39cbf9dc Leszek Koltunski
       case WEST : position[3*vertex  ] = (centerX-0.5f)/mCols;
714 6a06a912 Leszek Koltunski
                   position[3*vertex+1] = (back ? (centerY-0.5f):(centerY+0.5f))/mRows;
715
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
716
717 39cbf9dc Leszek Koltunski
                   normal[3*vertex  ]   =-1.0f;
718 6a06a912 Leszek Koltunski
                   normal[3*vertex+1]   = side==WEST ? 0.0f : (side==NORTH?-R:R);
719
                   normal[3*vertex+2]   = lower ? -R:R;
720
 
721 39cbf9dc Leszek Koltunski
                   texture[2*vertex  ]  = (float)(lower ? (curr.col-1):(curr.col  ))/mCols;
722 6a06a912 Leszek Koltunski
                   texture[2*vertex+1]  = (float)(back  ? (curr.row+1):(curr.row  ))/mRows;
723
                   break;
724 39cbf9dc Leszek Koltunski
       case EAST : position[3*vertex  ] = (centerX+0.5f)/mCols;
725 6a06a912 Leszek Koltunski
                   position[3*vertex+1] = (back ? (centerY+0.5f):(centerY-0.5f))/mRows;
726
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
727
728 39cbf9dc Leszek Koltunski
                   normal[3*vertex  ]   = 1.0f;
729 6a06a912 Leszek Koltunski
                   normal[3*vertex+1]   = side==EAST ? 0.0f : (side==SOUTH?-R:R);
730
                   normal[3*vertex+2]   = lower ? -R:R; 
731
732 39cbf9dc Leszek Koltunski
                   texture[2*vertex  ]  = (float)(lower ? (curr.col+2):(curr.col+1))/mCols;
733 6a06a912 Leszek Koltunski
                   texture[2*vertex+1]  = (float)(back  ? (curr.row  ):(curr.row+1))/mRows;
734
                   break;
735
       }
736
     
737 39cbf9dc Leszek Koltunski
     if(texture[2*vertex  ]>1.0f) texture[2*vertex  ] =2.0f-texture[2*vertex  ];
738
     if(texture[2*vertex  ]<0.0f) texture[2*vertex  ] =    -texture[2*vertex  ];
739 6a06a912 Leszek Koltunski
     if(texture[2*vertex+1]>1.0f) texture[2*vertex+1] =2.0f-texture[2*vertex+1];
740
     if(texture[2*vertex+1]<0.0f) texture[2*vertex+1] =    -texture[2*vertex+1];
741
     }
742
743
///////////////////////////////////////////////////////////////////////////////////////////////////
744
// PUBLIC API
745
///////////////////////////////////////////////////////////////////////////////////////////////////
746
   
747
/**
748
 * Creates the underlying grid of vertices, normals, texture coords and colors.
749
 *    
750 39cbf9dc Leszek Koltunski
 * @param cols      See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
751
 * @param desc      See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
752
 * @param frontOnly See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
753 6a06a912 Leszek Koltunski
 */
754 e458a4ba Leszek Koltunski
   public DistortedCubesGrid(int cols, String desc, boolean frontOnly)
755 6a06a912 Leszek Koltunski
      {
756 2e96ee72 Leszek Koltunski
      prepareDataStructures(cols,desc,frontOnly);
757 6a06a912 Leszek Koltunski
       
758
      int numVertices=0;
759
      float[] positionData= new float[POSITION_DATA_SIZE*dataLength];
760
      float[] normalData  = new float[NORMAL_DATA_SIZE  *dataLength];
761
      float[] textureData = new float[TEX_DATA_SIZE     *dataLength];
762
763
      numVertices = buildFrontBackGrid(true, numVertices,positionData,normalData,textureData);
764
      
765
      if( !frontOnly )
766
        {
767
        numVertices = repeatLast(numVertices,positionData,normalData,textureData);
768 84ee2a6a Leszek Koltunski
        if( numVertices%2==1 )
769
          {
770
          //android.util.Log.d("CUBES","repeating winding1 vertex");
771
772
          numVertices = repeatLast(numVertices,positionData,normalData,textureData);
773
          }
774 6a06a912 Leszek Koltunski
        numVertices = buildSideGrid (numVertices,positionData,normalData,textureData);
775
        numVertices = buildFrontBackGrid (false,numVertices,positionData,normalData,textureData);
776
        }
777
      
778
      /*
779
      android.util.Log.e("CUBES","dataLen="+dataLength+" vertex="+numVertices);
780
      android.util.Log.d("CUBES", "position: "+debug(positionData,3) );
781
      android.util.Log.d("CUBES", "normal: "  +debug(  normalData,3) );
782
      android.util.Log.d("CUBES", "texture: " +debug( textureData,2) );
783
      */
784 84ee2a6a Leszek Koltunski
      android.util.Log.d("CUBES", "remainingVert " +remainingVert );
785 6a06a912 Leszek Koltunski
786
      mGridPositions = ByteBuffer.allocateDirect(POSITION_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();                                                        
787
      mGridPositions.put(positionData).position(0); 
788
      
789
      mGridNormals = ByteBuffer.allocateDirect(NORMAL_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();                                                        
790
      mGridNormals.put(normalData).position(0); 
791
792
      mGridTexture = ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();                                                        
793
      mGridTexture.put(textureData).position(0); 
794
      }
795
   }
796
///////////////////////////////////////////////////////////////////////////////////////////////////