Project

General

Profile

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

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

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 06d71892 Leszek Koltunski
   private static final float R = 0.0f;//0.2f;
31 6a06a912 Leszek Koltunski
   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 6a06a912 Leszek Koltunski
   private static final boolean BACK  = true;
40
   private static final boolean FRONT = false;
41
   private static final boolean UPPER = false;
42
   private static final boolean LOWER = true;
43
   
44
   private static final float[] mNormalX = new float[4];
45
   private static final float[] mNormalY = new float[4];
46 ce7f3833 Leszek Koltunski
   private static final float[] mNormalZ = new float[4];
47
48 6a06a912 Leszek Koltunski
   private class Edge
49
     {
50
     final int side; 
51
     final int row;
52
     final int col;
53
     
54 06d71892 Leszek Koltunski
     Edge(int s, int r, int c)
55 6a06a912 Leszek Koltunski
       {
56
       side= s; 
57
       row = r;
58
       col = c;
59
       }
60 39cbf9dc Leszek Koltunski
     }
61 6a06a912 Leszek Koltunski
   
62
   private int mCols, mRows;
63
   private short[][] mCubes;
64 39cbf9dc Leszek Koltunski
   private ArrayList<Edge> mEdges = new ArrayList<>();
65 ce7f3833 Leszek Koltunski
66 84ee2a6a Leszek Koltunski
   private int remainingVert;
67 ce7f3833 Leszek Koltunski
68
///////////////////////////////////////////////////////////////////////////////////////////////////
69
// a Block is split into two triangles along the NE-SW line iff it is in the top-right
70
// or bottom-left quadrant of the grid.
71
72
   private boolean isNE(int row,int col)
73
     {
74 29dd01c6 Leszek Koltunski
     return ( (2*row<mRows)^(2*col<mCols) );
75 ce7f3833 Leszek Koltunski
     }
76
77 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
78 84ee2a6a Leszek Koltunski
// return the number of vertices our grid will contain
79 6a06a912 Leszek Koltunski
80
   private int computeDataLength(boolean frontOnly)
