Search in sources :

Example 6 with ElementSet

use of org.eaxy.ElementSet in project Terasology by MovingBlocks.

the class ColladaLoader method parseFaces.

private int parseFaces(Element rootElement, TIntList vcountList, TFloatList verticesParam, TFloatList texCoord0Param, TFloatList normalsParam, TIntList indicesParam, TFloatList colorsParam, int vertCountParam, Element geometry, Element mesh, Element faces, boolean yUp, boolean zUp) throws ColladaParseException {
    int vertCount = vertCountParam;
    String faceCountString = faces.attr("count");
    int faceCount = Integer.parseInt(faceCountString);
    ElementSet faceInputSet = faces.find("input");
    List<Input> faceInputs = parseInputs(faceInputSet);
    String facesMaterial = faces.attr("material");
    float[] vertexColors = null;
    ElementSet libraryMaterialsSet = rootElement.find("library_materials");
    if (0 != libraryMaterialsSet.size()) {
        if (1 != libraryMaterialsSet.size()) {
            throw new ColladaParseException("Found " + libraryMaterialsSet.size() + " library Material sets for geometry id=" + geometry.id() + " name=" + geometry.name());
        }
        Element libraryMaterials = libraryMaterialsSet.first();
        Element material;
        try {
            // TODO: this one isn't standard like the others, and sometimes it doesn't exist
            material = libraryMaterials.select("#" + facesMaterial);
            if (null == material) {
                throw new ColladaParseException("No material for " + facesMaterial + " for geometry id=" + geometry.id() + " name=" + geometry.name());
            }
            ElementSet instanceEffectSet = material.find("instance_effect");
            if (1 != instanceEffectSet.size()) {
                throw new ColladaParseException("Found " + instanceEffectSet.size() + " instance_effect sets for material " + facesMaterial + " for geometry id=" + geometry.id() + " name=" + geometry.name());
            }
            Element instanceEffect = instanceEffectSet.first();
            String effectUrl = instanceEffect.attr("url");
            ElementSet libraryEffectsSet = rootElement.find("library_effects");
            if (0 != libraryEffectsSet.size()) {
                if (1 != libraryEffectsSet.size()) {
                    throw new ColladaParseException("Found " + libraryEffectsSet.size() + " library effects sets for geometry id=" + geometry.id() + " name=" + geometry.name());
                }
                Element libraryEffects = libraryEffectsSet.first();
                Element effect = libraryEffects.select(effectUrl);
                if (null == effect) {
                    throw new ColladaParseException("No effect for " + effectUrl + " for geometry id=" + geometry.id() + " name=" + geometry.name());
                }
                ElementSet colorSet = effect.find("profile_COMMON", "technique", "lambert", "diffuse", "color");
                if (1 == colorSet.size()) {
                    Element color = colorSet.first();
                    String colorListString = color.text();
                    String[] colorString = getItemsInString(colorListString);
                    if (4 != colorString.length) {
                        throw new ColladaParseException("mesh only supports 4-float color arrays but color list was '" + colorListString + "' for geometry id=" + geometry.id() + " name=" + geometry.name());
                    }
                    vertexColors = new float[colorString.length];
                    for (int i = 0; i < colorString.length; i++) {
                        vertexColors[i] = Float.parseFloat(colorString[i]);
                    }
                }
            }
        } catch (NonMatchingPathException e) {
            // If we don't find the material, then we're done.
            logger.debug("Material not found, skipping", e);
        }
    }
    for (Input faceInput : faceInputs) {
        if ("VERTEX".equals(faceInput.semantic)) {
            ElementSet verticesSet = mesh.find("vertices");
            if (1 != verticesSet.size()) {
                throw new ColladaParseException("Found " + verticesSet.size() + " vertices sets for geometry id=" + geometry.id() + " name=" + geometry.name());
            }
            Element verticesElement = verticesSet.first();
            ElementSet verticesInputSet = verticesElement.find("input");
            List<Input> verticesInputs = parseInputs(verticesInputSet);
            for (Input vertexInput : verticesInputs) {
                if ("POSITION".equals(vertexInput.semantic)) {
                    Element vertexSourceElement = mesh.select(vertexInput.sourceName);
                    faceInput.vertexPositionSource = parseSource(vertexSourceElement);
                } else if ("NORMAL".equals(vertexInput.semantic)) {
                    Element normalSourceElement = mesh.select(vertexInput.sourceName);
                    faceInput.vertexNormalSource = parseSource(normalSourceElement);
                } else {
                    throw new ColladaParseException("Found unexpected vertex Input semantic " + vertexInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name());
                }
            }
        } else if ("NORMAL".equals(faceInput.semantic)) {
            Element normalSourceElement = mesh.select(faceInput.sourceName);
            faceInput.normalSource = parseSource(normalSourceElement);
            if (3 != faceInput.normalSource.stride) {
                throw new ColladaParseException("Found stride of " + faceInput.normalSource.stride + " for triangle Input semantic " + faceInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name());
            }
        } else if ("TEXCOORD".equals(faceInput.semantic)) {
            Element texCoordSourceElement = mesh.select(faceInput.sourceName);
            faceInput.texCoordSource = parseSource(texCoordSourceElement);
            if (2 != faceInput.texCoordSource.stride) {
                logger.warn("Found non-2 stride of " + faceInput.texCoordSource.stride + " for vertex Input semantic " + faceInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name() + ". Ignoring all but first two texture coordinate values.");
            }
        } else {
            throw new ColladaParseException("Found unexpected triangle Input semantic " + faceInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name());
        }
    }
    ElementSet faceDataSet = faces.find("p");
    if (1 != faceDataSet.size()) {
        throw new ColladaParseException("Found " + faceDataSet.size() + " triangleData sets for geometry id=" + geometry.id() + " name=" + geometry.name());
    }
    Element faceData = faceDataSet.first();
    String faceDataString = faceData.text();
    String[] facesStrings = getItemsInString(faceDataString);
    // TODO: for now, assume the offsets will always perfectly match the sorted-by-offset list indexes
    Collections.sort(faceInputs, (i1, i2) -> i1.offset - i2.offset);
    for (int i = 0; i < faceInputs.size(); i++) {
        Input input = faceInputs.get(i);
        if (input.offset != i) {
            throw new ColladaParseException("Triangle input list offset does not match list index for triangle input " + input + " for geometry id=" + geometry.id() + " name=" + geometry.name());
        }
    }
    int facesDataIndex = -1;
    for (int faceIndex = 0; faceIndex < faceCount; faceIndex++) {
        // default to 3 for triangles so we don't have to create a vcountList
        int vCount = 3;
        if (null != vcountList) {
            vCount = vcountList.get(faceIndex);
        }
        for (int vertexIndex = 0; vertexIndex < vCount; vertexIndex++) {
            for (Input faceInput : faceInputs) {
                ++facesDataIndex;
                String indexString = facesStrings[facesDataIndex];
                int index = Integer.parseInt(indexString);
                if ("VERTEX".equals(faceInput.semantic)) {
                    int vertexStride = faceInput.vertexPositionSource.stride;
                    if (3 != vertexStride) {
                        throw new ColladaParseException("Found non-3 stride of " + faceInput.vertexPositionSource.stride + " for vertex Input semantic " + faceInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name());
                    }
                    // TODO: probably should consider parameter indexes instead of assuming X,Y,Z order
                    float vertexX = faceInput.vertexPositionSource.floatValues[index * vertexStride + 0];
                    float vertexY = faceInput.vertexPositionSource.floatValues[index * vertexStride + 1];
                    float vertexZ = faceInput.vertexPositionSource.floatValues[index * vertexStride + 2];
                    // for up_axis coordinate systems
                    if (yUp) {
                        verticesParam.add(vertexX);
                        verticesParam.add(vertexY);
                        verticesParam.add(vertexZ);
                    } else if (zUp) {
                        verticesParam.add(vertexX);
                        verticesParam.add(vertexZ);
                        // negated compared to z in yUp
                        verticesParam.add(vertexY);
                    // TODO: Y is not negated relative to the orgin like it probably needs to be.
                    // } else if (xUp) {
                    // verticesParam.add(vertexY); // negated compared to x in yUp
                    // verticesParam.add(vertexX);
                    // verticesParam.add(vertexZ);
                    }
                    if (null != vertexColors) {
                        for (float vertexColor : vertexColors) {
                            colorsParam.add(vertexColor);
                        }
                    }
                    // TODO: Sometimes we get the normal attached to the triangle, sometimes to the vertex
                    if (null != faceInput.vertexNormalSource) {
                        int normalStride = faceInput.vertexNormalSource.stride;
                        if (3 != normalStride) {
                            throw new ColladaParseException("Found non-3 stride of " + faceInput.vertexNormalSource.stride + " for vertex Input semantic " + faceInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name());
                        }
                        // TODO: probably should consider parameter indexes instead of assuming X,Y,Z order
                        float normalX = faceInput.vertexNormalSource.floatValues[index * normalStride + 0];
                        float normalY = faceInput.vertexNormalSource.floatValues[index * normalStride + 1];
                        float normalZ = faceInput.vertexNormalSource.floatValues[index * normalStride + 2];
                        if (yUp) {
                            normalsParam.add(normalX);
                            normalsParam.add(normalY);
                            normalsParam.add(normalZ);
                        } else if (zUp) {
                            normalsParam.add(normalX);
                            normalsParam.add(normalZ);
                            normalsParam.add(normalY);
                        }
                    }
                // // TODO: how to triangulate faces on the fly
                // indicesParam.add(vertCount++);
                } else if ("NORMAL".equals(faceInput.semantic)) {
                    // TODO: Sometimes we get the normal attached to the triangle, sometimes to the vertex
                    int normalStride = faceInput.normalSource.stride;
                    if (3 != normalStride) {
                        throw new ColladaParseException("Found non-3 stride of " + faceInput.normalSource.stride + " for vertex Input semantic " + faceInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name());
                    }
                    // TODO: probably should consider parameter indexes instead of assuming X,Y,Z order
                    float normalX = faceInput.normalSource.floatValues[index * normalStride + 0];
                    float normalY = faceInput.normalSource.floatValues[index * normalStride + 1];
                    float normalZ = faceInput.normalSource.floatValues[index * normalStride + 2];
                    if (yUp) {
                        normalsParam.add(normalX);
                        normalsParam.add(normalY);
                        normalsParam.add(normalZ);
                    } else if (zUp) {
                        normalsParam.add(normalX);
                        normalsParam.add(normalZ);
                        normalsParam.add(normalY);
                    }
                } else if ("TEXCOORD".equals(faceInput.semantic)) {
                    int texCoordStride = faceInput.texCoordSource.stride;
                    if (2 > texCoordStride) {
                        throw new ColladaParseException("Found non-2 stride of " + faceInput.texCoordSource.stride + " for vertex Input semantic " + faceInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name());
                    }
                    // TODO: probably should consider parameter indexes instead of assuming S,T order
                    float texCoordS = faceInput.texCoordSource.floatValues[index * texCoordStride + 0];
                    float texCoordT = faceInput.texCoordSource.floatValues[index * texCoordStride + 1];
                    // For texture coordinates, COLLADA's right-handed coordinate system applies;
                    // therefore, an ST texture coordinate of [0,0] maps to the lower-left texel of a texture image
                    texCoord0Param.add(texCoordS);
                    texCoord0Param.add(1 - texCoordT);
                // texCoord0.add(texCoordT);
                } else {
                    throw new ColladaParseException("Found unexpected triangle Input semantic " + faceInput.semantic + " for geometry id=" + geometry.id() + " name=" + geometry.name());
                }
            }
        }
        for (int i = 0; i < vCount - 2; ++i) {
            indices.add(vertCount);
            indices.add(vertCount + i + 1);
            indices.add(vertCount + i + 2);
        }
        vertCount += vCount;
    }
    return vertCount;
}
Also used : ElementSet(org.eaxy.ElementSet) Element(org.eaxy.Element) NonMatchingPathException(org.eaxy.NonMatchingPathException)

Aggregations

Element (org.eaxy.Element)6 ElementSet (org.eaxy.ElementSet)6 TIntList (gnu.trove.list.TIntList)2 TFloatArrayList (gnu.trove.list.array.TFloatArrayList)2 TIntArrayList (gnu.trove.list.array.TIntArrayList)2 NonMatchingPathException (org.eaxy.NonMatchingPathException)2 Quat4f (org.terasology.math.geom.Quat4f)2 Vector3f (org.terasology.math.geom.Vector3f)2 Lists (com.google.common.collect.Lists)1 TFloatList (gnu.trove.list.TFloatList)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 Collections (java.util.Collections)1 Deque (java.util.Deque)1 HashMap (java.util.HashMap)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Map (java.util.Map)1