From 5f4ed36e9f1ee6c8aa4c6b69b0d39906aeb62667 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Thu, 10 Jan 2013 18:48:46 +0100 Subject: [PATCH] c-lib: initial work about base C library of FougDataEx --- qmake.build/c/c.pro | 2 + qmake.build/c/libstl/libstl.pro | 50 ++++++ qmake.build/foug_dataex.pro | 2 +- src/c++/foug_global.h | 36 ++--- src/c/foug_global.h | 35 +++++ src/c/libstl/stlb.c | 261 ++++++++++++++++++++++++++++++++ src/c/libstl/stlb.h | 59 ++++++++ src/c/libstl/triangle.h | 21 +++ src/c/memory.h | 9 ++ src/c/stream.c | 95 ++++++++++++ src/c/stream.h | 35 +++++ src/c/task_control.c | 161 ++++++++++++++++++++ src/c/task_control.h | 52 +++++++ 13 files changed, 792 insertions(+), 26 deletions(-) create mode 100644 qmake.build/c/c.pro create mode 100644 qmake.build/c/libstl/libstl.pro create mode 100644 src/c/foug_global.h create mode 100644 src/c/libstl/stlb.c create mode 100644 src/c/libstl/stlb.h create mode 100644 src/c/libstl/triangle.h create mode 100644 src/c/memory.h create mode 100644 src/c/stream.c create mode 100644 src/c/stream.h create mode 100644 src/c/task_control.c create mode 100644 src/c/task_control.h diff --git a/qmake.build/c/c.pro b/qmake.build/c/c.pro new file mode 100644 index 0000000..2d988ec --- /dev/null +++ b/qmake.build/c/c.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += libstl diff --git a/qmake.build/c/libstl/libstl.pro b/qmake.build/c/libstl/libstl.pro new file mode 100644 index 0000000..005d006 --- /dev/null +++ b/qmake.build/c/libstl/libstl.pro @@ -0,0 +1,50 @@ +isEmpty(PREFIX_DIR) { + PREFIX_DIR = ../../.. +} + +include(../../config.pri) + +message($$PREFIX_DIR) + +TEMPLATE = lib +TARGET = fougstl-c$$TARGET_SUFFIX +DESTDIR = $$PREFIX_DIR/lib +CONFIG *= dll + +dll { + DEFINES *= FOUG_STL_DLL FOUG_STL_MAKE_DLL +} + +#*g++*:QMAKE_CXXFLAGS_RELEASE -= -O2 +#*g++*:QMAKE_CXXFLAGS_RELEASE += -O3 + +INCLUDEPATH += ../../../src + +HEADERS += \ + ../../../src/c/foug_global.h \ + ../../../src/c/memory.h \ + ../../../src/c/stream.h \ + ../../../src/c/task_control.h \ + ../../../src/c/libstl/stlb.h \ + ../../../src/c/libstl/triangle.h + +SOURCES += \ + ../../../src/c/stream.c \ + ../../../src/c/task_control.c \ + ../../../src/c/libstl/stlb.c + +*-g++*:QMAKE_CFLAGS += -ansi + +global_inc.path = $$PREFIX_DIR/include +global_inc.files = ../../../src/*.h +c_global_inc.path = $$PREFIX_DIR/include/c +c_global_inc.files = ../../../src/c/*.h +c_streams_inc.path = $$PREFIX_DIR/include/c/streams +c_streams_inc.files = ../../../src/c/streams/*.h +c_libstl_inc.path = $$PREFIX_DIR/include/c/libstl +c_libstl_inc.files = ../../../src/c/libstl/*.h +INSTALLS += global_inc c_global_inc c_streams_inc c_libstl_inc + +VER_MAJ = 0 +VER_MIN = 1 +VER_PAT = 0 diff --git a/qmake.build/foug_dataex.pro b/qmake.build/foug_dataex.pro index c9e8d93..fdb370b 100644 --- a/qmake.build/foug_dataex.pro +++ b/qmake.build/foug_dataex.pro @@ -1,4 +1,4 @@ TEMPLATE = subdirs CONFIG *= ordered -SUBDIRS += c++ +SUBDIRS += c c++ diff --git a/src/c++/foug_global.h b/src/c++/foug_global.h index f0091e6..193c9d7 100644 --- a/src/c++/foug_global.h +++ b/src/c++/foug_global.h @@ -1,38 +1,24 @@ #ifndef FOUG_CPP_GLOBAL_H #define FOUG_CPP_GLOBAL_H -#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) - || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -# define FOUG_DECL_EXPORT __declspec(dllexport) -# define FOUG_DECL_IMPORT __declspec(dllimport) -#else -# define FOUG_DECL_EXPORT -# define FOUG_DECL_IMPORT -#endif // WIN - -//#include +#include "../c/foug_global.h" namespace foug { -typedef char Int8; -typedef unsigned char UInt8; +typedef foug_int8 Int8; +typedef foug_uint8 UInt8; -typedef short Int16; -typedef unsigned short UInt16; +typedef foug_int16 Int16; +typedef foug_uint16 UInt16; -typedef int Int32; -typedef unsigned int UInt32; +typedef foug_int32 Int32; +typedef foug_uint32 UInt32; -#ifdef _MSC_VER -typedef __int64 Int64; -typedef unsigned __int64 UInt64; -#else -typedef long long Int64; -typedef unsigned long long UInt64; -#endif // _MSC_VER +typedef foug_int64 Int64; +typedef foug_uint64 UInt64; -typedef float Real32; -typedef double Real64; +typedef foug_real32 Real32; +typedef foug_real64 Real64; } // namespace foug diff --git a/src/c/foug_global.h b/src/c/foug_global.h new file mode 100644 index 0000000..62f0f71 --- /dev/null +++ b/src/c/foug_global.h @@ -0,0 +1,35 @@ +#ifndef FOUG_C_GLOBAL_H +#define FOUG_C_GLOBAL_H + +#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) + || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +# define FOUG_DECL_EXPORT __declspec(dllexport) +# define FOUG_DECL_IMPORT __declspec(dllimport) +#else +# define FOUG_DECL_EXPORT +# define FOUG_DECL_IMPORT +#endif /* WIN */ + +typedef char foug_int8; +typedef unsigned char foug_uint8; + +typedef foug_int8 foug_bool; + +typedef short foug_int16; +typedef unsigned short foug_uint16; + +typedef int foug_int32; +typedef unsigned int foug_uint32; + +#ifdef _MSC_VER +typedef __int64 foug_int64; +typedef unsigned __int64 foug_uint64; +#else +typedef long long foug_int64; +typedef unsigned long long foug_uint64; +#endif /* _MSC_VER */ + +typedef float foug_real32; +typedef double foug_real64; + +#endif /* FOUG_C_GLOBAL_H */ diff --git a/src/c/libstl/stlb.c b/src/c/libstl/stlb.c new file mode 100644 index 0000000..d71607e --- /dev/null +++ b/src/c/libstl/stlb.c @@ -0,0 +1,261 @@ +#include "stlb.h" + +/* +#include "../abstract_task_progress.h" + +#include +#include + +// Read tools + +template +NUMERIC fromLittleEndian(const foug::UInt8* bytes) +{ + return 0; +} + +template<> +foug::UInt16 fromLittleEndian(const foug::UInt8* bytes) +{ + // |BB|AA| -> 0xAABB + return (bytes[1] << 8) | bytes[0]; +} + +template<> +foug::UInt32 fromLittleEndian(const foug::UInt8* bytes) +{ + // |DD|CC|BB|AA| -> 0xAABBCCDD + return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); +} + +template<> +foug::Real32 fromLittleEndian(const foug::UInt8* bytes) +{ + union + { + foug::UInt32 asInteger; + foug::Real32 asFloat; + } helper; + + helper.asInteger = fromLittleEndian(bytes); + return helper.asFloat; +} + +// Write tools + +template +void toLittleEndian(NUMERIC n, foug::UInt8* bytes) +{ + union { + NUMERIC asNumeric; + foug::UInt8 asBytes[sizeof(NUMERIC)]; + } helper; + helper.asNumeric = n; + // std::copy(helper.asBytes, helper.asBytes + sizeof(NUMERIC), bytes); + for (unsigned i = 0; i < sizeof(NUMERIC); ++i) + bytes[i] = helper.asBytes[i]; +} + +namespace foug { +namespace stlb { + +static const int stlFacetSize = 50; +static const int stlMinFileSize = 284; +static const int stlTriangleDataSize = (4 * 3) * sizeof(foug::Real32) + sizeof(foug::UInt16); + + +void AbstractGeometryBuilder::endTriangles() +{ +} + +Io::Io(AbstractStream *stream) + : IoBase(stream) +{ +} + +bool Io::read(AbstractGeometryBuilder* builder) +{ + // // Check file size + // const qint64 fileSize = stream->size(); + // if (((fileSize - stlHeaderSize - stlFacetCountSize) % stlFacetSize != 0) + // || fileSize < stlMinFileSize) { + // cpp::checkedAssign(err, WrongFileSizeBinaryStlLoadError); + // return false; + // } + + // const int facetCount = (fileSize - stlHeaderSize - stlFacetCountSize) / stlFacetSize; + + if (this->stream() == 0) + return false; + + AbstractStream* istream = this->stream(); + AbstractTaskProgress* progress = this->taskProgress(); + const UInt32 chunkSize = stlTriangleDataSize * 163; + + UInt8 buffer[8192]; + char* charBuffer = reinterpret_cast(buffer); + + // Read header + Header headerData; + if (istream->read(reinterpret_cast(&headerData), HeaderSize) != HeaderSize) + return false; + builder->processHeader(headerData); + + // Read facet count + if (istream->read(charBuffer, sizeof(UInt32)) != sizeof(UInt32)) + return false; + const UInt32 facetCount = ::fromLittleEndian(buffer); + builder->beginTriangles(facetCount); + + if (progress != 0) { + progress->reset(); + progress->setRange(0., facetCount); + } + + // Read triangles + const UInt64 totalFacetSize = stlTriangleDataSize * facetCount; + UInt64 amountReadSize = 0; + stl::Triangle triangle; + bool streamError = false; + while (amountReadSize < totalFacetSize && !streamError) { + const Int64 iReadSize = istream->read(charBuffer, chunkSize); + if (iReadSize > 0 && (iReadSize % stlTriangleDataSize == 0)) { + const UInt32 iFacetCount = iReadSize / stlTriangleDataSize; + UInt32 bufferOffset = 0; + for (UInt32 i = 0; i < iFacetCount; ++i) { + // Read normal + triangle.normal.x = ::fromLittleEndian(buffer + bufferOffset); + triangle.normal.y = ::fromLittleEndian(buffer + 1*sizeof(Real32) + bufferOffset); + triangle.normal.z = ::fromLittleEndian(buffer + 2*sizeof(Real32) + bufferOffset); + + // Read vertex1 + triangle.v1.x = ::fromLittleEndian(buffer + 3*sizeof(Real32) + bufferOffset); + triangle.v1.y = ::fromLittleEndian(buffer + 4*sizeof(Real32) + bufferOffset); + triangle.v1.z = ::fromLittleEndian(buffer + 5*sizeof(Real32) + bufferOffset); + + // Read vertex2 + triangle.v2.x = ::fromLittleEndian(buffer + 6*sizeof(Real32) + bufferOffset); + triangle.v2.y = ::fromLittleEndian(buffer + 7*sizeof(Real32) + bufferOffset); + triangle.v2.z = ::fromLittleEndian(buffer + 8*sizeof(Real32) + bufferOffset); + + // Read vertex3 + triangle.v3.x = ::fromLittleEndian(buffer + 9*sizeof(Real32) + bufferOffset); + triangle.v3.y = ::fromLittleEndian(buffer + 10*sizeof(Real32) + bufferOffset); + triangle.v3.z = ::fromLittleEndian(buffer + 11*sizeof(Real32) + bufferOffset); + + // Attribute byte count + const UInt16 attributeByteCount = + ::fromLittleEndian(buffer + 12*sizeof(Real32) + bufferOffset); + + // Add triangle + builder->processNextTriangle(triangle, attributeByteCount); + + bufferOffset += stlTriangleDataSize; + } // end for + + if (progress != 0) { + if (progress->isTaskStopRequested()) { + streamError = true; + progress->taskStoppedEvent(); + } + else { + progress->setValue(amountReadSize / stlTriangleDataSize); + } + } + + amountReadSize += iReadSize; + } + else { + streamError = true; + } + } // end while + + if (!streamError) + builder->endTriangles(); + + return !streamError; +} + +bool Io::write(const stl::AbstractGeometry& geom, const AbstractGeometryExtraData* extraData) +{ + if (this->stream() == 0) + return false; + + AbstractStream* ostream = this->stream(); + AbstractTaskProgress* progress = this->taskProgress(); + + UInt8 buffer[128]; + + // Write header + Header headerData; + if (extraData != 0) + extraData->getHeader(headerData); + else + std::fill(headerData, headerData + HeaderSize, 0); + + if (ostream->write(reinterpret_cast(&headerData), HeaderSize) != HeaderSize) + return false; + + // Write facet count + const UInt32 facetCount = geom.triangleCount(); + ::toLittleEndian(facetCount, buffer); + if (ostream->write(reinterpret_cast(&buffer), sizeof(UInt32)) != sizeof(UInt32)) + return false; + + if (progress != 0) { + progress->reset(); + progress->setRange(0., facetCount); + } + + // Write triangles + stl::Triangle triangle; + for (UInt32 facet = 0; facet < facetCount; ++facet) { + geom.getTriangle(facet, &triangle); + + // Write normal + ::toLittleEndian(triangle.normal.x, buffer); + ::toLittleEndian(triangle.normal.y, buffer + 1*sizeof(Real32)); + ::toLittleEndian(triangle.normal.z, buffer + 2*sizeof(Real32)); + + // Write vertex1 + ::toLittleEndian(triangle.v1.x, buffer + 3*sizeof(Real32)); + ::toLittleEndian(triangle.v1.y, buffer + 4*sizeof(Real32)); + ::toLittleEndian(triangle.v1.z, buffer + 5*sizeof(Real32)); + + // Write vertex2 + ::toLittleEndian(triangle.v2.x, buffer + 6*sizeof(Real32)); + ::toLittleEndian(triangle.v2.y, buffer + 7*sizeof(Real32)); + ::toLittleEndian(triangle.v2.z, buffer + 8*sizeof(Real32)); + + // Write vertex3 + ::toLittleEndian(triangle.v3.x, buffer + 9*sizeof(Real32)); + ::toLittleEndian(triangle.v3.y, buffer + 10*sizeof(Real32)); + ::toLittleEndian(triangle.v3.z, buffer + 11*sizeof(Real32)); + + // Attribute byte count + const UInt16 attrByteCount = extraData != 0 ? extraData->attributeByteCount(facet) : 0; + ::toLittleEndian(attrByteCount, buffer + 12*sizeof(Real32)); + + // Write to stream + if (ostream->write(reinterpret_cast(buffer), stlTriangleDataSize) + != stlTriangleDataSize) + return false; + + if (progress != 0) { + if (progress->isTaskStopRequested()) { + progress->taskStoppedEvent(); + return false; + } + else { + progress->setValue(facet + 1); + } + } + } // end for + + return true; +} + +} // namespace stlb +} // namespace foug + +*/ diff --git a/src/c/libstl/stlb.h b/src/c/libstl/stlb.h new file mode 100644 index 0000000..b9af9bc --- /dev/null +++ b/src/c/libstl/stlb.h @@ -0,0 +1,59 @@ +#ifndef FOUG_C_LIBSTL_STLB_H +#define FOUG_C_LIBSTL_STLB_H + +#include "triangle.h" +#include "../foug_global.h" +#include "../stream.h" +#include "../task_control.h" + +enum { foug_stlb_header_size = 80 }; +typedef foug_uint8 foug_stlb_header_t[foug_stlb_header_size]; + +/* foug_stlb_geom : opaque structure */ +typedef struct _internal_foug_stlb_geom foug_stlb_geom_t; +typedef void (*foug_stlb_geom_input_process_header_func_t)(foug_stlb_geom_t, + const foug_stlb_header_t); +typedef void (*foug_stlb_geom_input_begin_triangles_func_t)(foug_stlb_geom_t, foug_uint32); +typedef void (*foug_stlb_geom_input_process_next_triangle_func_t)(foug_stlb_geom_t, + const foug_stl_triangle_t*, + foug_uint16); +typedef void (*foug_stlb_geom_input_end_triangles_func_t)(foug_stlb_geom_t); + +typedef struct foug_stlb_geom_input_manip +{ + foug_stlb_geom_input_process_header_func_t process_header_func; + foug_stlb_geom_input_begin_triangles_func_t begin_triangles_func; + foug_stlb_geom_input_process_next_triangle_func_t process_next_triangle_func; + foug_stlb_geom_input_end_triangles_func_t end_triangles_func; +} foug_stlb_geom_input_manip_t; + +/* +typedef struct foug_stlb_read_args +{ + void* stream; + foug_stream_manip_t stream_manip; + + foug_stlb_geom_t geom; + foug_stlb_geom_input_manip_t geom_manip; +} foug_stlb_read_args_t; + +int foug_stlb_read(foug_stlb_geom_t geom, foug_stlb_read_args_t args); +*/ + +/*class FOUG_STL_EXPORT AbstractGeometryExtraData +{ +public: + virtual void getHeader(Header& data) const = 0; + virtual UInt16 attributeByteCount(UInt32 triangleIndex) const = 0; +}; + +class FOUG_STL_EXPORT Io : public IoBase +{ +public: + Io(AbstractStream* stream = 0); + + bool read(AbstractGeometryBuilder* builder); + bool write(const stl::AbstractGeometry& geom, const AbstractGeometryExtraData* extraData = 0); +};*/ + +#endif /* FOUG_C_LIBSTL_STLB_H */ diff --git a/src/c/libstl/triangle.h b/src/c/libstl/triangle.h new file mode 100644 index 0000000..928c9b0 --- /dev/null +++ b/src/c/libstl/triangle.h @@ -0,0 +1,21 @@ +#ifndef FOUG_C_LIBSTL_TRIANGLE_H +#define FOUG_C_LIBSTL_TRIANGLE_H + +#include "../foug_global.h" + +typedef struct foug_stl_coords +{ + foug_real32 x; + foug_real32 y; + foug_real32 z; +} foug_stl_coords_t; + +typedef struct foug_stl_triangle +{ + foug_stl_coords_t normal; + foug_stl_coords_t v1; + foug_stl_coords_t v2; + foug_stl_coords_t v3; +} foug_stl_triangle_t; + +#endif /* FOUG_C_LIBSTL_TRIANGLE_H */ diff --git a/src/c/memory.h b/src/c/memory.h new file mode 100644 index 0000000..daf5921 --- /dev/null +++ b/src/c/memory.h @@ -0,0 +1,9 @@ +#ifndef FOUG_C_MEMORY_H +#define FOUG_C_MEMORY_H + +#include + +typedef void* (*foug_malloc_func_t)(size_t); +typedef void (*foug_free_func_t)(void*); + +#endif /* FOUG_C_MEMORY_H */ diff --git a/src/c/stream.c b/src/c/stream.c new file mode 100644 index 0000000..40a5c1a --- /dev/null +++ b/src/c/stream.c @@ -0,0 +1,95 @@ +#include "stream.h" + +#include +#include +#include + +struct _internal_foug_stream +{ + void* cookie; + foug_stream_manip_t manip; +}; + +foug_stream_t* foug_stream_create(foug_malloc_func_t func, void* data, foug_stream_manip_t manip) +{ + if (func == NULL) + return NULL; + foug_stream_t* stream = (*func)(sizeof(struct _internal_foug_stream)); + if (stream != NULL) { + stream->cookie = data; + stream->manip = manip; + } + return stream; +} + +foug_stream_manip_t foug_stream_manip_null() +{ + foug_stream_manip_t manip; + memset(&manip, 0, sizeof(foug_stream_manip_t)); + return manip; +} + +static foug_bool foug_stream_stdio_at_end(foug_stream_t* stream) +{ + return feof((FILE*) stream->cookie); +} + +static foug_int32 foug_stream_stdio_seek(foug_stream_t* stream, foug_int64 pos) +{ + return fseek((FILE*) stream->cookie, pos, SEEK_SET); +} + +static foug_uint64 foug_stream_stdio_read(foug_stream_t* stream, char* s, foug_uint64 max_size) +{ + return fread(s, sizeof(char), max_size, (FILE*) stream->cookie); +} + +static foug_uint64 foug_stream_stdio_write(foug_stream_t* stream, + const char* s, + foug_uint64 max_size) +{ + return fwrite(s, sizeof(char), max_size, (FILE*) stream->cookie); +} + +foug_stream_manip_t foug_stream_manip_stdio() +{ + foug_stream_manip_t manip; + manip.at_end_func = &foug_stream_stdio_at_end; + manip.seek_func = &foug_stream_stdio_seek; + manip.read_func = &foug_stream_stdio_read; + manip.write_func = &foug_stream_stdio_write; + return manip; +} + +foug_bool foug_stream_at_end(foug_stream_t* stream) +{ + if (stream != NULL && stream->manip.at_end_func != NULL) + return (*(stream->manip.at_end_func))(stream); + return 0; +} + +foug_int32 foug_stream_seek(foug_stream_t* stream, foug_int64 max_size) +{ + if (stream != NULL && stream->manip.seek_func != NULL) + return (*(stream->manip.seek_func))(stream, max_size); + return -1; +} + +foug_uint64 foug_stream_read(foug_stream_t* stream, char* s, foug_uint64 max_size) +{ + if (stream != NULL && stream->manip.read_func != NULL) + return (*(stream->manip.read_func))(stream, s, max_size); + return 0; +} + +foug_uint64 foug_stream_write(foug_stream_t* stream, const char* s, foug_uint64 max_size) +{ + if (stream != NULL && stream->manip.write_func != NULL) + return (*(stream->manip.write_func))(stream, s, max_size); + return 0; +} + +void* foug_stream_get_cookie(const foug_stream_t* stream) +{ + return stream != NULL ? stream->cookie : NULL; +} diff --git a/src/c/stream.h b/src/c/stream.h new file mode 100644 index 0000000..0f7cccb --- /dev/null +++ b/src/c/stream.h @@ -0,0 +1,35 @@ +#ifndef FOUG_C_STREAM_H +#define FOUG_C_STREAM_H + +#include "foug_global.h" +#include "memory.h" + +/* foug_stream : opaque structure */ +typedef struct _internal_foug_stream foug_stream_t; + +/* foug_stream_manip */ +typedef foug_bool (*foug_stream_at_end_func_t)(foug_stream_t*); +typedef foug_int32 (*foug_stream_seek_func_t)(foug_stream_t*, foug_int64); +typedef foug_uint64 (*foug_stream_read_func_t)(foug_stream_t*, char*, foug_uint64); +typedef foug_uint64 (*foug_stream_write_func_t)(foug_stream_t*, const char*, foug_uint64); +typedef struct foug_stream_manip +{ + foug_stream_at_end_func_t at_end_func; + foug_stream_seek_func_t seek_func; + foug_stream_read_func_t read_func; + foug_stream_write_func_t write_func; +} foug_stream_manip_t; + +foug_stream_manip_t foug_stream_manip_null(); +foug_stream_manip_t foug_stream_manip_stdio(); + +/* Services */ +foug_stream_t* foug_stream_create(foug_malloc_func_t func, void* data, foug_stream_manip_t manip); + +foug_bool foug_stream_at_end(foug_stream_t* stream); +foug_int32 foug_stream_seek(foug_stream_t* stream, foug_int64 max_size); +foug_uint64 foug_stream_read(foug_stream_t* stream, char* s, foug_uint64 max_size); +foug_uint64 foug_stream_write(foug_stream_t* stream, const char* s, foug_uint64 max_size); +void* foug_stream_get_cookie(const foug_stream_t* stream); + +#endif /* FOUG_C_STREAM_H */ diff --git a/src/c/task_control.c b/src/c/task_control.c new file mode 100644 index 0000000..390cce6 --- /dev/null +++ b/src/c/task_control.c @@ -0,0 +1,161 @@ +#include "task_control.h" + +#include +#include + +/* foug_task_control */ + +struct _internal_foug_task_control +{ + foug_real32 range_min; + foug_real32 range_max; + foug_real32 range_length; + foug_int32 step_id; + foug_real32 progress_value; + foug_real32 progress_threshold; + foug_bool is_stop_requested; + void* cookie; + foug_task_control_manip_t manip; +}; + +foug_task_control_t* foug_task_control_create(foug_malloc_func_t func, + void* data, foug_task_control_manip_t manip) +{ + if (func == NULL) + return NULL; + + foug_task_control_t* ctrl = (*func)(sizeof(struct _internal_foug_task_control)); + if (ctrl != 0) { + ctrl->range_min = -1.; + ctrl->range_max = -2.; + ctrl->range_length = -0.; + ctrl->step_id = -1; + ctrl->progress_value = -1.; + ctrl->progress_threshold = 0.01; /* Notifies each percent only */ + ctrl->is_stop_requested = 0; + ctrl->cookie = data; + ctrl->manip = manip; + } + return ctrl; +} + +/* foug_task_control_manip */ + +void foug_task_control_manip_init(foug_task_control_manip_t* manip) +{ + if (manip != NULL) + memset(manip, 0, sizeof(foug_task_control_manip_t)); +} + +/* Range */ + +foug_real32 foug_task_control_get_range_min(const foug_task_control_t* ctrl) +{ + return ctrl != NULL ? ctrl->range_min : -1.; +} + +foug_real32 foug_task_control_get_range_max(const foug_task_control_t* ctrl) +{ + return ctrl != NULL ? ctrl->range_max : -2.; +} + +void foug_task_control_set_range(foug_task_control_t* ctrl, foug_real32 min, foug_real32 max) +{ + if (ctrl != NULL) { + ctrl->range_min = min; + ctrl->range_max = max; + ctrl->range_length = max - min; + } +} + +/* Step id */ + +foug_int32 foug_task_control_get_step_id(const foug_task_control_t* ctrl) +{ + return ctrl != NULL ? ctrl->step_id : -1; +} + +void foug_task_control_set_step_id(foug_task_control_t* ctrl, foug_int32 step_id) +{ + if (ctrl != NULL) + ctrl->step_id = step_id; +} + +/* Progress */ +foug_real32 foug_task_control_get_progress_as_pc(const foug_task_control_t* ctrl) +{ + if (ctrl == NULL) + return 0.; + const foug_real32 result = (ctrl->progress_value - ctrl->range_min) / ctrl->range_length; + return fabs(result); +} + +foug_real32 foug_task_control_get_progress(const foug_task_control_t* ctrl) +{ + return ctrl != NULL ? ctrl->progress_value : 0.; +} + +void foug_task_control_set_progress(foug_task_control_t* ctrl, foug_real32 v) +{ + if (ctrl == NULL) + return; + + if (fabs(v - ctrl->progress_value) > fabs(ctrl->progress_threshold * ctrl->range_length)) { + ctrl->progress_value = v; + if (ctrl->manip.handle_progress_update_func != NULL) + (*(ctrl->manip.handle_progress_update_func))(ctrl); + } +} + +foug_real32 foug_task_control_get_progress_update_threshold(const foug_task_control_t* ctrl) +{ + return ctrl != NULL ? ctrl->progress_threshold : 0.01; +} + +void foug_task_control_set_progress_update_threshold(foug_task_control_t* ctrl, foug_real32 v) +{ + if (ctrl != NULL) + ctrl->progress_threshold = v; +} + +/* Reset */ + +void foug_task_control_reset(foug_task_control_t* ctrl) +{ + if (ctrl != NULL) { + ctrl->step_id = -1; + ctrl->progress_value = -1.; + ctrl->range_min = -1.; + ctrl->range_max = -2.; + ctrl->is_stop_requested = 0; + } +} + +/* Task stop */ + +void foug_task_control_async_stop(foug_task_control_t* ctrl) +{ + if (ctrl != NULL) + ctrl->is_stop_requested = 1; +} + +void foug_task_control_handle_stop(foug_task_control_t* ctrl) +{ + if (ctrl != NULL) { + ctrl->is_stop_requested = 0; + if (ctrl->manip.handle_stop_func != NULL) + (*(ctrl->manip.handle_stop_func))(ctrl); + } +} + +foug_bool foug_task_control_is_stop_requested(const foug_task_control_t* ctrl) +{ + return ctrl != NULL ? ctrl->is_stop_requested : 0; +} + +/* Cookie */ + +void* foug_task_control_get_cookie(const foug_task_control_t* ctrl) +{ + return ctrl != NULL ? ctrl->cookie : NULL; +} diff --git a/src/c/task_control.h b/src/c/task_control.h new file mode 100644 index 0000000..4516c52 --- /dev/null +++ b/src/c/task_control.h @@ -0,0 +1,52 @@ +#ifndef FOUG_C_TASK_CONTROL_H +#define FOUG_C_TASK_CONTROL_H + +#include "foug_global.h" +#include "memory.h" + +/* foug_task_control : opaque structure */ +typedef struct _internal_foug_task_control foug_task_control_t; + +/* foug_task_control_manip */ +typedef void (*foug_task_control_handle_stop_func)(foug_task_control_t*); +typedef void (*foug_task_control_handle_progress_update_func)(foug_task_control_t*); +typedef struct foug_task_control_manip +{ + foug_task_control_handle_stop_func handle_stop_func; + foug_task_control_handle_progress_update_func handle_progress_update_func; +} foug_task_control_manip_t; + +void foug_task_control_manip_init(foug_task_control_manip_t* manip); + +foug_task_control_t* foug_task_control_create(foug_malloc_func_t func, + void* data, foug_task_control_manip_t manip); + +/* Range */ +foug_real32 foug_task_control_get_range_min(const foug_task_control_t* ctrl); +foug_real32 foug_task_control_get_range_max(const foug_task_control_t* ctrl); +void foug_task_control_set_range(foug_task_control_t* ctrl, foug_real32 min, foug_real32 max); + +/* Step id */ +foug_int32 foug_task_control_get_step_id(const foug_task_control_t* ctrl); +void foug_task_control_set_step_id(foug_task_control_t* ctrl, foug_int32 step_id); + +/* Progress */ +foug_real32 foug_task_control_get_progress_as_pc(const foug_task_control_t* ctrl); +foug_real32 foug_task_control_get_progress(const foug_task_control_t* ctrl); +void foug_task_control_set_progress(foug_task_control_t* ctrl, foug_real32 v); + +foug_real32 foug_task_control_get_progress_update_threshold(const foug_task_control_t* ctrl); +void foug_task_control_set_progress_update_threshold(foug_task_control_t* ctrl, foug_real32 v); + +/* Reset */ +void foug_task_control_reset(foug_task_control_t* ctrl); + +/* Task stop */ +void foug_task_control_async_stop(foug_task_control_t* ctrl); +void foug_task_control_handle_stop(foug_task_control_t* ctrl); +foug_bool foug_task_control_is_stop_requested(const foug_task_control_t* ctrl); + +/* Cookie */ +void* foug_task_control_get_cookie(const foug_task_control_t* ctrl); + +#endif /* FOUG_C_TASK_CONTROL_H */