Add support of multi STL solids loading

This commit is contained in:
Hugues Delorme 2016-02-24 16:43:40 +01:00
parent 9260bc480a
commit 77c65947bb
16 changed files with 1817 additions and 50 deletions

View File

@ -28,10 +28,16 @@ GMIO_INLINE int gmio_stream_error(struct gmio_stream* stream);
GMIO_INLINE size_t gmio_stream_read(
struct gmio_stream* stream, void *ptr, size_t size, size_t count);
GMIO_INLINE size_t gmio_stream_read_bytes(
struct gmio_stream* stream, void *ptr, size_t count);
/*! Safe and convenient function for gmio_stream::func_write() */
GMIO_INLINE size_t gmio_stream_write(
struct gmio_stream* stream, const void *ptr, size_t size, size_t count);
GMIO_INLINE size_t gmio_stream_write_bytes(
struct gmio_stream* stream, const void *ptr, size_t count);
/*! Safe and convenient function for gmio_stream::func_size() */
GMIO_INLINE gmio_streamsize_t gmio_stream_size(struct gmio_stream* stream);
@ -75,6 +81,14 @@ size_t gmio_stream_read(
return 0;
}
size_t gmio_stream_read_bytes(
struct gmio_stream* stream, void *ptr, size_t count)
{
if (stream != NULL && stream->func_read != NULL)
return stream->func_read(stream->cookie, ptr, 1, count);
return 0;
}
size_t gmio_stream_write(
struct gmio_stream* stream, const void *ptr, size_t size, size_t count)
{
@ -83,6 +97,14 @@ size_t gmio_stream_write(
return 0;
}
size_t gmio_stream_write_bytes(
struct gmio_stream* stream, const void *ptr, size_t count)
{
if (stream != NULL && stream->func_write != NULL)
return stream->func_write(stream->cookie, ptr, 1, count);
return 0;
}
gmio_streamsize_t gmio_stream_size(struct gmio_stream* stream)
{
if (stream != NULL && stream->func_size != NULL)

View File

@ -23,6 +23,7 @@ struct gmio_stringstream gmio_stringstream(
struct gmio_stringstream sstream = {0};
sstream.stream = stream;
sstream.strbuff = strbuff;
sstream.func_stream_read = gmio_stringstream_default_func_read;
gmio_stringstream_init_pos(&sstream);
return sstream;
}

View File

@ -41,12 +41,12 @@ struct gmio_stringstream
/*! Position indicator in strbuff */
const char* strbuff_at;
/*! User data to be passed to callback func_stream_read_hook */
/*! Data to be passed to callback func_stream_read */
void* cookie;
/*! Pointer on user function called each time next contents is read */
void (*func_stream_read_hook)(
void* cookie, const struct gmio_string* strbuff);
/*! Pointer on a function called each time next contents has to be read */
size_t (*func_stream_read)(
void* cookie, struct gmio_stream* stream, char* ptr, size_t len);
};
/*! Returns an initialized gmio_stringstream object */
@ -57,6 +57,10 @@ struct gmio_stringstream gmio_stringstream(
/*! Initializes position indicator */
void gmio_stringstream_init_pos(struct gmio_stringstream* sstream);
/*! Default function for gmio_stringstream::func_stream_read */
GMIO_INLINE size_t gmio_stringstream_default_func_read(
void* cookie, struct gmio_stream* stream, char* ptr, size_t len);
/*! Returns the char where the iterator is currently pointing at */
GMIO_INLINE const char* gmio_stringstream_current_char(
const struct gmio_stringstream* sstream);
@ -142,6 +146,13 @@ const char* gmio_stringstream_current_char(
NULL;
}
size_t gmio_stringstream_default_func_read(
void* cookie, struct gmio_stream* stream, char* ptr, size_t len)
{
GMIO_UNUSED(cookie);
return gmio_stream_read(stream, ptr, 1, len);
}
const char *gmio_stringstream_next_char(struct gmio_stringstream *sstream)
{
++(sstream->strbuff_at);
@ -151,15 +162,13 @@ const char *gmio_stringstream_next_char(struct gmio_stringstream *sstream)
/* Read next chunk of data */
sstream->strbuff_at = sstream->strbuff.ptr;
sstream->strbuff.len =
gmio_stream_read(
&sstream->stream, sstream->strbuff.ptr, 1, sstream->strbuff.max_len);
sstream->func_stream_read(
sstream->cookie,
&sstream->stream,
sstream->strbuff.ptr,
sstream->strbuff.max_len);
sstream->strbuff_end = sstream->strbuff.ptr + sstream->strbuff.len;
if (sstream->strbuff.len > 0) {
if (sstream->func_stream_read_hook != NULL)
sstream->func_stream_read_hook(sstream->cookie, &sstream->strbuff);
return sstream->strbuff.ptr;
}
return NULL;
return sstream->strbuff.len > 0 ? sstream->strbuff.ptr : NULL;
}
struct gmio_stringstream* gmio_stringstream_move_next_char(

View File

@ -50,12 +50,14 @@ static bool gmio_stringstream_icase_eat(
}
/* Callback invoked by gmio_stringstream */
static void gmio_stringstream_update_streamsize(
void* cookie, const struct gmio_string* strbuff)
static size_t gmio_stringstream_read(
void* cookie, struct gmio_stream* stream, char* ptr, size_t len)
{
gmio_streamsize_t* ptr_size = (gmio_streamsize_t*)(cookie);
const size_t len_read = gmio_stream_read_bytes(stream, ptr, len);
if (ptr_size != NULL)
*ptr_size += strbuff->len;
*ptr_size += len_read;
return len_read;
}
int gmio_stla_infos_get(
@ -88,7 +90,7 @@ int gmio_stla_infos_get(
if (flag_size) {
infos->size = 0;
sstream.cookie = &infos->size;
sstream.func_stream_read_hook = gmio_stringstream_update_streamsize;
sstream.func_stream_read = gmio_stringstream_read;
}
gmio_stringstream_init_pos(&sstream);

View File

@ -57,13 +57,16 @@ int gmio_stlb_infos_get(
memcpy(infos->stlb_header.data, buff, GMIO_STLB_HEADER_SIZE);
if (flags & GMIO_STL_INFO_FLAG_FACET_COUNT)
infos->facet_count = facet_count;
if (flags & GMIO_STL_INFO_FLAG_SIZE) {
infos->size =
GMIO_STLB_HEADER_SIZE
+ sizeof(uint32_t)
+ facet_count * GMIO_STLB_TRIANGLE_RAWSIZE;
}
if (flags & GMIO_STL_INFO_FLAG_SIZE)
infos->size = gmio_stlb_infos_size(facet_count);
}
return GMIO_ERROR_OK;
}
gmio_streamsize_t gmio_stlb_infos_size(uint32_t facet_count)
{
return GMIO_STLB_HEADER_SIZE
+ sizeof(uint32_t)
+ facet_count * GMIO_STLB_TRIANGLE_RAWSIZE;
}

View File

@ -19,11 +19,15 @@
#include "../stl_infos.h"
#include "../../gmio_core/endian.h"
/*! Find infos from a STL binary stream */
/*! Finds infos from a STL binary stream */
int gmio_stlb_infos_get(
struct gmio_stl_infos* infos,
struct gmio_stream stream,
unsigned flags,
const struct gmio_stl_infos_get_options* opts);
/*! Returns the size(in bytes) of the whole STL binary data given some facet
* count */
gmio_streamsize_t gmio_stlb_infos_size(uint32_t facet_count);
#endif /* GMIO_INTERNAL_STLB_INFOS_GET_H */

View File

@ -73,3 +73,14 @@ label_end:
gmio_memblock_helper_release(&mblock_helper);
return error;
}
gmio_streamsize_t gmio_stla_infos_get_streamsize(
struct gmio_stream *stream, struct gmio_memblock *stream_memblock)
{
struct gmio_stl_infos infos = {0};
struct gmio_stl_infos_get_options options = {0};
options.stream_memblock = *stream_memblock;
options.format_hint = GMIO_STL_FORMAT_ASCII;
gmio_stl_infos_get(&infos, *stream, GMIO_STL_INFO_FLAG_SIZE, &options);
return infos.size;
}

View File

@ -117,6 +117,15 @@ int gmio_stl_infos_get(
unsigned flags, /*!< Bitor combination of gmio_stl_info_flag values */
const struct gmio_stl_infos_get_options* options);
/*! Returns the size(in bytes) of next STL ascii solid in \p stream
*
* It is a facade over gmio_stl_infos_get() for gmio_stl_infos::size only
*/
GMIO_LIBSTL_EXPORT
gmio_streamsize_t gmio_stla_infos_get_streamsize(
struct gmio_stream* stream,
struct gmio_memblock* stream_memblock);
GMIO_C_LINKAGE_END
#endif /* GMIO_STL_INFOS_H */

View File

@ -82,19 +82,24 @@
*/
/* Callback used for gmio_stringstream::func_stream_read_hook */
static void gmio_stringstream_stla_read_hook(
void* cookie, const struct gmio_string* strbuff)
/* Callback used for gmio_stringstream::func_stream_read */
static size_t gmio_stringstream_stla_read(
void* cookie, struct gmio_stream* stream, char* ptr, size_t len)
{
struct gmio_stringstream_stla_cookie* tcookie =
struct gmio_stringstream_stla_cookie* stlac =
(struct gmio_stringstream_stla_cookie*)(cookie);
if (tcookie != NULL) {
const struct gmio_task_iface* task = tcookie->task;
tcookie->stream_offset += strbuff->len;
tcookie->is_stop_requested = gmio_task_iface_is_stop_requested(task);
if (stlac != NULL) {
const struct gmio_task_iface* task = stlac->task;
const size_t to_read =
GMIO_MIN(len, stlac->stream_size - stlac->stream_offset + 1);
const size_t len_read = gmio_stream_read_bytes(stream, ptr, to_read);
stlac->stream_offset += len_read;
stlac->is_stop_requested = gmio_task_iface_is_stop_requested(task);
gmio_task_iface_handle_progress(
task, tcookie->stream_offset, tcookie->stream_size);
task, stlac->stream_offset, stlac->stream_size);
return len_read;
}
return 0;
}
/* Root function, parses a whole solid */
@ -127,7 +132,7 @@ int gmio_stla_read(
parse_data.strstream.strbuff.ptr = mblock->ptr;
parse_data.strstream.strbuff.max_len = mblock->size;
parse_data.strstream.cookie = &parse_data.strstream_cookie;
parse_data.strstream.func_stream_read_hook = gmio_stringstream_stla_read_hook;
parse_data.strstream.func_stream_read = gmio_stringstream_stla_read;
gmio_stringstream_init_pos(&parse_data.strstream);
parse_data.token_str = gmio_string(fixed_buffer, 0, sizeof(fixed_buffer));
@ -532,8 +537,11 @@ int gmio_stla_parse_solidname_beg(struct gmio_stla_parse_data* data)
int parse_solidname_end(struct gmio_stla_parse_data* data)
{
GMIO_UNUSED(data);
/* TODO: parse according to retrieved solid name */
struct gmio_stringstream* sstream = &data->strstream;
/* Eat whole line after "endsolid" */
const char* c = gmio_stringstream_current_char(sstream);
while (c != NULL && *c != '\n' && *c != '\r')
c = gmio_stringstream_next_char(sstream);
return 0;
}

View File

@ -28,6 +28,7 @@
#include "../gmio_core/internal/helper_memblock.h"
#include "../gmio_core/internal/helper_stream.h"
#include "../gmio_core/internal/helper_task_iface.h"
#include "../gmio_core/internal/min_max.h"
#include "../gmio_core/internal/safe_cast.h"
#include <string.h>
@ -98,12 +99,11 @@ int gmio_stlb_read(
struct gmio_memblock_helper mblock_helper =
gmio_memblock_helper(opts != NULL ? &opts->stream_memblock : NULL);
struct gmio_memblock* mblock = &mblock_helper.memblock;
void* mblock_ptr = mblock->ptr;
const struct gmio_task_iface* task = opts != NULL ? &opts->task_iface : NULL;
struct gmio_stlb_header header;
uint32_t i_facet = 0; /* Facet counter */
uint32_t total_facet_count = 0; /* Facet count, as declared in the stream */
int error = GMIO_ERROR_OK; /* Helper to store function result error code */
int error = GMIO_ERROR_OK; /* Function result(error code) */
/* Constants */
const func_gmio_stlb_decode_facets_t func_decode_facets =
byte_order != GMIO_ENDIANNESS_HOST ?
@ -119,22 +119,17 @@ int gmio_stlb_read(
goto label_end;
/* Read header */
if (gmio_stream_read(&stream, &header, GMIO_STLB_HEADER_SIZE, 1)
!= 1)
{
if (gmio_stream_read(&stream, &header, GMIO_STLB_HEADER_SIZE, 1) != 1) {
error = GMIO_STL_ERROR_HEADER_WRONG_SIZE;
goto label_end;
}
/* Read facet count */
if (gmio_stream_read(&stream, mblock_ptr, sizeof(uint32_t), 1)
!= 1)
{
if (gmio_stream_read(&stream, mblock->ptr, sizeof(uint32_t), 1) != 1) {
error = GMIO_STL_ERROR_FACET_COUNT;
goto label_end;
}
memcpy(&total_facet_count, mblock_ptr, sizeof(uint32_t));
memcpy(&total_facet_count, mblock->ptr, sizeof(uint32_t));
if (byte_order != GMIO_ENDIANNESS_HOST)
total_facet_count = gmio_uint32_bswap(total_facet_count);
@ -153,13 +148,16 @@ int gmio_stlb_read(
/* Read triangles */
gmio_task_iface_handle_progress(task, 0, total_facet_count);
while (gmio_no_error(error) && i_facet < total_facet_count) {
const uint32_t facet_count_to_read =
GMIO_MIN(max_facet_count_per_read,
total_facet_count - i_facet);
const uint32_t read_facet_count =
gmio_size_to_uint32(
gmio_stream_read(
&stream,
mblock_ptr,
mblock->ptr,
GMIO_STLB_TRIANGLE_RAWSIZE,
max_facet_count_per_read));
facet_count_to_read));
if (gmio_stream_error(&stream) != 0)
error = GMIO_ERROR_STREAM;
@ -170,7 +168,7 @@ int gmio_stlb_read(
if (gmio_no_error(error)) {
func_decode_facets(
&mesh_creator, mblock_ptr, read_facet_count, i_facet);
&mesh_creator, mblock->ptr, read_facet_count, i_facet);
i_facet += read_facet_count;
if (gmio_task_iface_is_stop_requested(task))
error = GMIO_ERROR_TRANSFER_STOPPED;

View File

@ -15,6 +15,8 @@
#include "utest_lib.h"
#include "../src/gmio_core/memblock.h"
const char* test_stl_coords_packing();
const char* test_stl_triangle_packing();
const char* test_stl_triangle_compute_normal();
@ -24,6 +26,7 @@ const char* test_stl_internal__rw_common();
const char* test_stl_infos();
const char* test_stl_read();
const char* test_stl_read_multi_solid();
const char* test_stla_write();
const char* test_stlb_write_header();
const char* test_stlb_write();
@ -31,10 +34,21 @@ const char* test_stlb_write();
const char* test_stlb_header_str();
const char* test_stlb_header_to_printable_str();
void generate_stlb_tests_models();
/* Static memblock */
struct gmio_memblock gmio_memblock_for_tests()
{
static uint8_t buff[1024]; /* 1KB */
return gmio_memblock(buff, sizeof(buff), NULL);
}
const char* all_tests()
{
UTEST_SUITE_START();
gmio_memblock_set_default_constructor(gmio_memblock_for_tests);
UTEST_RUN(test_stl_coords_packing);
UTEST_RUN(test_stl_triangle_packing);
UTEST_RUN(test_stl_triangle_compute_normal);
@ -44,6 +58,7 @@ const char* all_tests()
UTEST_RUN(test_stl_infos);
UTEST_RUN(test_stl_read);
UTEST_RUN(test_stl_read_multi_solid);
UTEST_RUN(test_stla_write);
UTEST_RUN(test_stlb_write_header);
UTEST_RUN(test_stlb_write);
@ -51,6 +66,10 @@ const char* all_tests()
UTEST_RUN(test_stlb_header_str);
UTEST_RUN(test_stlb_header_to_printable_str);
#if 0
generate_stlb_tests_models();
#endif
return NULL;
}
UTEST_MAIN(all_tests)

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -44,6 +44,16 @@ struct gmio_stl_triangle_array gmio_stl_triangle_array_malloc(size_t tri_count)
return array;
}
void gmio_stl_triangle_array_free(struct gmio_stl_triangle_array *array)
{
if (array != NULL) {
free(array->ptr);
array->ptr = NULL;
array->count = 0;
array->capacity = 0;
}
}
static void gmio_stl_data__begin_solid(
void* cookie, const struct gmio_stl_mesh_creator_infos* infos)
{

View File

@ -65,6 +65,8 @@ struct gmio_stl_triangle_array
*/
struct gmio_stl_triangle_array gmio_stl_triangle_array_malloc(size_t tri_count);
void gmio_stl_triangle_array_free(struct gmio_stl_triangle_array* array);
/*! Holds complete STL data (usable for both binary and ascii formats) */
struct gmio_stl_data
{

View File

@ -21,6 +21,7 @@
#include "../src/gmio_core/error.h"
#include "../src/gmio_core/internal/min_max.h"
#include "../src/gmio_stl/stl_error.h"
#include "../src/gmio_stl/stl_infos.h"
#include "../src/gmio_stl/stl_io.h"
#include "../src/gmio_stl/stl_io_options.h"
@ -319,7 +320,7 @@ const char* test_stla_write()
{
const char* model_filepath = stl_grabcad_arm11_filepath;
const char* model_filepath_out = "temp/solid.stla";
struct gmio_stl_data data = {0};
struct gmio_stl_data data = {0}; /* TODO: fix memory leak on error */
char header_str[GMIO_STLB_HEADER_SIZE + 1] = {0};
int error = GMIO_ERROR_OK;
@ -370,6 +371,42 @@ const char* test_stla_write()
return NULL;
}
const char* generic_test_stl_read_multi_solid(
const char* filepath, unsigned expected_solid_count)
{
FILE* infile = fopen(filepath, "rb");
if (infile != NULL) {
unsigned solid_count = 0;
int error = GMIO_ERROR_OK;
struct gmio_stl_read_options roptions = {0};
roptions.func_stla_get_streamsize = gmio_stla_infos_get_streamsize;
while (gmio_no_error(error)) {
const struct gmio_stl_mesh_creator null_creator = {0};
error = gmio_stl_read(
gmio_stream_stdio(infile), null_creator, &roptions);
if (gmio_no_error(error))
++solid_count;
}
fclose(infile);
UTEST_COMPARE_UINT(expected_solid_count, solid_count);
}
else {
perror(NULL);
UTEST_FAIL("");
}
return NULL;
}
const char* test_stl_read_multi_solid()
{
const char* res = NULL;
res = generic_test_stl_read_multi_solid("models/solid_4meshs.stla", 4);
if (res != NULL)
return res;
res = generic_test_stl_read_multi_solid("models/solid_4meshs.le_stlb", 4);
return res;
}
void generate_stlb_tests_models()
{
{
@ -403,4 +440,29 @@ void generate_stlb_tests_models()
gmio_stl_data_mesh(&data),
NULL);
}
{
FILE* infile = fopen("models/solid_4meshs.stla", "rb");
FILE* outfile = fopen("models/solid_4meshs.le_stlb", "wb");
int read_error = GMIO_ERROR_OK;
struct gmio_stl_read_options roptions = {0};
roptions.func_stla_get_streamsize = gmio_stla_infos_get_streamsize;
while (gmio_no_error(read_error)) {
struct gmio_stl_data data = {0};
struct gmio_stl_write_options woptions = {0};
read_error = gmio_stla_read(
gmio_stream_stdio(infile),
gmio_stl_data_mesh_creator(&data),
&roptions);
woptions.stlb_header = gmio_stlb_header_str(data.solid_name);
gmio_stl_write(
GMIO_STL_FORMAT_BINARY_LE,
gmio_stream_stdio(outfile),
gmio_stl_data_mesh(&data),
&woptions);
gmio_stl_triangle_array_free(&data.tri_array);
}
fclose(infile);
fclose(outfile);
}
}