1 /* 2 * Copyright (C) 2022 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 17 package android.graphics; 18 19 import android.annotation.ColorInt; 20 import android.annotation.ColorLong; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 24 import libcore.util.NativeAllocationRegistry; 25 26 import java.nio.Buffer; 27 import java.nio.ShortBuffer; 28 29 /** 30 * Class representing a mesh object. 31 * 32 * This class represents a Mesh object that can optionally be indexed. 33 * A {@link MeshSpecification} is required along with various attributes for 34 * detailing the mesh object, including a mode, vertex buffer, optional index buffer, and bounds 35 * for the mesh. Once generated, a mesh object can be drawn through 36 * {@link Canvas#drawMesh(Mesh, BlendMode, Paint)} 37 */ 38 public class Mesh { 39 private long mNativeMeshWrapper; 40 private boolean mIsIndexed; 41 42 /** 43 * Determines how the mesh is represented and will be drawn. 44 */ 45 @IntDef({TRIANGLES, TRIANGLE_STRIP}) 46 private @interface Mode {} 47 48 /** 49 * The mesh will be drawn with triangles without utilizing shared vertices. 50 */ 51 public static final int TRIANGLES = 0; 52 53 /** 54 * The mesh will be drawn with triangles utilizing shared vertices. 55 */ 56 public static final int TRIANGLE_STRIP = 1; 57 58 private static class MeshHolder { 59 public static final NativeAllocationRegistry MESH_SPECIFICATION_REGISTRY = 60 NativeAllocationRegistry.createMalloced( 61 MeshSpecification.class.getClassLoader(), nativeGetFinalizer()); 62 } 63 64 /** 65 * Constructor for a non-indexed Mesh. 66 * 67 * @param meshSpec {@link MeshSpecification} used when generating the mesh. 68 * @param mode Determines what mode to draw the mesh in. Must be one of 69 * {@link Mesh#TRIANGLES} or {@link Mesh#TRIANGLE_STRIP} 70 * @param vertexBuffer vertex buffer representing through {@link Buffer}. This provides the data 71 * for all attributes provided within the meshSpec for every vertex. That 72 * is, a vertex buffer should be (attributes size * number of vertices) in 73 * length to be valid. Note that currently implementation will have a CPU 74 * backed buffer generated. 75 * @param vertexCount the number of vertices represented in the vertexBuffer and mesh. 76 * @param bounds bounds of the mesh object. 77 */ Mesh(@onNull MeshSpecification meshSpec, @Mode int mode, @NonNull Buffer vertexBuffer, int vertexCount, @NonNull RectF bounds)78 public Mesh(@NonNull MeshSpecification meshSpec, @Mode int mode, 79 @NonNull Buffer vertexBuffer, int vertexCount, @NonNull RectF bounds) { 80 if (mode != TRIANGLES && mode != TRIANGLE_STRIP) { 81 throw new IllegalArgumentException("Invalid value passed in for mode parameter"); 82 } 83 long nativeMesh = nativeMake(meshSpec.mNativeMeshSpec, mode, vertexBuffer, 84 vertexBuffer.isDirect(), vertexCount, vertexBuffer.position(), bounds.left, 85 bounds.top, bounds.right, bounds.bottom); 86 if (nativeMesh == 0) { 87 throw new IllegalArgumentException("Mesh construction failed."); 88 } 89 90 meshSetup(nativeMesh, false); 91 } 92 93 /** 94 * Constructor for an indexed Mesh. 95 * 96 * @param meshSpec {@link MeshSpecification} used when generating the mesh. 97 * @param mode Determines what mode to draw the mesh in. Must be one of 98 * {@link Mesh#TRIANGLES} or {@link Mesh#TRIANGLE_STRIP} 99 * @param vertexBuffer vertex buffer representing through {@link Buffer}. This provides the data 100 * for all attributes provided within the meshSpec for every vertex. That 101 * is, a vertex buffer should be (attributes size * number of vertices) in 102 * length to be valid. Note that currently implementation will have a CPU 103 * backed buffer generated. 104 * @param vertexCount the number of vertices represented in the vertexBuffer and mesh. 105 * @param indexBuffer index buffer representing through {@link ShortBuffer}. Indices are 106 * required to be 16 bits, so ShortBuffer is necessary. Note that 107 * currently implementation will have a CPU 108 * backed buffer generated. 109 * @param bounds bounds of the mesh object. 110 */ Mesh(@onNull MeshSpecification meshSpec, @Mode int mode, @NonNull Buffer vertexBuffer, int vertexCount, @NonNull ShortBuffer indexBuffer, @NonNull RectF bounds)111 public Mesh(@NonNull MeshSpecification meshSpec, @Mode int mode, 112 @NonNull Buffer vertexBuffer, int vertexCount, @NonNull ShortBuffer indexBuffer, 113 @NonNull RectF bounds) { 114 if (mode != TRIANGLES && mode != TRIANGLE_STRIP) { 115 throw new IllegalArgumentException("Invalid value passed in for mode parameter"); 116 } 117 long nativeMesh = nativeMakeIndexed(meshSpec.mNativeMeshSpec, mode, vertexBuffer, 118 vertexBuffer.isDirect(), vertexCount, vertexBuffer.position(), indexBuffer, 119 indexBuffer.isDirect(), indexBuffer.capacity(), indexBuffer.position(), bounds.left, 120 bounds.top, bounds.right, bounds.bottom); 121 if (nativeMesh == 0) { 122 throw new IllegalArgumentException("Mesh construction failed."); 123 } 124 125 meshSetup(nativeMesh, true); 126 } 127 128 /** 129 * Sets the uniform color value corresponding to the shader assigned to the mesh. If the shader 130 * does not have a uniform with that name or if the uniform is declared with a type other than 131 * vec3 or vec4 and corresponding layout(color) annotation then an IllegalArgumentExcepton is 132 * thrown. 133 * 134 * @param uniformName name matching the color uniform declared in the shader program. 135 * @param color the provided sRGB color will be converted into the shader program's output 136 * colorspace and be available as a vec4 uniform in the program. 137 */ setColorUniform(@onNull String uniformName, @ColorInt int color)138 public void setColorUniform(@NonNull String uniformName, @ColorInt int color) { 139 setUniform(uniformName, Color.valueOf(color).getComponents(), true); 140 } 141 142 /** 143 * Sets the uniform color value corresponding to the shader assigned to the mesh. If the shader 144 * does not have a uniform with that name or if the uniform is declared with a type other than 145 * vec3 or vec4 and corresponding layout(color) annotation then an IllegalArgumentExcepton is 146 * thrown. 147 * 148 * @param uniformName name matching the color uniform declared in the shader program. 149 * @param color the provided sRGB color will be converted into the shader program's output 150 * colorspace and be available as a vec4 uniform in the program. 151 */ setColorUniform(@onNull String uniformName, @ColorLong long color)152 public void setColorUniform(@NonNull String uniformName, @ColorLong long color) { 153 Color exSRGB = Color.valueOf(color).convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); 154 setUniform(uniformName, exSRGB.getComponents(), true); 155 } 156 157 /** 158 * Sets the uniform color value corresponding to the shader assigned to the mesh. If the shader 159 * does not have a uniform with that name or if the uniform is declared with a type other than 160 * vec3 or vec4 and corresponding layout(color) annotation then an IllegalArgumentExcepton is 161 * thrown. 162 * 163 * @param uniformName name matching the color uniform declared in the shader program. 164 * @param color the provided sRGB color will be converted into the shader program's output 165 * colorspace and will be made available as a vec4 uniform in the program. 166 */ setColorUniform(@onNull String uniformName, @NonNull Color color)167 public void setColorUniform(@NonNull String uniformName, @NonNull Color color) { 168 if (color == null) { 169 throw new NullPointerException("The color parameter must not be null"); 170 } 171 172 Color exSRGB = color.convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); 173 setUniform(uniformName, exSRGB.getComponents(), true); 174 } 175 176 /** 177 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 178 * not have a uniform with that name or if the uniform is declared with a type other than a 179 * float or float[1] then an IllegalArgumentException is thrown. 180 * 181 * @param uniformName name matching the float uniform declared in the shader program. 182 * @param value float value corresponding to the float uniform with the given name. 183 */ setFloatUniform(@onNull String uniformName, float value)184 public void setFloatUniform(@NonNull String uniformName, float value) { 185 setFloatUniform(uniformName, value, 0.0f, 0.0f, 0.0f, 1); 186 } 187 188 /** 189 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 190 * not have a uniform with that name or if the uniform is declared with a type other than a 191 * vec2 or float[2] then an IllegalArgumentException is thrown. 192 * 193 * @param uniformName name matching the float uniform declared in the shader program. 194 * @param value1 first float value corresponding to the float uniform with the given name. 195 * @param value2 second float value corresponding to the float uniform with the given name. 196 */ setFloatUniform(@onNull String uniformName, float value1, float value2)197 public void setFloatUniform(@NonNull String uniformName, float value1, float value2) { 198 setFloatUniform(uniformName, value1, value2, 0.0f, 0.0f, 2); 199 } 200 201 /** 202 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 203 * not have a uniform with that name or if the uniform is declared with a type other than a 204 * vec3 or float[3] then an IllegalArgumentException is thrown. 205 * 206 * @param uniformName name matching the float uniform declared in the shader program. 207 * @param value1 first float value corresponding to the float uniform with the given name. 208 * @param value2 second float value corresponding to the float uniform with the given name. 209 * @param value3 third float value corresponding to the float unifiform with the given 210 * name. 211 */ setFloatUniform( @onNull String uniformName, float value1, float value2, float value3)212 public void setFloatUniform( 213 @NonNull String uniformName, float value1, float value2, float value3) { 214 setFloatUniform(uniformName, value1, value2, value3, 0.0f, 3); 215 } 216 217 /** 218 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 219 * not have a uniform with that name or if the uniform is declared with a type other than a 220 * vec4 or float[4] then an IllegalArgumentException is thrown. 221 * 222 * @param uniformName name matching the float uniform declared in the shader program. 223 * @param value1 first float value corresponding to the float uniform with the given name. 224 * @param value2 second float value corresponding to the float uniform with the given name. 225 * @param value3 third float value corresponding to the float uniform with the given name. 226 * @param value4 fourth float value corresponding to the float uniform with the given name. 227 */ setFloatUniform( @onNull String uniformName, float value1, float value2, float value3, float value4)228 public void setFloatUniform( 229 @NonNull String uniformName, float value1, float value2, float value3, float value4) { 230 setFloatUniform(uniformName, value1, value2, value3, value4, 4); 231 } 232 233 /** 234 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 235 * not have a uniform with that name or if the uniform is declared with a type other than a 236 * float (for N=1), vecN, or float[N], where N is the length of the values param, then an 237 * IllegalArgumentException is thrown. 238 * 239 * @param uniformName name matching the float uniform declared in the shader program. 240 * @param values float value corresponding to the vec4 float uniform with the given name. 241 */ setFloatUniform(@onNull String uniformName, @NonNull float[] values)242 public void setFloatUniform(@NonNull String uniformName, @NonNull float[] values) { 243 setUniform(uniformName, values, false); 244 } 245 setFloatUniform( String uniformName, float value1, float value2, float value3, float value4, int count)246 private void setFloatUniform( 247 String uniformName, float value1, float value2, float value3, float value4, int count) { 248 if (uniformName == null) { 249 throw new NullPointerException("The uniformName parameter must not be null"); 250 } 251 nativeUpdateUniforms( 252 mNativeMeshWrapper, uniformName, value1, value2, value3, value4, count); 253 } 254 setUniform(String uniformName, float[] values, boolean isColor)255 private void setUniform(String uniformName, float[] values, boolean isColor) { 256 if (uniformName == null) { 257 throw new NullPointerException("The uniformName parameter must not be null"); 258 } 259 if (values == null) { 260 throw new NullPointerException("The uniform values parameter must not be null"); 261 } 262 263 nativeUpdateUniforms(mNativeMeshWrapper, uniformName, values, isColor); 264 } 265 266 /** 267 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 268 * not have a uniform with that name or if the uniform is declared with a type other than int 269 * or int[1] then an IllegalArgumentException is thrown. 270 * 271 * @param uniformName name matching the int uniform delcared in the shader program. 272 * @param value value corresponding to the int uniform with the given name. 273 */ setIntUniform(@onNull String uniformName, int value)274 public void setIntUniform(@NonNull String uniformName, int value) { 275 setIntUniform(uniformName, value, 0, 0, 0, 1); 276 } 277 278 /** 279 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 280 * not have a uniform with that name or if the uniform is declared with a type other than ivec2 281 * or int[2] then an IllegalArgumentException is thrown. 282 * 283 * @param uniformName name matching the int uniform delcared in the shader program. 284 * @param value1 first value corresponding to the int uniform with the given name. 285 * @param value2 second value corresponding to the int uniform with the given name. 286 */ setIntUniform(@onNull String uniformName, int value1, int value2)287 public void setIntUniform(@NonNull String uniformName, int value1, int value2) { 288 setIntUniform(uniformName, value1, value2, 0, 0, 2); 289 } 290 291 /** 292 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 293 * not have a uniform with that name or if the uniform is declared with a type other than ivec3 294 * or int[3] then an IllegalArgumentException is thrown. 295 * 296 * @param uniformName name matching the int uniform delcared in the shader program. 297 * @param value1 first value corresponding to the int uniform with the given name. 298 * @param value2 second value corresponding to the int uniform with the given name. 299 * @param value3 third value corresponding to the int uniform with the given name. 300 */ setIntUniform(@onNull String uniformName, int value1, int value2, int value3)301 public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3) { 302 setIntUniform(uniformName, value1, value2, value3, 0, 3); 303 } 304 305 /** 306 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 307 * not have a uniform with that name or if the uniform is declared with a type other than ivec4 308 * or int[4] then an IllegalArgumentException is thrown. 309 * 310 * @param uniformName name matching the int uniform delcared in the shader program. 311 * @param value1 first value corresponding to the int uniform with the given name. 312 * @param value2 second value corresponding to the int uniform with the given name. 313 * @param value3 third value corresponding to the int uniform with the given name. 314 * @param value4 fourth value corresponding to the int uniform with the given name. 315 */ setIntUniform( @onNull String uniformName, int value1, int value2, int value3, int value4)316 public void setIntUniform( 317 @NonNull String uniformName, int value1, int value2, int value3, int value4) { 318 setIntUniform(uniformName, value1, value2, value3, value4, 4); 319 } 320 321 /** 322 * Sets the uniform value corresponding to the shader assigned to the mesh. If the shader does 323 * not have a uniform with that name or if the uniform is declared with a type other than an 324 * int (for N=1), ivecN, or int[N], where N is the length of the values param, then an 325 * IllegalArgumentException is thrown. 326 * 327 * @param uniformName name matching the int uniform delcared in the shader program. 328 * @param values int values corresponding to the vec4 int uniform with the given name. 329 */ setIntUniform(@onNull String uniformName, @NonNull int[] values)330 public void setIntUniform(@NonNull String uniformName, @NonNull int[] values) { 331 if (uniformName == null) { 332 throw new NullPointerException("The uniformName parameter must not be null"); 333 } 334 if (values == null) { 335 throw new NullPointerException("The uniform values parameter must not be null"); 336 } 337 nativeUpdateUniforms(mNativeMeshWrapper, uniformName, values); 338 } 339 340 /** 341 * @hide so only calls from module can utilize it 342 */ getNativeWrapperInstance()343 long getNativeWrapperInstance() { 344 return mNativeMeshWrapper; 345 } 346 setIntUniform( String uniformName, int value1, int value2, int value3, int value4, int count)347 private void setIntUniform( 348 String uniformName, int value1, int value2, int value3, int value4, int count) { 349 if (uniformName == null) { 350 throw new NullPointerException("The uniformName parameter must not be null"); 351 } 352 353 nativeUpdateUniforms( 354 mNativeMeshWrapper, uniformName, value1, value2, value3, value4, count); 355 } 356 meshSetup(long nativeMeshWrapper, boolean isIndexed)357 private void meshSetup(long nativeMeshWrapper, boolean isIndexed) { 358 mNativeMeshWrapper = nativeMeshWrapper; 359 this.mIsIndexed = isIndexed; 360 MeshHolder.MESH_SPECIFICATION_REGISTRY.registerNativeAllocation(this, mNativeMeshWrapper); 361 } 362 nativeGetFinalizer()363 private static native long nativeGetFinalizer(); 364 nativeMake(long meshSpec, int mode, Buffer vertexBuffer, boolean isDirect, int vertexCount, int vertexOffset, float left, float top, float right, float bottom)365 private static native long nativeMake(long meshSpec, int mode, Buffer vertexBuffer, 366 boolean isDirect, int vertexCount, int vertexOffset, float left, float top, float right, 367 float bottom); 368 nativeMakeIndexed(long meshSpec, int mode, Buffer vertexBuffer, boolean isVertexDirect, int vertexCount, int vertexOffset, ShortBuffer indexBuffer, boolean isIndexDirect, int indexCount, int indexOffset, float left, float top, float right, float bottom)369 private static native long nativeMakeIndexed(long meshSpec, int mode, Buffer vertexBuffer, 370 boolean isVertexDirect, int vertexCount, int vertexOffset, ShortBuffer indexBuffer, 371 boolean isIndexDirect, int indexCount, int indexOffset, float left, float top, 372 float right, float bottom); 373 nativeUpdateUniforms(long builder, String uniformName, float value1, float value2, float value3, float value4, int count)374 private static native void nativeUpdateUniforms(long builder, String uniformName, float value1, 375 float value2, float value3, float value4, int count); 376 nativeUpdateUniforms( long builder, String uniformName, float[] values, boolean isColor)377 private static native void nativeUpdateUniforms( 378 long builder, String uniformName, float[] values, boolean isColor); 379 nativeUpdateUniforms(long builder, String uniformName, int value1, int value2, int value3, int value4, int count)380 private static native void nativeUpdateUniforms(long builder, String uniformName, int value1, 381 int value2, int value3, int value4, int count); 382 nativeUpdateUniforms(long builder, String uniformName, int[] values)383 private static native void nativeUpdateUniforms(long builder, String uniformName, int[] values); 384 385 } 386