diff --git a/android/filament-android/src/main/cpp/VertexBuffer.cpp b/android/filament-android/src/main/cpp/VertexBuffer.cpp index be8f68dc53..5b99567540 100644 --- a/android/filament-android/src/main/cpp/VertexBuffer.cpp +++ b/android/filament-android/src/main/cpp/VertexBuffer.cpp @@ -21,10 +21,14 @@ #include +#include +#include + #include "CallbackUtils.h" #include "NioUtils.h" using namespace filament; +using namespace filament::math; using namespace driver; extern "C" JNIEXPORT jlong JNICALL @@ -110,3 +114,43 @@ Java_com_google_android_filament_VertexBuffer_nSetBufferAt(JNIEnv *env, jclass t return 0; } + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_VertexBuffer_nPopulateTangentQuaternions(JNIEnv *env, + jclass type, jint quatType, jint quatCount, jobject outBuffer, jint outRemaining, + jint outStride, jobject normals, jint normalsRemaining, jint normalsStride, + jobject tangents, jint tangentsRemaining, jint tangentsStride) { + + AutoBuffer outNioBuffer(env, outBuffer, outRemaining); + void* outData = outNioBuffer.getData(); + + AutoBuffer normalsNioBuffer(env, normals, normalsRemaining); + auto normalsData = (const float3*) normalsNioBuffer.getData(); + + if (tangents) { + AutoBuffer tangentsNioBuffer(env, tangents, tangentsRemaining); + auto tangentsData = (const float4*) tangentsNioBuffer.getData(); + VertexBuffer::populateTangentQuaternions({ + .quatType = (VertexBuffer::QuatType) quatType, + .quatCount = (size_t) quatCount, + .outBuffer = outData, + .outStride = (size_t) outStride, + .normals = normalsData, + .normalsStride = (size_t) normalsStride, + .tangents = tangentsData, + .tangentsStride = (size_t) tangentsStride + }); + return; + } + + VertexBuffer::populateTangentQuaternions({ + .quatType = (VertexBuffer::QuatType) quatType, + .quatCount = (size_t) quatCount, + .outBuffer = outData, + .outStride = (size_t) outStride, + .normals = normalsData, + .normalsStride = (size_t) normalsStride, + .tangents = nullptr, + .tangentsStride = 0 + }); +} diff --git a/android/filament-android/src/main/java/com/google/android/filament/VertexBuffer.java b/android/filament-android/src/main/java/com/google/android/filament/VertexBuffer.java index 0e1f1ee653..faba52dd6d 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/VertexBuffer.java +++ b/android/filament-android/src/main/java/com/google/android/filament/VertexBuffer.java @@ -69,6 +69,23 @@ public class VertexBuffer { HALF4, } + public enum QuatType { + HALF4, // 2 bytes per component as half-floats (8 bytes per quat) + SHORT4, // 2 bytes per component as normalized integers (8 bytes per quat) + FLOAT4, // 4 bytes per component as floats (16 bytes per quat) + } + + public static class QuatTangentContext { + public QuatType quatType; // desired quaternion type (required) + public int quatCount; // number of quaternions (required) + public Buffer outBuffer; // pre-allocated output buffer (required) + public int outStride; // desired stride in bytes (optional) + public Buffer normals; // source normals (required) + public int normalsStride; // normals stride in bytes (optional) + public Buffer tangents; // source tangents (optional) + public int tangentsStride; // tangents stride in bytes (optional) + } + public static class Builder { @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources private final BuilderFinalizer mFinalizer; @@ -172,6 +189,14 @@ public class VertexBuffer { } } + public static void populateTangentQuaternions(@NonNull QuatTangentContext context) { + nPopulateTangentQuaternions(context.quatType.ordinal(), context.quatCount, + context.outBuffer, context.outBuffer.remaining(), context.outStride, + context.normals, context.normals.remaining(), context.normalsStride, + context.tangents, context.tangents != null ? context.tangents.remaining() : 0, + context.tangentsStride); + } + long getNativeObject() { if (mNativeObject == 0) { throw new IllegalStateException("Calling method on destroyed VertexBuffer"); @@ -197,4 +222,8 @@ public class VertexBuffer { private static native int nSetBufferAt(long nativeVertexBuffer, long nativeEngine, int bufferIndex, Buffer buffer, int remaining, int destOffsetInBytes, int count, Object handler, Runnable callback); + + private static native void nPopulateTangentQuaternions(int quatType, int quatCount, + Buffer outBuffer, int outRemaining, int outStride, Buffer normals, int normalsRemaining, + int normalsStride, Buffer tangents, int tangentsRemaining, int tangentsStride); } diff --git a/filament/include/filament/VertexBuffer.h b/filament/include/filament/VertexBuffer.h index cc5ab44db1..9db1967e77 100644 --- a/filament/include/filament/VertexBuffer.h +++ b/filament/include/filament/VertexBuffer.h @@ -119,14 +119,14 @@ public: * Specifies the parameters for the "populateTangentQuaternions" utility. */ struct QuatTangentContext { - QuatType quatType; // required - size_t quatCount; // required - void* outBuffer; // required - size_t outStride; // required stride in bytes - const filament::math::float3* normals; // required source data - size_t normalsStride; // optional stride in bytes (assumes packed) - const filament::math::float4* tangents; // optional source data - size_t tangentsStride; // optional stride in bytes (assumes packed) + QuatType quatType; // desired quaternion type (required) + size_t quatCount; // number of quaternions (required) + void* outBuffer; // pre-allocated output buffer (required) + size_t outStride; // desired stride in bytes (optional) + const filament::math::float3* normals; // source normals (required) + size_t normalsStride; // normals stride in bytes (optional) + const filament::math::float4* tangents; // source tangents (optional) + size_t tangentsStride; // tangents stride in bytes (optional) }; /** diff --git a/filament/src/VertexBuffer.cpp b/filament/src/VertexBuffer.cpp index e05bfc3244..a3d8a97fb6 100644 --- a/filament/src/VertexBuffer.cpp +++ b/filament/src/VertexBuffer.cpp @@ -211,27 +211,31 @@ void VertexBuffer::populateTangentQuaternions(const QuatTangentContext& ctx) { } // Define a small lambda that converts fp32 into the desired output format. - void (*writeQuat)(filament::math::quatf, uint8_t*); + size_t outStride = ctx.outStride; + void (*writeQuat)(quatf, uint8_t*); switch (ctx.quatType) { case HALF4: writeQuat = [] (quatf inquat, uint8_t* outquat) { *((quath*) outquat) = quath(inquat); }; + outStride = outStride ? outStride : sizeof(half4); break; case SHORT4: writeQuat = [] (quatf inquat, uint8_t* outquat) { *((short4*) outquat) = packSnorm16(inquat.xyzw); }; + outStride = outStride ? outStride : sizeof(short4); break; case FLOAT4: writeQuat = [] (quatf inquat, uint8_t* outquat) { *((quatf*) outquat) = inquat; }; + outStride = outStride ? outStride : sizeof(float4); break; } const float3* normal = ctx.normals; - const size_t nstride = ctx.normalsStride ? ctx.normalsStride : sizeof(filament::math::float3); + const size_t nstride = ctx.normalsStride ? ctx.normalsStride : sizeof(float3); uint8_t* outquat = (uint8_t*) ctx.outBuffer; // If tangents are not provided, simply cross N with arbitrary vector (1, 0, 0) @@ -242,14 +246,14 @@ void VertexBuffer::populateTangentQuaternions(const QuatTangentContext& ctx) { float3 t = cross(n, b); writeQuat(mat3f::packTangentFrame({t, b, n}), outquat); normal = (const float3*) (((const uint8_t*) normal) + nstride); - outquat += ctx.outStride; + outquat += outStride; } return; } const float3* tanvec = &ctx.tangents->xyz; const float* tandir = &ctx.tangents->w; - const size_t tstride = ctx.tangentsStride ? ctx.tangentsStride : sizeof(filament::math::float4); + const size_t tstride = ctx.tangentsStride ? ctx.tangentsStride : sizeof(float4); for (size_t qindex = 0, qcount = ctx.quatCount; qindex < qcount; ++qindex) { float3 n = *normal;