Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshPolygon.java @ d3287c14

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski  leszek@koltunski.pl                                          //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// This library is free software; you can redistribute it and/or                                 //
7
// modify it under the terms of the GNU Lesser General Public                                    //
8
// License as published by the Free Software Foundation; either                                  //
9
// version 2.1 of the License, or (at your option) any later version.                            //
10
//                                                                                               //
11
// This library 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 GNU                             //
14
// Lesser General Public License for more details.                                               //
15
//                                                                                               //
16
// You should have received a copy of the GNU Lesser General Public                              //
17
// License along with this library; if not, write to the Free Software                           //
18
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
19
///////////////////////////////////////////////////////////////////////////////////////////////////
20

    
21
package org.distorted.library.mesh;
22

    
23
///////////////////////////////////////////////////////////////////////////////////////////////////
24

    
25
import org.distorted.library.main.DistortedLibrary;
26

    
27
/**
28
 * Create a polygon of any shape and varying elevations from the edges towards the center.
29
 * <p>
30
 * Specify a list of vertices. Any two adjacent vertices + the center (0,0,0) form a triangle. The
31
 * polygon is going to be split into such triangles, and each triangle is split into adjustable number
32
 * of 'bands' form the outer edge towards the center. Edges of each band can can at any elevation.
33
 */
