loader_aw

Load OBJ/MTL file formats
git clone git://git.meso-star.fr/loader_aw.git
Log | Files | Refs | README | LICENSE

commit 2a9b2dc40ba0a95f4cc590287bf44c88dc381bd7
parent 25b9ad89d69c69bdec64724c8c79e72331ee9bdb
Author: vaplv <vaplv@free.fr>
Date:   Fri, 21 Feb 2020 15:53:26 +0100

Merge branch 'release_2.0'

Diffstat:
DCOPYING.LESSER | 165-------------------------------------------------------------------------------
MREADME.md | 29+++++++++++++++++++++++++----
Mcmake/CMakeLists.txt | 15+++++++++------
Msrc/aw.c | 81++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/aw.h | 144+++++++++++++++++++++++++------------------------------------------------------
Msrc/aw_c.h | 66++++++++++++++++--------------------------------------------------
Msrc/aw_mtl.c | 939+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/aw_obj.c | 847++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Asrc/test_aw.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_aw_mtl.c | 326++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/test_aw_obj.c | 402+++++++++++++++++++++++++++++++++++++++----------------------------------------
11 files changed, 1620 insertions(+), 1457 deletions(-)

diff --git a/COPYING.LESSER b/COPYING.LESSER @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/README.md b/README.md @@ -28,6 +28,27 @@ can be edited, built, tested and installed as any CMake project. ## Release notes +### Version 2.0 + +Full review and refactoring of the code. + +- The named groups, the maps and the materials become pod data structures + without any init/release/copy function. Their name is now exposed as a + regular `const char*` rather than stored in a `struct str` data structure. +- All floating point data are encoded in double precision rather than in single + precision. +- The `struct aw_obj_vertex` data structure stores only the index of the vertex + attributes. Their values are retrieved by the new `aw_obj_get_vertex_data` + function. +- Add an optional stream name parameter to the `aw_<obj|mtl>_load_stream` + functions: it allows the user to define the name of the stream to load, a + name that is internally used by the logger to print messages regarding the + stream. +- Rename the `get` functions. +- Rely on RSys to parse the input files and to perform text conversions. +- Add support of the `map_bump` keyword as an alias of the `bump` keyword in + the mtl fileformat. + ### Version 1.3.1 - Update the version of the RSys dependency to 0.6: replace the deprecated @@ -41,7 +62,7 @@ can be edited, built, tested and installed as any CMake project. ## License -AW is Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr). It is a free -software released under the [OSI](https://opensource.org)-approved LGPL v3+ -license. You are welcome to redistribute it under certain conditions; refer to -the COPYING file for details. +Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr). AW is free +software released under GPL v3+ license: GNU GPL version 3 or later. You are +welcome to redistribute it under certain conditions; refer to the COPYING file +for details. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr) +# Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) # # 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 @@ -26,7 +26,7 @@ set(AW_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) # Dependencies ################################################################################ find_package(RCMake 0.4 REQUIRED) -find_package(RSys 0.6 REQUIRED) +find_package(RSys 0.9 REQUIRED) set(CMAKE_MODULE_PATH ${RCMAKE_SOURCE_DIR}) include(rcmake) @@ -36,14 +36,14 @@ rcmake_append_runtime_dirs(_runtime_dirs RSys) ################################################################################ # Define targets ################################################################################ -set(VERSION_MAJOR 1) -set(VERSION_MINOR 3) -set(VERSION_PATCH 1) +set(VERSION_MAJOR 2) +set(VERSION_MINOR 0) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(AW_FILES_SRC aw_c.h aw.c aw_obj.c aw_mtl.c) set(AW_FILES_INC aw.h) -set(AW_FILES_DOC COPYING COPYING.LESSER README.md) +set(AW_FILES_DOC COPYING README.md) rcmake_prepend_path(AW_FILES_SRC ${AW_SOURCE_DIR}) rcmake_prepend_path(AW_FILES_INC ${AW_SOURCE_DIR}) rcmake_prepend_path(AW_FILES_DOC ${PROJECT_SOURCE_DIR}/../) @@ -76,6 +76,9 @@ if(NOT NO_TEST) target_link_libraries(test_aw_mtl aw) add_test(test_aw_mtl test_aw_mtl) rcmake_set_test_runtime_dirs(test_aw_mtl _runtime_dirs) + + add_executable(test_aw ${AW_SOURCE_DIR}/test_aw.c) + target_link_libraries(test_aw aw) endif(NOT NO_TEST) ################################################################################ diff --git a/src/aw.c b/src/aw.c @@ -1,8 +1,8 @@ -/* Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr) +/* Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -16,43 +16,86 @@ #define _POSIX_C_SOURCE 200112L /* strtok_r support */ #include "aw_c.h" +#include <rsys/cstr.h> +#include <rsys/logger.h> #include <rsys/mem_allocator.h> #include <string.h> /******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +print_info(const char* msg, void* ctx) +{ + fprintf(stderr, "%s%s", ctx ? (const char*)ctx : "info: ", msg); +} + +static void +print_err(const char* msg, void* ctx) +{ + fprintf(stderr, "%s%s", ctx ? (const char*)ctx : "error: ", msg); +} + +static void +print_warn(const char* msg, void* ctx) +{ + fprintf(stderr, "%s%s", ctx ? (const char*)ctx : "warning: ", msg); +} + +/******************************************************************************* * Local functions ******************************************************************************/ res_T -parse_floatX - (float* f, +parse_doubleX + (double* dblX, const unsigned int count_min, const unsigned int count_max, - const float range_min, - const float range_max, - const float default_value, - char** tk_ctxt) + const double range_min, + const double range_max, + const double default_value, + char** tk_ctx) { size_t i; - ASSERT(f && count_min <= count_max && range_min <= range_max && tk_ctxt); + ASSERT(dblX && count_min <= count_max && range_min <= range_max && tk_ctx); ASSERT(default_value >= range_min && default_value <= range_max); FOR_EACH(i, 0, count_max) { - char* real; - res_T res; - if(NULL == (real = strtok_r(NULL, " ", tk_ctxt))) - break; - res = string_to_float(real, f + i); - if(res != RES_OK) - return res; - if(f[i] < range_min || f[i] > range_max) + char* real = strtok_r(NULL, " \t", tk_ctx); + res_T res = RES_OK; + + if(!real) break; + + res = cstr_to_double(real, dblX + i); + if(res != RES_OK) return res; + + if(dblX[i] < range_min || dblX[i] > range_max) return RES_BAD_ARG; } if(i < count_min) return RES_BAD_ARG; FOR_EACH(i, i, count_max) - f[i] = default_value; + dblX[i] = default_value; + + return RES_OK; +} +res_T +setup_default_logger + (struct mem_allocator* allocator, + struct logger* logger, + const char* prefix_info, /* May be NULL */ + const char* prefix_error, /* May be NULL */ + const char* prefix_warning) /* May be NULL */ +{ + res_T res = RES_OK; + ASSERT(logger); + res = logger_init(allocator, logger); + if(res != RES_OK) return res; + logger_set_stream(logger, LOG_OUTPUT, print_info, (void*)prefix_info); + logger_set_stream(logger, LOG_ERROR, print_err, (void*)prefix_error); + logger_set_stream(logger, LOG_WARNING, print_warn, (void*)prefix_warning); return RES_OK; } + diff --git a/src/aw.h b/src/aw.h @@ -1,8 +1,8 @@ -/* Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr) +/* Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -73,49 +73,55 @@ struct aw_obj_face { }; struct aw_obj_named_group { - struct str name; - size_t face_id; /* Index of the first group face */ + const char* name; + size_t face_id; size_t faces_count; }; struct aw_obj_smooth_group { - char is_smoothed; size_t face_id; /* Index of the first smooth group face */ size_t faces_count; + char is_smoothed; }; struct aw_obj_vertex { - float position[4]; - float normal[3]; - float texcoord[3]; + size_t position_id; + size_t texcoord_id; + size_t normal_id; +}; + +struct aw_obj_vertex_data { + double position[4]; + double normal[3]; + double texcoord[3]; }; struct aw_color { - float value[3]; + double value[3]; enum aw_color_space color_space; }; struct aw_map { - struct str filename; /* str_len == 0 <=> Not defined */ + const char* filename; /* NULL <=> Not defined */ int options_mask; - float image_bias; /* Scalar to add to the image pixels */ - float image_scale; /* Scalar to multiply to the image pixels */ - float texcoord_bias[3]; - float texcoord_scale[3]; - float texcoord_turbulence[3]; + double image_bias; /* Scalar to add to the image pixels */ + double image_scale; /* Scalar to multiply to the image pixels */ + double texcoord_bias[3]; + double texcoord_scale[3]; + double texcoord_turbulence[3]; size_t resolution; /* image size = resolution x resolution */ enum aw_map_channel scalar; /* Channel used to create a scalar texture */ - float bump_multiplier; /* Only available on bump maps */ + double bump_multiplier; /* Only available on bump maps */ }; struct aw_material { - struct str name; + const char* name; struct aw_color ambient; struct aw_color diffuse; struct aw_color specular; struct aw_color transmission; - float specular_exponent; - float refraction_index; + double specular_exponent; + double refraction_index; size_t illumination_model; /* In [0, 10] */ struct aw_map ambient_map; struct aw_map diffuse_map; @@ -157,7 +163,8 @@ aw_obj_load AW_API res_T aw_obj_load_stream (struct aw_obj* obj, - FILE* stream); + FILE* stream, + const char* stream_name); /* May be NULL <=> default name, i.e. "stream" */ AW_API res_T aw_obj_clear @@ -169,46 +176,52 @@ aw_obj_purge (struct aw_obj* obj); AW_API res_T -aw_obj_desc_get - (struct aw_obj* obj, +aw_obj_get_desc + (const struct aw_obj* obj, struct aw_obj_desc* desc); AW_API res_T -aw_obj_face_get +aw_obj_get_face (const struct aw_obj* obj, const size_t face_id, struct aw_obj_face* face); AW_API res_T -aw_obj_group_get +aw_obj_get_group (const struct aw_obj* obj, const size_t group_id, struct aw_obj_named_group* group); AW_API res_T -aw_obj_smooth_group_get +aw_obj_get_smooth_group (const struct aw_obj* obj, const size_t smooth_group_id, struct aw_obj_smooth_group* smooth_group); AW_API res_T -aw_obj_mtl_get +aw_obj_get_mtl (const struct aw_obj* obj, const size_t mtl_id, struct aw_obj_named_group* mtl); AW_API res_T -aw_obj_mtllib_get +aw_obj_get_mtllib (const struct aw_obj* obj, const size_t mtllib_id, const char** mtllib); AW_API res_T -aw_obj_vertex_get +aw_obj_get_vertex (const struct aw_obj* obj, const size_t vertex_id, struct aw_obj_vertex* vertex); +AW_API res_T +aw_obj_get_vertex_data + (const struct aw_obj* obj, + const struct aw_obj_vertex* vertex, + struct aw_obj_vertex_data* vertex_data); + /******************************************************************************* * Mtl functions ******************************************************************************/ @@ -235,7 +248,8 @@ aw_mtl_load AW_API res_T aw_mtl_load_stream (struct aw_mtl* mtl, - FILE* stream); + FILE* stream, + const char* stream_name); /* May be NULL <=> default name, i.e. "stream" */ AW_API res_T aw_mtl_clear @@ -247,83 +261,17 @@ aw_mtl_purge (struct aw_mtl* mtl); AW_API res_T -aw_mtl_materials_count_get +aw_mtl_get_materials_count (struct aw_mtl* mtl, size_t* materials_count); /* The filled material must be released by the aw_material_release function */ AW_API res_T -aw_mtl_material_get +aw_mtl_get_material (struct aw_mtl* mtl, const size_t imaterial, struct aw_material* material); -/******************************************************************************* - * Obj group functions - ******************************************************************************/ -AW_API res_T -aw_obj_named_group_init - (struct mem_allocator* allocator, - struct aw_obj_named_group* grp); - -AW_API res_T -aw_obj_named_group_release - (struct aw_obj_named_group* grp); - -AW_API res_T -aw_obj_named_group_copy - (struct aw_obj_named_group* dst, - const struct aw_obj_named_group* src); - -AW_API res_T -aw_obj_named_group_copy_and_release - (struct aw_obj_named_group* dst, - struct aw_obj_named_group* src); - -/******************************************************************************* - * Map functions - ******************************************************************************/ -AW_API res_T -aw_map_init - (struct mem_allocator* allocator, - struct aw_map* map); - -AW_API res_T -aw_map_release - (struct aw_map* map); - -AW_API res_T -aw_map_copy - (struct aw_map* dst, - const struct aw_map* src); - -AW_API res_T -aw_map_copy_and_release - (struct aw_map* dst, - struct aw_map* src); - -/******************************************************************************* - * Material functions - ******************************************************************************/ -AW_API res_T -aw_material_init - (struct mem_allocator* allocator, - struct aw_material* material); - -AW_API res_T -aw_material_release - (struct aw_material* material); - -AW_API res_T -aw_material_copy - (struct aw_material* dst, - const struct aw_material* src); - -AW_API res_T -aw_material_copy_and_release - (struct aw_material* dst, - struct aw_material* src); - END_DECLS #endif /* AW_H */ diff --git a/src/aw_c.h b/src/aw_c.h @@ -1,8 +1,8 @@ -/* Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr) +/* Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -18,57 +18,23 @@ #include "aw.h" -static FINLINE res_T -string_to_float(const char* str, float* f) -{ - char* ptr = NULL; - ASSERT(f); - if(!str) - return RES_BAD_ARG; - *f = (float)strtod(str, &ptr); - if(ptr == str || *ptr != '\0') - return RES_BAD_ARG; - return RES_OK; -} - -static FINLINE res_T -string_to_long(const char* str, long* i) -{ - char* ptr = NULL; - ASSERT(i); - if(!str) - return RES_BAD_ARG; - *i = strtol(str, &ptr, 10); - if(ptr == str || *ptr != '\0') - return RES_BAD_ARG; - return RES_OK; -} - -static FINLINE res_T -string_to_size_t(const char* str, size_t* i) -{ - long l; - res_T res; - ASSERT(i); - - res = string_to_long(str, &l); - if(res != RES_OK) - return res; - if(l < 0) - return RES_BAD_ARG; - *i = (size_t)l; - return RES_OK; -} - extern LOCAL_SYM res_T -parse_floatX - (float* f, +parse_doubleX + (double* dblX, const unsigned int count_min, const unsigned int count_max, - const float range_min, - const float range_max, - const float default_value, + const double range_min, + const double range_max, + const double default_value, char** tk_ctxt); +extern LOCAL_SYM res_T +setup_default_logger + (struct mem_allocator* allocator, + struct logger* logger, + const char* prefix_info, /* May be NULL */ + const char* prefix_error, /* May be NULL */ + const char* prefix_warning); /* May be NULL */ + #endif /* AW_C_H */ diff --git a/src/aw_mtl.c b/src/aw_mtl.c @@ -1,8 +1,8 @@ -/* Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr) +/* Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -17,13 +17,13 @@ #include "aw_c.h" -#include <rsys/clock_time.h> -#include <rsys/dynamic_array_char.h> -#include <rsys/float3.h> +#include <rsys/cstr.h> +#include <rsys/double3.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> #include <rsys/str.h> +#include <rsys/text_reader.h> #include <float.h> @@ -32,6 +32,10 @@ #pragma warning(disable:4706) /* Assignment within a condition */ #endif +static const char* MSG_PREFIX_INFO = "load-mtl:info: "; +static const char* MSG_PREFIX_ERROR = "load-mtl:error: "; +static const char* MSG_PREFIX_WARNING = "load-mtl:warning: "; + enum map_type { MAP_COMMON = BIT(0), MAP_SCALAR = BIT(1), @@ -39,19 +43,196 @@ enum map_type { }; /******************************************************************************* - * Definition of the aw_mtl opaque data structure + * Map data structure + ******************************************************************************/ +struct map { + struct str filename; /* str_len == 0 <=> Not defined */ + int options_mask; + double image_bias; /* Scalar to add to the image pixels */ + double image_scale; /* Scalar to multiply to the image pixels */ + double texcoord_bias[3]; + double texcoord_scale[3]; + double texcoord_turbulence[3]; + size_t resolution; /* image size = resolution x resolution */ + enum aw_map_channel scalar; /* Channel used to create a scalar texture */ + double bump_multiplier; /* Only available on bump maps */ +}; + +static INLINE void +map_init(struct mem_allocator* allocator, struct map* map) +{ + ASSERT(map); + str_init(allocator, &map->filename); + map->options_mask = 0; + map->image_bias = 0.f; + map->image_scale = 1.f; + d3_splat(map->texcoord_bias, 0.f); + d3_splat(map->texcoord_scale, 1.f); + d3_splat(map->texcoord_turbulence, 0.f); + map->resolution = 0; + map->scalar = AW_MAP_CHANNEL_LUMINANCE; + map->bump_multiplier = 1.0f; +} + +static INLINE void +map_release(struct map* map) +{ + ASSERT(map); + str_release(&map->filename); +} + +static INLINE void +map_copy_pod(struct map* dst, const struct map* src) +{ + ASSERT(dst && src); + dst->options_mask = src->options_mask; + dst->image_bias = src->image_bias; + dst->image_scale = src->image_scale; + d3_set(dst->texcoord_bias, src->texcoord_bias); + d3_set(dst->texcoord_scale, src->texcoord_scale); + d3_set(dst->texcoord_turbulence, src->texcoord_turbulence); + dst->resolution = src->resolution; + dst->scalar = src->scalar; + dst->bump_multiplier = src->bump_multiplier; +} + +static INLINE res_T +map_copy(struct map* dst, const struct map* src) +{ + map_copy_pod(dst, src); + return str_copy(&dst->filename, &src->filename); +} + +static INLINE res_T +map_copy_and_release(struct map* dst, struct map* src) +{ + map_copy_pod(dst, src); + return str_copy_and_release(&dst->filename, &src->filename); +} + +static INLINE void +map_to_aw_map(const struct map* map, struct aw_map* aw_map) +{ + ASSERT(map && aw_map); + aw_map->filename = str_is_empty(&map->filename) ? NULL : str_cget(&map->filename); + aw_map->options_mask = map->options_mask; + aw_map->image_bias = map->image_bias; + aw_map->image_scale = map->image_scale; + d3_set(aw_map->texcoord_bias, map->texcoord_bias); + d3_set(aw_map->texcoord_scale, map->texcoord_scale); + d3_set(aw_map->texcoord_turbulence, map->texcoord_turbulence); + aw_map->resolution = map->resolution; + aw_map->scalar = map->scalar; + aw_map->bump_multiplier = map->bump_multiplier; +} + +/******************************************************************************* + * Material API ******************************************************************************/ +struct material { + struct str name; + struct aw_color ambient; + struct aw_color diffuse; + struct aw_color specular; + struct aw_color transmission; + double specular_exponent; + double refraction_index; + size_t illumination_model; /* In [0, 10] */ + struct map ambient_map; + struct map diffuse_map; + struct map specular_map; + struct map specular_exponent_map; /* Scalar texture */ + struct map bump_map; /* Scalar texture with valid bump multiplier */ +}; + +static INLINE void +material_init(struct mem_allocator* allocator, struct material* mtl) +{ + ASSERT(mtl); + memset(mtl, 0, sizeof(struct aw_material)); + str_init(allocator, &mtl->name); + map_init(allocator, &mtl->ambient_map); + map_init(allocator, &mtl->diffuse_map); + map_init(allocator, &mtl->specular_map); + map_init(allocator, &mtl->specular_exponent_map); + map_init(allocator, &mtl->bump_map); +} + +static INLINE void +material_release(struct material* mtl) +{ + ASSERT(mtl); + str_release(&mtl->name); + map_release(&mtl->ambient_map); + map_release(&mtl->diffuse_map); + map_release(&mtl->specular_map); + map_release(&mtl->specular_exponent_map); + map_release(&mtl->bump_map); +} + +static INLINE void +material_copy_pod(struct material* dst, const struct material* src) +{ + ASSERT(dst && src); + dst->ambient = src->ambient; + dst->diffuse = src->diffuse; + dst->specular = src->specular; + dst->transmission = src->transmission; + dst->specular_exponent = src->specular_exponent; + dst->refraction_index = src->refraction_index; + dst->illumination_model = src->illumination_model; +} + +static INLINE res_T +material_copy(struct material* dst, const struct material* src) +{ + res_T res = RES_OK; + ASSERT(dst && src); + material_copy_pod(dst, src); + #define CALL(Func) if(RES_OK != (res = Func)) return res + CALL(str_copy(&dst->name, &src->name)); + CALL(map_copy(&dst->ambient_map, &src->ambient_map)); + CALL(map_copy(&dst->diffuse_map, &src->diffuse_map)); + CALL(map_copy(&dst->specular_map, &src->specular_map)); + CALL(map_copy(&dst->specular_exponent_map, &src->specular_exponent_map)); + CALL(map_copy(&dst->bump_map, &src->bump_map)); + #undef CALL + return RES_OK; +} + +static INLINE res_T +material_copy_and_release(struct material* dst, struct material* src) +{ + res_T res = RES_OK; + ASSERT(dst && src); + material_copy_pod(dst, src); + #define CALL(Func) if(RES_OK != (res = Func)) return res + CALL(str_copy_and_release(&dst->name, &src->name)); + CALL(map_copy_and_release(&dst->ambient_map, &src->ambient_map)); + CALL(map_copy_and_release(&dst->diffuse_map, &src->diffuse_map)); + CALL(map_copy_and_release(&dst->specular_map, &src->specular_map)); + CALL(map_copy_and_release + (&dst->specular_exponent_map, &src->specular_exponent_map)); + CALL(map_copy_and_release(&dst->bump_map, &src->bump_map)); + #undef CALL + return RES_OK; +} + /* Generate the darray_mtl data structure */ #define DARRAY_NAME material -#define DARRAY_DATA struct aw_material -#define DARRAY_FUNCTOR_INIT aw_material_init -#define DARRAY_FUNCTOR_RELEASE aw_material_release -#define DARRAY_FUNCTOR_COPY aw_material_copy +#define DARRAY_DATA struct material +#define DARRAY_FUNCTOR_INIT material_init +#define DARRAY_FUNCTOR_RELEASE material_release +#define DARRAY_FUNCTOR_COPY material_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE material_copy_and_release #include <rsys/dynamic_array.h> +/******************************************************************************* + * Definition of the aw_mtl opaque data structure + ******************************************************************************/ struct aw_mtl { struct darray_material materials; - struct aw_material* newmtl; /* Pointer toward the current material */ + struct material* newmtl; /* Pointer toward the current material */ const char* filename; /* Currently parsed file. Use in error messages */ size_t iline; /* Currently parsed line index. Use in error messages */ @@ -59,117 +240,160 @@ struct aw_mtl { ref_T ref; struct mem_allocator* allocator; struct logger* logger; + struct logger logger__; /* Default logger */ int verbose; }; /******************************************************************************* * Helper functions ******************************************************************************/ -static INLINE res_T -parse_name(struct str* name, char* tk, char** tk_ctxt) +static INLINE void +log_msg + (const struct aw_mtl* mtl, + const enum log_type stream, + const char* msg, + va_list vargs) { - res_T res = RES_OK; - ASSERT(tk_ctxt && name); - - if(!tk) { - res = RES_BAD_ARG; - goto error; + ASSERT(mtl && msg); + if(mtl->verbose) { + res_T res; (void)res; + res = logger_vprint(mtl->logger, stream, msg, vargs); + ASSERT(res == RES_OK); } - str_clear(name); - do { - res = str_append(name, tk); - if(res != RES_OK) goto error; - } while((tk = strtok_r(NULL, " \t", tk_ctxt))); +} -exit: - return res; -error: - str_clear(name); - goto exit; +static INLINE void +log_err(const struct aw_mtl* mtl, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(mtl && msg); + + va_start(vargs_list, msg); + log_msg(mtl, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +static INLINE void +log_warn(const struct aw_mtl* mtl, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(mtl && msg); + + va_start(vargs_list, msg); + log_msg(mtl, LOG_WARNING, msg, vargs_list); + va_end(vargs_list); } static res_T -parse_newmtl(struct aw_mtl* mtl, char** word_tk) +parse_newmtl(struct aw_mtl* mtl, char** tk_ctx) { - char* word; + struct material* newmtl = NULL; + char* tk = NULL; size_t nmtls; - res_T res; - ASSERT(mtl && word_tk); + res_T res = RES_OK; + ASSERT(mtl && tk_ctx); - word = strtok_r(NULL, "\n", word_tk); - if(!word) - return RES_BAD_ARG; + tk = strtok_r(NULL, " \t", tk_ctx); /* Blanks are prohibited in mtl name */ + if(!tk) { + res = RES_BAD_ARG; + goto error; + } nmtls = darray_material_size_get(&mtl->materials); + + /* Allocate the new material */ res = darray_material_resize(&mtl->materials, nmtls + 1); - if(res != RES_OK) - return res; + if(res != RES_OK) goto error; - mtl->newmtl = darray_material_data_get(&mtl->materials) + nmtls; - res = parse_name(&mtl->newmtl->name, word, word_tk); - if(res != RES_OK) { - darray_material_pop_back(&mtl->materials); - mtl->newmtl = NULL; - return res; - } + /* Fetch the new material */ + newmtl = darray_material_data_get(&mtl->materials) + nmtls; + + /* Setup the material name */ + res = str_set(&newmtl->name, tk); + if(res != RES_OK) goto error; + + /* Set the new material as the material to parse */ + mtl->newmtl = newmtl; + +exit: return RES_OK; +error: + if(newmtl) darray_material_pop_back(&mtl->materials); + goto exit; } static res_T -parse_color(struct aw_mtl* mtl, struct aw_color* col, char** word_tk) +parse_color(struct aw_mtl* mtl, struct aw_color* col, char** tk_ctx) { - char* word; + char* tk = NULL; res_T res = RES_OK; - ASSERT(mtl && col && word_tk); + ASSERT(mtl && col && tk_ctx); - word = strtok_r(NULL, " \t", word_tk); - if(!word) - return RES_BAD_ARG; + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + res = RES_BAD_ARG; + goto error; + } - if(!strcmp(word, "spectral")) { - if(mtl->verbose) { - logger_print - (mtl->logger, LOG_ERROR, "spectral colors are not supported\n"); - } - return RES_BAD_ARG; + if(!strcmp(tk, "spectral")) { + log_err(mtl, "spectral colors are not supported\n"); + res = RES_BAD_ARG; + goto error; } - col->color_space = strcmp(word, "xyz") == 0 ? AW_COLOR_XYZ : AW_COLOR_RGB; - if(col->color_space == AW_COLOR_XYZ - && !(word = strtok_r(NULL, " \t", word_tk))) - return RES_BAD_ARG; + if(strcmp(tk, "xyz")) { + col->color_space = AW_COLOR_RGB; + } else { + col->color_space = AW_COLOR_XYZ; + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + res = RES_BAD_ARG; + goto error; + } + } - if(RES_OK != (res = string_to_float(word, &col->value[0]))) - return res; + res = cstr_to_double(tk, &col->value[0]); + if(res != RES_OK) goto error; /* If only the first component is defined the second and third components are * assumed to be equal to the first one */ - word = strtok_r(NULL, " \t", word_tk); - if(!word) { - col->value[1] = col->value[2] = col->value[0]; + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + col->value[1] = col->value[0]; + col->value[2] = col->value[0]; } else { - if(RES_OK != (res = string_to_float(word, &col->value[1]))) - return res; - word = strtok_r(NULL, " \t", word_tk); - if(RES_OK != (res = string_to_float(word, &col->value[2]))) - return res; + res = cstr_to_double(tk, &col->value[1]); + if(res != RES_OK) goto error; + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { res = RES_BAD_ARG; goto error; } + + res = cstr_to_double(tk, &col->value[2]); + if(res == RES_OK) goto error; } - return RES_OK; + +exit: + return res; +error: + goto exit; } static INLINE res_T parse_size_t - (size_t* s, const size_t range_min, const size_t range_max, char** word_tk) + (size_t* s, const size_t range_min, const size_t range_max, char** tk_ctx) { - char* word; + unsigned long ul; + char* tk = NULL; res_T res = RES_OK; - ASSERT(s && word_tk && range_min < range_max); + ASSERT(s && tk_ctx && range_min < range_max); - word = strtok_r(NULL, "\n", word_tk); - if(RES_OK != (res = string_to_size_t(word, s))) - return res; - if(range_min > *s || range_max < *s) - return RES_BAD_ARG; + tk = strtok_r(NULL, "\n", tk_ctx); + if(!tk) return res; + + res = cstr_to_ulong(tk, &ul); + if(res != RES_OK) return res; + if((unsigned long)range_min > ul || (unsigned long)range_max < ul) return res; + *s = ul; return RES_OK; } @@ -177,40 +401,44 @@ static res_T parse_bool_option (int* options_mask, const enum aw_map_flag option, - char** tk_ctxt) + char** tk_ctx) { - char* word; - ASSERT(options_mask && tk_ctxt); - word = strtok_r(NULL, " \t", tk_ctxt); - if(!word) - return RES_BAD_ARG; - if(strcmp(word, "on") == 0) { + char* tk; + ASSERT(options_mask && tk_ctx); + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) return RES_BAD_ARG; + + if(!strcmp(tk, "on")) { *options_mask |= (int)option; - } else if(strcmp(word, "off") != 0) { + } else if(!strcmp(tk, "off")) { + *options_mask &= ~((int)option); + } else { return RES_BAD_ARG; } return RES_OK; } static FINLINE res_T -parse_imfchan_option(enum aw_map_channel* channel, char** tk_ctxt) +parse_imfchan_option(enum aw_map_channel* channel, char** tk_ctx) { - char* word; - ASSERT(channel && tk_ctxt); - word = strtok_r(NULL, " \t", tk_ctxt); - if(!word) - return RES_BAD_ARG; - if(!strcmp(word, "r")) { + char* tk = NULL; + ASSERT(channel && tk_ctx); + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) return RES_BAD_ARG; + + if(!strcmp(tk, "r")) { *channel = AW_MAP_CHANNEL_RED; - } else if(!strcmp(word, "g")) { + } else if(!strcmp(tk, "g")) { *channel = AW_MAP_CHANNEL_GREEN; - } else if(!strcmp(word, "b")) { + } else if(!strcmp(tk, "b")) { *channel = AW_MAP_CHANNEL_BLUE; - } else if(!strcmp(word, "m")) { + } else if(!strcmp(tk, "m")) { *channel = AW_MAP_CHANNEL_MATTE; - } else if(!strcmp(word, "l")) { + } else if(!strcmp(tk, "l")) { *channel = AW_MAP_CHANNEL_LUMINANCE; - } else if(!strcmp(word, "z")) { + } else if(!strcmp(tk, "z")) { *channel = AW_MAP_CHANNEL_DEPTH; } else { return RES_BAD_ARG; @@ -219,166 +447,182 @@ parse_imfchan_option(enum aw_map_channel* channel, char** tk_ctxt) } static res_T -parse_map - (struct aw_map* map, - const enum map_type type, - char** tk_ctxt) -{ - char* word; - ASSERT(map && tk_ctxt); - - word = strtok_r(NULL, " \t", tk_ctxt); - while(word) { - res_T res; - - if(!strcmp(word, "-blendu")) { - res = parse_bool_option(&map->options_mask, AW_MAP_BLEND_U, tk_ctxt); - } else if(!strcmp(word, "-blendv")) { - res = parse_bool_option(&map->options_mask, AW_MAP_BLEND_V, tk_ctxt); - } else if(!strcmp(word, "-cc")) { +parse_map(struct map* map, const enum map_type type, char** tk_ctx) +{ + char* tk = NULL; + res_T res = RES_OK; + ASSERT(map && tk_ctx); + + for(;;) { + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp(tk, "-blendu")) { + res = parse_bool_option(&map->options_mask, AW_MAP_BLEND_U, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-blendv")) { + res = parse_bool_option(&map->options_mask, AW_MAP_BLEND_V, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-cc")) { res = parse_bool_option - (&map->options_mask, AW_MAP_COLOR_CORRECTION, tk_ctxt); - } else if(!strcmp(word, "-clamp")) { - res = parse_bool_option(&map->options_mask, AW_MAP_CLAMP, tk_ctxt); - } else if(!strcmp(word, "-imfchan") && (type & MAP_SCALAR)) { - res = parse_imfchan_option(&map->scalar, tk_ctxt); - } else if(!strcmp(word, "-mm")) { /* Image bias and scale */ - res = parse_floatX - (&map->image_bias, 1, 1, -FLT_MAX, FLT_MAX, 0.f, tk_ctxt); - if(res == RES_OK) { - res = parse_floatX - (&map->image_scale, 1, 1, -FLT_MAX, FLT_MAX, 0.f, tk_ctxt); + (&map->options_mask, AW_MAP_COLOR_CORRECTION, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-clamp")) { + res = parse_bool_option(&map->options_mask, AW_MAP_CLAMP, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-imfchan") && (type & MAP_SCALAR)) { + res = parse_imfchan_option(&map->scalar, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-mm")) { /* Image bias and scale */ + res = parse_doubleX + (&map->image_bias, 1, 1, -DBL_MAX, DBL_MAX, 0.f, tk_ctx); + if(res != RES_OK) goto error; + res = parse_doubleX + (&map->image_scale, 1, 1, -DBL_MAX, DBL_MAX, 0.f, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-o")) { /* Texcoord offset */ + res = parse_doubleX + (map->texcoord_bias, 1, 3, -DBL_MAX, DBL_MAX, 0.f, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-s")) { /* Texcoord scale */ + res = parse_doubleX + (map->texcoord_scale, 1, 3, -DBL_MAX, DBL_MAX, 1.f, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-t")) { /* Texcoord turbulence */ + res = parse_doubleX + (map->texcoord_turbulence, 1, 3, -DBL_MAX, DBL_MAX, 0.f, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-texres")) { /* Texture resolution */ + res = parse_size_t(&map->resolution, 1, SIZE_MAX, tk_ctx); + if(res != RES_OK) goto error; + } else if(!strcmp(tk, "-bm") && (type == MAP_BUMP)) {/* Bump multiplier */ + res = parse_doubleX + (&map->bump_multiplier, 1, 1, -DBL_MAX, DBL_MAX, 0.f, tk_ctx); + if(res != RES_OK) goto error; + } else { /* Map filename */ + res = str_set(&map->filename, tk); + if(res != RES_OK) goto error; + tk = strtok_r(NULL, "", tk_ctx); + if(tk) { + res = str_append_char(&map->filename, ' '); + if(res != RES_OK) goto error; + res = str_append(&map->filename, strtok_r(NULL, "", tk_ctx)); + if(res != RES_OK) goto error; } - } else if(!strcmp(word, "-o")) { /* Texcoord offset */ - res = parse_floatX - (map->texcoord_bias, 1, 3, -FLT_MAX, FLT_MAX, 0.f, tk_ctxt); - } else if(!strcmp(word, "-s")) { /* Texcoord scale */ - res = parse_floatX - (map->texcoord_scale, 1, 3, -FLT_MAX, FLT_MAX, 1.f, tk_ctxt); - } else if(!strcmp(word, "-t")) { /* Texcoord turbulence */ - res = parse_floatX - (map->texcoord_turbulence, 1, 3,-FLT_MAX, FLT_MAX, 0.f, tk_ctxt); - } else if(!strcmp(word, "-texres")) { /* Texture resolution */ - res = parse_size_t(&map->resolution, 1, SIZE_MAX, tk_ctxt); - } else if(!strcmp(word, "-bm") && (type == MAP_BUMP)) {/* Bump multiplier */ - res = parse_floatX - (&map->bump_multiplier, 1, 1, -FLT_MAX, FLT_MAX, 0.f, tk_ctxt); - } else { - res = parse_name(&map->filename, word, tk_ctxt); + break; /* The map is fully parsed */ } - if(res != RES_OK) - return res; - word = strtok_r(NULL, " \t", tk_ctxt); } - return RES_OK; + +exit: + return res; +error: + goto exit; } static res_T -parse_mtl_line(struct aw_mtl* mtl, char* line) +parse_mtl_line(struct aw_mtl* mtl, struct txtrdr* txtrdr) { + char* tk = NULL; + char* tk_ctx = NULL; res_T res = RES_OK; - char* word, *word_tk; - ASSERT(mtl && line); - - word = strtok_r(line, " \t", &word_tk); - if(word) { - if(word[0] == '#') { /* Comment */ - goto exit; - } else if(!strcmp(word, "newmtl")) { /* Material name declaration */ - res = parse_newmtl(mtl, &word_tk); - } else if(mtl->newmtl == NULL) { - res = RES_BAD_ARG; - } else if(!strcmp(word, "Ka")) { /* Ambient reflectivity */ - res = parse_color(mtl, &mtl->newmtl->ambient, &word_tk); - } else if(!strcmp(word, "Kd")) { /* Diffuse reflectivity */ - res = parse_color(mtl, &mtl->newmtl->diffuse, &word_tk); - } else if(!strcmp(word, "Ks")) { /* Specular reflectivity */ - res = parse_color(mtl, &mtl->newmtl->specular, &word_tk); - } else if(!strcmp(word, "Tf")) { /* Transimission filter */ - res = parse_color(mtl, &mtl->newmtl->transmission, &word_tk); - } else if(!strcmp(word, "Ns")) { /* Specular exponent */ - res = parse_floatX - (&mtl->newmtl->specular_exponent, 1, 1, 0.f, FLT_MAX, 0.f, &word_tk); - } else if(!strcmp(word, "Ni")) { /* Refraction index */ - res = parse_floatX - (&mtl->newmtl->refraction_index, 1, 1, 0.001f, 10.f, 0.001f,&word_tk); - } else if(!strcmp(word, "illum")) { /* Illumination model */ - res = parse_size_t(&mtl->newmtl->illumination_model, 0, 10, &word_tk); - } else if(!strcmp(word, "map_Ka")) { /* Ambient texture */ - res = parse_map(&mtl->newmtl->ambient_map, MAP_COMMON, &word_tk); - } else if(!strcmp(word, "map_Kd")) { /* Diffuse texture */ - res = parse_map(&mtl->newmtl->diffuse_map, MAP_COMMON, &word_tk); - } else if(!strcmp(word, "map_Ks")) { /* Specular texture */ - res = parse_map(&mtl->newmtl->specular_map, MAP_COMMON, &word_tk); - } else if(!strcmp(word, "map_Ns")) { /* Specular exponent texture */ - res = parse_map - (&mtl->newmtl->specular_exponent_map, MAP_SCALAR, &word_tk); - } else if(!strcmp(word, "bump")) { /* Bump map */ - res = parse_map(&mtl->newmtl->bump_map, MAP_BUMP, &word_tk); - } else { - res = RES_OK; - if(mtl->verbose) { - logger_print(mtl->logger, LOG_WARNING, - "%s:%lu: warning: ignored or malformed directive %s\n", - mtl->filename, (unsigned long)mtl->iline, word); - } - while((word = strtok_r(NULL, " \t", &word_tk))); /* Skip spaces */ - } - if(res != RES_OK) - goto error; - if((word = strtok_r(NULL, " ", &word_tk))) { - if(mtl->verbose) { - logger_print(mtl->logger, LOG_ERROR, "%s:%lu: unexpected directive %s\n", - mtl->filename, (unsigned long)mtl->iline, word); - } - res = RES_BAD_ARG; - goto error; - } + ASSERT(mtl && txtrdr); + + tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + ASSERT(tk); /* A line should exist since it was parsed by txtrdr */ + + if(!strcmp(tk, "newmtl")) { /* Material name declaration */ + res = parse_newmtl(mtl, &tk_ctx); + } else if(mtl->newmtl == NULL) { + res = RES_BAD_ARG; + } else if(!strcmp(tk, "Ka")) { /* Ambient reflectivity */ + res = parse_color(mtl, &mtl->newmtl->ambient, &tk_ctx); + } else if(!strcmp(tk, "Kd")) { /* Diffuse reflectivity */ + res = parse_color(mtl, &mtl->newmtl->diffuse, &tk_ctx); + } else if(!strcmp(tk, "Ks")) { /* Specular reflectivity */ + res = parse_color(mtl, &mtl->newmtl->specular, &tk_ctx); + } else if(!strcmp(tk, "Tf")) { /* Transimission filter */ + res = parse_color(mtl, &mtl->newmtl->transmission, &tk_ctx); + } else if(!strcmp(tk, "Ns")) { /* Specular exponent */ + res = parse_doubleX + (&mtl->newmtl->specular_exponent, 1, 1, 0, DBL_MAX, 0, &tk_ctx); + } else if(!strcmp(tk, "Ni")) { /* Refraction index */ + res = parse_doubleX + (&mtl->newmtl->refraction_index, 1, 1, 0.001, 10, 0.001, &tk_ctx); + } else if(!strcmp(tk, "illum")) { /* Illumination model */ + res = parse_size_t(&mtl->newmtl->illumination_model, 0, 10, &tk_ctx); + } else if(!strcmp(tk, "map_Ka")) { /* Ambient texture */ + res = parse_map(&mtl->newmtl->ambient_map, MAP_COMMON, &tk_ctx); + } else if(!strcmp(tk, "map_Kd")) { /* Diffuse texture */ + res = parse_map(&mtl->newmtl->diffuse_map, MAP_COMMON, &tk_ctx); + } else if(!strcmp(tk, "map_Ks")) { /* Specular texture */ + res = parse_map(&mtl->newmtl->specular_map, MAP_COMMON, &tk_ctx); + } else if(!strcmp(tk, "map_Ns")) { /* Specular exponent texture */ + res = parse_map + (&mtl->newmtl->specular_exponent_map, MAP_SCALAR, &tk_ctx); + } else if(!strcmp(tk, "bump") || !strcmp(tk, "map_bump")) { /* Bump map */ + res = parse_map(&mtl->newmtl->bump_map, MAP_BUMP, &tk_ctx); + } else { + log_warn(mtl, + "%s:%lu: warning: ignored or malformed directive `%s'\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + strtok_r(NULL, "", &tk_ctx); /* Discard remaining text */ } + if(res != RES_OK) { + log_err(mtl, "%s:%lu: parsing failed.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + goto error; + } + + tk = strtok_r(NULL, "", &tk_ctx); + if(tk) { + log_err(mtl, "%s:%lu: unexpected text `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + exit: return res; error: - if(mtl->verbose) { - logger_print(mtl->logger, LOG_ERROR, "%s:%lu: error: parsing failed\n", - mtl->filename, (unsigned long)mtl->iline); - } goto exit; } -static void -mtl_clear(struct aw_mtl* mtl) +static res_T +load_stream(struct aw_mtl* mtl, FILE* stream, const char* stream_name) { - ASSERT(mtl); - darray_material_clear(&mtl->materials); - mtl->newmtl = NULL; -} + struct txtrdr* txtrdr = NULL; + res_T res = RES_OK; + ASSERT(mtl && stream && stream_name); -static FINLINE void -map_copy_pod__(struct aw_map* dst, const struct aw_map* src) -{ - ASSERT(dst && src); - dst->options_mask = src->options_mask; - dst->image_bias = src->image_bias; - dst->image_scale = src->image_scale; - f3_set(dst->texcoord_bias, src->texcoord_bias); - f3_set(dst->texcoord_scale, src->texcoord_scale); - f3_set(dst->texcoord_turbulence, src->texcoord_turbulence); - dst->resolution = src->resolution; - dst->scalar = src->scalar; - dst->bump_multiplier = src->bump_multiplier; -} + res = txtrdr_stream(mtl->allocator, stream, stream_name, '#', &txtrdr); + if(res != RES_OK) { + log_err(mtl, "Could not create the text reader.\n"); + goto error; + } -static FINLINE void -material_copy_pod__(struct aw_material* dst, const struct aw_material* src) -{ - ASSERT(dst && src); - dst->ambient = src->ambient; - dst->diffuse = src->diffuse; - dst->specular = src->specular; - dst->transmission = src->transmission; - dst->specular_exponent = src->specular_exponent; - dst->refraction_index = src->refraction_index; - dst->illumination_model = src->illumination_model; + for(;;) { + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + log_err(mtl, "%s: could not read the line `%lu'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + goto error; + } + + if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ + + res = parse_mtl_line(mtl, txtrdr); + if(res != RES_OK) goto error; + } + +exit: + if(txtrdr) txtrdr_ref_put(txtrdr); + return res; +error: + AW(mtl_clear(mtl)); + goto exit; } static void @@ -387,6 +631,7 @@ mtl_release(ref_T* ref) struct aw_mtl* mtl = CONTAINER_OF(ref, struct aw_mtl, ref); ASSERT(ref); darray_material_release(&mtl->materials); + if(mtl->logger == &mtl->logger__) logger_release(&mtl->logger__); MEM_RM(mtl->allocator, mtl); } @@ -416,13 +661,20 @@ aw_mtl_create } ref_init(&mtl->ref); mtl->allocator = allocator; - mtl->logger = logger ? logger : LOGGER_DEFAULT; mtl->verbose = verbose; darray_material_init(allocator, &mtl->materials); + if(logger) { + mtl->logger = logger; + } else { + res = setup_default_logger(mtl->allocator, &mtl->logger__, + MSG_PREFIX_INFO, MSG_PREFIX_ERROR, MSG_PREFIX_WARNING); + if(res != RES_OK) goto error; + mtl->logger = &mtl->logger__; + } + exit: - if(mtl_out) - *mtl_out = mtl; + if(mtl_out) *mtl_out = mtl; return res; error: if(mtl) { @@ -451,80 +703,47 @@ aw_mtl_ref_put(struct aw_mtl* mtl) res_T aw_mtl_load(struct aw_mtl* mtl, const char* filename) { - FILE* file; + FILE* file = NULL; res_T res = RES_OK; - if(!mtl || !filename) - return RES_BAD_ARG; + if(!mtl || !filename) { + res = RES_BAD_ARG; + goto error; + } - mtl->filename = filename; file = fopen(filename, "r"); if(!file) { - if(mtl->verbose) - logger_print(mtl->logger, LOG_ERROR, "Error opening `%s'\n", filename); - return RES_IO_ERR; + log_err(mtl, "Error opening `%s'\n", filename); + res = RES_IO_ERR; + goto error; } - res = aw_mtl_load_stream(mtl, file); - mtl->filename = NULL; - fclose(file); + res = load_stream(mtl, file, filename); + if(res != RES_OK) goto error; + +exit: + if(file) fclose(file); return res; +error: + goto exit; } res_T -aw_mtl_load_stream(struct aw_mtl* mtl, FILE* stream) +aw_mtl_load_stream(struct aw_mtl* mtl, FILE* stream, const char* stream_name) { - char* line; - struct darray_char buf; - const unsigned buf_chunk = 256; res_T res = RES_OK; - /* Avoid zealous "may be used uninitialized" warning of GCC 4.9.2 */ - memset(&buf, 0, sizeof(buf)); - if(!mtl || !stream) { res = RES_BAD_ARG; goto error; } - darray_char_init(mtl->allocator, &buf); - - res = darray_char_resize(&buf, buf_chunk); - if(res != RES_OK) - goto error; - if(!mtl->filename) - mtl->filename = "stream"; - mtl->iline = 1; - mtl_clear(mtl); - while((line = fgets - (darray_char_data_get(&buf), (int)darray_char_size_get(&buf), stream))) { - size_t last_char; - - while(!strrchr(line,'\n')) { /* Ensure that the whole line was read */ - res = darray_char_resize(&buf, darray_char_size_get(&buf) + buf_chunk); - if(res != RES_OK) - goto error; - line = darray_char_data_get(&buf); - if(!fgets(line + strlen(line), (int)buf_chunk, stream)) /* EOF */ - break; - } - /* Remove the newline character(s) */ - last_char = strlen(line); - while(last_char-- && (line[last_char]=='\n' || line[last_char]=='\r')); - line[last_char + 1] = '\0'; - - if(RES_OK != (res = parse_mtl_line(mtl, line))) - goto error; - ++mtl->iline; - } + res = load_stream(mtl, stream, stream_name ? stream_name : "stream"); + if(res != RES_OK) goto error; exit: - if(mtl && stream) - darray_char_release(&buf); return res; error: - if(mtl) - mtl_clear(mtl); goto exit; } @@ -547,7 +766,7 @@ aw_mtl_purge(struct aw_mtl* mtl) } res_T -aw_mtl_materials_count_get(struct aw_mtl* mtl, size_t* nmtls) +aw_mtl_get_materials_count(struct aw_mtl* mtl, size_t* nmtls) { if(!mtl || !nmtls) return RES_BAD_ARG; @@ -556,122 +775,30 @@ aw_mtl_materials_count_get(struct aw_mtl* mtl, size_t* nmtls) } res_T -aw_mtl_material_get +aw_mtl_get_material (struct aw_mtl* mtl, const size_t imaterial, struct aw_material* material) { - const struct aw_material* mtr; + const struct material* mat = NULL; + if(!mtl || !material || imaterial>=darray_material_size_get(&mtl->materials)) return RES_BAD_ARG; - mtr = darray_material_cdata_get(&mtl->materials) + imaterial; - return aw_material_copy(material, mtr); -} - -res_T -aw_map_init(struct mem_allocator* allocator, struct aw_map* map) -{ - if(!map) return RES_BAD_ARG; - str_init(allocator, &map->filename); - map->options_mask = 0; - map->image_bias = 0.f; - map->image_scale = 1.f; - f3_splat(map->texcoord_bias, 0.f); - f3_splat(map->texcoord_scale, 1.f); - f3_splat(map->texcoord_turbulence, 0.f); - map->resolution = 0; - map->scalar = AW_MAP_CHANNEL_LUMINANCE; - map->bump_multiplier = 1.0f; - return RES_OK; -} - -res_T -aw_map_release(struct aw_map* map) -{ - if(!map) return RES_BAD_ARG; - str_release(&map->filename); - return RES_OK; -} -res_T -aw_map_copy(struct aw_map* dst, const struct aw_map* src) -{ - if(!dst || !src) return RES_BAD_ARG; - if(dst == src) return RES_OK; - map_copy_pod__(dst, src); - return str_copy(&dst->filename, &src->filename); -} - -res_T -aw_map_copy_and_release(struct aw_map* dst, struct aw_map* src) -{ - if(!dst || !src) return RES_BAD_ARG; - if(dst == src) return RES_OK; - map_copy_pod__(dst, src); - return str_copy_and_release(&dst->filename, &src->filename); -} - -res_T -aw_material_init(struct mem_allocator* allocator, struct aw_material* mtl) -{ - if(!mtl) return RES_BAD_ARG; - memset(mtl, 0, sizeof(struct aw_material)); - str_init(allocator, &mtl->name); - AW(map_init(allocator, &mtl->ambient_map)); - AW(map_init(allocator, &mtl->diffuse_map)); - AW(map_init(allocator, &mtl->specular_map)); - AW(map_init(allocator, &mtl->specular_exponent_map)); - AW(map_init(allocator, &mtl->bump_map)); - return RES_OK; -} - -res_T -aw_material_release(struct aw_material* mtl) -{ - if(!mtl) return RES_BAD_ARG; - str_release(&mtl->name); - AW(map_release(&mtl->ambient_map)); - AW(map_release(&mtl->diffuse_map)); - AW(map_release(&mtl->specular_map)); - AW(map_release(&mtl->specular_exponent_map)); - AW(map_release(&mtl->bump_map)); - return RES_OK; -} - -res_T -aw_material_copy(struct aw_material* dst, const struct aw_material* src) -{ - res_T res; - if(!dst || !src) return RES_BAD_ARG; - if(dst == src) return RES_OK; - material_copy_pod__(dst, src); - #define CALL(Func) if(RES_OK != (res = Func)) return res - CALL(str_copy(&dst->name, &src->name)); - CALL(aw_map_copy(&dst->ambient_map, &src->ambient_map)); - CALL(aw_map_copy(&dst->diffuse_map, &src->diffuse_map)); - CALL(aw_map_copy(&dst->specular_map, &src->specular_map)); - CALL(aw_map_copy(&dst->specular_exponent_map, &src->specular_exponent_map)); - CALL(aw_map_copy(&dst->bump_map, &src->bump_map)); - #undef CALL - return RES_OK; -} - -res_T -aw_material_copy_and_release(struct aw_material* dst, struct aw_material* src) -{ - res_T res; - if(!dst || !src) return RES_BAD_ARG; - if(dst == src) return RES_OK; - material_copy_pod__(dst, src); - #define CALL(Func) if(RES_OK != (res = Func)) return res - CALL(str_copy_and_release(&dst->name, &src->name)); - CALL(aw_map_copy_and_release(&dst->ambient_map, &src->ambient_map)); - CALL(aw_map_copy_and_release(&dst->diffuse_map, &src->diffuse_map)); - CALL(aw_map_copy_and_release(&dst->specular_map, &src->specular_map)); - CALL(aw_map_copy_and_release - (&dst->specular_exponent_map, &src->specular_exponent_map)); - CALL(aw_map_copy_and_release(&dst->bump_map, &src->bump_map)); - #undef CALL + mat = darray_material_cdata_get(&mtl->materials) + imaterial; + material->name = str_cget(&mat->name); + material->ambient = mat->ambient; + material->diffuse = mat->diffuse; + material->specular = mat->specular; + material->transmission = mat->transmission; + material->specular_exponent = mat->specular_exponent; + material->refraction_index = mat->refraction_index; + material->illumination_model = mat->illumination_model; + map_to_aw_map(&mat->ambient_map, &material->ambient_map); + map_to_aw_map(&mat->diffuse_map, &material->diffuse_map); + map_to_aw_map(&mat->specular_map, &material->specular_map); + map_to_aw_map(&mat->specular_exponent_map, &material->specular_exponent_map); + map_to_aw_map(&mat->bump_map, &material->bump_map); return RES_OK; } diff --git a/src/aw_obj.c b/src/aw_obj.c @@ -1,8 +1,8 @@ -/* Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr) +/* Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -17,33 +17,29 @@ #include "aw_c.h" -#include <rsys/clock_time.h> -#include <rsys/dynamic_array_char.h> -#include <rsys/dynamic_array_float.h> -#include <rsys/float3.h> -#include <rsys/float4.h> +#include <rsys/cstr.h> +#include <rsys/dynamic_array_double.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> #include <rsys/str.h> +#include <rsys/text_reader.h> -#include <float.h> +#include <float.h> /* DBL_MAX & DBL_MIN definition */ +#include <stdarg.h> #ifdef COMPILER_CL #pragma warning(push) #pragma warning(disable:4706) /* Assignment within a condition */ #endif -struct vertex { - size_t iposition; - size_t inormal; - size_t itexcoord; -}; -static const struct vertex VERTEX_NULL = { AW_ID_NONE, AW_ID_NONE, AW_ID_NONE }; +static const char* MSG_PREFIX_INFO = "load-obj:info: "; +static const char* MSG_PREFIX_ERROR = "load-obj:error: "; +static const char* MSG_PREFIX_WARNING = "load-obj:warning: "; /* Generate the darray_vertex data structure */ #define DARRAY_NAME vertex -#define DARRAY_DATA struct vertex +#define DARRAY_DATA struct aw_obj_vertex #include <rsys/dynamic_array.h> /* Generate the darray_face data structure */ @@ -51,13 +47,56 @@ static const struct vertex VERTEX_NULL = { AW_ID_NONE, AW_ID_NONE, AW_ID_NONE }; #define DARRAY_DATA struct aw_obj_face #include <rsys/dynamic_array.h> +static const struct aw_obj_vertex VERTEX_NULL = { + AW_ID_NONE, AW_ID_NONE, AW_ID_NONE +}; + +struct named_group { + struct str name; + size_t face_id; /* Index of the first group face */ + size_t faces_count; +}; + +static INLINE void +named_group_init(struct mem_allocator* allocator, struct named_group* grp) +{ + str_init(allocator, &grp->name); +} + +static INLINE void +named_group_release(struct named_group* grp) +{ + ASSERT(grp); + str_release(&grp->name); +} + +static INLINE res_T +named_group_copy(struct named_group* dst, const struct named_group* src) +{ + ASSERT(dst && src); + if(dst == src) return RES_OK; + dst->face_id = src->face_id; + dst->faces_count = src->faces_count; + return str_copy(&dst->name, &src->name); +} + +static INLINE res_T +named_group_copy_and_release(struct named_group* dst, struct named_group* src) +{ + ASSERT(dst && src); + if(dst == src) return RES_OK; + dst->face_id = src->face_id; + dst->faces_count = src->faces_count; + return str_copy_and_release(&dst->name, &src->name); +} + /* Generate the darray_named_group data structure */ #define DARRAY_NAME named_group -#define DARRAY_DATA struct aw_obj_named_group -#define DARRAY_FUNCTOR_INIT aw_obj_named_group_init -#define DARRAY_FUNCTOR_RELEASE aw_obj_named_group_release -#define DARRAY_FUNCTOR_COPY aw_obj_named_group_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE aw_obj_named_group_copy_and_release +#define DARRAY_DATA struct named_group +#define DARRAY_FUNCTOR_INIT named_group_init +#define DARRAY_FUNCTOR_RELEASE named_group_release +#define DARRAY_FUNCTOR_COPY named_group_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE named_group_copy_and_release #include <rsys/dynamic_array.h> /* Generate the darray_smooth_group data structure */ @@ -75,9 +114,9 @@ static const struct vertex VERTEX_NULL = { AW_ID_NONE, AW_ID_NONE, AW_ID_NONE }; #include <rsys/dynamic_array.h> struct aw_obj { - struct darray_float positions; /* float4 */ - struct darray_float normals; /* float3 */ - struct darray_float texcoords; /* float3 */ + struct darray_double positions; /* double4 */ + struct darray_double normals; /* double3 */ + struct darray_double texcoords; /* double3 */ struct darray_vertex vertices; struct darray_face faces; struct darray_named_group groups; @@ -87,90 +126,141 @@ struct aw_obj { size_t igroups_active; /* Index toward the first active group */ - const char* filename; /* Currently parsed file. Use in messages */ - size_t iline; /* Currently parsed line index. Use in messages */ - ref_T ref; struct mem_allocator* allocator; struct logger* logger; + struct logger logger__; /* Default logger */ int verbose; }; /******************************************************************************* * Helper functions ******************************************************************************/ -static FINLINE void +static INLINE void +log_msg + (const struct aw_obj* obj, + const enum log_type stream, + const char* msg, + va_list vargs) +{ + ASSERT(obj && msg); + if(obj->verbose) { + res_T res; (void)res; + res = logger_vprint(obj->logger, stream, msg, vargs); + ASSERT(res == RES_OK); + } +} + +static INLINE void +log_err(const struct aw_obj* obj, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(obj && msg); + + va_start(vargs_list, msg); + log_msg(obj, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +static INLINE void +log_warn(const struct aw_obj* obj, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(obj && msg); + + va_start(vargs_list, msg); + log_msg(obj, LOG_WARNING, msg, vargs_list); + va_end(vargs_list); +} + +static INLINE void flush_groups(struct aw_obj* obj) { size_t nfaces, ngrps; ASSERT(obj); - if(0 == (nfaces = darray_face_size_get(&obj->faces))) - return; - if(0 == (ngrps = darray_named_group_size_get(&obj->groups))) - return; - if(obj->igroups_active >= ngrps) - return; + + nfaces = darray_face_size_get(&obj->faces); + if(!nfaces) return; /* No face to flush */ + + ngrps = darray_named_group_size_get(&obj->groups); + if(!ngrps) return; /* No group */ + + /* There should be an active group to flush if ngrps is not null */ + ASSERT(obj->igroups_active < ngrps); + + /* Setup the number of faces of each active group */ FOR_EACH(obj->igroups_active, obj->igroups_active, ngrps) { - struct aw_obj_named_group* grp; + struct named_group* grp; grp = darray_named_group_data_get(&obj->groups) + obj->igroups_active; ASSERT(grp->face_id <= nfaces); grp->faces_count = nfaces - grp->face_id; } } -static FINLINE void +static INLINE void flush_usemtl(struct aw_obj* obj) { - struct aw_obj_named_group* mtl; + struct named_group* mtl; size_t nfaces, ngrps; ASSERT(obj); - if(0 == (nfaces = darray_face_size_get(&obj->faces))) - return; - if(0 == (ngrps = darray_named_group_size_get(&obj->usemtls))) - return; + + nfaces = darray_face_size_get(&obj->faces); + if(!nfaces) return; /* No face to flush */ + + ngrps = darray_named_group_size_get(&obj->usemtls); + if(!ngrps) return; /* No group */ + + /* Setup the number of faces of the current mtl */ mtl = darray_named_group_data_get(&obj->usemtls) + (ngrps - 1); ASSERT(mtl->face_id <= nfaces); mtl->faces_count = nfaces - mtl->face_id; } -static FINLINE void +static INLINE void flush_smooth_group(struct aw_obj* obj) { struct aw_obj_smooth_group* grp; size_t nfaces, ngrps; ASSERT(obj); - if(0 == (nfaces = darray_face_size_get(&obj->faces))) - return; - if(0 == (ngrps = darray_smooth_group_size_get(&obj->smooth_groups))) - return; + + nfaces = darray_face_size_get(&obj->faces); + if(!nfaces) return; /* No face to flush */ + + ngrps = darray_smooth_group_size_get(&obj->smooth_groups); + if(!ngrps) return; /* No smooth group */ + + /* Setup the number of faces of the current smoothed group */ grp = darray_smooth_group_data_get(&obj->smooth_groups) + (ngrps - 1); ASSERT(grp->face_id <= nfaces); grp->faces_count = nfaces - grp->face_id; } static res_T -parse_floatX_in_darray - (struct darray_float* darray, +parse_doubleX_in_darray + (struct darray_double* darray, const unsigned int count_min, const unsigned int count_max, - const float default_value, - char** tk_ctxt) + const double default_value, + char** tk_ctx) { - res_T res; + res_T res = RES_OK; size_t i; ASSERT(darray); - i = darray_float_size_get(darray); - res = darray_float_resize(darray, i + count_max); - if(res != RES_OK) - return res; + i = darray_double_size_get(darray); + + res = darray_double_resize(darray, i + count_max); + if(res != RES_OK) goto error; - res = parse_floatX - (darray_float_data_get(darray) + i, - count_min, count_max, -FLT_MAX, FLT_MAX, default_value, tk_ctxt); - if(res != RES_OK) - darray_float_resize(darray, i); + res = parse_doubleX(darray_double_data_get(darray) + i, count_min, count_max, + -DBL_MAX, DBL_MAX, default_value, tk_ctx); + if(res != RES_OK) goto error; + +exit: return res; +error: + darray_double_resize(darray, i); + goto exit; } static res_T @@ -182,7 +272,7 @@ string_to_vertex_id long id_long; res_T res; - res = string_to_long(str, &id_long); + res = cstr_to_long(str, &id_long); if(res != RES_OK) return res; if(id_long > 0) { @@ -201,252 +291,349 @@ string_to_vertex_id } static res_T -parse_face(struct aw_obj* obj, char** word_tk) +parse_face_vertex + (struct aw_obj* obj, + struct aw_obj_face* face, + char* str) { - struct aw_obj_face face; - char* word; + struct aw_obj_vertex vert = VERTEX_NULL; + char* tk1 = NULL; + char* tk2 = NULL; + char* tk3 = NULL; + char* tk_ctx = NULL; + size_t npositions = 0; + size_t nnormals = 0; + size_t ntexcoords = 0; res_T res = RES_OK; - ASSERT(obj && word_tk); + ASSERT(obj && face && str); + + npositions = darray_double_size_get(&obj->positions) / 4; + nnormals = darray_double_size_get(&obj->normals) / 3; + ntexcoords = darray_double_size_get(&obj->texcoords) / 3; + #define CALL(Func) if(RES_OK != (res = Func)) goto error + /* Parse the position */ + tk1 = strtok_r(str, "/", &tk_ctx); + ASSERT(tk1); + CALL(string_to_vertex_id(tk1, npositions, &vert.position_id)); + + tk2 = strtok_r(NULL, "/", &tk_ctx); + if(tk2) { + tk1 += strlen(tk1); + if(tk2 > tk1 + 3) { /* Unexpected N `/' separators with N > 2 */ + res = RES_BAD_ARG; + goto error; + } + + if(tk2 == tk1 + 2) { /* `//' separator => No tex */ + /* Parse the normal */ + CALL(string_to_vertex_id(tk2, nnormals, &vert.normal_id)); + } else { + /* Parse the texcoords and */ + CALL(string_to_vertex_id(tk2, ntexcoords, &vert.texcoord_id)); + + tk3 = strtok_r(NULL, "", &tk_ctx); + if(tk3) { + /* Parse the normal */ + CALL(string_to_vertex_id(tk3, nnormals, &vert.normal_id)); + } + } + } + + /* Register the vertex */ + CALL(darray_vertex_push_back(&obj->vertices, &vert)); + ++face->vertices_count; + + #undef CALL +exit: + return res; +error: + goto exit; +} + +static res_T +parse_face(struct aw_obj* obj, char** tk_ctx) +{ + struct aw_obj_face face; + char* tk = NULL; + res_T res = RES_OK; + ASSERT(obj && tk_ctx); + face.vertex_id = darray_vertex_size_get(&obj->vertices); face.vertices_count = 0; face.group_id = darray_named_group_size_get(&obj->groups) - 1; face.smooth_group_id = darray_smooth_group_size_get(&obj->smooth_groups) - 1; face.mtl_id = darray_named_group_size_get(&obj->usemtls) - 1; - while((word = strtok_r(NULL, " \t", word_tk))) { - char* id, *id_tk, *id_pos; - struct vertex vert = VERTEX_NULL; - const size_t positions_count = darray_float_size_get(&obj->positions) / 4; - const size_t normals_count = darray_float_size_get(&obj->normals) / 3; - const size_t texcoords_count = darray_float_size_get(&obj->texcoords) / 3; - - /* position index */ - id_pos = strtok_r(word, "/", &id_tk); - CALL(string_to_vertex_id(id_pos, positions_count, &vert.iposition)); - if((id = strtok_r(NULL, "/", &id_tk))) { - id_pos += strlen(id_pos); - if(id > id_pos + 3) /* Unexpected N `/' separators with N > 2 */ - goto error; - if(id == id_pos + 2) { /* `//' separator => No tex */ - /* normal index */ - CALL(string_to_vertex_id(id, normals_count, &vert.inormal)); - } else { - /* texcoord index */ - CALL(string_to_vertex_id(id, texcoords_count, &vert.itexcoord)); - /* normal index */ - if((id = strtok_r(NULL, "/", &id_tk))) { - CALL(string_to_vertex_id(id, normals_count, &vert.inormal)); - } - } - } - CALL(darray_vertex_push_back(&obj->vertices, &vert)); - ++face.vertices_count; + while((tk = strtok_r(NULL, " \t", tk_ctx))) { + res = parse_face_vertex(obj, &face, tk); + if(res != RES_OK) goto error; } - CALL(darray_face_push_back(&obj->faces, &face)); - #undef CALL + /* Register the face */ + res = darray_face_push_back(&obj->faces, &face); + if(res != RES_OK) goto error; + exit: return res; error: - FOR_EACH_REVERSE(face.vertices_count, face.vertices_count, 0) - darray_vertex_pop_back(&obj->vertices); + /* Release the registered faces */ + CHK(darray_vertex_resize(&obj->vertices, face.vertex_id) == RES_OK); goto exit; } static res_T -parse_group(struct aw_obj* obj, char** word_tk) +parse_group(struct aw_obj* obj, char** tk_ctx) { - char* word; - size_t ngrps = 0, igrp = 0; + char* tk; + size_t ngrps = 0; + size_t igrp = 0; res_T res = RES_OK; - ASSERT(obj && word_tk); + ASSERT(obj && tk_ctx); flush_groups(obj); - word = strtok_r(NULL, " \t", word_tk); ngrps = igrp = darray_named_group_size_get(&obj->groups); - obj->igroups_active = ngrps; + obj->igroups_active = igrp; + + tk = strtok_r(NULL, " \t", tk_ctx); /* May be NULL */ + do { - struct aw_obj_named_group* grp = NULL; + struct named_group* grp = NULL; + + /* Allocate a group */ res = darray_named_group_resize(&obj->groups, igrp + 1); - if(res != RES_OK) - goto error; - grp = darray_named_group_data_get(&obj->groups) + ngrps; + if(res != RES_OK) goto error; + + /* Fetch the group */ + grp = darray_named_group_data_get(&obj->groups) + igrp; ++igrp; - res = str_set(&grp->name, word ? word : "default"); - if(res != RES_OK) - goto error; + + /* Setup the group name */ + res = str_set(&grp->name, tk ? tk : "default"); + if(res != RES_OK) goto error; + + /* Initialize the group face indices */ grp->face_id = darray_face_size_get(&obj->faces); grp->faces_count = 0; - } while((word = strtok_r(NULL, " \t", word_tk))); + } while((tk = strtok_r(NULL, " \t", tk_ctx))); exit: return res; error: - if(igrp != ngrps) - CHK(darray_named_group_resize(&obj->groups, ngrps) == RES_OK); + /* Release the created groups */ + CHK(darray_named_group_resize(&obj->groups, ngrps) == RES_OK); goto exit; } static res_T -parse_smooth_group(struct aw_obj* obj, char** word_tk) +parse_smooth_group(struct aw_obj* obj, char** tk_ctx) { - char* word; struct aw_obj_smooth_group grp; + char* tk = NULL; res_T res; - size_t i; - ASSERT(obj && word_tk); + ASSERT(obj && tk_ctx); flush_smooth_group(obj); - word = strtok_r(NULL, " \t", word_tk); - if(!strcmp(word, "off")) { + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) return RES_BAD_ARG; + + if(!strcmp(tk, "off")) { grp.is_smoothed = 0; - } else if(!strcmp(word, "on")) { + } else if(!strcmp(tk, "on")) { grp.is_smoothed = 1; } else { - res = string_to_size_t(word, &i); - if(res != RES_OK) - return res; + int i; + res = cstr_to_int(tk, &i); + if(res != RES_OK) return res; grp.is_smoothed = i != 0; } + + /* Initialize the smoot group face indices */ grp.face_id = darray_face_size_get(&obj->faces); grp.faces_count = 0; + /* Register the smooth group */ res = darray_smooth_group_push_back(&obj->smooth_groups, &grp); - if(res != RES_OK) - return res; + if(res != RES_OK) return res; return RES_OK; } static res_T -parse_mtllib(struct aw_obj* obj, char** word_tk) +parse_mtllib(struct aw_obj* obj, char** tk_ctx) { - char* word; + char* tk = NULL; size_t imtllib = 0; size_t nmtllibs = 0; res_T res = RES_OK; - ASSERT(obj && word_tk); + ASSERT(obj && tk_ctx); - word = strtok_r(NULL, " \t", word_tk); - if(!word) { + nmtllibs = imtllib = darray_mtllib_size_get(&obj->mtllibs); + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { res = RES_BAD_ARG; goto error; } - nmtllibs = imtllib = darray_mtllib_size_get(&obj->mtllibs); + do { - struct str* str; + struct str* str = NULL; + + /* Allocate the mtllib path */ res = darray_mtllib_resize(&obj->mtllibs, imtllib + 1); - if(res != RES_OK) - goto error; + if(res != RES_OK) goto error; + + /* Fetc the mtllib path */ str = darray_mtllib_data_get(&obj->mtllibs) + imtllib; ++imtllib; - res = str_set(str, word); - if(res != RES_OK) - goto error; - } while((word = strtok_r(NULL, " \t", word_tk))); + + /* Setup the mtllib name */ + res = str_set(str, tk); + if(res != RES_OK) goto error; + + } while((tk = strtok_r(NULL, " \t", tk_ctx))); exit: return res; error: - if(imtllib != nmtllibs) - CHK(darray_mtllib_resize(&obj->mtllibs, nmtllibs) == RES_OK); + CHK(darray_mtllib_resize(&obj->mtllibs, nmtllibs) == RES_OK); goto exit; } static res_T -parse_usemtl(struct aw_obj* obj, char** word_tk) +parse_usemtl(struct aw_obj* obj, char** tk_ctx) { - char* word; - struct aw_obj_named_group* mtl = NULL; + char* tk = NULL; + struct named_group* mtl = NULL; size_t nmtls; res_T res = RES_OK; - ASSERT(obj && word_tk); + ASSERT(obj && tk_ctx); flush_usemtl(obj); - word= strtok_r(NULL, " \t", word_tk); - if(!word_tk) { + tk = strtok_r(NULL, " \t", tk_ctx); /* Blanks are prohibited in mtl name */ + if(!tk) { res = RES_BAD_ARG; goto error; } nmtls = darray_named_group_size_get(&obj->usemtls); + + /* Allocate the material */ res = darray_named_group_resize(&obj->usemtls, nmtls + 1); - if(res != RES_OK) - goto error; + if(res != RES_OK) goto error; + + /* Fetch the material */ mtl = darray_named_group_data_get(&obj->usemtls) + nmtls; - res = str_set(&mtl->name, word); - if(res != RES_OK) - goto error; + + /* Setup the material name */ + res = str_set(&mtl->name, tk); + if(res != RES_OK) goto error; + + /* Initialize the material face indices */ mtl->face_id = darray_face_size_get(&obj->faces); mtl->faces_count = 0; exit: return res; error: - if(mtl) - darray_named_group_pop_back(&obj->usemtls); + if(mtl) darray_named_group_pop_back(&obj->usemtls); goto exit; } static res_T -parse_obj_line(struct aw_obj* obj, char* line) +parse_obj_line(struct aw_obj* obj, struct txtrdr* txtrdr) { - char* word, *word_tk; + char* tk = NULL; + char* tk_ctx = NULL; res_T res = RES_OK; - ASSERT(obj && line); - - word = strtok_r(line, " \t", &word_tk); - if(word) { - if(word[0] == '#') { /* Comment */ - goto exit; - } else if(!strcmp(word, "v")) { /* Vertex position */ - res = parse_floatX_in_darray(&obj->positions, 3, 4, 1.f, &word_tk); - } else if(!strcmp(word, "vn")) { /* Vertex normal */ - res = parse_floatX_in_darray(&obj->normals, 3, 3, 0.f, &word_tk); - } else if(!strcmp(word, "vt")) { /* Vertex texture coordinates */ - res = parse_floatX_in_darray(&obj->texcoords, 1, 3, 0.f, &word_tk); - } else if(!strcmp(word, "f") || !strcmp(word, "fo")) { /* face element */ - res = parse_face(obj, &word_tk); - } else if(!strcmp(word, "g")) { /* Grouping */ - res = parse_group(obj, &word_tk); - } else if(!strcmp(word, "s")) { /* Smooth group */ - res = parse_smooth_group(obj, &word_tk); - } else if(!strcmp(word, "mtllib")) { /* Mtl library */ - res = parse_mtllib(obj, &word_tk); - } else if(!strcmp(word, "usemtl")) { /* Use the mtl library */ - res = parse_usemtl(obj, &word_tk); - } else { - res = RES_OK; - if(obj->verbose) { - logger_print(obj->logger, LOG_WARNING, - "%s:%lu: warning: ignored or malformed directive %s\n", - obj->filename, (unsigned long)obj->iline, word); - } - while((word = strtok_r(NULL, " \t", &word_tk))); /* Skip the line */ - } - if(res != RES_OK) - goto error; - if((word = strtok_r(NULL, " ", &word_tk))) { - if(obj->verbose) { - logger_print(obj->logger, LOG_ERROR, "%s:%lu: unexpected directive %s\n", - obj->filename, (unsigned long)obj->iline, word); - } - res = RES_BAD_ARG; + ASSERT(obj && txtrdr); + + tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + ASSERT(tk); /* A line should exist since it was parsed by txtrdr */ + + if(!strcmp(tk, "v")) { /* Vertex position */ + res = parse_doubleX_in_darray(&obj->positions, 3, 4, 1.f, &tk_ctx); + } else if(!strcmp(tk, "vn")) { /* Vertex normal */ + res = parse_doubleX_in_darray(&obj->normals, 3, 3, 0.f, &tk_ctx); + } else if(!strcmp(tk, "vt")) { /* Vertex texture coordinates */ + res = parse_doubleX_in_darray(&obj->texcoords, 1, 3, 0.f, &tk_ctx); + } else if(!strcmp(tk, "f") || !strcmp(tk, "fo")) { /* face element */ + res = parse_face(obj, &tk_ctx); + } else if(!strcmp(tk, "g")) { /* Grouping */ + res = parse_group(obj, &tk_ctx); + } else if(!strcmp(tk, "s")) { /* Smooth group */ + res = parse_smooth_group(obj, &tk_ctx); + } else if(!strcmp(tk, "mtllib")) { /* Mtl library */ + res = parse_mtllib(obj, &tk_ctx); + } else if(!strcmp(tk, "usemtl")) { /* Use the mtl library */ + res = parse_usemtl(obj, &tk_ctx); + } else { + log_warn(obj, + "%s:%lu: warning: ignored or malformed directive `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + strtok_r(NULL, "", &tk_ctx); /* Discard remaining text */ + } + if(res != RES_OK) { + log_err(obj, "%s:%lu: parsing failed.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + goto error; + } + + tk = strtok_r(NULL, "", &tk_ctx); + if(tk) { + log_err(obj, "%s:%lu: unexpected text `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +load_stream(struct aw_obj* obj, FILE* stream, const char* stream_name) +{ + struct txtrdr* txtrdr = NULL; + res_T res = RES_OK; + ASSERT(obj && stream && stream_name); + + AW(obj_clear(obj)); + + res = txtrdr_stream(obj->allocator, stream, stream_name, '#', &txtrdr); + if(res != RES_OK) { + log_err(obj, "Could not create the text reader.\n"); + goto error; + } + + for(;;) { + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + log_err(obj, "%s: could not read the line `%lu'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); goto error; } + + if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ + + res = parse_obj_line(obj, txtrdr); + if(res != RES_OK) goto error; } + + flush_groups(obj); + flush_smooth_group(obj); + flush_usemtl(obj); exit: + if(txtrdr) txtrdr_ref_put(txtrdr); return res; error: - if(obj->verbose) { - logger_print(obj->logger, LOG_ERROR, "%s:%lu: error: parsing failed\n", - obj->filename, (unsigned long)obj->iline); - } + AW(obj_clear(obj)); goto exit; } @@ -455,15 +642,16 @@ obj_release(ref_T* ref) { struct aw_obj* obj = CONTAINER_OF(ref, struct aw_obj, ref); ASSERT(ref); - darray_float_release(&obj->positions); - darray_float_release(&obj->normals); - darray_float_release(&obj->texcoords); + darray_double_release(&obj->positions); + darray_double_release(&obj->normals); + darray_double_release(&obj->texcoords); darray_vertex_release(&obj->vertices); darray_face_release(&obj->faces); darray_named_group_release(&obj->groups); darray_named_group_release(&obj->usemtls); darray_smooth_group_release(&obj->smooth_groups); darray_mtllib_release(&obj->mtllibs); + if(obj->logger == &obj->logger__) logger_release(&obj->logger__); MEM_RM(obj->allocator, obj); } @@ -493,11 +681,10 @@ aw_obj_create } ref_init(&obj->ref); obj->allocator = allocator; - obj->logger = logger ? logger : LOGGER_DEFAULT; obj->verbose = verbose; - darray_float_init(mem_allocator, &obj->positions); - darray_float_init(mem_allocator, &obj->normals); - darray_float_init(mem_allocator, &obj->texcoords); + darray_double_init(mem_allocator, &obj->positions); + darray_double_init(mem_allocator, &obj->normals); + darray_double_init(mem_allocator, &obj->texcoords); darray_vertex_init(mem_allocator, &obj->vertices); darray_face_init(mem_allocator, &obj->faces); darray_named_group_init(mem_allocator, &obj->groups); @@ -505,6 +692,15 @@ aw_obj_create darray_smooth_group_init(mem_allocator, &obj->smooth_groups); darray_mtllib_init(mem_allocator, &obj->mtllibs); + if(logger) { + obj->logger = logger; + } else { + res = setup_default_logger(obj->allocator, &obj->logger__, + MSG_PREFIX_INFO, MSG_PREFIX_ERROR, MSG_PREFIX_WARNING); + if(res != RES_OK) goto error; + obj->logger = &obj->logger__; + } + exit: if(obj_out) *obj_out = obj; @@ -536,82 +732,47 @@ aw_obj_ref_put(struct aw_obj* obj) res_T aw_obj_load(struct aw_obj* obj, const char* filename) { - FILE* file; + FILE* fp = NULL; res_T res = RES_OK; - if(!obj || !filename) - return RES_BAD_ARG; + if(!obj || !filename) { + res = RES_BAD_ARG; + goto error; + } - obj->filename = filename; - file = fopen(filename, "r"); - if(!file) { - if(obj->verbose) - logger_print(obj->logger, LOG_ERROR, "Error opening `%s'\n", filename); - return RES_IO_ERR; + fp = fopen(filename, "r"); + if(!fp) { + log_err(obj, "Error opening `%s'.\n", filename); + res = RES_IO_ERR; + goto error; } - res = aw_obj_load_stream(obj, file); - obj->filename = NULL; - fclose(file); + + res = load_stream(obj, fp, filename); + if(res != RES_OK) goto error; + +exit: + if(fp) fclose(fp); return res; +error: + goto exit; } res_T -aw_obj_load_stream(struct aw_obj* obj, FILE* stream) +aw_obj_load_stream(struct aw_obj* obj, FILE* stream, const char* stream_name) { - char* line; - struct darray_char buf; - const unsigned buf_chunk = 256; res_T res = RES_OK; - /* Avoid zealous "may be used uninitialized" warning of GCC 4.9.2 */ - memset(&buf, 0, sizeof(buf)); - if(!obj || !stream) { res = RES_BAD_ARG; goto error; } - darray_char_init(obj->allocator, &buf); - res = darray_char_resize(&buf, buf_chunk); - if(res != RES_OK) - goto error; + res = load_stream(obj, stream, stream_name ? stream_name : "stream"); + if(res != RES_OK) goto error; - if(!obj->filename) - obj->filename = "stream"; - obj->iline = 1; - AW(obj_clear(obj)); - while((line = fgets - (darray_char_data_get(&buf), (int)darray_char_size_get(&buf), stream))) { - size_t last_char; - - while(!strrchr(line,'\n')) { /* Ensure that the whole line was read */ - res = darray_char_resize(&buf, darray_char_size_get(&buf) + buf_chunk); - if(res != RES_OK) - goto error; - - line = darray_char_data_get(&buf); - if(!fgets(line + strlen(line), (int)buf_chunk, stream)) /* EOF */ - break; - } - - /* Remove the newline character(s) */ - last_char = strlen(line); - while(last_char-- && (line[last_char]=='\n' || line[last_char]=='\r')); - line[last_char + 1] = '\0'; - - if(RES_OK != (res = parse_obj_line(obj, line))) - goto error; - ++obj->iline; - } - flush_groups(obj); - flush_smooth_group(obj); - flush_usemtl(obj); exit: - if(obj && stream) - darray_char_release(&buf); return res; error: - if(obj) AW(obj_clear(obj)); goto exit; } @@ -619,9 +780,9 @@ res_T aw_obj_clear(struct aw_obj* obj) { if(!obj) return RES_BAD_ARG; - darray_float_clear(&obj->positions); - darray_float_clear(&obj->normals); - darray_float_clear(&obj->texcoords); + darray_double_clear(&obj->positions); + darray_double_clear(&obj->normals); + darray_double_clear(&obj->texcoords); darray_vertex_clear(&obj->vertices); darray_face_clear(&obj->faces); darray_named_group_clear(&obj->groups); @@ -636,9 +797,9 @@ res_T aw_obj_purge(struct aw_obj* obj) { if(!obj) return RES_BAD_ARG; - darray_float_purge(&obj->positions); - darray_float_purge(&obj->normals); - darray_float_purge(&obj->texcoords); + darray_double_purge(&obj->positions); + darray_double_purge(&obj->normals); + darray_double_purge(&obj->texcoords); darray_vertex_purge(&obj->vertices); darray_face_purge(&obj->faces); darray_named_group_purge(&obj->groups); @@ -650,7 +811,7 @@ aw_obj_purge(struct aw_obj* obj) } res_T -aw_obj_desc_get(struct aw_obj* obj, struct aw_obj_desc* desc) +aw_obj_get_desc(const struct aw_obj* obj, struct aw_obj_desc* desc) { if(!obj || !desc) return RES_BAD_ARG; @@ -663,8 +824,10 @@ aw_obj_desc_get(struct aw_obj* obj, struct aw_obj_desc* desc) } res_T -aw_obj_face_get - (const struct aw_obj* obj, const size_t iface, struct aw_obj_face* face) +aw_obj_get_face + (const struct aw_obj* obj, + const size_t iface, + struct aw_obj_face* face) { if(!obj || !face || iface >= darray_face_size_get(&obj->faces)) return RES_BAD_ARG; @@ -673,20 +836,23 @@ aw_obj_face_get } res_T -aw_obj_group_get +aw_obj_get_group (const struct aw_obj* obj, const size_t igroup, struct aw_obj_named_group* grp) { - const struct aw_obj_named_group* src; + const struct named_group* src = NULL; if(!obj || !grp || igroup >= darray_named_group_size_get(&obj->groups)) return RES_BAD_ARG; src = darray_named_group_cdata_get(&obj->groups) + igroup; - return aw_obj_named_group_copy(grp, src); + grp->name = str_cget(&src->name); + grp->face_id = src->face_id; + grp->faces_count = src->faces_count; + return RES_OK; } res_T -aw_obj_smooth_group_get +aw_obj_get_smooth_group (const struct aw_obj* obj, const size_t ismooth_group, struct aw_obj_smooth_group* group) @@ -699,21 +865,26 @@ aw_obj_smooth_group_get } res_T -aw_obj_mtl_get +aw_obj_get_mtl (const struct aw_obj* obj, const size_t imtl, struct aw_obj_named_group* mtl) { - const struct aw_obj_named_group* src; + const struct named_group* src; if(!obj || !mtl || imtl >= darray_named_group_size_get(&obj->usemtls)) return RES_BAD_ARG; src = darray_named_group_cdata_get(&obj->usemtls) + imtl; - return aw_obj_named_group_copy(mtl, src); + mtl->name = str_cget(&src->name); + mtl->face_id = src->face_id; + mtl->faces_count = src->faces_count; + return RES_OK; } res_T -aw_obj_mtllib_get - (const struct aw_obj* obj, const size_t imtllib, const char** mtllib) +aw_obj_get_mtllib + (const struct aw_obj* obj, + const size_t imtllib, + const char** mtllib) { const struct str* str; if(!obj || !mtllib || imtllib >= darray_mtllib_size_get(&obj->mtllibs)) @@ -724,76 +895,82 @@ aw_obj_mtllib_get } res_T -aw_obj_vertex_get - (const struct aw_obj* obj, const size_t ivertex, struct aw_obj_vertex* vertex) +aw_obj_get_vertex + (const struct aw_obj* obj, + const size_t ivertex, + struct aw_obj_vertex* vertex) { - const struct vertex* vert; - const float* data; if(!obj || !vertex || ivertex >= darray_vertex_size_get(&obj->vertices)) return RES_BAD_ARG; - vert = darray_vertex_cdata_get(&obj->vertices) + ivertex; + *vertex = darray_vertex_cdata_get(&obj->vertices)[ivertex]; + return RES_OK; +} + +res_T +aw_obj_get_vertex_data + (const struct aw_obj* obj, + const struct aw_obj_vertex* vertex, + struct aw_obj_vertex_data* vertex_data) +{ + const double* data; + res_T res = RES_OK; + + if(!obj || !vertex || !vertex_data) { + res = RES_BAD_ARG; + goto error; + } + if(vertex->position_id >= darray_double_size_get(&obj->positions) / 4) { + res = RES_BAD_ARG; + goto error; + } + if(vertex->texcoord_id != VERTEX_NULL.texcoord_id + && vertex->texcoord_id >= darray_double_size_get(&obj->texcoords) / 3) { + res = RES_BAD_ARG; + goto error; + } + if(vertex->normal_id != VERTEX_NULL.normal_id + && vertex->normal_id >= darray_double_size_get(&obj->normals) / 3) { + res = RES_BAD_ARG; + goto error; + } /* Fetch vertex position */ - ASSERT(vert->iposition != VERTEX_NULL.iposition); - data = darray_float_cdata_get(&obj->positions) + vert->iposition * 4; - f4_set(vertex->position, data); + data = darray_double_cdata_get(&obj->positions) + vertex->position_id * 4; + vertex_data->position[0] = data[0]; + vertex_data->position[1] = data[1]; + vertex_data->position[2] = data[2]; + vertex_data->position[3] = data[3]; + /* Setup vertex texcoord */ - if(vert->itexcoord == VERTEX_NULL.itexcoord) { - f3_splat(vertex->texcoord, 0.f); + if(vertex->texcoord_id == VERTEX_NULL.texcoord_id) { + vertex_data->texcoord[0] = 0; + vertex_data->texcoord[1] = 0; + vertex_data->texcoord[2] = 0; } else { - data = darray_float_cdata_get(&obj->texcoords) + vert->itexcoord * 3; - f3_set(vertex->texcoord, data); + data = darray_double_cdata_get(&obj->texcoords) + vertex->texcoord_id * 3; + vertex_data->texcoord[0] = data[0]; + vertex_data->texcoord[1] = data[1]; + vertex_data->texcoord[2] = data[2]; } /* Setup vertex normal */ - if(vert->inormal == VERTEX_NULL.inormal) { - f3_splat(vertex->normal, 0.f); + if(vertex->normal_id == VERTEX_NULL.normal_id) { + vertex_data->normal[0] = 0; + vertex_data->normal[1] = 0; + vertex_data->normal[2] = 0; } else { - data = darray_float_cdata_get(&obj->normals) + vert->inormal * 3; - f3_set(vertex->normal, data); + data = darray_double_cdata_get(&obj->normals) + vertex->normal_id * 3; + vertex_data->normal[0] = data[0]; + vertex_data->normal[1] = data[1]; + vertex_data->normal[2] = data[2]; } - return RES_OK; -} - -res_T -aw_obj_named_group_init - (struct mem_allocator* allocator, struct aw_obj_named_group* grp) -{ - if(!grp) return RES_BAD_ARG; - str_init(allocator, &grp->name); - return RES_OK; -} - -res_T -aw_obj_named_group_release(struct aw_obj_named_group* grp) -{ - if(!grp) return RES_BAD_ARG; - str_release(&grp->name); - return RES_OK; -} - -res_T -aw_obj_named_group_copy - (struct aw_obj_named_group* dst, - const struct aw_obj_named_group* src) -{ - if(!dst || !src) return RES_BAD_ARG; - if(dst == src) return RES_OK; - dst->face_id = src->face_id; - dst->faces_count = src->faces_count; - return str_copy(&dst->name, &src->name); -} -res_T -aw_obj_named_group_copy_and_release - (struct aw_obj_named_group* dst, struct aw_obj_named_group* src) -{ - if(!dst || !src) return RES_BAD_ARG; - if(dst == src) return RES_OK; - dst->face_id = src->face_id; - dst->faces_count = src->faces_count; - return str_copy_and_release(&dst->name, &src->name); +exit: + return res; +error: + goto exit; } #ifdef COMPILER_CL #pragma warning(pop) #endif + diff --git a/src/test_aw.c b/src/test_aw.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) + * + * 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 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "aw.h" + +#include <rsys/clock_time.h> +#include <rsys/mem_allocator.h> + +int +main(int argc, char** argv) +{ + struct aw_obj* obj = NULL; + struct aw_mtl* mtl = NULL; + struct time t0, t1; + struct aw_obj_desc desc; + char buf[128]; + size_t i; + + if(argc < 2) { + fprintf(stderr, "Usage: %s OBJ-FILENAME\n", argv[0]); + return -1; + } + + CHK(aw_obj_create(NULL, &mem_default_allocator, 1, &obj) == RES_OK); + CHK(aw_mtl_create(NULL, &mem_default_allocator, 1, &mtl) == RES_OK); + + time_current(&t0); + CHK(aw_obj_load(obj, argv[1]) == RES_OK); + CHK(aw_obj_get_desc(obj, &desc) == RES_OK); + FOR_EACH(i, 0, desc.mtllibs_count) { + const char* mtllib = NULL; + CHK(aw_obj_get_mtllib(obj, i, &mtllib) == RES_OK); + aw_mtl_load(mtl, mtllib); + } + time_current(&t1); + time_sub(&t0, &t1, &t0); + time_dump(&t0, TIME_MIN|TIME_SEC|TIME_MSEC, NULL, buf, sizeof(buf)); + + fprintf(stdout, "load `%s' in %s\n", argv[1], buf); + fprintf(stdout, "faces count = %lu\n", (unsigned long)desc.faces_count); + fprintf(stdout, "groups count = %lu\n", (unsigned long)desc.groups_count); + fprintf(stdout, "usemtls count = %lu\n", (unsigned long)desc.usemtls_count); + fprintf(stdout, "mtllibs count = %lu\n", (unsigned long)desc.mtllibs_count); + + CHK(aw_obj_ref_put(obj) == RES_OK); + CHK(aw_mtl_ref_put(mtl) == RES_OK); + + CHK(MEM_ALLOCATED_SIZE(&mem_default_allocator) == 0); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_aw_mtl.c b/src/test_aw_mtl.c @@ -1,8 +1,8 @@ -/* Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr) +/* Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -15,7 +15,7 @@ #include "aw.h" -#include <rsys/float3.h> +#include <rsys/double3.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> @@ -50,8 +50,8 @@ test_common(struct aw_mtl* mtl) "bump -s 1 1 1 -o 0 0 0 -bm 1 sand.mpb"; FILE* file; size_t nmtls; - float tmp[3]; - struct aw_material mtr; + double tmp[3]; + struct aw_material mat; CHK(mtl != NULL); @@ -66,101 +66,92 @@ test_common(struct aw_mtl* mtl) CHK(aw_mtl_load(mtl, "none.mtl") == RES_IO_ERR); CHK(aw_mtl_load(mtl, "test_mtl_common.mtl") == RES_OK); - CHK(aw_mtl_materials_count_get(NULL, NULL) == RES_BAD_ARG); - CHK(aw_mtl_materials_count_get(mtl, NULL) == RES_BAD_ARG); - CHK(aw_mtl_materials_count_get(NULL, &nmtls) == RES_BAD_ARG); - CHK(aw_mtl_materials_count_get(mtl, &nmtls) == RES_OK); + CHK(aw_mtl_get_materials_count(NULL, NULL) == RES_BAD_ARG); + CHK(aw_mtl_get_materials_count(mtl, NULL) == RES_BAD_ARG); + CHK(aw_mtl_get_materials_count(NULL, &nmtls) == RES_BAD_ARG); + CHK(aw_mtl_get_materials_count(mtl, &nmtls) == RES_OK); CHK(nmtls == 1); CHK(aw_mtl_clear(NULL) == RES_BAD_ARG); CHK(aw_mtl_clear(mtl) == RES_OK); - CHK(aw_mtl_materials_count_get(mtl, &nmtls) == RES_OK); + CHK(aw_mtl_get_materials_count(mtl, &nmtls) == RES_OK); CHK(nmtls == 0); CHK(aw_mtl_load(mtl, "test_mtl_common.mtl") == RES_OK); - CHK(aw_material_init(NULL, NULL) == RES_BAD_ARG); - CHK(aw_material_init(NULL, &mtr) == RES_OK); - CHK(aw_mtl_material_get(NULL, SIZE_MAX, NULL) == RES_BAD_ARG); - CHK(aw_mtl_material_get(mtl, SIZE_MAX, NULL) == RES_BAD_ARG); - CHK(aw_mtl_material_get(NULL, 0, NULL) == RES_BAD_ARG); - CHK(aw_mtl_material_get(mtl, 0, NULL) == RES_BAD_ARG); - CHK(aw_mtl_material_get(NULL, SIZE_MAX, &mtr) == RES_BAD_ARG); - CHK(aw_mtl_material_get(mtl, SIZE_MAX, &mtr) == RES_BAD_ARG); - CHK(aw_mtl_material_get(NULL, 0, &mtr) == RES_BAD_ARG); - CHK(aw_mtl_material_get(mtl, 0, &mtr) == RES_OK); - - CHK(strcmp(str_cget(&mtr.name), "my_mtl") == 0); - CHK(mtr.ambient.color_space == AW_COLOR_RGB); - f3(tmp, 0.0435f, 0.0436f, 0.0437f); - CHK(f3_eq(mtr.ambient.value, tmp) == 1); - - CHK(mtr.diffuse.color_space == AW_COLOR_RGB); - f3(tmp, 0.1086f, 0.1087f, 0.1088f); - CHK(f3_eq(mtr.diffuse.value, tmp) == 1); - - CHK(mtr.specular.color_space == AW_COLOR_RGB); - f3_splat(tmp, 0.f); - CHK(f3_eq(mtr.specular.value, tmp) == 1); - - CHK(mtr.transmission.color_space == AW_COLOR_XYZ); - f3(tmp, 0.987f, 0.988f, 0.989f); - CHK(f3_eq(mtr.transmission.value, tmp) == 1); - - CHK(mtr.specular_exponent == 10.f); - CHK(mtr.refraction_index == (float)1.19713f); - CHK(mtr.illumination_model == 6); - - CHK(strcmp(str_cget(&mtr.ambient_map.filename), "chrome.mpc") == 0); - CHK(mtr.ambient_map.options_mask == 0); - CHK(mtr.ambient_map.image_bias == 0.f); - CHK(mtr.ambient_map.image_scale == 1.f); - CHK(f3_eq(mtr.ambient_map.texcoord_bias, f3_splat(tmp, 0.f)) == 1); - CHK(f3_eq(mtr.ambient_map.texcoord_scale, f3_splat(tmp, 1.f)) == 1); - CHK(f3_eq(mtr.ambient_map.texcoord_turbulence, f3_splat(tmp, 0.f)) == 1); - - CHK(strcmp(str_cget(&mtr.diffuse_map.filename), "chrome.mpc") == 0); - CHK(mtr.diffuse_map.options_mask == 0); - CHK(mtr.diffuse_map.image_bias == 0.f); - CHK(mtr.diffuse_map.image_scale == 1.f); - CHK(f3_eq(mtr.diffuse_map.texcoord_bias, f3_splat(tmp, 0.f)) == 1); - CHK(f3_eq(mtr.diffuse_map.texcoord_scale, f3_splat(tmp, 1.f)) == 1); - CHK(f3_eq(mtr.diffuse_map.texcoord_turbulence, f3_splat(tmp, 0.f)) == 1); - - CHK(strcmp(str_cget(&mtr.specular_map.filename), "chrome.mpc") == 0); - CHK(mtr.specular_map.options_mask == 0); - CHK(mtr.specular_map.image_bias == 0.f); - CHK(mtr.specular_map.image_scale == 1.f); - CHK(f3_eq(mtr.specular_map.texcoord_bias, f3_splat(tmp, 0.f)) == 1); - CHK(f3_eq(mtr.specular_map.texcoord_scale, f3_splat(tmp, 1.f)) == 1); - CHK(f3_eq(mtr.specular_map.texcoord_turbulence, f3_splat(tmp, 0.f)) == 1); - - CHK(strcmp(str_cget(&mtr.specular_exponent_map.filename), "wisp.mps") == 0); - CHK(mtr.specular_exponent_map.options_mask == 0); - CHK(mtr.specular_exponent_map.image_bias == 0.f); - CHK(mtr.specular_exponent_map.image_scale == 1.f); - CHK(f3_eq(mtr.specular_exponent_map.texcoord_scale, f3_splat(tmp, 1.f)) == 1); - CHK(f3_eq(mtr.specular_exponent_map.texcoord_bias, f3_splat(tmp, 0.f)) == 1); - CHK(f3_eq(mtr.specular_exponent_map.texcoord_turbulence, tmp) == 1); - CHK(mtr.specular_exponent_map.scalar == AW_MAP_CHANNEL_LUMINANCE); - - CHK(strcmp(str_cget(&mtr.bump_map.filename), "sand.mpb") == 0); - CHK(mtr.bump_map.options_mask == 0); - CHK(mtr.bump_map.image_bias == 0.f); - CHK(mtr.bump_map.image_scale == 1.f); - CHK(f3_eq(mtr.bump_map.texcoord_scale, f3_splat(tmp, 1.f)) == 1); - CHK(f3_eq(mtr.bump_map.texcoord_bias, f3_splat(tmp, 0.f)) == 1); - CHK(f3_eq(mtr.bump_map.texcoord_turbulence, tmp) == 1); - CHK(mtr.bump_map.scalar == AW_MAP_CHANNEL_LUMINANCE); - CHK(mtr.bump_map.bump_multiplier == 1.f); - - CHK(aw_material_release(NULL) == RES_BAD_ARG); - CHK(aw_material_release(&mtr) == RES_OK); + CHK(aw_mtl_get_material(NULL, 0, &mat) == RES_BAD_ARG); + CHK(aw_mtl_get_material(mtl, SIZE_MAX, &mat) == RES_BAD_ARG); + CHK(aw_mtl_get_material(mtl, 0, NULL) == RES_BAD_ARG); + CHK(aw_mtl_get_material(mtl, 0, &mat) == RES_OK); + + CHK(!strcmp(mat.name, "my_mtl")); + CHK(mat.ambient.color_space == AW_COLOR_RGB); + d3(tmp, 0.0435, 0.0436, 0.0437); + CHK(d3_eq(mat.ambient.value, tmp)); + + CHK(mat.diffuse.color_space == AW_COLOR_RGB); + d3(tmp, 0.1086, 0.1087, 0.1088); + CHK(d3_eq(mat.diffuse.value, tmp)); + + CHK(mat.specular.color_space == AW_COLOR_RGB); + d3_splat(tmp, 0); + CHK(d3_eq(mat.specular.value, tmp)); + + CHK(mat.transmission.color_space == AW_COLOR_XYZ); + d3(tmp, 0.987, 0.988, 0.989); + CHK(d3_eq(mat.transmission.value, tmp)); + + CHK(mat.specular_exponent == 10.0); + CHK(mat.refraction_index == 1.19713); + CHK(mat.illumination_model == 6); + + CHK(!strcmp(mat.ambient_map.filename, "chrome.mpc")); + CHK(mat.ambient_map.options_mask == 0); + CHK(mat.ambient_map.image_bias == 0.f); + CHK(mat.ambient_map.image_scale == 1.f); + CHK(d3_eq(mat.ambient_map.texcoord_bias, d3_splat(tmp, 0.0))); + CHK(d3_eq(mat.ambient_map.texcoord_scale, d3_splat(tmp, 1.0))); + CHK(d3_eq(mat.ambient_map.texcoord_turbulence, d3_splat(tmp, 0.0))); + + CHK(!strcmp(mat.diffuse_map.filename, "chrome.mpc")); + CHK(mat.diffuse_map.options_mask == 0); + CHK(mat.diffuse_map.image_bias == 0.f); + CHK(mat.diffuse_map.image_scale == 1.f); + CHK(d3_eq(mat.diffuse_map.texcoord_bias, d3_splat(tmp, 0.0))); + CHK(d3_eq(mat.diffuse_map.texcoord_scale, d3_splat(tmp, 1.0))); + CHK(d3_eq(mat.diffuse_map.texcoord_turbulence, d3_splat(tmp, 0.0))); + + CHK(!strcmp(mat.specular_map.filename, "chrome.mpc")); + CHK(mat.specular_map.options_mask == 0); + CHK(mat.specular_map.image_bias == 0.0); + CHK(mat.specular_map.image_scale == 1.0); + CHK(d3_eq(mat.specular_map.texcoord_bias, d3_splat(tmp, 0.0))); + CHK(d3_eq(mat.specular_map.texcoord_scale, d3_splat(tmp, 1.0))); + CHK(d3_eq(mat.specular_map.texcoord_turbulence, d3_splat(tmp, 0.0))); + + CHK(!strcmp(mat.specular_exponent_map.filename, "wisp.mps")); + CHK(mat.specular_exponent_map.options_mask == 0); + CHK(mat.specular_exponent_map.image_bias == 0.0); + CHK(mat.specular_exponent_map.image_scale == 1.0); + CHK(d3_eq(mat.specular_exponent_map.texcoord_scale, d3_splat(tmp, 1.0))); + CHK(d3_eq(mat.specular_exponent_map.texcoord_bias, d3_splat(tmp, 0.0))); + CHK(d3_eq(mat.specular_exponent_map.texcoord_turbulence, tmp) == 1); + CHK(mat.specular_exponent_map.scalar == AW_MAP_CHANNEL_LUMINANCE); + + CHK(!strcmp(mat.bump_map.filename, "sand.mpb")); + CHK(mat.bump_map.options_mask == 0); + CHK(mat.bump_map.image_bias == 0.0); + CHK(mat.bump_map.image_scale == 1.0); + CHK(d3_eq(mat.bump_map.texcoord_scale, d3_splat(tmp, 1.0))); + CHK(d3_eq(mat.bump_map.texcoord_bias, d3_splat(tmp, 0.0))); + CHK(d3_eq(mat.bump_map.texcoord_turbulence, tmp) == 1); + CHK(mat.bump_map.scalar == AW_MAP_CHANNEL_LUMINANCE); + CHK(mat.bump_map.bump_multiplier == 1.0); CHK(aw_mtl_purge(NULL) == RES_BAD_ARG); CHK(aw_mtl_purge(mtl) == RES_OK); - CHK(aw_mtl_materials_count_get(mtl, &nmtls) == RES_OK); + CHK(aw_mtl_get_materials_count(mtl, &nmtls) == RES_OK); CHK(nmtls == 0); } @@ -205,8 +196,8 @@ test_multiple_materials(struct aw_mtl* mtl) "Ks 2\n"; FILE* file; size_t nmtls; - float tmp[3]; - struct aw_material mtr; + double tmp[3]; + struct aw_material mat; CHK(mtl != NULL); @@ -215,81 +206,78 @@ test_multiple_materials(struct aw_mtl* mtl) fwrite(mtl_multi, sizeof(char), strlen(mtl_multi), file); CHK(fseek(file, 0, SEEK_SET) == 0); - CHK(aw_mtl_load_stream(NULL, NULL) == RES_BAD_ARG); - CHK(aw_mtl_load_stream(mtl, NULL) == RES_BAD_ARG); - CHK(aw_mtl_load_stream(NULL, file) == RES_BAD_ARG); - CHK(aw_mtl_load_stream(mtl, file) == RES_OK); - CHK(aw_mtl_materials_count_get(mtl, &nmtls) == RES_OK); + CHK(aw_mtl_load_stream(NULL, file, NULL) == RES_BAD_ARG); + CHK(aw_mtl_load_stream(mtl, NULL, NULL) == RES_BAD_ARG); + CHK(aw_mtl_load_stream(mtl, file, NULL) == RES_OK); + CHK(aw_mtl_get_materials_count(mtl, &nmtls) == RES_OK); CHK(nmtls == 3); - CHK(aw_material_init(NULL, &mtr) == RES_OK); - CHK(aw_mtl_material_get(mtl, 0, &mtr) == RES_OK); - CHK(strcmp(str_cget(&mtr.name), "material_0") == 0); - CHK(mtr.specular_exponent == 8.f); - CHK(mtr.refraction_index == 1.5f); - CHK(mtr.transmission.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.transmission.value, f3_splat(tmp, 1.f)) == 1); - CHK(mtr.illumination_model == 2); - CHK(mtr.ambient.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.ambient.value, f3_splat(tmp, 0.f)) == 1); - CHK(mtr.diffuse.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.diffuse.value, f3(tmp, 0.734118f, 0.730588f, 0.674118f)) == 1); - CHK(mtr.specular.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.specular.value, f3_splat(tmp, 0.f)) == 1); - CHK(strcmp - (str_cget(&mtr.ambient_map.filename), - "my_long_and_verbose_filename_of_a_RED_GREEN_BLUE_1024x64_image.png") == 0); - CHK(mtr.ambient_map.options_mask == 0); - CHK(mtr.ambient_map.image_bias == 0.f); - CHK(mtr.ambient_map.image_scale == 1.f); - CHK(f3_eq(mtr.ambient_map.texcoord_bias, f3_splat(tmp, 0.f)) == 1); - CHK(f3_eq(mtr.ambient_map.texcoord_scale, f3_splat(tmp, 1.f)) == 1); - CHK(f3_eq(mtr.ambient_map.texcoord_turbulence, f3_splat(tmp, 0.f)) == 1); - CHK(mtr.ambient_map.resolution == 0); - CHK(strcmp(str_cget(&mtr.diffuse_map.filename), "tp.png") == 0); - CHK(str_len(&mtr.specular_map.filename) == 0); - CHK(str_len(&mtr.specular_exponent_map.filename) == 0); - CHK(str_len(&mtr.bump_map.filename) == 0); - - CHK(aw_mtl_material_get(mtl, 1, &mtr) == RES_OK); - CHK(strcmp(str_cget(&mtr.name), "textured_material") == 0); - CHK(mtr.specular_exponent == 6.f); - CHK(mtr.refraction_index == (float)1.7f); - CHK(mtr.transmission.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.transmission.value, f3(tmp, 1.f, 1.2f, 1.3f)) == 1); - CHK(mtr.illumination_model == 0); - CHK(mtr.ambient.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.ambient.value, f3_splat(tmp, 0.f)) == 1); - CHK(mtr.diffuse.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.diffuse.value, f3(tmp, 0.734118f, 0.709412f, 0.674118f)) == 1); - CHK(mtr.specular.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.specular.value, f3_splat(tmp, 0.f)) == 1); - CHK(strcmp(str_cget(&mtr.ambient_map.filename), "tex6x6.png") == 0); - CHK(strcmp(str_cget(&mtr.diffuse_map.filename), "tex6x6.png") == 0); - CHK(strcmp(str_cget(&mtr.bump_map.filename), "tex6x6-bump.png") == 0); - CHK(mtr.bump_map.scalar == AW_MAP_CHANNEL_RED); - CHK(mtr.bump_map.bump_multiplier == (float)0.2f); - CHK(str_len(&mtr.specular_exponent_map.filename) == 0); - - CHK(aw_mtl_material_get(mtl, 2, &mtr) == RES_OK); - CHK(strcmp(str_cget(&mtr.name), "hello_world") == 0); - CHK(mtr.specular_exponent == 8.f); - CHK(mtr.refraction_index == 1.5f); - CHK(mtr.transmission.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.transmission.value, f3_splat(tmp, 1.f)) == 1); - CHK(mtr.illumination_model == 2); - CHK(mtr.ambient.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.ambient.value, f3_splat(tmp, 0.f)) == 1); - CHK(mtr.diffuse.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.diffuse.value, f3(tmp, 0.546274f, 0.219608f, 0.183922f)) == 1); - CHK(mtr.specular.color_space == AW_COLOR_RGB); - CHK(f3_eq(mtr.specular.value, f3_splat(tmp, 2.f)) == 1); - CHK(str_len(&mtr.ambient_map.filename) == 0); - CHK(str_len(&mtr.diffuse_map.filename) == 0); - CHK(str_len(&mtr.bump_map.filename) == 0); - CHK(str_len(&mtr.specular_exponent_map.filename) == 0); - - CHK(aw_material_release(&mtr) == RES_OK); + CHK(aw_mtl_get_material(mtl, 0, &mat) == RES_OK); + CHK(!strcmp(mat.name, "material_0")); + CHK(mat.specular_exponent == 8.f); + CHK(mat.refraction_index == 1.5f); + CHK(mat.transmission.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.transmission.value, d3_splat(tmp, 1.0))); + CHK(mat.illumination_model == 2); + CHK(mat.ambient.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.ambient.value, d3_splat(tmp, 0.0))); + CHK(mat.diffuse.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.diffuse.value, d3(tmp, 0.734118, 0.730588, 0.674118))); + CHK(mat.specular.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.specular.value, d3_splat(tmp, 0.0))); + CHK(!strcmp + (mat.ambient_map.filename, + "my_long_and_verbose_filename_of_a_RED_GREEN_BLUE_1024x64_image.png")); + CHK(mat.ambient_map.options_mask == 0); + CHK(mat.ambient_map.image_bias == 0.0); + CHK(mat.ambient_map.image_scale == 1.0); + CHK(d3_eq(mat.ambient_map.texcoord_bias, d3_splat(tmp, 0.0))); + CHK(d3_eq(mat.ambient_map.texcoord_scale, d3_splat(tmp, 1.0))); + CHK(d3_eq(mat.ambient_map.texcoord_turbulence, d3_splat(tmp, 0.0))); + CHK(mat.ambient_map.resolution == 0); + CHK(!strcmp(mat.diffuse_map.filename, "tp.png")); + CHK(!mat.specular_map.filename); + CHK(!mat.specular_exponent_map.filename); + CHK(!mat.bump_map.filename); + + CHK(aw_mtl_get_material(mtl, 1, &mat) == RES_OK); + CHK(!strcmp(mat.name, "textured_material")); + CHK(mat.specular_exponent == 6.0); + CHK(mat.refraction_index == 1.7); + CHK(mat.transmission.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.transmission.value, d3(tmp, 1.0, 1.2, 1.3))); + CHK(mat.illumination_model == 0); + CHK(mat.ambient.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.ambient.value, d3_splat(tmp, 0.0))); + CHK(mat.diffuse.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.diffuse.value, d3(tmp, 0.734118, 0.709412, 0.674118))); + CHK(mat.specular.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.specular.value, d3_splat(tmp, 0.0))); + CHK(!strcmp(mat.ambient_map.filename, "tex6x6.png")); + CHK(!strcmp(mat.diffuse_map.filename, "tex6x6.png")); + CHK(!strcmp(mat.bump_map.filename, "tex6x6-bump.png")); + CHK(mat.bump_map.scalar == AW_MAP_CHANNEL_RED); + CHK(mat.bump_map.bump_multiplier == 0.2); + CHK(!mat.specular_exponent_map.filename); + + CHK(aw_mtl_get_material(mtl, 2, &mat) == RES_OK); + CHK(!strcmp(mat.name, "hello_world")); + CHK(mat.specular_exponent == 8.0); + CHK(mat.refraction_index == 1.5); + CHK(mat.transmission.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.transmission.value, d3_splat(tmp, 1.0))); + CHK(mat.illumination_model == 2); + CHK(mat.ambient.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.ambient.value, d3_splat(tmp, 0.0))); + CHK(mat.diffuse.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.diffuse.value, d3(tmp, 0.546274, 0.219608, 0.183922))); + CHK(mat.specular.color_space == AW_COLOR_RGB); + CHK(d3_eq(mat.specular.value, d3_splat(tmp, 2.0))); + CHK(!mat.ambient_map.filename); + CHK(!mat.diffuse_map.filename); + CHK(!mat.bump_map.filename); + CHK(!mat.specular_exponent_map.filename); + fclose(file); } @@ -318,7 +306,7 @@ test_unloadable(struct aw_mtl* mtl) fclose(file); CHK(aw_mtl_load(mtl, "mtl0.mtl") == RES_BAD_ARG); - CHK(aw_mtl_materials_count_get(mtl, &nmtls) == RES_OK); + CHK(aw_mtl_get_materials_count(mtl, &nmtls) == RES_OK); CHK(nmtls == 0); } int @@ -330,9 +318,9 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(aw_mtl_create(NULL, NULL, 1, NULL) == RES_BAD_ARG); - CHK(aw_mtl_create(NULL, &allocator, 1, NULL) == RES_BAD_ARG); - CHK(aw_mtl_create(NULL, NULL, 1, &mtl) == RES_OK); + CHK(aw_mtl_create(LOGGER_DEFAULT, NULL, 1, NULL) == RES_BAD_ARG); + CHK(aw_mtl_create(LOGGER_DEFAULT, &allocator, 1, NULL) == RES_BAD_ARG); + CHK(aw_mtl_create(LOGGER_DEFAULT, NULL, 1, &mtl) == RES_OK); CHK(aw_mtl_ref_get(NULL) == RES_BAD_ARG); CHK(aw_mtl_ref_get(mtl) == RES_OK); @@ -340,7 +328,7 @@ main(int argc, char** argv) CHK(aw_mtl_ref_put(mtl) == RES_OK); CHK(aw_mtl_ref_put(mtl) == RES_OK); - CHK(aw_mtl_create(LOGGER_DEFAULT, &allocator, 1, &mtl) == RES_OK); + CHK(aw_mtl_create(NULL, &allocator, 1, &mtl) == RES_OK); test_common(mtl); test_multiple_materials(mtl); diff --git a/src/test_aw_obj.c b/src/test_aw_obj.c @@ -1,8 +1,8 @@ -/* Copyright (C) 2013-2016 Vincent Forest (vaplv@free.fr) +/* Copyright (C) 2014-2017, 2020 Vincent Forest (vaplv@free.fr) * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -15,8 +15,8 @@ #include "aw.h" -#include <rsys/float3.h> -#include <rsys/float4.h> +#include <rsys/double3.h> +#include <rsys/double4.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> @@ -29,6 +29,7 @@ test_plane(struct aw_obj* obj) "mtllib master.mtl" "\n" "g\n" + "o plane\n" "v 0.0000 2.0000 0.0000\n" "v 0.0000 0.0000 0.0000\n" "v 2.0000 0.0000 0.0000\n" @@ -42,12 +43,13 @@ test_plane(struct aw_obj* obj) "usemtl wood\n" "f 1/1 2/2 3/3 4/4\n" "# 1 element\n"; - float v4[4]; + double v4[4]; struct aw_obj_desc desc; struct aw_obj_face face; struct aw_obj_named_group group; struct aw_obj_named_group mtl; struct aw_obj_vertex vertex; + struct aw_obj_vertex_data vdata; FILE* file; const char* mtllib; @@ -58,98 +60,89 @@ test_plane(struct aw_obj* obj) fwrite(plane_obj, sizeof(char), strlen(plane_obj), file); fclose(file); - CHK(aw_obj_named_group_init(NULL, NULL) == RES_BAD_ARG); - CHK(aw_obj_named_group_init(NULL, &group) == RES_OK); - CHK(aw_obj_named_group_init(NULL, &mtl) == RES_OK); - - CHK(aw_obj_load(NULL, NULL) == RES_BAD_ARG); CHK(aw_obj_load(obj, NULL) == RES_BAD_ARG); CHK(aw_obj_load(NULL, "test_obj_plane.obj") == RES_BAD_ARG); CHK(aw_obj_load(obj, "none.obj") == RES_IO_ERR); CHK(aw_obj_load(obj, "test_obj_plane.obj") == RES_OK); - CHK(aw_obj_desc_get(NULL, NULL) == RES_BAD_ARG); - CHK(aw_obj_desc_get(obj, NULL) == RES_BAD_ARG); - CHK(aw_obj_desc_get(NULL, &desc) == RES_BAD_ARG); - CHK(aw_obj_desc_get(obj, &desc) == RES_OK); + CHK(aw_obj_get_desc(NULL, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_desc(obj, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_desc(NULL, &desc) == RES_BAD_ARG); + CHK(aw_obj_get_desc(obj, &desc) == RES_OK); CHK(desc.faces_count == 1); CHK(desc.groups_count == 1); CHK(desc.smooth_groups_count == 0); CHK(desc.usemtls_count == 1); CHK(desc.mtllibs_count == 1); - CHK(aw_obj_face_get(NULL, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_face_get(obj, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_face_get(NULL, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_face_get(obj, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_face_get(NULL, AW_ID_NONE, &face) == RES_BAD_ARG); - CHK(aw_obj_face_get(obj, AW_ID_NONE, &face) == RES_BAD_ARG); - CHK(aw_obj_face_get(NULL, 0, &face) == RES_BAD_ARG); - CHK(aw_obj_face_get(obj, 0, &face) == RES_OK); + CHK(aw_obj_get_face(NULL, 0, &face) == RES_BAD_ARG); + CHK(aw_obj_get_face(obj, AW_ID_NONE, &face) == RES_BAD_ARG); + CHK(aw_obj_get_face(obj, 0, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_face(obj, 0, &face) == RES_OK); CHK(face.vertex_id == 0); CHK(face.vertices_count == 4); CHK(face.group_id == 0); CHK(face.smooth_group_id == AW_ID_NONE); CHK(face.mtl_id == 0); - CHK(aw_obj_mtl_get(NULL, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_mtl_get(obj, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_mtl_get(NULL, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_mtl_get(obj, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_mtl_get(NULL, AW_ID_NONE, &mtl) == RES_BAD_ARG); - CHK(aw_obj_mtl_get(obj, AW_ID_NONE, &mtl) == RES_BAD_ARG); - CHK(aw_obj_mtl_get(NULL, 0, &mtl) == RES_BAD_ARG); - CHK(aw_obj_mtl_get(obj, 0, &mtl) == RES_OK); - CHK(strcmp(str_cget(&mtl.name), "wood") == 0); + CHK(aw_obj_get_mtl(NULL, 0, &mtl) == RES_BAD_ARG); + CHK(aw_obj_get_mtl(obj, AW_ID_NONE, &mtl) == RES_BAD_ARG); + CHK(aw_obj_get_mtl(obj, 0, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_mtl(obj, 0, &mtl) == RES_OK); + CHK(!strcmp(mtl.name, "wood")); CHK(mtl.face_id == 0); CHK(mtl.faces_count == 1); - CHK(aw_obj_mtllib_get(NULL, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_mtllib_get(obj, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_mtllib_get(NULL, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_mtllib_get(obj, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_mtllib_get(NULL, AW_ID_NONE, &mtllib) == RES_BAD_ARG); - CHK(aw_obj_mtllib_get(obj, AW_ID_NONE, &mtllib) == RES_BAD_ARG); - CHK(aw_obj_mtllib_get(NULL, 0, &mtllib) == RES_BAD_ARG); - CHK(aw_obj_mtllib_get(obj, 0, &mtllib) == RES_OK); + CHK(aw_obj_get_mtllib(NULL, 0, &mtllib) == RES_BAD_ARG); + CHK(aw_obj_get_mtllib(obj, AW_ID_NONE, &mtllib) == RES_BAD_ARG); + CHK(aw_obj_get_mtllib(obj, 0, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_mtllib(obj, 0, &mtllib) == RES_OK); CHK(strcmp(mtllib, "master.mtl") == 0); - CHK(aw_obj_vertex_get(NULL, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_vertex_get(obj, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_vertex_get(NULL, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_vertex_get(obj, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_vertex_get(NULL, AW_ID_NONE, &vertex) == RES_BAD_ARG); - CHK(aw_obj_vertex_get(obj, AW_ID_NONE, &vertex) == RES_BAD_ARG); - CHK(aw_obj_vertex_get(NULL, 0, &vertex) == RES_BAD_ARG); - - CHK(aw_obj_vertex_get(obj, 0, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 0.f, 2.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.texcoord, f3(v4, 0.f, 1.f, 0.f)) == 1); - CHK(aw_obj_vertex_get(obj, 1, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 0.f, 0.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.texcoord, f3(v4, 0.f, 0.f, 0.f)) == 1); - CHK(aw_obj_vertex_get(obj, 2, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.texcoord, f3(v4, 1.f, 0.f, 0.f)) == 1); - CHK(aw_obj_vertex_get(obj, 3, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.texcoord, f3(v4, 1.f, 1.f, 0.f)) == 1); - - CHK(aw_obj_group_get(NULL, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_group_get(obj, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_group_get(NULL, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_group_get(obj, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_group_get(NULL, AW_ID_NONE, &group) == RES_BAD_ARG); - CHK(aw_obj_group_get(obj, AW_ID_NONE, &group) == RES_BAD_ARG); - CHK(aw_obj_group_get(NULL, 0, &group) == RES_BAD_ARG); - CHK(aw_obj_group_get(obj, 0, &group) == RES_OK); - CHK(strcmp(str_cget(&group.name), "default") == 0); + CHK(aw_obj_get_vertex(NULL, 0, &vertex) == RES_BAD_ARG); + CHK(aw_obj_get_vertex(obj, AW_ID_NONE, &vertex) == RES_BAD_ARG); + CHK(aw_obj_get_vertex(obj, 0, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_vertex(obj, 0, &vertex) == RES_OK); + + CHK(aw_obj_get_vertex_data(NULL, &vertex, &vdata) == RES_BAD_ARG); + CHK(aw_obj_get_vertex_data(obj, NULL, &vdata) == RES_BAD_ARG); + CHK(aw_obj_get_vertex_data(obj, &vertex, NULL) == RES_BAD_ARG); + + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 0, 2, 0, 1))); + CHK(d3_eq(vdata.texcoord, d3(v4, 0, 1, 0))); + + vertex.position_id = 4; + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_BAD_ARG); + vertex.position_id = 0; + vertex.texcoord_id = 4; + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_BAD_ARG); + vertex.texcoord_id = 0; + vertex.normal_id = 0; + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_BAD_ARG); + + CHK(aw_obj_get_vertex(obj, 1, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 0, 0, 0, 1))); + CHK(d3_eq(vdata.texcoord, d3(v4, 0, 0, 0))); + + CHK(aw_obj_get_vertex(obj, 2, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 2, 0, 0, 1))); + CHK(d3_eq(vdata.texcoord, d3(v4, 1, 0, 0))); + + CHK(aw_obj_get_vertex(obj, 3, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 2, 2, 0, 1))); + CHK(d3_eq(vdata.texcoord, d3(v4, 1, 1, 0))); + + CHK(aw_obj_get_group(NULL, 0, &group) == RES_BAD_ARG); + CHK(aw_obj_get_group(obj, AW_ID_NONE, &group) == RES_BAD_ARG); + CHK(aw_obj_get_group(obj, 0, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_group(obj, 0, &group) == RES_OK); + CHK(!strcmp(group.name, "default")); CHK(group.face_id == 0); CHK(group.faces_count == 1); - - CHK(aw_obj_named_group_release(NULL) == RES_BAD_ARG); - CHK(aw_obj_named_group_release(&group) == RES_OK); - CHK(aw_obj_named_group_release(&mtl) == RES_OK); } static void @@ -177,18 +170,17 @@ test_squares(struct aw_obj* obj) "f 1//1 2//2 3//3 4//4\n" "f 4//4 3//3 5//5 6//6\n" "# 2 elements\n"; - float v4[4]; + double v4[4]; struct aw_obj_desc desc; struct aw_obj_face face; struct aw_obj_named_group group; struct aw_obj_named_group mtl; struct aw_obj_smooth_group sgroup; struct aw_obj_vertex vertex; + struct aw_obj_vertex_data vdata; FILE* file; CHK(obj != NULL); - CHK(aw_obj_named_group_init(NULL, &group) == RES_OK); - CHK(aw_obj_named_group_init(NULL, &mtl) == RES_OK); file = fopen("test_obj_squares.obj", "w"); CHK(file != NULL); @@ -196,81 +188,78 @@ test_squares(struct aw_obj* obj) fclose(file); CHK(aw_obj_load(obj, "test_obj_squares.obj") == RES_OK); - CHK(aw_obj_desc_get(obj, &desc) == RES_OK); + CHK(aw_obj_get_desc(obj, &desc) == RES_OK); CHK(desc.faces_count == 2); CHK(desc.groups_count == 1); CHK(desc.smooth_groups_count == 1); CHK(desc.usemtls_count == 0); CHK(desc.mtllibs_count == 0); - CHK(aw_obj_face_get(obj, 0, &face) == RES_OK); + CHK(aw_obj_get_face(obj, 0, &face) == RES_OK); CHK(face.vertex_id == 0); CHK(face.vertices_count == 4); CHK(face.group_id == 0); CHK(face.smooth_group_id == 0); CHK(face.mtl_id == AW_ID_NONE); - CHK(aw_obj_vertex_get(obj, 0, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 0.f, 2.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.normal, f3(v4, 0.f, 0.f, 1.f)) == 1); - CHK(aw_obj_vertex_get(obj, 1, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 0.f, 0.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.normal, f3(v4, 0.f, 0.f, 1.f)) == 1); - CHK(aw_obj_vertex_get(obj, 2, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)) == 1); - CHK(aw_obj_vertex_get(obj, 3, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)) == 1); - - CHK(aw_obj_face_get(obj, 1, &face) == RES_OK); + CHK(aw_obj_get_vertex(obj, 0, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 0.0, 2.0, 0.0, 1.0))); + CHK(d3_eq(vdata.normal, d3(v4, 0.0, 0.0, 1.0))); + CHK(aw_obj_get_vertex(obj, 1, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 0.0, 0.0, 0.0, 1.0))); + CHK(d3_eq(vdata.normal, d3(v4, 0.0, 0.0, 1.0))); + CHK(aw_obj_get_vertex(obj, 2, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 2.0, 0.0, 0.0, 1.0))); + CHK(d3_eq(vdata.normal, d3(v4, 0.276597, 0.0, 0.960986))); + CHK(aw_obj_get_vertex(obj, 3, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 2.0, 2.0, 0.0, 1.0))); + CHK(d3_eq(vdata.normal, d3(v4, 0.276597, 0.0, 0.960986))); + + CHK(aw_obj_get_face(obj, 1, &face) == RES_OK); CHK(face.vertex_id == 4); CHK(face.vertices_count == 4); CHK(face.group_id == 0); CHK(face.smooth_group_id == 0); CHK(face.mtl_id == AW_ID_NONE); - CHK(aw_obj_vertex_get(obj, 4, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)) == 1); - CHK(aw_obj_vertex_get(obj, 5, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)) == 1); - CHK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)) == 1); - CHK(aw_obj_vertex_get(obj, 6, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 4.f, 0.f, -1.255298f, 1.f)) == 1); - CHK(f3_eq(vertex.normal, f3(v4, 0.531611f, 0.f, 0.846988f)) == 1); - CHK(aw_obj_vertex_get(obj, 7, &vertex) == RES_OK); - CHK(f4_eq(vertex.position, f4(v4, 4.f, 2.f, -1.255298f, 1.f)) == 1); - CHK(f3_eq(vertex.normal, f3(v4, 0.531611f, 0.f, 0.846988f)) == 1); - - CHK(aw_obj_group_get(NULL, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_group_get(obj, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_group_get(NULL, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_group_get(obj, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_group_get(NULL, AW_ID_NONE, &group) == RES_BAD_ARG); - CHK(aw_obj_group_get(obj, AW_ID_NONE, &group) == RES_BAD_ARG); - CHK(aw_obj_group_get(NULL, 0, &group) == RES_BAD_ARG); - CHK(aw_obj_group_get(obj, 0, &group) == RES_OK); - CHK(strcmp(str_cget(&group.name), "all") == 0); + CHK(aw_obj_get_vertex(obj, 4, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 2.0, 2.0, 0.0, 1.0))); + CHK(d3_eq(vdata.normal, d3(v4, 0.276597, 0.0, 0.960986))); + CHK(aw_obj_get_vertex(obj, 5, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 2.0, 0.0, 0.0, 1.0))); + CHK(d3_eq(vdata.normal, d3(v4, 0.276597, 0.0, 0.960986))); + CHK(aw_obj_get_vertex(obj, 6, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 4.0, 0.0, -1.255298, 1.0))); + CHK(d3_eq(vdata.normal, d3(v4, 0.531611, 0.0, 0.8469880))); + CHK(aw_obj_get_vertex(obj, 7, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d4_eq(vdata.position, d4(v4, 4.0, 2.0, -1.255298, 1.0)) == 1); + CHK(d3_eq(vdata.normal, d3(v4, 0.531611, 0.0, 0.846988)) == 1); + + CHK(aw_obj_get_group(NULL, 0, &group) == RES_BAD_ARG); + CHK(aw_obj_get_group(obj, AW_ID_NONE, &group) == RES_BAD_ARG); + CHK(aw_obj_get_group(obj, 0, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_group(obj, 0, &group) == RES_OK); + CHK(strcmp(group.name, "all") == 0); CHK(group.face_id == 0); CHK(group.faces_count == 2); - CHK(aw_obj_smooth_group_get(NULL, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_smooth_group_get(obj, AW_ID_NONE, NULL) == RES_BAD_ARG); - CHK(aw_obj_smooth_group_get(NULL, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_smooth_group_get(obj, 0, NULL) == RES_BAD_ARG); - CHK(aw_obj_smooth_group_get(NULL, AW_ID_NONE, &sgroup) == RES_BAD_ARG); - CHK(aw_obj_smooth_group_get(obj, AW_ID_NONE, &sgroup) == RES_BAD_ARG); - CHK(aw_obj_smooth_group_get(NULL, 0, &sgroup) == RES_BAD_ARG); - CHK(aw_obj_smooth_group_get(obj, 0, &sgroup) == RES_OK); + CHK(aw_obj_get_smooth_group(NULL, 0, &sgroup) == RES_BAD_ARG); + CHK(aw_obj_get_smooth_group(obj, AW_ID_NONE, &sgroup) == RES_BAD_ARG); + CHK(aw_obj_get_smooth_group(obj, 0, NULL) == RES_BAD_ARG); + CHK(aw_obj_get_smooth_group(obj, 0, &sgroup) == RES_OK); CHK(sgroup.is_smoothed == 1); CHK(sgroup.face_id == 0); CHK(sgroup.faces_count == 2); - CHK(aw_obj_mtl_get(obj, 0, &mtl) == RES_BAD_ARG); - - CHK(aw_obj_named_group_release(&group) == RES_OK); - CHK(aw_obj_named_group_release(&mtl) == RES_OK); + CHK(aw_obj_get_mtl(obj, 0, &mtl) == RES_BAD_ARG); } static void @@ -324,12 +313,11 @@ test_cube(struct aw_obj* obj) fwrite(cube_obj, sizeof(char), strlen(cube_obj), file); CHK(fseek(file, 0, SEEK_SET) == 0); - CHK(aw_obj_load_stream(NULL, NULL) == RES_BAD_ARG); - CHK(aw_obj_load_stream(obj, NULL) == RES_BAD_ARG); - CHK(aw_obj_load_stream(NULL, file) == RES_BAD_ARG); - CHK(aw_obj_load_stream(obj, file) == RES_OK); + CHK(aw_obj_load_stream(obj, NULL, NULL) == RES_BAD_ARG); + CHK(aw_obj_load_stream(NULL, file, NULL) == RES_BAD_ARG); + CHK(aw_obj_load_stream(obj, file, NULL) == RES_OK); - CHK(aw_obj_desc_get(obj, &desc) == RES_OK); + CHK(aw_obj_get_desc(obj, &desc) == RES_OK); CHK(desc.faces_count == 6); CHK(desc.groups_count == 6); CHK(desc.smooth_groups_count == 0); @@ -338,7 +326,7 @@ test_cube(struct aw_obj* obj) CHK(aw_obj_clear(NULL) == RES_BAD_ARG); CHK(aw_obj_clear(obj) == RES_OK); - CHK(aw_obj_desc_get(obj, &desc) == RES_OK); + CHK(aw_obj_get_desc(obj, &desc) == RES_OK); CHK(desc.faces_count == 0); CHK(desc.groups_count == 0); CHK(desc.smooth_groups_count == 0); @@ -346,12 +334,12 @@ test_cube(struct aw_obj* obj) CHK(desc.mtllibs_count == 0); CHK(fseek(file, 0, SEEK_SET) == 0); - CHK(aw_obj_load_stream(obj, file) == RES_OK); - CHK(aw_obj_desc_get(obj, &desc) == RES_OK); + CHK(aw_obj_load_stream(obj, file, "cube") == RES_OK); + CHK(aw_obj_get_desc(obj, &desc) == RES_OK); FOR_EACH(i, 0, 6) { struct aw_obj_face face; - CHK(aw_obj_face_get(obj, i, &face) == RES_OK); + CHK(aw_obj_get_face(obj, i, &face) == RES_OK); CHK(face.vertex_id == i*4); CHK(face.vertices_count == 4); CHK(face.group_id == i); @@ -361,35 +349,31 @@ test_cube(struct aw_obj* obj) FOR_EACH(i, 0, 6) { struct aw_obj_named_group group; - CHK(aw_obj_named_group_init(NULL, &group) == RES_OK); - CHK(aw_obj_group_get(obj, i, &group) == RES_OK); - CHK(strcmp(str_cget(&group.name), group_names[i]) == 0); + CHK(aw_obj_get_group(obj, i, &group) == RES_OK); + CHK(!strcmp(group.name, group_names[i])); CHK(group.face_id == i); CHK(group.faces_count == 1); - CHK(aw_obj_named_group_release(&group) == RES_OK); } FOR_EACH(i, 0, 6) { struct aw_obj_named_group mtl; - CHK(aw_obj_named_group_init(NULL, &mtl) == RES_OK); - CHK(aw_obj_mtl_get(obj, i, &mtl) == RES_OK); - CHK(strcmp(str_cget(&mtl.name), mtl_names[i]) == 0); + CHK(aw_obj_get_mtl(obj, i, &mtl) == RES_OK); + CHK(!strcmp(mtl.name, mtl_names[i])); CHK(mtl.face_id == i); CHK(mtl.faces_count == 1); - CHK(aw_obj_named_group_release(&mtl) == RES_OK); } - CHK(aw_obj_mtllib_get(obj, 0, &mtllib) == RES_OK); - CHK(strcmp(mtllib, "master.mtl") == 0); - CHK(aw_obj_mtllib_get(obj, 1, &mtllib) == RES_OK); - CHK(strcmp(mtllib, "hop.mtl") == 0); - CHK(aw_obj_mtllib_get(obj, 2, &mtllib) == RES_OK); - CHK(strcmp(mtllib, "my.mtl") == 0); - CHK(aw_obj_mtllib_get(obj, 3, &mtllib) == RES_BAD_ARG); + CHK(aw_obj_get_mtllib(obj, 0, &mtllib) == RES_OK); + CHK(!strcmp(mtllib, "master.mtl")); + CHK(aw_obj_get_mtllib(obj, 1, &mtllib) == RES_OK); + CHK(!strcmp(mtllib, "hop.mtl")); + CHK(aw_obj_get_mtllib(obj, 2, &mtllib) == RES_OK); + CHK(!strcmp(mtllib, "my.mtl")); + CHK(aw_obj_get_mtllib(obj, 3, &mtllib) == RES_BAD_ARG); CHK(aw_obj_purge(NULL) == RES_BAD_ARG); CHK(aw_obj_purge(obj) == RES_OK); - CHK(aw_obj_desc_get(obj, &desc) == RES_OK); + CHK(aw_obj_get_desc(obj, &desc) == RES_OK); CHK(desc.faces_count == 0); CHK(desc.groups_count == 0); CHK(desc.smooth_groups_count == 0); @@ -446,106 +430,114 @@ test_cbox(struct aw_obj* obj) struct aw_obj_desc desc; struct aw_obj_face face; struct aw_obj_vertex vertex; + struct aw_obj_vertex_data vdata; struct aw_obj_named_group group; struct aw_obj_named_group mtl; - float tmp[3]; + double tmp[3]; FILE* file; CHK(obj != NULL); - CHK(aw_obj_named_group_init(NULL, &group) == RES_OK); - CHK(aw_obj_named_group_init(NULL, &mtl) == RES_OK); file = fopen("test_cbox.obj", "w+"); CHK(file != NULL); fwrite(cbox_obj, sizeof(char), strlen(cbox_obj), file); CHK(fseek(file, 0, SEEK_SET) == 0); - CHK(aw_obj_load_stream(obj, file) == RES_OK); + CHK(aw_obj_load_stream(obj, file, "cbox") == RES_OK); fclose(file); - CHK(aw_obj_desc_get(obj, &desc) == RES_OK); + CHK(aw_obj_get_desc(obj, &desc) == RES_OK); CHK(desc.faces_count == 5); CHK(desc.groups_count == 5); CHK(desc.smooth_groups_count == 0); CHK(desc.usemtls_count == 5); CHK(desc.mtllibs_count == 1); - CHK(aw_obj_face_get(obj, 0, &face) == RES_OK); + CHK(aw_obj_get_face(obj, 0, &face) == RES_OK); CHK(face.vertex_id == 0); CHK(face.vertices_count == 4); CHK(face.group_id == 0); CHK(face.mtl_id == 0); - CHK(aw_obj_group_get(obj, 0, &group) == RES_OK); - CHK(strcmp(str_cget(&group.name), "floor") == 0); + CHK(aw_obj_get_group(obj, 0, &group) == RES_OK); + CHK(!strcmp(group.name, "floor")); CHK(group.face_id == 0); CHK(group.faces_count == 1); - CHK(aw_obj_mtl_get(obj, 0, &mtl) == RES_OK); - CHK(strcmp(str_cget(&mtl.name), "floor") == 0); + CHK(aw_obj_get_mtl(obj, 0, &mtl) == RES_OK); + CHK(!strcmp(mtl.name, "floor")); CHK(mtl.face_id == 0); CHK(mtl.faces_count == 1); - CHK(aw_obj_vertex_get(obj, 0, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, -1.01f, 0.f, 0.99f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 1, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, 1.f, 0.f, 0.99f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 2, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, 1.f, 0.f, -1.04f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 3, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, -0.99f, 0.f, -1.04f), 1.e-6f) == 1); - - CHK(aw_obj_face_get(obj, 1, &face) == RES_OK); + CHK(aw_obj_get_vertex(obj, 0, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, -1.01, 0.0, 0.99), 1.e-6)); + CHK(aw_obj_get_vertex(obj, 1, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, 1.0, 0.0, 0.99), 1.e-6)); + CHK(aw_obj_get_vertex(obj, 2, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, 1.f, 0.0, -1.04), 1.e-6)); + CHK(aw_obj_get_vertex(obj, 3, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, -0.99, 0.0, -1.04), 1.e-6)); + + CHK(aw_obj_get_face(obj, 1, &face) == RES_OK); CHK(face.vertex_id == 4); CHK(face.vertices_count == 4); CHK(face.group_id == 1); CHK(face.mtl_id == 1); - CHK(aw_obj_group_get(obj, 1, &group) == RES_OK); - CHK(strcmp(str_cget(&group.name), "ceiling") == 0); + CHK(aw_obj_get_group(obj, 1, &group) == RES_OK); + CHK(!strcmp(group.name, "ceiling")); CHK(group.face_id == 1); CHK(group.faces_count == 1); - CHK(aw_obj_mtl_get(obj, 1, &mtl) == RES_OK); - CHK(strcmp(str_cget(&mtl.name), "ceiling") == 0); + CHK(aw_obj_get_mtl(obj, 1, &mtl) == RES_OK); + CHK(!strcmp(mtl.name, "ceiling")); CHK(mtl.face_id == 1); CHK(mtl.faces_count == 1); - CHK(aw_obj_vertex_get(obj, 4, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, -1.02f, 1.99f, 0.99f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 5, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, -1.02f, 1.99f, -1.04f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 6, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, 1.f, 1.99f, -1.04f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 7, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, 1.f, 1.99f, 0.99f), 1.e-6f) == 1); - - CHK(aw_obj_face_get(obj, 4, &face) == RES_OK); + CHK(aw_obj_get_vertex(obj, 4, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, -1.02, 1.99, 0.99), 1.e-6)); + CHK(aw_obj_get_vertex(obj, 5, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, -1.02, 1.99, -1.04), 1.e-6f)); + CHK(aw_obj_get_vertex(obj, 6, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, 1.0, 1.99, -1.04), 1.e-6f)); + CHK(aw_obj_get_vertex(obj, 7, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, 1.0, 1.99, 0.99), 1.e-6f)); + + CHK(aw_obj_get_face(obj, 4, &face) == RES_OK); CHK(face.vertex_id == 16); CHK(face.vertices_count == 4); CHK(face.group_id == 4); CHK(face.mtl_id == 4); - CHK(aw_obj_group_get(obj, 4, &group) == RES_OK); - CHK(strcmp(str_cget(&group.name), "left") == 0); + CHK(aw_obj_get_group(obj, 4, &group) == RES_OK); + CHK(!strcmp(group.name, "left")); CHK(group.face_id == 4); CHK(group.faces_count == 1); - CHK(aw_obj_mtl_get(obj, 4, &mtl) == RES_OK); - CHK(strcmp(str_cget(&mtl.name), "left") == 0); + CHK(aw_obj_get_mtl(obj, 4, &mtl) == RES_OK); + CHK(!strcmp(mtl.name, "left")); CHK(mtl.face_id == 4); CHK(mtl.faces_count == 1); - CHK(aw_obj_vertex_get(obj, 16, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, -1.01f, 0.f, 0.99f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 17, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, -0.99f, 0.f, -1.04f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 18, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, -1.02f, 1.99f, -1.04f), 1.e-6f) == 1); - CHK(aw_obj_vertex_get(obj, 19, &vertex) == RES_OK); - CHK(f3_eq_eps(vertex.position, f3(tmp, -1.02f, 1.99f, 0.99f), 1.e-6f) == 1); - - CHK(aw_obj_named_group_release(&group) == RES_OK); - CHK(aw_obj_named_group_release(&mtl) == RES_OK); + CHK(aw_obj_get_vertex(obj, 16, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, -1.01, 0.0, 0.99), 1.e-6)); + CHK(aw_obj_get_vertex(obj, 17, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, -0.99, 0.0, -1.04), 1.e-6)); + CHK(aw_obj_get_vertex(obj, 18, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, -1.02, 1.99, -1.04), 1.e-6)); + CHK(aw_obj_get_vertex(obj, 19, &vertex) == RES_OK); + CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK); + CHK(d3_eq_eps(vdata.position, d3(tmp, -1.02, 1.99, 0.99), 1.e-6)); } int @@ -557,9 +549,9 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(aw_obj_create(NULL, NULL, 1, NULL) == RES_BAD_ARG); - CHK(aw_obj_create(NULL, &allocator, 1, NULL) == RES_BAD_ARG); - CHK(aw_obj_create(NULL, NULL, 1, &obj) == RES_OK); + CHK(aw_obj_create(LOGGER_DEFAULT, NULL, 1, NULL) == RES_BAD_ARG); + CHK(aw_obj_create(LOGGER_DEFAULT, &allocator, 1, NULL) == RES_BAD_ARG); + CHK(aw_obj_create(LOGGER_DEFAULT, NULL, 1, &obj) == RES_OK); CHK(aw_obj_ref_get(NULL) == RES_BAD_ARG); CHK(aw_obj_ref_get(obj) == RES_OK); @@ -567,7 +559,7 @@ main(int argc, char** argv) CHK(aw_obj_ref_put(obj) == RES_OK); CHK(aw_obj_ref_put(obj) == RES_OK); - CHK(aw_obj_create(LOGGER_DEFAULT, &allocator, 1, &obj) == RES_OK); + CHK(aw_obj_create(NULL, &allocator, 1, &obj) == RES_OK); test_plane(obj); test_squares(obj);