Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshBase.java @ 23b733db

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
package org.distorted.library.mesh;
21

    
22
import android.opengl.GLES31;
23
import android.opengl.Matrix;
24

    
25
import org.distorted.library.effect.MatrixEffect;
26
import org.distorted.library.main.DistortedLibrary;
27
import org.distorted.library.main.InternalBuffer;
28
import org.distorted.library.program.DistortedProgram;
29

    
30
import java.nio.ByteBuffer;
31
import java.nio.ByteOrder;
32
import java.nio.FloatBuffer;
33
import java.util.ArrayList;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36
/**
37
 * Abstract class which represents a Mesh, ie an array of vertices (rendered as a TRIANGLE_STRIP).
38
 * <p>
39
 * If you want to render to a particular shape, extend from here, construct a float array
40
 * containing per-vertex attributes, and call back setAttribs().
41
 */
42
public abstract class MeshBase
43
   {
44
   // sizes of attributes of an individual vertex.
45
   private static final int POS_DATA_SIZE= 3; // vertex coordinates: x,y,z
46
   private static final int NOR_DATA_SIZE= 3; // normal vector: x,y,z
47
   private static final int INF_DATA_SIZE= 3; // 'inflate' vector: x,y,z
48
   private static final int TEX_DATA_SIZE= 2; // texture coordinates: s,t
49

    
50
   static final int POS_ATTRIB   = 0;
51
   static final int NOR_ATTRIB   = POS_DATA_SIZE;
52
   static final int INF_ATTRIB   = POS_DATA_SIZE + NOR_DATA_SIZE;
53
   static final int TEX_ATTRIB   = POS_DATA_SIZE + NOR_DATA_SIZE + INF_DATA_SIZE;
54
   static final int VERT_ATTRIBS = POS_DATA_SIZE + NOR_DATA_SIZE + INF_DATA_SIZE + TEX_DATA_SIZE;  // number of attributes of a 'normal' vertex
55
   static final int TRAN_ATTRIBS = POS_DATA_SIZE + POS_DATA_SIZE;                                  // number of attributes of a transform feedback vertex
56

    
57
   private static final int BYTES_PER_FLOAT = 4;
58

    
59
   private static final int OFFSET_POS = POS_ATTRIB*BYTES_PER_FLOAT;
60
   private static final int OFFSET_NOR = NOR_ATTRIB*BYTES_PER_FLOAT;
61
   private static final int OFFSET_INF = INF_ATTRIB*BYTES_PER_FLOAT;
62
   private static final int OFFSET_TEX = TEX_ATTRIB*BYTES_PER_FLOAT;
63
   private static final int TRAN_SIZE  = TRAN_ATTRIBS*BYTES_PER_FLOAT;
64
   private static final int VERT_SIZE  = VERT_ATTRIBS*BYTES_PER_FLOAT;
65

    
66
   private boolean mShowNormals;      // when rendering this mesh, draw normal vectors?
67
   private InternalBuffer mVBO, mTFO; // main vertex buffer and transform feedback buffer
68
   private int mNumVertices;
69
   private float[] mVertAttribs;      // packed: PosX,PosY,PosZ, NorX,NorY,NorZ, InfX,InfY,InfZ, TexS,TexT
70
   private float mInflate;
71
   private float mBoundingX, mBoundingY, mBoundingZ;
72
   private float mStretchX, mStretchY, mStretchZ;
73

    
74
   private class Component
75
     {
76
     private int mEndIndex;
77
     private float[] mTextureMap;
78

    
79
     Component()
80
       {
81
       mTextureMap = new float[8];
82

    
83
       mTextureMap[ 0] = 0.0f;  // LD_X
84
       mTextureMap[ 1] = 0.0f;  // LD_Y
85
       mTextureMap[ 2] = 0.0f;  // LU_X
86
       mTextureMap[ 3] = 1.0f;  // LU_Y
87
       mTextureMap[ 4] = 1.0f;  // RU_X
88
       mTextureMap[ 5] = 1.0f;  // RU_Y
89
       mTextureMap[ 6] = 1.0f;  // RD_X
90
       mTextureMap[ 7] = 0.0f;  // RD_Y
91
       }
92
     Component(Component original)
93
       {
94
       mEndIndex = original.mEndIndex;
95
       mTextureMap = new float[8];
96
       System.arraycopy(original.mTextureMap,0,mTextureMap,0,8);
97
       }
98
     }
99

    
100
   private ArrayList<Component> mComponent;
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
   MeshBase(float bx, float by, float bz)
105
     {
106
     mBoundingX = bx/2;
107
     mBoundingY = by/2;
108
     mBoundingZ = bz/2;
109

    
110
     mStretchX = 1.0f;
111
     mStretchY = 1.0f;
112
     mStretchZ = 1.0f;
113

    
114
     mShowNormals = false;
115
     mInflate     = 0.0f;
116
     mComponent = new ArrayList<>();
117
     mComponent.add(new Component());
118

    
119
     mVBO = new InternalBuffer(GLES31.GL_ARRAY_BUFFER             , GLES31.GL_STATIC_READ);
120
     mTFO = new InternalBuffer(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, GLES31.GL_STATIC_READ);
121
     }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
// copy constructor
125

    
126
   MeshBase(MeshBase original)
127
     {
128
     mBoundingX = original.mBoundingX;
129
     mBoundingY = original.mBoundingY;
130
     mBoundingZ = original.mBoundingZ;
131

    
132
     mStretchX = original.mStretchX;
133
     mStretchY = original.mStretchY;
134
     mStretchZ = original.mStretchZ;
135

    
136
     mShowNormals = original.mShowNormals;
137
     mInflate     = original.mInflate;
138

    
139
     int size = original.mComponent.size();
140
     mComponent = new ArrayList<>();
141
     for(int i=0; i<size; i++)
142
       {
143
       Component comp = new Component(original.mComponent.get(i));
144
       mComponent.add(comp);
145
       }
146

    
147
     mVBO = new InternalBuffer(GLES31.GL_ARRAY_BUFFER             , GLES31.GL_STATIC_READ);
148
     mTFO = new InternalBuffer(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, GLES31.GL_STATIC_READ);
149

    
150
     System.arraycopy(original.mVertAttribs,0,mVertAttribs,0,original.mNumVertices*VERT_ATTRIBS);
151
     setAttribs(mVertAttribs);
152
     }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155
// when a derived class is done computing its mesh, it has to call this method.
156

    
157
   void setAttribs(float[] vertexAttribs)
158
     {
159
     mNumVertices = vertexAttribs.length/VERT_ATTRIBS;
160
     mVertAttribs = vertexAttribs;
161

    
162
     mComponent.get(0).mEndIndex = mNumVertices;
163

    
164
     FloatBuffer attribs = ByteBuffer.allocateDirect(mNumVertices*VERT_SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
165
     attribs.put(vertexAttribs).position(0);
166

    
167
     mVBO.setData(mNumVertices*VERT_SIZE, attribs);
168
     mTFO.setData(mNumVertices*TRAN_SIZE, null   );
169
     }
170

    
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172
/**
173
 * Not part of public API, do not document (public only because has to be used from the main package)
174
 *
175
 * @y.exclude
176
 */
177
   public int getTFO()
178
     {
179
     return mTFO.mIndex[0];
180
     }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183
/**
184
 * Not part of public API, do not document (public only because has to be used from the main package)
185
 *
186
 * @y.exclude
187
 */
188
   public int getNumVertices()
189
     {
190
     return mNumVertices;
191
     }
192

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194
/**
195
 * Each mesh has its 'bounding box' - return half of its X-length.
196
 * <p>
197
 * In case of all 'simple' Meshes, the bounding box is always 1x1x1 (Sphere, Cubes) or 1x1x0
198
 * (Rectangles, Triangles, Quad - i.e. all 'flat' Meshes). But this can be something else in case of
199
 * MeshComponent.
200
 */
201
   public float getBoundingX()
202
    {
203
    return mBoundingX*mStretchX;
204
    }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207
/**
208
 * Each mesh has its 'bounding box' - return half of its Y-length.
209
 */
210
   public float getBoundingY()
211
    {
212
    return mBoundingY*mStretchY;
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216
/**
217
 * Each mesh has its 'bounding box' - return half of its Z-length.
218
 */
219
   public float getBoundingZ()
220
    {
221
    return mBoundingZ*mStretchZ;
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225
/**
226
 * Sometimes we want to display a Mesh on a rectangular screen. Then we need to stretch it by
227
 * different factors in x and y (or z) directions. If we also wanted do display some vertex effects
228
 * done on this mesh, let's say a bulge done by a Distort effect, and wanted the bulge to be round,
229
 * (i.e the same in x and y directions) then doing so without this method would be impossible.
230
 *
231
 * This sets 'stretch' factors in each 3 dimensions. All vertices of this Mesh will be premultiplied
232
 * by those factors in the very first line of the Vertex Shader, before any Effects are done on it.
233
 * Using this we can thus pre-stretch the mesh to aspect ratio equal to the surface we eventually
234
 * want to display the Mesh on, and this way we can achieve a round Distort bulge!
235
 *
236
 * This could also be used to pre-stretch a Rectangles Mesh to a size equal (in pixels) to the bitmap
237
 * this mesh is textured with - and this lets us work with all Effects in natural, pixel units.
238
 *
239
 * @param sx stretch factor in x.
240
 * @param sy stretch factor in y.
241
 * @param sz stretch factor in z.
242
 */
243
   public void setStretch(float sx, float sy, float sz)
244
     {
245
     mStretchX = sx;
246
     mStretchY = sy;
247
     mStretchZ = sz;
248
     }
249

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251
/**
252
 * Returns the x-factor set by setStretch().
253
 */
254
   public float getStretchX()
255
     {
256
     return mStretchX;
257
     }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260
/**
261
 * Returns the y-factor set by setStretch().
262
 */
263
   public float getStretchY()
264
     {
265
     return mStretchY;
266
     }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269
/**
270
 * Returns the z-factor set by setStretch().
271
 */
272
   public float getStretchZ()
273
     {
274
     return mStretchZ;
275
     }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278
/**
279
 * Not part of public API, do not document (public only because has to be used from the main package)
280
 *
281
 * @y.exclude
282
 */
283
   public void bindVertexAttribs(DistortedProgram program)
284
     {
285
     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, mVBO.mIndex[0] );
286
     GLES31.glVertexAttribPointer(program.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_POS);
287
     GLES31.glVertexAttribPointer(program.mAttribute[1], NOR_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_NOR);
288
     GLES31.glVertexAttribPointer(program.mAttribute[2], INF_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_INF);
289
     GLES31.glVertexAttribPointer(program.mAttribute[3], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_TEX);
290
     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);
291
     }
292

    
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294
/**
295
 * Not part of public API, do not document (public only because has to be used from the main package)
296
 *
297
 * @y.exclude
298
 */
299
   public void bindTransformAttribs(DistortedProgram program)
300
     {
301
     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, mTFO.mIndex[0] );
302
     GLES31.glVertexAttribPointer(program.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, 0, 0);
303
     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);
304
     }
