Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshBandedTriangle.java @ 33dbf30b

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
 * Creator a triangular mesh divided into 'bands' i.e. strips parallel to one of the sides and
29
 * and of different elevations.
30
 * <p>
31
 * This is a building block for MeshMultigon.
32
 */
33
public class MeshBandedTriangle extends MeshBase
34
  {
35
  private static final int NUM_CACHE = 20;
36
  private static final int MODE_UP   = 0;
37
  private static final int MODE_DOWN = 1;
38
  private static final int MODE_FLAT = 2;
39

    
40
  private float mLeftX, mLeftY;
41
  private float mRightX, mRightY;
42
  private float mTopX, mTopY;
43

    
44
  private float[] mNormL, mNormR;
45
  private int mMode;
46

    
47
  private float[] mBands;
48
  private int mNumBands;
49

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

    
54
  private float[] mCurveCache;
55
  private float mVecX, mVecY;
56
  private int[] mEdgeShape;
57

    
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59
// mNumBands>=2
60

    
61
  private void computeNumberOfVertices()
62
     {
63
     /*
64
     if( mNumBands==2 && extraIndex>0 )
65
       {
66
       numVertices = 1 + 2*mNumPolygonVertices*(1+extraIndex+2*extraVertices);
67
       }
68
     else
69
       {
70
       numVertices = (mNumPolygonVertices*mNumPolygonBands+2)*(mNumPolygonBands-1) - 1;
71
       numVertices+= 2*mNumPolygonVertices*(2*extraIndex*extraVertices);
72
       }
73

    
74
     remainingVert = numVertices;
75

    
76
      */
77
     }
78

    
79
///////////////////////////////////////////////////////////////////////////////////////////////////
80

    
81
  private void computeCache()
82
    {
83
    /*
84
    mCurveCache = new float[NUM_CACHE];
85
    float[] tmpD = new float[mNumPolygonBands+1];
86
    float[] tmpX = new float[mNumPolygonBands+1];
87

    
88
    for(int i=1; i<mNumPolygonBands; i++)
89
      {
90
      tmpD[i] = (mPolygonBands[2*i-1]-mPolygonBands[2*i+1]) / (mPolygonBands[2*i]-mPolygonBands[2*i-2]);
91
      tmpX[i] = 1.0f - (mPolygonBands[2*i]+mPolygonBands[2*i-2])/2;
92
      }
93

    
94
    tmpD[0] = tmpD[1];
95
    tmpD[mNumPolygonBands] = tmpD[mNumPolygonBands-1];
96
    tmpX[0] = 0.0f;
97
    tmpX[mNumPolygonBands] = 1.0f;
98

    
99
    int prev = 0;
100
    int next = 0;
101

    
102
    for(int i=0; i<NUM_CACHE-1; i++)
103
      {
104
      float x = i/(NUM_CACHE-1.0f);
105

    
106
      if( x>=tmpX[next] )
107
        {
108
        prev = next;
109
        while( next<=mNumPolygonBands && x>=tmpX[next] ) next++;
110
        }
111

    
112
      if( next>prev )
113
        {
114
        float t = (x-tmpX[prev]) / (tmpX[next]-tmpX[prev]);
115
        mCurveCache[i] = t*(tmpD[next]-tmpD[prev]) + tmpD[prev];
116
        }
117
      else
118
        {
119
        mCurveCache[i] = tmpD[next];
120
        }
121
      }
122

    
123
    mCurveCache[NUM_CACHE-1] = tmpD[mNumPolygonBands];
124

    
125
     */
126
    }
127
/*
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129

    
130
  private float getSpecialQuot(int index)
131
    {
132
    int num = 1 + extraIndex + 2*extraVertices;
133
    int change1 = extraVertices+1;
134
    int change2 = num-change1;
135
    float quot = 1.0f/(extraIndex+1);
136

    
137
    if( index<change1 )      return index*quot/change1;
138
    else if( index>change2 ) return 1-quot + (index-change2)*quot/change1;
139
    else                     return (index-change1+1)*quot;
140
    }
141

    
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

    
144
  private float getQuot(int index, int band, boolean isExtra)
145
    {
146
    int num = mNumPolygonBands-1-band;
147

    
148
    if( num>0 )
149
      {
150
      if( isExtra )
151
        {
152
        int extra = extraIndex-band+extraVertices;
153

    
154
        if( index < extra )
155
          {
156
          float quot = ((float)extraIndex-band)/(extra*num);
157
          return index*quot;
158
          }
159
        else if( index > num+2*extraVertices-extra )
160
          {
161
          float quot = ((float)extraIndex-band)/(extra*num);
162
          return (1.0f-((float)extraIndex-band)/num) + (index-num-2*extraVertices+extra)*quot;
163
          }
164
        else
165
          {
166
          return ((float)(index-extraVertices))/num;
167
          }
168
        }
169

    
170
      return (float)index/num;
171
      }
172

    
173
    return 1.0f;
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

    
178
  private float computeZEdge(float quot)
179
    {
180
    if( quot>=1.0f ) return 0.0f;
181

    
182
    for(int band=1; band<mNumPolygonBands; band++)
183
      {
184
      float curr = mPolygonBands[2*band];
185

    
186
      if( curr<=quot )
187
        {
188
        float prev = mPolygonBands[2*band-2];
189
        float prevH= mPolygonBands[2*band-1];
190
        float currH= mPolygonBands[2*band+1];
191

    
192
        float A = (prev-quot)/(prev-curr);
193

    
194
        return A*currH + (1-A)*prevH;
195
        }
196
      }
197

    
198
    return 0.0f;
199
    }
200

    
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202

    
203
  private float derivative(float x)
204
    {
205
    if( x>=1.0f )
206
      {
207
      return 0.0f;
208
      }
209
    else
210
      {
211
      float tmp = x*(NUM_CACHE-1);
212
      int i1 = (int)tmp;
213
      int i2 = i1+1;
214

    
215
      // why 0.5? Arbitrarily; this way the cubit faces of Twisty Puzzles
216
      // [the main and only user of this class] look better.
217
      return 0.5f*((tmp-i1)*(mCurveCache[i2]-mCurveCache[i1]) + mCurveCache[i1]);
218
      }
219
    }
220

    
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222

    
223
  private void figureOutNormalVector2D(int edgeShape, int polyVertex, int polyEndVer, float quot, float xEdge, float yEdge )
224
    {
225
    if( edgeShape==SHAPE_DD )
226
      {
227
      if( quot<0.5f )
228
        {
229
        int p = polyVertex>0 ? polyVertex-1 : mNumPolygonVertices-1;
230
        int prvShape = mEdgeShape[p];
231

    
232
        switch(prvShape)
233
          {
234
          case SHAPE_DD : mVecX = xEdge;
235
                          mVecY = yEdge;
236
                          break;
237
          case SHAPE_UD :
238
          case SHAPE_DUD: float a = 2*quot;
239
                          float xCurr= mPolygonVertices[2*polyVertex  ];
240
                          float yCurr= mPolygonVertices[2*polyVertex+1];
241
                          float xPrev= mPolygonVertices[2*p  ];
242
                          float yPrev= mPolygonVertices[2*p+1];
243
                          float xVec = xCurr-xPrev;
244
                          float yVec = yCurr-yPrev;
245

    
246
                          mVecX = a*xEdge + (1-a)*xVec;
247
                          mVecY = a*yEdge + (1-a)*yVec;
248

    
249
                          break;
250
          default: throw new RuntimeException("figureOutNormalVector2D: impossible1: "+prvShape);
251
          }
252
        }
253
      else
254
        {
255
        int n = polyEndVer==mNumPolygonVertices-1 ? 0 : polyEndVer+1;
256
        int nxtShape = mEdgeShape[polyEndVer];
257

    
258
        switch(nxtShape)
259
          {
260
          case SHAPE_DD : mVecX = xEdge;
261
                          mVecY = yEdge;
262
                          break;
263
          case SHAPE_DU :
264
          case SHAPE_DUD: float a = 2-2*quot;
265
                          float xCurr= mPolygonVertices[2*polyEndVer  ];
266
                          float yCurr= mPolygonVertices[2*polyEndVer+1];
267
                          float xNext= mPolygonVertices[2*n  ];
268
                          float yNext= mPolygonVertices[2*n+1];
269
                          float xVec = xCurr-xNext;
270
                          float yVec = yCurr-yNext;
271

    
272
                          mVecX = a*xEdge + (1-a)*xVec;
273
                          mVecY = a*yEdge + (1-a)*yVec;
274
                          break;
275
          default: throw new RuntimeException("figureOutNormalVector2D: impossible2: "+nxtShape);
276
          }
277
        }
278
      }
279
    else if( edgeShape==SHAPE_UU || (quot>=0.5f && edgeShape==SHAPE_DU) || (quot<0.5f && edgeShape==SHAPE_UD) )
280
      {
281
      mVecX = 1;
282
      mVecY = 0;
283
      }
284
    else
285
      {
286
      float dx = mPolygonVertices[2*polyVertex  ] - mPolygonVertices[2*polyEndVer  ];
287
      float dy = mPolygonVertices[2*polyVertex+1] - mPolygonVertices[2*polyEndVer+1];
288

    
289
      if( quot<0.5 )
290
        {
291
        mVecX = dx;
292
        mVecY = dy;
293
        }
294
      else
295
        {
296
        mVecX = -dx;
297
        mVecY = -dy;
298
        }
299
      }
300
    }
301

    
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303

    
304
  private float figureOutDerivative(int edgeShape, int polyBand, float quot)
305
    {
306
    if( edgeShape==SHAPE_DD )
307
      {
308
      return derivative(1-mPolygonBands[2*polyBand]);
309
      }
310
    if( edgeShape==SHAPE_UU || (quot>=0.5f && edgeShape==SHAPE_DU) || (quot<0.5f && edgeShape==SHAPE_UD) )
311
      {
312
      return 0;
313
      }
314

    
315
    float x = 1-mPolygonBands[2*polyBand];
316
    float q = quot>=0.5f ? 2-2*quot : 2*quot;
317
    return derivative((1-x)*q+x);
318
    }
319

    
320
///////////////////////////////////////////////////////////////////////////////////////////////////
321

    
322
  private int addVertex(int vertex, int polyBand, int polyVertex, int polyEndVer, float quot,
323
                        float[] attribs1, float[] attribs2)
324
    {
325
    remainingVert--;
326

    
327
    float Xfirst= mPolygonVertices[2*polyVertex  ];
328
    float Yfirst= mPolygonVertices[2*polyVertex+1];
329
    float Xlast = mPolygonVertices[2*polyEndVer  ];
330
    float Ylast = mPolygonVertices[2*polyEndVer+1];
331

    
332
    float xEdge = Xfirst + quot*(Xlast-Xfirst);
333
    float yEdge = Yfirst + quot*(Ylast-Yfirst);
334
    float zEdge;
335

    
336
    float q = mPolygonBands[2*polyBand];
337
    float o = mPolygonBands[2*polyBand+1];
338
    float t = mPolygonBands[2*mNumPolygonBands-1];
339

    
340
    int shape = mEdgeShape[polyVertex];
341

    
342
    switch(shape)
343
      {
344
      case SHAPE_DD : zEdge = 0.0f; break;
345
      case SHAPE_UU : zEdge = t;    break;
346
      case SHAPE_DU : zEdge = quot>=0.5f ? t : computeZEdge(1-2*quot); break;
347
      case SHAPE_UD : zEdge = quot<=0.5f ? t : computeZEdge(2*quot-1); break;
348
      default       : zEdge = quot<=0.5f ? computeZEdge(1-2*quot) : computeZEdge(2*quot-1); break;
349
      }
350

    
351
    float x = q*xEdge;
352
    float y = q*yEdge;
353
    float z = o + (t-o)*(zEdge/t);
354

    
355
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB  ] = x;
356
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+1] = y;
357
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+2] = z;
358

    
359
    figureOutNormalVector2D(shape, polyVertex, polyEndVer, quot, xEdge, yEdge);
360
    float d = figureOutDerivative(shape,polyBand,quot);
361

    
362
    float vx = d*mVecX;
363
    float vy = d*mVecY;
364
    float vz = mVecX*mVecX + mVecY*mVecY;
365
    float len = (float)Math.sqrt(vx*vx + vy*vy + vz*vz);
366

    
367
    int index = VERT1_ATTRIBS*vertex + NOR_ATTRIB;
368
    attribs1[index  ] = vx/len;
369
    attribs1[index+1] = vy/len;
370
    attribs1[index+2] = vz/len;
371

    
372
    attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB  ] = x+0.5f;
373
    attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB+1] = y+0.5f;
374

    
375
    return vertex+1;
376
    }
377

    
378
///////////////////////////////////////////////////////////////////////////////////////////////////
379

    
380
  private int createBandStrip(int vertex, int polyBand, int polyVertex, float[] attribs1, float[] attribs2)
381
    {
382
    if( polyVertex==0 )
383
      {
384
      vertex = addVertex(vertex,polyBand,0,1,0,attribs1,attribs2);
385
      if( polyBand>0 ) vertex = addVertex(vertex,polyBand,0,1,0,attribs1,attribs2);
386
      }
387

    
388
    boolean specialCase = mNumPolygonBands==2 && polyBand==0 && extraIndex>0;
389
    boolean isExtra = polyBand<extraIndex;
390
    int numPairs = specialCase ? extraIndex+1 : mNumPolygonBands-1-polyBand;
391
    if( isExtra ) numPairs += 2*extraVertices;
392

    
393
    int polyEndVer = polyVertex==mNumPolygonVertices-1 ? 0 : polyVertex+1;
394
    float quot1, quot2;
395

    
396
    for(int index=0; index<numPairs; index++)
397
      {
398
      if( specialCase )
399
        {
400
        quot1 = 1.0f;
401
        quot2 = getSpecialQuot(index+1);
402
        }
403
      else
404
        {
405
        quot1 = getQuot(index  ,polyBand+1, isExtra);
406
        quot2 = getQuot(index+1,polyBand  , isExtra);
407
        }
408

    
409
      vertex = addVertex(vertex,polyBand+1,polyVertex,polyEndVer,quot1,attribs1,attribs2);
410
      vertex = addVertex(vertex,polyBand  ,polyVertex,polyEndVer,quot2,attribs1,attribs2);
411
      }
412

    
413
    return vertex;
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  private int computeEdgeShape(int curr)
419
    {
420
    if( mEdgeUp==null || !mEdgeUp[curr] ) return SHAPE_DD;
421

    
422
    int prev = (curr==0 ? mNumPolygonVertices-1 : curr-1);
423
    int next = (curr==mNumPolygonVertices-1 ? 0 : curr+1);
424

    
425
    boolean rd = ( !mEdgeUp[next] || mVertUp==null || !mVertUp[next] );
426
    boolean ld = ( !mEdgeUp[prev] || mVertUp==null || !mVertUp[curr] );
427

    
428
    return rd ? (ld ? SHAPE_DUD : SHAPE_UD) : (ld ? SHAPE_DU : SHAPE_UU);
429
    }
430
*/
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432

    
433
  private void buildGrid(float[] attribs1, float[] attribs2)
434
    {
435
    /*
436
    int vertex=0;
437

    
438
    mEdgeShape = new int[mNumPolygonVertices];
439

    
440
    for(int polyVertex=0; polyVertex<mNumPolygonVertices; polyVertex++)
441
      mEdgeShape[polyVertex] = computeEdgeShape(polyVertex);
442

    
443
    for(int polyBand=0; polyBand<mNumPolygonBands-1; polyBand++)
444
      for(int polyVertex=0; polyVertex<mNumPolygonVertices; polyVertex++)
445
        vertex = createBandStrip(vertex,polyBand,polyVertex,attribs1,attribs2);
446

    
447
     */
448
    }
449

    
450
///////////////////////////////////////////////////////////////////////////////////////////////////
451
// PUBLIC API
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453
/**
454
 * Create a triangular mesh split into 'bands' - i.e. strips of triangles - which are parallel to
455
 * a given edge.
456
 *
457
 * @param vL         A pair of floats (x,y) which defines the 'left' vertex of the triangle.
458
 * @param vR         A pair of floats (x,y) which defines the 'right' vertex of the triangle.
459
 * @param vT         A pair of floats (x,y) which defines the 'top' vertex of the triangle.
460
 * @param bands      2K floats; K pairs of two floats each describing a single band.
461
 *                   From (1.0,Z[0]) (the 'left-right' edge, its Z elevation) to (0.0,Z[K])
462
 *                   (the 'top' vertex, its elevation). The polygon is split into such strips.
463
 *                   Must be band[2*i] > band[2*(i+1)] !
464
 *                   The way the bands get interpreted also depends on the 'mode' param.
465
 * @param normL      A pair of floats which define a 2D vector - which is the normal vector of each
466
 *                   mesh vertex which lies on the 'left-top' edge casted to the XY plane.
467
 * @param normR      Same as above but about the vertices which belong to the 'right-top' triangle
468
 *                   edge. This and the previous param define the vector field of normals, as seen
469
 *                   from above, of the whole mesh.
470
 * @param mode       MODE_UP, MODE_DOWN or MODE_FLAT.
471
 *                   This defines how we interpret the bands.
472
 *                   If UP, we interpret them the same as in MeshPolygon - i.e. the first band is
473
 *                   about the 'left-right' edge, then progressively towards the 'top'.
474
 *                   If DOWN, we turn the interpretation of the bands upside-down: it is the last
475
 *                   band which defines the strip aong the 'left-right' edge.
476
 *                   If FLAT, everything is flat anyway, so we disregard the bands and return a mesh
477
 *                   with 3 vertices.
478
 * @param exIndex    This and the next parameter describe how to make the mesh denser at the
479
 *                   'left' and 'right' vertices. If e.g. exIndex=3 and exVertices=2, then 3 triangles
480
 *                   of the outermost band (and 2 triangles of the next band, and 1 triangle of the
481
 *                   third band) get denser - the 3 triangles become 3+2 = 5.
482
 * @param exVertices See above.
483
 */
484
  public MeshBandedTriangle(float[] vL, float[] vR, float[] vT, float[] bands, float[] normL, float[] normR, int mode, int exIndex, int exVertices)
485
    {
486
    super();
487

    
488
    mLeftX   = vL[0];
489
    mLeftY   = vL[1];
490
    mRightX  = vR[0];
491
    mRightY  = vR[1];
492
    mTopX    = vT[0];
493
    mTopY    = vT[1];
494

    
495
    mMode = mode;
496
    mNormL= normL;
497
    mNormR= normR;
498

    
499
    mBands        = bands;
500
    mNumBands     = mBands.length /2;
501
    extraIndex    = exIndex;
502
    extraVertices = exVertices;
503

    
504
    computeNumberOfVertices();
505
    computeCache();
506

    
507
    float[] attribs1= new float[VERT1_ATTRIBS*numVertices];
508
    float[] attribs2= new float[VERT2_ATTRIBS*numVertices];
509

    
510
    buildGrid(attribs1,attribs2);
511

    
512
    if( remainingVert!=0 )
513
      DistortedLibrary.logMessage("MeshBandedTriangle: remainingVert " +remainingVert );
514

    
515
    setAttribs(attribs1,attribs2);
516
    }
517

    
518
///////////////////////////////////////////////////////////////////////////////////////////////////
519
/**
520
 * Copy constructor.
521
 */
522
  public MeshBandedTriangle(MeshBandedTriangle mesh, boolean deep)
523
    {
524
    super(mesh,deep);
525
    }
526

    
527
///////////////////////////////////////////////////////////////////////////////////////////////////
528
/**
529
 * Copy the Mesh.
530
 *
531
 * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
532
 *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
533
 *             coordinates and effect associations, is always deep copied)
534
 */
535
  public MeshBandedTriangle copy(boolean deep)
536
    {
537
    return new MeshBandedTriangle(this,deep);
538
    }
539
 }
(2-2/12)