2016-09-09 05:06:06 +02:00
|
|
|
/*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-02-18 11:23:17 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup balembic
|
|
|
|
|
*/
|
|
|
|
|
|
2016-09-09 05:06:06 +02:00
|
|
|
#include "abc_archive.h"
|
2019-04-17 06:17:24 +02:00
|
|
|
extern "C" {
|
|
|
|
|
#include "BKE_blender_version.h"
|
2019-09-19 15:55:03 +02:00
|
|
|
#include "BKE_main.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_path_util.h"
|
|
|
|
|
#include "BLI_string.h"
|
2019-11-19 12:45:43 +01:00
|
|
|
|
|
|
|
|
#include "DNA_scene_types.h"
|
2017-05-25 15:23:45 -06:00
|
|
|
}
|
2017-05-24 11:45:14 +02:00
|
|
|
|
2016-09-09 05:06:06 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
|
# include "utfconv.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-04-25 14:30:01 +02:00
|
|
|
#include <fstream>
|
|
|
|
|
|
2016-09-09 05:06:06 +02:00
|
|
|
using Alembic::Abc::ErrorHandler;
|
2019-04-17 06:17:24 +02:00
|
|
|
using Alembic::Abc::Exception;
|
2016-09-09 05:06:06 +02:00
|
|
|
using Alembic::Abc::IArchive;
|
|
|
|
|
using Alembic::Abc::kWrapExisting;
|
|
|
|
|
using Alembic::Abc::OArchive;
|
|
|
|
|
|
|
|
|
|
static IArchive open_archive(const std::string &filename,
|
|
|
|
|
const std::vector<std::istream *> &input_streams,
|
|
|
|
|
bool &is_hdf5)
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
is_hdf5 = false;
|
2017-04-25 14:30:01 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
try {
|
|
|
|
|
Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams);
|
2016-09-09 05:06:06 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return IArchive(archive_reader(filename), kWrapExisting, ErrorHandler::kThrowPolicy);
|
|
|
|
|
}
|
|
|
|
|
catch (const Exception &e) {
|
|
|
|
|
std::cerr << e.what() << '\n';
|
2016-09-09 05:06:06 +02:00
|
|
|
|
|
|
|
|
#ifdef WITH_ALEMBIC_HDF5
|
2019-04-17 06:17:24 +02:00
|
|
|
try {
|
|
|
|
|
is_hdf5 = true;
|
|
|
|
|
Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr;
|
|
|
|
|
|
|
|
|
|
return IArchive(Alembic::AbcCoreHDF5::ReadArchive(),
|
|
|
|
|
filename.c_str(),
|
|
|
|
|
ErrorHandler::kThrowPolicy,
|
|
|
|
|
cache_ptr);
|
|
|
|
|
}
|
|
|
|
|
catch (const Exception &) {
|
|
|
|
|
std::cerr << e.what() << '\n';
|
|
|
|
|
return IArchive();
|
|
|
|
|
}
|
2016-09-09 05:06:06 +02:00
|
|
|
#else
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Inspect the file to see whether it's really a HDF5 file. */
|
|
|
|
|
char header[4]; /* char(0x89) + "HDF" */
|
|
|
|
|
std::ifstream the_file(filename.c_str(), std::ios::in | std::ios::binary);
|
|
|
|
|
if (!the_file) {
|
|
|
|
|
std::cerr << "Unable to open " << filename << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else if (!the_file.read(header, sizeof(header))) {
|
|
|
|
|
std::cerr << "Unable to read from " << filename << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else if (strncmp(header + 1, "HDF", 3)) {
|
|
|
|
|
std::cerr << filename << " has an unknown file format, unable to read." << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
is_hdf5 = true;
|
|
|
|
|
std::cerr << filename << " is in the obsolete HDF5 format, unable to read." << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (the_file.is_open()) {
|
|
|
|
|
the_file.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IArchive();
|
2016-09-09 05:06:06 +02:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-09-09 05:06:06 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return IArchive();
|
2016-09-09 05:06:06 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-19 15:55:03 +02:00
|
|
|
ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename)
|
2016-09-09 05:06:06 +02:00
|
|
|
{
|
2019-09-19 15:55:03 +02:00
|
|
|
char abs_filename[FILE_MAX];
|
|
|
|
|
BLI_strncpy(abs_filename, filename, FILE_MAX);
|
|
|
|
|
BLI_path_abs(abs_filename, BKE_main_blendfile_path(bmain));
|
|
|
|
|
|
2016-09-09 05:06:06 +02:00
|
|
|
#ifdef WIN32
|
2019-09-19 15:55:03 +02:00
|
|
|
UTF16_ENCODE(abs_filename);
|
2019-09-19 17:10:50 +02:00
|
|
|
std::wstring wstr(abs_filename_16);
|
2019-04-17 06:17:24 +02:00
|
|
|
m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary);
|
2019-09-19 15:55:03 +02:00
|
|
|
UTF16_UN_ENCODE(abs_filename);
|
2016-09-09 05:06:06 +02:00
|
|
|
#else
|
2019-09-19 15:55:03 +02:00
|
|
|
m_infile.open(abs_filename, std::ios::in | std::ios::binary);
|
2016-09-09 05:06:06 +02:00
|
|
|
#endif
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
m_streams.push_back(&m_infile);
|
2016-09-09 05:06:06 +02:00
|
|
|
|
2019-09-19 15:55:03 +02:00
|
|
|
m_archive = open_archive(abs_filename, m_streams, m_is_hdf5);
|
2016-09-09 05:06:06 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* We can't open an HDF5 file from a stream, so close it. */
|
|
|
|
|
if (m_is_hdf5) {
|
|
|
|
|
m_infile.close();
|
|
|
|
|
m_streams.clear();
|
|
|
|
|
}
|
2016-09-09 05:06:06 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:30:01 +02:00
|
|
|
bool ArchiveReader::is_hdf5() const
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return m_is_hdf5;
|
2017-04-25 14:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
2016-09-09 05:06:06 +02:00
|
|
|
bool ArchiveReader::valid() const
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return m_archive.valid();
|
2016-09-09 05:06:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Alembic::Abc::IObject ArchiveReader::getTop()
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return m_archive.getTop();
|
2016-09-09 05:06:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************** */
|
|
|
|
|
|
|
|
|
|
/* This kinda duplicates CreateArchiveWithInfo, but Alembic does not seem to
|
|
|
|
|
* have a version supporting streams. */
|
|
|
|
|
static OArchive create_archive(std::ostream *ostream,
|
|
|
|
|
const std::string &filename,
|
|
|
|
|
const std::string &scene_name,
|
2019-11-19 12:45:43 +01:00
|
|
|
double scene_fps,
|
2016-09-09 05:06:06 +02:00
|
|
|
bool ogawa)
|
|
|
|
|
{
|
2019-11-19 12:45:43 +01:00
|
|
|
Alembic::Abc::MetaData abc_metadata;
|
|
|
|
|
|
|
|
|
|
abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender");
|
|
|
|
|
abc_metadata.set(Alembic::Abc::kUserDescriptionKey, scene_name);
|
|
|
|
|
abc_metadata.set("blender_version", versionstr);
|
|
|
|
|
abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps));
|
2016-09-09 05:06:06 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
time_t raw_time;
|
|
|
|
|
time(&raw_time);
|
|
|
|
|
char buffer[128];
|
2016-09-09 05:06:06 +02:00
|
|
|
|
|
|
|
|
#if defined _WIN32 || defined _WIN64
|
2019-04-17 06:17:24 +02:00
|
|
|
ctime_s(buffer, 128, &raw_time);
|
2016-09-09 05:06:06 +02:00
|
|
|
#else
|
2019-04-17 06:17:24 +02:00
|
|
|
ctime_r(&raw_time, buffer);
|
2016-09-09 05:06:06 +02:00
|
|
|
#endif
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
const std::size_t buffer_len = strlen(buffer);
|
|
|
|
|
if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') {
|
|
|
|
|
buffer[buffer_len - 1] = '\0';
|
|
|
|
|
}
|
2016-09-09 05:06:06 +02:00
|
|
|
|
2019-11-19 12:45:43 +01:00
|
|
|
abc_metadata.set(Alembic::Abc::kDateWrittenKey, buffer);
|
2016-09-09 05:06:06 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy;
|
2016-09-09 05:06:06 +02:00
|
|
|
|
|
|
|
|
#ifdef WITH_ALEMBIC_HDF5
|
2019-04-17 06:17:24 +02:00
|
|
|
if (!ogawa) {
|
2019-11-19 12:45:43 +01:00
|
|
|
return OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, abc_metadata, policy);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-09-09 05:06:06 +02:00
|
|
|
#else
|
2019-04-17 06:17:24 +02:00
|
|
|
static_cast<void>(filename);
|
|
|
|
|
static_cast<void>(ogawa);
|
2016-09-09 05:06:06 +02:00
|
|
|
#endif
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
Alembic::AbcCoreOgawa::WriteArchive archive_writer;
|
2019-11-19 12:45:43 +01:00
|
|
|
return OArchive(archive_writer(ostream, abc_metadata), kWrapExisting, policy);
|
2016-09-09 05:06:06 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ArchiveWriter::ArchiveWriter(const char *filename,
|
2019-11-19 12:45:43 +01:00
|
|
|
const std::string &abc_scene_name,
|
|
|
|
|
const Scene *scene,
|
|
|
|
|
bool do_ogawa)
|
2016-09-09 05:06:06 +02:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Use stream to support unicode character paths on Windows. */
|
|
|
|
|
if (do_ogawa) {
|
2016-09-09 05:06:06 +02:00
|
|
|
#ifdef WIN32
|
2019-04-17 06:17:24 +02:00
|
|
|
UTF16_ENCODE(filename);
|
|
|
|
|
std::wstring wstr(filename_16);
|
|
|
|
|
m_outfile.open(wstr.c_str(), std::ios::out | std::ios::binary);
|
|
|
|
|
UTF16_UN_ENCODE(filename);
|
2016-09-09 05:06:06 +02:00
|
|
|
#else
|
2019-04-17 06:17:24 +02:00
|
|
|
m_outfile.open(filename, std::ios::out | std::ios::binary);
|
2016-09-09 05:06:06 +02:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-09-09 05:06:06 +02:00
|
|
|
|
2019-11-19 12:45:43 +01:00
|
|
|
m_archive = create_archive(&m_outfile, filename, abc_scene_name, FPS, do_ogawa);
|
2016-09-09 05:06:06 +02:00
|
|
|
}
|
|
|
|
|
|
2016-09-16 09:27:44 +02:00
|
|
|
OArchive &ArchiveWriter::archive()
|
2016-09-09 05:06:06 +02:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return m_archive;
|
2016-09-09 05:06:06 +02:00
|
|
|
}
|