All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.javagl.jgltf.model.v1.GltfModelV1 Maven / Gradle / Ivy

There is a newer version: 2.0.4
Show newest version
/*
 * 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.model.v1;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.logging.Logger;

import de.javagl.jgltf.impl.v1.Accessor;
import de.javagl.jgltf.impl.v1.Animation;
import de.javagl.jgltf.impl.v1.AnimationChannel;
import de.javagl.jgltf.impl.v1.AnimationChannelTarget;
import de.javagl.jgltf.impl.v1.AnimationSampler;
import de.javagl.jgltf.impl.v1.Buffer;
import de.javagl.jgltf.impl.v1.BufferView;
import de.javagl.jgltf.impl.v1.Camera;
import de.javagl.jgltf.impl.v1.GlTF;
import de.javagl.jgltf.impl.v1.Image;
import de.javagl.jgltf.impl.v1.Material;
import de.javagl.jgltf.impl.v1.Mesh;
import de.javagl.jgltf.impl.v1.MeshPrimitive;
import de.javagl.jgltf.impl.v1.Node;
import de.javagl.jgltf.impl.v1.Program;
import de.javagl.jgltf.impl.v1.Sampler;
import de.javagl.jgltf.impl.v1.Scene;
import de.javagl.jgltf.impl.v1.Shader;
import de.javagl.jgltf.impl.v1.Skin;
import de.javagl.jgltf.impl.v1.Technique;
import de.javagl.jgltf.impl.v1.TechniqueParameters;
import de.javagl.jgltf.impl.v1.TechniqueStatesFunctions;
import de.javagl.jgltf.impl.v1.Texture;
import de.javagl.jgltf.model.AccessorModel;
import de.javagl.jgltf.model.Accessors;
import de.javagl.jgltf.model.AnimationModel;
import de.javagl.jgltf.model.AnimationModel.Channel;
import de.javagl.jgltf.model.AnimationModel.Interpolation;
import de.javagl.jgltf.model.BufferModel;
import de.javagl.jgltf.model.BufferViewModel;
import de.javagl.jgltf.model.CameraModel;
import de.javagl.jgltf.model.ElementType;
import de.javagl.jgltf.model.GltfConstants;
import de.javagl.jgltf.model.GltfModel;
import de.javagl.jgltf.model.ImageModel;
import de.javagl.jgltf.model.MaterialModel;
import de.javagl.jgltf.model.MathUtils;
import de.javagl.jgltf.model.MeshModel;
import de.javagl.jgltf.model.MeshPrimitiveModel;
import de.javagl.jgltf.model.NodeModel;
import de.javagl.jgltf.model.Optionals;
import de.javagl.jgltf.model.SceneModel;
import de.javagl.jgltf.model.SkinModel;
import de.javagl.jgltf.model.TextureModel;
import de.javagl.jgltf.model.Utils;
import de.javagl.jgltf.model.gl.ProgramModel;
import de.javagl.jgltf.model.gl.ShaderModel;
import de.javagl.jgltf.model.gl.ShaderModel.ShaderType;
import de.javagl.jgltf.model.gl.TechniqueModel;
import de.javagl.jgltf.model.gl.TechniqueParametersModel;
import de.javagl.jgltf.model.gl.TechniqueStatesFunctionsModel;
import de.javagl.jgltf.model.gl.TechniqueStatesModel;
import de.javagl.jgltf.model.gl.impl.DefaultProgramModel;
import de.javagl.jgltf.model.gl.impl.DefaultShaderModel;
import de.javagl.jgltf.model.gl.impl.DefaultTechniqueModel;
import de.javagl.jgltf.model.gl.impl.DefaultTechniqueParametersModel;
import de.javagl.jgltf.model.gl.impl.DefaultTechniqueStatesModel;
import de.javagl.jgltf.model.gl.impl.v1.DefaultTechniqueStatesFunctionsModelV1;
import de.javagl.jgltf.model.impl.DefaultAccessorModel;
import de.javagl.jgltf.model.impl.DefaultAnimationModel;
import de.javagl.jgltf.model.impl.DefaultAnimationModel.DefaultChannel;
import de.javagl.jgltf.model.impl.DefaultAnimationModel.DefaultSampler;
import de.javagl.jgltf.model.impl.DefaultBufferModel;
import de.javagl.jgltf.model.impl.DefaultBufferViewModel;
import de.javagl.jgltf.model.impl.DefaultCameraModel;
import de.javagl.jgltf.model.impl.DefaultImageModel;
import de.javagl.jgltf.model.impl.DefaultMaterialModel;
import de.javagl.jgltf.model.impl.DefaultMeshModel;
import de.javagl.jgltf.model.impl.DefaultMeshPrimitiveModel;
import de.javagl.jgltf.model.impl.DefaultNodeModel;
import de.javagl.jgltf.model.impl.DefaultSceneModel;
import de.javagl.jgltf.model.impl.DefaultSkinModel;
import de.javagl.jgltf.model.impl.DefaultTextureModel;
import de.javagl.jgltf.model.io.Buffers;
import de.javagl.jgltf.model.io.IO;
import de.javagl.jgltf.model.io.v1.GltfAssetV1;
import de.javagl.jgltf.model.v1.gl.DefaultModels;
import de.javagl.jgltf.model.v1.gl.GltfDefaults;
import de.javagl.jgltf.model.v1.gl.Techniques;

/**
 * Implementation of a {@link GltfModel}, based on a {@link GlTF glTF 1.0}.
*/ public final class GltfModelV1 implements GltfModel { /** * The logger used in this class */ private static final Logger logger = Logger.getLogger(GltfModelV1.class.getName()); /** * The {@link GltfAssetV1} of this model */ private final GltfAssetV1 gltfAsset; /** * The {@link GlTF} of the {@link GltfAssetV1} */ private final GlTF gltf; /** * The binary data that is associated with this model in the case * that the glTF was a binary glTF */ private final ByteBuffer binaryData; /** * The {@link IndexMappingSet} */ private final IndexMappingSet indexMappingSet; /** * The {@link AccessorModel} instances that have been created from * the {@link Accessor} instances */ private final List accessorModels; /** * The {@link AnimationModel} instances that have been created from * the {@link Animation} instances */ private final List animationModels; /** * The {@link BufferModel} instances that have been created from * the {@link Buffer} instances */ private final List bufferModels; /** * The {@link BufferViewModel} instances that have been created from * the {@link Buffer} instances */ private final List bufferViewModels; /** * The {@link CameraModel} instances that have been created from * the {@link Camera} references of {@link Node} instances */ private final List cameraModels; /** * The {@link ImageModel} instances that have been created from * the {@link Image} references of {@link Node} instances */ private final List imageModels; /** * The {@link MaterialModel} instances that have been created from * the {@link Material} instances */ private final List materialModels; /** * The {@link MeshModel} instances that have been created from * the {@link Mesh} instances */ private final List meshModels; /** * The {@link NodeModel} instances that have been created from * the {@link Node} instances */ private final List nodeModels; /** * The {@link SceneModel} instances that have been created from * the {@link Scene} instances */ private final List sceneModels; /** * The {@link SkinModel} instances that have been created from * the {@link Skin} instances */ private final List skinModels; /** * The {@link TextureModel} instances that have been created from * the {@link Texture} instances */ private final List textureModels; /** * The {@link ShaderModel} instances that have been created from * the {@link Shader} instances */ private final List shaderModels; /** * The {@link ProgramModel} instances that have been created from * the {@link Program} instances */ private final List programModels; /** * The {@link TechniqueModel} instances that have been created from * the {@link Technique} instances */ private final List techniqueModels; /** * Creates a new model for the given glTF * * @param gltfAsset The {@link GltfAssetV1} */ public GltfModelV1(GltfAssetV1 gltfAsset) { this.gltfAsset = Objects.requireNonNull(gltfAsset, "The gltf may not be null"); this.gltf = gltfAsset.getGltf(); ByteBuffer binaryData = gltfAsset.getBinaryData(); if (binaryData != null && binaryData.capacity() > 0) { this.binaryData = binaryData; } else { this.binaryData = null; } this.indexMappingSet = IndexMappingSets.create(gltf); this.accessorModels = new ArrayList(); this.animationModels = new ArrayList(); this.bufferModels = new ArrayList(); this.bufferViewModels = new ArrayList(); this.cameraModels = new ArrayList(); this.imageModels = new ArrayList(); this.materialModels = new ArrayList(); this.meshModels = new ArrayList(); this.nodeModels = new ArrayList(); this.sceneModels = new ArrayList(); this.skinModels = new ArrayList(); this.textureModels = new ArrayList(); this.shaderModels = new ArrayList(); this.programModels = new ArrayList(); this.techniqueModels = new ArrayList(); createAccessorModels(); createAnimationModels(); createBufferModels(); createBufferViewModels(); createImageModels(); createMaterialModels(); createMeshModels(); createNodeModels(); createSceneModels(); createSkinModels(); createTextureModels(); createShaderModels(); createProgramModels(); createTechniqueModels(); initBufferModels(); initBufferViewModels(); initAccessorModels(); assignBufferViewByteStrides(); initAnimationModels(); initImageModels(); initMaterialModels(); initMeshModels(); initNodeModels(); initSceneModels(); initSkinModels(); initTextureModels(); initShaderModels(); initProgramModels(); initTechniqueModels(); instantiateCameraModels(); } /** * Returns the {@link BufferModel} for the {@link Buffer} with the given ID. * If the given ID is not valid, then a warning will be printed and * null will be returned. * * @param bufferId The {@link Buffer} ID * @return The {@link BufferModel} */ public BufferModel getBufferModelById(String bufferId) { return get("buffers", bufferId, bufferModels); } /** * Returns the {@link ShaderModel} for the {@link Shader} with the given ID. * If the given ID is not valid, then a warning will be printed and * null will be returned. * * @param shaderId The {@link Shader} ID * @return The {@link ShaderModel} */ public ShaderModel getShaderModelById(String shaderId) { return get("shaders", shaderId, shaderModels); } /** * Returns the {@link ImageModel} for the {@link Image} with the given ID. * If the given ID is not valid, then a warning will be printed and * null will be returned. * * @param imageId The {@link Image} ID * @return The {@link ImageModel} */ public ImageModel getImageModelById(String imageId) { return get("images", imageId, imageModels); } /** * Returns the {@link TextureModel} for the {@link Texture} with the given * ID. If the given ID is not valid, then a warning will be printed and * null will be returned.
*
* This is only used for supporting the legacy technique-based rendering. * * @param textureId The {@link Texture} ID * @return The {@link TextureModel} */ public TextureModel getTextureModelById(String textureId) { return get("textures", textureId, textureModels); } /** * Returns the {@link AccessorModel} for the {@link Accessor} with the * given ID. * If the given ID is not valid, then a warning will be printed and * null will be returned. * * @param accessorId The {@link Accessor} ID * @return The {@link AccessorModel} */ public AccessorModel getAccessorModelById(String accessorId) { return get("accessors", accessorId, accessorModels); } /** * Returns the {@link BufferViewModel} for the {@link BufferView} with the * given ID. * If the given ID is not valid, then a warning will be printed and * null will be returned. * * @param bufferViewId The {@link BufferView} ID * @return The {@link BufferViewModel} */ private BufferViewModel getBufferViewModelById(String bufferViewId) { return get("bufferViews", bufferViewId, bufferViewModels); } /** * Create the {@link AccessorModel} instances */ private void createAccessorModels() { Map accessors = Optionals.of(gltf.getAccessors()); for (Accessor accessor : accessors.values()) { DefaultAccessorModel accessorModel = createAccessorModel(accessor); accessorModels.add(accessorModel); } } /** * Create a {@link DefaultAccessorModel} for the given {@link Accessor} * * @param accessor The {@link Accessor} * @return The {@link AccessorModel} */ private static DefaultAccessorModel createAccessorModel(Accessor accessor) { Integer componentType = accessor.getComponentType(); Integer byteOffset = accessor.getByteOffset(); Integer count = accessor.getCount(); ElementType elementType = ElementType.forString(accessor.getType()); Integer byteStride = accessor.getByteStride(); if (byteStride == null) { byteStride = elementType.getNumComponents() * Accessors.getNumBytesForAccessorComponentType( componentType); } DefaultAccessorModel accessorModel = new DefaultAccessorModel( componentType, count, elementType); accessorModel.setByteOffset(byteOffset); accessorModel.setByteStride(byteStride); return accessorModel; } /** * Create the {@link AnimationModel} instances */ private void createAnimationModels() { Map animations = Optionals.of(gltf.getAnimations()); for (int i = 0; i < animations.size(); i++) { animationModels.add(new DefaultAnimationModel()); } } /** * Create the {@link BufferModel} instances */ private void createBufferModels() { Map buffers = Optionals.of(gltf.getBuffers()); for (Buffer buffer : buffers.values()) { DefaultBufferModel bufferModel = new DefaultBufferModel(); bufferModel.setUri(buffer.getUri()); bufferModels.add(bufferModel); } } /** * Create the {@link BufferViewModel} instances */ private void createBufferViewModels() { Map bufferViews = Optionals.of(gltf.getBufferViews()); for (BufferView bufferView : bufferViews.values()) { DefaultBufferViewModel bufferViewModel = createBufferViewModel(bufferView); bufferViewModels.add(bufferViewModel); } } /** * Create a {@link DefaultBufferViewModel} for the given {@link BufferView} * * @param bufferView The {@link BufferView} * @return The {@link BufferViewModel} */ private static DefaultBufferViewModel createBufferViewModel( BufferView bufferView) { int byteOffset = bufferView.getByteOffset(); Integer byteLength = bufferView.getByteLength(); if (byteLength == null) { logger.warning("No byteLength found in BufferView"); byteLength = 0; } Integer target = bufferView.getTarget(); DefaultBufferViewModel bufferViewModel = new DefaultBufferViewModel(target); bufferViewModel.setByteOffset(byteOffset); bufferViewModel.setByteLength(byteLength); return bufferViewModel; } /** * Create the {@link ImageModel} instances */ private void createImageModels() { Map images = Optionals.of(gltf.getImages()); for (Image image : images.values()) { DefaultImageModel imageModel = new DefaultImageModel(null, null); String uri = image.getUri(); imageModel.setUri(uri); imageModels.add(imageModel); } } /** * Create the {@link MaterialModel} instances */ private void createMaterialModels() { Map materials = Optionals.of(gltf.getMaterials()); for (int i = 0; i < materials.size(); i++) { materialModels.add(new DefaultMaterialModel()); } } /** * Create the {@link MeshModel} instances */ private void createMeshModels() { Map meshes = Optionals.of(gltf.getMeshes()); for (int i = 0; i < meshes.size(); i++) { meshModels.add(new DefaultMeshModel()); } } /** * Create the {@link NodeModel} instances */ private void createNodeModels() { Map nodes = Optionals.of(gltf.getNodes()); for (int i = 0; i < nodes.size(); i++) { nodeModels.add(new DefaultNodeModel()); } } /** * Create the {@link SceneModel} instances */ private void createSceneModels() { Map scenes = Optionals.of(gltf.getScenes()); for (int i = 0; i < scenes.size(); i++) { sceneModels.add(new DefaultSceneModel()); } } /** * Create the {@link SkinModel} instances */ private void createSkinModels() { Map skins = Optionals.of(gltf.getSkins()); for (Entry entry : skins.entrySet()) { Skin skin = entry.getValue(); float[] bindShapeMatrix = skin.getBindShapeMatrix(); skinModels.add(new DefaultSkinModel(bindShapeMatrix)); } } /** * Create the {@link TextureModel} instances */ private void createTextureModels() { Map textures = Optionals.of(gltf.getTextures()); Map samplers = Optionals.of(gltf.getSamplers()); for (Entry entry : textures.entrySet()) { Texture texture = entry.getValue(); String samplerId = texture.getSampler(); Sampler sampler = samplers.get(samplerId); int magFilter = Optionals.of( sampler.getMagFilter(), sampler.defaultMagFilter()); int minFilter = Optionals.of( sampler.getMinFilter(), sampler.defaultMinFilter()); int wrapS = Optionals.of( sampler.getWrapS(), sampler.defaultWrapS()); int wrapT = Optionals.of( sampler.getWrapT(), sampler.defaultWrapT()); textureModels.add(new DefaultTextureModel( magFilter, minFilter, wrapS, wrapT)); } } /** * Create the {@link ShaderModel} instances */ private void createShaderModels() { Map shaders = Optionals.of(gltf.getShaders()); for (Entry entry : shaders.entrySet()) { Shader shader = entry.getValue(); Integer type = shader.getType(); ShaderType shaderType = null; if (type == GltfConstants.GL_VERTEX_SHADER) { shaderType = ShaderType.VERTEX_SHADER; } else { shaderType = ShaderType.FRAGMENT_SHADER; } DefaultShaderModel shaderModel = new DefaultShaderModel(shader.getUri(), shaderType); shaderModels.add(shaderModel); } } /** * Create the {@link ProgramModel} instances */ private void createProgramModels() { Map programs = Optionals.of(gltf.getPrograms()); for (int i = 0; i < programs.size(); i++) { programModels.add(new DefaultProgramModel()); } } /** * Create the {@link TechniqueModel} instances */ private void createTechniqueModels() { Map techniques = Optionals.of(gltf.getTechniques()); for (int i = 0; i < techniques.size(); i++) { techniqueModels.add(new DefaultTechniqueModel()); } } /** * Initialize the {@link AccessorModel} instances */ private void initAccessorModels() { Map accessors = Optionals.of(gltf.getAccessors()); for (Entry entry : accessors.entrySet()) { String accessorId = entry.getKey(); Accessor accessor = entry.getValue(); String bufferViewId = accessor.getBufferView(); BufferViewModel bufferViewModel = get("bufferViews", bufferViewId, bufferViewModels); DefaultAccessorModel accessorModel = get("accessors", accessorId, accessorModels); accessorModel.setName(accessor.getName()); accessorModel.setBufferViewModel(bufferViewModel); } } /** * Initialize the {@link AnimationModel} instances */ private void initAnimationModels() { Map animations = Optionals.of(gltf.getAnimations()); for (Entry entry : animations.entrySet()) { String animationId = entry.getKey(); Animation animation = entry.getValue(); DefaultAnimationModel animationModel = get("animations", animationId, animationModels); animationModel.setName(animation.getName()); List channels = Optionals.of(animation.getChannels()); for (AnimationChannel animationChannel : channels) { Channel channel = createChannel(animation, animationChannel); animationModel.addChannel(channel); } } } /** * Initialize the {@link ImageModel} instances */ private void initImageModels() { Map images = Optionals.of(gltf.getImages()); for (Entry entry : images.entrySet()) { String imageId = entry.getKey(); Image image = entry.getValue(); DefaultImageModel imageModel = get("images", imageId, imageModels); imageModel.setName(image.getName()); if (BinaryGltfV1.hasBinaryGltfExtension(image)) { String bufferViewId = BinaryGltfV1.getBinaryGltfBufferViewId(image); BufferViewModel bufferViewModel = getBufferViewModelById(bufferViewId); imageModel.setBufferViewModel(bufferViewModel); } else { String uri = image.getUri(); if (IO.isDataUriString(uri)) { byte data[] = IO.readDataUri(uri); ByteBuffer imageData = Buffers.create(data); imageModel.setImageData(imageData); } else { ByteBuffer imageData = gltfAsset.getReferenceData(uri); imageModel.setImageData(imageData); } } } } /** * Create the {@link Channel} object for the given animation and animation * channel * * @param animation The {@link Animation} * @param animationChannel The {@link AnimationChannel} * @return The {@link Channel} */ private Channel createChannel( Animation animation, AnimationChannel animationChannel) { Map parameters = Optionals.of(animation.getParameters()); Map samplers = Optionals.of(animation.getSamplers()); String samplerId = animationChannel.getSampler(); AnimationSampler animationSampler = samplers.get(samplerId); String inputParameterId = animationSampler.getInput(); String inputAccessorId = parameters.get(inputParameterId); if (inputAccessorId == null) { // This was valid for a short time, when glTF 2.0 was still // called glTF 1.1. The check here is not perfectly reliable, // but there should be a decreasing number of glTF 1.0 models // out there, and even fewer glTF 1.1 ones. logger.warning( "Assuming " + inputParameterId + " to be an accessor ID"); inputAccessorId = inputParameterId; } DefaultAccessorModel inputAccessorModel = get("accessors", inputAccessorId, accessorModels); String outputParameterId = animationSampler.getOutput(); String outputAccessorId = parameters.get(outputParameterId); if (outputAccessorId == null) { // This was valid for a short time, when glTF 2.0 was still // called glTF 1.1. The check here is not perfectly reliable, // but there should be a decreasing number of glTF 1.0 models // out there, and even fewer glTF 1.1 ones. logger.warning( "Assuming " + outputParameterId + " to be an accessor ID"); outputAccessorId = outputParameterId; } DefaultAccessorModel outputAccessorModel = get("accessors", outputAccessorId, accessorModels); String interpolationString = animationSampler.getInterpolation(); Interpolation interpolation = interpolationString == null ? Interpolation.LINEAR : Interpolation.valueOf(interpolationString); AnimationModel.Sampler sampler = new DefaultSampler( inputAccessorModel, interpolation, outputAccessorModel); AnimationChannelTarget animationChannelTarget = animationChannel.getTarget(); String nodeId = animationChannelTarget.getId(); String path = animationChannelTarget.getPath(); NodeModel nodeModel = get("nodes", nodeId, nodeModels); AnimationModel.Channel channel = new DefaultChannel(sampler, nodeModel, path); return channel; } /** * Initialize the {@link BufferModel} instances */ private void initBufferModels() { Map buffers = Optionals.of(gltf.getBuffers()); for (Entry entry : buffers.entrySet()) { String bufferId = entry.getKey(); Buffer buffer = entry.getValue(); DefaultBufferModel bufferModel = get("buffers", bufferId, bufferModels); bufferModel.setName(buffer.getName()); if (BinaryGltfV1.isBinaryGltfBufferId(bufferId)) { if (binaryData == null) { logger.severe("The glTF contains a buffer with the binary" + " buffer ID, but no binary data has been given"); continue; } bufferModel.setBufferData(binaryData); } else { String uri = buffer.getUri(); if (IO.isDataUriString(uri)) { byte data[] = IO.readDataUri(uri); ByteBuffer bufferData = Buffers.create(data); bufferModel.setBufferData(bufferData); } else { ByteBuffer bufferData = gltfAsset.getReferenceData(uri); bufferModel.setBufferData(bufferData); } } } } /** * Initialize the {@link BufferViewModel} instances */ private void initBufferViewModels() { Map bufferViews = Optionals.of(gltf.getBufferViews()); for (Entry entry : bufferViews.entrySet()) { String bufferViewId = entry.getKey(); BufferView bufferView = entry.getValue(); String bufferId = bufferView.getBuffer(); BufferModel bufferModel = get("buffers", bufferId, bufferModels); DefaultBufferViewModel bufferViewModel = get("bufferViews", bufferViewId, bufferViewModels); bufferViewModel.setName(bufferView.getName()); bufferViewModel.setBufferModel(bufferModel); } } /** * Compute all {@link AccessorModel} instances that refer to the * given {@link BufferViewModel} * * @param bufferViewModel The {@link BufferViewModel} * @return The list of {@link AccessorModel} instances */ private List computeAccessorModelsOf( BufferViewModel bufferViewModel) { List result = new ArrayList(); for (DefaultAccessorModel accessorModel : accessorModels) { BufferViewModel b = accessorModel.getBufferViewModel(); if (bufferViewModel.equals(b)) { result.add(accessorModel); } } return result; } /** * Computes the {@link AccessorModel#getByteStride() byte stride} of * the given {@link AccessorModel} instances. If the given instances * do not have the same byte stride, then a warning will be printed. * * @param accessorModels The {@link AccessorModel} instances * @return The common byte stride */ private static int computeCommonByteStride( Iterable accessorModels) { int commonByteStride = -1; for (AccessorModel accessorModel : accessorModels) { int byteStride = accessorModel.getByteStride(); if (commonByteStride == -1) { commonByteStride = byteStride; } else { if (commonByteStride != byteStride) { logger.warning("The accessor models do not have the " + "same byte stride: " + commonByteStride + " and " + byteStride); } } } return commonByteStride; } /** * Set the {@link BufferViewModel#getByteStride() byte strides} of all * {@link BufferViewModel} instances, depending on the * {@link AccessorModel} instances that refer to them */ private void assignBufferViewByteStrides() { for (DefaultBufferViewModel bufferViewModel : bufferViewModels) { List accessorModelsOfBufferView = computeAccessorModelsOf(bufferViewModel); if (accessorModelsOfBufferView.size() > 1) { int byteStride = computeCommonByteStride(accessorModelsOfBufferView); bufferViewModel.setByteStride(byteStride); } } } /** * Initialize the {@link MeshModel} instances */ private void initMeshModels() { Map meshes = Optionals.of(gltf.getMeshes()); for (Entry entry : meshes.entrySet()) { String meshId = entry.getKey(); Mesh mesh = entry.getValue(); List primitives = Optionals.of(mesh.getPrimitives()); DefaultMeshModel meshModel = get("meshes", meshId, meshModels); meshModel.setName(mesh.getName()); for (MeshPrimitive meshPrimitive : primitives) { MeshPrimitiveModel meshPrimitiveModel = createMeshPrimitiveModel(meshPrimitive); meshModel.addMeshPrimitiveModel(meshPrimitiveModel); } } } /** * Create a {@link MeshPrimitiveModel} for the given {@link MeshPrimitive} * * @param meshPrimitive The {@link MeshPrimitive} * @return The {@link MeshPrimitiveModel} */ private DefaultMeshPrimitiveModel createMeshPrimitiveModel( MeshPrimitive meshPrimitive) { Integer mode = meshPrimitive.getMode(); if (mode == null) { mode = meshPrimitive.defaultMode(); } DefaultMeshPrimitiveModel meshPrimitiveModel = new DefaultMeshPrimitiveModel(mode); String indicesId = meshPrimitive.getIndices(); if (indicesId != null) { AccessorModel indices = get("accessors", indicesId, accessorModels); meshPrimitiveModel.setIndices(indices); } Map attributes = Optionals.of(meshPrimitive.getAttributes()); for (Entry entry : attributes.entrySet()) { String attributeName = entry.getKey(); String attributeId = entry.getValue(); AccessorModel attribute = get("accessors", attributeId, accessorModels); meshPrimitiveModel.putAttribute(attributeName, attribute); } String materialId = meshPrimitive.getMaterial(); if (materialId == null || GltfDefaults.isDefaultMaterialId(materialId)) { meshPrimitiveModel.setMaterialModel( DefaultModels.getDefaultMaterialModel()); } else { MaterialModel materialModel = get("materials", materialId, materialModels); meshPrimitiveModel.setMaterialModel(materialModel); } return meshPrimitiveModel; } /** * Initialize the {@link NodeModel} instances */ private void initNodeModels() { Map nodes = Optionals.of(gltf.getNodes()); for (Entry entry : nodes.entrySet()) { String nodeId = entry.getKey(); Node node = entry.getValue(); DefaultNodeModel nodeModel = get("nodes", nodeId, nodeModels); nodeModel.setName(node.getName()); List childIds = Optionals.of(node.getChildren()); for (String childId : childIds) { DefaultNodeModel child = get("nodes", childId, nodeModels); nodeModel.addChild(child); } List meshIds = Optionals.of(node.getMeshes()); for (String meshId : meshIds) { MeshModel meshModel = get("meshes", meshId, meshModels); nodeModel.addMeshModel(meshModel); } String skinId = node.getSkin(); if (skinId != null) { SkinModel skinModel = get("skins", skinId, skinModels); nodeModel.setSkinModel(skinModel); } float matrix[] = node.getMatrix(); float translation[] = node.getTranslation(); float rotation[] = node.getRotation(); float scale[] = node.getScale(); nodeModel.setMatrix( matrix == null ? null : matrix.clone()); nodeModel.setTranslation( translation == null ? null : translation.clone()); nodeModel.setRotation( rotation == null ? null : rotation.clone()); nodeModel.setScale( scale == null ? null : scale.clone()); } } /** * Initialize the {@link SceneModel} instances */ private void initSceneModels() { Map scenes = Optionals.of(gltf.getScenes()); for (Entry entry : scenes.entrySet()) { String sceneId = entry.getKey(); Scene scene = entry.getValue(); DefaultSceneModel sceneModel = get("scenes", sceneId, sceneModels); sceneModel.setName(scene.getName()); List nodes = Optionals.of(scene.getNodes()); for (String nodeId : nodes) { NodeModel nodeModel = get("nodes", nodeId, nodeModels); sceneModel.addNode(nodeModel); } } } /** * Compute the mapping from joint names to the ID of the {@link Node} with * the respective {@link Node#getJointName() joint name} * * @param gltf The {@link GlTF} * @return The mapping */ private static Map computeJointNameToNodeIdMap(GlTF gltf) { Map map = new LinkedHashMap(); Map nodes = Optionals.of(gltf.getNodes()); for (Entry entry : nodes.entrySet()) { String nodeId = entry.getKey(); Node node = entry.getValue(); if (node.getJointName() != null) { String oldNodeId = map.put(node.getJointName(), nodeId); if (oldNodeId != null) { logger.warning("Joint name " + node.getJointName() + " is mapped to nodes with IDs " + nodeId + " and " + oldNodeId); } } } return map; } /** * Initialize the {@link SkinModel} instances */ private void initSkinModels() { Map jointNameToNodeIdMap = computeJointNameToNodeIdMap(gltf); Map skins = Optionals.of(gltf.getSkins()); for (Entry entry : skins.entrySet()) { String skinId = entry.getKey(); Skin skin = entry.getValue(); DefaultSkinModel skinModel = get("skins", skinId, skinModels); skinModel.setName(skin.getName()); List jointNames = skin.getJointNames(); for (String jointName : jointNames) { String nodeId = jointNameToNodeIdMap.get(jointName); NodeModel nodeModel = get("nodes", nodeId, nodeModels); skinModel.addJoint(nodeModel); } String inverseBindMatricesId = skin.getInverseBindMatrices(); DefaultAccessorModel inverseBindMatrices = get("accessors", inverseBindMatricesId, accessorModels); skinModel.setInverseBindMatrices(inverseBindMatrices); } } /** * Initialize the {@link TextureModel} instances */ private void initTextureModels() { Map textures = Optionals.of(gltf.getTextures()); for (Entry entry : textures.entrySet()) { String textureId = entry.getKey(); Texture texture = entry.getValue(); DefaultTextureModel textureModel = get("textures", textureId, textureModels); textureModel.setName(texture.getName()); String imageId = texture.getSource(); DefaultImageModel imageModel = get("images", imageId, imageModels); textureModel.setImageModel(imageModel); } } /** * Initialize the {@link ShaderModel} instances */ private void initShaderModels() { Map shaders = Optionals.of(gltf.getShaders()); for (Entry entry : shaders.entrySet()) { String shaderId = entry.getKey(); Shader shader = entry.getValue(); DefaultShaderModel shaderModel = get("shaders", shaderId, shaderModels); shaderModel.setName(shader.getName()); if (BinaryGltfV1.hasBinaryGltfExtension(shader)) { String bufferViewId = BinaryGltfV1.getBinaryGltfBufferViewId(shader); BufferViewModel bufferViewModel = getBufferViewModelById(bufferViewId); shaderModel.setShaderData(bufferViewModel.getBufferViewData()); } else { String uri = shader.getUri(); if (IO.isDataUriString(uri)) { byte data[] = IO.readDataUri(uri); ByteBuffer shaderData = Buffers.create(data); shaderModel.setShaderData(shaderData); } else { ByteBuffer shaderData = gltfAsset.getReferenceData(uri); shaderModel.setShaderData(shaderData); } } } } /** * Initialize the {@link ProgramModel} instances */ void initProgramModels() { Map programs = Optionals.of(gltf.getPrograms()); for (Entry entry : programs.entrySet()) { String programId = entry.getKey(); Program program = entry.getValue(); DefaultProgramModel programModel = get("programs", programId, programModels); programModel.setName(program.getName()); String vertexShaderId = program.getVertexShader(); DefaultShaderModel vertexShaderModel = get("shaders", vertexShaderId, shaderModels); programModel.setVertexShaderModel(vertexShaderModel); String fragmentShaderId = program.getFragmentShader(); DefaultShaderModel fragmentShaderModel = get("shaders", fragmentShaderId, shaderModels); programModel.setFragmentShaderModel(fragmentShaderModel); } } /** * Add all {@link TechniqueParametersModel} instances for the * attributes of the given {@link Technique} to the given * {@link TechniqueModel} * * @param technique The {@link Technique} * @param techniqueModel The {@link TechniqueModel} */ private void addParameters(Technique technique, DefaultTechniqueModel techniqueModel) { Map parameters = Optionals.of(technique.getParameters()); for (Entry entry : parameters.entrySet()) { String parameterName = entry.getKey(); TechniqueParameters parameter = entry.getValue(); int type = parameter.getType(); int count = Optionals.of(parameter.getCount(), 1); String semantic = parameter.getSemantic(); Object value = parameter.getValue(); String nodeId = parameter.getNode(); NodeModel nodeModel = null; if (nodeId != null) { nodeModel = get("nodes", nodeId, nodeModels); } TechniqueParametersModel techniqueParametersModel = new DefaultTechniqueParametersModel( type, count, semantic, value, nodeModel); techniqueModel.addParameter( parameterName, techniqueParametersModel); } } /** * Add all attribute entries of the given {@link Technique} to the given * {@link TechniqueModel} * * @param technique The {@link Technique} * @param techniqueModel The {@link TechniqueModel} */ private static void addAttributes(Technique technique, DefaultTechniqueModel techniqueModel) { Map attributes = Optionals.of(technique.getAttributes()); for (Entry entry : attributes.entrySet()) { String attributeName = entry.getKey(); String parameterName = entry.getValue(); techniqueModel.addAttribute(attributeName, parameterName); } } /** * Add all uniform entries of the given {@link Technique} to the given * {@link TechniqueModel} * * @param technique The {@link Technique} * @param techniqueModel The {@link TechniqueModel} */ private static void addUniforms(Technique technique, DefaultTechniqueModel techniqueModel) { Map uniforms = Optionals.of(technique.getUniforms()); for (Entry entry : uniforms.entrySet()) { String uniformName = entry.getKey(); String parameterName = entry.getValue(); techniqueModel.addUniform(uniformName, parameterName); } } /** * Initialize the {@link TechniqueModel} instances */ private void initTechniqueModels() { Map techniques = Optionals.of(gltf.getTechniques()); for (Entry entry : techniques.entrySet()) { String techniqueId = entry.getKey(); Technique technique = entry.getValue(); DefaultTechniqueModel techniqueModel = get("techniques", techniqueId, techniqueModels); techniqueModel.setName(technique.getName()); String programId = technique.getProgram(); DefaultProgramModel programModel = get("programs", programId, programModels); techniqueModel.setProgramModel(programModel); addParameters(technique, techniqueModel); addAttributes(technique, techniqueModel); addUniforms(technique, techniqueModel); List enable = Techniques.obtainEnabledStates(technique); TechniqueStatesFunctions functions = Techniques.obtainTechniqueStatesFunctions(technique); TechniqueStatesFunctionsModel techniqueStatesFunctionsModel = new DefaultTechniqueStatesFunctionsModelV1(functions); TechniqueStatesModel techniqueStatesModel = new DefaultTechniqueStatesModel( enable, techniqueStatesFunctionsModel); techniqueModel.setTechniqueStatesModel(techniqueStatesModel); } } /** * Initialize the {@link MaterialModel} instances */ private void initMaterialModels() { Map materials = Optionals.of(gltf.getMaterials()); for (Entry entry : materials.entrySet()) { String materialId = entry.getKey(); Material material = entry.getValue(); DefaultMaterialModel materialModel = get("materials", materialId, materialModels); materialModel.setValues(material.getValues()); materialModel.setName(material.getName()); String techniqueId = material.getTechnique(); if (techniqueId == null || GltfDefaults.isDefaultTechniqueId(techniqueId)) { materialModel.setTechniqueModel( DefaultModels.getDefaultTechniqueModel()); } else { DefaultTechniqueModel techniqueModel = get("techniques", techniqueId, techniqueModels); materialModel.setTechniqueModel(techniqueModel); } } } /** * Create the {@link CameraModel} instances. This has to be be called * after the {@link #nodeModels} have been created: Each time * that a node refers to a camera, a new instance of this camera * has to be created. */ private void instantiateCameraModels() { Map nodes = Optionals.of(gltf.getNodes()); Map cameras = Optionals.of(gltf.getCameras()); for (Entry entry : nodes.entrySet()) { String nodeId = entry.getKey(); Node node = entry.getValue(); String cameraId = node.getCamera(); if (cameraId != null) { Camera camera = cameras.get(cameraId); NodeModel nodeModel = get("nodes", nodeId, nodeModels); Function viewMatrixComputer = result -> { float localResult[] = Utils.validate(result, 16); nodeModel.computeGlobalTransform(localResult); MathUtils.invert4x4(localResult, localResult); return localResult; }; BiFunction projectionMatrixComputer = (result, aspectRatio) -> { float localResult[] = Utils.validate(result, 16); CamerasV1.computeProjectionMatrix( camera, aspectRatio, localResult); return localResult; }; DefaultCameraModel cameraModel = new DefaultCameraModel( viewMatrixComputer, projectionMatrixComputer); cameraModel.setName(camera.getName()); cameraModel.setNodeModel(nodeModel); String nodeName = Optionals.of(node.getName(), nodeId); String cameraName = Optionals.of(camera.getName(), cameraId); String instanceName = nodeName + "." + cameraName; cameraModel.setInstanceName(instanceName); cameraModels.add(cameraModel); } } } @Override public List getAccessorModels() { return Collections.unmodifiableList(accessorModels); } @Override public List getAnimationModels() { return Collections.unmodifiableList(animationModels); } @Override public List getBufferModels() { return Collections.unmodifiableList(bufferModels); } @Override public List getBufferViewModels() { return Collections.unmodifiableList(bufferViewModels); } @Override public List getCameraModels() { return Collections.unmodifiableList(cameraModels); } @Override public List getImageModels() { return Collections.unmodifiableList(imageModels); } @Override public List getMaterialModels() { return Collections.unmodifiableList(materialModels); } @Override public List getNodeModels() { return Collections.unmodifiableList(nodeModels); } @Override public List getSceneModels() { return Collections.unmodifiableList(sceneModels); } @Override public List getTextureModels() { return Collections.unmodifiableList(textureModels); } /** * Returns an unmodifiable view on the list of {@link ShaderModel} * instances that have been created for the glTF. * * @return The {@link ShaderModel} instances */ public List getShaderModels() { return Collections.unmodifiableList(shaderModels); } /** * Returns the raw glTF object, which is a * {@link de.javagl.jgltf.impl.v1.GlTF version 1.0 glTF}.
*
* This method should usually not be called by clients. It may be * omitted in future versions. * * @return The glTF object */ public GlTF getGltf() { return gltf; } /** * Return the element from the given list, based on the * {@link #indexMappingSet} for the given name and ID. * If the ID is null, then null is * returned. If there is no proper index stored for the given * ID, then a warning will be printed and null * will be returned. If the index is not valid for the given * list, then a warning will be printed, and null * will be returned. * * @param name The name * @param id The ID * @param list The list * @return The element */ private T get(String name, String id, List list) { Integer index = indexMappingSet.getIndex(name, id); if (index == null) { logger.severe("No index found for " + name + " ID " + id); return null; } if (index < 0 || index >= list.size()) { logger.severe("Index for " + name + " ID " + id + " is " + index + ", but must be in [0, " + list.size() + ")"); return null; } T element = list.get(index); return element; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy