/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.gameperformance; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * Helper class that generates patch to render. Patch is a regular polygon with the center in 0. * Regular polygon fits in circle with requested radius. */ public class RenderPatch { public static final int FLOAT_SIZE = 4; public static final int SHORT_SIZE = 2; public static final int VERTEX_COORD_COUNT = 3; public static final int VERTEX_STRIDE = VERTEX_COORD_COUNT * FLOAT_SIZE; public static final int TEXTURE_COORD_COUNT = 2; public static final int TEXTURE_STRIDE = TEXTURE_COORD_COUNT * FLOAT_SIZE; // Tessellation is done using points on circle. public static final int TESSELLATION_BASE = 0; // Tesselation is done using extra point in 0. public static final int TESSELLATION_TO_CENTER = 1; // Radius of circle that fits polygon. private final float mDimension; private final ByteBuffer mVertexBuffer; private final ByteBuffer mTextureBuffer; private final ByteBuffer mIndexBuffer; public RenderPatch(int triangleCount, float dimension, int tessellation) { mDimension = dimension; int pointCount; int externalPointCount; if (triangleCount < 1) { throw new IllegalArgumentException("Too few triangles to perform tessellation"); } switch (tessellation) { case TESSELLATION_BASE: externalPointCount = triangleCount + 2; pointCount = externalPointCount; break; case TESSELLATION_TO_CENTER: if (triangleCount < 3) { throw new IllegalArgumentException( "Too few triangles to perform tessellation to center"); } externalPointCount = triangleCount; pointCount = triangleCount + 1; break; default: throw new IllegalArgumentException("Wrong tesselation requested"); } if (pointCount > Short.MAX_VALUE) { throw new IllegalArgumentException("Number of requested triangles is too big"); } mVertexBuffer = ByteBuffer.allocateDirect(pointCount * VERTEX_STRIDE); mVertexBuffer.order(ByteOrder.nativeOrder()); mTextureBuffer = ByteBuffer.allocateDirect(pointCount * TEXTURE_STRIDE); mTextureBuffer.order(ByteOrder.nativeOrder()); for (int i = 0; i < externalPointCount; ++i) { // Use 45 degree rotation to make quad aligned along axises in case // triangleCount is four. final double angle = Math.PI * 0.25 + (Math.PI * 2.0 * i) / (externalPointCount); // Positions mVertexBuffer.putFloat((float) (dimension * Math.sin(angle))); mVertexBuffer.putFloat((float) (dimension * Math.cos(angle))); mVertexBuffer.putFloat(0.0f); // Texture coordinates. mTextureBuffer.putFloat((float) (0.5 + 0.5 * Math.sin(angle))); mTextureBuffer.putFloat((float) (0.5 - 0.5 * Math.cos(angle))); } if (tessellation == TESSELLATION_TO_CENTER) { // Add center point. mVertexBuffer.putFloat(0.0f); mVertexBuffer.putFloat(0.0f); mVertexBuffer.putFloat(0.0f); mTextureBuffer.putFloat(0.5f); mTextureBuffer.putFloat(0.5f); } mIndexBuffer = ByteBuffer.allocateDirect( triangleCount * 3 /* indices per triangle */ * SHORT_SIZE); mIndexBuffer.order(ByteOrder.nativeOrder()); switch (tessellation) { case TESSELLATION_BASE: for (int i = 0; i < triangleCount; ++i) { mIndexBuffer.putShort((short) 0); mIndexBuffer.putShort((short) (i + 1)); mIndexBuffer.putShort((short) (i + 2)); } break; case TESSELLATION_TO_CENTER: for (int i = 0; i < triangleCount; ++i) { mIndexBuffer.putShort((short)i); mIndexBuffer.putShort((short)((i + 1) % externalPointCount)); mIndexBuffer.putShort((short)externalPointCount); } break; } if (mVertexBuffer.remaining() != 0 || mTextureBuffer.remaining() != 0 || mIndexBuffer.remaining() != 0) { throw new RuntimeException("Failed to fill buffers"); } mVertexBuffer.position(0); mTextureBuffer.position(0); mIndexBuffer.position(0); } public float getDimension() { return mDimension; } public ByteBuffer getVertexBuffer() { return mVertexBuffer; } public ByteBuffer getTextureBuffer() { return mTextureBuffer; } public ByteBuffer getIndexBuffer() { return mIndexBuffer; } }