34
public class MeshPolygon extends MeshBase
35
  {
36
  private static final int NUM_CACHE = 20;
37
  private static final int SHAPE_DD = 0;
38
  private static final int SHAPE_DU = 1;
39
  private static final int SHAPE_UD = 2;
40
  private static final int SHAPE_UU = 3;
41
  private static final int SHAPE_DUD= 4;
42

    
43
  private float[] mPolygonVertices;
44
  private int mNumPolygonVertices;
45
  private float[] mPolygonBands;
46
  private int mNumPolygonBands;
47
  private boolean[] mEdgeUp;
48

    
49
  private int remainingVert;
50
  private int numVertices;
51
  private int extraIndex, extraVertices;
52

    
53
  private float[] mCurveCache;
54

    
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56
// polygonVertices>=3 , polygonBands>=2
57

    
58
  private void computeNumberOfVertices()
59
     {
60
     if( mNumPolygonBands==2 && extraIndex>0 )
61
       {
62
       numVertices = 1 + 2*mNumPolygonVertices*(1+extraIndex+2*extraVertices);
63
       }
64
     else
65
       {
66
       numVertices = (mNumPolygonVertices*mNumPolygonBands+2)*(mNumPolygonBands-1) - 1;
67
       numVertices+= 2*mNumPolygonVertices*(2*extraIndex*extraVertices);
68
       }
69

    
70
     remainingVert = numVertices;
71
     }
72

    
73
///////////////////////////////////////////////////////////////////////////////////////////////////
74

    
75
  private void computeCache()
76
    {
77
    mCurveCache = new float[NUM_CACHE];
78
    float[] tmpD = new float[mNumPolygonBands+1];
79
    float[] tmpX = new float[mNumPolygonBands+1];
80

    
81
    for(int i=1; i<mNumPolygonBands; i++)
82
      {
83
      tmpD[i] = (mPolygonBands[2*i-1]-mPolygonBands[2*i+1]) / (mPolygonBands[2*i]-mPolygonBands[2*i-2]);
84
      tmpX[i] = 1.0f - (mPolygonBands[2*i]+mPolygonBands[2*i-2])/2;
85
      }
86

    
87
    tmpD[0] = tmpD[1];
88
    tmpD[mNumPolygonBands] = tmpD[mNumPolygonBands-1];
89
    tmpX[0] = 0.0f;
90
    tmpX[mNumPolygonBands] = 1.0f;
91

    
92
    int prev = 0;
93
    int next = 0;
94

    
95
    for(int i=0; i<NUM_CACHE-1; i++)
96
      {
97
      float x = i/(NUM_CACHE-1.0f);
98

    
99
      if( x>=tmpX[next] )
100
        {
101
        prev = next;
102
        while( next<=mNumPolygonBands && x>=tmpX[next] ) next++;
103
        }
104

    
105
      if( next>prev )
106
        {
107
        float t = (x-tmpX[prev]) / (tmpX[next]-tmpX[prev]);
108
        mCurveCache[i] = t*(tmpD[next]-tmpD[prev]) + tmpD[prev];
109
        }
110
      else
111
        {
112
        mCurveCache[i] = tmpD[next];
113
        }
114
      }
115

    
116
    mCurveCache[NUM_CACHE-1] = tmpD[mNumPolygonBands];
117
    }
118

    
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

    
121
  private float getSpecialQuot(int index)
122
    {
123
    int num = 1 + extraIndex + 2*extraVertices;
124
    int change1 = extraVertices+1;
125
    int change2 = num-change1;
126
    float quot = 1.0f/(extraIndex+1);
127

    
128
    if( index<change1 )      return index*quot/change1;
129
    else if( index>change2 ) return 1-quot + (index-change2)*quot/change1;
130
    else                     return (index-change1+1)*quot;
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  private float getQuot(int index, int band, boolean isExtra)
136
    {
137
    int num = mNumPolygonBands-1-band;
138

    
139
    if( num>0 )
140
      {
141
      if( isExtra )
142
        {
143
        int extra = extraIndex-band+extraVertices;
144

    
145
        if( index < extra )
146
          {
147
          float quot = ((float)extraIndex-band)/(extra*num);
148
          return index*quot;
149
          }
150
        else if( index > num+2*extraVertices-extra )
151
          {
152
          float quot = ((float)extraIndex-band)/(extra*num);
153
          return (1.0f-((float)extraIndex-band)/num) + (index-num-2*extraVertices+extra)*quot;
154
          }
155
        else
156
          {
157
          return ((float)(index-extraVertices))/num;
158
          }
159
        }
160

    
161
      return (float)index/num;
162
      }
163

    
164
    return 1.0f;
165
    }
166

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168

    
169
  private float computeZEdge(float quot)
170
    {
171
    if( quot>=1.0f ) return 0.0f;
172

    
173
    for(int band=1; band<mNumPolygonBands; band++)
174
      {
175
      float curr = mPolygonBands[2*band];
176

    
177
      if( curr<=quot )
178
        {
179
        float prev = mPolygonBands[2*band-2];
180
        float prevH= mPolygonBands[2*band-1];
181
        float currH= mPolygonBands[2*band+1];
182

    
183
        float A = (prev-quot)/(prev-curr);
184

    
185
        return A*currH + (1-A)*prevH;
186
        }
187
      }
188

    
189
    return 0.0f;
190
    }
191

    
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193

    
194
  private float derivative(float x)
195
    {
196
    if( x>=1.0f )
197
      {
198
      return mCurveCache[NUM_CACHE-1];
199
      }
200
    else
201
      {
202
      float tmp = x*(NUM_CACHE-1);
203
      int i1 = (int)tmp;
204
      int i2 = i1+1;
205
      return (tmp-i1)*(mCurveCache[i2]-mCurveCache[i1]) + mCurveCache[i1];
206
      }
207
    }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

    
211
  private void doNormals(float[] attribs1, int index, float quot, int edgeShape,
212
                         float xEdge, float yEdge, float zEdge, int polyBand)
213
    {
214
    if( ( quot<=0.5f && (edgeShape==SHAPE_UD || edgeShape==SHAPE_UU) ) ||
215
        ( quot> 0.5f && (edgeShape==SHAPE_DU || edgeShape==SHAPE_UU) )  )
216
      {
217
      attribs1[index  ] = 0;
218
      attribs1[index+1] = 0;
219
      attribs1[index+2] = 1;
220
      }
221
    else
222
      {
223
      float t = mPolygonBands[2*mNumPolygonBands-1];
224
      float x = 1.0f - mPolygonBands[2*polyBand];
225
      float d = derivative(x);
226

    
227
      d *= ((t-zEdge)/t);
228

    
229
      float vx = d*xEdge;
230
      float vy = d*yEdge;
231
      float vz = xEdge*xEdge + yEdge*yEdge;
232
      float len = (float)Math.sqrt(vx*vx + vy*vy + vz*vz);
233

    
234
      attribs1[index  ] = vx/len;
235
      attribs1[index+1] = vy/len;
236
      attribs1[index+2] = vz/len;
237
      }
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

    
242
  private int addVertex(int vertex, int polyBand, int polyVertex, int polyEndVer, float quot,
243
                        int edgeShape, float[] attribs1, float[] attribs2)
244
    {
245
    remainingVert--;
246

    
247
    float Xfirst= mPolygonVertices[2*polyVertex  ];
248
    float Yfirst= mPolygonVertices[2*polyVertex+1];
249
    float Xlast = mPolygonVertices[2*polyEndVer  ];
250
    float Ylast = mPolygonVertices[2*polyEndVer+1];
251

    
252
    float xEdge = Xfirst + quot*(Xlast-Xfirst);
253
    float yEdge = Yfirst + quot*(Ylast-Yfirst);
254
    float zEdge;
255

    
256
    float q = mPolygonBands[2*polyBand];
257
    float o = mPolygonBands[2*polyBand+1];
258
    float t = mPolygonBands[2*mNumPolygonBands-1];
259

    
260
    switch(edgeShape)
261
      {
262
      case SHAPE_DD : zEdge = 0.0f; break;
263
      case SHAPE_UU : zEdge = t;    break;
264
      case SHAPE_DU : zEdge = quot>=0.5f ? t : computeZEdge(1-2*quot); break;
265
      case SHAPE_UD : zEdge = quot<=0.5f ? t : computeZEdge(2*quot-1); break;
266
      default       : zEdge = quot<=0.5f ? computeZEdge(1-2*quot) : computeZEdge(2*quot-1); break;
267
      }
268

    
269
    float x = q*xEdge;
270
    float y = q*yEdge;
271
    float z = o + (t-o)*(zEdge/t);
272

    
273
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB  ] = x;
274
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+1] = y;
275
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+2] = z;
276

    
277
    int index = VERT1_ATTRIBS*vertex + NOR_ATTRIB;
278
    doNormals(attribs1,index, quot, edgeShape, xEdge, yEdge, zEdge, polyBand);
279

    
280
    attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB  ] = x+0.5f;
