mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-04-22 05:39:54 +08:00
179 lines
6.3 KiB
JavaScript
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);
|
|
}
|
|
}
|