81
      {
82 84ee2a6a Leszek Koltunski
      int frontWalls=0, frontSegments=0, sideWalls=0, sideBends=0, triangleShifts=0, windingShifts=0;
83 ce7f3833 Leszek Koltunski
      int shiftCol = (mCols-1)/2;
84
85
      boolean lastBlockIsNE=false;
86
      boolean thisBlockIsNE;        // the block we are currently looking at is split into
87
                                    // two triangles along the NE-SW line (rather than NW-SE)
88 29dd01c6 Leszek Koltunski
      for(int row=0; row<mRows; row++)
89 ce7f3833 Leszek Koltunski
         {
90 29dd01c6 Leszek Koltunski
         if( mCols>=2 && (mCubes[row][shiftCol]%2 == 1) && (mCubes[row][shiftCol+1]%2 == 1) ) triangleShifts++;
91 ce7f3833 Leszek Koltunski
92 29dd01c6 Leszek Koltunski
         for(int col=0; col<mCols; col++)
93 6a06a912 Leszek Koltunski
            {
94 29dd01c6 Leszek Koltunski
            if( mCubes[row][col]%2 == 1 )  // land
95 6a06a912 Leszek Koltunski
              {
96 29dd01c6 Leszek Koltunski
              thisBlockIsNE = isNE(row,col);
97 84ee2a6a Leszek Koltunski
              if( thisBlockIsNE^lastBlockIsNE ) windingShifts++;
98 ce7f3833 Leszek Koltunski
              lastBlockIsNE = thisBlockIsNE;
99 6a06a912 Leszek Koltunski
              frontWalls++;
100 29dd01c6 Leszek Koltunski
              if( col==mCols-1 || mCubes[row][col+1]%2 == 0 ) frontSegments++;
101 6a06a912 Leszek Koltunski
              }
102
              
103 29dd01c6 Leszek Koltunski
            if( (row==0 && mCubes[row][col]!=2) || (row!=0 && mCubes[row][col] != mCubes[row-1][col  ]) ) sideWalls++; // up
104
            if( (col==0 && mCubes[row][col]!=2) || (col!=0 && mCubes[row][col] != mCubes[row  ][col-1]) ) sideWalls++; // left
105
            if( row==mRows-1 && mCubes[row][col]!=2                                                     ) sideWalls++; // bottom
106
            if( col==mCols-1 && mCubes[row][col]!=2                                                     ) sideWalls++; // right
107 6a06a912 Leszek Koltunski
            }
108 ce7f3833 Leszek Koltunski
         }
109
110 6a06a912 Leszek Koltunski
      int edges= mEdges.size();
111
      
112
      for(int i=0; i<edges; i++) 
113
        {
114
        Edge curr = mEdges.get(i);
115
        Edge next = getNextEdge(curr);
116
        int startX = curr.col;
117
        int startY = curr.row;
118
        int startS = curr.side;
119
        
120
        do
121
          {
122
          if( next.side != curr.side ) sideBends++; 
123
          curr  = next; 
124
          next = getNextEdge(curr);
125
          }
126
        while( curr.col!=startX || curr.row!=startY || curr.side!=startS );
127
        }
128 ce7f3833 Leszek Koltunski
129 84ee2a6a Leszek Koltunski
      int frontVert = 2*( frontWalls + 2*frontSegments - 1) +2*triangleShifts + windingShifts;
130 39cbf9dc Leszek Koltunski
      int sideVert  = 2*( sideWalls + sideBends + edges -1);
131 e99dd9d6 Leszek Koltunski
      int firstWinding=( !frontOnly && (frontVert+1)%2==1 ) ? 1:0;
132 84ee2a6a Leszek Koltunski
      int dataL = frontOnly ? frontVert : (frontVert+1) +firstWinding+ (1+sideVert+1) + (1+frontVert);
133
134 e99dd9d6 Leszek Koltunski
      android.util.Log.e("CUBES","triangleShifts="+triangleShifts+" windingShifts="+windingShifts);
135
      android.util.Log.e("CUBES","Winding1="+firstWinding+" frontVert="+frontVert+" sideVert="+sideVert);
136
      android.util.Log.e("CUBES", "frontW="+frontWalls+" fSegments="+frontSegments+" sWalls="+sideWalls+" sSegments="+edges+" sideBends="+sideBends+" dataLen="+dataL );
137 6a06a912 Leszek Koltunski
      
138
      return dataL<0 ? 0:dataL;
139
      }
140
141
///////////////////////////////////////////////////////////////////////////////////////////////////
142
/*
143
   private static String debug(short[] val)
144
     {
145 ce7f3833 Leszek Koltunski
     String ret="";j
146 6a06a912 Leszek Koltunski
     
147
     for(int i=0; i<val.length; i++) ret+=(" "+val[i]); 
148
     
149
     return ret;
150
     }
151
*/
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153
/*
154
   private static String debug(float[] val, int stop)
155
     {
156
     String ret="";
157
158
     for(int i=0; i<val.length; i++) 
159
        {
160
        if( i%stop==0 ) ret+="\n";
161
        ret+=(" "+val[i]);
162
        }
163
164
     return ret;
165
     }
166
*/  
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168 e99dd9d6 Leszek Koltunski
169 6a06a912 Leszek Koltunski
   private static String debug(Edge e)
170
     {
171
     String d = "";
172
     
173
     switch(e.side)
174
       {
175
       case NORTH: d+="NORTH "; break;
176
       case SOUTH: d+="SOUTH "; break;
177
       case WEST : d+="WEST  "; break;
178
       case EAST : d+="EAST  "; break;
179
       }
180
     
181
     d+=("("+e.row+","+e.col+")");
182
     
183
     return d;
184
     }   
185 e99dd9d6 Leszek Koltunski
186 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
187 0729bc41 Leszek Koltunski
// desc is guaranteed to be padded with 0s in the end (DistortedCubes constructor does it)
188 6a06a912 Leszek Koltunski
189 2e96ee72 Leszek Koltunski
   private void prepareDataStructures(int cols, String desc, boolean frontOnly)
