Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshPolygon.java @ 724f67ee

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 float NOT_DONE_YET = -1000;
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[] mBandQuot;
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
    mBandQuot = new float[mNumPolygonBands];
78

    
79
    int next, prev;
80

    
81
    for(int band=0; band<mNumPolygonBands; band++)
82
      {
83
      next = (band==mNumPolygonBands-1 ? band : band+1);
84
      prev = (band==                 0 ? band : band-1);
85

    
86
      mBandQuot[band] = (mPolygonBands[2*prev+1]-mPolygonBands[2*next+1]) / (mPolygonBands[2*next]-mPolygonBands[2*prev]);
87
      }
88
    }
89

    
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91

    
92
  private float getSpecialQuot(int index)
93
    {
94
    int num = 1 + extraIndex + 2*extraVertices;
95
    int change1 = extraVertices+1;
96
    int change2 = num-change1;
97
    float quot = 1.0f/(extraIndex+1);
98

    
99
    if( index<change1 )      return index*quot/change1;
100
    else if( index>change2 ) return 1-quot + (index-change2)*quot/change1;
101
    else                     return (index-change1+1)*quot;
102
    }
103

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

    
106
  private float getQuot(int index, int band, boolean isExtra)
107
    {
108
    int num = mNumPolygonBands-1-band;
109

    
110
    if( num>0 )
111
      {
112
      if( isExtra )
113
        {
114
        int extra = extraIndex-band+extraVertices;
115

    
116
        if( index < extra )
117
          {
118
          float quot = ((float)extraIndex-band)/(extra*num);
119
          return index*quot;
120
          }
121
        else if( index > num+2*extraVertices-extra )
122
          {
123
          float quot = ((float)extraIndex-band)/(extra*num);
124
          return (1.0f-((float)extraIndex-band)/num) + (index-num-2*extraVertices+extra)*quot;
125
          }
126
        else
127
          {
128
          return ((float)(index-extraVertices))/num;
129
          }
130
        }
131

    
132
      return (float)index/num;
133
      }
134

    
135
    return 1.0f;
136
    }
137

    
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

    
140
  private float computeZEdge(float quot)
141
    {
142
    if( quot>=1.0f ) return 0.0f;
143

    
144
    for(int band=1; band<mNumPolygonBands; band++)
145
      {
146
      float curr = mPolygonBands[2*band];
147

    
148
      if( curr<=quot )
149
        {
150
        float prev = mPolygonBands[2*band-2];
151
        float prevH= mPolygonBands[2*band-1];
152
        float currH= mPolygonBands[2*band+1];
153

    
154
        float A = (prev-quot)/(prev-curr);
155

    
156
        return A*currH + (1-A)*prevH;
157
        }
158
      }
159

    
160
    return 0.0f;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

    
165
  private int addVertex(int vertex, int polyBand, int polyVertex, int polyEndVer, float quot,
166
                        int edgeShape, float[] attribs1, float[] attribs2)
167
    {
168
    remainingVert--;
169

    
170
    float Xfirst= mPolygonVertices[2*polyVertex  ];
171
    float Yfirst= mPolygonVertices[2*polyVertex+1];
172
    float Xlast = mPolygonVertices[2*polyEndVer  ];
173
    float Ylast = mPolygonVertices[2*polyEndVer+1];
174

    
175
    float xEdge = Xfirst + quot*(Xlast-Xfirst);
176
    float yEdge = Yfirst + quot*(Ylast-Yfirst);
177
    float zEdge;
178

    
179
    switch(edgeShape)
180
      {
181
      case SHAPE_DD : zEdge = 0.0f;
182
                      break;
183
      case SHAPE_UU : zEdge = mPolygonBands[2*mNumPolygonBands-1];
184
                      break;
185
      case SHAPE_DU : zEdge = quot>=0.5f ? mPolygonBands[2*mNumPolygonBands-1] : computeZEdge(1-2*quot);
186
                      break;
187
      case SHAPE_UD : zEdge = quot<=0.5f ? mPolygonBands[2*mNumPolygonBands-1] : computeZEdge(2*quot-1);
188
                      break;
189
      default       : zEdge = quot<=0.5f ? computeZEdge(1-2*quot) : computeZEdge(2*quot-1);
190
                      break;
191
      }
192

    
193
    float q =  mPolygonBands[2*polyBand];
194

    
195
    float x = q*xEdge;
196
    float y = q*yEdge;
197
    float z = q*zEdge + mPolygonBands[2*polyBand+1];
198

    
199
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB  ] = x;
200
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+1] = y;
201
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+2] = z;
202

    
203
    int index = VERT1_ATTRIBS*vertex + NOR_ATTRIB;
204

    
205
    if( quot==0.0f || quot==1.0f )
