Search in sources :

Example 6 with Element

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

the class ColladaLoader method parseMeshData.

protected void parseMeshData(Element rootElement) throws ColladaParseException {
    vertices = new TFloatArrayList();
    texCoord0 = new TFloatArrayList();
    texCoord1 = new TFloatArrayList();
    normals = new TFloatArrayList();
    colors = new TFloatArrayList();
    indices = new TIntArrayList();
    int vertCount = 0;
    ElementSet upAxisSet = rootElement.find("asset", "up_axis");
    if (1 != upAxisSet.size()) {
        throw new ColladaParseException("Found multiple up_axis asset values");
    }
    Element upAxisElement = upAxisSet.first();
    String upAxis = upAxisElement.text();
    ElementSet unitSet = rootElement.find("asset", "unit");
    if (1 != unitSet.size()) {
        throw new ColladaParseException("Found multiple unit asset values");
    }
    Element unitElement = unitSet.first();
    String unitsPerMeterString = unitElement.attr("meter");
    if (null != unitsPerMeterString) {
        unitsPerMeter = Double.parseDouble(unitsPerMeterString);
    }
    boolean yUp = "Y_UP".equals(upAxis);
    boolean zUp = "Z_UP".equals(upAxis);
    boolean xUp = "X_UP".equals(upAxis);
    if (xUp) {
        throw new ColladaParseException("Not supporting X_UP as the upAxis value yet.");
    }
    // TODO: we shouldn't just cram everything into a single mesh, but should expect separate meshes with differing materials
    ElementSet geometrySet = rootElement.find("library_geometries", "geometry");
    for (Element geometry : geometrySet) {
        ElementSet meshSet = geometry.find("mesh");
        if (1 != meshSet.size()) {
            throw new ColladaParseException("Found " + meshSet.size() + " mesh sets for geometry id=" + geometry.id() + " name=" + geometry.name());
        }
        logger.info("Parsing geometry id=" + geometry.id() + " name=" + geometry.name());
        for (Element mesh : meshSet) {
            ElementSet trianglesSet = mesh.find("triangles");
            for (Element triangles : trianglesSet) {
                vertCount = parseTriangles(rootElement, vertices, texCoord0, normals, indices, colors, vertCount, geometry, mesh, triangles, yUp, zUp);
            }
            ElementSet polylistSet = mesh.find("polylist");
            for (Element polylist : polylistSet) {
                ElementSet vCountSet = polylist.find("vcount");
                if (1 != vCountSet.size()) {
                    throw new ColladaParseException("Found " + vCountSet.size() + " vcount sets for polylist in geometry id=" + geometry.id() + " name=" + geometry.name());
                }
                Element vCountElement = vCountSet.first();
                TIntList vcountList = new TIntArrayList();
                String[] vCountStrings = getItemsInString(vCountElement.text());
                for (String string : vCountStrings) {
                    int vCount = Integer.parseInt(string);
                    vcountList.add(vCount);
                }
                vertCount = parseFaces(rootElement, vcountList, vertices, texCoord0, normals, indices, colors, vertCount, geometry, mesh, polylist, yUp, zUp);
            }
        }
    }
}
Also used : ElementSet(org.eaxy.ElementSet) Element(org.eaxy.Element) TIntList(gnu.trove.list.TIntList) TIntArrayList(gnu.trove.list.array.TIntArrayList) TFloatArrayList(gnu.trove.list.array.TFloatArrayList)

Example 7 with Element

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

the class ColladaLoader method parseMeshData.

public void parseMeshData(InputStream inputStream) throws ColladaParseException, IOException {
    Document document = Xml.readAndClose(inputStream);
    Element rootElement = document.getRootElement();
    parseMeshData(rootElement);
}
Also used : Element(org.eaxy.Element) Document(org.eaxy.Document)

Example 8 with Element

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

the class ColladaLoader method parseInputs.

private List<Input> parseInputs(ElementSet inputElementSet) {
    List<Input> inputList = new ArrayList<>();
    for (Element inputElement : inputElementSet) {
        Input input = new Input();
        inputList.add(input);
        input.semantic = inputElement.attr("semantic");
        input.sourceName = inputElement.attr("source");
        String offsetString = inputElement.attr("offset");
        if (null != offsetString) {
            input.offset = Integer.parseInt(offsetString);
        }
    }
    return inputList;
}
Also used : Element(org.eaxy.Element) TIntArrayList(gnu.trove.list.array.TIntArrayList) ArrayList(java.util.ArrayList) TFloatArrayList(gnu.trove.list.array.TFloatArrayList)

Example 9 with Element

use of org.eaxy.Element 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)9 ElementSet (org.eaxy.ElementSet)6 TFloatArrayList (gnu.trove.list.array.TFloatArrayList)3 TIntArrayList (gnu.trove.list.array.TIntArrayList)3 Document (org.eaxy.Document)3 TIntList (gnu.trove.list.TIntList)2 ArrayList (java.util.ArrayList)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 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