305

    
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307
/**
308
 * Not part of public API, do not document (public only because has to be used from the main package)
309
 *
310
 * @y.exclude
311
 */
312
   public void setInflate(float inflate)
313
     {
314
     mInflate = inflate;
315
     }
316

    
317
///////////////////////////////////////////////////////////////////////////////////////////////////
318
/**
319
 * Not part of public API, do not document (public only because has to be used from the main package)
320
 *
321
 * @y.exclude
322
 */
323
   public float getInflate()
324
     {
325
     return mInflate;
326
     }
327

    
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329
// PUBLIC API
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331
/**
332
 * When rendering this Mesh, do we want to render the Normal vectors as well?
333
 * <p>
334
 * Will work only on OpenGL ES >= 3.0 devices.
335
 *
336
 * @param show Controls if we render the Normal vectors or not.
337
 */
338
   public void setShowNormals(boolean show)
339
     {
340
     mShowNormals = (DistortedLibrary.GLSL >= 300 && show);
341
     }
342

    
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344
/**
345
 * When rendering this mesh, should we also draw the normal vectors?
346
 *
347
 * @return <i>true</i> if we do render normal vectors
348
 */
349
   public boolean getShowNormals()
350
     {
351
     return mShowNormals;
352
     }
353

    
354
///////////////////////////////////////////////////////////////////////////////////////////////////
355
/**
356
 * Release all internal resources.
357
 */
