Giter Site home page Giter Site logo

Comments (6)

ArMouReR avatar ArMouReR commented on July 22, 2024 2

Adding solution just in case someone will land here form Google:

// The glTF SDK is decoupled from all file I/O by the IStreamWriter (and IStreamReader)
// interface(s) and the C++ stream-based I/O library. This allows the glTF SDK to be used in
// sandboxed environments, such as WebAssembly modules and UWP apps, where any file I/O code
// must be platform or use-case specific.
class StreamWriter : public Microsoft::glTF::IStreamWriter
{
public:
    // Resolves the relative URIs of any external resources declared in the glTF manifest

    StreamWriter()
        : m_streams()
    {
    }

    //{
    //    auto stream = std::make_shared<std::ofstream>(filename, std::ios_base::binary);
    //    return stream;
    //}

    std::shared_ptr<std::ostream> GetOutputStream(const std::string& uri) const override
    {
        return GetStream(true);
    }

    std::shared_ptr<std::istream> getReferenceToOutputStream() const  {
        return GetStream(false);
    }

private:
    std::shared_ptr<std::iostream> GetStream(const bool getNewStream) const
    {
        if (getNewStream) {
            m_streams["0"] = std::make_shared<std::stringstream>();
        }
        return m_streams["0"];
    }

    mutable std::unordered_map<std::string, std::shared_ptr<std::stringstream>> m_streams;
};

And the function for save. need to remove one of std::moves...

