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:
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 */
+