Example usage for com.google.common.io LittleEndianDataOutputStream flush

List of usage examples for com.google.common.io LittleEndianDataOutputStream flush

Introduction

In this page you can find the example usage for com.google.common.io LittleEndianDataOutputStream flush.

Prototype

@Override
public void flush() throws IOException 

Source Link

Document

Flushes this output stream and forces any buffered output bytes to be written out to the stream.

Usage

From source file:org.bimserver.serializers.binarygeometry.BinaryGeometrySerializer.java

private void writeGeometries(OutputStream outputStream) throws IOException {
    long start = System.nanoTime();

    LittleEndianDataOutputStream dataOutputStream = new LittleEndianDataOutputStream(outputStream);
    // Identifier for clients to determine if this server is even serving binary geometry
    dataOutputStream.writeUTF("BGS");

    // Version of the current format being outputted, should be changed for every (released) change in protocol 
    dataOutputStream.writeByte(FORMAT_VERSION);

    Bounds modelBounds = new Bounds();
    int nrObjects = 0;

    // All access to EClass is being done generically to support multiple IFC schema's with 1 serializer
    EClass productClass = getModel().getPackageMetaData().getEClass("IfcProduct");

    List<IdEObject> products = getModel().getAllWithSubTypes(productClass);

    // First iteration, to determine number of objects with geometry and calculate model bounds
    for (IdEObject ifcProduct : products) {
        GeometryInfo geometryInfo = (GeometryInfo) ifcProduct
                .eGet(ifcProduct.eClass().getEStructuralFeature("geometry"));
        if (geometryInfo != null && geometryInfo.getTransformation() != null) {
            Bounds objectBounds = new Bounds(
                    new Float3(geometryInfo.getMinBounds().getX(), geometryInfo.getMinBounds().getY(),
                            geometryInfo.getMinBounds().getZ()),
                    new Float3(geometryInfo.getMaxBounds().getX(), geometryInfo.getMaxBounds().getY(),
                            geometryInfo.getMaxBounds().getZ()));
            modelBounds.integrate(objectBounds);
            nrObjects++;//from   w  ww .ja  v a 2s .  co m
        }
    }
    modelBounds.writeTo(dataOutputStream);
    dataOutputStream.writeInt(nrObjects);
    int bytesSaved = 0;
    int bytesTotal = 0;

    // Keeping track of geometry already sent, this can be used for instancing of reused geometry
    Set<Long> concreteGeometrySent = new HashSet<>();

    // Flushing here so the client can show progressbar etc...
    dataOutputStream.flush();

    int bytes = 6;
    int counter = 0;

    // Second iteration actually writing the geometry
    for (IdEObject ifcProduct : products) {
        GeometryInfo geometryInfo = (GeometryInfo) ifcProduct
                .eGet(ifcProduct.eClass().getEStructuralFeature("geometry"));
        if (geometryInfo != null && geometryInfo.getTransformation() != null) {
            String type = ifcProduct.eClass().getName();
            dataOutputStream.writeUTF(type);
            dataOutputStream.writeLong(ifcProduct.getOid());

            GeometryData geometryData = geometryInfo.getData();
            byte[] vertices = geometryData.getVertices();

            // BEWARE, ByteOrder is always LITTLE_ENDIAN, because that's what GPU's seem to prefer, Java's ByteBuffer default is BIG_ENDIAN though!

            bytesTotal += vertices.length;
            byte geometryType = concreteGeometrySent.contains(geometryData.getOid()) ? GEOMETRY_TYPE_INSTANCE
                    : GEOMETRY_TYPE_TRIANGLES;
            dataOutputStream.write(geometryType);

            bytes += (type.getBytes(Charsets.UTF_8).length + 3);

            // This is an ugly hack to align the bytes, but for 2 different kinds of output (this first one is the websocket implementation)
            int skip = 4 - (bytes % 4); // TODO fix
            if (skip != 0 && skip != 4) {
                dataOutputStream.write(new byte[skip]);
            }

            bytes = 0;

            dataOutputStream.write(geometryInfo.getTransformation());

            if (concreteGeometrySent.contains(geometryData.getOid())) {
                // Reused geometry, only send the id of the reused geometry data
                dataOutputStream.writeLong(geometryData.getOid());
                bytesSaved += vertices.length;
            } else {
                ByteBuffer vertexByteBuffer = ByteBuffer.wrap(vertices);
                dataOutputStream.writeLong(geometryData.getOid());

                Bounds objectBounds = new Bounds(geometryInfo.getMinBounds(), geometryInfo.getMaxBounds());
                objectBounds.writeTo(dataOutputStream);

                ByteBuffer indicesBuffer = ByteBuffer.wrap(geometryData.getIndices());
                dataOutputStream.writeInt(indicesBuffer.capacity() / 4);
                dataOutputStream.write(indicesBuffer.array());

                dataOutputStream.writeInt(vertexByteBuffer.capacity() / 4);
                dataOutputStream.write(vertexByteBuffer.array());

                ByteBuffer normalsBuffer = ByteBuffer.wrap(geometryData.getNormals());
                dataOutputStream.writeInt(normalsBuffer.capacity() / 4);
                dataOutputStream.write(normalsBuffer.array());

                // Only when materials are used we send them
                if (geometryData.getMaterials() != null) {
                    ByteBuffer materialsByteBuffer = ByteBuffer.wrap(geometryData.getMaterials());

                    dataOutputStream.writeInt(materialsByteBuffer.capacity() / 4);
                    dataOutputStream.write(materialsByteBuffer.array());
                } else {
                    // No materials used
                    dataOutputStream.writeInt(0);
                }

                concreteGeometrySent.add(geometryData.getOid());
            }
            counter++;
            if (counter % 12 == 0) {
                // Flushing in batches, this is to limit the amount of WebSocket messages
                dataOutputStream.flush();
            }
        }
    }
    dataOutputStream.flush();
    if (bytesTotal != 0 && bytesSaved != 0) {
        LOGGER.info((100 * bytesSaved / bytesTotal) + "% saved");
    }
    long end = System.nanoTime();
    LOGGER.debug(((end - start) / 1000000) + " ms");
}