Alembic: addition of a simple logging class.

The idea is to have a system where we properly log error messages and
let the users know that errors occured redirecting them to the console
for explanations. This is only implemented for the exporter since the
importer already has similar functionalities; however they shall
ultimately be unified in some way.

Reviewers: sybren, dfelinto

Differential Revision: https://developer.blender.org/D2541
This commit is contained in:
2017-04-05 04:56:38 +02:00
parent 411e7abe94
commit 6d55dcf4dd
6 changed files with 103 additions and 5 deletions

View File

@@ -66,6 +66,7 @@ using Alembic::Abc::OBox3dProperty;
ExportSettings::ExportSettings()
: scene(NULL)
, logger()
, selected_only(false)
, visible_layers_only(false)
, renderable_only(false)
@@ -419,7 +420,7 @@ void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupl
/* check if we have already created a transform writer for this object */
if (getXForm(name) != NULL) {
std::cerr << "xform " << name << " already exists\n";
ABC_LOG(m_settings.logger) << "xform " << name << " already exists!\n";
return;
}
@@ -513,7 +514,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
AbcTransformWriter *xform = getXForm(name);
if (!xform) {
std::cerr << __func__ << ": xform " << name << " is NULL\n";
ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n";
return;
}

View File

@@ -28,6 +28,8 @@
#include <set>
#include <vector>
#include "abc_util.h"
class AbcObjectWriter;
class AbcTransformWriter;
class ArchiveWriter;
@@ -41,6 +43,7 @@ struct ExportSettings {
ExportSettings();
Scene *scene;
SimpleLogger logger;
bool selected_only;
bool visible_layers_only;

View File

@@ -91,7 +91,7 @@ Imath::Box3d AbcObjectWriter::bounds()
if (!bb) {
if (this->m_object->type != OB_CAMERA) {
std::cerr << "Boundbox is null!\n";
ABC_LOG(m_settings.logger) << "Bounding box is null!\n";
}
return Imath::Box3d();

View File

@@ -537,3 +537,32 @@ ScopeTimer::~ScopeTimer()
{
fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start);
}
/* ********************** */
bool SimpleLogger::empty()
{
return m_stream.tellp() == 0ul;
}
std::string SimpleLogger::str() const
{
return m_stream.str();
}
void SimpleLogger::clear()
{
m_stream.clear();
m_stream.str("");
}
std::ostringstream &SimpleLogger::stream()
{
return m_stream;
}
std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger)
{
os << logger.str();
return os;
}

View File

@@ -165,4 +165,48 @@ public:
# define SCOPE_TIMER(message)
#endif
/* *************************** */
/**
* Utility class whose purpose is to more easily log related informations. An
* instance of the SimpleLogger can be created in any context, and will hold a
* copy of all the strings passed to its output stream.
*
* Different instances of the class may be accessed from different threads,
* although accessing the same instance from different threads will lead to race
* conditions.
*/
class SimpleLogger {
std::ostringstream m_stream;
public:
/**
* Check whether or not the SimpleLogger's stream is empty.
*/
bool empty();
/**
* Return a copy of the string contained in the SimpleLogger's stream.
*/
std::string str() const;
/**
* Remove the bits set on the SimpleLogger's stream and clear its string.
*/
void clear();
/**
* Return a reference to the SimpleLogger's stream, in order to e.g. push
* content into it.
*/
std::ostringstream &stream();
};
#define ABC_LOG(logger) logger.stream()
/**
* Pass the content of the logger's stream to the specified std::ostream.
*/
std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger);
#endif /* __ABC_UTIL_H__ */

View File

@@ -301,10 +301,10 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
}
}
catch (const std::exception &e) {
std::cerr << "Abc Export error: " << e.what() << '\n';
ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n';
}
catch (...) {
std::cerr << "Abc Export error\n";
ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n";
}
}
@@ -316,6 +316,11 @@ static void export_endjob(void *customdata)
BLI_delete(data->filename, false, false);
}
if (!data->settings.logger.empty()) {
std::cerr << data->settings.logger;
WM_report(RPT_ERROR, "Errors occured during the export, look in the console to know more...");
}
G.is_rendering = false;
BKE_spacedata_draw_locks(false);
}
@@ -331,6 +336,22 @@ void ABC_export(
job->bmain = CTX_data_main(C);
BLI_strncpy(job->filename, filepath, 1024);
/* Alright, alright, alright....
*
* ExportJobData contains an ExportSettings containing a SimpleLogger.
*
* Since ExportJobData is a C-style struct dynamically allocated with
* MEM_mallocN (see above), its construtor is never called, therefore the
* ExportSettings constructor is not called which implies that the
* SimpleLogger one is not called either. SimpleLogger in turn does not call
* the constructor of its data members which ultimately means that its
* std::ostringstream member has a NULL pointer. To be able to properly use
* the stream's operator<<, the pointer needs to be set, therefore we have
* to properly construct everything. And this is done using the placement
* new operator as here below. It seems hackish, but I'm too lazy to
* do bigger refactor and maybe there is a better way which does not involve
* hardcore refactoring. */
new (&job->settings) ExportSettings();
job->settings.scene = job->scene;
job->settings.frame_start = params->frame_start;
job->settings.frame_end = params->frame_end;