commit e12349b3416ec25db978ced64316ddfed7665041
parent f87ef006714a775935ddeb7f209bd21878198172
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 18 Oct 2023 12:02:53 +0200
Merge branch 'release_2.1'
Diffstat:
15 files changed, 538 insertions(+), 163 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,11 +1,14 @@
.gitignore
-CMakeCache.txt
-CMakeFiles
-Makefile
-tmp
[Bb]uild*
*.sw[po]
-*.[ao]
+*.[aod]
+*.so
*~
+test*
+!test*.[ch]
+.test
+.config
tags
-
+aw.pc
+aw-local.pc
+*.mtl
diff --git a/Makefile b/Makefile
@@ -0,0 +1,151 @@
+# Copyright (C) 2014-2017, 2020-2023 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+.POSIX:
+.SUFFIXES: # Clean up default inference rules
+
+include config.mk
+
+LIBNAME_STATIC = libaw.a
+LIBNAME_SHARED = libaw.so
+LIBNAME = $(LIBNAME_$(LIB_TYPE))
+
+################################################################################
+# Library building
+################################################################################
+SRC = src/aw.c src/aw_obj.c src/aw_mtl.c
+OBJ = $(SRC:.c=.o)
+DEP = $(SRC:.c=.d)
+
+build_library: .config $(DEP)
+ @$(MAKE) -fMakefile $$(for i in $(DEP); do echo -f $${i}; done) \
+ $$(if [ -n "$(LIBNAME)" ]; then\
+ echo "$(LIBNAME)";\
+ else\
+ echo "$(LIBNAME_SHARED)";\
+ fi)
+
+$(DEP) $(OBJ): config.mk
+
+$(LIBNAME_SHARED): $(OBJ)
+ $(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -o $@ $(OBJ) $(LDFLAGS_SO) $(RSYS_LIBS)
+
+$(LIBNAME_STATIC): libaw.o
+ $(AR) -rc $@ $?
+ $(RANLIB) $@
+
+libaw.o: $(OBJ)
+ $(LD) -r $(OBJ) -o $@
+ $(OBJCOPY) $(OCPFLAGS) $@
+
+.config: Makefile config.mk
+ @if ! $(PKG_CONFIG) --atleast-version $(RSYS_VERSION) rsys; then \
+ echo "rsys $(RSYS_VERSION) not found"; exit 1; fi
+ @echo "config done" > .config
+
+.SUFFIXES: .c .d .o
+.c.d:
+ @$(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -MM -MT "$(@:.d=.o) $@" $< -MF $@
+
+.c.o:
+ $(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -DAW_SHARED_BUILD -c $< -o $@
+
+################################################################################
+# Installation
+################################################################################
+pkg:
+ sed -e 's#@PREFIX@#$(PREFIX)#g' \
+ -e 's#@VERSION@#$(VERSION)#g' \
+ -e 's#@RSYS_VERSION@#$(RSYS_VERSION)#g' \
+ aw.pc.in > aw.pc
+
+aw-local.pc: aw.pc.in
+ sed -e '1d'\
+ -e 's#^includedir=.*#includedir=./src/#'\
+ -e 's#^libdir=.*#libdir=./#'\
+ -e 's#@VERSION@#$(VERSION)#g'\
+ -e 's#@RSYS_VERSION@#$(RSYS_VERSION)#g' \
+ aw.pc.in > $@
+
+install: build_library pkg
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/lib" $(LIBNAME)
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/lib/pkgconfig" aw.pc
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/include" src/aw.h
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/share/doc/aw"\
+ COPYING README.md
+
+uninstall:
+ rm -f "$(DESTDIR)$(PREFIX)/lib/$(LIBNAME)"
+ rm -f "$(DESTDIR)$(PREFIX)/lib/pkgconfig/aw.pc"
+ rm -f "$(DESTDIR)$(PREFIX)/include/aw.h"
+ rm -f "$(DESTDIR)$(PREFIX)/share/doc/aw/COPYING"
+ rm -f "$(DESTDIR)$(PREFIX)/share/doc/aw/README.md"
+
+################################################################################
+# Miscellaneous targets
+################################################################################
+all: build_library build_tests
+
+clean: clean_test
+ rm -f $(OBJ) $(TEST_OBJ) $(LIBNAME)
+ rm -f .config .test aw.pc aw-local.pc libaw.o
+
+distclean: clean
+ rm -f $(DEP) $(TEST_DEP)
+
+lint:
+ shellcheck -o all make.sh
+
+################################################################################
+# Tests
+################################################################################
+TEST_SRC =\
+ src/test_aw.c\
+ src/test_aw_mtl.c\
+ src/test_aw_obj.c
+TEST_OBJ = $(TEST_SRC:.c=.o)
+TEST_DEP = $(TEST_SRC:.c=.d)
+
+PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG)
+AW_CFLAGS = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags aw-local.pc)
+AW_LIBS = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs aw-local.pc)
+
+build_tests: build_library $(TEST_DEP) .test
+ @$(MAKE) -fMakefile -f.test $$(for i in $(TEST_DEP); do echo -f"$${i}"; done) test_bin
+
+test: build_tests
+ @$(SHELL) make.sh run_test src/test_aw_mtl.c src/test_aw_obj.c
+
+.test: Makefile make.sh
+ @$(SHELL) make.sh config_test $(TEST_SRC) > $@
+
+clean_test:
+ rm -f test_cbox.obj test_obj_cube.obj test_obj_plane.obj test_obj_squares.obj
+ rm -f mtl0.mtl test_mtl_common.mtl test_mtl_multi.mtl
+ $(SHELL) make.sh clean_test $(TEST_SRC)
+
+$(TEST_DEP) $(TEST_OBJ): config.mk aw-local.pc
+
+$(TEST_DEP):
+ @$(CC) $(CFLAGS_EXE) $(AW_CFLAGS) $(RSYS_CFLAGS) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+
+$(TEST_OBJ):
+ $(CC) $(CFLAGS_EXE) $(AW_CFLAGS) $(RSYS_CFLAGS) -c $(@:.o=.c) -o $@
+
+test_aw \
+test_aw_mtl \
+test_aw_obj \
+: config.mk aw-local.pc $(LIBNAME)
+ $(CC) $(CFLAGS_EXE) -o $@ src/$@.o $(LDFLAGS_EXE) $(AW_LIBS) $(RSYS_LIBS)
diff --git a/README.md b/README.md
@@ -1,73 +1,103 @@
# Loader of the Alias Wafefront obj and mtl file formats
-This C89 code base loads the Alias Wavefront
+AW is a C library whose purpose is to load the Alias Wavefront
[`obj`](http://www.martinreddy.net/gfx/3d/OBJ.spec) and
-[`mtl`](http://www.fileformat.info/format/material/) file formats. Note that
-only a subset of these formats are currently supported.
-
-For `obj` files, polygonal primitives with their per vertex position, normal
-and texture coordinates are loaded. Smooth, common and material groupings are
-also correctly handled.
-
-For `mtl` files, the ambient, diffuse, specular, glossiness and transmissive RGB
-or XYZ colors are supported. In addition, it loads the refraction index and the
-illumination model. It also handles the ambient, diffuse, specular, glossiness and
-bump textures as well as their attributes (blend< u|v \>, color correction,
-channel mapping, texcoord < offset|scale|turbulence \>, image resolution and bump
-multiplier).
-
-## How to build
-
-The library uses [CMake](http://www.cmake.org) and the
-[RCMake](https://gitlab.com/vaplv/rcmake/#tab-readme) package to build. It also
-depends on the [RSys](https://gitlab.com/vaplv/rsys/#tab-readme) library. First,
-install the RCMake package and the RSys library. Then, generate the project
-from the cmake/CMakeLists.txt file by appending the RCMake and RSys
-install directories to the `CMAKE_PREFIX_PATH` variable. The resulting project
-can be edited, built, tested and installed as any CMake project.
+[`mtl`](http://www.fileformat.info/format/material/) file formats. Only
+a subset of these formats are currently supported.
+
+For `obj` files, polygonal primitives with their per vertex-position,
+normal and texture coordinates are loaded. Smooth, common and material
+groupings are also handled correctly.
+
+For `mtl` files, ambient, diffuse, specular, glossiness and transmissive
+RGB or XYZ colors are supported. Additionally, it loads the refraction
+index and the illumination model. The library also loads the filename of
+ambient, diffuse, specular, glossiness and bump textures and their
+attributes (blend< u|v \>, color correction, channel mapping, texcoord
+< offset|scale|turbulence \>, image resolution and bump multiplier).
+
+## Requirements
+
+- C compiler
+- POSIX make
+- pkg-config
+- [RSys](https://gitlab.com/vaplv/rsys/)
+
+## Installation
+
+Edit config.mk as needed, then run:
+
+ make clean install
## Release notes
+### Version 2.1
+
+### POSIX make
+
+Replace CMake by Makefile as build system. The build procedure is
+written in POSIX make, which the user can configure via the `config.mk`
+file. The POSIX script `make.sh` contains commands that could be found
+directly in the Makefile, but which are placed here to simplify its
+writing. Finally, a pkg-config file is provided to link the library as
+an external dependency.
+
+In addition to the features already provided by its CMake alternative,
+the Makefile supports the construction of static libraries, provides an
+uninstall target and updates compiler and linker flags to increase the
+security and robustness of generated binaries. In any case, the main
+motivation for using POSIX make is to rely on a good old
+well-established standard with simple functionality, available on all
+UNIX systems, thus simplifying its portability and support while being
+much lighter.
+
+### Miscellaneous
+
+Update the `aw_obj_desc` data structure: add the number of positions,
+texcoords and normals as new member variables of the structure.
+
### Version 2.0.1
-Sets the CMake minimum version to 3.1: since CMake 3.20, version 2.8 has become
-obsolete.
+Sets the CMake minimum version to 3.1: since CMake 3.20, version 2.8 has
+become obsolete.
### 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.
+- 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.
+- 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
- `[N]CHECK` macros by the new macro `CHK`.
+- Update the version of the RSys dependency to 0.6: replace the
+ deprecated `[N]CHECK` macros by the new macro `CHK`.
### Version 1.3
-- Add the `aw_obj_purge` and `aw_mtl_purge` functions that not only reset the
- state of the loaders, as the `aw_obj_clear` and `aw_mtl_clear` functions, but
- also free their internal memory.
+- Add the `aw_obj_purge` and `aw_mtl_purge` functions that not only
+ reset the state of the loaders, as the `aw_obj_clear` and
+ `aw_mtl_clear` functions, but also free their internal memory.
## License
-Copyright (C) 2014-2017, 2020, 2021 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.
+Copyright (C) 2014-2017, 2020-2023 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/aw.pc.in b/aw.pc.in
@@ -0,0 +1,10 @@
+prefix=@PREFIX@
+includedir=${prefix}/include
+libdir=${prefix}/lib
+
+Requires: rsys >= @RSYS_VERSION@
+Name: AW
+Description: AW library
+Version: @VERSION@
+Libs: -L${libdir} -law
+CFlags: -I${includedir}
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,93 +0,0 @@
-# Copyright (C) 2014-2017, 2020, 2021 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-cmake_minimum_required(VERSION 3.1)
-project(aw C)
-cmake_policy(SET CMP0011 NEW)
-enable_testing()
-
-option(NO_TEST "Do not compile the test pograms" OFF)
-
-set(AW_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
-
-################################################################################
-# Dependencies
-################################################################################
-find_package(RCMake 0.4 REQUIRED)
-find_package(RSys 0.9 REQUIRED)
-
-set(CMAKE_MODULE_PATH ${RCMAKE_SOURCE_DIR})
-include(rcmake)
-include(rcmake_runtime)
-rcmake_append_runtime_dirs(_runtime_dirs RSys)
-
-################################################################################
-# Define targets
-################################################################################
-set(VERSION_MAJOR 2)
-set(VERSION_MINOR 0)
-set(VERSION_PATCH 1)
-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 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}/../)
-
-add_library(aw SHARED ${AW_FILES_SRC} ${AW_FILES_INC})
-set_target_properties(aw PROPERTIES
- DEFINE_SYMBOL AW_SHARED_BUILD
- VERSION ${VERSION}
- SOVERSION ${VERSION_MAJOR})
-target_link_libraries(aw RSys)
-
-if(MSVC)
- # The CL compiler does not support the strtok_r POSIX function but proposes
- # the strtok_s function that have the same profile and does the same thing.
- set_target_properties(aw PROPERTIES COMPILE_FLAGS "/Dstrtok_r=strtok_s")
-endif(MSVC)
-
-rcmake_setup_devel(aw AW ${VERSION} aw_version.h)
-
-################################################################################
-# Define tests
-################################################################################
-if(NOT NO_TEST)
- add_executable(test_aw_obj ${AW_SOURCE_DIR}/test_aw_obj.c)
- target_link_libraries(test_aw_obj aw)
- add_test(test_aw_obj test_aw_obj)
- rcmake_set_test_runtime_dirs(test_aw_obj _runtime_dirs)
-
- add_executable(test_aw_mtl ${AW_SOURCE_DIR}/test_aw_mtl.c)
- 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)
-
-################################################################################
-# Install directories
-################################################################################
-install(TARGETS aw
- ARCHIVE DESTINATION bin
- LIBRARY DESTINATION lib
- RUNTIME DESTINATION bin)
-install(FILES ${AW_FILES_INC} DESTINATION include)
-install(FILES ${AW_FILES_DOC} DESTINATION share/doc/aw)
-
diff --git a/config.mk b/config.mk
@@ -0,0 +1,75 @@
+VERSION = 2.1.0
+PREFIX = /usr/local
+
+LIB_TYPE = SHARED
+#LIB_TYPE = STATIC
+
+BUILD_TYPE = RELEASE
+#BUILD_TYPE = DEBUG
+
+################################################################################
+# Tools
+################################################################################
+AR = ar
+CC = cc
+LD = ld
+PKG_CONFIG = pkg-config
+OBJCOPY = objcopy
+RANLIB = ranlib
+
+################################################################################
+# Dependencies
+################################################################################
+PCFLAGS_STATIC = --static
+PCFLAGS = $(PCFLAGS_$(LIB_TYPE))
+
+RSYS_VERSION = 0.14
+RSYS_CFLAGS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags rsys)
+RSYS_LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs rsys)
+
+################################################################################
+# Compilation options
+################################################################################
+WFLAGS =\
+ -Wall\
+ -Wcast-align\
+ -Wconversion\
+ -Wextra\
+ -Wmissing-declarations\
+ -Wmissing-prototypes\
+ -Wshadow
+
+CFLAGS_HARDENED =\
+ -D_FORTIFY_SOURCES=2\
+ -fcf-protection=full\
+ -fstack-clash-protection\
+ -fstack-protector-strong
+
+CFLAGS_COMMON=\
+ -std=c89\
+ -pedantic\
+ -fvisibility=hidden\
+ -fstrict-aliasing\
+ $(CFLAGS_HARDENED)\
+ $(WFLAGS)
+
+CFLAGS_RELEASE = -O2 -DNDEBUG $(CFLAGS_COMMON)
+CFLAGS_DEBUG = -g $(CFLAGS_COMMON)
+CFLAGS = $(CFLAGS_$(BUILD_TYPE))
+CFLAGS_SO = $(CFLAGS) -fPIC
+CFLAGS_EXE = $(CFLAGS) -fPIE
+
+################################################################################
+# Linker options
+################################################################################
+LDFLAGS_HARDENED = -Wl,-z,relro,-z,now
+LDFLAGS_DEBUG = $(LDFLAGS_HARDENED)
+LDFLAGS_RELEASE = -s $(LDFLAGS_HARDENED)
+LDFLAGS = $(LDFLAGS_$(BUILD_TYPE))
+
+LDFLAGS_SO = $(LDFLAGS) -shared -Wl,--no-undefined
+LDFLAGS_EXE = $(LDFLAGS) -pie
+
+OCPFLAGS_DEBUG = --localize-hidden
+OCPFLAGS_RELEASE = --localize-hidden --strip-unneeded
+OCPFLAGS = $(OCPFLAGS_$(BUILD_TYPE))
diff --git a/make.sh b/make.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+# Copyright (C) 2014-2017, 2020-2023 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+set -e
+
+config_test()
+{
+ for i in "$@"; do
+ test=$(basename "${i}" ".c")
+ test_list="${test_list} ${test}"
+ printf "%s: src/%s.o\n" "${test}" "${test}"
+ done
+ printf "test_bin: %s\n" "${test_list}"
+}
+
+run_test()
+{
+ for i in "$@"; do
+ test=$(basename "${i}" ".c")
+
+ printf "%s " "${test}"
+ if ./"${test}" > /dev/null 2>&1; then
+ printf "\033[1;32mOK\033[m\n"
+ else
+ printf "\033[1;31mError\033[m\n"
+ fi
+ done 2> /dev/null
+}
+
+clean_test()
+{
+ for i in "$@"; do
+ rm -f "$(basename "${i}" ".c")"
+ done
+}
+
+install()
+{
+ prefix=$1
+ shift 1
+
+ mkdir -p "${prefix}"
+
+ for i in "$@"; do
+ dst="${prefix}/${i##*/}"
+
+ if cmp -s "${i}" "${dst}"; then
+ printf "Up to date %s\n" "${dst}"
+ else
+ printf "Installing %s\n" "${dst}"
+ cp "${i}" "${prefix}"
+ fi
+ done
+}
+
+"$@"
diff --git a/src/aw.c b/src/aw.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2017, 2020, 2021 Vincent Forest (vaplv@free.fr)
+/* Copyright (C) 2014-2017, 2020-2023 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
diff --git a/src/aw.h b/src/aw.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2017, 2020, 2021 Vincent Forest (vaplv@free.fr)
+/* Copyright (C) 2014-2017, 2020-2023 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
@@ -58,6 +58,9 @@ enum aw_map_channel {
struct aw_obj_desc {
size_t faces_count;
+ size_t positions_count;
+ size_t normals_count;
+ size_t texcoords_count;
size_t groups_count;
size_t smooth_groups_count;
size_t usemtls_count;
@@ -222,6 +225,21 @@ aw_obj_get_vertex_data
const struct aw_obj_vertex* vertex,
struct aw_obj_vertex_data* vertex_data);
+AW_API res_T
+aw_obj_get_positions
+ (const struct aw_obj* obj,
+ const double** positions); /* List of double 4 */
+
+AW_API res_T
+aw_obj_get_texcoords
+ (const struct aw_obj* obj,
+ const double** texcoords); /* List of double 3 */
+
+AW_API res_T
+aw_obj_get_normals
+ (const struct aw_obj* obj,
+ const double** normals); /* List of double 3 */
+
/*******************************************************************************
* Mtl functions
******************************************************************************/
diff --git a/src/aw_c.h b/src/aw_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2017, 2020, 2021 Vincent Forest (vaplv@free.fr)
+/* Copyright (C) 2014-2017, 2020-2023 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
diff --git a/src/aw_mtl.c b/src/aw_mtl.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2017, 2020, 2021 Vincent Forest (vaplv@free.fr)
+/* Copyright (C) 2014-2017, 2020-2023 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
diff --git a/src/aw_obj.c b/src/aw_obj.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2017, 2020, 2021 Vincent Forest (vaplv@free.fr)
+/* Copyright (C) 2014-2017, 2020-2023 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
@@ -816,6 +816,9 @@ aw_obj_get_desc(const struct aw_obj* obj, struct aw_obj_desc* desc)
if(!obj || !desc)
return RES_BAD_ARG;
desc->faces_count = darray_face_size_get(&obj->faces);
+ desc->positions_count = darray_double_size_get(&obj->positions) / 4;
+ desc->normals_count = darray_double_size_get(&obj->normals) / 3;
+ desc->texcoords_count = darray_double_size_get(&obj->texcoords) / 3;
desc->groups_count = darray_named_group_size_get(&obj->groups);
desc->smooth_groups_count = darray_smooth_group_size_get(&obj->smooth_groups);
desc->usemtls_count = darray_named_group_size_get(&obj->usemtls);
@@ -970,6 +973,30 @@ error:
goto exit;
}
+res_T
+aw_obj_get_positions(const struct aw_obj* obj, const double** positions)
+{
+ if(!obj || !positions) return RES_BAD_ARG;
+ *positions = darray_double_cdata_get(&obj->positions);
+ return RES_OK;
+}
+
+res_T
+aw_obj_get_texcoords(const struct aw_obj* obj, const double** texcoords)
+{
+ if(!obj || !texcoords) return RES_BAD_ARG;
+ *texcoords = darray_double_cdata_get(&obj->texcoords);
+ return RES_OK;
+}
+
+res_T
+aw_obj_get_normals(const struct aw_obj* obj, const double** normals)
+{
+ if(!obj || !normals) return RES_BAD_ARG;
+ *normals = darray_double_cdata_get(&obj->normals);
+ return RES_OK;
+}
+
#ifdef COMPILER_CL
#pragma warning(pop)
#endif
diff --git a/src/test_aw.c b/src/test_aw.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2017, 2020, 2021 Vincent Forest (vaplv@free.fr)
+/* Copyright (C) 2014-2017, 2020-2023 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
diff --git a/src/test_aw_mtl.c b/src/test_aw_mtl.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2017, 2020, 2021 Vincent Forest (vaplv@free.fr)
+/* Copyright (C) 2014-2017, 2020-2023 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
@@ -58,7 +58,7 @@ test_common(struct aw_mtl* mtl)
file = fopen("test_mtl_common.mtl", "w");
CHK(file != NULL);
fwrite(mtl_common, sizeof(char), strlen(mtl_common), file);
- fclose(file);
+ CHK(fclose(file) == 0);
CHK(aw_mtl_load(NULL, NULL) == RES_BAD_ARG);
CHK(aw_mtl_load(mtl, NULL) == RES_BAD_ARG);
@@ -278,7 +278,7 @@ test_multiple_materials(struct aw_mtl* mtl)
CHK(!mat.bump_map.filename);
CHK(!mat.specular_exponent_map.filename);
- fclose(file);
+ CHK(fclose(file) == 0);
}
static void
@@ -303,7 +303,7 @@ test_unloadable(struct aw_mtl* mtl)
file = fopen("mtl0.mtl", "w");
CHK(file != NULL);
fwrite(mtl0, sizeof(char), strlen(mtl0), file);
- fclose(file);
+ CHK(fclose(file) == 0);
CHK(aw_mtl_load(mtl, "mtl0.mtl") == RES_BAD_ARG);
CHK(aw_mtl_get_materials_count(mtl, &nmtls) == RES_OK);
diff --git a/src/test_aw_obj.c b/src/test_aw_obj.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2017, 2020, 2021 Vincent Forest (vaplv@free.fr)
+/* Copyright (C) 2014-2017, 2020-2023 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
@@ -50,6 +50,7 @@ test_plane(struct aw_obj* obj)
struct aw_obj_named_group mtl;
struct aw_obj_vertex vertex;
struct aw_obj_vertex_data vdata;
+ const double* data = NULL;
FILE* file;
const char* mtllib;
@@ -58,7 +59,7 @@ test_plane(struct aw_obj* obj)
file = fopen("test_obj_plane.obj", "w");
CHK(file != NULL);
fwrite(plane_obj, sizeof(char), strlen(plane_obj), file);
- fclose(file);
+ CHK(fclose(file) == 0);
CHK(aw_obj_load(obj, NULL) == RES_BAD_ARG);
CHK(aw_obj_load(NULL, "test_obj_plane.obj") == RES_BAD_ARG);
@@ -70,6 +71,9 @@ test_plane(struct aw_obj* obj)
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.positions_count == 4);
+ CHK(desc.texcoords_count == 4);
+ CHK(desc.normals_count == 0);
CHK(desc.groups_count == 1);
CHK(desc.smooth_groups_count == 0);
CHK(desc.usemtls_count == 1);
@@ -143,6 +147,22 @@ test_plane(struct aw_obj* obj)
CHK(!strcmp(group.name, "default"));
CHK(group.face_id == 0);
CHK(group.faces_count == 1);
+
+ CHK(aw_obj_get_positions(NULL, &data) == RES_BAD_ARG);
+ CHK(aw_obj_get_positions(obj, NULL) == RES_BAD_ARG);
+ CHK(aw_obj_get_positions(obj, &data) == RES_OK);
+ CHK(d4_eq(data+0, d4(v4,0,2,0,1)));
+ CHK(d4_eq(data+4, d4(v4,0,0,0,1)));
+ CHK(d4_eq(data+8, d4(v4,2,0,0,1)));
+ CHK(d4_eq(data+12, d4(v4,2,2,0,1)));
+
+ CHK(aw_obj_get_texcoords(NULL, &data) == RES_BAD_ARG);
+ CHK(aw_obj_get_texcoords(obj, NULL) == RES_BAD_ARG);
+ CHK(aw_obj_get_texcoords(obj, &data) == RES_OK);
+ CHK(d3_eq(data+0, d3(v4,0,1,0)));
+ CHK(d3_eq(data+3, d3(v4,0,0,0)));
+ CHK(d3_eq(data+6, d3(v4,1,0,0)));
+ CHK(d3_eq(data+9, d3(v4,1,1,0)));
}
static void
@@ -178,6 +198,7 @@ test_squares(struct aw_obj* obj)
struct aw_obj_smooth_group sgroup;
struct aw_obj_vertex vertex;
struct aw_obj_vertex_data vdata;
+ const double* data = NULL;
FILE* file;
CHK(obj != NULL);
@@ -185,11 +206,14 @@ test_squares(struct aw_obj* obj)
file = fopen("test_obj_squares.obj", "w");
CHK(file != NULL);
fwrite(squares_obj, sizeof(char), strlen(squares_obj), file);
- fclose(file);
+ CHK(fclose(file) == 0);
CHK(aw_obj_load(obj, "test_obj_squares.obj") == RES_OK);
CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
CHK(desc.faces_count == 2);
+ CHK(desc.positions_count == 6);
+ CHK(desc.texcoords_count == 0);
+ CHK(desc.normals_count == 6);
CHK(desc.groups_count == 1);
CHK(desc.smooth_groups_count == 1);
CHK(desc.usemtls_count == 0);
@@ -260,6 +284,24 @@ test_squares(struct aw_obj* obj)
CHK(sgroup.faces_count == 2);
CHK(aw_obj_get_mtl(obj, 0, &mtl) == RES_BAD_ARG);
+
+ CHK(aw_obj_get_positions(obj, &data) == RES_OK);
+ CHK(d4_eq(data+0, d4(v4,0,2,0,1)));
+ CHK(d4_eq(data+4, d4(v4,0,0,0,1)));
+ CHK(d4_eq(data+8, d4(v4,2,0,0,1)));
+ CHK(d4_eq(data+12, d4(v4,2,2,0,1)));
+ CHK(d4_eq(data+16, d4(v4,4,0,-1.255298,1)));
+ CHK(d4_eq(data+20, d4(v4,4,2,-1.255298,1)));
+
+ CHK(aw_obj_get_normals(NULL, &data) == RES_BAD_ARG);
+ CHK(aw_obj_get_normals(obj, NULL) == RES_BAD_ARG);
+ CHK(aw_obj_get_normals(obj, &data) == RES_OK);
+ CHK(d3_eq(data+0, d3(v4,0,0,1)));
+ CHK(d3_eq(data+3, d3(v4,0,0,1)));
+ CHK(d3_eq(data+6, d3(v4,0.276597,0,0.960986)));
+ CHK(d3_eq(data+9, d3(v4,0.276597,0,0.960986)));
+ CHK(d3_eq(data+12, d3(v4,0.531611,0,0.846988)));
+ CHK(d3_eq(data+15, d3(v4,0.531611,0,0.846988)));
}
static void
@@ -297,6 +339,7 @@ test_cube(struct aw_obj* obj)
"usemtl purple\n"
"f 2 6 7 3\n"
"# 6 elements\n";
+ double v4[4];
const char* group_names[6] =
{ "front", "back", "right", "top", "left", "bottom" };
const char* mtl_names[6] =
@@ -304,6 +347,7 @@ test_cube(struct aw_obj* obj)
struct aw_obj_desc desc;
FILE* file;
const char* mtllib;
+ const double* data;
size_t i;
CHK(obj != NULL);
@@ -319,6 +363,9 @@ test_cube(struct aw_obj* obj)
CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
CHK(desc.faces_count == 6);
+ CHK(desc.positions_count == 8);
+ CHK(desc.texcoords_count == 0);
+ CHK(desc.normals_count == 0);
CHK(desc.groups_count == 6);
CHK(desc.smooth_groups_count == 0);
CHK(desc.usemtls_count == 6);
@@ -371,6 +418,16 @@ test_cube(struct aw_obj* obj)
CHK(!strcmp(mtllib, "my.mtl"));
CHK(aw_obj_get_mtllib(obj, 3, &mtllib) == RES_BAD_ARG);
+ CHK(aw_obj_get_positions(obj, &data) == RES_OK);
+ CHK(d4_eq(data+0, d4(v4,0,2,2,1)));
+ CHK(d4_eq(data+4, d4(v4,0,0,2,1)));
+ CHK(d4_eq(data+8, d4(v4,2,0,2,1)));
+ CHK(d4_eq(data+12, d4(v4,2,2,2,1)));
+ CHK(d4_eq(data+16, d4(v4,0,2,0,1)));
+ CHK(d4_eq(data+20, d4(v4,0,0,0,1)));
+ CHK(d4_eq(data+24, d4(v4,2,0,0,1)));
+ CHK(d4_eq(data+28, d4(v4,2,2,0,1)));
+
CHK(aw_obj_purge(NULL) == RES_BAD_ARG);
CHK(aw_obj_purge(obj) == RES_OK);
CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
@@ -380,7 +437,7 @@ test_cube(struct aw_obj* obj)
CHK(desc.usemtls_count == 0);
CHK(desc.mtllibs_count == 0);
- fclose(file);
+ CHK(fclose(file) == 0);
}
static void
@@ -433,7 +490,9 @@ test_cbox(struct aw_obj* obj)
struct aw_obj_vertex_data vdata;
struct aw_obj_named_group group;
struct aw_obj_named_group mtl;
+ double v4[4];
double tmp[3];
+ const double* data;
FILE* file;
CHK(obj != NULL);
@@ -443,10 +502,13 @@ test_cbox(struct aw_obj* obj)
fwrite(cbox_obj, sizeof(char), strlen(cbox_obj), file);
CHK(fseek(file, 0, SEEK_SET) == 0);
CHK(aw_obj_load_stream(obj, file, "cbox") == RES_OK);
- fclose(file);
+ CHK(fclose(file) == 0);
CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
CHK(desc.faces_count == 5);
+ CHK(desc.positions_count == 20);
+ CHK(desc.texcoords_count == 0);
+ CHK(desc.normals_count == 0);
CHK(desc.groups_count == 5);
CHK(desc.smooth_groups_count == 0);
CHK(desc.usemtls_count == 5);
@@ -538,6 +600,28 @@ test_cbox(struct aw_obj* obj)
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));
+
+ CHK(aw_obj_get_positions(obj, &data) == RES_OK);
+ CHK(d4_eq(data+0, d4(v4,-1.01,0,0.99,1)));
+ CHK(d4_eq(data+4, d4(v4,1,0,0.99,1)));
+ CHK(d4_eq(data+8, d4(v4,1,0,-1.04,1)));
+ CHK(d4_eq(data+12, d4(v4,-0.99,0,-1.04,1)));
+ CHK(d4_eq(data+16, d4(v4,-1.02,1.99,0.99,1)));
+ CHK(d4_eq(data+20, d4(v4,-1.02,1.99,-1.04,1)));
+ CHK(d4_eq(data+24, d4(v4,1,1.99,-1.04,1)));
+ CHK(d4_eq(data+28, d4(v4,1,1.99,0.99,1)));
+ CHK(d4_eq(data+32, d4(v4,-0.99,0,-1.04,1)));
+ CHK(d4_eq(data+36, d4(v4,1,0,-1.04,1)));
+ CHK(d4_eq(data+40, d4(v4,1,1.99,-1.04,1)));
+ CHK(d4_eq(data+44, d4(v4,-1.02,1.99,-1.04,1)));
+ CHK(d4_eq(data+48, d4(v4,1,0,-1.04,1)));
+ CHK(d4_eq(data+52, d4(v4,1,0,0.99,1)));
+ CHK(d4_eq(data+56, d4(v4,1,1.99,0.99,1)));
+ CHK(d4_eq(data+60, d4(v4,1,1.99,-1.04,1)));
+ CHK(d4_eq(data+64, d4(v4,-1.01,0,0.99,1)));
+ CHK(d4_eq(data+68, d4(v4,-0.99,0,-1.04,1)));
+ CHK(d4_eq(data+72, d4(v4,-1.02,1.99,-1.04,1)));
+ CHK(d4_eq(data+76, d4(v4,-1.02,1.99,0.99,1)));
}
int