206
      {
207
      float vx = mBandQuot[polyBand]*xEdge;
208
      float vy = mBandQuot[polyBand]*yEdge;
209
      float vz = xEdge*xEdge + yEdge*yEdge;
210
      float len = (float)Math.sqrt(vx*vx + vy*vy + vz*vz);
211

    
212
      attribs1[index  ] = vx/len;
213
      attribs1[index+1] = vy/len;
214
      attribs1[index+2] = vz/len;
215
      }
216
    else
217
      {
218
      attribs1[index  ] = NOT_DONE_YET;
219
      }
220

    
221
    attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB  ] = x+0.5f;
222
    attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB+1] = y+0.5f;
223

    
224
    return vertex+1;
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228

    
229
  private void addVertexNormal(int vertex, int end1, int end2, float[] attribs1)
230
    {
231
    // android.util.Log.e("D", "vertex="+vertex+" end1="+end1+" end2="+end2);
232

    
233
    int index = VERT1_ATTRIBS*vertex + NOR_ATTRIB;
234

    
235
    if( attribs1[index] == NOT_DONE_YET)
236
      {
237
      int iv = VERT1_ATTRIBS*vertex + POS_ATTRIB;
238
      int i1 = VERT1_ATTRIBS*end1   + POS_ATTRIB;
239
      int i2 = VERT1_ATTRIBS*end2   + POS_ATTRIB;
240

    
241
      float vx = attribs1[iv  ];
242
      float vy = attribs1[iv+1];
243
      float vz = attribs1[iv+2];
244

    
245
      float x1 = attribs1[i1  ];
246
      float y1 = attribs1[i1+1];
247
      float z1 = attribs1[i1+2];
248

    
249
      float x2 = attribs1[i2  ];
250
      float y2 = attribs1[i2+1];
251
      float z2 = attribs1[i2+2];
252

    
253
      float dx1 = vx-x1;
254
      float dy1 = vy-y1;
255
      float dz1 = vz-z1;
256

    
257
      float dx2 = vx-x2;
258
      float dy2 = vy-y2;
259
      float dz2 = vz-z2;
260

    
261
      float cx = dy1*dz2 - dz1*dy2;
262
      float cy = dz1*dx2 - dx1*dz2;
263
      float cz = dx1*dy2 - dy1*dx2;
264

    
265
      float len = (float)Math.sqrt(cx*cx + cy*cy + cz*cz);
266

    
267
      attribs1[index  ] = cx/len;
268
      attribs1[index+1] = cy/len;
269
      attribs1[index+2] = cz/len;
270
      }
271
    }
272

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

    
275
  private int createBandStrip(int vertex, int polyBand, int polyVertex, int edgeShape, float[] attribs1, float[] attribs2)
276
    {
277
    int initVertex = vertex;
278

    
279
    if( polyVertex==0 )
280
      {
281
      vertex = addVertex(vertex,polyBand,0,1,0,edgeShape,attribs1,attribs2);
282
      if( polyBand>0 ) vertex = addVertex(vertex,polyBand,0,1,0,edgeShape,attribs1,attribs2);
283
      }
284

    
285
    boolean specialCase = mNumPolygonBands==2 && polyBand==0 && extraIndex>0;
286
    boolean isExtra = polyBand<extraIndex;
287
    int numPairs = specialCase ? extraIndex+1 : mNumPolygonBands-1-polyBand;
288
    if( isExtra ) numPairs += 2*extraVertices;
289

    
290
    int polyEndVer = polyVertex==mNumPolygonVertices-1 ? 0 : polyVertex+1;
291
    float quot1, quot2;
292

    
293
    for(int index=0; index<numPairs; index++)
294
      {
295
      if( specialCase )
296
        {
297
        quot1 = 1.0f;
298
        quot2 = getSpecialQuot(index+1);
299
        }
300
      else
301
        {
302
        quot1 = getQuot(index  ,polyBand+1, isExtra);
303
        quot2 = getQuot(index+1,polyBand  , isExtra);
304
        }
305

    
306
      vertex = addVertex(vertex,polyBand+1,polyVertex,polyEndVer,quot1,edgeShape,attribs1,attribs2);
307
      vertex = addVertex(vertex,polyBand  ,polyVertex,polyEndVer,quot2,edgeShape,attribs1,attribs2);
308
      }
309

    
310
    if( polyVertex==0 )
311
      {
312
      if( polyBand>0 ) addVertexNormal(initVertex,initVertex+3,initVertex+2,attribs1);
313
      else             addVertexNormal(initVertex,initVertex+2,initVertex+1,attribs1);
314
      }
315
    else
316
      {
317
      addVertexNormal(initVertex,initVertex-1,initVertex+1,attribs1);
318
      }
319

    
320
    boolean lower = (polyVertex>0 || polyBand>0);
321

    
322
    for(int index=initVertex+1; index<vertex-1; index++)
323
      {
324
      addVertexNormal(index,(lower ? index+2 : index-1),index+1,attribs1);
325
      lower = !lower;
326
      }
327

    
328
    addVertexNormal(vertex-1,vertex-2,vertex-3,attribs1);
329

    
330
    return vertex;
331
    }
