Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshBandedTriangle.java @ f19d533d

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
  public static final int MODE_NORMAL  = 0;
36
  public static final int MODE_INVERTED= 1;
37
  public static final int MODE_FLAT    = 2;
38

    
39
  private static final int NUM_CACHE = 20;
40

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

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

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

    
51
  private int remainingVert;
52
  private int numVertices;
53
  private int extraBands, extraVertices;
54

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

    
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59

    
60
  private void computeNumberOfVertices()
61
    {
62
    if( mMode==MODE_FLAT )
63
      {
64
      numVertices = 3;
65
      }
66
    else if( mMode==MODE_NORMAL )
67
      {
68
      numVertices = mNumBands*(mNumBands+2) + 4*extraVertices*extraBands;
69
      }
70
    else
71
      {
72
      numVertices = mNumBands*(mNumBands+2);
73
      }
74

    
75
    remainingVert = numVertices;
76
    }
77

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

    
80
  private void computeCache()
81
    {
82
    mCurveCache = new float[NUM_CACHE];
83
    float[] tmpD = new float[mNumBands+1];
84
    float[] tmpX = new float[mNumBands+1];
85

    
86
    for(int i=1; i<mNumBands; i++)
87
      {
88
      tmpD[i] = (mBands[2*i-1]-mBands[2*i+1]) / (mBands[2*i]-mBands[2*i-2]);
89
      tmpX[i] = 1.0f - (mBands[2*i]+mBands[2*i-2])/2;
90
      }
91

    
92
    tmpD[0] = tmpD[1];
93
    tmpD[mNumBands] = tmpD[mNumBands-1];
94
    tmpX[0] = 0.0f;
95
    tmpX[mNumBands] = 1.0f;
96

    
97
    int prev = 0;
98
    int next = 0;
99

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

    
104
      if( x>=tmpX[next] )
105
        {
106
        prev = next;
107
        while( next<=mNumBands && x>=tmpX[next] ) next++;
108
        }
109

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

    
121
    mCurveCache[NUM_CACHE-1] = tmpD[mNumBands];
122
    }
123

    
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125

    
126
  private float derivative(float x)
127
    {
128
    if( x>=1.0f )
129
      {
130
      return 0.0f;
131
      }
132
    else
133
      {
134
      float tmp = x*(NUM_CACHE-1);
135
      int i1 = (int)tmp;
136
      int i2 = i1+1;
137

    
138
      // why 0.5? Arbitrarily; this way the cubit faces of Twisty Puzzles
139
      // [the main and only user of this class] look better.
140
      return 0.5f*((tmp-i1)*(mCurveCache[i2]-mCurveCache[i1]) + mCurveCache[i1]);
141
      }
142
    }
143

    
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145

    
146
  private void figureOutNormalVector2D(float qx)
147
    {
148
    mVecX = mNormL[0] + qx*(mNormR[0]-mNormL[0]);
149
    mVecY = mNormL[1] + qx*(mNormR[1]-mNormL[1]);
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

    
154
  private float figureOutDerivative(float qy)
155
    {
156
    switch(mMode)
157
      {
158
      case MODE_NORMAL  : return derivative(1-qy);
159
      case MODE_INVERTED: return -derivative(qy);
160
      default           : return 0;
161
      }
162
    }
163

    
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165

    
166
  private float computeElevation(int band)
167
    {
168
    switch(mMode)
169
      {
170
      case MODE_NORMAL  : return mBands[2*band+1];
171
      case MODE_INVERTED: return mBands[2*(mNumBands-band)+1];
172
      default           : return mBands[2*mNumBands+1];
173
      }
174
    }
175

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

    
178
  private int addStripVertex(int vertex, float qx, float qy, int band, float[] attribs1, float[] attribs2)
179
    {
180
    remainingVert--;
181

    
182
    // android.util.Log.e("D", "new v: qx="+qx+" band="+band);
183

    
184
    float bx = mLeftX + qx*(mRightX-mLeftX);
185
    float by = mLeftY + qx*(mRightY-mLeftY);
186

    
187
    float q = 1-qy;
188
    float x = bx + q*(mTopX-bx);
189
    float y = by + q*(mTopY-by);
190
    float z = computeElevation(band);
191

    
192
    figureOutNormalVector2D(band<mNumBands ? qx : 0.5f);
193
    float d = figureOutDerivative(qy);
194

    
195
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB  ] = x;
196
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+1] = y;
197
    attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+2] = z;