281
    attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB+1] = y+0.5f;
282

    
283
    return vertex+1;
284
    }
285

    
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287

    
288
  private int createBandStrip(int vertex, int polyBand, int polyVertex, int edgeShape, float[] attribs1, float[] attribs2)
289
    {
290
    if( polyVertex==0 )
291
      {
292
      vertex = addVertex(vertex,polyBand,0,1,0,edgeShape,attribs1,attribs2);
293
      if( polyBand>0 ) vertex = addVertex(vertex,polyBand,0,1,0,edgeShape,attribs1,attribs2);
294
      }
295

    
296
    boolean specialCase = mNumPolygonBands==2 && polyBand==0 && extraIndex>0;
297
    boolean isExtra = polyBand<extraIndex;
298
    int numPairs = specialCase ? extraIndex+1 : mNumPolygonBands-1-polyBand;
299
    if( isExtra ) numPairs += 2*extraVertices;
300

    
301
    int polyEndVer = polyVertex==mNumPolygonVertices-1 ? 0 : polyVertex+1;
302
    float quot1, quot2;
303

    
304
    for(int index=0; index<numPairs; index++)
305
      {
306
      if( specialCase )
307
        {
308
        quot1 = 1.0f;
309
        quot2 = getSpecialQuot(index+1);
310
        }
311
      else
312
        {
313
        quot1 = getQuot(index  ,polyBand+1, isExtra);
314
        quot2 = getQuot(index+1,polyBand  , isExtra);
315
        }
316

    
317
      vertex = addVertex(vertex,polyBand+1,polyVertex,polyEndVer,quot1,edgeShape,attribs1,attribs2);
318
      vertex = addVertex(vertex,polyBand  ,polyVertex,polyEndVer,quot2,edgeShape,attribs1,attribs2);
319
      }
320

    
321
    return vertex;
322
    }
323

    
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325

    
326
  private int computeEdgeShape(int curr)
327
    {
328
    if( mEdgeUp==null || !mEdgeUp[curr] ) return SHAPE_DD;
329

    
330
    int prev = (curr==0 ? mNumPolygonVertices-1 : curr-1);
331
    int next = (curr==mNumPolygonVertices-1 ? 0 : curr+1);
332

    
333
    boolean l = mEdgeUp[prev];
334
    boolean r = mEdgeUp[next];
335

    
336
    return l ? (r ? SHAPE_UU : SHAPE_UD) : (r ? SHAPE_DU : SHAPE_DUD);
337
    }
338

    
339
///////////////////////////////////////////////////////////////////////////////////////////////////
340

    
341
  private void buildGrid(float[] attribs1, float[] attribs2)
342
    {
343
    int vertex=0;
344

    
345
    int[] edgeShape = new int[mNumPolygonVertices];
346

    
347
    for(int polyVertex=0; polyVertex<mNumPolygonVertices; polyVertex++)
348
      edgeShape[polyVertex] = computeEdgeShape(polyVertex);
349

    
350
    for(int polyBand=0; polyBand<mNumPolygonBands-1; polyBand++)
351
      for(int polyVertex=0; polyVertex<mNumPolygonVertices; polyVertex++)
352
        {
353
       // android.util.Log.e("D", "creating strip polyBand="+polyBand+" polyVertex="+polyVertex+" : "+vertex);
354
        vertex = createBandStrip(vertex,polyBand,polyVertex,edgeShape[polyVertex],attribs1,attribs2);
355
       // android.util.Log.e("D", "  "+vertex);
356
        }
357
    }