332

    
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334

    
335
  private int computeEdgeShape(int curr)
336
    {
337
    if( mEdgeUp==null || !mEdgeUp[curr] ) return SHAPE_DD;
338

    
339
    int prev = (curr==0 ? mNumPolygonVertices-1 : curr-1);
340
    int next = (curr==mNumPolygonVertices-1 ? 0 : curr+1);
341

    
342
    boolean l = mEdgeUp[prev];
343
    boolean r = mEdgeUp[next];
344

    
345
    return l ? (r ? SHAPE_UU : SHAPE_UD) : (r ? SHAPE_DU : SHAPE_DUD);
346
    }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  private void buildGrid(float[] attribs1, float[] attribs2)
351
    {
352
    int vertex=0;
353

    
354
    int[] edgeShape = new int[mNumPolygonVertices];
355

    
356
    for(int polyVertex=0; polyVertex<mNumPolygonVertices; polyVertex++)
357
      edgeShape[polyVertex] = computeEdgeShape(polyVertex);
358

    
359
    for(int polyBand=0; polyBand<mNumPolygonBands-1; polyBand++)
360
      for(int polyVertex=0; polyVertex<mNumPolygonVertices; polyVertex++)
361
        {
362
       // android.util.Log.e("D", "creating strip polyBand="+polyBand+" polyVertex="+polyVertex+" : "+vertex);
363
        vertex = createBandStrip(vertex,polyBand,polyVertex,edgeShape[polyVertex],attribs1,attribs2);
364
       // android.util.Log.e("D", "  "+vertex);
365
        }
366
    }
367

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

    
402
    mPolygonVertices   = verticesXY;
403
    mPolygonBands      = bands;
404
    mNumPolygonVertices= mPolygonVertices.length /2;
405
    mNumPolygonBands   = mPolygonBands.length /2;
406
    mEdgeUp            = edgeUp;
407
    extraIndex         = exIndex;
408
    extraVertices      = exVertices;
409

    
410
    if( centerX!=0.0f || centerY!=0.0f )
411
      {
412
      for(int v=0; v<mNumPolygonVertices; v++)
413
        {
414
        mPolygonVertices[2*v  ] -= centerX;
415
        mPolygonVertices[2*v+1] -= centerY;
416
        }
417
      }
418

    
419
    computeNumberOfVertices();
420
    computeCache();
421

    
422
    float[] attribs1= new float[VERT1_ATTRIBS*numVertices];
423
    float[] attribs2= new float[VERT2_ATTRIBS*numVertices];
424

    
425
    buildGrid(attribs1,attribs2);
426

    
427
    if( remainingVert!=0 )
428
      DistortedLibrary.logMessage("MeshPolygon: remainingVert " +remainingVert );
429

    
430
    if( centerX!=0.0f || centerY!=0.0f )
431
      {
432
      for(int v=0; v<numVertices; v++)
433
        {
434
        attribs1[VERT1_ATTRIBS*v + POS_ATTRIB  ] += centerX;
435
        attribs1[VERT1_ATTRIBS*v + POS_ATTRIB+1] += centerY;
436
        attribs2[VERT2_ATTRIBS*v + TEX_ATTRIB  ] += centerX;
437
        attribs2[VERT2_ATTRIBS*v + TEX_ATTRIB+1] += centerY;
438
        }
439
      }
440

    
441
    setAttribs(attribs1,attribs2);
442
    }
443

    
444
///////////////////////////////////////////////////////////////////////////////////////////////////
445

    
446
  public MeshPolygon(float[] verticesXY, float[] bands, int exIndex, int exVertices)
447
    {
448
    this(verticesXY,bands,null,exIndex,exVertices,0.0f,0.0f);
449
    }
450

    
451
///////////////////////////////////////////////////////////////////////////////////////////////////
452
/**
453
 * Create a polygon of any shape and varying elevations from the edges towards the center.
454
 * Equivalent of the previous with exIndex=0 or exVertices=0.
455
 */
456
  public MeshPolygon(float[] verticesXY, float[] bands)
457
    {
458
    this(verticesXY,bands,null,0,0,0.0f,0.0f);
459
    }
460

    
461
///////////////////////////////////////////////////////////////////////////////////////////////////
462
/**
463
 * Copy constructor.
464
 */
465
  public MeshPolygon(MeshPolygon mesh, boolean deep)
466
    {
467
    super(mesh,deep);
468
    }
469

    
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471
/**
472
 * Copy the Mesh.
473
 *
474
 * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
475
 *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
476
 *             coordinates and effect associations, is always deep copied)
477
 */
478
  public MeshPolygon copy(boolean deep)
479
    {
480
    return new MeshPolygon(this,deep);
481
    }
482
 }
(6-6/10)