Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedCubesGrid.java @ 16d8b8f3

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