/*
* Copyright (c) 2015 NOVA, All rights reserved.
* This library is free software, licensed under GNU Lesser General Public License version 3
*
* This file is part of NOVA.
*
* NOVA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NOVA. If not, see <http://www.gnu.org/licenses/>.
*/
package nova.core.render.model;
import nova.core.util.collection.TreeNode;
import nova.core.util.math.MatrixStack;
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* A model is a 3D object capable of taking transformations.
*
* @author Calclavia
*/
public abstract class Model extends TreeNode<Model> implements Cloneable {
/**
* The name of the model
*/
public final String name;
/**
* The transformation matrix.
*/
public MatrixStack matrix = new MatrixStack();
//TODO: There should be a better method to handle this.
//GL Blending
public int blendSFactor = -1;
public int blendDFactor = -1;
/**
* Creates named model.
*
* @param name to be used.
*/
public Model(String name) {
this.name = Objects.requireNonNull(name, "Model name cannot be null!");
}
/**
* Creates unnamed model.
*/
public Model() {
this("");
}
public Set<Model> flatten() {
return flatten(new MatrixStack());
}
/**
* Flattens the model into a set of models with no additional transformations,
* applying all the transformations into the individual vertices.
*
* @param matrixStack transformation matrix.
* @return Resulting set of models
*/
public abstract Set<Model> flatten(MatrixStack matrixStack);
/**
* Combines child models with names into one model with its children being the children selected.
*
* @param newModelName The new name for the model
* @param names The names of the child models
* @return The new model containing all the children.
*/
public Model combineChildren(String newModelName, String... names) {
return combineChildren(newModelName, m -> Arrays.asList(names).contains(m.name));
}
/**
* Combines child models with names into one model with its children being the children selected.
*
* @param newModelName The new name for the model
* @param predicate The condition to select children
* @return The new model containing all the children.
*/
public Model combineChildren(String newModelName, Predicate<Model> predicate) {
Model newModel = newModel(newModelName);
Set<Model> combineChildren = children
.stream()
.filter(predicate)
.collect(Collectors.toSet());
newModel.children.addAll(combineChildren);
children.removeAll(combineChildren);
children.add(newModel);
return newModel;
}
protected abstract Model newModel(String name);
@Override
public Model clone() {
Model model = newModel(name);
model.children.addAll(stream().map(Model::clone).collect(Collectors.toSet()));
model.matrix = new MatrixStack(matrix);
return model;
}
@Override
public String toString() {
return "Model['" + name + "', " + children.size() + " children]";
}
}