static void writeToGlbFile(const std::string &fileName, const std::vector<Point3f>& points, const std::vector<Vec3f>& normals, const std::vector<int>& indices, const Vec3b &color, std::shared_ptr<std::istream> & stream)
{
    // Pass the absolute path, without the filename, to the stream writer
    auto streamWriter = std::make_shared<StreamWriter>();

    std::unique_ptr< Microsoft::glTF::ResourceWriter> resourceWriter;

    // create a GLBResourceWriter. This class derives
    // from GLTFResourceWriter and adds support for writing manifests to a GLB container's
    // JSON chunk and resource data to the binary chunk.
    resourceWriter = std::make_unique< Microsoft::glTF::GLBResourceWriter>(streamWriter);

    // The Document instance represents the glTF JSON manifest
    Microsoft::glTF::Document document;

    std::string accessorIdIndices;
    std::string accessorIdPositions;
    std::string accessorIdNormals;

    // Use the BufferBuilder helper class to simplify the process of
    // constructing valid glTF Buffer, BufferView and Accessor entities
    Microsoft::glTF::BufferBuilder bufferBuilder(std::move(resourceWriter));

    Microsoft::glTF::Color4 glbColor((float)color[0] / 255.0f, (float)color[1] / 255.0f, (float)color[2] / 255.0f, 1.0f);
    CreateTriangleResources(document, bufferBuilder, accessorIdIndices, accessorIdPositions, accessorIdNormals, points, normals, indices);
    CreateTriangleEntities(document, accessorIdIndices, accessorIdPositions, accessorIdNormals, glbColor);

    std::string manifest;

    // Serialize the glTF Document into a JSON manifest
    manifest = Serialize(document, Microsoft::glTF::SerializeFlags::Pretty);

    auto glbResourceWriter = dynamic_cast<Microsoft::glTF::GLBResourceWriter*>(&bufferBuilder.GetResourceWriter());
    glbResourceWriter->Flush(manifest, fileName); // A GLB container isn't created until the GLBResourceWriter::Flush member function is called
    stream = streamWriter->getReferenceToOutputStream();

}```

from gltf-sdk.

chriche-ms avatar chriche-ms commented on July 22, 2024 1

The serialize sample is a better example of how to implement a simple stream writer. The gltf/glb resource writers construct an LRU stream cache by default so there is no need to retain a reference to all the streams created by the writer like the test does (I think the unit test @bghgary linked to predates the stream caching functionality).

from gltf-sdk.

chriche-ms avatar chriche-ms commented on July 22, 2024 1

Sorry, I pointed you to the sample code without fully taking into account what you are trying to achieve!

The IStreamWriter interface has caused a fair bit of confusion and many times it's been asked why there isn't a simple and straightforward way to write to a file (or in your case a stream). This part of the SDK is relatively complex because the glTF spec provides different ways to store buffer data (data uri, external buffer files, glb blob etc.) and the SDK has to support all of them. For example, even when creating a glb there will be multiple output streams involved if you write to multiple buffers.

If you can ensure that any glb you create only contains the default buffer then you can do as @bghgary suggested and store a pointer to the first (only?) stream created by the stream writer and access it after flushing the resource writer. Alternatively, you could implement a custom stream cache that makes the streams stored by the resource writer publicly accessible.

Finally, the uri passed to the stream writer doesn't have to be a file name - for your scenario it would only be used to uniquely identify a particular stream.

from gltf-sdk.

bghgary avatar bghgary commented on July 22, 2024

I'm not sure what your code looks like, but you can do something like this:

class StreamReaderWriter : public Microsoft::glTF::IStreamWriter, public Microsoft::glTF::IStreamReader
{
public:
StreamReaderWriter()
: m_streams()
{
}
std::shared_ptr<std::ostream> GetOutputStream(const std::string& uri) const override
{
return GetStream(uri);
}
std::shared_ptr<std::istream> GetInputStream(const std::string& uri) const override
{
return GetStream(uri);
}
private:
std::shared_ptr<std::iostream> GetStream(const std::string& uri) const
{
if (m_streams.find(uri) == m_streams.end())
{
m_streams[uri] = std::make_shared<std::stringstream>();
}
return m_streams[uri];
}
mutable std::unordered_map<std::string, std::shared_ptr<std::stringstream>> m_streams;
};

Create your own writer and then do something like this:

GLTFSDK_TEST_METHOD(GLBResourceWriterTests, WriteBufferView_Empty_Bin)
{
auto streamWriter = std::make_shared<const StreamReaderWriter>();
GLBResourceWriter writer(streamWriter);
std::string uri = "foo.glb";
// Serialize Default Document -> Json string -> Stream
Document doc;
const auto serialiedJson = Serialize(doc, SerializeFlags::None);
writer.Flush(serialiedJson, uri);
auto stream = streamWriter->GetInputStream(uri);
// Deserialize Stream -> Document
GLBResourceReader resourceReader(streamWriter, stream);
Document roundTrippedDoc = Deserialize(resourceReader.GetJson());
Assert::IsFalse(stream->fail());
Assert::IsTrue(doc == roundTrippedDoc);
}

from gltf-sdk.

ArMouReR avatar ArMouReR commented on July 22, 2024

Thanks to all for explanations, but if I am checking "The serialize sample", the only relevant part as I understand is:

        auto& gltfResourceWriter = bufferBuilder.GetResourceWriter();

        if (auto glbResourceWriter = dynamic_cast<GLBResourceWriter*>(&gltfResourceWriter))
        {
            glbResourceWriter->Flush(manifest, pathFile.u8string()); // A GLB container isn't created until the GLBResourceWriter::Flush member function is called
        }
        else
        {
            gltfResourceWriter.WriteExternal(pathFile.u8string(), manifest); // Binary resources have already been written, just need to write the manifest
}

And here pathFile.u8string() is still file, while I am looking for stream.

from gltf-sdk.

ArMouReR avatar ArMouReR commented on July 22, 2024

@chriche-ms & @bghgary thanks for explanations, I have used the way suggested by you and used @bghgary example and I do see when I do flush() my string stream is used.
But I got stuck with C++ features, I want to get access to the stream but I don't understand how: the original object is std:moved twice, so when I want to get pointer to the string stream the streamWriter object is empty.

Here is part of my code:

The StreamWriter class:

class StreamWriter : public Microsoft::glTF::IStreamWriter, Microsoft::glTF::IStreamReader
{
public:
    // Resolves the relative URIs of any external resources declared in the glTF manifest

    StreamWriter()
        : m_streams()
    {
    }

    //{
    //    auto stream = std::make_shared<std::ofstream>(filename, std::ios_base::binary);
    //    return stream;
    //}

    std::shared_ptr<std::ostream> GetOutputStream(const std::string& uri) const override
    {
        return GetStream(uri);
    }

    std::shared_ptr<std::istream> GetInputStream(const std::string& uri) const override {
        return GetStream(uri);
    }

private:
    std::shared_ptr<std::iostream> GetStream(const std::string& uri) const
    {
        if (m_streams.find(uri) == m_streams.end()) {
            m_streams[uri] = std::make_shared<std::stringstream>();
        }
        return m_streams[uri];
    }

    mutable std::unordered_map<std::string, std::shared_ptr<std::stringstream>> m_streams;
    //std::shared_ptr<std::stringstream> binFile;
    std::string m_pathBase;
};

And the actual save function:

static void writeToGlbFile(const std::string &fileName, const std::vector<Point3f>& points, const std::vector<Vec3f>& normals, const std::vector<int>& indices, const Vec3b &color, std::shared_ptr<std::istream> & stream)
{
    // Pass the absolute path, without the filename, to the stream writer
    auto streamWriter = std::make_unique<StreamWriter>();

    std::unique_ptr< Microsoft::glTF::ResourceWriter> resourceWriter;

    // create a GLBResourceWriter. This class derives
    // from GLTFResourceWriter and adds support for writing manifests to a GLB container's
    // JSON chunk and resource data to the binary chunk.
    resourceWriter = std::make_unique< Microsoft::glTF::GLBResourceWriter>(std::move(streamWriter));

    // The Document instance represents the glTF JSON manifest
    Microsoft::glTF::Document document;

    std::string accessorIdIndices;
    std::string accessorIdPositions;
    std::string accessorIdNormals;

    // Use the BufferBuilder helper class to simplify the process of
    // constructing valid glTF Buffer, BufferView and Accessor entities
    Microsoft::glTF::BufferBuilder bufferBuilder(std::move(resourceWriter));

    Microsoft::glTF::Color4 glbColor((float)color[0] / 255.0f, (float)color[1] / 255.0f, (float)color[2] / 255.0f, 1.0f);
    CreateTriangleResources(document, bufferBuilder, accessorIdIndices, accessorIdPositions, accessorIdNormals, points, normals, indices);
    CreateTriangleEntities(document, accessorIdIndices, accessorIdPositions, accessorIdNormals, glbColor);

    std::string manifest;

    // Serialize the glTF Document into a JSON manifest
    manifest = Serialize(document, Microsoft::glTF::SerializeFlags::Pretty);

    auto glbResourceWriter = dynamic_cast<Microsoft::glTF::GLBResourceWriter*>(&bufferBuilder.GetResourceWriter());
    glbResourceWriter->Flush(manifest, fileName); // A GLB container isn't created until the GLBResourceWriter::Flush member function is called


    auto streamWriterNew = dynamic_cast<StreamWriter*>(&bufferBuilder.GetResourceWriter());
    stream = streamWriterNew->GetInputStream(fileName);
}

So, what I don't understand is how to get access to GetInputStream() and get back pointer to string stream.
The original object is moved and empty now, and bufferBuilder or glbResourceWriter do not have access to this.

from gltf-sdk.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.