use of com.jme3.scene.shape.Line in project jmonkeyengine by jMonkeyEngine.
the class CurvesTemporalMesh method applyBevelAndTaper.
/**
* This method applies bevel and taper objects to the curve.
* @param curve
* the curve we apply the objects to
* @param bevelObject
* the bevel object
* @param taperObject
* the taper object
* @param blenderContext
* the blender context
* @return a list of geometries representing the beveled and/or tapered curve
* @throws BlenderFileException
* an exception is thrown when problems with reading occur
*/
private CurvesTemporalMesh applyBevelAndTaper(CurvesTemporalMesh curve, CurvesTemporalMesh bevelObject, CurvesTemporalMesh taperObject, BlenderContext blenderContext) throws BlenderFileException {
List<BezierLine> bevelBezierLines = bevelObject.getScaledBeziers();
List<BezierLine> curveLines = curve.beziers;
if (bevelBezierLines.size() == 0 || curveLines.size() == 0) {
return null;
}
CurvesTemporalMesh result = new CurvesTemporalMesh(blenderContext);
for (BezierLine curveLine : curveLines) {
Vector3f[] curveLineVertices = curveLine.getVertices(bevelStart, bevelEnd);
for (BezierLine bevelBezierLine : bevelBezierLines) {
CurvesTemporalMesh partResult = new CurvesTemporalMesh(blenderContext);
Vector3f[] bevelLineVertices = bevelBezierLine.getVertices();
List<Vector3f[]> bevels = new ArrayList<Vector3f[]>();
Vector3f[] bevelPoints = curvesHelper.transformToFirstLineOfBevelPoints(bevelLineVertices, curveLineVertices[0], curveLineVertices[1]);
bevels.add(bevelPoints);
for (int i = 1; i < curveLineVertices.length - 1; ++i) {
bevelPoints = curvesHelper.transformBevel(bevelPoints, curveLineVertices[i - 1], curveLineVertices[i], curveLineVertices[i + 1]);
bevels.add(bevelPoints);
}
bevelPoints = curvesHelper.transformBevel(bevelPoints, curveLineVertices[curveLineVertices.length - 2], curveLineVertices[curveLineVertices.length - 1], null);
bevels.add(bevelPoints);
Vector3f subtractResult = new Vector3f();
if (bevels.size() > 2) {
// changing the first and last bevel so that they are parallel to their neighbours (blender works this way)
// notice this implicates that the distances of every corresponding point in the two bevels must be identical and
// equal to the distance between the points on curve that define the bevel position
// so instead doing complicated rotations on each point we will simply properly translate each of them
int[][] pointIndexes = new int[][] { { 0, 1 }, { curveLineVertices.length - 1, curveLineVertices.length - 2 } };
for (int[] indexes : pointIndexes) {
float distance = curveLineVertices[indexes[1]].subtract(curveLineVertices[indexes[0]], subtractResult).length();
Vector3f[] bevel = bevels.get(indexes[0]);
Vector3f[] nextBevel = bevels.get(indexes[1]);
for (int i = 0; i < bevel.length; ++i) {
float d = bevel[i].subtract(nextBevel[i], subtractResult).length();
subtractResult.normalizeLocal().multLocal(distance - d);
bevel[i].addLocal(subtractResult);
}
}
}
if (taperObject != null) {
float curveLength = curveLine.getLength(), lengthAlongCurve = bevelStart;
for (int i = 0; i < curveLineVertices.length; ++i) {
if (i > 0) {
lengthAlongCurve += curveLineVertices[i].subtract(curveLineVertices[i - 1], subtractResult).length();
}
float taperScale = -taperObject.getValueAlongCurve(lengthAlongCurve / curveLength).z * taperObject.scale.z;
if (taperScale != 1) {
this.applyScale(bevels.get(i), curveLineVertices[i], taperScale);
}
}
}
// adding vertices to the part result
for (Vector3f[] bevel : bevels) {
for (Vector3f d : bevel) {
partResult.getVertices().add(d);
}
}
// preparing faces for the part result (each face is a quad)
int bevelVertCount = bevelPoints.length;
for (int i = 0; i < bevels.size() - 1; ++i) {
for (int j = 0; j < bevelVertCount - 1; ++j) {
Integer[] indexes = new Integer[] { i * bevelVertCount + j + 1, (i + 1) * bevelVertCount + j + 1, (i + 1) * bevelVertCount + j, i * bevelVertCount + j };
partResult.getFaces().add(new Face(indexes, curveLine.isSmooth(), curveLine.getMaterialNumber(), null, null, partResult));
partResult.getEdges().add(new Edge(indexes[0], indexes[1], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[1], indexes[2], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[2], indexes[3], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[3], indexes[0], 0, true, partResult));
}
if (bevelBezierLine.isCyclic()) {
int j = bevelVertCount - 1;
Integer[] indexes = new Integer[] { i * bevelVertCount, (i + 1) * bevelVertCount, (i + 1) * bevelVertCount + j, i * bevelVertCount + j };
partResult.getFaces().add(new Face(indexes, curveLine.isSmooth(), curveLine.getMaterialNumber(), null, null, partResult));
partResult.getEdges().add(new Edge(indexes[0], indexes[1], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[1], indexes[2], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[2], indexes[3], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[3], indexes[0], 0, true, partResult));
}
}
partResult.generateNormals();
if (fillCaps) {
// caps in blender behave as if they weren't affected by the smooth factor
// START CAP
Vector3f[] cap = bevels.get(0);
List<Integer> capIndexes = new ArrayList<Integer>(cap.length);
Vector3f capNormal = curveLineVertices[0].subtract(curveLineVertices[1]).normalizeLocal();
for (int i = 0; i < cap.length; ++i) {
capIndexes.add(partResult.getVertices().size());
partResult.getVertices().add(cap[i]);
partResult.getNormals().add(capNormal);
}
// the indexes ned to be reversed for the face to have fron face outside the beveled line
Collections.reverse(capIndexes);
partResult.getFaces().add(new Face(capIndexes.toArray(new Integer[capIndexes.size()]), false, curveLine.getMaterialNumber(), null, null, partResult));
for (int i = 1; i < capIndexes.size(); ++i) {
partResult.getEdges().add(new Edge(capIndexes.get(i - 1), capIndexes.get(i), 0, true, partResult));
}
// END CAP
cap = bevels.get(bevels.size() - 1);
capIndexes.clear();
capNormal = curveLineVertices[curveLineVertices.length - 1].subtract(curveLineVertices[curveLineVertices.length - 2]).normalizeLocal();
for (int i = 0; i < cap.length; ++i) {
capIndexes.add(partResult.getVertices().size());
partResult.getVertices().add(cap[i]);
partResult.getNormals().add(capNormal);
}
partResult.getFaces().add(new Face(capIndexes.toArray(new Integer[capIndexes.size()]), false, curveLine.getMaterialNumber(), null, null, partResult));
for (int i = 1; i < capIndexes.size(); ++i) {
partResult.getEdges().add(new Edge(capIndexes.get(i - 1), capIndexes.get(i), 0, true, partResult));
}
}
result.append(partResult);
}
}
return result;
}
use of com.jme3.scene.shape.Line in project jmonkeyengine by jMonkeyEngine.
the class Face method contains.
/**
* The method verifies if the edge is contained within the face.
* It means it cannot cross any other edge and it must be inside the face and not outside of it.
* @param edge
* the edge to be checked
* @return <b>true</b> if the given edge is contained within the face and <b>false</b> otherwise
*/
private boolean contains(Edge edge) {
int index1 = edge.getFirstIndex();
int index2 = edge.getSecondIndex();
// check if the line between the vertices is not a border edge of the face
if (!indexes.areNeighbours(index1, index2)) {
for (int i = 0; i < indexes.size(); ++i) {
int i1 = this.getIndex(i - 1);
int i2 = this.getIndex(i);
// check if the edges have no common verts (because if they do, they cannot cross)
if (i1 != index1 && i1 != index2 && i2 != index1 && i2 != index2) {
if (edge.cross(new Edge(i1, i2, 0, false, temporalMesh))) {
return false;
}
}
}
// computing the edge's middle point
Vector3f edgeMiddlePoint = edge.computeCentroid();
// computing the edge that is perpendicular to the given edge and has a length of 1 (length actually does not matter)
Vector3f edgeVector = edge.getSecondVertex().subtract(edge.getFirstVertex());
Vector3f edgeNormal = temporalMesh.getNormals().get(index1).cross(edgeVector).normalizeLocal();
Edge e = new Edge(edgeMiddlePoint, edgeNormal.add(edgeMiddlePoint));
// compute the vectors from the middle point to the crossing between the extended edge 'e' and other edges of the face
List<Vector3f> crossingVectors = new ArrayList<Vector3f>();
for (int i = 0; i < indexes.size(); ++i) {
int i1 = this.getIndex(i);
int i2 = this.getIndex(i + 1);
Vector3f crossPoint = e.getCrossPoint(new Edge(i1, i2, 0, false, temporalMesh), true, false);
if (crossPoint != null) {
crossingVectors.add(crossPoint.subtractLocal(edgeMiddlePoint));
}
}
if (crossingVectors.size() == 0) {
// edges do not cross
return false;
}
// use only distinct vertices (doubles may appear if the crossing point is a vertex)
List<Vector3f> distinctCrossingVectors = new ArrayList<Vector3f>();
for (Vector3f cv : crossingVectors) {
double minDistance = Double.MAX_VALUE;
for (Vector3f dcv : distinctCrossingVectors) {
minDistance = Math.min(minDistance, dcv.distance(cv));
}
if (minDistance > FastMath.FLT_EPSILON) {
distinctCrossingVectors.add(cv);
}
}
if (distinctCrossingVectors.size() == 0) {
throw new IllegalStateException("There MUST be at least 2 crossing vertices!");
}
// checking if all crossing vectors point to the same direction (if yes then the edge is outside the face)
// if at least one vector has different direction that this - it means that the edge is inside the face
float direction = Math.signum(distinctCrossingVectors.get(0).dot(edgeNormal));
for (int i = 1; i < distinctCrossingVectors.size(); ++i) {
if (direction != Math.signum(distinctCrossingVectors.get(i).dot(edgeNormal))) {
return true;
}
}
return false;
}
return true;
}
use of com.jme3.scene.shape.Line in project jmonkeyengine by jMonkeyEngine.
the class Line method updatePoints.
/**
* Update the start and end points of the line.
*/
public void updatePoints(Vector3f start, Vector3f end) {
VertexBuffer posBuf = getBuffer(Type.Position);
FloatBuffer fb = (FloatBuffer) posBuf.getData();
fb.rewind();
fb.put(start.x).put(start.y).put(start.z);
fb.put(end.x).put(end.y).put(end.z);
posBuf.updateData(fb);
updateBound();
}
use of com.jme3.scene.shape.Line in project jmonkeyengine by jMonkeyEngine.
the class ShaderNodeLoaderDelegate method readShaderNodeDefinition.
/**
* effectively reads the ShaderNodesDefinitions block
*
* @param statements the list of statements to parse
* @param key the ShaderNodeDefinitionKey
* @throws IOException
*/
protected void readShaderNodeDefinition(List<Statement> statements, ShaderNodeDefinitionKey key) throws IOException {
boolean isLoadDoc = key instanceof ShaderNodeDefinitionKey && ((ShaderNodeDefinitionKey) key).isLoadDocumentation();
for (Statement statement : statements) {
String[] split = statement.getLine().split("[ \\{]");
String line = statement.getLine();
if (line.startsWith("Type")) {
String type = line.substring(line.lastIndexOf(':') + 1).trim();
shaderNodeDefinition.setType(Shader.ShaderType.valueOf(type));
} else if (line.startsWith("Shader ")) {
readShaderStatement(statement);
shaderNodeDefinition.getShadersLanguage().add(shaderLanguage);
shaderNodeDefinition.getShadersPath().add(shaderName);
} else if (line.startsWith("Documentation")) {
if (isLoadDoc) {
String doc = "";
for (Statement statement1 : statement.getContents()) {
doc += "\n" + statement1.getLine();
}
shaderNodeDefinition.setDocumentation(doc);
}
} else if (line.startsWith("Input")) {
varNames = "";
for (Statement statement1 : statement.getContents()) {
shaderNodeDefinition.getInputs().add(readVariable(statement1));
}
} else if (line.startsWith("Output")) {
varNames = "";
for (Statement statement1 : statement.getContents()) {
if (statement1.getLine().trim().equals("None")) {
shaderNodeDefinition.setNoOutput(true);
} else {
shaderNodeDefinition.getOutputs().add(readVariable(statement1));
}
}
} else {
throw new MatParseException("one of Type, Shader, Documentation, Input, Output", split[0], statement);
}
}
}
use of com.jme3.scene.shape.Line in project jmonkeyengine by jMonkeyEngine.
the class ShaderNodeLoaderDelegate method readShaderNode.
/**
* reads a list of ShaderNode{} blocks
*
* @param statements the list of statements to parse
* @throws IOException
*/
protected void readShaderNode(List<Statement> statements) throws IOException {
for (Statement statement : statements) {
String line = statement.getLine();
String[] split = statement.getLine().split("[ \\{]");
if (line.startsWith("Definition")) {
ShaderNodeDefinition def = findDefinition(statement);
shaderNode.setDefinition(def);
if (def.isNoOutput()) {
techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(shaderNode.getName());
}
} else if (line.startsWith("Condition")) {
String condition = line.substring(line.lastIndexOf(":") + 1).trim();
extractCondition(condition, statement);
shaderNode.setCondition(conditionParser.getFormattedExpression());
} else if (line.startsWith("InputMapping")) {
for (Statement statement1 : statement.getContents()) {
VariableMapping mapping = readInputMapping(statement1);
techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(mapping.getRightVariable().getNameSpace());
shaderNode.getInputMapping().add(mapping);
}
} else if (line.startsWith("OutputMapping")) {
for (Statement statement1 : statement.getContents()) {
VariableMapping mapping = readOutputMapping(statement1);
techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(shaderNode.getName());
shaderNode.getOutputMapping().add(mapping);
}
} else {
throw new MatParseException("ShaderNodeDefinition", split[0], statement);
}
}
}
Aggregations