190 6a06a912 Leszek Koltunski
     {
191
     mRows     =0;
192
     mCols     =0;
193
     dataLength=0;
194
     
195 0729bc41 Leszek Koltunski
     if( cols>0 && desc.contains("1") )
196 6a06a912 Leszek Koltunski
       {
197 0729bc41 Leszek Koltunski
       mCols = cols;
198
       mRows = desc.length()/cols;
199 6a06a912 Leszek Koltunski
200 0729bc41 Leszek Koltunski
       mCubes = new short[mRows][mCols];
201 6a06a912 Leszek Koltunski
       
202 0729bc41 Leszek Koltunski
       for(int j=0; j<mCols; j++)
203
         for(int i=0; i<mRows; i++)
204
           mCubes[i][j] = (short)(desc.charAt(i*mCols+j) == '1' ? 1:0);
205 6a06a912 Leszek Koltunski
       
206 0729bc41 Leszek Koltunski
       markRegions();
207
       dataLength = computeDataLength(frontOnly);
208 84ee2a6a Leszek Koltunski
209
       remainingVert = dataLength;
210 6a06a912 Leszek Koltunski
       }
211
     }
212 665e2c45 Leszek Koltunski
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214
// full grid
215
216
   private void prepareDataStructures(int cols, int rows, boolean frontOnly)
217
     {
218
     mRows     =rows;
219
     mCols     =cols;
220
     dataLength=   0;
221
222
     if( cols>0 && rows>0 )
223
       {
224
       mCubes = new short[mRows][mCols];
225
226
       for(int j=0; j<mCols; j++)
227
         for(int i=0; i<mRows; i++)
228
           mCubes[i][j] = (short)1;
229
230
       markRegions();
231
       dataLength = computeDataLength(frontOnly);
232
233
       remainingVert = dataLength;
234
       }
235
     }
236
237 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 e99dd9d6 Leszek Koltunski
281 6a06a912 Leszek Koltunski
     for(i=0; i<numEdges; i++) 
282
       {
283
       e = mEdges.get(i);
284
       initRow= e.row;
285
       initCol= e.col;
286
         
287 e99dd9d6 Leszek Koltunski
       android.util.Log.e("CUBES", "checking edge "+debug(e));
288 6a06a912 Leszek Koltunski
             
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 e99dd9d6 Leszek Koltunski
           android.util.Log.e("CUBES", " next edge "+debug(e));
298 6a06a912 Leszek Koltunski
       
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 e99dd9d6 Leszek Koltunski
             android.util.Log.e("CUBES", "kicking out edge!");
310 6a06a912 Leszek Koltunski
             mEdges.remove(i);
311
             i--;
312
             numEdges--; 
313
             }
314
           }
315 e99dd9d6 Leszek Koltunski
         while( !kicked && (e.col!=initCol || e.row!=initRow || e.side!=NORTH) );
316 6a06a912 Leszek Koltunski
         
317 e99dd9d6 Leszek Koltunski
         if( !kicked )
