Mesh.java revision f5c876e82d7cc647ba94d29eb914e64b7977c303
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.renderscript; 18 19import java.util.Vector; 20 21import android.util.Config; 22import android.util.Log; 23 24/** 25 * Mesh class is a container for geometric data displayed in 26 * renderscript. 27 * 28 * Internally, mesh is a collection of allocations that 29 * represent vertex data (positions, normals, texture 30 * coordinates) and index data such as triangles and lines. 31 * 32 * Vertex data could either be interlieved within one 33 * allocation, provided separately as multiple allocation 34 * objects or done as a combination of the above. When a 35 * vertex channel name matches an input in the vertex program, 36 * renderscript will automatically connect the two together. 37 * 38 * Parts of the mesh could be rendered with either explicit 39 * index sets or primitive types. 40 * 41 **/ 42public class Mesh extends BaseObj { 43 44 /** 45 * Describes the way mesh vertex data is interpreted when rendering 46 * 47 **/ 48 public enum Primitive { 49 POINT (0), 50 LINE (1), 51 LINE_STRIP (2), 52 TRIANGLE (3), 53 TRIANGLE_STRIP (4), 54 TRIANGLE_FAN (5); 55 56 int mID; 57 Primitive(int id) { 58 mID = id; 59 } 60 } 61 62 Allocation[] mVertexBuffers; 63 Allocation[] mIndexBuffers; 64 Primitive[] mPrimitives; 65 66 Mesh(int id, RenderScript rs) { 67 super(id, rs); 68 } 69 70 /** 71 * @return number of allocations containing vertex data 72 * 73 **/ 74 public int getVertexAllocationCount() { 75 if(mVertexBuffers == null) { 76 return 0; 77 } 78 return mVertexBuffers.length; 79 } 80 /** 81 * @param slot index in the list of allocations to return 82 * @return vertex data allocation at the given index 83 * 84 **/ 85 public Allocation getVertexAllocation(int slot) { 86 return mVertexBuffers[slot]; 87 } 88 89 /** 90 * @return number of primitives or index sets in the mesh 91 * 92 **/ 93 public int getPrimitiveCount() { 94 if(mIndexBuffers == null) { 95 return 0; 96 } 97 return mIndexBuffers.length; 98 } 99 100 /** 101 * @param slot locaton within the list of index set allocation 102 * @return allocation containing primtive index data or null if 103 * the index data is not specified explicitly 104 * 105 **/ 106 public Allocation getIndexSetAllocation(int slot) { 107 return mIndexBuffers[slot]; 108 } 109 /** 110 * @param slot locaiton within the list of index set primitives 111 * @return index set primitive type 112 * 113 **/ 114 public Primitive getPrimitive(int slot) { 115 return mPrimitives[slot]; 116 } 117 118 @Override 119 void updateFromNative() { 120 super.updateFromNative(); 121 int vtxCount = mRS.nMeshGetVertexBufferCount(getID()); 122 int idxCount = mRS.nMeshGetIndexCount(getID()); 123 124 int[] vtxIDs = new int[vtxCount]; 125 int[] idxIDs = new int[idxCount]; 126 int[] primitives = new int[idxCount]; 127 128 mRS.nMeshGetVertices(getID(), vtxIDs, vtxCount); 129 mRS.nMeshGetIndices(getID(), idxIDs, primitives, idxCount); 130 131 mVertexBuffers = new Allocation[vtxCount]; 132 mIndexBuffers = new Allocation[idxCount]; 133 mPrimitives = new Primitive[idxCount]; 134 135 for(int i = 0; i < vtxCount; i ++) { 136 if(vtxIDs[i] != 0) { 137 mVertexBuffers[i] = new Allocation(vtxIDs[i], mRS, null, Allocation.USAGE_SCRIPT); 138 mVertexBuffers[i].updateFromNative(); 139 } 140 } 141 142 for(int i = 0; i < idxCount; i ++) { 143 if(idxIDs[i] != 0) { 144 mIndexBuffers[i] = new Allocation(idxIDs[i], mRS, null, Allocation.USAGE_SCRIPT); 145 mIndexBuffers[i].updateFromNative(); 146 } 147 mPrimitives[i] = Primitive.values()[primitives[i]]; 148 } 149 } 150 151 /** 152 * Mesh builder object. It starts empty and requires the user to 153 * add the types necessary to create vertex and index 154 * allocations 155 * 156 */ 157 public static class Builder { 158 RenderScript mRS; 159 int mUsage; 160 161 class Entry { 162 Type t; 163 Element e; 164 int size; 165 Primitive prim; 166 int usage; 167 } 168 169 int mVertexTypeCount; 170 Entry[] mVertexTypes; 171 Vector mIndexTypes; 172 173 /** 174 * Creates builder object 175 * @param rs Context to which the mesh will belong. 176 * @param usage specifies how the mesh allocations are to be 177 * handled, whether they need to be uploaded to a 178 * buffer on the gpu, maintain a cpu copy, etc 179 */ 180 public Builder(RenderScript rs, int usage) { 181 mRS = rs; 182 mUsage = usage; 183 mVertexTypeCount = 0; 184 mVertexTypes = new Entry[16]; 185 mIndexTypes = new Vector(); 186 } 187 188 /** 189 * @return internal index of the last vertex buffer type added to 190 * builder 191 **/ 192 public int getCurrentVertexTypeIndex() { 193 return mVertexTypeCount - 1; 194 } 195 196 /** 197 * @return internal index of the last index set added to the 198 * builder 199 **/ 200 public int getCurrentIndexSetIndex() { 201 return mIndexTypes.size() - 1; 202 } 203 204 /** 205 * Adds a vertex data type to the builder object 206 * 207 * @param t type of the vertex data allocation to be created 208 * 209 * @return this 210 **/ 211 public Builder addVertexType(Type t) throws IllegalStateException { 212 if (mVertexTypeCount >= mVertexTypes.length) { 213 throw new IllegalStateException("Max vertex types exceeded."); 214 } 215 216 mVertexTypes[mVertexTypeCount] = new Entry(); 217 mVertexTypes[mVertexTypeCount].t = t; 218 mVertexTypes[mVertexTypeCount].e = null; 219 mVertexTypeCount++; 220 return this; 221 } 222 223 /** 224 * Adds a vertex data type to the builder object 225 * 226 * @param e element describing the vertex data layout 227 * @param size number of elements in the buffer 228 * 229 * @return this 230 **/ 231 public Builder addVertexType(Element e, int size) throws IllegalStateException { 232 if (mVertexTypeCount >= mVertexTypes.length) { 233 throw new IllegalStateException("Max vertex types exceeded."); 234 } 235 236 mVertexTypes[mVertexTypeCount] = new Entry(); 237 mVertexTypes[mVertexTypeCount].t = null; 238 mVertexTypes[mVertexTypeCount].e = e; 239 mVertexTypes[mVertexTypeCount].size = size; 240 mVertexTypeCount++; 241 return this; 242 } 243 244 /** 245 * Adds an index set data type to the builder object 246 * 247 * @param t type of the index set data, could be null 248 * @param p primitive type 249 * 250 * @return this 251 **/ 252 public Builder addIndexSetType(Type t, Primitive p) { 253 Entry indexType = new Entry(); 254 indexType.t = t; 255 indexType.e = null; 256 indexType.size = 0; 257 indexType.prim = p; 258 mIndexTypes.addElement(indexType); 259 return this; 260 } 261 262 /** 263 * Adds an index set primitive type to the builder object 264 * 265 * @param p primitive type 266 * 267 * @return this 268 **/ 269 public Builder addIndexSetType(Primitive p) { 270 Entry indexType = new Entry(); 271 indexType.t = null; 272 indexType.e = null; 273 indexType.size = 0; 274 indexType.prim = p; 275 mIndexTypes.addElement(indexType); 276 return this; 277 } 278 279 /** 280 * Adds an index set data type to the builder object 281 * 282 * @param e element describing the index set data layout 283 * @param size number of elements in the buffer 284 * @param p primitive type 285 * 286 * @return this 287 **/ 288 public Builder addIndexSetType(Element e, int size, Primitive p) { 289 Entry indexType = new Entry(); 290 indexType.t = null; 291 indexType.e = e; 292 indexType.size = size; 293 indexType.prim = p; 294 mIndexTypes.addElement(indexType); 295 return this; 296 } 297 298 Type newType(Element e, int size) { 299 Type.Builder tb = new Type.Builder(mRS, e); 300 tb.setX(size); 301 return tb.create(); 302 } 303 304 static synchronized Mesh internalCreate(RenderScript rs, Builder b) { 305 306 int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size()); 307 Mesh newMesh = new Mesh(id, rs); 308 newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()]; 309 newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()]; 310 newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount]; 311 312 for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) { 313 Allocation alloc = null; 314 Entry entry = (Entry)b.mIndexTypes.elementAt(ct); 315 if (entry.t != null) { 316 alloc = Allocation.createTyped(rs, entry.t, b.mUsage); 317 } 318 else if(entry.e != null) { 319 alloc = Allocation.createSized(rs, entry.e, entry.size, b.mUsage); 320 } 321 int allocID = (alloc == null) ? 0 : alloc.getID(); 322 rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct); 323 newMesh.mIndexBuffers[ct] = alloc; 324 newMesh.mPrimitives[ct] = entry.prim; 325 } 326 327 for(int ct = 0; ct < b.mVertexTypeCount; ct ++) { 328 Allocation alloc = null; 329 Entry entry = b.mVertexTypes[ct]; 330 if (entry.t != null) { 331 alloc = Allocation.createTyped(rs, entry.t, b.mUsage); 332 } else if(entry.e != null) { 333 alloc = Allocation.createSized(rs, entry.e, entry.size, b.mUsage); 334 } 335 rs.nMeshBindVertex(id, alloc.getID(), ct); 336 newMesh.mVertexBuffers[ct] = alloc; 337 } 338 rs.nMeshInitVertexAttribs(id); 339 340 return newMesh; 341 } 342 343 /** 344 * Create a Mesh object from the current state of the builder 345 * 346 **/ 347 public Mesh create() { 348 mRS.validate(); 349 Mesh sm = internalCreate(mRS, this); 350 return sm; 351 } 352 } 353 354 /** 355 * Mesh builder object. It starts empty and requires the user to 356 * add all the vertex and index allocations that comprise the 357 * mesh 358 * 359 */ 360 public static class AllocationBuilder { 361 RenderScript mRS; 362 363 class Entry { 364 Allocation a; 365 Primitive prim; 366 } 367 368 int mVertexTypeCount; 369 Entry[] mVertexTypes; 370 371 Vector mIndexTypes; 372 373 public AllocationBuilder(RenderScript rs) { 374 mRS = rs; 375 mVertexTypeCount = 0; 376 mVertexTypes = new Entry[16]; 377 mIndexTypes = new Vector(); 378 } 379 380 /** 381 * @return internal index of the last vertex buffer type added to 382 * builder 383 **/ 384 public int getCurrentVertexTypeIndex() { 385 return mVertexTypeCount - 1; 386 } 387 388 /** 389 * @return internal index of the last index set added to the 390 * builder 391 **/ 392 public int getCurrentIndexSetIndex() { 393 return mIndexTypes.size() - 1; 394 } 395 396 /** 397 * Adds an allocation containing vertex buffer data to the 398 * builder 399 * 400 * @param a vertex data allocation 401 * 402 * @return this 403 **/ 404 public AllocationBuilder addVertexAllocation(Allocation a) throws IllegalStateException { 405 if (mVertexTypeCount >= mVertexTypes.length) { 406 throw new IllegalStateException("Max vertex types exceeded."); 407 } 408 409 mVertexTypes[mVertexTypeCount] = new Entry(); 410 mVertexTypes[mVertexTypeCount].a = a; 411 mVertexTypeCount++; 412 return this; 413 } 414 415 /** 416 * Adds an allocation containing index buffer data and index type 417 * to the builder 418 * 419 * @param a index set data allocation, could be null 420 * @param p index set primitive type 421 * 422 * @return this 423 **/ 424 public AllocationBuilder addIndexSetAllocation(Allocation a, Primitive p) { 425 Entry indexType = new Entry(); 426 indexType.a = a; 427 indexType.prim = p; 428 mIndexTypes.addElement(indexType); 429 return this; 430 } 431 432 /** 433 * Adds an index set type to the builder 434 * 435 * @param p index set primitive type 436 * 437 * @return this 438 **/ 439 public AllocationBuilder addIndexSetType(Primitive p) { 440 Entry indexType = new Entry(); 441 indexType.a = null; 442 indexType.prim = p; 443 mIndexTypes.addElement(indexType); 444 return this; 445 } 446 447 static synchronized Mesh internalCreate(RenderScript rs, AllocationBuilder b) { 448 449 int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size()); 450 Mesh newMesh = new Mesh(id, rs); 451 newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()]; 452 newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()]; 453 newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount]; 454 455 for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) { 456 Entry entry = (Entry)b.mIndexTypes.elementAt(ct); 457 int allocID = (entry.a == null) ? 0 : entry.a.getID(); 458 rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct); 459 newMesh.mIndexBuffers[ct] = entry.a; 460 newMesh.mPrimitives[ct] = entry.prim; 461 } 462 463 for(int ct = 0; ct < b.mVertexTypeCount; ct ++) { 464 Entry entry = b.mVertexTypes[ct]; 465 rs.nMeshBindVertex(id, entry.a.getID(), ct); 466 newMesh.mVertexBuffers[ct] = entry.a; 467 } 468 rs.nMeshInitVertexAttribs(id); 469 470 return newMesh; 471 } 472 473 /** 474 * Create a Mesh object from the current state of the builder 475 * 476 **/ 477 public Mesh create() { 478 mRS.validate(); 479 Mesh sm = internalCreate(mRS, this); 480 return sm; 481 } 482 } 483 484 /** 485 * Builder that allows creation of a mesh object point by point 486 * and triangle by triangle 487 * 488 **/ 489 public static class TriangleMeshBuilder { 490 float mVtxData[]; 491 int mVtxCount; 492 short mIndexData[]; 493 int mIndexCount; 494 RenderScript mRS; 495 Element mElement; 496 497 float mNX = 0; 498 float mNY = 0; 499 float mNZ = -1; 500 float mS0 = 0; 501 float mT0 = 0; 502 float mR = 1; 503 float mG = 1; 504 float mB = 1; 505 float mA = 1; 506 507 int mVtxSize; 508 int mFlags; 509 510 public static final int COLOR = 0x0001; 511 public static final int NORMAL = 0x0002; 512 public static final int TEXTURE_0 = 0x0100; 513 514 /** 515 * @param rs Context to which the mesh will belong. 516 * @param vtxSize specifies whether the vertex is a float2 or 517 * float3 518 * @param flags bitfield that is a combination of COLOR, NORMAL, 519 * and TEXTURE_0 that specifies what vertex data 520 * channels are present in the mesh 521 * 522 **/ 523 public TriangleMeshBuilder(RenderScript rs, int vtxSize, int flags) { 524 mRS = rs; 525 mVtxCount = 0; 526 mIndexCount = 0; 527 mVtxData = new float[128]; 528 mIndexData = new short[128]; 529 mVtxSize = vtxSize; 530 mFlags = flags; 531 532 if (vtxSize < 2 || vtxSize > 3) { 533 throw new IllegalArgumentException("Vertex size out of range."); 534 } 535 } 536 537 private void makeSpace(int count) { 538 if ((mVtxCount + count) >= mVtxData.length) { 539 float t[] = new float[mVtxData.length * 2]; 540 System.arraycopy(mVtxData, 0, t, 0, mVtxData.length); 541 mVtxData = t; 542 } 543 } 544 545 private void latch() { 546 if ((mFlags & COLOR) != 0) { 547 makeSpace(4); 548 mVtxData[mVtxCount++] = mR; 549 mVtxData[mVtxCount++] = mG; 550 mVtxData[mVtxCount++] = mB; 551 mVtxData[mVtxCount++] = mA; 552 } 553 if ((mFlags & TEXTURE_0) != 0) { 554 makeSpace(2); 555 mVtxData[mVtxCount++] = mS0; 556 mVtxData[mVtxCount++] = mT0; 557 } 558 if ((mFlags & NORMAL) != 0) { 559 makeSpace(3); 560 mVtxData[mVtxCount++] = mNX; 561 mVtxData[mVtxCount++] = mNY; 562 mVtxData[mVtxCount++] = mNZ; 563 } 564 } 565 566 /** 567 * Adds a float2 vertex to the mesh 568 * 569 * @param x position x 570 * @param y position y 571 * 572 * @return this 573 * 574 **/ 575 public TriangleMeshBuilder addVertex(float x, float y) { 576 if (mVtxSize != 2) { 577 throw new IllegalStateException("add mistmatch with declared components."); 578 } 579 makeSpace(2); 580 mVtxData[mVtxCount++] = x; 581 mVtxData[mVtxCount++] = y; 582 latch(); 583 return this; 584 } 585 586 /** 587 * Adds a float3 vertex to the mesh 588 * 589 * @param x position x 590 * @param y position y 591 * @param z position z 592 * 593 * @return this 594 * 595 **/ 596 public TriangleMeshBuilder addVertex(float x, float y, float z) { 597 if (mVtxSize != 3) { 598 throw new IllegalStateException("add mistmatch with declared components."); 599 } 600 makeSpace(3); 601 mVtxData[mVtxCount++] = x; 602 mVtxData[mVtxCount++] = y; 603 mVtxData[mVtxCount++] = z; 604 latch(); 605 return this; 606 } 607 608 /** 609 * Sets the texture coordinate for the last added vertex 610 * 611 * @param s texture coordinate s 612 * @param t texture coordinate t 613 * 614 * @return this 615 **/ 616 public TriangleMeshBuilder setTexture(float s, float t) { 617 if ((mFlags & TEXTURE_0) == 0) { 618 throw new IllegalStateException("add mistmatch with declared components."); 619 } 620 mS0 = s; 621 mT0 = t; 622 return this; 623 } 624 625 /** 626 * Sets the normal vector for the last added vertex 627 * 628 * @param x normal vector x 629 * @param y normal vector y 630 * @param z normal vector z 631 * 632 * @return this 633 **/ 634 public TriangleMeshBuilder setNormal(float x, float y, float z) { 635 if ((mFlags & NORMAL) == 0) { 636 throw new IllegalStateException("add mistmatch with declared components."); 637 } 638 mNX = x; 639 mNY = y; 640 mNZ = z; 641 return this; 642 } 643 644 /** 645 * Sets the color for the last added vertex 646 * 647 * @param r red component 648 * @param g green component 649 * @param b blue component 650 * @param a alpha component 651 * 652 * @return this 653 **/ 654 public TriangleMeshBuilder setColor(float r, float g, float b, float a) { 655 if ((mFlags & COLOR) == 0) { 656 throw new IllegalStateException("add mistmatch with declared components."); 657 } 658 mR = r; 659 mG = g; 660 mB = b; 661 mA = a; 662 return this; 663 } 664 665 /** 666 * Adds a new triangle to the mesh builder 667 * 668 * @param idx1 index of the first vertex in the triangle 669 * @param idx2 index of the second vertex in the triangle 670 * @param idx3 index of the third vertex in the triangle 671 * 672 * @return this 673 **/ 674 public TriangleMeshBuilder addTriangle(int idx1, int idx2, int idx3) { 675 if((idx1 >= mVtxCount) || (idx1 < 0) || 676 (idx2 >= mVtxCount) || (idx2 < 0) || 677 (idx3 >= mVtxCount) || (idx3 < 0)) { 678 throw new IllegalStateException("Index provided greater than vertex count."); 679 } 680 if ((mIndexCount + 3) >= mIndexData.length) { 681 short t[] = new short[mIndexData.length * 2]; 682 System.arraycopy(mIndexData, 0, t, 0, mIndexData.length); 683 mIndexData = t; 684 } 685 mIndexData[mIndexCount++] = (short)idx1; 686 mIndexData[mIndexCount++] = (short)idx2; 687 mIndexData[mIndexCount++] = (short)idx3; 688 return this; 689 } 690 691 /** 692 * Creates the mesh object from the current state of the builder 693 * 694 * @param uploadToBufferObject specifies whether the vertex data 695 * is to be uploaded into the buffer 696 * object indicating that it's likely 697 * not going to be modified and 698 * rendered many times. 699 * Alternatively, it indicates the 700 * mesh data will be updated 701 * frequently and remain in script 702 * accessible memory 703 * 704 **/ 705 public Mesh create(boolean uploadToBufferObject) { 706 Element.Builder b = new Element.Builder(mRS); 707 int floatCount = mVtxSize; 708 b.add(Element.createVector(mRS, 709 Element.DataType.FLOAT_32, 710 mVtxSize), "position"); 711 if ((mFlags & COLOR) != 0) { 712 floatCount += 4; 713 b.add(Element.F32_4(mRS), "color"); 714 } 715 if ((mFlags & TEXTURE_0) != 0) { 716 floatCount += 2; 717 b.add(Element.F32_2(mRS), "texture0"); 718 } 719 if ((mFlags & NORMAL) != 0) { 720 floatCount += 3; 721 b.add(Element.F32_3(mRS), "normal"); 722 } 723 mElement = b.create(); 724 725 int usage = Allocation.USAGE_SCRIPT; 726 if (uploadToBufferObject) { 727 usage |= Allocation.USAGE_GRAPHICS_VERTEX; 728 } 729 730 Builder smb = new Builder(mRS, usage); 731 smb.addVertexType(mElement, mVtxCount / floatCount); 732 smb.addIndexSetType(Element.U16(mRS), mIndexCount, Primitive.TRIANGLE); 733 734 Mesh sm = smb.create(); 735 736 sm.getVertexAllocation(0).copyFrom(mVtxData); 737 if(uploadToBufferObject) { 738 if (uploadToBufferObject) { 739 sm.getVertexAllocation(0).syncAll(Allocation.USAGE_SCRIPT); 740 } 741 } 742 743 sm.getIndexSetAllocation(0).copyFrom(mIndexData); 744 if (uploadToBufferObject) { 745 sm.getIndexSetAllocation(0).syncAll(Allocation.USAGE_SCRIPT); 746 } 747 748 return sm; 749 } 750 } 751} 752 753