358
   public void markForDeletion()
359
     {
360
     mVertAttribs = null;
361

    
362
     mVBO.markForDeletion();
363
     mTFO.markForDeletion();
364
     }
365

    
366
///////////////////////////////////////////////////////////////////////////////////////////////////
367
/**
368
 * Apply all Effects to the vertex mesh. Overwrite the mesh in place.
369
 * <p>
370
 * This is a static, permanent modification of the vertices contained in this Mesh. If the effects
371
 * contain any Dynamics, they will be evaluated at 0.
372
 *
373
 * Please note that calling this once with the complete list of Effects will be much faster than
374
 * calling it repeatedly with one Effect at a time, as we have to reallocate the array of vertices
375
 * each time.
376
 */
377
   public void apply(MatrixEffect[] effects)
378
     {
379
     float[][] matrix = new float[effects.length][16];
380
     float[] tmp;
381
     float[] array = new float[4];
382
     float x,y,z;
383
     int numEffects = 0;
384

    
385
     for(MatrixEffect eff: effects)
386
       {
387
       if( eff!=null )
388
         {
389
         Matrix.setIdentityM(matrix[numEffects],0);
390
         eff.compute(array,0,0,0);
391
         eff.apply(matrix[numEffects], array, 0);
392
         numEffects++;
393
         }
394
       }
395

    
396
     for(int index=0; index<mNumVertices*VERT_ATTRIBS; index+=VERT_ATTRIBS )
397
       {
398
       for(int mat=0; mat<numEffects; mat++)
399
         {
400
         tmp = matrix[mat];
401

    
402
         x = mVertAttribs[index+POS_ATTRIB  ];
403
         y = mVertAttribs[index+POS_ATTRIB+1];
404
         z = mVertAttribs[index+POS_ATTRIB+2];
405

    
406
         mVertAttribs[index+POS_ATTRIB  ] = tmp[0]*x + tmp[4]*y + tmp[ 8]*z + tmp[12];
407
         mVertAttribs[index+POS_ATTRIB+1] = tmp[1]*x + tmp[5]*y + tmp[ 9]*z + tmp[13];
408
         mVertAttribs[index+POS_ATTRIB+2] = tmp[2]*x + tmp[6]*y + tmp[10]*z + tmp[14];
409

    
410
         x = mVertAttribs[index+NOR_ATTRIB  ];
411
         y = mVertAttribs[index+NOR_ATTRIB+1];
412
         z = mVertAttribs[index+NOR_ATTRIB+2];
413

    
414
         mVertAttribs[index+NOR_ATTRIB  ] = tmp[0]*x + tmp[4]*y + tmp[ 8]*z;
415
         mVertAttribs[index+NOR_ATTRIB+1] = tmp[1]*x + tmp[5]*y + tmp[ 9]*z;
416
         mVertAttribs[index+NOR_ATTRIB+2] = tmp[2]*x + tmp[6]*y + tmp[10]*z;
417

    
418
         x = mVertAttribs[index+INF_ATTRIB  ];
419
         y = mVertAttribs[index+INF_ATTRIB+1];
420
         z = mVertAttribs[index+INF_ATTRIB+2];
421

    
422
         mVertAttribs[index+INF_ATTRIB  ] = tmp[0]*x + tmp[4]*y + tmp[ 8]*z;
423
         mVertAttribs[index+INF_ATTRIB+1] = tmp[1]*x + tmp[5]*y + tmp[ 9]*z;
424
         mVertAttribs[index+INF_ATTRIB+2] = tmp[2]*x + tmp[6]*y + tmp[10]*z;
425
         }
426
       }
427

    
428
     FloatBuffer attribs = ByteBuffer.allocateDirect(mNumVertices*VERT_SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
429
     attribs.put(mVertAttribs).position(0);
430

    
431
     mVBO.setData(mNumVertices*VERT_SIZE, attribs);
432
     mTFO.setData(mNumVertices*TRAN_SIZE, null   );
433
     }
434

    
435
///////////////////////////////////////////////////////////////////////////////////////////////////
436
/**
437
 * Join a list of Meshes into this one.
438
 * <p>
439
 * Please note that calling this once with the complete list of Meshes will be much faster than
440
 * calling it repeatedly with one Mesh at a time, as we have to reallocate the array of vertices
441
 * each time.
442
 */
443
   public void join(MeshBase[] meshes)
444
     {
445
     MeshBase mesh;
446
     Component comp;
447
     int com, num, len = meshes.length;
448
     int origVertices = mNumVertices;
449

    
450
     // compute new numVertices; take care of Components
451
     mNumVertices+= ( mNumVertices%2==1 ? 2:1 );
452
     com = mComponent.size();
453
     mComponent.get(com-1).mEndIndex = mNumVertices;
454

    
455
     for(int i=0; i<len; i++)
456
       {
457
       mesh = meshes[i];
458
       com = mesh.mComponent.size();
459

    
460
       for(int j=0; j<com; j++)
461
         {
462
         comp = new Component(mesh.mComponent.get(j));
463
         comp.mEndIndex += mNumVertices;
464
         mComponent.add(comp);
465
         }
466

    
467
       num = mesh.mNumVertices;
468
       mNumVertices+= (i<len-1 ? ( num%2==1 ? num+2 : num+1 ) : num);
469
       }
470

    
471
     // allocate new attrib array
472
     float[] newAttribs = new float[VERT_ATTRIBS*mNumVertices];
473
     num = origVertices;
474

    
475
     System.arraycopy(mVertAttribs,                             0, newAttribs,                         0, VERT_ATTRIBS*num);
476
     System.arraycopy(mVertAttribs, VERT_ATTRIBS*(origVertices-1), newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS    );
477
     origVertices++;
478

    
479
     if( num%2==1 )
480
       {
481
       System.arraycopy(mVertAttribs, VERT_ATTRIBS*(origVertices-1), newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS);
482
       origVertices++;
483
       }
484

    
485
     for(int i=0; i<len; i++)
486
       {
487
       mesh = meshes[i];
488
       num = mesh.mNumVertices;
489

    
490
       System.arraycopy(mesh.mVertAttribs, 0, newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS    );
491
       origVertices++;
492
       System.arraycopy(mesh.mVertAttribs, 0, newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS*num);
493
       origVertices+=num;
494

    
495
       if( i<len-1 )
496
         {
497
         System.arraycopy(mesh.mVertAttribs, VERT_ATTRIBS*(num-1), newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS);
498
         origVertices++;
499

    
500
         if( num%2==1 )
501
           {
502
           System.arraycopy(mesh.mVertAttribs, VERT_ATTRIBS*(num-1), newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS);
503
           origVertices++;
504
           }
505
         }
506
       }
507

    
508
     if( origVertices!=mNumVertices )
509
       {
510
       android.util.Log.e("mesh", "join: origVertices: "+origVertices+" numVertices: "+mNumVertices);
511
       }
512

    
513
     mVertAttribs = newAttribs;
514

    
515
     FloatBuffer attribs = ByteBuffer.allocateDirect(mNumVertices*VERT_SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
516
     attribs.put(mVertAttribs).position(0);
517

    
518
     mVBO.setData(mNumVertices*VERT_SIZE, attribs);
519
     mTFO.setData(mNumVertices*TRAN_SIZE, null   );
520
     }
521

    
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523
/**
524
 * Sets texture maps for all components of this mesh.
525
 * <p>
526
 * Please note that calling this once with the complete list of Maps will be much faster than
527
 * calling it repeatedly with one Maps at a time, as we have to reallocate the array of vertices
528
 * each time.
529
 */
530
   public void setTextureMap(float[][] maps)
531
     {
532
     int components = mComponent.size();
533

    
534
     for(int comp=0; comp<components; comp++)
535
       {
536

    
537
       }
538
     }
539
   }
540

    
541

    
542

    
(1-1/6)