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