1 /* 2 * Copyright (C) 2019 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 package android.gameperformance; 17 18 import java.nio.ByteBuffer; 19 import java.nio.ByteOrder; 20 21 /** 22 * Helper class that generates patch to render. Patch is a regular polygon with the center in 0. 23 * Regular polygon fits in circle with requested radius. 24 */ 25 public class RenderPatch { 26 public static final int FLOAT_SIZE = 4; 27 public static final int SHORT_SIZE = 2; 28 public static final int VERTEX_COORD_COUNT = 3; 29 public static final int VERTEX_STRIDE = VERTEX_COORD_COUNT * FLOAT_SIZE; 30 public static final int TEXTURE_COORD_COUNT = 2; 31 public static final int TEXTURE_STRIDE = TEXTURE_COORD_COUNT * FLOAT_SIZE; 32 33 // Tessellation is done using points on circle. 34 public static final int TESSELLATION_BASE = 0; 35 // Tesselation is done using extra point in 0. 36 public static final int TESSELLATION_TO_CENTER = 1; 37 38 // Radius of circle that fits polygon. 39 private final float mDimension; 40 41 private final ByteBuffer mVertexBuffer; 42 private final ByteBuffer mTextureBuffer; 43 private final ByteBuffer mIndexBuffer; 44 RenderPatch(int triangleCount, float dimension, int tessellation)45 public RenderPatch(int triangleCount, float dimension, int tessellation) { 46 mDimension = dimension; 47 48 int pointCount; 49 int externalPointCount; 50 51 if (triangleCount < 1) { 52 throw new IllegalArgumentException("Too few triangles to perform tessellation"); 53 } 54 55 switch (tessellation) { 56 case TESSELLATION_BASE: 57 externalPointCount = triangleCount + 2; 58 pointCount = externalPointCount; 59 break; 60 case TESSELLATION_TO_CENTER: 61 if (triangleCount < 3) { 62 throw new IllegalArgumentException( 63 "Too few triangles to perform tessellation to center"); 64 } 65 externalPointCount = triangleCount; 66 pointCount = triangleCount + 1; 67 break; 68 default: 69 throw new IllegalArgumentException("Wrong tesselation requested"); 70 } 71 72 if (pointCount > Short.MAX_VALUE) { 73 throw new IllegalArgumentException("Number of requested triangles is too big"); 74 } 75 76 mVertexBuffer = ByteBuffer.allocateDirect(pointCount * VERTEX_STRIDE); 77 mVertexBuffer.order(ByteOrder.nativeOrder()); 78 79 mTextureBuffer = ByteBuffer.allocateDirect(pointCount * TEXTURE_STRIDE); 80 mTextureBuffer.order(ByteOrder.nativeOrder()); 81 82 for (int i = 0; i < externalPointCount; ++i) { 83 // Use 45 degree rotation to make quad aligned along axises in case 84 // triangleCount is four. 85 final double angle = Math.PI * 0.25 + (Math.PI * 2.0 * i) / (externalPointCount); 86 // Positions 87 mVertexBuffer.putFloat((float) (dimension * Math.sin(angle))); 88 mVertexBuffer.putFloat((float) (dimension * Math.cos(angle))); 89 mVertexBuffer.putFloat(0.0f); 90 // Texture coordinates. 91 mTextureBuffer.putFloat((float) (0.5 + 0.5 * Math.sin(angle))); 92 mTextureBuffer.putFloat((float) (0.5 - 0.5 * Math.cos(angle))); 93 } 94 95 if (tessellation == TESSELLATION_TO_CENTER) { 96 // Add center point. 97 mVertexBuffer.putFloat(0.0f); 98 mVertexBuffer.putFloat(0.0f); 99 mVertexBuffer.putFloat(0.0f); 100 mTextureBuffer.putFloat(0.5f); 101 mTextureBuffer.putFloat(0.5f); 102 } 103 104 mIndexBuffer = 105 ByteBuffer.allocateDirect( 106 triangleCount * 3 /* indices per triangle */ * SHORT_SIZE); 107 mIndexBuffer.order(ByteOrder.nativeOrder()); 108 109 switch (tessellation) { 110 case TESSELLATION_BASE: 111 for (int i = 0; i < triangleCount; ++i) { 112 mIndexBuffer.putShort((short) 0); 113 mIndexBuffer.putShort((short) (i + 1)); 114 mIndexBuffer.putShort((short) (i + 2)); 115 } 116 break; 117 case TESSELLATION_TO_CENTER: 118 for (int i = 0; i < triangleCount; ++i) { 119 mIndexBuffer.putShort((short)i); 120 mIndexBuffer.putShort((short)((i + 1) % externalPointCount)); 121 mIndexBuffer.putShort((short)externalPointCount); 122 } 123 break; 124 } 125 126 if (mVertexBuffer.remaining() != 0 || mTextureBuffer.remaining() != 0 || mIndexBuffer.remaining() != 0) { 127 throw new RuntimeException("Failed to fill buffers"); 128 } 129 130 mVertexBuffer.position(0); 131 mTextureBuffer.position(0); 132 mIndexBuffer.position(0); 133 } 134 getDimension()135 public float getDimension() { 136 return mDimension; 137 } 138 getVertexBuffer()139 public ByteBuffer getVertexBuffer() { 140 return mVertexBuffer; 141 } 142 getTextureBuffer()143 public ByteBuffer getTextureBuffer() { 144 return mTextureBuffer; 145 } 146 getIndexBuffer()147 public ByteBuffer getIndexBuffer() { 148 return mIndexBuffer; 149 } 150 }