358

    
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360
// PUBLIC API
361
///////////////////////////////////////////////////////////////////////////////////////////////////
362
/**
363
 * Create a polygon of any shape and varying elevations from the edges towards the center.
364
 * Optionally make it more dense at the vertices.
365
 *
366
 * @param verticesXY 2N floats - packed description of polygon vertices. N pairs (x,y).
367
 *                   Vertices HAVE TO be specified in a COUNTERCLOCKWISE order (starting from any).
368
 * @param bands      2K floats; K pairs of two floats each describing a single band.
369
 *                   From (1.0,Z[0]) (outer edge, its Z elevation) to (0.0,Z[K]) (the center,
370
 *                   its elevation). The polygon is split into such concentric bands.
371
 *                   Must be band[2*i] > band[2*(i+1)] !
372
 * @param edgeUp     N booleans - one for each edge; the first connects vertices (0,1) and (2,3);
373
 *                   then just like 'verticesXY', i.e. counterclockwise.
374
 *                   If this is null, all edges are by default 'down'.
375
 *                   'Down' means that edge's Z is equal to 0; 'up' means that its Z, at least in its
376
 *                   middle, is equal to the highest elevation in the middle of the mesh.
377
 *                   If the 'previous' edge is also up, then the Z is up horizontally from its middle
378
 *                   to the left vertex; else it goes down along the same function it goes along the bands.
379
 *                   Same with the right half of the edge.
380
 * @param exIndex    This and the next parameter describe how to make the mesh denser at the
381
 *                   polyVertices. If e.g. exIndex=3 and exVertices=2, then 3 triangles of the
382
 *                   outermost band (and 2 triangles of the next band, and 1 triangle of the third
383
 *                   band) get denser - the 3 triangles become 3+2 = 5.
384
 * @param exVertices See above.
385
 * @param centerX    the X coordinate of the 'center' of the Polygon, i.e. point of the mesh
386
 *                   all bands go to.
387
 * @param centerY    Y coordinate of the center.
388
 */
389
  public MeshPolygon(float[] verticesXY, float[] bands, boolean[] edgeUp, int exIndex, int exVertices, float centerX, float centerY)
390
    {
391
    super();
392

    
393
    mPolygonVertices   = verticesXY;
394
    mPolygonBands      = bands;
395
    mNumPolygonVertices= mPolygonVertices.length /2;
396
    mNumPolygonBands   = mPolygonBands.length /2;
397
    mEdgeUp            = edgeUp;
398
    extraIndex         = exIndex;
399
    extraVertices      = exVertices;
400

    
401
    if( centerX!=0.0f || centerY!=0.0f )
402
      {
403
      for(int v=0; v<mNumPolygonVertices; v++)
404
        {
405
        mPolygonVertices[2*v  ] -= centerX;
406
        mPolygonVertices[2*v+1] -= centerY;
407
        }
408
      }
409

    
410
    computeNumberOfVertices();
411
    computeCache();
412

    
413
    float[] attribs1= new float[VERT1_ATTRIBS*numVertices];
414
    float[] attribs2= new float[VERT2_ATTRIBS*numVertices];
415

    
416
    buildGrid(attribs1,attribs2);
417

    
418
    if( remainingVert!=0 )
419
      DistortedLibrary.logMessage("MeshPolygon: remainingVert " +remainingVert );
420

    
421
    if( centerX!=0.0f || centerY!=0.0f )
422
      {
423
      for(int v=0; v<numVertices; v++)
424
        {
425
        attribs1[VERT1_ATTRIBS*v + POS_ATTRIB  ] += centerX;
426
        attribs1[VERT1_ATTRIBS*v + POS_ATTRIB+1] += centerY;
427
        attribs2[VERT2_ATTRIBS*v + TEX_ATTRIB  ] += centerX;
428
        attribs2[VERT2_ATTRIBS*v + TEX_ATTRIB+1] += centerY;
429
        }
430
      }
431

    
432
    setAttribs(attribs1,attribs2);
433
    }
434

    
435
///////////////////////////////////////////////////////////////////////////////////////////////////
436

    
437
  public MeshPolygon(float[] verticesXY, float[] bands, int exIndex, int exVertices)
438
    {
439
    this(verticesXY,bands,null,exIndex,exVertices,0.0f,0.0f);
440
    }
441

    
442
///////////////////////////////////////////////////////////////////////////////////////////////////
443
/**
444
 * Create a polygon of any shape and varying elevations from the edges towards the center.
445
 * Equivalent of the previous with exIndex=0 or exVertices=0.
446
 */
447
  public MeshPolygon(float[] verticesXY, float[] bands)
448
    {
449
    this(verticesXY,bands,null,0,0,0.0f,0.0f);
450
    }
451

    
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453
/**
454
 * Copy constructor.
455
 */
456
  public MeshPolygon(MeshPolygon mesh, boolean deep)
457
    {
458
    super(mesh,deep);
459
    }
460

    
461
///////////////////////////////////////////////////////////////////////////////////////////////////
462
/**
463
 * Copy the Mesh.
464
 *
465
 * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
466
 *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
467
 *             coordinates and effect associations, is always deep copied)
468
 */
469
  public MeshPolygon copy(boolean deep)
470
    {
471
    return new MeshPolygon(this,deep);
472
    }
473
 }
(6-6/10)