198

    
199
    float vx = d*mVecX;
200
    float vy = d*mVecY;
201
    float vz = mVecX*mVecX + mVecY*mVecY;
202
    float len = (float)Math.sqrt(vx*vx + vy*vy + vz*vz);
203

    
204
    int index = VERT1_ATTRIBS*vertex + NOR_ATTRIB;
205
    attribs1[index  ] = vx/len;
206
    attribs1[index+1] = vy/len;
207
    attribs1[index+2] = vz/len;
208

    
209
    attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB  ] = x+0.5f;
210
    attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB+1] = y+0.5f;
211

    
212
    return vertex+1;
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

    
217
  private int createBand(int vertex, int band, float[] attribs1, float[] attribs2)
218
    {
219
    boolean fromLeft = (band%2 == 0);
220
    int extra = ((band<extraBands && mMode==MODE_NORMAL) ? extraVertices : 0);
221
    int n = mNumBands-band-1;
222

    
223
    float b = 1.0f/(mNumBands-band);
224
    float dxb = fromLeft ? b : -b;
225
    float sdx = dxb/(extra+1);
226

    
227
    float qx = fromLeft ? 0.0f : 1.0f;
228

    
229
    int bb = mMode==MODE_NORMAL ? band   : mNumBands-band;
230
    int bt = mMode==MODE_NORMAL ? band+1 : mNumBands-(band+1);
231

    
232
    float qyb = mBands[2*bb];
233
    float qyt = mBands[2*bt];
234

    
235
    if( mMode!=MODE_NORMAL )
236
      {
237
      qyb = 1-qyb;
238
      qyt = 1-qyt;
239
      }
240

    
241
    vertex = addStripVertex(vertex, qx, qyb, band, attribs1,attribs2);
242

    
243
    for(int v=0; v<extra; v++)
244
      {
245
      vertex = addStripVertex(vertex, qx          , qyt, band+1, attribs1,attribs2);
246
      vertex = addStripVertex(vertex, qx+(v+1)*sdx, qyb, band  , attribs1,attribs2);
247
      }
248

    
249
    if( n>0 )
250
      {
251
      float t = 1.0f/n;
252
      float dxt = fromLeft ? t : -t;
253

    
254
      for(int v=0; v<n; v++)
255
        {
256
        vertex=addStripVertex(vertex, qx+ v   *dxt, qyt, band+1, attribs1, attribs2);
257
        vertex=addStripVertex(vertex, qx+(v+1)*dxb, qyb, band  , attribs1, attribs2);
258
        }
259
      }
260

    
261
    qx = 1-qx;
262

    
263
    for(int v=0; v<=extra; v++)
264
      {
265
      vertex = addStripVertex(vertex, qx              , qyt, band+1, attribs1,attribs2);
266
      vertex = addStripVertex(vertex, qx-dxb+(v+1)*sdx, qyb, band  , attribs1,attribs2);
267
      }
268

    
269
    return vertex;
270
    }
271

    
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273

    
274
  private void buildGrid(float[] attribs1, float[] attribs2)
275
    {
276
    if( mMode==MODE_FLAT )
277
      {
278
      addStripVertex(0, 0, 1, 0, attribs1,attribs2);
279
      addStripVertex(1, 0, 0, 0, attribs1,attribs2);
280
      addStripVertex(2, 1, 1, 0, attribs1,attribs2);
281
      }
282
    else
283
      {
284
      int vertex=0;
285
      for(int b=0; b<mNumBands; b++) vertex=createBand(vertex, b, attribs1, attribs2);
286
      }
287
    }
