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