summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/testing.txt44
-rw-r--r--tests/CMakeLists.txt107
-rw-r--r--tests/FindGLEW.cmake3
-rw-r--r--tests/OffscreenContext.h2
-rw-r--r--tests/OffscreenContext.mm10
-rw-r--r--tests/OffscreenContextGLX.cc (renamed from tests/OffscreenContext.cc)63
-rw-r--r--tests/OffscreenContextWGL.cc58
-rw-r--r--tests/OffscreenView.cc137
-rw-r--r--tests/OffscreenView.h4
-rw-r--r--tests/cgalpngtest.cc3
-rw-r--r--tests/csgtestcore.cc197
-rw-r--r--tests/fbo.cc21
-rw-r--r--tests/system-gl.cc39
-rw-r--r--tests/system-gl.h3
-rwxr-xr-xtests/test_cmdline_tool.py34
-rwxr-xr-xtests/test_pretty_print.py413
-rw-r--r--tests/yee_compare.cpp681
-rw-r--r--tests/yee_compare.h126
18 files changed, 903 insertions, 1042 deletions
diff --git a/doc/testing.txt b/doc/testing.txt
index 66ceac2..9391832 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,6 +33,9 @@ $ ctest -C <configs> Adds extended tests belonging to configs.
Examples - test all examples
All - test everything
+Headless unix servers (no X11):
+$ Xvfb :5 -screen 0 800x600x24 &
+$ DISPLAY=:5 ctest
Adding a new regression test:
------------------------------
@@ -59,20 +51,16 @@ 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
+To helping CMAKE find eigen2, OpenCSG, CGAL, Boost, and GLEW, you can use the
+-D option. Here are some examples:
-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
-
+ cmake . -DOPENCSG_DIR=~/OpenCSG-1.3.2
+ cmake . -DCGAL_DIR=c:\CGAL-3.7 -DBOOST_ROOT=c:\boost_1_46_0
+
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:
-
- $ make cgalpngtest
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 29f8b25..314b51f 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,26 @@ 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 (WIN32)
+ set(Boost_USE_STATIC_LIBS TRUE)
+ set(BOOST_STATIC TRUE)
+ set(BOOST_THREAD_USE_LIB TRUE)
+endif()
+
+#set(Boost_DEBUG TRUE)
+set(Boost_NO_SYSTEM_PATHS TRUE)
+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 +139,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 +154,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 +185,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 +258,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
@@ -262,13 +281,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
@@ -287,6 +306,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
@@ -295,11 +315,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)
@@ -437,13 +452,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 -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
@@ -493,6 +525,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/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 &center)
{
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..ebe802e 100755
--- a/tests/test_cmdline_tool.py
+++ b/tests/test_cmdline_tool.py
@@ -35,6 +35,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
@@ -66,32 +67,38 @@ 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):
+ #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:"]
+ # 'morphology' is only available in newer versions of ImageMagick.
+ # http://www.imagemagick.org/Usage/morphology/#alturnative
+ args = [expectedfilename, resultfilename, "-alpha", "Off",
+ "-compose", "difference", "-composite", "-threshold", "10%",
+ #"-morphology", "Erode", "Square",
+ "-gaussian-blur","3x65535", "-threshold","99.999%",
+ "-format", "%[fx:w*h*mean]", "info:"]
+ print >> sys.stderr, 'ImageMagick image comparison: convert ', ' '.join(args[2:])
+ print >> sys.stderr, ' expected image: ', expectedfilename
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)
if retval == 0:
pixelerr = int(float(output.strip()))
if pixelerr < 32: return True
else: print >> sys.stderr, pixelerr, ' pixel errors'
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 +150,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:", ["generate", "convexec=", "suffix=", "test="])
except getopt.GetoptError, err:
usage()
sys.exit(2)
@@ -165,6 +173,8 @@ 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 )
# <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..e2193e2
--- /dev/null
+++ b/tests/test_pretty_print.py
@@ -0,0 +1,413 @@
+#!/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/wiki
+# 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
+# repair html output
+# 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
+
+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>
+
+'''Failed 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>
+
+
+'''Failed 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 failed_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 wikitohtml(wiki_rootpath, sysid, wikidata, manifest):
+ # temporarily defunct/broken
+ head = '<html><head><title>'+wiki_rootpath+' test run for '+sysid +'</title></head><body>'
+ revmanifest = dict((val,key) for key, val in manifest.iteritems())
+ x=re.sub('\{\|(.*?)\n','<table \\1>\n',wikidata)
+ x=re.sub('\|(.*?colspan.*?)\|','<td \\1>',x)
+ x=re.sub("'''(.*?)'''","<b>\\1</b>",x)
+ filestrs=re.findall('\[\[File\:(.*?)\|.*?\]\]',x)
+ for f in filestrs:
+ newfile_html='<img src="'+revmanifest[f]+'" width=250 />'
+ x=re.sub('\[\[File\:'+f+'\|.*?\]\]',newfile_html,x)
+ dic = { '|}':'</table>', '|-':'<tr>', '||':'<td>', '|':'<td>',
+ '!!':'<th>', '!':'<tr><th>', '\n\n':'\n<p>\n'} #order matters
+ for key in dic: x=x.replace(key,dic[key])
+ x=re.sub("\[\[(.*?)\]\]","\\1",x)
+ return head + x + '</body></html>'
+
+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:
+ import mwclient
+ except:
+ print 'please download mwclient and unpack here:', os.getcwd()
+ sys.exit()
+ print 'opening site:',wikiurl
+ if wetrun:
+ site = mwclient.Site(wikiurl,api_php_path)
+
+ print 'bot login:', botname
+ if wetrun: site.login(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)
+ print 'upload wiki pages:'
+ for wikiname in wikifiles:
+ filename = os.path.join(wikidir,wikiname)
+ filedata = tryread(filename)
+ print 'upload',len(filedata),'bytes from',wikiname,'...',
+ sys.stdout.flush()
+ if wikiname.endswith('.png'):
+ localf = open(filename,'rb') # mwclient needs file handle
+ descrip = wiki_rootpath + ' test'
+ if wetrun:
+ site.upload(localf,wikiname,descrip,ignore=True)
+ print 'image uploaded'
+ else: # textpage
+ if wetrun:
+ page = site.Pages[wikiname]
+ text = page.edit()
+ page.save(filedata)
+ print 'text page uploaded'
+
+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
+ 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()
+ 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)
+ 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+'_wiki')
+ print 'writing',len(imgs),'images and',len(txtpages),'wiki pages to:\n ', '.'+wikidir.replace(os.getcwd(),'')
+ for k in sorted(imgs): trysave( os.path.join(wikidir,k), imgs[k])
+ for k in sorted(txtpages): trysave( os.path.join(wikidir,k), txtpages[k])
+
+ if '--upload' in sys.argv:
+ upload(wikisite,wiki_api_path,wiki_rootpath,sysid,'openscadbot',
+ 'tobdacsnepo',wikidir,dryrun=dry)
+
+ 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'
+
+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
contact: Jan Huwald // Impressum