de.javagl.jgltf.viewer.Morphing Maven / Gradle / Ivy
/*
* www.javagl.de - JglTF
*
* Copyright 2015-2016 Marco Hutter - http://www.javagl.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package de.javagl.jgltf.viewer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import de.javagl.jgltf.model.AccessorData;
import de.javagl.jgltf.model.AccessorFloatData;
import de.javagl.jgltf.model.AccessorModel;
import de.javagl.jgltf.model.BufferModel;
import de.javagl.jgltf.model.BufferViewModel;
import de.javagl.jgltf.model.MeshPrimitiveModel;
/**
* Utility methods and classes related to morphing.
*/
class Morphing
{
// TODO This is a first working implementation. It can (and should) be
// improved in many ways. For example: There are very few error checks...
/**
* The logger used in this class
*/
private static final Logger logger =
Logger.getLogger(Morphing.class.getName());
/**
* A class representing an attribute to which morphing can be applied.
*/
static class MorphableAttribute
{
/**
* A newly created {@link AccessorModel} containing the morphed data
*/
private final AccessorModel morphedAccessorModel;
/**
* The original {@link AccessorModel} that represents the original
* values of this attribute, without morphing.
*/
private final AccessorModel baseAccessorModel;
/**
* The accessor data of the morph targets
*/
private final List targetAccessorFloatDatas;
/**
* Creates a new isntance
*
* @param morphedAccessorModel A newly created {@link AccessorModel}
* (with a newly created {@link BufferViewModel} and
* {@link BufferModel}) that exactly represents the morphed attribute
* data. The contents of this model will be overwritten by this
* instance, when {@link #updateMorphedAccessorData(float[])} is
* called
* @param baseAccessorModel The base {@link AccessorModel} for the
* attribute
* @param targetAccessorFloatDatas The {@link AccessorFloatData}
* elements that have been obtained from the morph target accessors
*/
private MorphableAttribute(AccessorModel morphedAccessorModel,
AccessorModel baseAccessorModel,
Collection extends AccessorFloatData> targetAccessorFloatDatas)
{
this.baseAccessorModel = baseAccessorModel;
this.morphedAccessorModel = morphedAccessorModel;
this.targetAccessorFloatDatas =
Collections.unmodifiableList(
new ArrayList(targetAccessorFloatDatas));
}
/**
* Returns the {@link AccessorModel} that contains the morphed data.
* This {@link AccessorModel} will be used for rendering. It refers
* to a {@link BufferViewModel} and a {@link BufferModel} that contain
* exactly the morphed data. This model (and thus, the underlying
* buffer data) will be updated when
* {@link #updateMorphedAccessorData(float[])} is called.
*
* @return The {@link AccessorModel} containing the morphed data.
*/
AccessorModel getMorphedAccessorModel()
{
return morphedAccessorModel;
}
/**
* Returns the number of morph targets for this attribute
*
* @return The number of morph targets
*/
int getNumTargets()
{
return targetAccessorFloatDatas.size();
}
/**
* Update the data of the {@link #getMorphedAccessorModel() morphed
* accessor model} based on the given weights.
*
* @param weights The morph target weights.
*/
void updateMorphedAccessorData(float weights[])
{
AccessorFloatData morphedAccessorData =
(AccessorFloatData) morphedAccessorModel.getAccessorData();
AccessorFloatData baseAccessorData =
(AccessorFloatData) baseAccessorModel.getAccessorData();
combine3D(
morphedAccessorData,
baseAccessorData,
targetAccessorFloatDatas,
weights);
}
}
/**
* Returns whether the attribute with the given semantic in the given
* {@link MeshPrimitiveModel} is "morphable".
*
* This is supposed to do the basic tests that are necessary in order
* to call {@link #createMorphableAttribute} with the same parameters
* and obtain a valid result.
*
* If the underlying data is supposed to contain morph data, but the
* data is invalid in any way, an error message might be printed.
* Further details are not specified.
*
* @param meshPrimitiveModel The {@link MeshPrimitiveModel}
* @param semantic The semantic string (e.g. "POSITION"
)
* @return Whether the attribute is morphable.
*/
static boolean isMorphableAttribute(
MeshPrimitiveModel meshPrimitiveModel, String semantic)
{
// Check if the attribute exists at all
Map meshPrimitiveAttributes =
meshPrimitiveModel.getAttributes();
AccessorModel accessorModel = meshPrimitiveAttributes.get(semantic);
if (accessorModel == null)
{
return false;
}
// Check if there are morph targets for the attribute,
// and whether each morph target has float components
boolean hasMorphTargetsForSemantic = false;
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy