draco/javascript/npm/draco_animation/draco_animation_encoding_test.js
2020-12-01 13:01:33 -08:00

179 lines
6.3 KiB
JavaScript

// Copyright 2017 The Draco Authors.
//
// 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.
//
'use_strict';
const assert = require('assert');
const draco = require('./draco-animation');
// Global variables to keep track of which modules have been intiailized.
let encoderModuleInitialized = false;
let decoderModuleInitialized = false;
// Callback function when encoder module has been intialized.
let dracoEncoderType = {};
dracoEncoderType['onModuleLoaded'] = function(module) {
encoderModuleInitialized = true;
console.log('Encoder Module Initialized!');
moduleInitialized();
};
// Callback function when decoder module has been intialized.
let dracoDecoderType = {};
dracoDecoderType['onModuleLoaded'] = function(module) {
decoderModuleInitialized = true;
console.log('Decoder Module Initialized!');
moduleInitialized();
};
// The code to create the encoder and decoder modules is asynchronous.
// draco will call the 'onModuleLoaded' callback when the different
// modules have been fully initialized.
const encoderModule = draco.createEncoderModule(dracoEncoderType);
const decoderModule = draco.createDecoderModule(dracoDecoderType);
function generateAnimationData(numKeyframes, numAnimations, numComponents) {
const timestamps = new Float32Array(numKeyframes);
const keyframes = new Array(numAnimations);
for (let i = 0; i < numAnimations; ++i) {
keyframes[i] = new Float32Array(numKeyframes * numComponents[i]);
}
for (let frameId = 0; frameId < numKeyframes; ++frameId) {
timestamps[frameId] = frameId;
for (let keyframeId = 0; keyframeId < numAnimations; ++keyframeId) {
for (let j = 0; j < numComponents[keyframeId]; ++j) {
// Set an arbitrary deterministic value.
keyframes[keyframeId][frameId * numComponents[keyframeId] + j] =
(frameId * numComponents[keyframeId] + j) * (keyframeId + 1);
}
}
}
const animation = {
timestamps : timestamps,
keyframes : keyframes
};
return animation;
}
function encodeAnimation(animation) {
const encoder = new encoderModule.AnimationEncoder();
const animationBuilder = new encoderModule.AnimationBuilder();
const dracoAnimation = new encoderModule.KeyframeAnimation();
// Add timestamps to animation.
const numKeyframes = animation.timestamps.length;
assert(animationBuilder.SetTimestamps(dracoAnimation, numKeyframes,
animation.timestamps));
// Add keyframes.
for (let keyframeId = 0; keyframeId < animation.keyframes.length;
++keyframeId) {
const numComponents =
animation.keyframes[keyframeId].length / animation.timestamps.length;
assert(animationBuilder.AddKeyframes(dracoAnimation, numKeyframes,
numComponents, animation.keyframes[keyframeId]) == keyframeId + 1);
}
const encodedData = new encoderModule.DracoInt8Array();
encoder.SetTimestampsQuantization(16);
encoder.SetKeyframesQuantization(16);
console.log("Quantized timestamps to 16 bits.");
console.log("Quantized keyframes to 16 bits.");
const encodedLen = encoder.EncodeAnimationToDracoBuffer(dracoAnimation,
encodedData);
encoderModule.destroy(dracoAnimation);
encoderModule.destroy(animationBuilder);
encoderModule.destroy(encoder);
assert(encodedLen > 0, "Failed encoding.");
console.log("Encoded size: " + encodedLen);
const outputBuffer = new ArrayBuffer(encodedLen);
const outputData = new Int8Array(outputBuffer);
for (let i = 0; i < encodedLen; ++i) {
const data0 = encodedData.GetValue(i);
outputData[i] = encodedData.GetValue(i);
}
encoderModule.destroy(encodedData);
return outputBuffer;
}
function decodeAnimation(encodedData) {
const buffer = new decoderModule.DecoderBuffer();
buffer.Init(new Int8Array(encodedData), encodedData.byteLength);
const decoder = new decoderModule.AnimationDecoder();
const dracoAnimation = new decoderModule.KeyframeAnimation();
decoder.DecodeBufferToKeyframeAnimation(buffer, dracoAnimation);
assert(dracoAnimation.ptr != 0, "Invalid animation.");
const numKeyframes = dracoAnimation.num_frames();
const timestampAttData = new decoderModule.DracoFloat32Array();
assert(decoder.GetTimestamps(dracoAnimation, timestampAttData));
const timestamps = new Float32Array(numKeyframes);
for (let i = 0; i < numKeyframes; ++i) {
timestamps[i] = timestampAttData.GetValue(i);
}
const numAnimations = dracoAnimation.num_animations();
const keyframes = new Array(numAnimations);
for (let keyframeId = 0; keyframeId < numAnimations; ++keyframeId) {
const animationAttData = new decoderModule.DracoFloat32Array();
// The id of keyframe attribute starts at 1.
assert(decoder.GetKeyframes(dracoAnimation, keyframeId + 1,
animationAttData));
keyframes[keyframeId] = new Float32Array(animationAttData.size());
for (let i = 0; i < animationAttData.size(); ++i) {
keyframes[keyframeId][i] = animationAttData.GetValue(i);
}
}
const animation = {
timestamps : timestamps,
keyframes : keyframes
}
console.log("Decoding successful.");
return animation;
}
function compareAnimation(animation, decodedAnimation) {
console.log("Comparing decoded animation data...");
assert(animation.timestamps.length == decodedAnimation.timestamps.length);
assert(animation.keyframes.length == decodedAnimation.keyframes.length);
console.log("Done.");
}
function moduleInitialized() {
if (encoderModuleInitialized && decoderModuleInitialized) {
// Create animation with 50 frames and two animations.
// The first animation has 3 components and the second has 4 components.
const animation = generateAnimationData(100, 2, [3, 4]);
const encodedData = encodeAnimation(animation);
const decodedAnimation = decodeAnimation(encodedData);
compareAnimation(animation, decodedAnimation);
}
}