288

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290
// PUBLIC API
291
///////////////////////////////////////////////////////////////////////////////////////////////////
292
/**
293
 * Create a triangular mesh split into 'bands' - i.e. strips of triangles - which are parallel to
294
 * a given edge.
295
 *
296
 * @param vL         A pair of floats (x,y) which defines the 'left' vertex of the triangle.
297
 * @param vR         A pair of floats (x,y) which defines the 'right' vertex of the triangle.
298
 * @param vT         A pair of floats (x,y) which defines the 'top' vertex of the triangle.
299
 * @param bands      2K floats; K pairs of two floats each describing a single band.
300
 *                   From (1.0,Z[0]) (the 'left-right' edge, its Z elevation) to (0.0,Z[K])
301
 *                   (the 'top' vertex, its elevation). The polygon is split into such strips.
302
 *                   Must be band[2*i] > band[2*(i+1)] !
303
 *                   The way the bands get interpreted also depends on the 'mode' param.
304
 * @param normL      A pair of floats which define a 2D vector - which is the normal vector of each
305
 *                   mesh vertex which lies on the 'left-top' edge casted to the XY plane.
306
 * @param normR      Same as above but about the vertices which belong to the 'right-top' triangle
307
 *                   edge. This and the previous param define the vector field of normals, as seen
308
 *                   from above, of the whole mesh.
309
 * @param mode       MODE_UP, MODE_DOWN or MODE_FLAT.
310
 *                   This defines how we interpret the bands.
311
 *                   If UP, we interpret them the same as in MeshPolygon - i.e. the first band is
312
 *                   about the 'left-right' edge, then progressively towards the 'top'.
313
 *                   If DOWN, we turn the interpretation of the bands upside-down: it is the last
314
 *                   band which defines the strip aong the 'left-right' edge.
315
 *                   If FLAT, everything is flat anyway, so we disregard the bands and return a mesh
316
 *                   with 3 vertices.
317
 * @param exBands    This and the next parameter describe how to make the mesh denser at the
318
 *                   'left' and 'right' vertices. If e.g. exBands=3 and exVertices=2, then 3 triangles
319
 *                   of the outermost band (and 2 triangles of the next band, and 1 triangle of the
320
 *                   third band) get denser - the 3 triangles become 3+2 = 5.
321
 * @param exVertices See above.
322
 */
323
  public MeshBandedTriangle(float[] vL, float[] vR, float[] vT, float[] bands, float[] normL, float[] normR, int mode, int exBands, int exVertices)
324
    {
325
    super();
326

    
327
    mLeftX   = vL[0];
328
    mLeftY   = vL[1];
329
    mRightX  = vR[0];
330
    mRightY  = vR[1];
331
    mTopX    = vT[0];
332
    mTopY    = vT[1];
333

    
334
    mMode = mode;
335
    mNormL= normL;
336
    mNormR= normR;
337

    
338
    mBands        = bands;
339
    mNumBands     = mBands.length/2 -1;
340
    extraBands    = exBands;
341
    extraVertices = exVertices;
342

    
343
    computeNumberOfVertices();
344
    computeCache();
345

    
346
    float[] attribs1= new float[VERT1_ATTRIBS*numVertices];
347
    float[] attribs2= new float[VERT2_ATTRIBS*numVertices];
348

    
349
    buildGrid(attribs1,attribs2);
350

    
351
    if( remainingVert!=0 )
352
      DistortedLibrary.logMessage("MeshBandedTriangle: remainingVert " +remainingVert );
353

    
354
    setAttribs(attribs1,attribs2);
355
    }
356

    
357
///////////////////////////////////////////////////////////////////////////////////////////////////
358
/**
359
 * Copy constructor.
360
 */
361
  public MeshBandedTriangle(MeshBandedTriangle mesh, boolean deep)
362
    {
363
    super(mesh,deep);
364
    }
365

    
366
///////////////////////////////////////////////////////////////////////////////////////////////////
367
/**
368
 * Copy the Mesh.
369
 *
370
 * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
371
 *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
372
 *             coordinates and effect associations, is always deep copied)
373
 */
374
  public MeshBandedTriangle copy(boolean deep)
375
    {
376
    return new MeshBandedTriangle(this,deep);
377
    }
378
 }
(2-2/12)