diff options
-rw-r--r-- | doc/testing.txt | 66 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 123 | ||||
-rw-r--r-- | tests/FindBoost.cmake | 872 | ||||
-rw-r--r-- | tests/FindGLEW.cmake | 3 | ||||
-rw-r--r-- | tests/OffscreenContext.h | 2 | ||||
-rw-r--r-- | tests/OffscreenContext.mm | 10 | ||||
-rw-r--r-- | tests/OffscreenContextGLX.cc (renamed from tests/OffscreenContext.cc) | 63 | ||||
-rw-r--r-- | tests/OffscreenContextWGL.cc | 58 | ||||
-rw-r--r-- | tests/OffscreenView.cc | 137 | ||||
-rw-r--r-- | tests/OffscreenView.h | 4 | ||||
-rw-r--r-- | tests/cgalpngtest.cc | 3 | ||||
-rw-r--r-- | tests/csgtestcore.cc | 197 | ||||
-rw-r--r-- | tests/fbo.cc | 21 | ||||
-rw-r--r-- | tests/system-gl.cc | 39 | ||||
-rw-r--r-- | tests/system-gl.h | 3 | ||||
-rwxr-xr-x | tests/test_cmdline_tool.py | 59 | ||||
-rwxr-xr-x | tests/test_pretty_print.py | 484 | ||||
-rw-r--r-- | tests/yee_compare.cpp | 681 | ||||
-rw-r--r-- | tests/yee_compare.h | 126 |
19 files changed, 1614 insertions, 1337 deletions
diff --git a/doc/testing.txt b/doc/testing.txt index 66ceac2..403ef4a 100644 --- a/doc/testing.txt +++ b/doc/testing.txt @@ -1,7 +1,7 @@ Running regression tests: ------------------------- -Prerequisites: cmake, python +Prerequisites: cmake, python, ImageMagick 6.5.9.3 or newer A) Building test environment @@ -16,25 +16,14 @@ First, get a normal build working by following instructions at http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Building_on_Windows Then, from the QT command prompt: -$ cd tests -$ cmake . -DCMAKE_BUILD_TYPE=Release -$ sed -i s/\/MD/\/MT/ CMakeCache.txt -$ cmake . -$ nmake -f Makefile +> cd tests +> cmake . -DCMAKE_BUILD_TYPE=Release +> sed -i s/\/MD/\/MT/ CMakeCache.txt +> cmake . +> nmake -f Makefile B) Running tests -Easy version: -$ make test - -Windows: -$ nmake -f Makefile test - -Headless servers (no X11): -$ Xvnc :5 -screen 0 800x600x24 & -$ DISPLAY=:5 make test - -Partial or extended test runs: $ ctest Runs tests enabled by default $ ctest -R <regex> Runs only matching tests, e.g. ctest -R dxf $ ctest -C <configs> Adds extended tests belonging to configs. @@ -44,7 +33,6 @@ $ ctest -C <configs> Adds extended tests belonging to configs. Examples - test all examples All - test everything - Adding a new regression test: ------------------------------ @@ -59,20 +47,44 @@ Adding a new regression test: 7) run the test normally and verify that it passes: $ ctest -R mytest -Troubleshooting a failed test: +Troubleshooting: ------------------------------ -You can run a single test by passing the test name to ctest: - $ ctest -R throwntogethertest_sphere +0. Headless unix servers (no X11) + +$ Xvfb :5 -screen 0 800x600x24 & +$ DISPLAY=:5 ctest + +1. Trouble finding libraries -You can run a series of tests by passing part of a name to ctest: - $ ctest -R cgalpng # runs all cgalpng tests - $ ctest -R sphere # runs all sphere tests - + To help CMAKE find eigen2, OpenCSG, CGAL, Boost, and GLEW, you can use + the -D option. See CMakeLists.txt for more information. Examples: + + cmake . -DOPENCSG_DIR=~/OpenCSG-1.3.2 + cmake . -DCGAL_DIR=c:\CGAL-3.7 -DBOOST_DIR=c:\boost_1_46_0 + +2. Logs + Logs of test runs are found in tests/build/Testing/Temporary +Pretty-printed html output is in a subdir of tests/build/Testing/Temporary Expected results are found in tests/regression/* Actual results are found in tests/build/testname-output/* -You can also compile a single test program: +3. Cross-compiling + +Cross-compiling of tests has not been automated nor tested + +4. Testing images takes forever, they fail, and it says 'return -11' + +Imagemagick may have crashed. You can try using the alternate comparison +based on Normalized Cross Correlation. Pass -DCOMPARATOR=ncc to cmake + +5. Testing images fails with 'morphology' not found for ImageMagick + +Your version of imagemagick is old. Upgrade, or pass -DCOMPARATOR=old to cmake. +The comparison will be of lowered reliability. + +6. Many cgalpngtests are failing with weird assertion errors. + +Edit CMakeCache.txt and replace '-DNDEBUG' or '/D NDEBUG' with blank spaces - $ make cgalpngtest diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a2e3c34..585c3b1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,11 +27,7 @@ endif() if(WIN32_STATIC_BUILD) if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") - set(EMSG "\nTo build Win32 STATIC OpenSCAD tests you must run") - set(EMSG "${EMSG} \ncmake .. -DCMAKE_BUILD_TYPE=Release") - set(EMSG "${EMSG} \nthen replace /MD with /MT in CMakeCache.txt") - set(EMSG "${EMSG} \ni.e. sed -i s/\\/MD/\\/MT/ CMakeCache.txt") - set(EMSG "${EMSG} \nthen re-run cmake ..") + set(EMSG "\nTo build Win32 STATIC OpenSCAD please see doc/testing.txt") message(FATAL_ERROR ${EMSG}) endif() endif() @@ -75,24 +71,36 @@ if (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "") set(BOOST_ROOT "$ENV{MACOSX_DEPLOY_DIR}") endif() -if(BOOST_ROOT) - #set(Boost_DEBUG TRUE) - set(Boost_NO_SYSTEM_PATHS TRUE) - set(Boost_ADDITIONAL_VERSIONS "1.47.0") - find_package( Boost 1.35.0 COMPONENTS thread program_options ) - if(Boost_FOUND) - message(STATUS "Boost includes found: " ${Boost_INCLUDE_DIRS}) - message(STATUS "Boost libraries found:") - foreach(boostlib ${Boost_LIBRARIES}) - message(STATUS " " ${boostlib}) - endforeach() - include_directories(${Boost_INCLUDE_DIRS}) - else() - message(STATUS "BOOST_ROOT:" ${BOOST_ROOT}) - message(FATAL_ERROR "BOOST_ROOT specified but no boost found") - endif() +if (NOT $ENV{BOOST_DIR} STREQUAL "") + set(BOOST_DIR "$ENV{BOOST_DIR}") +endif() + +if (NOT ${BOOST_DIR} STREQUAL "") + set(BOOST_ROOT ${BOOST_DIR}) + message(STATUS "BOOST_ROOT: " ${BOOST_ROOT}) + set(Boost_NO_SYSTEM_PATHS "TRUE") + set(Boost_DEBUG TRUE) +endif() + + +if (WIN32) + set(Boost_USE_STATIC_LIBS TRUE) + set(BOOST_STATIC TRUE) + set(BOOST_THREAD_USE_LIB TRUE) +endif() + +set(Boost_ADDITIONAL_VERSIONS "1.47.0" "1.46.0") +find_package( Boost 1.35.0 COMPONENTS thread program_options ) +if(Boost_FOUND) + message(STATUS "Boost includes found: " ${Boost_INCLUDE_DIRS}) + message(STATUS "Boost libraries found:") + foreach(boostlib ${Boost_LIBRARIES}) + message(STATUS " " ${boostlib}) + endforeach() + include_directories(${Boost_INCLUDE_DIRS}) else() - message(STATUS "BOOST_ROOT unset. Assuming it will be found automatically.") + message(STATUS "BOOST_ROOT: ${BOOST_ROOT}") + message(FATAL_ERROR "Boost not found.") endif() # Mac OS X @@ -141,10 +149,10 @@ if (NOT OPENCSG_INCLUDE_DIR) message(STATUS "OPENCSG_DIR: " ${OPENCSG_DIR}) find_path(OPENCSG_INCLUDE_DIR opencsg.h - PATHS ${OPENCSG_DIR}/include) + HINTS ${OPENCSG_DIR}/include) find_library(OPENCSG_LIBRARY opencsg - PATHS ${OPENCSG_DIR}/lib) + HINTS ${OPENCSG_DIR}/lib) if (NOT OPENCSG_INCLUDE_DIR OR NOT OPENCSG_LIBRARY) message(FATAL_ERROR "OpenCSG not found") else() @@ -156,7 +164,9 @@ include_directories(${OPENCSG_INCLUDE_DIR}) # GLEW -if (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "") +if (NOT $ENV{GLEW_DIR} STREQUAL "") + set(GLEW_DIR "$ENV{GLEW_DIR}") +elseif (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "") set(GLEW_DIR "$ENV{MACOSX_DEPLOY_DIR}") endif() @@ -185,16 +195,35 @@ BISON_TARGET(OpenSCADparser ../src/parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser_y ADD_FLEX_BISON_DEPENDENCY(OpenSCADlexer OpenSCADparser) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser_yacc.c PROPERTIES LANGUAGE "CXX") -if (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "") +# CGAL + +if (NOT $ENV{CGAL_DIR} STREQUAL "") + set(CGAL_DIR "$ENV{CGAL_DIR}") +elseif (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "") set(CGAL_DIR "$ENV{MACOSX_DEPLOY_DIR}/lib/CGAL") set(CMAKE_MODULE_PATH "${CGAL_DIR}") endif() +message(STATUS "CGAL_DIR: " ${CGAL_DIR}) find_package(CGAL REQUIRED) +message(STATUS "CGAL config found in " ${CGAL_USE_FILE} ) +foreach(cgal_incdir ${CGAL_INCLUDE_DIRS}) + message(STATUS "CGAL include found in " ${cgal_incdir} ) +endforeach() +message(STATUS "CGAL libraries found in " ${CGAL_LIBRARIES_DIR} ) if("${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}" VERSION_LESS 3.6) message(FATAL_ERROR "CGAL >= 3.6 required") endif() include_directories(${CGAL_INCLUDE_DIRS}) +# Imagemagick + +find_package(ImageMagick COMPONENTS convert) +if (ImageMagick_convert_FOUND) + message(STATUS "ImageMagick convert executable found: " ${ImageMagick_convert_EXECUTABLE}) +else() + message(FATAL_ERROR "Couldn't find imagemagick 'convert' program") +endif() + # Internal includes include_directories(../src) @@ -239,7 +268,7 @@ set(NOCGAL_SOURCES set(CGAL_SOURCES ${NOCGAL_SOURCES} - ../src/CSGTermEvaluator.cc + ../src/CSGTermEvaluator.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc ../src/CGALEvaluator.cc @@ -261,13 +290,13 @@ set(COMMON_SOURCES # if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") message(STATUS "Offscreen OpenGL Context - using Apple CGL") - set(OFFSCREEN_CTX_SOURCE "OffscreenContext.mm") + set(OFFSCREEN_CTX_SOURCE "OffscreenContext.mm" CACHE TYPE STRING) elseif(UNIX) message(STATUS "Offscreen OpenGL Context - using Unix GLX") - set(OFFSCREEN_CTX_SOURCE "OffscreenContext.cc") + set(OFFSCREEN_CTX_SOURCE "OffscreenContextGLX.cc" CACHE TYPE STRING) elseif(WIN32) message(STATUS "Offscreen OpenGL Context - using Microsoft WGL") - set(OFFSCREEN_CTX_SOURCE "OffscreenContextWGL.cc") + set(OFFSCREEN_CTX_SOURCE "OffscreenContextWGL.cc" CACHE TYPE STRING) endif() set(OFFSCREEN_SOURCES @@ -286,6 +315,7 @@ target_link_libraries(tests-cgal tests-common) add_library(tests-nocgal STATIC ${NOCGAL_SOURCES}) target_link_libraries(tests-nocgal tests-common) add_library(tests-offscreen STATIC ${OFFSCREEN_SOURCES}) +# set_target_properties(tests-offscreen PROPERTIES COMPILE_FLAGS "-DENABLE_OPENCSG -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}") # # echotest @@ -294,11 +324,6 @@ add_executable(echotest echotest.cc) target_link_libraries(echotest tests-nocgal tests-core ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES}) # -# Yangli Hector Yee's PerceptualDiff code -# FIXME: Disabled since we use ImageMagick now. Eventually remove this and the files. -# add_executable(yee_compare yee_compare.cpp lodepng.cpp) - -# # dumptest # add_executable(dumptest dumptest.cc) @@ -406,6 +431,12 @@ function(get_test_fullname TESTCMD FILENAME FULLNAME) set(${FULLNAME} ${${FULLNAME}} PARENT_SCOPE) endfunction() +# comparison method to use +if (NOT $ENV{COMPARATOR} STREQUAL "") + set(COMPARATOR "$ENV{COMPARATOR}") +endif() +message(STATUS "COMPARATOR: " ${COMPARATOR}) + # # This functions adds cmd-line tests given files. # Files are sent as the parameters following TESTSUFFIX @@ -436,13 +467,30 @@ macro(add_cmdline_test TESTCMD TESTSUFFIX) set(CONFARG CONFIGURATIONS) set(CONFVAL ${FOUNDCONFIGS}) - add_test(NAME ${TEST_FULLNAME} ${CONFARG} ${CONFVAL} COMMAND ${PYTHON_EXECUTABLE} ${tests_SOURCE_DIR}/test_cmdline_tool.py -s ${TESTSUFFIX} ${CMAKE_BINARY_DIR}/${TESTCMD} "${SCADFILE}") + add_test(NAME ${TEST_FULLNAME} ${CONFARG} ${CONFVAL} COMMAND ${PYTHON_EXECUTABLE} ${tests_SOURCE_DIR}/test_cmdline_tool.py --comparator=${COMPARATOR} -c ${ImageMagick_convert_EXECUTABLE} -s ${TESTSUFFIX} ${CMAKE_BINARY_DIR}/${TESTCMD} "${SCADFILE}") endif() endforeach() endmacro() enable_testing() +# set up custom pretty printing of results + +set(INFOCMD "execute_process(COMMAND ${CMAKE_CURRENT_BINARY_DIR}/opencsgtest --info OUTPUT_FILE sysinfo.txt)") +set(PRETTYCMD "\"${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_pretty_print.py --builddir=${CMAKE_CURRENT_BINARY_DIR}\"") +set(CTEST_CUSTOM_FILE ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake) +set(CTEST_CUSTOM_TXT "\n + message(\"running 'opencsgtest --info' to generate sysinfo.txt\")\n + ${INFOCMD}\n + set(CTEST_CUSTOM_POST_TEST ${PRETTYCMD})\n +") +file(WRITE ${CTEST_CUSTOM_FILE} ${CTEST_CUSTOM_TXT}) + +foreach(FILE test_pretty_print.py) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${FILE} + ${CMAKE_CURRENT_BINARY_DIR}/${FILE} COPYONLY) +endforeach() + set_directory_properties(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_SOURCE_DIR}/EnforceConfig.cmake") # Find all scad files @@ -492,6 +540,9 @@ disable_tests(dumptest_transform-tests # Reenable it when this is improved disable_tests(opencsgtest_child-background) +# FIXME: This single test takes over an hour to run on a 2.7 GHz P4 +disable_tests(opencsgtest_example006 cgalpngtest_example006) + # These tests only makes sense in OpenCSG mode disable_tests(cgalpngtest_child-background cgalpngtest_highlight-and-background-modifier diff --git a/tests/FindBoost.cmake b/tests/FindBoost.cmake index dfaf660..ea60354 100644 --- a/tests/FindBoost.cmake +++ b/tests/FindBoost.cmake @@ -17,8 +17,9 @@ # # == Using actual libraries from within Boost: == # -# set(Boost_USE_STATIC_LIBS ON) -# set(Boost_USE_MULTITHREADED ON) +# set(Boost_USE_STATIC_LIBS ON) +# set(Boost_USE_MULTITHREADED ON) +# set(Boost_USE_STATIC_RUNTIME OFF) # find_package( Boost 1.36.0 COMPONENTS date_time filesystem system ... ) # # if(Boost_FOUND) @@ -33,7 +34,7 @@ # Boost that contain header files only (e.g. foreach) you do not need to # specify COMPONENTS. # -# You should provide a minimum version number that should be used. If you provide this +# You should provide a minimum version number that should be used. If you provide this # version number and specify the REQUIRED attribute, this module will fail if it # can't find the specified or a later version. If you specify a version number this is # automatically put into the considered list of version numbers and thus doesn't need @@ -63,14 +64,15 @@ # Currently this module searches for the following version numbers: # 1.33, 1.33.0, 1.33.1, 1.34, 1.34.0, 1.34.1, 1.35, 1.35.0, 1.35.1, # 1.36, 1.36.0, 1.36.1, 1.37, 1.37.0, 1.38, 1.38.0, 1.39, 1.39.0, -# 1.40, 1.40.0, 1.41, 1.41.0 +# 1.40, 1.40.0, 1.41, 1.41.0, 1.42, 1.42.0, 1.43, 1.43.0, 1.44, 1.44.0, +# 1.45, 1.45.0, 1.46, 1.46.0, 1.46.1, 1.47, 1.47.0, 1.48, 1.48.0 # # NOTE: If you add a new major 1.x version in Boost_ADDITIONAL_VERSIONS you should # add both 1.x and 1.x.0 as shown above. Official Boost include directories # omit the 3rd version number from include paths if it is 0 although not all # binary Boost releases do so. # -# SET(Boost_ADDITIONAL_VERSIONS "1.78" "1.78.0" "1.79" "1.79.0") +# set(Boost_ADDITIONAL_VERSIONS "1.78" "1.78.0" "1.79" "1.79.0") # # ===================================== ============= ======================== # @@ -84,6 +86,43 @@ # Boost_USE_STATIC_LIBS Can be set to ON to force the use of the static # boost libraries. Defaults to OFF. # +# Boost_NO_SYSTEM_PATHS Set to TRUE to suppress searching in system +# paths (or other locations outside of BOOST_ROOT +# or BOOST_INCLUDEDIR). Useful when specifying +# BOOST_ROOT. Defaults to OFF. +# [Since CMake 2.8.3] +# +# Boost_NO_BOOST_CMAKE Do not do a find_package call in config mode +# before searching for a regular boost install. +# This will avoid finding boost-cmake installs. +# Defaults to OFF. +# [Since CMake 2.8.6] +# +# Boost_USE_STATIC_RUNTIME If enabled, searches for boost libraries +# linked against a static C++ standard library +# ('s' ABI tag). This option should be set to +# ON or OFF because the default behavior +# if not specified is platform dependent +# for backwards compatibility. +# [Since CMake 2.8.3] +# +# Boost_USE_DEBUG_PYTHON If enabled, searches for boost libraries +# compiled against a special debug build of +# Python ('y' ABI tag). Defaults to OFF. +# [Since CMake 2.8.3] +# +# Boost_USE_STLPORT If enabled, searches for boost libraries +# compiled against the STLPort standard +# library ('p' ABI tag). Defaults to OFF. +# [Since CMake 2.8.3] +# +# Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS +# If enabled, searches for boost libraries +# compiled against the deprecated STLPort +# "native iostreams" feature ('n' ABI tag). +# Defaults to OFF. +# [Since CMake 2.8.3] +# # Other Variables used by this module which you may want to set. # # Boost_ADDITIONAL_VERSIONS A list of version numbers to use for searching @@ -101,17 +140,58 @@ # unless this is set to TRUE or the REQUIRED # keyword is specified in find_package(). # [Since CMake 2.8.0] -# +# # Boost_COMPILER Set this to the compiler suffix used by Boost # (e.g. "-gcc43") if FindBoost has problems finding # the proper Boost installation # +# Boost_THREADAPI When building boost.thread, sometimes the name of the +# library contains an additional "pthread" or "win32" +# string known as the threadapi. This can happen when +# compiling against pthreads on Windows or win32 threads +# on Cygwin. You may specify this variable and if set +# when FindBoost searches for the Boost threading library +# it will first try to match the threadapi you specify. +# For Example: libboost_thread_win32-mgw45-mt-1_43.a +# might be found if you specified "win32" here before +# falling back on libboost_thread-mgw45-mt-1_43.a. +# [Since CMake 2.8.3] +# +# Boost_REALPATH Resolves symbolic links for discovered boost libraries +# to assist with packaging. For example, instead of +# Boost_SYSTEM_LIBRARY_RELEASE being resolved to +# "/usr/lib/libboost_system.so" it would be +# "/usr/lib/libboost_system.so.1.42.0" instead. +# This does not affect linking and should not be +# enabled unless the user needs this information. +# [Since CMake 2.8.3] +# + + +# # These last three variables are available also as environment variables: +# Also, note they are completely UPPERCASE, except Boost_DIR. # -# BOOST_ROOT or BOOSTROOT The preferred installation prefix for searching for -# Boost. Set this if the module has problems finding +# Boost_DIR or The preferred installation prefix for searching for +# BOOST_ROOT or BOOSTROOT Boost. Set this if the module has problems finding # the proper Boost installation. # +# Note that Boost_DIR behaves exactly as <package>_DIR +# variables are documented to behave in find_package's +# Config mode. That is, if it is set as a -D argument +# to CMake, it must point to the location of the +# BoostConfig.cmake or Boost-config.cmake file. If it +# is set as an environment variable, it must point to +# the root of the boost installation. BOOST_ROOT and +# BOOSTROOT, on the other hand, will point to the root +# in either case. +# +# To prevent falling back on the system paths, set +# Boost_NO_SYSTEM_PATHS to true. +# +# To avoid finding boost-cmake installations, set +# Boost_NO_BOOST_CMAKE to true. +# # BOOST_INCLUDEDIR Set this to the include directory of Boost, if the # module has problems finding the proper Boost installation # @@ -165,7 +245,7 @@ # Copyright 2007 Wengo # Copyright 2007 Mike Jackson # Copyright 2008 Andreas Pakulat <apaku@gmx.de> -# Copyright 2008-2009 Philip Lowman <philip@yhbt.com> +# Copyright 2008-2010 Philip Lowman <philip@yhbt.com> # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. @@ -174,9 +254,46 @@ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= -# (To distributed this file outside of CMake, substitute the full +# (To distribute this file outside of CMake, substitute the full # License text for the above reference.) + +#------------------------------------------------------------------------------- +# Before we go searching, check whether boost-cmake is avaialble, unless the +# user specifically asked NOT to search for boost-cmake. +# +# If Boost_DIR is set, this behaves as any find_package call would. If not, +# it looks at BOOST_ROOT and BOOSTROOT to find Boost. +# +if (NOT Boost_NO_BOOST_CMAKE) + # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives, + # since these are more conventional for Boost. + if ("$ENV{Boost_DIR}" STREQUAL "") + if (NOT "$ENV{BOOST_ROOT}" STREQUAL "") + set(ENV{Boost_DIR} $ENV{BOOST_ROOT}) + elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "") + set(ENV{Boost_DIR} $ENV{BOOSTROOT}) + endif() + endif() + + # Do the same find_package call but look specifically for the CMake version. + # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no + # need to delegate them to this find_package call. + find_package(Boost QUIET NO_MODULE) + + # If we found boost-cmake, then we're done. Print out what we found. + # Otherwise let the rest of the module try to find it. + if (Boost_FOUND) + message("Boost ${Boost_FIND_VERSION} found.") + if (Boost_FIND_COMPONENTS) + message("Found Boost components:") + message(" ${Boost_FIND_COMPONENTS}") + endif() + return() + endif() +endif() + + #------------------------------------------------------------------------------- # FindBoost functions & macros # @@ -192,59 +309,65 @@ # And ELSE/ENDIF pairs were removed for readability. ######################################################################### -MACRO (_Boost_ADJUST_LIB_VARS basename) - IF (Boost_INCLUDE_DIR ) - IF (Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) +macro(_Boost_ADJUST_LIB_VARS basename) + if(Boost_INCLUDE_DIR ) + if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) # if the generator supports configuration types then set # optimized and debug libraries, or if the CMAKE_BUILD_TYPE has a value - IF (CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) - SET(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) - ELSE() + if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) + set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) + else() # if there are no configuration types and CMAKE_BUILD_TYPE has no value # then just use the release libraries - SET(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) - ENDIF() + set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) + endif() # FIXME: This probably should be set for both cases - SET(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) - ENDIF() + set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) + endif() # if only the release version was found, set the debug variable also to the release version - IF (Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) - SET(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) - SET(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) - SET(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) - ENDIF() + if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) + set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) + set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) + set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) + endif() # if only the debug version was found, set the release variable also to the debug version - IF (Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) - SET(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) - SET(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) - SET(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) - ENDIF() - - IF (Boost_${basename}_LIBRARY) + if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) + set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) + set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) + set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) + endif() + + # If the debug & release library ends up being the same, omit the keywords + if(${Boost_${basename}_LIBRARY_RELEASE} STREQUAL ${Boost_${basename}_LIBRARY_DEBUG}) + set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) + set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} ) + endif() + + if(Boost_${basename}_LIBRARY) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY} CACHE FILEPATH "The Boost ${basename} library") # Remove superfluous "debug" / "optimized" keywords from # Boost_LIBRARY_DIRS - FOREACH(_boost_my_lib ${Boost_${basename}_LIBRARY}) - GET_FILENAME_COMPONENT(_boost_my_lib_path "${_boost_my_lib}" PATH) - LIST(APPEND Boost_LIBRARY_DIRS ${_boost_my_lib_path}) - ENDFOREACH() - LIST(REMOVE_DUPLICATES Boost_LIBRARY_DIRS) + foreach(_boost_my_lib ${Boost_${basename}_LIBRARY}) + get_filename_component(_boost_my_lib_path "${_boost_my_lib}" PATH) + list(APPEND Boost_LIBRARY_DIRS ${_boost_my_lib_path}) + endforeach() + list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS) set(Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIRS} CACHE FILEPATH "Boost library directory") - SET(Boost_${basename}_FOUND ON CACHE INTERNAL "Whether the Boost ${basename} library found") - ENDIF(Boost_${basename}_LIBRARY) + set(Boost_${basename}_FOUND ON CACHE INTERNAL "Whether the Boost ${basename} library found") + endif(Boost_${basename}_LIBRARY) - ENDIF (Boost_INCLUDE_DIR ) + endif(Boost_INCLUDE_DIR ) # Make variables changeble to the advanced user - MARK_AS_ADVANCED( + mark_as_advanced( Boost_${basename}_LIBRARY Boost_${basename}_LIBRARY_RELEASE Boost_${basename}_LIBRARY_DEBUG ) -ENDMACRO (_Boost_ADJUST_LIB_VARS) +endmacro(_Boost_ADJUST_LIB_VARS) #------------------------------------------------------------------------------- @@ -252,17 +375,17 @@ ENDMACRO (_Boost_ADJUST_LIB_VARS) # Runs compiler with "-dumpversion" and parses major/minor # version with a regex. # -FUNCTION(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION) +function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION) - EXEC_PROGRAM(${CMAKE_CXX_COMPILER} + exec_program(${CMAKE_CXX_COMPILER} ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion OUTPUT_VARIABLE _boost_COMPILER_VERSION ) - STRING(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" + string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" _boost_COMPILER_VERSION ${_boost_COMPILER_VERSION}) - SET(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) -ENDFUNCTION() + set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) +endfunction() # # A convenience function for marking desired components @@ -276,16 +399,45 @@ function(_Boost_MARK_COMPONENTS_FOUND _yes_or_no) endfunction() # +# Take a list of libraries with "thread" in it +# and prepend duplicates with "thread_${Boost_THREADAPI}" +# at the front of the list +# +function(_Boost_PREPEND_LIST_WITH_THREADAPI _output) + set(_orig_libnames ${ARGN}) + string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames ${_orig_libnames}) + set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE) +endfunction() + +# +# If a library is found, replace its cache entry with its REALPATH +# +function(_Boost_SWAP_WITH_REALPATH _library _docstring) + if(${_library}) + get_filename_component(_boost_filepathreal ${${_library}} REALPATH) + unset(${_library} CACHE) + set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}") + endif() +endfunction() + +function(_Boost_CHECK_SPELLING _var) + if(${_var}) + string(TOUPPER ${_var} _var_UC) + message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.") + endif() +endfunction() + +# # End functions/macros -# +# #------------------------------------------------------------------------------- -IF(NOT DEFINED Boost_USE_MULTITHREADED) - SET(Boost_USE_MULTITHREADED TRUE) -ENDIF() +if(NOT DEFINED Boost_USE_MULTITHREADED) + set(Boost_USE_MULTITHREADED TRUE) +endif() if(Boost_FIND_VERSION_EXACT) # The version may appear in a directory with or without the patch @@ -297,6 +449,8 @@ else(Boost_FIND_VERSION_EXACT) # The user has not requested an exact version. Among known # versions, find those that are acceptable to the user request. set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} + "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1" + "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42" "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37" "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" "1.34" "1.33.1" "1.33.0" "1.33") @@ -325,49 +479,47 @@ endif(Boost_FIND_VERSION_EXACT) # Boost. set(Boost_ERROR_REASON) -SET( _boost_IN_CACHE TRUE) -IF(Boost_INCLUDE_DIR) +set( _boost_IN_CACHE TRUE) +if(Boost_INCLUDE_DIR) # On versions < 1.35, remove the System library from the considered list # since it wasn't added until 1.35. if(Boost_VERSION AND Boost_FIND_COMPONENTS) - math(EXPR _boost_maj "${Boost_VERSION} / 100000") - math(EXPR _boost_min "${Boost_VERSION} / 100 % 1000") - if(${_boost_maj}.${_boost_min} VERSION_LESS 1.35) + if(Boost_VERSION LESS 103500) list(REMOVE_ITEM Boost_FIND_COMPONENTS system) endif() endif() - FOREACH(COMPONENT ${Boost_FIND_COMPONENTS}) - STRING(TOUPPER ${COMPONENT} COMPONENT) - IF(NOT Boost_${COMPONENT}_FOUND) - SET( _boost_IN_CACHE FALSE) - ENDIF(NOT Boost_${COMPONENT}_FOUND) - ENDFOREACH(COMPONENT) -ELSE(Boost_INCLUDE_DIR) - SET( _boost_IN_CACHE FALSE) -ENDIF(Boost_INCLUDE_DIR) - -IF (_boost_IN_CACHE) + foreach(COMPONENT ${Boost_FIND_COMPONENTS}) + string(TOUPPER ${COMPONENT} COMPONENT) + if(NOT Boost_${COMPONENT}_FOUND) + set( _boost_IN_CACHE FALSE) + endif(NOT Boost_${COMPONENT}_FOUND) + endforeach(COMPONENT) +else(Boost_INCLUDE_DIR) + set( _boost_IN_CACHE FALSE) +endif(Boost_INCLUDE_DIR) + +if(_boost_IN_CACHE) # in cache already - SET(Boost_FOUND TRUE) - FOREACH(COMPONENT ${Boost_FIND_COMPONENTS}) - STRING(TOUPPER ${COMPONENT} COMPONENT) + set(Boost_FOUND TRUE) + foreach(COMPONENT ${Boost_FIND_COMPONENTS}) + string(TOUPPER ${COMPONENT} COMPONENT) _Boost_ADJUST_LIB_VARS( ${COMPONENT} ) - SET(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${COMPONENT}_LIBRARY}) - ENDFOREACH(COMPONENT) - SET(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) - IF(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") - MATH(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") - MATH(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") - MATH(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") - ENDIF(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") + set(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${COMPONENT}_LIBRARY}) + endforeach(COMPONENT) + set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) + if(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") + math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") + math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") + math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") + endif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "boost ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION} " - "is already in the cache. For debugging messages, please clear the cache.") + "is already in the cache. To view debugging messages, please clear the cache.") endif() -ELSE (_boost_IN_CACHE) +else(_boost_IN_CACHE) # Need to search for boost if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " @@ -379,9 +531,15 @@ ELSE (_boost_IN_CACHE) "Boost_USE_MULTITHREADED = ${Boost_USE_MULTITHREADED}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_STATIC_LIBS = ${Boost_USE_STATIC_LIBS}") + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "Boost_USE_STATIC_RUNTIME = ${Boost_USE_STATIC_RUNTIME}") + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "Boost_ADDITIONAL_VERSIONS = ${Boost_ADDITIONAL_VERSIONS}") + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}") endif() - IF(WIN32) + if(WIN32) # In windows, automatic linking is performed, so you do not have # to specify the libraries. If you are linking to a dynamic # runtime, then you can choose to link to either a static or a @@ -390,20 +548,20 @@ ELSE (_boost_IN_CACHE) # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be # linked dynamically. Alternatively you can force all Boost # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. - + # This feature can be disabled for Boost library "whatever" by # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining # BOOST_ALL_NO_LIB. - + # If you want to observe which libraries are being linked against # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking # code to emit a #pragma message each time a library is selected # for linking. - SET(Boost_LIB_DIAGNOSTIC_DEFINITIONS + set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC" CACHE STRING "Boost diagnostic define") - ENDIF(WIN32) + endif(WIN32) - SET(_boost_INCLUDE_SEARCH_DIRS + set(_boost_INCLUDE_SEARCH_DIRS_SYSTEM C:/boost/include C:/boost "$ENV{ProgramFiles}/boost/include" @@ -411,29 +569,38 @@ ELSE (_boost_IN_CACHE) /sw/local/include ) + _Boost_CHECK_SPELLING(Boost_ROOT) + _Boost_CHECK_SPELLING(Boost_LIBRARYDIR) + _Boost_CHECK_SPELLING(Boost_INCLUDEDIR) + + # If BOOST_ROOT was defined in the environment, use it. + if (NOT BOOST_ROOT AND NOT $ENV{Boost_DIR} STREQUAL "") + set(BOOST_ROOT $ENV{Boost_DIR}) + endif() + # If BOOST_ROOT was defined in the environment, use it. if (NOT BOOST_ROOT AND NOT $ENV{BOOST_ROOT} STREQUAL "") set(BOOST_ROOT $ENV{BOOST_ROOT}) - endif(NOT BOOST_ROOT AND NOT $ENV{BOOST_ROOT} STREQUAL "") + endif() # If BOOSTROOT was defined in the environment, use it. if (NOT BOOST_ROOT AND NOT $ENV{BOOSTROOT} STREQUAL "") set(BOOST_ROOT $ENV{BOOSTROOT}) - endif(NOT BOOST_ROOT AND NOT $ENV{BOOSTROOT} STREQUAL "") + endif() # If BOOST_INCLUDEDIR was defined in the environment, use it. - IF( NOT $ENV{BOOST_INCLUDEDIR} STREQUAL "" ) + if( NOT $ENV{BOOST_INCLUDEDIR} STREQUAL "" ) set(BOOST_INCLUDEDIR $ENV{BOOST_INCLUDEDIR}) - ENDIF( NOT $ENV{BOOST_INCLUDEDIR} STREQUAL "" ) - + endif() + # If BOOST_LIBRARYDIR was defined in the environment, use it. - IF( NOT $ENV{BOOST_LIBRARYDIR} STREQUAL "" ) + if( NOT $ENV{BOOST_LIBRARYDIR} STREQUAL "" ) set(BOOST_LIBRARYDIR $ENV{BOOST_LIBRARYDIR}) - ENDIF( NOT $ENV{BOOST_LIBRARYDIR} STREQUAL "" ) - - IF( BOOST_ROOT ) + endif() + + if( BOOST_ROOT ) file(TO_CMAKE_PATH ${BOOST_ROOT} BOOST_ROOT) - ENDIF( BOOST_ROOT ) + endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " @@ -448,50 +615,54 @@ ELSE (_boost_IN_CACHE) "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") endif() - IF( BOOST_ROOT ) - SET(_boost_INCLUDE_SEARCH_DIRS - ${BOOST_ROOT}/include + if( Boost_NO_SYSTEM_PATHS) + set(_boost_FIND_OPTIONS NO_CMAKE_SYSTEM_PATH) + else() + set(_boost_INCLUDE_SEARCH_DIRS ${_boost_INCLUDE_SEARCH_DIRS_SYSTEM}) + endif() + + if( BOOST_ROOT ) + set(_boost_INCLUDE_SEARCH_DIRS + ${BOOST_ROOT}/include ${BOOST_ROOT} ${_boost_INCLUDE_SEARCH_DIRS}) - ENDIF( BOOST_ROOT ) + endif() - IF( BOOST_INCLUDEDIR ) + # prepend BOOST_INCLUDEDIR to search path if specified + if( BOOST_INCLUDEDIR ) file(TO_CMAKE_PATH ${BOOST_INCLUDEDIR} BOOST_INCLUDEDIR) - SET(_boost_INCLUDE_SEARCH_DIRS + set(_boost_INCLUDE_SEARCH_DIRS ${BOOST_INCLUDEDIR} ${_boost_INCLUDE_SEARCH_DIRS}) - ENDIF( BOOST_INCLUDEDIR ) + endif( BOOST_INCLUDEDIR ) # ------------------------------------------------------------------------ - # Search for Boost include DIR + # Search for Boost include DIR # ------------------------------------------------------------------------ # Try to find Boost by stepping backwards through the Boost versions # we know about. - IF( NOT Boost_INCLUDE_DIR ) + if( NOT Boost_INCLUDE_DIR ) # Build a list of path suffixes for each version. - SET(_boost_PATH_SUFFIXES) - FOREACH(_boost_VER ${_boost_TEST_VERSIONS}) + set(_boost_PATH_SUFFIXES) + foreach(_boost_VER ${_boost_TEST_VERSIONS}) # Add in a path suffix, based on the required version, ideally # we could read this from version.hpp, but for that to work we'd # need to know the include dir already set(_boost_BOOSTIFIED_VERSION) # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 - IF(_boost_VER MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") - STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1_\\2_\\3" + if(_boost_VER MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1_\\2_\\3" _boost_BOOSTIFIED_VERSION ${_boost_VER}) - ELSEIF(_boost_VER MATCHES "[0-9]+\\.[0-9]+") - STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1_\\2" + elseif(_boost_VER MATCHES "[0-9]+\\.[0-9]+") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1_\\2" _boost_BOOSTIFIED_VERSION ${_boost_VER}) - ENDIF() - - list(APPEND _boost_PATH_SUFFIXES "boost-${_boost_BOOSTIFIED_VERSION}") - if(WIN32) - # For BoostPro's underscores (and others?) - list(APPEND _boost_PATH_SUFFIXES "boost_${_boost_BOOSTIFIED_VERSION}") endif() - ENDFOREACH(_boost_VER) - + list(APPEND _boost_PATH_SUFFIXES "boost-${_boost_BOOSTIFIED_VERSION}") + list(APPEND _boost_PATH_SUFFIXES "boost_${_boost_BOOSTIFIED_VERSION}") + + endforeach(_boost_VER) + if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Include debugging info:") @@ -502,61 +673,62 @@ ELSE (_boost_IN_CACHE) endif() # Look for a standard boost header file. - FIND_PATH(Boost_INCLUDE_DIR + find_path(Boost_INCLUDE_DIR NAMES boost/config.hpp HINTS ${_boost_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${_boost_PATH_SUFFIXES} + ${_boost_FIND_OPTIONS} ) - ENDIF( NOT Boost_INCLUDE_DIR ) - + endif( NOT Boost_INCLUDE_DIR ) + # ------------------------------------------------------------------------ # Extract version information from version.hpp # ------------------------------------------------------------------------ - IF(Boost_INCLUDE_DIR) + if(Boost_INCLUDE_DIR) # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp # Read the whole file: # - SET(BOOST_VERSION 0) - SET(BOOST_LIB_VERSION "") - FILE(READ "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS) + set(BOOST_VERSION 0) + set(BOOST_LIB_VERSION "") + file(READ "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp") endif() - - STRING(REGEX REPLACE ".*#define BOOST_VERSION ([0-9]+).*" "\\1" Boost_VERSION "${_boost_VERSION_HPP_CONTENTS}") - STRING(REGEX REPLACE ".*#define BOOST_LIB_VERSION \"([0-9_]+)\".*" "\\1" Boost_LIB_VERSION "${_boost_VERSION_HPP_CONTENTS}") - - SET(Boost_LIB_VERSION ${Boost_LIB_VERSION} CACHE INTERNAL "The library version string for boost libraries") - SET(Boost_VERSION ${Boost_VERSION} CACHE INTERNAL "The version number for boost libraries") - - IF(NOT "${Boost_VERSION}" STREQUAL "0") - MATH(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") - MATH(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") - MATH(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") + + string(REGEX REPLACE ".*#define BOOST_VERSION ([0-9]+).*" "\\1" Boost_VERSION "${_boost_VERSION_HPP_CONTENTS}") + string(REGEX REPLACE ".*#define BOOST_LIB_VERSION \"([0-9_]+)\".*" "\\1" Boost_LIB_VERSION "${_boost_VERSION_HPP_CONTENTS}") + + set(Boost_LIB_VERSION ${Boost_LIB_VERSION} CACHE INTERNAL "The library version string for boost libraries") + set(Boost_VERSION ${Boost_VERSION} CACHE INTERNAL "The version number for boost libraries") + + if(NOT "${Boost_VERSION}" STREQUAL "0") + math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") + math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") + math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") set(Boost_ERROR_REASON "${Boost_ERROR_REASON}Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\nBoost include path: ${Boost_INCLUDE_DIR}") - ENDIF(NOT "${Boost_VERSION}" STREQUAL "0") + endif(NOT "${Boost_VERSION}" STREQUAL "0") if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "version.hpp reveals boost " "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") endif() - ELSE(Boost_INCLUDE_DIR) + else(Boost_INCLUDE_DIR) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers.") - ENDIF(Boost_INCLUDE_DIR) - + endif(Boost_INCLUDE_DIR) + # ------------------------------------------------------------------------ # Suffix initialization and compiler suffix detection. # ------------------------------------------------------------------------ # Setting some more suffixes for the library - SET (Boost_LIB_PREFIX "") - if ( WIN32 AND Boost_USE_STATIC_LIBS ) - SET (Boost_LIB_PREFIX "lib") + set(Boost_LIB_PREFIX "") + if ( WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) + set(Boost_LIB_PREFIX "lib") endif() if (Boost_COMPILER) @@ -571,62 +743,64 @@ ELSE (_boost_IN_CACHE) # please report them and use the Boost_COMPILER variable # to work around the problems. if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" - OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" + OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc") if(WIN32) set (_boost_COMPILER "-iw") else() set (_boost_COMPILER "-il") endif() - elseif (MSVC90) - SET (_boost_COMPILER "-vc90") + elseif (MSVC11) + set(_boost_COMPILER "-vc110") elseif (MSVC10) - SET (_boost_COMPILER "-vc100") + set(_boost_COMPILER "-vc100") + elseif (MSVC90) + set(_boost_COMPILER "-vc90") elseif (MSVC80) - SET (_boost_COMPILER "-vc80") + set(_boost_COMPILER "-vc80") elseif (MSVC71) - SET (_boost_COMPILER "-vc71") + set(_boost_COMPILER "-vc71") elseif (MSVC70) # Good luck! - SET (_boost_COMPILER "-vc7") # yes, this is correct + set(_boost_COMPILER "-vc7") # yes, this is correct elseif (MSVC60) # Good luck! - SET (_boost_COMPILER "-vc6") # yes, this is correct + set(_boost_COMPILER "-vc6") # yes, this is correct elseif (BORLAND) - SET (_boost_COMPILER "-bcb") + set(_boost_COMPILER "-bcb") elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "SunPro") set(_boost_COMPILER "-sw") elseif (MINGW) if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) - SET(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 + set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 else() _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) - SET (_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") + set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") endif() elseif (UNIX) if (CMAKE_COMPILER_IS_GNUCXX) if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) - SET(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 + set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 else() _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) # Determine which version of GCC we have. - IF(APPLE) - IF(Boost_MINOR_VERSION) - IF(${Boost_MINOR_VERSION} GREATER 35) + if(APPLE) + if(Boost_MINOR_VERSION) + if(${Boost_MINOR_VERSION} GREATER 35) # In Boost 1.36.0 and newer, the mangled compiler name used # on Mac OS X/Darwin is "xgcc". - SET(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") - ELSE(${Boost_MINOR_VERSION} GREATER 35) + set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") + else(${Boost_MINOR_VERSION} GREATER 35) # In Boost <= 1.35.0, there is no mangled compiler name for # the Mac OS X/Darwin version of GCC. - SET(_boost_COMPILER "") - ENDIF(${Boost_MINOR_VERSION} GREATER 35) - ELSE(Boost_MINOR_VERSION) + set(_boost_COMPILER "") + endif(${Boost_MINOR_VERSION} GREATER 35) + else(Boost_MINOR_VERSION) # We don't know the Boost version, so assume it's # pre-1.36.0. - SET(_boost_COMPILER "") - ENDIF(Boost_MINOR_VERSION) - ELSE() - SET (_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") - ENDIF() + set(_boost_COMPILER "") + endif(Boost_MINOR_VERSION) + else() + set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") + endif() endif() endif (CMAKE_COMPILER_IS_GNUCXX) endif() @@ -636,7 +810,7 @@ ELSE (_boost_IN_CACHE) endif() endif(Boost_COMPILER) - SET (_boost_MULTITHREADED "-mt") + set (_boost_MULTITHREADED "-mt") if( NOT Boost_USE_MULTITHREADED ) set (_boost_MULTITHREADED "") endif() @@ -645,32 +819,67 @@ ELSE (_boost_IN_CACHE) "_boost_MULTITHREADED = ${_boost_MULTITHREADED}") endif() - SET( _boost_STATIC_TAG "") - set( _boost_ABI_TAG "") - IF (WIN32) - IF(MSVC OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" + #====================== + # Systematically build up the Boost ABI tag + # http://boost.org/doc/libs/1_41_0/more/getting_started/windows.html#library-naming + set( _boost_RELEASE_ABI_TAG "-") + set( _boost_DEBUG_ABI_TAG "-") + # Key Use this library when: + # s linking statically to the C++ standard library and + # compiler runtime support libraries. + if(Boost_USE_STATIC_RUNTIME) + set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s") + set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s") + endif() + # g using debug versions of the standard and runtime + # support libraries + if(WIN32) + if(MSVC OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc") - SET (_boost_ABI_TAG "g") - ENDIF() - IF( Boost_USE_STATIC_LIBS ) - SET( _boost_STATIC_TAG "-s") - ENDIF( Boost_USE_STATIC_LIBS ) - ENDIF(WIN32) - SET (_boost_ABI_TAG "${_boost_ABI_TAG}d") + set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}g") + endif() + endif() + # y using special debug build of python + if(Boost_USE_DEBUG_PYTHON) + set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}y") + endif() + # d using a debug version of your code + set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}d") + # p using the STLport standard library rather than the + # default one supplied with your compiler + if(Boost_USE_STLPORT) + set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}p") + set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}p") + endif() + # n using the STLport deprecated "native iostreams" feature + if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) + set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}n") + set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}n") + endif() + if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_STATIC_TAG = ${_boost_STATIC_TAG}") + "_boost_RELEASE_ABI_TAG = ${_boost_RELEASE_ABI_TAG}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_ABI_TAG = ${_boost_ABI_TAG}") + "_boost_DEBUG_ABI_TAG = ${_boost_DEBUG_ABI_TAG}") endif() # ------------------------------------------------------------------------ # Begin finding boost libraries # ------------------------------------------------------------------------ - SET(_boost_LIBRARIES_SEARCH_DIRS + if(BOOST_ROOT) + set(_boost_LIBRARY_SEARCH_DIRS_ALWAYS + ${BOOST_ROOT}/lib + ${BOOST_ROOT}/stage/lib) + endif() + set(_boost_LIBRARY_SEARCH_DIRS_ALWAYS + ${_boost_LIBRARY_SEARCH_DIRS_ALWAYS} ${Boost_INCLUDE_DIR}/lib ${Boost_INCLUDE_DIR}/../lib + ${Boost_INCLUDE_DIR}/stage/lib + ) + set(_boost_LIBRARY_SEARCH_DIRS_SYSTEM C:/boost/lib C:/boost "$ENV{ProgramFiles}/boost/boost_${Boost_MAJOR_VERSION}_${Boost_MINOR_VERSION}_${Boost_SUBMINOR_VERSION}/lib" @@ -679,78 +888,158 @@ ELSE (_boost_IN_CACHE) "$ENV{ProgramFiles}/boost" /sw/local/lib ) - IF( BOOST_ROOT ) - SET(_boost_LIBRARIES_SEARCH_DIRS - ${BOOST_ROOT}/lib - ${BOOST_ROOT}/stage/lib - ${_boost_LIBRARIES_SEARCH_DIRS}) - ENDIF( BOOST_ROOT ) - - IF( BOOST_LIBRARYDIR ) + set(_boost_LIBRARY_SEARCH_DIRS ${_boost_LIBRARY_SEARCH_DIRS_ALWAYS}) + if( Boost_NO_SYSTEM_PATHS ) + set(_boost_FIND_OPTIONS NO_CMAKE_SYSTEM_PATH) + else() + list(APPEND _boost_LIBRARY_SEARCH_DIRS ${_boost_LIBRARY_SEARCH_DIRS_SYSTEM}) + endif() + + # prepend BOOST_LIBRARYDIR to search path if specified + if( BOOST_LIBRARYDIR ) file(TO_CMAKE_PATH ${BOOST_LIBRARYDIR} BOOST_LIBRARYDIR) - SET(_boost_LIBRARIES_SEARCH_DIRS - ${BOOST_LIBRARYDIR} ${_boost_LIBRARIES_SEARCH_DIRS}) - ENDIF( BOOST_LIBRARYDIR ) + set(_boost_LIBRARY_SEARCH_DIRS + ${BOOST_LIBRARYDIR} ${_boost_LIBRARY_SEARCH_DIRS}) + endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_LIBRARIES_SEARCH_DIRS = ${_boost_LIBRARIES_SEARCH_DIRS}") - endif() - - FOREACH(COMPONENT ${Boost_FIND_COMPONENTS}) - STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT) - SET( Boost_${UPPERCOMPONENT}_LIBRARY "Boost_${UPPERCOMPONENT}_LIBRARY-NOTFOUND" ) - SET( Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE-NOTFOUND" ) - SET( Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG-NOTFOUND") - - # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES - IF( Boost_USE_STATIC_LIBS ) - SET( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - IF(WIN32) - SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) - ELSE(WIN32) - SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) - ENDIF(WIN32) - ENDIF( Boost_USE_STATIC_LIBS ) - - FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE - NAMES ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_STATIC_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_STATIC_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_STATIC_TAG} - HINTS ${_boost_LIBRARIES_SEARCH_DIRS} + "_boost_LIBRARY_SEARCH_DIRS = ${_boost_LIBRARY_SEARCH_DIRS}") + endif() + + # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES + if( Boost_USE_STATIC_LIBS ) + set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) + endif() + endif() + + # We want to use the tag inline below without risking double dashes + if(_boost_RELEASE_ABI_TAG) + if(${_boost_RELEASE_ABI_TAG} STREQUAL "-") + set(_boost_RELEASE_ABI_TAG "") + endif() + endif() + if(_boost_DEBUG_ABI_TAG) + if(${_boost_DEBUG_ABI_TAG} STREQUAL "-") + set(_boost_DEBUG_ABI_TAG "") + endif() + endif() + + # The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled + # on WIN32 was to: + # 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found) + # 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found) + # We maintain this behavior since changing it could break people's builds. + # To disable the ambiguous behavior, the user need only + # set Boost_USE_STATIC_RUNTIME either ON or OFF. + set(_boost_STATIC_RUNTIME_WORKAROUND false) + if(WIN32 AND Boost_USE_STATIC_LIBS) + if(NOT DEFINED Boost_USE_STATIC_RUNTIME) + set(_boost_STATIC_RUNTIME_WORKAROUND true) + endif() + endif() + + + foreach(COMPONENT ${Boost_FIND_COMPONENTS}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + set( Boost_${UPPERCOMPONENT}_LIBRARY "Boost_${UPPERCOMPONENT}_LIBRARY-NOTFOUND" ) + set( Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE-NOTFOUND" ) + set( Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG-NOTFOUND") + + set( _boost_docstring_release "Boost ${COMPONENT} library (release)") + set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)") + + # + # Find RELEASE libraries + # + set(_boost_RELEASE_NAMES + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} + ${Boost_LIB_PREFIX}boost_${COMPONENT} ) + if(_boost_STATIC_RUNTIME_WORKAROUND) + set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") + list(APPEND _boost_RELEASE_NAMES + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) + endif() + if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") + _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES}) + endif() + if(Boost_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}") + endif() + find_library(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE + NAMES ${_boost_RELEASE_NAMES} + HINTS ${_boost_LIBRARY_SEARCH_DIRS} + ${_boost_FIND_OPTIONS} + DOC "${_boost_docstring_release}" ) - FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG - NAMES ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}-${_boost_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_STATIC_TAG}${_boost_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}-${_boost_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_STATIC_TAG}${_boost_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}-${_boost_ABI_TAG} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_STATIC_TAG}${_boost_ABI_TAG} - ${Boost_LIB_PREFIX}boost_${COMPONENT}-${_boost_ABI_TAG} - HINTS ${_boost_LIBRARIES_SEARCH_DIRS} + # + # Find DEBUG libraries + # + set(_boost_DEBUG_NAMES + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED} + ${Boost_LIB_PREFIX}boost_${COMPONENT} ) + if(_boost_STATIC_RUNTIME_WORKAROUND) + set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") + list(APPEND _boost_DEBUG_NAMES + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) + endif() + if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") + _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES}) + endif() + if(Boost_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}") + endif() + find_library(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG + NAMES ${_boost_DEBUG_NAMES} + HINTS ${_boost_LIBRARY_SEARCH_DIRS} + ${_boost_FIND_OPTIONS} + DOC "${_boost_docstring_debug}" ) + if(Boost_REALPATH) + _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}") + _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" ) + endif() + _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) - IF( Boost_USE_STATIC_LIBS ) - SET(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) - ENDIF( Boost_USE_STATIC_LIBS ) - ENDFOREACH(COMPONENT) + + endforeach(COMPONENT) + + # Restore the original find library ordering + if( Boost_USE_STATIC_LIBS ) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) + endif() # ------------------------------------------------------------------------ # End finding boost libraries # ------------------------------------------------------------------------ - SET(Boost_INCLUDE_DIRS + set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR} ) - SET(Boost_FOUND FALSE) - IF(Boost_INCLUDE_DIR) - SET( Boost_FOUND TRUE ) + set(Boost_FOUND FALSE) + if(Boost_INCLUDE_DIR) + set( Boost_FOUND TRUE ) # Check the version of Boost against the requested version. if (Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) @@ -785,7 +1074,7 @@ ELSE (_boost_IN_CACHE) if (NOT Boost_FIND_VERSION_PATCH) set(Boost_FIND_VERSION_PATCH 0) endif (NOT Boost_FIND_VERSION_PATCH) - + # We'll set Boost_FOUND true again if we have an exact version match. set(Boost_FOUND FALSE) _Boost_MARK_COMPONENTS_FOUND(OFF) @@ -804,7 +1093,7 @@ ELSE (_boost_IN_CACHE) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}\nDetected version of Boost is too ${_Boost_VERSION_AGE}. Requested version was ${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") if (Boost_FIND_VERSION_PATCH) - set(Boost_ERROR_REASON + set(Boost_ERROR_REASON "${Boost_ERROR_REASON}.${Boost_FIND_VERSION_PATCH}") endif (Boost_FIND_VERSION_PATCH) if (NOT Boost_FIND_VERSION_EXACT) @@ -823,7 +1112,7 @@ ELSE (_boost_IN_CACHE) string(TOLOWER ${COMPONENT} COMPONENT) list(APPEND _Boost_MISSING_COMPONENTS ${COMPONENT}) set( Boost_FOUND FALSE) - endif(NOT Boost_${COMPONENT}_FOUND) + endif() endforeach(COMPONENT) if(Boost_DEBUG) @@ -844,67 +1133,67 @@ ELSE (_boost_IN_CACHE) list(LENGTH _Boost_MISSING_COMPONENTS Boost_NUM_MISSING_COMPONENTS) if (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}No Boost libraries were found. You may need to set Boost_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") + "${Boost_ERROR_REASON}No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") else (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set Boost_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") + "${Boost_ERROR_REASON}Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") endif (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) endif (_Boost_MISSING_COMPONENTS) - IF( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) + if( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) # Compatibility Code for backwards compatibility with CMake # 2.4's FindBoost module. # Look for the boost library path. # Note that the user may not have installed any libraries # so it is quite possible the Boost_LIBRARY_PATH may not exist. - SET(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) - - IF("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") - GET_FILENAME_COMPONENT(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) - ENDIF ("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") - - IF("${_boost_LIB_DIR}" MATCHES "/include$") + set(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) + + if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") + get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) + endif() + + if("${_boost_LIB_DIR}" MATCHES "/include$") # Strip off the trailing "/include" in the path. - GET_FILENAME_COMPONENT(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) - ENDIF("${_boost_LIB_DIR}" MATCHES "/include$") - - IF(EXISTS "${_boost_LIB_DIR}/lib") - SET (_boost_LIB_DIR ${_boost_LIB_DIR}/lib) - ELSE(EXISTS "${_boost_LIB_DIR}/lib") - IF(EXISTS "${_boost_LIB_DIR}/stage/lib") - SET(_boost_LIB_DIR ${_boost_LIB_DIR}/stage/lib) - ELSE(EXISTS "${_boost_LIB_DIR}/stage/lib") - SET(_boost_LIB_DIR "") - ENDIF(EXISTS "${_boost_LIB_DIR}/stage/lib") - ENDIF(EXISTS "${_boost_LIB_DIR}/lib") - - IF(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") - SET(Boost_LIBRARY_DIRS ${_boost_LIB_DIR} CACHE FILEPATH "Boost library directory") - ENDIF(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") - - ENDIF( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) - - ELSE(Boost_INCLUDE_DIR) - SET( Boost_FOUND FALSE) - ENDIF(Boost_INCLUDE_DIR) - - IF (Boost_FOUND) - IF (NOT Boost_FIND_QUIETLY) - MESSAGE(STATUS "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") + get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) + endif() + + if(EXISTS "${_boost_LIB_DIR}/lib") + set(_boost_LIB_DIR ${_boost_LIB_DIR}/lib) + else() + if(EXISTS "${_boost_LIB_DIR}/stage/lib") + set(_boost_LIB_DIR ${_boost_LIB_DIR}/stage/lib) + else() + set(_boost_LIB_DIR "") + endif() + endif() + + if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") + set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR} CACHE FILEPATH "Boost library directory") + endif() + + endif( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) + + else(Boost_INCLUDE_DIR) + set( Boost_FOUND FALSE) + endif(Boost_INCLUDE_DIR) + + if(Boost_FOUND) + if(NOT Boost_FIND_QUIETLY) + message(STATUS "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") if(Boost_FIND_COMPONENTS) message(STATUS "Found the following Boost libraries:") endif() - ENDIF(NOT Boost_FIND_QUIETLY) - FOREACH ( COMPONENT ${Boost_FIND_COMPONENTS} ) - STRING( TOUPPER ${COMPONENT} UPPERCOMPONENT ) - IF ( Boost_${UPPERCOMPONENT}_FOUND ) - IF (NOT Boost_FIND_QUIETLY) - MESSAGE (STATUS " ${COMPONENT}") - ENDIF(NOT Boost_FIND_QUIETLY) - SET(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${UPPERCOMPONENT}_LIBRARY}) - ENDIF ( Boost_${UPPERCOMPONENT}_FOUND ) - ENDFOREACH(COMPONENT) + endif(NOT Boost_FIND_QUIETLY) + foreach( COMPONENT ${Boost_FIND_COMPONENTS} ) + string( TOUPPER ${COMPONENT} UPPERCOMPONENT ) + if( Boost_${UPPERCOMPONENT}_FOUND ) + if(NOT Boost_FIND_QUIETLY) + message (STATUS " ${COMPONENT}") + endif(NOT Boost_FIND_QUIETLY) + set(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${UPPERCOMPONENT}_LIBRARY}) + endif( Boost_${UPPERCOMPONENT}_FOUND ) + endforeach(COMPONENT) else() if(Boost_FIND_REQUIRED) message(SEND_ERROR "Unable to find the requested Boost libraries.\n${Boost_ERROR_REASON}") @@ -924,9 +1213,8 @@ ELSE (_boost_IN_CACHE) endif() # show the Boost_INCLUDE_DIRS AND Boost_LIBRARIES variables only in the advanced view - MARK_AS_ADVANCED(Boost_INCLUDE_DIR + mark_as_advanced(Boost_INCLUDE_DIR Boost_INCLUDE_DIRS Boost_LIBRARY_DIRS ) -ENDIF(_boost_IN_CACHE) - +endif(_boost_IN_CACHE) diff --git a/tests/FindGLEW.cmake b/tests/FindGLEW.cmake index 32c2d6e..8093ed3 100644 --- a/tests/FindGLEW.cmake +++ b/tests/FindGLEW.cmake @@ -44,7 +44,8 @@ ENDIF (WIN32) IF (GLEW_INCLUDE_PATH) SET( GLEW_FOUND 1 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise") - MESSAGE(STATUS "GLEW found in " ${GLEW_INCLUDE_PATH} " " ${GLEW_LIBRARY}) + MESSAGE(STATUS "GLEW include found in " ${GLEW_INCLUDE_PATH} ) + MESSAGE(STATUS "GLEW library found in " ${GLEW_LIBRARY} ) ELSE (GLEW_INCLUDE_PATH) SET( GLEW_FOUND 0 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise") ENDIF (GLEW_INCLUDE_PATH) diff --git a/tests/OffscreenContext.h b/tests/OffscreenContext.h index a079c3f..6eebcba 100644 --- a/tests/OffscreenContext.h +++ b/tests/OffscreenContext.h @@ -2,10 +2,12 @@ #define OFFSCREENCONTEXT_H_ #include <iostream> // for error output +#include <string> struct OffscreenContext *create_offscreen_context(int w, int h); void bind_offscreen_context(OffscreenContext *ctx); bool teardown_offscreen_context(OffscreenContext *ctx); bool save_framebuffer(OffscreenContext *ctx, const char *filename); +std::string offscreen_context_getinfo(OffscreenContext *ctx); #endif diff --git a/tests/OffscreenContext.mm b/tests/OffscreenContext.mm index 0c44d7d..eb06615 100644 --- a/tests/OffscreenContext.mm +++ b/tests/OffscreenContext.mm @@ -17,6 +17,15 @@ struct OffscreenContext fbo_t *fbo; }; +string offscreen_context_getinfo(OffscreenContext *ctx) +{ + stringstream out; + out << "GL context creator: Cocoa / CGL\n" + << "PNG generator: Core Foundation\n" + << "OS info: Mac OSX\n" + << "Machine: Apple(TM) Mac(TM)\n"; + return out.str(); +} OffscreenContext *create_offscreen_context(int w, int h) { @@ -84,6 +93,7 @@ bool teardown_offscreen_context(OffscreenContext *ctx) */ bool save_framebuffer(OffscreenContext *ctx, const char *filename) { + if (!ctx || !filename) return false; // Read pixels from OpenGL int samplesPerPixel = 4; // R, G, B and A int rowBytes = samplesPerPixel * ctx->width; diff --git a/tests/OffscreenContext.cc b/tests/OffscreenContextGLX.cc index 839eea9..e607593 100644 --- a/tests/OffscreenContext.cc +++ b/tests/OffscreenContextGLX.cc @@ -44,6 +44,11 @@ See Also #include <GL/gl.h> #include <GL/glx.h> +#include <assert.h> +#include <sstream> + +#include <sys/utsname.h> // for uname + using namespace std; struct OffscreenContext @@ -66,6 +71,42 @@ void offscreen_context_init(OffscreenContext &ctx, int width, int height) ctx.fbo = NULL; } +string get_os_info() +{ + struct utsname u; + stringstream out; + + if (uname(&u) < 0) + out << "OS info: unknown, uname() error\n"; + else { + out << "OS info: " + << u.sysname << " " + << u.release << " " + << u.version << "\n"; + out << "Machine: " << u.machine; + } + return out.str(); +} + +string offscreen_context_getinfo(OffscreenContext *ctx) +{ + assert(ctx); + + if (!ctx->xdisplay) + return string("No GL Context initialized. No information to report\n"); + + int major, minor; + glXQueryVersion(ctx->xdisplay, &major, &minor); + + stringstream out; + out << "GL context creator: GLX\n" + << "PNG generator: lodepng\n" + << "GLX version: " << major << "." << minor << "\n" + << get_os_info(); + + return out.str(); +} + static XErrorHandler original_xlib_handler = (XErrorHandler) NULL; static bool XCreateWindow_failed = false; static int XCreateWindow_error(Display *dpy, XErrorEvent *event) @@ -94,11 +135,15 @@ bool create_glx_dummy_window(OffscreenContext &ctx) */ int attributes[] = { - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT, //support all 3, for OpenCSG GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, // depth-stencil for OpenCSG + GLX_STENCIL_SIZE, 8, + GLX_DOUBLEBUFFER, True, None }; @@ -123,8 +168,9 @@ bool create_glx_dummy_window(OffscreenContext &ctx) Window root = DefaultRootWindow( dpy ); XSetWindowAttributes xwin_attr; - int width = 42; - int height = 42; + int width = ctx.width; + int height = ctx.height; + xwin_attr.background_pixmap = None; xwin_attr.background_pixel = 0; xwin_attr.border_pixel = 0; xwin_attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); @@ -137,7 +183,6 @@ bool create_glx_dummy_window(OffscreenContext &ctx) // Window xWin = XCreateSimpleWindow( dpy, DefaultRootWindow(dpy), 0,0,42,42, 0,0,0 ); - XSync( dpy, false ); if ( XCreateWindow_failed ) { XFree( visinfo ); @@ -227,7 +272,6 @@ OffscreenContext *create_offscreen_context(int w, int h) cerr << "Unable to init GLEW: " << glewGetErrorString(err) << endl; return NULL; } - glew_dump(); ctx->fbo = fbo_new(); if (!fbo_init(ctx->fbo, w, h)) { @@ -256,6 +300,7 @@ bool teardown_offscreen_context(OffscreenContext *ctx) */ bool save_framebuffer(OffscreenContext *ctx, const char *filename) { + glXSwapBuffers(ctx->xdisplay, ctx->xwindow); if (!ctx || !filename) return false; int samplesPerPixel = 4; // R, G, B and A GLubyte pixels[ctx->width * ctx->height * samplesPerPixel]; @@ -265,7 +310,7 @@ bool save_framebuffer(OffscreenContext *ctx, const char *filename) int rowBytes = samplesPerPixel * ctx->width; unsigned char *flippedBuffer = (unsigned char *)malloc(rowBytes * ctx->height); if (!flippedBuffer) { - std::cerr << "Unable to allocate flipped buffer for corrected image."; + cerr << "Unable to allocate flipped buffer for corrected image."; return 1; } flip_image(pixels, flippedBuffer, samplesPerPixel, ctx->width, ctx->height); diff --git a/tests/OffscreenContextWGL.cc b/tests/OffscreenContextWGL.cc index 3b966e2..f36671c 100644 --- a/tests/OffscreenContextWGL.cc +++ b/tests/OffscreenContextWGL.cc @@ -22,6 +22,10 @@ For more info: #include <GL/gl.h> // must be included after glew.h +#include <map> +#include <string> +#include <sstream> + using namespace std; struct OffscreenContext @@ -44,6 +48,45 @@ void offscreen_context_init(OffscreenContext &ctx, int width, int height) ctx.fbo = NULL; } +string get_os_info() +{ + OSVERSIONINFO osvi; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + SYSTEM_INFO si; + GetSystemInfo(&si); + map<WORD,const char*> archs; + archs[PROCESSOR_ARCHITECTURE_AMD64] = "amd64"; + archs[PROCESSOR_ARCHITECTURE_IA64] = "itanium"; + archs[PROCESSOR_ARCHITECTURE_INTEL] = "x86"; + archs[PROCESSOR_ARCHITECTURE_UNKNOWN] = "unknown"; + + stringstream out; + out << "OS info: " + << "Microsoft(TM) Windows(TM) " << osvi.dwMajorVersion << " " + << osvi.dwMinorVersion << " " << osvi.dwBuildNumber << " " + << osvi.szCSDVersion; + if (archs.find(si.wProcessorArchitecture) != archs.end()) + out << " " << archs[si.wProcessorArchitecture]; + out << "\n"; + + out << "Machine: " << si.dwProcessorType; + + return out.str(); +} + +string offscreen_context_getinfo(OffscreenContext *ctx) +{ + stringstream out; + out << "GL context creator: WGL\n" + << "PNG generator: lodepng\n" + << get_os_info(); + return out.str(); +} + LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { return DefWindowProc( hwnd, message, wparam, lparam ); @@ -87,11 +130,15 @@ bool create_wgl_dummy_context(OffscreenContext &ctx) ZeroMemory( &pixformat, sizeof( pixformat ) ); pixformat.nSize = sizeof( pixformat ); pixformat.nVersion = 1; - pixformat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + pixformat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pixformat.iPixelType = PFD_TYPE_RGBA; - pixformat.cColorBits = 24; - pixformat.cDepthBits = 16; - pixformat.iLayerType = PFD_MAIN_PLANE; + pixformat.cGreenBits = 8; + pixformat.cRedBits = 8; + pixformat.cBlueBits = 8; + pixformat.cAlphaBits = 8; + pixformat.cDepthBits = 24; + pixformat.cStencilBits = 8; + chosenformat = ChoosePixelFormat( dev_context, &pixformat ); if (chosenformat==0) { cerr << "MS GDI - ChoosePixelFormat failed\n"; @@ -142,7 +189,7 @@ OffscreenContext *create_offscreen_context(int w, int h) cerr << "Unable to init GLEW: " << glewGetErrorString(err) << "\n"; return NULL; } - glew_dump(); + //cerr << glew_dump(0); ctx->fbo = fbo_new(); if (!fbo_init(ctx->fbo, w, h)) { @@ -172,6 +219,7 @@ bool teardown_offscreen_context(OffscreenContext *ctx) */ bool save_framebuffer(OffscreenContext *ctx, const char *filename) { + wglSwapLayerBuffers( ctx->dev_context, WGL_SWAP_MAIN_PLANE ); if (!ctx || !filename) return false; int samplesPerPixel = 4; // R, G, B and A vector<GLubyte> pixels(ctx->width * ctx->height * samplesPerPixel); diff --git a/tests/OffscreenView.cc b/tests/OffscreenView.cc index 46951c1..61d5818 100644 --- a/tests/OffscreenView.cc +++ b/tests/OffscreenView.cc @@ -1,11 +1,12 @@ #include <GL/glew.h> #include "OffscreenView.h" -#include <opencsg.h> +#include "system-gl.h" #include "renderer.h" #include <math.h> #include <stdio.h> #include <string.h> #include <cstdlib> +#include <sstream> #define FAR_FAR_AWAY 100000.0 @@ -17,19 +18,6 @@ OffscreenView::OffscreenView(size_t width, size_t height) this->ctx = create_offscreen_context(width, height); if ( this->ctx == NULL ) throw -1; -#ifdef DEBUG - GLint rbits, gbits, bbits, abits, dbits, sbits; - glGetIntegerv(GL_RED_BITS, &rbits); - glGetIntegerv(GL_GREEN_BITS, &gbits); - glGetIntegerv(GL_BLUE_BITS, &bbits); - glGetIntegerv(GL_ALPHA_BITS, &abits); - glGetIntegerv(GL_DEPTH_BITS, &dbits); - glGetIntegerv(GL_STENCIL_BITS, &sbits); - - fprintf(stderr, "FBO: RGBA(%d%d%d%d), depth(%d), stencil(%d)\n", - rbits, gbits, bbits, abits, dbits, sbits); -#endif - initializeGL(); resizeGL(width, height); } @@ -68,105 +56,13 @@ void OffscreenView::initializeGL() glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); -#ifdef ENABLE_OPENCSG - const char *openscad_disable_gl20_env = getenv("OPENSCAD_DISABLE_GL20"); - if (openscad_disable_gl20_env && !strcmp(openscad_disable_gl20_env, "0")) - openscad_disable_gl20_env = NULL; - if (glewIsSupported("GL_VERSION_2_0") && openscad_disable_gl20_env == NULL) - { - const char *vs_source = - "uniform float xscale, yscale;\n" - "attribute vec3 pos_b, pos_c;\n" - "attribute vec3 trig, mask;\n" - "varying vec3 tp, tr;\n" - "varying float shading;\n" - "void main() {\n" - " vec4 p0 = gl_ModelViewProjectionMatrix * gl_Vertex;\n" - " vec4 p1 = gl_ModelViewProjectionMatrix * vec4(pos_b, 1.0);\n" - " vec4 p2 = gl_ModelViewProjectionMatrix * vec4(pos_c, 1.0);\n" - " float a = distance(vec2(xscale*p1.x/p1.w, yscale*p1.y/p1.w), vec2(xscale*p2.x/p2.w, yscale*p2.y/p2.w));\n" - " float b = distance(vec2(xscale*p0.x/p0.w, yscale*p0.y/p0.w), vec2(xscale*p1.x/p1.w, yscale*p1.y/p1.w));\n" - " float c = distance(vec2(xscale*p0.x/p0.w, yscale*p0.y/p0.w), vec2(xscale*p2.x/p2.w, yscale*p2.y/p2.w));\n" - " float s = (a + b + c) / 2.0;\n" - " float A = sqrt(s*(s-a)*(s-b)*(s-c));\n" - " float ha = 2.0*A/a;\n" - " gl_Position = p0;\n" - " tp = mask * ha;\n" - " tr = trig;\n" - " vec3 normal, lightDir;\n" - " normal = normalize(gl_NormalMatrix * gl_Normal);\n" - " lightDir = normalize(vec3(gl_LightSource[0].position));\n" - " shading = abs(dot(normal, lightDir));\n" - "}\n"; - - const char *fs_source = - "uniform vec4 color1, color2;\n" - "varying vec3 tp, tr, tmp;\n" - "varying float shading;\n" - "void main() {\n" - " gl_FragColor = vec4(color1.r * shading, color1.g * shading, color1.b * shading, color1.a);\n" - " if (tp.x < tr.x || tp.y < tr.y || tp.z < tr.z)\n" - " gl_FragColor = color2;\n" - "}\n"; - - GLuint vs = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vs, 1, (const GLchar**)&vs_source, NULL); - glCompileShader(vs); - - GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fs, 1, (const GLchar**)&fs_source, NULL); - glCompileShader(fs); - - GLuint edgeshader_prog = glCreateProgram(); - glAttachShader(edgeshader_prog, vs); - glAttachShader(edgeshader_prog, fs); - glLinkProgram(edgeshader_prog); - - shaderinfo[0] = edgeshader_prog; - shaderinfo[1] = glGetUniformLocation(edgeshader_prog, "color1"); - shaderinfo[2] = glGetUniformLocation(edgeshader_prog, "color2"); - shaderinfo[3] = glGetAttribLocation(edgeshader_prog, "trig"); - shaderinfo[4] = glGetAttribLocation(edgeshader_prog, "pos_b"); - shaderinfo[5] = glGetAttribLocation(edgeshader_prog, "pos_c"); - shaderinfo[6] = glGetAttribLocation(edgeshader_prog, "mask"); - shaderinfo[7] = glGetUniformLocation(edgeshader_prog, "xscale"); - shaderinfo[8] = glGetUniformLocation(edgeshader_prog, "yscale"); - - GLenum err = glGetError(); - if (err != GL_NO_ERROR) { - fprintf(stderr, "OpenGL Error: %s\n", gluErrorString(err)); - } - - GLint status; - glGetProgramiv(edgeshader_prog, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - int loglen; - char logbuffer[1000]; - glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer); - fprintf(stderr, "OpenGL Program Linker Error:\n%.*s", loglen, logbuffer); - } else { - int loglen; - char logbuffer[1000]; - glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer); - if (loglen > 0) { - fprintf(stderr, "OpenGL Program Link OK:\n%.*s", loglen, logbuffer); - } - glValidateProgram(edgeshader_prog); - glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer); - if (loglen > 0) { - fprintf(stderr, "OpenGL Program Validation results:\n%.*s", loglen, logbuffer); - } - } - } -#endif /* ENABLE_OPENCSG */ + } void OffscreenView::resizeGL(int w, int h) { -#ifdef ENABLE_OPENCSG - shaderinfo[9] = w; - shaderinfo[10] = h; -#endif + this->width = w; + this->height = h; glViewport(0, 0, w, h); w_h_ratio = sqrt((double)w / (double)h); } @@ -237,9 +133,6 @@ void OffscreenView::paintGL() glColor3d(1.0, 0.0, 0.0); if (this->renderer) { -#ifdef ENABLE_OPENCSG - OpenCSG::setContext(0); -#endif this->renderer->draw(showfaces, showedges); } } @@ -249,6 +142,26 @@ bool OffscreenView::save(const char *filename) return save_framebuffer(this->ctx, filename); } +std::string OffscreenView::getInfo() +{ + std::stringstream out; + GLint rbits, gbits, bbits, abits, dbits, sbits; + glGetIntegerv(GL_RED_BITS, &rbits); + glGetIntegerv(GL_GREEN_BITS, &gbits); + glGetIntegerv(GL_BLUE_BITS, &bbits); + glGetIntegerv(GL_ALPHA_BITS, &abits); + glGetIntegerv(GL_DEPTH_BITS, &dbits); + glGetIntegerv(GL_STENCIL_BITS, &sbits); + + out << glew_dump(false) + << "FBO: RGBA(" << rbits << gbits << bbits << abits + << "), depth(" << dbits + << "), stencil(" << sbits << ")\n" + << offscreen_context_getinfo(this->ctx); + + return out.str(); +} + void OffscreenView::setCamera(const Eigen::Vector3d &pos, const Eigen::Vector3d ¢er) { this->camera_eye = pos; diff --git a/tests/OffscreenView.h b/tests/OffscreenView.h index e3c8579..8b98b29 100644 --- a/tests/OffscreenView.h +++ b/tests/OffscreenView.h @@ -4,6 +4,7 @@ #include "OffscreenContext.h" #include <Eigen/Core> #include <Eigen/Geometry> +#include <string> #ifndef _MSC_VER #include <stdint.h> #endif @@ -22,9 +23,12 @@ public: void setupOrtho(bool offset=false); void paintGL(); bool save(const char *filename); + std::string getInfo(); GLint shaderinfo[11]; OffscreenContext *ctx; + size_t width; + size_t height; private: Renderer *renderer; double w_h_ratio; diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc index 800a829..608fb08 100644 --- a/tests/cgalpngtest.cc +++ b/tests/cgalpngtest.cc @@ -172,16 +172,19 @@ int main(int argc, char **argv) BoundingBox bbox; if (cgalRenderer.polyhedron) { + std::cout << "polyhedron\n" ; CGAL::Bbox_3 cgalbbox = cgalRenderer.polyhedron->bbox(); bbox = BoundingBox(Vector3d(cgalbbox.xmin(), cgalbbox.ymin(), cgalbbox.zmin()), Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax())); } else if (cgalRenderer.polyset) { + std::cout << "polyset\n" ; bbox = cgalRenderer.polyset->getBoundingBox(); } Vector3d center = getBoundingCenter(bbox); double radius = getBoundingRadius(bbox); + std::cout << "radius: " << radius << "\n"; Vector3d cameradir(1, 1, -0.5); Vector3d camerapos = center - radius*2*cameradir; diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc index 864d40e..4cdc5d8 100644 --- a/tests/csgtestcore.cc +++ b/tests/csgtestcore.cc @@ -14,6 +14,7 @@ #include "CGALEvaluator.h" #include "PolySetCGALEvaluator.h" +#include <opencsg.h> #include "OpenCSGRenderer.h" #include "ThrownTogetherRenderer.h" @@ -25,8 +26,15 @@ #include <QDir> #include <QSet> #include <QTimer> + #include <sstream> +#include <vector> + +#include <boost/program_options.hpp> +namespace po = boost::program_options; +using std::string; +using std::vector; using std::cerr; using std::cout; @@ -64,16 +72,181 @@ AbstractNode *find_root_tag(AbstractNode *n) return NULL; } +string info_dump(OffscreenView *glview) +{ + assert(glview); + +#ifdef __GNUG__ +#define compiler_info "GCC " << __VERSION__ +#elif defined(_MSC_VER) +#define compiler_info "MSVC " << _MSC_FULL_VER +#else +#define compiler_info "unknown compiler" +#endif + +#ifndef OPENCSG_VERSION_STRING +#define OPENCSG_VERSION_STRING "unknown, <1.3.2" +#endif + + std::stringstream out; +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + out << "\nOpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION) + << "\nCompiled by: " << compiler_info + << "\nCompile date: " << __DATE__ + << "\nBoost version: " << BOOST_LIB_VERSION + << "\nEigen version: " << EIGEN_WORLD_VERSION << "." + << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION + << "\nCGAL version: " << TOSTRING(CGAL_VERSION) + << "\nOpenCSG version: " << OPENCSG_VERSION_STRING + << "\n" << glview->getInfo() + << "\n"; + + return out.str(); +} + +po::variables_map parse_options(int argc, char *argv[]) +{ + po::options_description desc("Allowed options"); + desc.add_options() + ("help,h", "help message")//; + ("info,i", "information on GLEW, OpenGL, OpenSCAD, and OS")//; + +// po::options_description hidden("Hidden options"); +// hidden.add_options() + ("input-file", po::value< vector<string> >(), "input file") + ("output-file", po::value< vector<string> >(), "ouput file"); + + po::positional_options_description p; + p.add("input-file", 1).add("output-file", 1); + + po::options_description all_options; + all_options.add(desc); // .add(hidden); + + po::variables_map vm; + po::store(po::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm); + po::notify(vm); + + return vm; +} + +void enable_opencsg_shaders( OffscreenView *glview ) +{ + bool ignore_gl_version = true; + const char *openscad_disable_gl20_env = getenv("OPENSCAD_DISABLE_GL20"); + if (openscad_disable_gl20_env && !strcmp(openscad_disable_gl20_env, "0")) + openscad_disable_gl20_env = NULL; + if (glewIsSupported("GL_VERSION_2_0") && openscad_disable_gl20_env == NULL ) + { + const char *vs_source = + "uniform float xscale, yscale;\n" + "attribute vec3 pos_b, pos_c;\n" + "attribute vec3 trig, mask;\n" + "varying vec3 tp, tr;\n" + "varying float shading;\n" + "void main() {\n" + " vec4 p0 = gl_ModelViewProjectionMatrix * gl_Vertex;\n" + " vec4 p1 = gl_ModelViewProjectionMatrix * vec4(pos_b, 1.0);\n" + " vec4 p2 = gl_ModelViewProjectionMatrix * vec4(pos_c, 1.0);\n" + " float a = distance(vec2(xscale*p1.x/p1.w, yscale*p1.y/p1.w), vec2(xscale*p2.x/p2.w, yscale*p2.y/p2.w));\n" + " float b = distance(vec2(xscale*p0.x/p0.w, yscale*p0.y/p0.w), vec2(xscale*p1.x/p1.w, yscale*p1.y/p1.w));\n" + " float c = distance(vec2(xscale*p0.x/p0.w, yscale*p0.y/p0.w), vec2(xscale*p2.x/p2.w, yscale*p2.y/p2.w));\n" + " float s = (a + b + c) / 2.0;\n" + " float A = sqrt(s*(s-a)*(s-b)*(s-c));\n" + " float ha = 2.0*A/a;\n" + " gl_Position = p0;\n" + " tp = mask * ha;\n" + " tr = trig;\n" + " vec3 normal, lightDir;\n" + " normal = normalize(gl_NormalMatrix * gl_Normal);\n" + " lightDir = normalize(vec3(gl_LightSource[0].position));\n" + " shading = abs(dot(normal, lightDir));\n" + "}\n"; + + const char *fs_source = + "uniform vec4 color1, color2;\n" + "varying vec3 tp, tr, tmp;\n" + "varying float shading;\n" + "void main() {\n" + " gl_FragColor = vec4(color1.r * shading, color1.g * shading, color1.b * shading, color1.a);\n" + " if (tp.x < tr.x || tp.y < tr.y || tp.z < tr.z)\n" + " gl_FragColor = color2;\n" + "}\n"; + + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs, 1, (const GLchar**)&vs_source, NULL); + glCompileShader(vs); + + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs, 1, (const GLchar**)&fs_source, NULL); + glCompileShader(fs); + + GLuint edgeshader_prog = glCreateProgram(); + glAttachShader(edgeshader_prog, vs); + glAttachShader(edgeshader_prog, fs); + glLinkProgram(edgeshader_prog); + + glview->shaderinfo[0] = edgeshader_prog; + glview->shaderinfo[1] = glGetUniformLocation(edgeshader_prog, "color1"); + glview->shaderinfo[2] = glGetUniformLocation(edgeshader_prog, "color2"); + glview->shaderinfo[3] = glGetAttribLocation(edgeshader_prog, "trig"); + glview->shaderinfo[4] = glGetAttribLocation(edgeshader_prog, "pos_b"); + glview->shaderinfo[5] = glGetAttribLocation(edgeshader_prog, "pos_c"); + glview->shaderinfo[6] = glGetAttribLocation(edgeshader_prog, "mask"); + glview->shaderinfo[7] = glGetUniformLocation(edgeshader_prog, "xscale"); + glview->shaderinfo[8] = glGetUniformLocation(edgeshader_prog, "yscale"); + + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + fprintf(stderr, "OpenGL Error: %s\n", gluErrorString(err)); + } + + GLint status; + glGetProgramiv(edgeshader_prog, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + int loglen; + char logbuffer[1000]; + glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer); + fprintf(stderr, "OpenGL Program Linker Error:\n%.*s", loglen, logbuffer); + } else { + int loglen; + char logbuffer[1000]; + glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer); + if (loglen > 0) { + fprintf(stderr, "OpenGL Program Link OK:\n%.*s", loglen, logbuffer); + } + glValidateProgram(edgeshader_prog); + glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer); + if (loglen > 0) { + fprintf(stderr, "OpenGL Program Validation results:\n%.*s", loglen, logbuffer); + } + } + } + glview->shaderinfo[9] = glview->width; + glview->shaderinfo[10] = glview->height; +} + int csgtestcore(int argc, char *argv[], test_type_e test_type) { - if (argc != 3) { - fprintf(stderr, "Usage: %s <file.scad> <output.png>\n", argv[0]); + bool sysinfo_dump = false; + const char *filename, *outfilename = NULL; + po::variables_map vm; + try { + vm = parse_options(argc, argv); + } catch ( po::error e ) { + cerr << "error parsing options\n"; + } + if (vm.count("info")) sysinfo_dump = true; + if (vm.count("input-file")) + filename = vm["input-file"].as< vector<string> >().begin()->c_str(); + if (vm.count("output-file")) + outfilename = vm["output-file"].as< vector<string> >().begin()->c_str(); + + if ((!filename || !outfilename) && !sysinfo_dump) { + cerr << "Usage: " << argv[0] << " <file.scad> <output.png>\n"; exit(1); } - const char *filename = argv[1]; - const char *outfilename = argv[2]; - Builtins::instance()->initialize(); QApplication app(argc, argv, false); @@ -107,7 +280,11 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) AbstractModule *root_module; ModuleInstantiation root_inst; - root_module = parsefile(filename); + if (sysinfo_dump) + root_module = parse("sphere();","",false); + else + root_module = parsefile(filename); + if (!root_module) { exit(1); } @@ -188,6 +365,9 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i. Exiting.\n", error); exit(1); } + enable_opencsg_shaders(csgInfo.glview); + + if (sysinfo_dump) cout << info_dump(csgInfo.glview); BoundingBox bbox = csgInfo.root_chain->getBoundingBox(); Vector3d center = (bbox.min() + bbox.max()) / 2; @@ -206,8 +386,11 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) else csgInfo.glview->setRenderer(&opencsgRenderer); - csgInfo.glview->paintGL(); + OpenCSG::setContext(0); + OpenCSG::setOption(OpenCSG::OffscreenSetting, OpenCSG::FrameBufferObject); + csgInfo.glview->paintGL(); + csgInfo.glview->save(outfilename); delete root_node; diff --git a/tests/fbo.cc b/tests/fbo.cc index 2a3342d..a6677c1 100644 --- a/tests/fbo.cc +++ b/tests/fbo.cc @@ -93,6 +93,7 @@ bool fbo_ext_init(fbo_t *fbo, size_t width, size_t height) glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthbuf_id); if (report_glerror("specifying depth render buffer EXT")) return false; + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthbuf_id); if (report_glerror("specifying stencil render buffer EXT")) return false; @@ -142,7 +143,12 @@ bool fbo_arb_init(fbo_t *fbo, size_t width, size_t height) return false; } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + // to prevent Mesa's software renderer from crashing, do this in two stages. + // ie. instead of using GL_DEPTH_STENCIL_ATTACHMENT, do DEPTH then STENCIL. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, fbo->depthbuf_id); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->depthbuf_id); if (report_glerror("specifying depth stencil render buffer")) return false; @@ -183,24 +189,25 @@ bool fbo_resize(fbo_t *fbo, size_t width, size_t height) glBindRenderbufferEXT(GL_RENDERBUFFER, fbo->depthbuf_id); if (glewIsSupported("GL_EXT_packed_depth_stencil")) { glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); - if (report_glerror("creating depth stencil render buffer")) return false; + if (report_glerror("creating EXT depth stencil render buffer")) return false; } else { glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); - if (report_glerror("creating depth render buffer")) return false; + if (report_glerror("creating EXT depth render buffer")) return false; } glBindRenderbufferEXT(GL_RENDERBUFFER, fbo->renderbuf_id); glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA8, width, height); - if (report_glerror("creating color render buffer")) return false; + if (report_glerror("creating EXT color render buffer")) return false; } else { + glBindRenderbuffer(GL_RENDERBUFFER, fbo->renderbuf_id); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); + if (report_glerror("creating color render buffer")) return false; + glBindRenderbuffer(GL_RENDERBUFFER, fbo->depthbuf_id); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); if (report_glerror("creating depth stencil render buffer")) return false; - glBindRenderbuffer(GL_RENDERBUFFER, fbo->renderbuf_id); - glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); - if (report_glerror("creating color render buffer")) return false; } return true; diff --git a/tests/system-gl.cc b/tests/system-gl.cc index bdf3bf9..2e3f3bc 100644 --- a/tests/system-gl.cc +++ b/tests/system-gl.cc @@ -2,35 +2,40 @@ /* OpenGL helper functions */ #include <iostream> +#include <sstream> +#include <string> #include "system-gl.h" #include <boost/algorithm/string.hpp> using namespace std; using namespace boost; -void glew_dump(bool dumpall) { -#ifdef DEBUG - cerr << "GLEW version: " << glewGetString(GLEW_VERSION) << endl - << "Renderer: " << (const char *)glGetString(GL_RENDERER) << endl - << "Vendor: " << (const char *)glGetString(GL_VENDOR) << endl - << "OpenGL version: " << (const char *)glGetString(GL_VERSION) << endl; +string glew_dump(bool dumpall) +{ + stringstream out; + out << "GLEW version: " << glewGetString(GLEW_VERSION) << endl + << "GL Renderer: " << (const char *)glGetString(GL_RENDERER) << endl + << "GL Vendor: " << (const char *)glGetString(GL_VENDOR) << endl + << "OpenGL Version: " << (const char *)glGetString(GL_VERSION) << endl; + out << "GL Extensions: " << endl; if (dumpall) { string extensions((const char *)glGetString(GL_EXTENSIONS)); replace_all( extensions, " ", "\n " ); - cerr << "Extensions: " << endl << " " << extensions << endl; + out << " " << extensions << endl; } - cerr << " GL_ARB_framebuffer_object: " - << (glewIsSupported("GL_ARB_framebuffer_object") ? "yes" : "no") - << endl - << " GL_EXT_framebuffer_object: " - << (glewIsSupported("GL_EXT_framebuffer_object") ? "yes" : "no") - << endl - << " GL_EXT_packed_depth_stencil: " - << (glewIsSupported("GL_EXT_packed_depth_stencil") ? "yes" : "no") - << endl; -#endif + out << "GL_ARB_framebuffer_object: " + << (glewIsSupported("GL_ARB_framebuffer_object") ? "yes" : "no") + << endl + << "GL_EXT_framebuffer_object: " + << (glewIsSupported("GL_EXT_framebuffer_object") ? "yes" : "no") + << endl + << "GL_EXT_packed_depth_stencil: " + << (glewIsSupported("GL_EXT_packed_depth_stencil") ? "yes" : "no") + << endl; + + return out.str(); }; bool report_glerror(const char * function) diff --git a/tests/system-gl.h b/tests/system-gl.h index b41e32c..4a8ccac 100644 --- a/tests/system-gl.h +++ b/tests/system-gl.h @@ -2,8 +2,9 @@ #define SYSTEMGL_H_ #include <GL/glew.h> +#include <string> -void glew_dump(bool dumpall = false); +std::string glew_dump(bool dumpall=false); bool report_glerror(const char *task); #endif diff --git a/tests/test_cmdline_tool.py b/tests/test_cmdline_tool.py index 8b49f78..848a6eb 100755 --- a/tests/test_cmdline_tool.py +++ b/tests/test_cmdline_tool.py @@ -26,6 +26,7 @@ import re import getopt import shutil import platform +import string def initialize_environment(): if not options.generate: options.generate = bool(os.getenv("TEST_GENERATE")) @@ -35,6 +36,7 @@ def init_expected_filename(testname, cmd): global expecteddir, expectedfilename expecteddir = os.path.join(options.regressiondir, os.path.split(cmd)[1]) expectedfilename = os.path.join(expecteddir, testname + "-expected." + options.suffix) + expectedfilename = os.path.normpath( expectedfilename ) def verify_test(testname, cmd): global expectedfilename @@ -47,7 +49,7 @@ def verify_test(testname, cmd): def execute_and_redirect(cmd, params, outfile): retval = -1 try: - proc = subprocess.Popen([cmd] + params, stdout=outfile) + proc = subprocess.Popen([cmd] + params, stdout=outfile, stderr=subprocess.STDOUT) out = proc.communicate()[0] retval = proc.wait() except: @@ -66,32 +68,52 @@ def compare_text(expected, actual): return get_normalized_text(expected) == get_normalized_text(actual) def compare_default(resultfilename): + print >> sys.stderr, 'diff text compare: ' + print >> sys.stderr, ' expected textfile: ', expectedfilename + print >> sys.stderr, ' actual textfile: ', resultfilename if not compare_text(expectedfilename, resultfilename): execute_and_redirect("diff", [expectedfilename, resultfilename], sys.stderr) return False return True def compare_png(resultfilename): + compare_method = 'pixel' + #args = [expectedfilename, resultfilename, "-alpha", "Off", "-compose", "difference", "-composite", "-threshold", "10%", "-blur", "2", "-threshold", "30%", "-format", "%[fx:w*h*mean]", "info:"] + args = [expectedfilename, resultfilename, "-alpha", "Off", "-compose", "difference", "-composite", "-threshold", "10%", "-morphology", "Erode", "Square", "-format", "%[fx:w*h*mean]", "info:"] + + # for systems with older imagemagick that doesnt support '-morphology' + # http://www.imagemagick.org/Usage/morphology/#alturnative + if options.comparator == 'old': + args = [expectedfilename, resultfilename, "-alpha", "Off", "-compose", "difference", "-composite", "-threshold", "10%", "-gaussian-blur","3x65535", "-threshold", "99.99%", "-format", "%[fx:w*h*mean]", "info:"] + + if options.comparator == 'ncc': + # for systems where imagemagick crashes when using the above comparators + args = [expectedfilename, resultfilename, "-alpha", "Off", "-compose", "difference", "-metric", "NCC", "tmp.png"] + options.convert_exec = 'compare' + compare_method = 'NCC' + + msg = 'ImageMagick image comparison: ' + options.convert_exec + ' '+ ' '.join(args[2:]) + msg += '\nexpected image: ' + expectedfilename + '\n' + print >> sys.stderr, msg if not resultfilename: - print >> sys.stderr, "Error: OpenSCAD did not generate an image" + print >> sys.stderr, "Error: OpenSCAD did not generate an image to test" return False + print >> sys.stderr, ' actual image: ', resultfilename -# args = [expectedfilename, resultfilename, "-alpha", "Off", "-compose", "difference", "-composite", "-threshold", "10%", "-blur", "2", "-threshold", "30%", "-format", "%[fx:w*h*mean]", "info:"] - args = [expectedfilename, resultfilename, "-alpha", "Off", "-compose", "difference", "-composite", "-threshold", "10%", "-morphology", "Erode", "Square", "-format", "%[fx:w*h*mean]", "info:"] - print >> sys.stderr, 'convert ', ' '.join(args) - (retval, output) = execute_and_redirect("convert", args, subprocess.PIPE) + (retval, output) = execute_and_redirect(options.convert_exec, args, subprocess.PIPE) + print "Imagemagick return", retval, "output:", output if retval == 0: - pixelerr = int(float(output.strip())) - if pixelerr < 32: return True - else: print >> sys.stderr, pixelerr, ' pixel errors' + if compare_method=='pixel': + pixelerr = int(float(output.strip())) + if pixelerr < 32: return True + else: print >> sys.stderr, pixelerr, ' pixel errors' + elif compare_method=='NCC': + thresh = 0.95 + ncc_err = float(output.strip()) + if ncc_err > thresh: return True + else: print >> sys.stderr, ncc_err, ' Images differ: NCC comparison < ', thresh return False -# Old compare solution, based on yee_compare -# print >> sys.stderr, 'Yee image compare: ', expectedfilename, ' ', resultfilename -# if execute_and_redirect("./yee_compare", [expectedfilename, resultfilename, "-downsample", "1", "-threshold", "150"], sys.stderr) != 0: -# return False -# return True - def compare_with_expected(resultfilename): if not options.generate: if "compare_" + options.suffix in globals(): return globals()["compare_" + options.suffix](resultfilename) @@ -143,11 +165,12 @@ def usage(): print >> sys.stderr, " -g, --generate Generate expected output for the given tests" print >> sys.stderr, " -s, --suffix=<suffix> Write -expected and -actual files with the given suffix instead of .txt" print >> sys.stderr, " -t, --test=<name> Specify test name instead of deducting it from the argument" + print >> sys.stderr, " -c, --convexec=<name> Path to ImageMagick 'convert' executable" if __name__ == '__main__': # Handle command-line arguments try: - opts, args = getopt.getopt(sys.argv[1:], "gs:t:", ["generate", "suffix=", "test="]) + opts, args = getopt.getopt(sys.argv[1:], "gs:c:t:m:", ["generate", "convexec=", "suffix=", "test=", "comparator="]) except getopt.GetoptError, err: usage() sys.exit(2) @@ -165,6 +188,10 @@ if __name__ == '__main__': else: options.suffix = a elif o in ("-t", "--test"): options.testname = a + elif o in ("-c", "--convexec"): + options.convert_exec = os.path.normpath( a ) + elif o in ("-m", "--comparator"): + options.comparator = a # <cmdline-tool> and <argument> if len(args) < 2: diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py new file mode 100755 index 0000000..fa8b390 --- /dev/null +++ b/tests/test_pretty_print.py @@ -0,0 +1,484 @@ +#!/usr/bin/python + +# Copyright (C) 2011 Don Bright <hugh.m.bright@gmail.com> +# +# 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 2 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# +# This program 'pretty prints' the ctest output, namely +# files from builddir/Testing/Temporary. +# html & wiki output are produced in Testing/Temporary/sysid_report +# +# experimental wiki uploading is available by running +# +# python test_pretty_print.py --upload +# + +# Design philosophy +# +# 1. parse the data (images, logs) into easy-to-use data structures +# 2. wikifiy the data +# 3. save the wikified data to disk + +# todo +# do something if tests for GL extensions for OpenCSG fail (test fail, no image production) +# copy all images, sysinfo.txt to bundle for html/upload (images +# can be altered by subsequent runs) +# figure out hwo to make the thing run after the test +# figure out how CTEST treats the logfiles. +# why is hash differing +# instead of having special '-info' prerun, put it as yet-another-test +# and parse the log +# fix windows so that it won't keep asking 'this program crashed' over and over. +# (you can set this in the registry to never happen, but itd be better if the program +# itself was able to disable that temporarily in it's own process) + +import string,sys,re,os,hashlib,subprocess,textwrap,time + +def tryread(filename): + data = None + try: + f = open(filename,'rb') + data = f.read() + f.close() + except: + print 'couldn\'t open ',filename + return data + +def trysave(filename,data): + try: + if not os.path.isdir(os.path.dirname(filename)): + #print 'creating',os.path.dirname(filename) + os.mkdir(os.path.dirname(filename)) + f=open(filename,'wb') + f.write(data) + f.close() + except: + print 'problem writing to',filename + return None + return True + +def ezsearch(pattern,str): + x = re.search(pattern,str,re.DOTALL|re.MULTILINE) + if x and len(x.groups())>0: return x.group(1).strip() + return '' + +def read_gitinfo(): + # won't work if run from outside of branch. + data = subprocess.Popen(['git','remote','-v'],stdout=subprocess.PIPE).stdout.read() + origin = ezsearch('^origin *?(.*?)\(fetch.*?$',data) + upstream = ezsearch('^upstream *?(.*?)\(fetch.*?$',data) + data = subprocess.Popen(['git','branch'],stdout=subprocess.PIPE).stdout.read() + branch = ezsearch('^\*(.*?)$',data) + out = 'Git branch: ' + branch + ' from origin ' + origin + '\n' + out += 'Git upstream: ' + upstream + '\n' + return out + +def read_sysinfo(filename): + data = tryread(filename) + if not data: return 'sysinfo: unknown' + + machine = ezsearch('Machine:(.*?)\n',data) + machine = machine.replace(' ','-').replace('/','-') + + osinfo = ezsearch('OS info:(.*?)\n',data) + osplain = osinfo.split(' ')[0].strip().replace('/','-') + if 'windows' in osinfo.lower(): osplain = 'win' + + renderer = ezsearch('GL Renderer:(.*?)\n',data) + tmp = renderer.split(' ') + tmp = string.join(tmp[0:3],'-') + tmp = tmp.split('/')[0] + renderer = tmp + + data += read_gitinfo() + + data += 'Image comparison: ImageMagick' + + data = data.strip() + + # create 4 letter hash and stick on end of sysid + nondate_data = re.sub("\n.*?ompile date.*?\n","\n",data).strip() + hexhash = hashlib.md5() + hexhash.update(nondate_data) + hexhash = hexhash.hexdigest()[-4:].upper() + hash = '' + for c in hexhash: hash += chr(ord(c)+97-48) + + sysid = osplain + '_' + machine + '_' + renderer + '_' + hash + sysid = sysid.lower() + + return data, sysid + +class Test: + def __init__(self,fullname,time,passed,output,type,actualfile,expectedfile,scadfile,log): + self.fullname,self.time,self.passed,self.output = \ + fullname, time, passed, output + self.type, self.actualfile, self.expectedfile, self.scadfile = \ + type, actualfile, expectedfile, scadfile + self.fulltestlog = log + + def __str__(self): + x = 'fullname: ' + self.fullname + x+= '\nactualfile: ' + self.actualfile + x+= '\nexpectedfile: ' + self.expectedfile + x+= '\ntesttime: ' + self.time + x+= '\ntesttype: ' + self.type + x+= '\npassed: ' + str(self.passed) + x+= '\nscadfile: ' + self.scadfile + x+= '\noutput bytes: ' + str(len(self.output)) + x+= '\ntestlog bytes: ' + str(len(self.fulltestlog)) + x+= '\n' + return x + +def parsetest(teststring): + patterns = ["Test:(.*?)\n", # fullname + "Test time =(.*?) sec\n", + "Test time.*?Test (Passed)", # pass/fail + "Output:(.*?)<end of output>", + 'Command:.*?-s" "(.*?)"', # type + "actual .*?:(.*?)\n", + "expected .*?:(.*?)\n", + 'Command:.*?(testdata.*?)"' # scadfile + ] + hits = map( lambda pattern: ezsearch(pattern,teststring), patterns ) + test = Test(hits[0],hits[1],hits[2]=='Passed',hits[3],hits[4],hits[5],hits[6],hits[7],teststring) + test.actualfile_data = tryread(test.actualfile) + test.expectedfile_data = tryread(test.expectedfile) + return test + +def parselog(data): + startdate = ezsearch('Start testing: (.*?)\n',data) + enddate = ezsearch('End testing: (.*?)\n',data) + pattern = '([0-9]*/[0-9]* Testing:.*?time elapsed.*?\n)' + test_chunks = re.findall(pattern,data,re.S) + tests = map( parsetest, test_chunks ) + tests = sorted(tests, key = lambda t:t.passed) + return startdate, tests, enddate + +def load_makefiles(builddir): + filelist = [] + for root, dirs, files in os.walk(builddir): + for fname in files: filelist += [ os.path.join(root, fname) ] + files = filter(lambda x: 'build.make' in os.path.basename(x), filelist) + files += filter(lambda x: 'flags.make' in os.path.basename(x), filelist) + files = filter(lambda x: 'esting' not in x and 'emporary' not in x, files) + result = {} + for fname in files: + result[fname.replace(builddir,'')] = open(fname,'rb').read() + return result + +def wikify_filename(fname, wiki_rootpath, sysid): + wikifname = fname.replace('/','_').replace('\\','_').strip('.') + return wiki_rootpath + '_' + sysid + '_' + wikifname + +def towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles): + + wiki_template = """ +<h3>[[WIKI_ROOTPATH]] test run report</h3> + +'''Sysid''': SYSID + +'''Result summary''': NUMPASSED / NUMTESTS tests passed ( PERCENTPASSED % ) <br> + +'''System info''': +<pre> +SYSINFO +</pre> + +start time: STARTDATE <br> +end time : ENDDATE <br> + +'''Image tests''' + +<REPEAT1> +{| border=1 cellspacing=0 cellpadding=1 +|- +| colspan=2 | FTESTNAME +|- +| Expected image || Actual image +|- +| [[File:EXPECTEDFILE|250px]] || ACTUALFILE_WIKI +|} + +<pre> +TESTLOG +</pre> + + + +</REPEAT1> + + +'''Text tests''' + +<REPEAT2> +{|border=1 cellspacing=0 cellpadding=1 +|- +| FTESTNAME +|} + +<pre> +TESTLOG +</pre> + + +</REPEAT2> + +'''build.make and flags.make''' +<REPEAT3> +*[[MAKEFILE_NAME]] +</REPEAT3> +""" + txtpages = {} + imgs = {} + passed_tests = filter(lambda x: x.passed, tests) + failed_tests = filter(lambda x: not x.passed, tests) + percent = str(int(100.0*len(passed_tests) / len(tests))) + s = wiki_template + repeat1 = ezsearch('(<REPEAT1>.*?</REPEAT1>)',s) + repeat2 = ezsearch('(<REPEAT2>.*?</REPEAT2>)',s) + repeat3 = ezsearch('(<REPEAT3>.*?</REPEAT3>)',s) + dic = { 'STARTDATE': startdate, 'ENDDATE': enddate, 'WIKI_ROOTPATH': wiki_rootpath, + 'SYSINFO': sysinfo, 'SYSID':sysid, + 'NUMTESTS':len(tests), 'NUMPASSED':len(passed_tests), 'PERCENTPASSED':percent } + for key in dic.keys(): + s = s.replace(key,str(dic[key])) + for t in tests: + if t.type=='txt': + newchunk = re.sub('FTESTNAME',t.fullname,repeat2) + newchunk = newchunk.replace('TESTLOG',t.fulltestlog) + s = s.replace(repeat2, newchunk+repeat2) + elif t.type=='png': + tmp = t.actualfile.replace(builddir,'') + wikiname_a = wikify_filename(tmp,wiki_rootpath,sysid) + tmp = t.expectedfile.replace(os.path.dirname(builddir),'') + wikiname_e = wikify_filename(tmp,wiki_rootpath,sysid) + imgs[wikiname_e] = t.expectedfile_data + if t.actualfile: + actualfile_wiki = '[[File:'+wikiname_a+'|250px]]' + imgs[wikiname_a] = t.actualfile_data + else: + actualfile_wiki = 'No image generated.' + newchunk = re.sub('FTESTNAME',t.fullname,repeat1) + newchunk = newchunk.replace('ACTUALFILE_WIKI',actualfile_wiki) + newchunk = newchunk.replace('EXPECTEDFILE',wikiname_e) + newchunk = newchunk.replace('TESTLOG',t.fulltestlog) + s = s.replace(repeat1, newchunk+repeat1) + + makefiles_wikinames = {} + for mf in sorted(makefiles.keys()): + tmp = mf.replace('CMakeFiles','').replace('.dir','') + wikiname = wikify_filename(tmp,wiki_rootpath,sysid) + newchunk = re.sub('MAKEFILE_NAME',wikiname,repeat3) + s = s.replace(repeat3, newchunk+repeat3) + makefiles_wikinames[mf] = wikiname + + s = s.replace(repeat1,'') + s = s.replace(repeat2,'') + s = s.replace(repeat3,'') + s = re.sub('<REPEAT.*?>\n','',s) + s = re.sub('</REPEAT.*?>','',s) + + mainpage_wikiname = wiki_rootpath + '_' + sysid + '_test_report' + txtpages[ mainpage_wikiname ] = s + for mf in sorted(makefiles.keys()): + txtpages[ makefiles_wikinames[ mf ] ] = '\n*Subreport from [['+mainpage_wikiname+']]\n\n\n<pre>\n'+makefiles[mf]+'\n</pre>' + + return imgs, txtpages + +def tohtml(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles): + # kludge. assume wiki stuff has alreayd run and dumped files properly + head = '<html><head><title>'+wiki_rootpath+' test run for '+sysid +'</title></head><body>' + tail = '</body></html>' + + passed_tests = filter(lambda x: x.passed, tests) + failed_tests = filter(lambda x: not x.passed, tests) + percent = str(int(100.0*len(passed_tests) / len(tests))) + + s='' + + s+= '\n<pre>' + s+= '\nSYSINFO\n'+ sysinfo + s+= '\n</pre><p>' + + s+= '\n<pre>' + s+= '\nSTARTDATE: '+ startdate + s+= '\nENDDATE: '+ enddate + s+= '\nWIKI_ROOTPATH: '+ wiki_rootpath + s+= '\nSYSID: '+sysid + s+= '\nNUMTESTS: '+str(len(tests)) + s+= '\nNUMPASSED: '+str(len(passed_tests)) + s+= '\nPERCENTPASSED: '+ percent + s+= '\n</pre>' + + for t in tests: + if t.type=='txt': + s+='\n<pre>'+t.fullname+'</pre>\n' + s+='<p><pre>'+t.fulltestlog+'</pre>\n\n' + elif t.type=='png': + tmp = t.actualfile.replace(builddir,'') + wikiname_a = wikify_filename(tmp,wiki_rootpath,sysid) + tmp = t.expectedfile.replace(os.path.dirname(builddir),'') + wikiname_e = wikify_filename(tmp,wiki_rootpath,sysid) + s+='<table>' + s+='\n<tr><td colspan=2>'+t.fullname + s+='\n<tr><td>Expected<td>Actual' + s+='\n<tr><td><img src='+wikiname_e+' width=250/>' + s+='\n <td><img src='+wikiname_a+' width=250/>' + s+='\n</table>' + s+='\n<pre>' + s+=t.fulltestlog + s+='\n</pre>' + + s+='\n\n<p>\n\n' + makefiles_wikinames = {} + for mf in sorted(makefiles.keys()): + tmp = mf.replace('CMakeFiles','').replace('.dir','') + wikiname = wikify_filename(tmp,wiki_rootpath,sysid) + s += '\n<a href='+wikiname+'>'+wikiname+'</a><br>' + s+='\n' + + return head + s + tail + +def wiki_login(wikiurl,api_php_path,botname,botpass): + site = mwclient.Site(wikiurl,api_php_path) + site.login(botname,botpass) + return site + +def wiki_upload(wikiurl,api_php_path,botname,botpass,filedata,wikipgname): + counter = 0 + done = False + descrip = 'test' + time.sleep(1) + while not done: + try: + print 'login',botname,'to',wikiurl + site = wiki_login(wikiurl,api_php_path,botname,botpass) + print 'uploading...', + if wikipgname.endswith('png'): + site.upload(filedata,wikipgname,descrip,ignore=True) + else: + page = site.Pages[wikipgname] + text = page.edit() + page.save(filedata) + done = True + print 'transfer ok' + except Exception, e: + print 'Error:', type(e),e + counter += 1 + if counter>maxretry: + print 'giving up. please try a different wiki site' + done = True + else: + print 'wiki',wikiurl,'down. retrying in 15 seconds' + time.sleep(15) + +def upload(wikiurl,api_php_path='/',wiki_rootpath='test', sysid='null', botname='cakebaby',botpass='anniew',wikidir='.',dryrun=True): + wetrun = not dryrun + if dryrun: print 'dry run' + try: + global mwclient + import mwclient + except: + print 'please download mwclient 0.6.5 and unpack here:', os.getcwd() + sys.exit() + + if wetrun: site = wiki_login(wikiurl,api_php_path,botname,botpass) + + wikifiles = os.listdir(wikidir) + testreport_page = filter( lambda x: 'test_report' in x, wikifiles ) + if (len(testreport_page)>1): + print 'multiple test reports found, please clean dir',wikidir + sys.exit() + + rootpage = testreport_page[0] + print 'add',rootpage,' to main report page ',wiki_rootpath + if wetrun: + page = site.Pages[wiki_rootpath] + text = page.edit() + if not '[['+rootpage+']]' in text: + page.save(text +'\n*[['+rootpage+']]\n') + + wikifiles = os.listdir(wikidir) + wikifiles = filter(lambda x: not x.endswith('html'), wikifiles) + + print 'upload wiki pages:' + for wikiname in wikifiles: + filename = os.path.join(wikidir,wikiname) + filedata = tryread(filename) + print 'upload',len(filedata),'bytes from',wikiname + if wetrun: + wiki_upload(wikiurl,api_php_path,botname,botpass,filedata,wikiname) + +def findlogfile(builddir): + logpath = os.path.join(builddir,'Testing','Temporary') + logfilename = os.path.join(logpath,'LastTest.log.tmp') + if not os.path.isfile(logfilename): + logfilename = os.path.join(logpath,'LastTest.log') + if not os.path.isfile(logfilename): + print 'cant find and/or open logfile',logfilename + sys.exit() + return logpath, logfilename + +def main(): + dry = False + if verbose: print 'running test_pretty_print' + if '--dryrun' in sys.argv: dry=True + suffix = ezsearch('--suffix=(.*?) ',string.join(sys.argv)+' ') + builddir = ezsearch('--builddir=(.*?) ',string.join(sys.argv)+' ') + if builddir=='': builddir=os.getcwd() + if verbose: print 'build dir set to', builddir + + sysinfo, sysid = read_sysinfo(os.path.join(builddir,'sysinfo.txt')) + makefiles = load_makefiles(builddir) + logpath, logfilename = findlogfile(builddir) + testlog = tryread(logfilename) + startdate, tests, enddate = parselog(testlog) + if verbose: + print 'found sysinfo.txt,', + print 'found', len(makefiles),'makefiles,', + print 'found', len(tests),'test results' + + imgs, txtpages = towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles) + + wikidir = os.path.join(logpath,sysid+'_report') + if verbose: print 'erasing files in',wikidir + try: map(lambda x:os.remove(os.path.join(wikidir,x)), os.listdir(wikidir)) + except: pass + print 'writing',len(imgs),'images and',len(txtpages),'text pages to:\n', ' .'+wikidir.replace(os.getcwd(),'') + for pgname in sorted(imgs): trysave( os.path.join(wikidir,pgname), imgs[pgname]) + for pgname in sorted(txtpages): trysave( os.path.join(wikidir,pgname), txtpages[pgname]) + + htmldata = tohtml(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles) + trysave( os.path.join(wikidir,'index.html'), htmldata ) + + if '--upload' in sys.argv: + upload(wikisite,wiki_api_path,wiki_rootpath,sysid,'openscadbot', + 'tobdacsnepo',wikidir,dryrun=dry) + print 'upload attempt complete' + + if verbose: print 'test_pretty_print complete' + +#wikisite = 'cakebaby.referata.com' +#wiki_api_path = '' +wikisite = 'cakebaby.wikia.com' +wiki_api_path = '/' +wiki_rootpath = 'OpenSCAD' +builddir = os.getcwd() # os.getcwd()+'/build' +verbose = False +maxretry = 10 + +main() diff --git a/tests/yee_compare.cpp b/tests/yee_compare.cpp deleted file mode 100644 index 9de4720..0000000 --- a/tests/yee_compare.cpp +++ /dev/null @@ -1,681 +0,0 @@ -// modified from PerceptualDiff source for OpenSCAD, 2011 September - -#include "yee_compare.h" -#include "lodepng.h" -#include <cstdlib> -#include <cstring> -#include <cstdio> -#include <math.h> - -static const char* copyright = -"PerceptualDiff version 1.1.1, Copyright (C) 2006 Yangli Hector Yee\n\ -PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\ -This is free software, and you are welcome\n\ -to redistribute it under certain conditions;\n\ -See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n"; - -static const char *usage = -"PeceptualDiff image1.tif image2.tif\n\n\ - Compares image1.tif and image2.tif using a perceptually based image metric\n\ - Options:\n\ -\t-verbose : Turns on verbose mode\n\ -\t-fov deg : Field of view in degrees (0.1 to 89.9)\n\ -\t-threshold p : #pixels p below which differences are ignored\n\ -\t-gamma g : Value to convert rgb into linear space (default 2.2)\n\ -\t-luminance l : White luminance (default 100.0 cdm^-2)\n\ -\t-luminanceonly : Only consider luminance; ignore chroma (color) in the comparison\n\ -\t-colorfactor : How much of color to use, 0.0 to 1.0, 0.0 = ignore color.\n\ -\t-downsample : How many powers of two to down sample the image.\n\ -\t-output o.ppm : Write difference to the file o.ppm\n\ -\n\ -\n Note: Input or Output files can also be in the PNG or JPG format or any format\ -\n that FreeImage supports.\ -\n"; - -CompareArgs::CompareArgs() -{ - ImgA = NULL; - ImgB = NULL; - ImgDiff = NULL; - Verbose = false; - LuminanceOnly = false; - FieldOfView = 45.0f; - Gamma = 2.2f; - ThresholdPixels = 100; - Luminance = 100.0f; - ColorFactor = 1.0f; - DownSample = 0; -} - -CompareArgs::~CompareArgs() -{ - if (ImgA) delete ImgA; - if (ImgB) delete ImgB; - if (ImgDiff) delete ImgDiff; -} - -bool CompareArgs::Parse_Args(int argc, char **argv) -{ - if (argc < 3) { - ErrorStr = copyright; - ErrorStr += usage; - return false; - } - int image_count = 0; - const char* output_file_name = NULL; - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "-fov") == 0) { - if (++i < argc) { - FieldOfView = (float) atof(argv[i]); - } - } else if (strcmp(argv[i], "-verbose") == 0) { - Verbose = true; - } else if (strcmp(argv[i], "-threshold") == 0) { - if (++i < argc) { - ThresholdPixels = atoi(argv[i]); - } - } else if (strcmp(argv[i], "-gamma") == 0) { - if (++i < argc) { - Gamma = (float) atof(argv[i]); - } - } else if (strcmp(argv[i], "-luminance") == 0) { - if (++i < argc) { - Luminance = (float) atof(argv[i]); - } - } else if (strcmp(argv[i], "-luminanceonly") == 0) { - LuminanceOnly = true; - } else if (strcmp(argv[i], "-colorfactor") == 0) { - if (++i < argc) { - ColorFactor = (float) atof(argv[i]); - } - } else if (strcmp(argv[i], "-downsample") == 0) { - if (++i < argc) { - DownSample = (int) atoi(argv[i]); - } - } else if (strcmp(argv[i], "-output") == 0) { - if (++i < argc) { - output_file_name = argv[i]; - } - } else if (image_count < 2) { - RGBAImage* img = RGBAImage::ReadFromFile(argv[i]); - if (!img) { - ErrorStr = "FAIL: Cannot open "; - ErrorStr += argv[i]; - ErrorStr += "\n"; - return false; - } else { - ++image_count; - if(image_count == 1) - ImgA = img; - else - ImgB = img; - } - } else { - fprintf(stderr, "Warning: option/file \"%s\" ignored\n", argv[i]); - } - } // i - if(!ImgA || !ImgB) { - ErrorStr = "FAIL: Not enough image files specified\n"; - return false; - } - for (int i = 0; i < DownSample; i++) { - if (Verbose) printf("Downsampling by %d\n", 1 << (i+1)); - RGBAImage *tmp = ImgA->DownSample(); - if (tmp) { - delete ImgA; - ImgA = tmp; - } - tmp = ImgB->DownSample(); - if (tmp) { - delete ImgB; - ImgB = tmp; - } - } - if(output_file_name) { - ImgDiff = new RGBAImage(ImgA->Get_Width(), ImgA->Get_Height(), output_file_name); - } - return true; -} - -void CompareArgs::Print_Args() -{ - printf("Field of view is %f degrees\n", FieldOfView); - printf("Threshold pixels is %d pixels\n", ThresholdPixels); - printf("The Gamma is %f\n", Gamma); - printf("The Display's luminance is %f candela per meter squared\n", Luminance); -} - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -LPyramid::LPyramid(float *image, int width, int height) : - Width(width), - Height(height) -{ - // Make the Laplacian pyramid by successively - // copying the earlier levels and blurring them - for (int i=0; i<MAX_PYR_LEVELS; i++) { - if (i == 0) { - Levels[i] = Copy(image); - } else { - Levels[i] = new float[Width * Height]; - Convolve(Levels[i], Levels[i - 1]); - } - } -} - -LPyramid::~LPyramid() -{ - for (int i=0; i<MAX_PYR_LEVELS; i++) { - if (Levels[i]) delete Levels[i]; - } -} - -float *LPyramid::Copy(float *img) -{ - int max = Width * Height; - float *out = new float[max]; - for (int i = 0; i < max; i++) out[i] = img[i]; - - return out; -} - -void LPyramid::Convolve(float *a, float *b) -// convolves image b with the filter kernel and stores it in a -{ - int y,x,i,j,nx,ny; - const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f}; - - for (y=0; y<Height; y++) { - for (x=0; x<Width; x++) { - int index = y * Width + x; - a[index] = 0.0f; - for (i=-2; i<=2; i++) { - for (j=-2; j<=2; j++) { - nx=x+i; - ny=y+j; - if (nx<0) nx=-nx; - if (ny<0) ny=-ny; - if (nx>=Width) nx=2*Width-nx-1; - if (ny>=Height) ny=2*Height-ny-1; - a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * Width + nx]; - } - } - } - } -} - -float LPyramid::Get_Value(int x, int y, int level) -{ - int index = x + y * Width; - int l = level; - if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS; - return Levels[level][index]; -} - - - -#ifndef M_PI -#define M_PI 3.14159265f -#endif - -/* -* Given the adaptation luminance, this function returns the -* threshold of visibility in cd per m^2 -* TVI means Threshold vs Intensity function -* This version comes from Ward Larson Siggraph 1997 -*/ - -float tvi(float adaptation_luminance) -{ - // returns the threshold luminance given the adaptation luminance - // units are candelas per meter squared - - float log_a, r, result; - log_a = log10f(adaptation_luminance); - - if (log_a < -3.94f) { - r = -2.86f; - } else if (log_a < -1.44f) { - r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f; - } else if (log_a < -0.0184f) { - r = log_a - 0.395f; - } else if (log_a < 1.9f) { - r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f; - } else { - r = log_a - 1.255f; - } - - result = powf(10.0f , r); - - return result; - -} - -// computes the contrast sensitivity function (Barten SPIE 1989) -// given the cycles per degree (cpd) and luminance (lum) -float csf(float cpd, float lum) -{ - float a, b, result; - - a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f); - b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f); - - result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd)); - - return result; -} - -/* -* Visual Masking Function -* from Daly 1993 -*/ -float mask(float contrast) -{ - float a, b, result; - a = powf(392.498f * contrast, 0.7f); - b = powf(0.0153f * a, 4.0f); - result = powf(1.0f + b, 0.25f); - - return result; -} - -// convert Adobe RGB (1998) with reference white D65 to XYZ -void AdobeRGBToXYZ(float r, float g, float b, float &x, float &y, float &z) -{ - // matrix is from http://www.brucelindbloom.com/ - x = r * 0.576700f + g * 0.185556f + b * 0.188212f; - y = r * 0.297361f + g * 0.627355f + b * 0.0752847f; - z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f; -} - -void XYZToLAB(float x, float y, float z, float &L, float &A, float &B) -{ - static float xw = -1; - static float yw; - static float zw; - // reference white - if (xw < 0) { - AdobeRGBToXYZ(1, 1, 1, xw, yw, zw); - } - const float epsilon = 216.0f / 24389.0f; - const float kappa = 24389.0f / 27.0f; - float f[3]; - float r[3]; - r[0] = x / xw; - r[1] = y / yw; - r[2] = z / zw; - for (int i = 0; i < 3; i++) { - if (r[i] > epsilon) { - f[i] = powf(r[i], 1.0f / 3.0f); - } else { - f[i] = (kappa * r[i] + 16.0f) / 116.0f; - } - } - L = 116.0f * f[1] - 16.0f; - A = 500.0f * (f[0] - f[1]); - B = 200.0f * (f[1] - f[2]); -} - -bool Yee_Compare(CompareArgs &args) -{ - if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) || - (args.ImgA->Get_Height() != args.ImgB->Get_Height())) { - args.ErrorStr = "Image dimensions do not match\n"; - return false; - } - - unsigned int i, dim; - dim = args.ImgA->Get_Width() * args.ImgA->Get_Height(); - bool identical = true; - for (i = 0; i < dim; i++) { - if (args.ImgA->Get(i) != args.ImgB->Get(i)) { - identical = false; - break; - } - } - if (identical) { - args.ErrorStr = "Images are binary identical\n"; - return true; - } - - // assuming colorspaces are in Adobe RGB (1998) convert to XYZ - float *aX = new float[dim]; - float *aY = new float[dim]; - float *aZ = new float[dim]; - float *bX = new float[dim]; - float *bY = new float[dim]; - float *bZ = new float[dim]; - float *aLum = new float[dim]; - float *bLum = new float[dim]; - - float *aA = new float[dim]; - float *bA = new float[dim]; - float *aB = new float[dim]; - float *bB = new float[dim]; - - if (args.Verbose) printf("Converting RGB to XYZ\n"); - - unsigned int x, y, w, h; - w = args.ImgA->Get_Width(); - h = args.ImgA->Get_Height(); - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - float r, g, b, l; - i = x + y * w; - r = powf(args.ImgA->Get_Red(i) / 255.0f, args.Gamma); - g = powf(args.ImgA->Get_Green(i) / 255.0f, args.Gamma); - b = powf(args.ImgA->Get_Blue(i) / 255.0f, args.Gamma); - AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]); - XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]); - r = powf(args.ImgB->Get_Red(i) / 255.0f, args.Gamma); - g = powf(args.ImgB->Get_Green(i) / 255.0f, args.Gamma); - b = powf(args.ImgB->Get_Blue(i) / 255.0f, args.Gamma); - AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]); - XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]); - aLum[i] = aY[i] * args.Luminance; - bLum[i] = bY[i] * args.Luminance; - } - } - - if (args.Verbose) printf("Constructing Laplacian Pyramids\n"); - - LPyramid *la = new LPyramid(aLum, w, h); - LPyramid *lb = new LPyramid(bLum, w, h); - - float num_one_degree_pixels = (float) (2 * tan( args.FieldOfView * 0.5 * M_PI / 180) * 180 / M_PI); - float pixels_per_degree = w / num_one_degree_pixels; - - if (args.Verbose) printf("Performing test\n"); - - float num_pixels = 1; - unsigned int adaptation_level = 0; - for (i = 0; i < MAX_PYR_LEVELS; i++) { - adaptation_level = i; - if (num_pixels > num_one_degree_pixels) break; - num_pixels *= 2; - } - - float cpd[MAX_PYR_LEVELS]; - cpd[0] = 0.5f * pixels_per_degree; - for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1]; - float csf_max = csf(3.248f, 100.0f); - - float F_freq[MAX_PYR_LEVELS - 2]; - for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f); - - unsigned int pixels_failed = 0; - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - int index = x + y * w; - float contrast[MAX_PYR_LEVELS - 2]; - float sum_contrast = 0; - for (i = 0; i < MAX_PYR_LEVELS - 2; i++) { - float n1 = fabsf(la->Get_Value(x,y,i) - la->Get_Value(x,y,i + 1)); - float n2 = fabsf(lb->Get_Value(x,y,i) - lb->Get_Value(x,y,i + 1)); - float numerator = (n1 > n2) ? n1 : n2; - float d1 = fabsf(la->Get_Value(x,y,i+2)); - float d2 = fabsf(lb->Get_Value(x,y,i+2)); - float denominator = (d1 > d2) ? d1 : d2; - if (denominator < 1e-5f) denominator = 1e-5f; - contrast[i] = numerator / denominator; - sum_contrast += contrast[i]; - } - if (sum_contrast < 1e-5) sum_contrast = 1e-5f; - float F_mask[MAX_PYR_LEVELS - 2]; - float adapt = la->Get_Value(x,y,adaptation_level) + lb->Get_Value(x,y,adaptation_level); - adapt *= 0.5f; - if (adapt < 1e-5) adapt = 1e-5f; - for (i = 0; i < MAX_PYR_LEVELS - 2; i++) { - F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt)); - } - float factor = 0; - for (i = 0; i < MAX_PYR_LEVELS - 2; i++) { - factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast; - } - if (factor < 1) factor = 1; - if (factor > 10) factor = 10; - float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(x,y,0)); - bool pass = true; - // pure luminance test - if (delta > factor * tvi(adapt)) { - pass = false; - } else if (!args.LuminanceOnly) { - // CIE delta E test with modifications - float color_scale = args.ColorFactor; - // ramp down the color test in scotopic regions - if (adapt < 10.0f) { - // Don't do color test at all. - color_scale = 0.0; - } - float da = aA[index] - bA[index]; - float db = aB[index] - bB[index]; - da = da * da; - db = db * db; - float delta_e = (da + db) * color_scale; - if (delta_e > factor) { - pass = false; - } - } - if (!pass) { - pixels_failed++; - if (args.ImgDiff) { - args.ImgDiff->Set(255, 0, 0, 255, index); - } - } else { - if (args.ImgDiff) { - args.ImgDiff->Set(0, 0, 0, 255, index); - } - } - } - } - - if (aX) delete[] aX; - if (aY) delete[] aY; - if (aZ) delete[] aZ; - if (bX) delete[] bX; - if (bY) delete[] bY; - if (bZ) delete[] bZ; - if (aLum) delete[] aLum; - if (bLum) delete[] bLum; - if (la) delete la; - if (lb) delete lb; - if (aA) delete aA; - if (bA) delete bA; - if (aB) delete aB; - if (bB) delete bB; - - char different[100]; - sprintf(different, "%d pixels are different\n", pixels_failed); - - // Always output image difference if requested. - if (args.ImgDiff) { - if (args.ImgDiff->WriteToFile(args.ImgDiff->Get_Name().c_str())) { - args.ErrorStr += "Wrote difference image to "; - args.ErrorStr+= args.ImgDiff->Get_Name(); - args.ErrorStr += "\n"; - } else { - args.ErrorStr += "Could not write difference image to "; - args.ErrorStr+= args.ImgDiff->Get_Name(); - args.ErrorStr += "\n"; - } - } - - if (pixels_failed < args.ThresholdPixels) { - args.ErrorStr = "Images are perceptually indistinguishable\n"; - args.ErrorStr += different; - return true; - } - - args.ErrorStr = "Images are visibly different\n"; - args.ErrorStr += different; - - return false; -} - -RGBAImage* RGBAImage::DownSample() const { - if (Width <=1 || Height <=1) return NULL; - int nw = Width / 2; - int nh = Height / 2; - RGBAImage* img = new RGBAImage(nw, nh, Name.c_str()); - for (int y = 0; y < nh; y++) { - for (int x = 0; x < nw; x++) { - int d[4]; - // Sample a 2x2 patch from the parent image. - d[0] = Get(2 * x + 0, 2 * y + 0); - d[1] = Get(2 * x + 1, 2 * y + 0); - d[2] = Get(2 * x + 0, 2 * y + 1); - d[3] = Get(2 * x + 1, 2 * y + 1); - int rgba = 0; - // Find the average color. - for (int i = 0; i < 4; i++) { - int c = (d[0] >> (8 * i)) & 0xFF; - c += (d[1] >> (8 * i)) & 0xFF; - c += (d[2] >> (8 * i)) & 0xFF; - c += (d[3] >> (8 * i)) & 0xFF; - c /= 4; - rgba |= (c & 0xFF) << (8 * i); - } - img->Set(x, y, rgba); - } - } - return img; -} - - -bool RGBAImage::WriteToFile(const char* filename) -{ - LodePNG::Encoder encoder; - encoder.addText("Comment","lodepng"); - encoder.getSettings().zlibsettings.windowSize = 2048; - - -/* - const FREE_IMAGE_FORMAT fileType = FreeImage_GetFIFFromFilename(filename); - if(FIF_UNKNOWN == fileType) - { - printf("Can't save to unknown filetype %s\n", filename); - return false; - } - - FIBITMAP* bitmap = FreeImage_Allocate(Width, Height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000); - if(!bitmap) - { - printf("Failed to create freeimage for %s\n", filename); - return false; - } - - const unsigned int* source = Data; - for( int y=0; y < Height; y++, source += Width ) - { - unsigned int* scanline = (unsigned int*)FreeImage_GetScanLine(bitmap, Height - y - 1 ); - memcpy(scanline, source, sizeof(source[0]) * Width); - } - - FreeImage_SetTransparent(bitmap, false); - FIBITMAP* converted = FreeImage_ConvertTo24Bits(bitmap); - - - const bool result = !!FreeImage_Save(fileType, converted, filename); - if(!result) - printf("Failed to save to %s\n", filename); - - FreeImage_Unload(converted); - FreeImage_Unload(bitmap); - return result; -*/ - return true; -} - -RGBAImage* RGBAImage::ReadFromFile(const char* filename) -{ - unsigned char* buffer; - unsigned char* image; - size_t buffersize, imagesize, i; - LodePNG_Decoder decoder; - - LodePNG_loadFile(&buffer, &buffersize, filename); /*load the image file with given filename*/ - LodePNG_Decoder_init(&decoder); - LodePNG_Decoder_decode(&decoder, &image, &imagesize, buffer, buffersize); /*decode the png*/ - - /*load and decode*/ - /*if there's an error, display it, otherwise display information about the image*/ - if(decoder.error) printf("error %u: %s\n", decoder.error, LodePNG_error_text(decoder.error)); - - int w = decoder.infoPng.width; - int h = decoder.infoPng.height; - - - RGBAImage* result = new RGBAImage(w, h, filename); - // Copy the image over to our internal format, FreeImage has the scanlines bottom to top though. - unsigned int* dest = result->Data; - memcpy(dest, (void *)image, h*w*4); - - /*cleanup decoder*/ - free(image); - free(buffer); - LodePNG_Decoder_cleanup(&decoder); - - return result; -/* - const FREE_IMAGE_FORMAT fileType = FreeImage_GetFileType(filename); - if(FIF_UNKNOWN == fileType) - { - printf("Unknown filetype %s\n", filename); - return 0; - } - - FIBITMAP* freeImage = 0; - if(FIBITMAP* temporary = FreeImage_Load(fileType, filename, 0)) - { - freeImage = FreeImage_ConvertTo32Bits(temporary); - FreeImage_Unload(temporary); - } - if(!freeImage) - { - printf( "Failed to load the image %s\n", filename); - return 0; - } - - const int w = FreeImage_GetWidth(freeImage); - const int h = FreeImage_GetHeight(freeImage); - - RGBAImage* result = new RGBAImage(w, h, filename); - // Copy the image over to our internal format, FreeImage has the scanlines bottom to top though. - unsigned int* dest = result->Data; - for( int y=0; y < h; y++, dest += w ) - { - const unsigned int* scanline = (const unsigned int*)FreeImage_GetScanLine(freeImage, h - y - 1 ); - memcpy(dest, scanline, sizeof(dest[0]) * w); - } - - FreeImage_Unload(freeImage); - return result; - return NULL; -*/ -} - - -int main(int argc, char **argv) -{ - CompareArgs args; - - if (!args.Parse_Args(argc, argv)) { - printf("%s", args.ErrorStr.c_str()); - return -1; - } else { - if (args.Verbose) args.Print_Args(); - } - - const bool passed = Yee_Compare(args); - if (passed) { - if(args.Verbose) - printf("PASS: %s\n", args.ErrorStr.c_str()); - } else { - printf("FAIL: %s\n", args.ErrorStr.c_str()); - } - - return passed ? 0 : 1; -} - diff --git a/tests/yee_compare.h b/tests/yee_compare.h deleted file mode 100644 index 041ae4c..0000000 --- a/tests/yee_compare.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef _yee_compare_h -#define _yee_compare_h - -// source code modified for OpenSCAD, Sept 2011 -// original copyright notice follows: -/* -Metric -RGBAImage.h -Comapre Args -Laplacian Pyramid -Copyright (C) 2006 Yangli Hector Yee - -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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <string> - -class RGBAImage; - -// Args to pass into the comparison function -class CompareArgs -{ -public: - CompareArgs(); - ~CompareArgs(); - bool Parse_Args(int argc, char **argv); - void Print_Args(); - - RGBAImage *ImgA; // Image A - RGBAImage *ImgB; // Image B - RGBAImage *ImgDiff; // Diff image - bool Verbose; // Print lots of text or not - bool LuminanceOnly; // Only consider luminance; ignore chroma channels in the comparison. - float FieldOfView; // Field of view in degrees - float Gamma; // The gamma to convert to linear color space - float Luminance; // the display's luminance - unsigned int ThresholdPixels; // How many pixels different to ignore - std::string ErrorStr; // Error string - // How much color to use in the metric. - // 0.0 is the same as LuminanceOnly = true, - // 1.0 means full strength. - float ColorFactor; - // How much to down sample image before comparing, in powers of 2. - int DownSample; -}; - -#define MAX_PYR_LEVELS 8 - -class LPyramid -{ -public: - LPyramid(float *image, int width, int height); - virtual ~LPyramid(); - float Get_Value(int x, int y, int level); -protected: - float *Copy(float *img); - void Convolve(float *a, float *b); - - // Succesively blurred versions of the original image - float *Levels[MAX_PYR_LEVELS]; - - int Width; - int Height; -}; - -class CompareArgs; - -// Image comparison metric using Yee's method -// References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004 -bool Yee_Compare(CompareArgs &args); - -/** Class encapsulating an image containing R,G,B,A channels. - * - * Internal representation assumes data is in the ABGR format, with the RGB - * color channels premultiplied by the alpha value. Premultiplied alpha is - * often also called "associated alpha" - see the tiff 6 specification for some - * discussion - http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf - * - */ -class RGBAImage -{ - RGBAImage(const RGBAImage&); - RGBAImage& operator=(const RGBAImage&); -public: - RGBAImage(int w, int h, const char *name = 0) - { - Width = w; - Height = h; - if (name) Name = name; - Data = new unsigned int[w * h]; - }; - ~RGBAImage() { if (Data) delete[] Data; } - unsigned char Get_Red(unsigned int i) { return (Data[i] & 0xFF); } - unsigned char Get_Green(unsigned int i) { return ((Data[i]>>8) & 0xFF); } - unsigned char Get_Blue(unsigned int i) { return ((Data[i]>>16) & 0xFF); } - unsigned char Get_Alpha(unsigned int i) { return ((Data[i]>>24) & 0xFF); } - void Set(unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned int i) - { Data[i] = r | (g << 8) | (b << 16) | (a << 24); } - int Get_Width(void) const { return Width; } - int Get_Height(void) const { return Height; } - void Set(int x, int y, unsigned int d) { Data[x + y * Width] = d; } - unsigned int Get(int x, int y) const { return Data[x + y * Width]; } - unsigned int Get(int i) const { return Data[i]; } - const std::string &Get_Name(void) const { return Name; } - RGBAImage* DownSample() const; - - bool WriteToFile(const char* filename); - static RGBAImage* ReadFromFile(const char* filename); - -protected: - int Width; - int Height; - std::string Name; - unsigned int *Data; -}; - -#endif |