318 6a06a912 Leszek Koltunski
           {
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 e5d9b235 Leszek Koltunski
   private int addFrontVertex(int vertex, int index, float vectZ, int col, int row, float[] position, float[] normal, float[] texture)
417 ce7f3833 Leszek Koltunski
     {
418 84ee2a6a Leszek Koltunski
     remainingVert--;
419 15873844 Leszek Koltunski
420 e5d9b235 Leszek Koltunski
     float x = (float)col/mCols;
421
     float y = (float)row/mRows;
422 ce7f3833 Leszek Koltunski
423 15873844 Leszek Koltunski
     position[3*vertex  ] = x-0.5f;
424
     position[3*vertex+1] = 0.5f-y;
425
     position[3*vertex+2] = vectZ;
426
     normal[3*vertex  ]   = mNormalX[index];
427
     normal[3*vertex+1]   = mNormalY[index];
428
     normal[3*vertex+2]   = mNormalZ[index];
429
     texture[2*vertex  ]  = x;
430 985ea9c5 Leszek Koltunski
     texture[2*vertex+1]  = 1.0f-y;
431 15873844 Leszek Koltunski
432
     return vertex+1;
433 ce7f3833 Leszek Koltunski
     }
434
435
///////////////////////////////////////////////////////////////////////////////////////////////////
436
437 6a06a912 Leszek Koltunski
   private int buildFrontBackGrid(boolean front, int vertex, float[] position, float[] normal, float[] texture)
438
     {
439
     short last, current;
440 ce7f3833 Leszek Koltunski
     boolean seenLand=false;
441
     boolean lastBlockIsNE = false;
442
     boolean currentBlockIsNE;
443
     float vectZ = front?FRONTZ:BACKZ;
444
445 84ee2a6a Leszek Koltunski
     //android.util.Log.d("CUBES", "buildFrontBack");
446
447 e5d9b235 Leszek Koltunski
     for(int row=0; row<mRows; row++)
448 6a06a912 Leszek Koltunski
       {
449
       last =0;
450
         
451 e5d9b235 Leszek Koltunski
       for(int col=0; col<mCols; col++)
452 6a06a912 Leszek Koltunski
         {
453 e5d9b235 Leszek Koltunski
         current = mCubes[row][col];
454 ce7f3833 Leszek Koltunski
455 6a06a912 Leszek Koltunski
         if( current%2 == 1 )
456
           {
457 e5d9b235 Leszek Koltunski
           currentBlockIsNE = isNE(row,col);
458 84ee2a6a Leszek Koltunski
459
           if( !seenLand && !front && ((vertex%2==1)^currentBlockIsNE) )
460
             {
461
             //android.util.Log.d("CUBES","repeating winding2 vertex");
462
463
             vertex = repeatLast(vertex,position,normal,texture);
464
             }
465
466 e5d9b235 Leszek Koltunski
           createNormals(front,row,col);
467 ce7f3833 Leszek Koltunski
468 e5d9b235 Leszek Koltunski
           if( currentBlockIsNE )
469 6a06a912 Leszek Koltunski
             {
470 e5d9b235 Leszek Koltunski
             if( (last!=current) || !lastBlockIsNE )
471
               {
472
               if( seenLand  && (last != current) ) vertex = repeatLast(vertex,position,normal,texture);
473
               vertex= addFrontVertex( vertex, 0, vectZ, col, row, position, normal, texture);
474
               if( seenLand  && (last != current) ) vertex = repeatLast(vertex,position,normal,texture);
475
               if( !lastBlockIsNE || (!front && !seenLand) ) vertex = repeatLast(vertex,position,normal,texture);
476
               vertex= addFrontVertex( vertex, 1, vectZ, col, row+1, position, normal, texture);
477
               }
478
             vertex= addFrontVertex( vertex, 2, vectZ, col+1, row, position, normal, texture);
479
             vertex= addFrontVertex( vertex, 3, vectZ, col+1, row+1, position, normal, texture);
480
             }
481
           else
482
             {
483
             if( (last!=current) || lastBlockIsNE )
484
               {
485
               if( seenLand  && (last != current) ) vertex = repeatLast(vertex,position,normal,texture);
486
               vertex= addFrontVertex( vertex, 1, vectZ, col, row+1, position, normal, texture);
487
               if( seenLand  && (last != current) ) vertex = repeatLast(vertex,position,normal,texture);
488
               if( lastBlockIsNE || (!front && !seenLand) ) vertex = repeatLast(vertex,position,normal,texture);
489
               vertex= addFrontVertex( vertex, 0, vectZ, col, row, position, normal, texture);
490
               }
491
             vertex= addFrontVertex( vertex, 3, vectZ, col+1, row+1, position, normal, texture);
492
             vertex= addFrontVertex( vertex, 2, vectZ, col+1, row  , position, normal, texture);
493 6a06a912 Leszek Koltunski
             }
494 ce7f3833 Leszek Koltunski
495
           seenLand = true;
496
           lastBlockIsNE = currentBlockIsNE;
497 6a06a912 Leszek Koltunski
           }
498
            
499
         last = current;
500
         }
501
       }
502
     
503
     return vertex;
504
     }
505
506
///////////////////////////////////////////////////////////////////////////////////////////////////
507
508
   private int repeatLast(int vertex, float[] position, float[] normal, float[] texture)
509
     {
510 84ee2a6a Leszek Koltunski
     //android.util.Log.e("CUBES", "repeating last vertex!");
511
512 6a06a912 Leszek Koltunski
     if( vertex>0 )
513
       {
514 e5d9b235 Leszek Koltunski
       remainingVert--;
515
516 39cbf9dc Leszek Koltunski
       position[3*vertex  ] = position[3*vertex-3];
517 6a06a912 Leszek Koltunski
       position[3*vertex+1] = position[3*vertex-2];
518
       position[3*vertex+2] = position[3*vertex-1];
519
520 39cbf9dc Leszek Koltunski
       normal[3*vertex  ]   = normal[3*vertex-3];
521 6a06a912 Leszek Koltunski
       normal[3*vertex+1]   = normal[3*vertex-2];
522
       normal[3*vertex+2]   = normal[3*vertex-1];
523
524 39cbf9dc Leszek Koltunski
       texture[2*vertex  ]  = texture[2*vertex-2];
525 6a06a912 Leszek Koltunski
       texture[2*vertex+1]  = texture[2*vertex-1];
526
         
527
       vertex++;     
528
       }
529
     
530
     return vertex;
531
     }
532
   
533
///////////////////////////////////////////////////////////////////////////////////////////////////
534
535
   private int buildSideGrid(int vertex, float[] position, float[] normal, float[] texture)
536
     {
537 84ee2a6a Leszek Koltunski
     //android.util.Log.d("CUBES", "buildSide");
538 ce7f3833 Leszek Koltunski
539 84ee2a6a Leszek Koltunski
     int edges= mEdges.size();
540 ce7f3833 Leszek Koltunski
541 6a06a912 Leszek Koltunski
     for(int i=0; i<edges; i++) 
542
       {
543
       vertex = buildIthSide(mEdges.get(i), vertex, position, normal, texture);  
544
       } 
545
      
546
     return vertex;
547
     }
548
549
///////////////////////////////////////////////////////////////////////////////////////////////////
550
551
   private int buildIthSide(Edge curr, int vertex, float[] position, float[] normal, float[] texture)
552
     {
553
     Edge prev; 
554
     
555
     if( curr.side==NORTH ) // water outside
556
       {
557
       prev = new Edge(WEST,curr.row,curr.col);
558
       }
559
     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.
560
       {
561
       prev = curr;
562
       curr = new Edge(EAST,curr.row+1,curr.col-1);
563
       }
564
     
565
     int col = curr.col;
566
     int row = curr.row;
567
     int side= curr.side;  
568
     Edge next = getNextEdge(curr);
569
     
570 84ee2a6a Leszek Koltunski
     addSideVertex(curr,BACK,LOWER,prev.side,vertex,position,normal,texture);
571 6a06a912 Leszek Koltunski
     vertex++;
572
     
573
     do
574
       {
575
       if( prev.side!=curr.side )
576
         {
577 84ee2a6a Leszek Koltunski
         addSideVertex(curr,BACK,LOWER,prev.side,vertex,position,normal,texture);
578 6a06a912 Leszek Koltunski
         vertex++;
579 84ee2a6a Leszek Koltunski
         addSideVertex(curr,BACK,UPPER,prev.side,vertex,position,normal,texture);
580 6a06a912 Leszek Koltunski
         vertex++;
581
         }
582
       
583 84ee2a6a Leszek Koltunski
       addSideVertex(curr,FRONT,LOWER,next.side,vertex,position,normal,texture);
584 6a06a912 Leszek Koltunski
       vertex++;
585 84ee2a6a Leszek Koltunski
       addSideVertex(curr,FRONT,UPPER,next.side,vertex,position,normal,texture);
586 6a06a912 Leszek Koltunski
       vertex++;
587
       
588
       prev = curr;
589
       curr = next; 
590
       next = getNextEdge(curr);
591
       }
592
     while( curr.col!=col || curr.row!=row || curr.side!=side );
593
     
594
     vertex = repeatLast(vertex,position,normal,texture);
595
     
596
     return vertex;
597
     }
598
599
///////////////////////////////////////////////////////////////////////////////////////////////////
600
601
   private Edge getNextEdge(Edge curr)
602
     {
603
     int col = curr.col;
604
     int row = curr.row;
605
      
606
     //android.util.Log.e("CUBES", "row="+row+" col="+col+" mRows="+mRows+" mCols="+mCols);
607
                       
608
     switch(curr.side) 
609
       {
610
       case NORTH: if( col==mCols-1 ) 
611
                     return new Edge(EAST,row,col);
612
                   if( row>0 && mCubes[row-1][col+1]==mCubes[row][col] )
613
                     return new Edge(WEST,row-1,col+1);
614
                   if( mCubes[row][col+1]==mCubes[row][col] )
615
                     return new Edge(NORTH,row,col+1);
616
                   else  
617
                     return new Edge(EAST,row,col);
618
                   
619
       case SOUTH: if( col==0 ) 
620
                     return new Edge(WEST,row,col);
621
                   if( (row<mRows-1) && mCubes[row+1][col-1]==mCubes[row][col] )
622
                     return new Edge(EAST,row+1,col-1); 
623
                   if( mCubes[row][col-1]==mCubes[row][col] )
624
                     return new Edge(SOUTH,row,col-1);
625
                   else
626
                     return new Edge(WEST,row,col); 
627
                     
628
       case EAST : if( row==mRows-1 ) 
629
                     return new Edge(SOUTH,row,col);
630
                   if( (col<mCols-1) && mCubes[row+1][col+1]==mCubes[row][col] )
631
                     return new Edge(NORTH,row+1,col+1);
632
                   if( mCubes[row+1][col]==mCubes[row][col] )
633
                     return new Edge(EAST,row+1,col);
634
                   else 
635
                     return new Edge(SOUTH,row,col);
636
                   
637
       case WEST : if( row==0 )
638
                     return new Edge(NORTH,row,col);
639
                   if( col>0 && mCubes[row-1][col-1]==mCubes[row][col] )
640
                     return new Edge(SOUTH,row-1,col-1);
641
                   if( mCubes[row-1][col]==mCubes[row][col] )
642
                     return new Edge(WEST,row-1,col);
643
                   else
644
                     return new Edge(NORTH,row,col);     
645
       }
646
     
647
     return null;
648
     }
649
650
///////////////////////////////////////////////////////////////////////////////////////////////////
651
   
652 84ee2a6a Leszek Koltunski
   private void addSideVertex(Edge curr, boolean back, boolean lower,int side, int vertex, float[] position, float[] normal, float[] texture)
653 6a06a912 Leszek Koltunski
     {
654 84ee2a6a Leszek Koltunski
     //android.util.Log.e("CUBES", "adding Side vertex!");
655
656
     remainingVert--;
657
658 985ea9c5 Leszek Koltunski
     float x, y;
659
660 6a06a912 Leszek Koltunski
     switch(curr.side)
661
       {
662 985ea9c5 Leszek Koltunski
       case NORTH: x = (float)(back ? (curr.col  ):(curr.col+1))/mCols;
663
664
                   position[3*vertex  ] = x - 0.5f;
665
                   position[3*vertex+1] = 0.5f - (float)curr.row/mRows;
666 6a06a912 Leszek Koltunski
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
667
668 39cbf9dc Leszek Koltunski
                   normal[3*vertex  ]   = side==NORTH ? 0.0f : (side==WEST?-R:R);
669 6a06a912 Leszek Koltunski
                   normal[3*vertex+1]   = 1.0f;
670
                   normal[3*vertex+2]   = lower ? -R:R;
671
672 985ea9c5 Leszek Koltunski
                   texture[2*vertex  ]  = x;
673
                   texture[2*vertex+1]  = 1.0f-(float)(lower? (curr.row-1):(curr.row  ))/mRows;
674 6a06a912 Leszek Koltunski
                   break;
675 985ea9c5 Leszek Koltunski
       case SOUTH: x = (float)(back ? (curr.col+1):(curr.col  ))/mCols;
676
677
                   position[3*vertex  ] = x - 0.5f;
678
                   position[3*vertex+1] = 0.5f - (float)(curr.row+1)/mRows;
679 6a06a912 Leszek Koltunski
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;  
680
            
681 39cbf9dc Leszek Koltunski
                   normal[3*vertex  ]   = side==SOUTH ? 0.0f: (side==EAST?-R:R);
682 6a06a912 Leszek Koltunski
                   normal[3*vertex+1]   =-1.0f;
683
                   normal[3*vertex+2]   = lower ? -R:R;
684
685 985ea9c5 Leszek Koltunski
                   texture[2*vertex  ]  = x;
686
                   texture[2*vertex+1]  = 1.0f-(float)(lower? (curr.row+2):(curr.row+1))/mRows;
687 6a06a912 Leszek Koltunski
                   break;
688 985ea9c5 Leszek Koltunski
       case WEST : y = (float)(back  ? (curr.row+1):(curr.row))/mRows;
689
690
                   position[3*vertex  ] = (float)curr.col/mCols -0.5f;
691
                   position[3*vertex+1] = 0.5f - y;
692 6a06a912 Leszek Koltunski
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
693
694 39cbf9dc Leszek Koltunski
                   normal[3*vertex  ]   =-1.0f;
695 6a06a912 Leszek Koltunski
                   normal[3*vertex+1]   = side==WEST ? 0.0f : (side==NORTH?-R:R);
696
                   normal[3*vertex+2]   = lower ? -R:R;
697
 
698 39cbf9dc Leszek Koltunski
                   texture[2*vertex  ]  = (float)(lower ? (curr.col-1):(curr.col  ))/mCols;
699 985ea9c5 Leszek Koltunski
                   texture[2*vertex+1]  = 1.0f - y;
700 6a06a912 Leszek Koltunski
                   break;
701 985ea9c5 Leszek Koltunski
       case EAST : y = (float)(back  ? (curr.row):(curr.row+1))/mRows;
702
703
                   position[3*vertex  ] = (float)(curr.col+1)/mCols -0.5f;
704
                   position[3*vertex+1] = 0.5f - y;
705 6a06a912 Leszek Koltunski
                   position[3*vertex+2] = lower ? BACKZ : FRONTZ;
706
707 39cbf9dc Leszek Koltunski
                   normal[3*vertex  ]   = 1.0f;
708 6a06a912 Leszek Koltunski
                   normal[3*vertex+1]   = side==EAST ? 0.0f : (side==SOUTH?-R:R);
709
                   normal[3*vertex+2]   = lower ? -R:R; 
710
711 39cbf9dc Leszek Koltunski
                   texture[2*vertex  ]  = (float)(lower ? (curr.col+2):(curr.col+1))/mCols;
712 985ea9c5 Leszek Koltunski
                   texture[2*vertex+1]  = 1.0f - y;
713 6a06a912 Leszek Koltunski
                   break;
714
       }
715
     
716 39cbf9dc Leszek Koltunski
     if(texture[2*vertex  ]>1.0f) texture[2*vertex  ] =2.0f-texture[2*vertex  ];
717
     if(texture[2*vertex  ]<0.0f) texture[2*vertex  ] =    -texture[2*vertex  ];
718 6a06a912 Leszek Koltunski
     if(texture[2*vertex+1]>1.0f) texture[2*vertex+1] =2.0f-texture[2*vertex+1];
719
     if(texture[2*vertex+1]<0.0f) texture[2*vertex+1] =    -texture[2*vertex+1];
720
     }
721
722 665e2c45 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
723
724
   private void build(boolean frontOnly)
725
     {
726
     int numVertices=0;
727
     float[] positionData= new float[POSITION_DATA_SIZE*dataLength];
728
     float[] normalData  = new float[NORMAL_DATA_SIZE  *dataLength];
729
     float[] textureData = new float[TEX_DATA_SIZE     *dataLength];
730
731
     //android.util.Log.d("CUBES","building front grid...");
732
733
     numVertices = buildFrontBackGrid(true, numVertices,positionData,normalData,textureData);
734
735
     if( !frontOnly )
736
       {
737
       numVertices = repeatLast(numVertices,positionData,normalData,textureData);
738
       if( numVertices%2==1 )
739
         {
740
         //android.util.Log.d("CUBES","repeating winding1 vertex");
741
742
         numVertices = repeatLast(numVertices,positionData,normalData,textureData);
743
         }
744
745
       //android.util.Log.d("CUBES","building side grid...");
746
747
       numVertices = buildSideGrid (numVertices,positionData,normalData,textureData);
748
749
       //android.util.Log.d("CUBES","building back grid...");
750
751
       numVertices = buildFrontBackGrid (false,numVertices,positionData,normalData,textureData);
752
       }
753
754
     /*
755
     android.util.Log.e("CUBES","dataLen="+dataLength+" vertex="+numVertices);
756
     android.util.Log.d("CUBES", "position: "+debug(positionData,3) );
757
     android.util.Log.d("CUBES", "normal: "  +debug(  normalData,3) );
758
     android.util.Log.d("CUBES", "texture: " +debug( textureData,2) );
759
     */
760 16d8b8f3 Leszek Koltunski
761
     if( remainingVert!=0 )
762
       android.util.Log.d("CUBES", "remainingVert " +remainingVert );
763 665e2c45 Leszek Koltunski
764
     mGridPositions = ByteBuffer.allocateDirect(POSITION_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
765
     mGridPositions.put(positionData).position(0);
766
767
     mGridNormals = ByteBuffer.allocateDirect(NORMAL_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
768
     mGridNormals.put(normalData).position(0);
769
770
     mGridTexture = ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
771
     mGridTexture.put(textureData).position(0);
772
     }
773
774 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
775
// PUBLIC API
776
///////////////////////////////////////////////////////////////////////////////////////////////////
777
/**
778
 * Creates the underlying grid of vertices, normals, texture coords and colors.
779
 *    
780 39cbf9dc Leszek Koltunski
 * @param cols      See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
781
 * @param desc      See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
782
 * @param frontOnly See {@link DistortedCubes#DistortedCubes(int,String,int,boolean)}
783 6a06a912 Leszek Koltunski
 */
784 665e2c45 Leszek Koltunski
   DistortedCubesGrid(int cols, String desc, boolean frontOnly)
785 6a06a912 Leszek Koltunski
      {
786 2e96ee72 Leszek Koltunski
      prepareDataStructures(cols,desc,frontOnly);
787 665e2c45 Leszek Koltunski
      build(frontOnly);
788
      }
789 6a06a912 Leszek Koltunski
790 665e2c45 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
791
/**
792
 * Creates a full, hole-less underlying grid of vertices, normals, texture coords and colors.
793
 *
794
 * @param cols      See {@link DistortedCubes#DistortedCubes(int,int,int,boolean)}
795
 * @param rows      See {@link DistortedCubes#DistortedCubes(int,int,int,boolean)}
796
 * @param frontOnly See {@link DistortedCubes#DistortedCubes(int,int,int,boolean)}
797
 */
798
   DistortedCubesGrid(int cols, int rows, boolean frontOnly)
799
      {
800
      prepareDataStructures(cols,rows,frontOnly);
801
      build(frontOnly);
802 6a06a912 Leszek Koltunski
      }
803
   }
804
///////////////////////////////////////////////////////////////////////////////////////////////////