htrdr

Solving radiative transfer in heterogeneous media
git clone git://git.meso-star.fr/htrdr.git
Log | Files | Refs | README | LICENSE

commit 4f8c845ccfbeb31a09d8b37265122a5b9dfdba35
parent 0b7802916e87eee88e6734594e9934d24e261c2f
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 26 Jul 2018 10:05:58 +0200

First try to use OpenEXR as output image format

Diffstat:
Mcmake/CMakeLists.txt | 27++++++++++++++++++++++++---
Acmake/FindOpenEXR.cmake | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/htrdr.c | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/htrdr.h | 1+
Asrc/htrdr_openexr.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/htrdr_openexr.h | 36++++++++++++++++++++++++++++++++++++
6 files changed, 315 insertions(+), 29 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -14,7 +14,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. cmake_minimum_required(VERSION 2.8) -project(htrdr C) +project(htrdr C CXX) enable_testing() set(HTRDR_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) @@ -23,6 +23,9 @@ option(NO_TEST "Do not build the tests" OFF) ################################################################################ # Check dependencies ################################################################################ +get_filename_component(_current_source_dir ${CMAKE_CURRENT_LIST_FILE} PATH) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${_current_source_dir}) + find_package(RCMake 0.3 REQUIRED) find_package(RSys 0.6 REQUIRED) find_package(Star3D 0.5 REQUIRED) @@ -33,11 +36,17 @@ find_package(StarVX REQUIRED) find_package(HTCP REQUIRED) find_package(HTMIE REQUIRED) find_package(OpenMP 1.2 REQUIRED) +find_package(OpenEXR REQUIRED) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) include(rcmake) include(rcmake_runtime) +if(CMAKE_COMPILER_IS_GNUCXX) + string(REPLACE "-fno-rtti" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) +endif() + include_directories( ${RSys_INCLUDE_DIR} ${Star3D_INCLUDE_DIR} @@ -46,7 +55,17 @@ include_directories( ${StarSP_INCLUDE_DIR} ${StarVX_INCLUDE_DIR} ${HTCP_INCLUDE_DIR} - ${HTMIE_INCLUDE_DIR}) + ${HTMIE_INCLUDE_DIR} + ${OPENEXR_INCLUDE_DIR}) + +################################################################################ +# Build the EXR static library +################################################################################ +set_source_files_properties(${HTRDR_SOURCE_DIR}/htrdr_openexr.c + PROPERTIES LANGUAGE CXX) + +add_library(htrdr_openexr STATIC ${HTRDR_SOURCE_DIR}/htrdr_openexr.c) +target_link_libraries(htrdr_openexr ${OPENEXR_LIBRARIES}) ################################################################################ # Configure and define targets @@ -79,13 +98,15 @@ set(HTRDR_FILES_INC htrdr_solve.h) set(HTDRD_FILES_DOC COPYING README.md) + # Prepend each file in the `HTRDR_FILES_<SRC|INC>' list by `HTRDR_SOURCE_DIR' rcmake_prepend_path(HTRDR_FILES_SRC ${HTRDR_SOURCE_DIR}) rcmake_prepend_path(HTRDR_FILES_INC ${HTRDR_SOURCE_DIR}) rcmake_prepend_path(HTRDR_FILES_DOC ${PROJECT_SOURCE_DIR}/../) add_executable(htrdr ${HTRDR_FILES_SRC} ${HTRDR_FILES_INC}) -target_link_libraries(htrdr HTCP HTMIE RSys Star3D Star3DAW StarSF StarSP StarVX) +target_link_libraries(htrdr HTCP HTMIE RSys Star3D Star3DAW StarSF StarSP + StarVX htrdr_openexr) if(CMAKE_COMPILER_IS_GNUCC) target_link_libraries(htrdr m) diff --git a/cmake/FindOpenEXR.cmake b/cmake/FindOpenEXR.cmake @@ -0,0 +1,99 @@ +# +# Copyright 2016 Pixar +# +# Licensed under the Apache License, Version 2.0 (the "Apache License") +# with the following modification; you may not use this file except in +# compliance with the Apache License and the following modification to it: +# Section 6. Trademarks. is deleted and replaced with: +# +# 6. Trademarks. This License does not grant permission to use the trade +# names, trademarks, service marks, or product names of the Licensor +# and its affiliates, except as required to comply with Section 4(c) of +# the License and to reproduce the content of the NOTICE file. +# +# You may obtain a copy of the Apache License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the Apache License with the above modification is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the Apache License for the specific +# language governing permissions and limitations under the Apache License. +# + +find_path(OPENEXR_INCLUDE_DIR + OpenEXR/half.h +HINTS + "${OPENEXR_LOCATION}" + "$ENV{OPENEXR_LOCATION}" +PATH_SUFFIXES + include/ +DOC + "OpenEXR headers path" +) + +if(OPENEXR_INCLUDE_DIR) + set(openexr_config_file "${OPENEXR_INCLUDE_DIR}/OpenEXR/OpenEXRConfig.h") + if(EXISTS ${openexr_config_file}) + file(STRINGS + ${openexr_config_file} + TMP + REGEX "#define OPENEXR_VERSION_STRING.*$") + string(REGEX MATCHALL "[0-9.]+" OPENEXR_VERSION ${TMP}) + + file(STRINGS + ${openexr_config_file} + TMP + REGEX "#define OPENEXR_VERSION_MAJOR.*$") + string(REGEX MATCHALL "[0-9]" OPENEXR_MAJOR_VERSION ${TMP}) + + file(STRINGS + ${openexr_config_file} + TMP + REGEX "#define OPENEXR_VERSION_MINOR.*$") + string(REGEX MATCHALL "[0-9]" OPENEXR_MINOR_VERSION ${TMP}) + endif() +endif() + +foreach(OPENEXR_LIB + Half + Iex + Imath + IlmImf + IlmThread + ) + + # OpenEXR libraries may be suffixed with the version number, so we search + # using both versioned and unversioned names. + find_library(OPENEXR_${OPENEXR_LIB}_LIBRARY + NAMES + ${OPENEXR_LIB}-${OPENEXR_MAJOR_VERSION}_${OPENEXR_MINOR_VERSION} + ${OPENEXR_LIB} + HINTS + "${OPENEXR_LOCATION}" + "$ENV{OPENEXR_LOCATION}" + PATH_SUFFIXES + lib/ + DOC + "OPENEXR's ${OPENEXR_LIB} library path" + ) + + if(OPENEXR_${OPENEXR_LIB}_LIBRARY) + list(APPEND OPENEXR_LIBRARIES ${OPENEXR_${OPENEXR_LIB}_LIBRARY}) + endif() +endforeach(OPENEXR_LIB) + +# So #include <half.h> works +list(APPEND OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR}) +list(APPEND OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR}/OpenEXR) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OpenEXR + REQUIRED_VARS + OPENEXR_INCLUDE_DIRS + OPENEXR_LIBRARIES + VERSION_VAR + OPENEXR_VERSION +) + diff --git a/src/htrdr.c b/src/htrdr.c @@ -19,6 +19,7 @@ #include "htrdr_args.h" #include "htrdr_buffer.h" #include "htrdr_camera.h" +#include "htrdr_openexr.h" #include "htrdr_sky.h" #include "htrdr_sun.h" #include "htrdr_solve.h" @@ -141,36 +142,64 @@ error: goto exit; } -static void -dump_buffer(struct htrdr_buffer* buf, FILE* output) +static res_T +dump_buffer + (struct htrdr* htrdr, + struct htrdr_buffer* buf, + const char* stream_name, + FILE* stream) { - struct htrdr_buffer_layout buf_layout; - double max_val = -DBL_MAX; + struct htrdr_buffer_layout layout; + const char* mem; + float* pixels = NULL; + size_t ipix_slice; size_t x, y; - ASSERT(buf && output); - - htrdr_buffer_get_layout(buf, &buf_layout); - ASSERT(buf_layout.elmt_size == sizeof(struct htrdr_accum)); - - fprintf(output, "P3 %lu %lu\n65535\n", - (unsigned long)buf_layout.width, - (unsigned long)buf_layout.height); - FOR_EACH(y, 0, buf_layout.height) { - FOR_EACH(x, 0, buf_layout.width) { - const struct htrdr_accum* acc = htrdr_buffer_at(buf, x, y); - const double E = acc->nweights ? acc->sum_weights/(double)acc->nweights:0; - max_val = MMAX(E, max_val); - } + res_T res = RES_OK; + ASSERT(htrdr && buf && stream_name && stream); + + htrdr_buffer_get_layout(buf, &layout); + if(layout.elmt_size != sizeof(struct htrdr_accum) + || layout.alignment < ALIGNOF(struct htrdr_accum)) { + htrdr_log_err(htrdr, + "%s: invalid buffer layout. " + "The pixel size must be the size of an accumulator.\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the slice memory */ + pixels = MEM_CALLOC + (htrdr->allocator, layout.width*layout.height, sizeof(*pixels)); + if(!pixels) { + htrdr_log_err(htrdr, + "%s: could not allocate the memory of the OpenEXR slice.\n", FUNC_NAME); + res = RES_MEM_ERR; + goto error; } - FOR_EACH(y, 0, buf_layout.height) { - FOR_EACH(x, 0, buf_layout.width) { - const struct htrdr_accum* acc = htrdr_buffer_at(buf, x, y); - const double E = acc->nweights ? acc->sum_weights/(double)acc->nweights:0; - const double En = E / (double)max_val; - const uint16_t val_ui16 = (uint16_t)(En * 65535.0 + 0.5/*round*/); - fprintf(output, "%u %u %u\n", val_ui16, val_ui16, val_ui16); + + /* Define the slice data from the buf */ + mem = (const char*)htrdr_buffer_get_data(buf); + ipix_slice = 0; + FOR_EACH(y, 0, layout.height) { + const struct htrdr_accum* row = + (const struct htrdr_accum*)(mem + y*layout.pitch); + FOR_EACH(x, 0, layout.width) { + const struct htrdr_accum* accum = row + x; + const double E = accum->nweights + ? accum->sum_weights / (double)accum->nweights + : 0; + pixels[ipix_slice] = (float)E; + fprintf(stream, "%g ", E); } + fprintf(stream, "\n"); } + +exit: + if(pixels) MEM_RM(htrdr->allocator, pixels); + return res; +error: + goto exit; } static res_T @@ -250,9 +279,11 @@ htrdr_init if(!args->output) { htrdr->output = stdout; + htrdr->output_name = "<stdout>"; } else { res = open_output_stream(htrdr, args); if(res != RES_OK) goto error; + htrdr->output_name = "todo"; } res = svx_device_create @@ -361,7 +392,7 @@ htrdr_run(struct htrdr* htrdr) time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf)); htrdr_log(htrdr, "Elapsed time: %s\n", buf); - dump_buffer(htrdr->buf, htrdr->output); + dump_buffer(htrdr, htrdr->buf, htrdr->output_name, htrdr->output); } exit: return res; diff --git a/src/htrdr.h b/src/htrdr.h @@ -50,6 +50,7 @@ struct htrdr { size_t spp; /* #samples per pixel */ FILE* output; + const char* output_name; unsigned nthreads; int dump_vtk; diff --git a/src/htrdr_openexr.c b/src/htrdr_openexr.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2018 Université Paul Sabatier, |Meso|Star> + * + * 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/>. */ + +#include "htrdr_openexr.h" + +#include <OpenEXR/Iex.h> +#include <OpenEXR/ImfChannelList.h> +#include <OpenEXR/ImfFrameBuffer.h> +#include <OpenEXR/ImfIO.h> +#include <OpenEXR/ImfOutputFile.h> + +/******************************************************************************* + * Helper class + ******************************************************************************/ +class OFStream : public Imf::OStream { +public: + OFStream(FILE* stream, const char* filename) + : OStream(filename), _stream(stream) {} + + void write(const char c[], int n) + { + if(n < 0 || fwrite(c, 1, n, _stream) != (size_t)n) { + std::stringstream s; + s << "Error writing the OpenEXR image into`" << fileName() << "'."; + + throw Iex::IoExc(s); + } + } + + Imf::Int64 tellp() + { + const long l = ftell(_stream); + if(l == -1) Iex::throwErrnoExc(); + return Imf::Int64(l); + } + + void seekp(Imf::Int64 pos) + { + const int err = fseek(_stream, long(pos), SEEK_SET); + if(err == -1) Iex::throwErrnoExc(); + } + +private: + FILE* _stream; +}; + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +htrdr_openexr_write + (const float* pixels, + const size_t width, + const size_t height, + const size_t pitch, + const char* output_name, + FILE* output) +{ + res_T res = RES_OK; + + /* Init the OpenEXR slice */ + Imf::Slice slice + (Imf::FLOAT, (char*)pixels, sizeof(*pixels), pitch); + + /* Setup the OpenEXR framebuffer */ + Imf::FrameBuffer framebuffer; + framebuffer.insert("L", slice); + + /* Define the OpenEXR header */ + Imf::Header header((int)width, (int)height); + header.channels().insert("L", Imf::FLOAT); + + /* Setup the OpenEXR output file from the submitted C stream */ + OFStream out_stream(output, output_name); + Imf::OutputFile out_file(out_stream, header); + + /* Write data */ + out_file.setFrameBuffer(framebuffer); + try { + out_file.writePixels((int)height); + } catch(...) { + res = RES_IO_ERR; + } + return res; +} + diff --git a/src/htrdr_openexr.h b/src/htrdr_openexr.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2018 Université Paul Sabatier, |Meso|Star> + * + * 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/>. */ + +#ifndef HTRDR_OPENEXR_H +#define HTRDR_OPENEXR_H + +#include <rsys/rsys.h> +#include <stdio.h> + +BEGIN_DECLS + +extern res_T +htrdr_openexr_write + (const float* pixels, + const size_t width, + const size_t height, + const size_t pitch, + const char* output_name, + FILE* output); + +END_DECLS + +#endif /* HTRDR_OPENEXR_H */ +