From b6b3e52543696c5d6efd85b4d86fc13abb327518 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Wed, 16 Nov 2011 05:58:07 -0600 Subject: add more info to --info dumps. improve wiki output diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 85c4f21..5315c01 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -265,7 +265,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 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" CACHE TYPE STRING) + 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" CACHE TYPE STRING) @@ -367,16 +367,20 @@ 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} ctest_pretty_print.py\"") +set(PRETTYCMD "\"${PYTHON_EXECUTABLE} test_pretty_print.py\"") 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 + # set(CTEST_CUSTOM_POST_TEST ${PRETTYCMD})\n # doesn't work. log is written + # after all tests run. ") file(WRITE ${CTEST_CUSTOM_FILE} ${CTEST_CUSTOM_TXT}) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ctest_pretty_print.py - ${CMAKE_CURRENT_BINARY_DIR}/ctest_pretty_print.py COPYONLY) + +foreach(FILE test_pretty_print.py) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${FILE} + ${CMAKE_CURRENT_BINARY_DIR}/${FILE} COPYONLY) +endforeach() # Find all scad files file(GLOB MINIMAL_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/minimal/*.scad) diff --git a/tests/OffscreenContext.cc b/tests/OffscreenContext.cc deleted file mode 100644 index 994a74d..0000000 --- a/tests/OffscreenContext.cc +++ /dev/null @@ -1,325 +0,0 @@ -/* - -Create an OpenGL context without creating an OpenGL Window. for Linux. - -See Also - - glxgears.c by Brian Paul from mesa-demos (mesa3d.org) - http://cgit.freedesktop.org/mesa/demos/tree/src/xdemos?id=mesa-demos-8.0.1 - http://www.opengl.org/sdk/docs/man/xhtml/glXIntro.xml - http://www.mesa3d.org/brianp/sig97/offscrn.htm - http://glprogramming.com/blue/ch07.html - OffscreenContext.mm (Mac OSX version) - -*/ - -/* - * Some portions of the code below are: - * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "OffscreenContext.h" -#include "printutils.h" -#include "imageutils.h" -#include "system-gl.h" -#include "fbo.h" - -#include -#include - -#include -#include - -#include // for uname - -using namespace std; - -struct OffscreenContext - { - GLXContext openGLContext; - Display *xdisplay; - Window xwindow; - int width; - int height; - fbo_t *fbo; -}; - -void offscreen_context_init(OffscreenContext &ctx, int width, int height) -{ - ctx.width = width; - ctx.height = height; - ctx.openGLContext = NULL; - ctx.xdisplay = NULL; - ctx.xwindow = (Window)NULL; - ctx.fbo = NULL; -} - -string get_unix_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 << "GLX version: " << major << "." << minor << "\n"; - out << glew_dump(false); - - out << get_unix_info(); - - return out.str(); -} - -static XErrorHandler original_xlib_handler = (XErrorHandler) NULL; -static bool XCreateWindow_failed = false; -static int XCreateWindow_error(Display *dpy, XErrorEvent *event) -{ - cerr << "XCreateWindow failed: XID: " << event->resourceid - << " request: " << (int)event->request_code - << " minor: " << (int)event->minor_code << "\n"; - char description[1024]; - XGetErrorText( dpy, event->error_code, description, 1023 ); - cerr << " error message: " << description << "\n"; - XCreateWindow_failed = true; - return 0; -} - -bool create_glx_dummy_window(OffscreenContext &ctx) -{ - /* - create a dummy X window without showing it. (without 'mapping' it) - and save information to the ctx. - - This purposely does not use glxCreateWindow, to avoid crashes, - "failed to create drawable" errors, and Mesa "WARNING: Application calling - GLX 1.3 function when GLX 1.3 is not supported! This is an application bug!" - - This function will alter ctx.openGLContext and ctx.xwindow if successfull - */ - - int attributes[] = { - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DEPTH_SIZE, 1, - None - }; - - Display *dpy = ctx.xdisplay; - - int num_returned = 0; - GLXFBConfig *fbconfigs = glXChooseFBConfig( dpy, DefaultScreen(dpy), attributes, &num_returned ); - if ( fbconfigs == NULL ) { - cerr << "glXChooseFBConfig failed\n"; - return false; - } - - XVisualInfo *visinfo = glXGetVisualFromFBConfig( dpy, fbconfigs[0] ); - if ( visinfo == NULL ) { - cerr << "glXGetVisualFromFBConfig failed\n"; - XFree( fbconfigs ); - return false; - } - - // can't depend on xWin==NULL at failure. use a custom Xlib error handler instead. - original_xlib_handler = XSetErrorHandler( XCreateWindow_error ); - - Window root = DefaultRootWindow( dpy ); - XSetWindowAttributes xwin_attr; - int width = ctx.width; - int height = ctx.height; - xwin_attr.background_pixel = 0; - xwin_attr.border_pixel = 0; - xwin_attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); - xwin_attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; - unsigned long int mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; - - Window xWin = XCreateWindow( dpy, root, 0, 0, width, height, - 0, visinfo->depth, InputOutput, - visinfo->visual, mask, &xwin_attr ); - - // Window xWin = XCreateSimpleWindow( dpy, DefaultRootWindow(dpy), 0,0,42,42, 0,0,0 ); - - - XSync( dpy, false ); - if ( XCreateWindow_failed ) { - XFree( visinfo ); - XFree( fbconfigs ); - return false; - } - XSetErrorHandler( original_xlib_handler ); - - // Most programs would call XMapWindow here. But we don't, to keep the window hidden - XMapWindow( dpy, xWin ); - - GLXContext context = glXCreateNewContext( dpy, fbconfigs[0], GLX_RGBA_TYPE, NULL, True ); - if ( context == NULL ) { - cerr << "glXCreateNewContext failed\n"; - XDestroyWindow( dpy, xWin ); - XFree( visinfo ); - XFree( fbconfigs ); - return false; - } - - //GLXWindow glxWin = glXCreateWindow( dpy, fbconfigs[0], xWin, NULL ); - - if (!glXMakeContextCurrent( dpy, xWin, xWin, context )) { - //if (!glXMakeContextCurrent( dpy, glxWin, glxWin, context )) { - cerr << "glXMakeContextCurrent failed\n"; - glXDestroyContext( dpy, context ); - XDestroyWindow( dpy, xWin ); - XFree( visinfo ); - XFree( fbconfigs ); - return false; - } - - ctx.openGLContext = context; - ctx.xwindow = xWin; - - XFree( visinfo ); - XFree( fbconfigs ); - - return true; -} - - -Bool create_glx_dummy_context(OffscreenContext &ctx) -{ - // This will alter ctx.openGLContext and ctx.xdisplay and ctx.xwindow if successfull - int major; - int minor; - Bool result = False; - - ctx.xdisplay = XOpenDisplay( NULL ); - if ( ctx.xdisplay == NULL ) { - cerr << "Unable to open a connection to the X server\n"; - return False; - } - - // glxQueryVersion is not always reliable. Use it, but then - // also check to see if GLX 1.3 functions exist - - glXQueryVersion(ctx.xdisplay, &major, &minor); - - if ( major==1 && minor<=2 && glXGetVisualFromFBConfig==NULL ) { - cerr << "Error: GLX version 1.3 functions missing. " - << "Your GLX version: " << major << "." << minor << endl; - } else { - result = create_glx_dummy_window(ctx); - } - - if (!result) XCloseDisplay( ctx.xdisplay ); - return result; -} - -OffscreenContext *create_offscreen_context(int w, int h) -{ - OffscreenContext *ctx = new OffscreenContext; - offscreen_context_init( *ctx, w, h ); - - // before an FBO can be setup, a GLX context must be created - // this call alters ctx->xDisplay and ctx->openGLContext - // and ctx->xwindow if successfull - if (!create_glx_dummy_context( *ctx )) { - return NULL; - } - - // glewInit must come after Context creation and before FBO calls. - GLenum err = glewInit(); - if (GLEW_OK != err) { - cerr << "Unable to init GLEW: " << glewGetErrorString(err) << endl; - return NULL; - } - // cerr << glew_dump(0); - -/* ctx->fbo = fbo_new(); - if (!fbo_init(ctx->fbo, w, h)) { - cerr << "GL Framebuffer Object init failed; dumping GLEW info" << endl; - return NULL; - }*/ - - return ctx; -} - -bool teardown_offscreen_context(OffscreenContext *ctx) -{ - if (ctx) { - fbo_unbind(ctx->fbo); - fbo_delete(ctx->fbo); - XDestroyWindow( ctx->xdisplay, ctx->xwindow ); - glXDestroyContext( ctx->xdisplay, ctx->openGLContext ); - XCloseDisplay( ctx->xdisplay ); - return true; - } - return false; -} - -/*! - Capture framebuffer from OpenGL and write it to the given filename as PNG. -*/ -bool save_framebuffer(OffscreenContext *ctx, const char *filename) -{ - if (!ctx || !filename) return false; - int samplesPerPixel = 4; // R, G, B and A - GLubyte pixels[ctx->width * ctx->height * samplesPerPixel]; - glReadPixels(0, 0, ctx->width, ctx->height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // Flip it vertically - images read from OpenGL buffers are upside-down - int rowBytes = samplesPerPixel * ctx->width; - unsigned char *flippedBuffer = (unsigned char *)malloc(rowBytes * ctx->height); - if (!flippedBuffer) { - cerr << "Unable to allocate flipped buffer for corrected image."; - return 1; - } - flip_image(pixels, flippedBuffer, samplesPerPixel, ctx->width, ctx->height); - - bool writeok = write_png(filename, flippedBuffer, ctx->width, ctx->height); - - free(flippedBuffer); - - return writeok; -} - -void bind_offscreen_context(OffscreenContext *ctx) -{ - if (ctx) fbo_bind(ctx->fbo); -} diff --git a/tests/OffscreenContext.mm b/tests/OffscreenContext.mm index baa39e0..7d95481 100644 --- a/tests/OffscreenContext.mm +++ b/tests/OffscreenContext.mm @@ -18,10 +18,11 @@ struct OffscreenContext string offscreen_context_getinfo(OffscreenContext *ctx) { - sstream result; - result << "OS info: Mac OSX\n"; - result << "Machine: Apple(TM) Mac(TM)\n"; - return result.str(); + stringstream out; + out << "GL context creator: Cocoa / CGL\n" + << "OS info: Mac OSX\n" + << "Machine: Apple(TM) Mac(TM)\n"; + return out.str(); } OffscreenContext *create_offscreen_context(int w, int h) diff --git a/tests/OffscreenContextGLX.cc b/tests/OffscreenContextGLX.cc new file mode 100644 index 0000000..ed9ef46 --- /dev/null +++ b/tests/OffscreenContextGLX.cc @@ -0,0 +1,324 @@ +/* + +Create an OpenGL context without creating an OpenGL Window. for Linux. + +See Also + + glxgears.c by Brian Paul from mesa-demos (mesa3d.org) + http://cgit.freedesktop.org/mesa/demos/tree/src/xdemos?id=mesa-demos-8.0.1 + http://www.opengl.org/sdk/docs/man/xhtml/glXIntro.xml + http://www.mesa3d.org/brianp/sig97/offscrn.htm + http://glprogramming.com/blue/ch07.html + OffscreenContext.mm (Mac OSX version) + +*/ + +/* + * Some portions of the code below are: + * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "OffscreenContext.h" +#include "printutils.h" +#include "imageutils.h" +#include "system-gl.h" +#include "fbo.h" + +#include +#include + +#include +#include + +#include // for uname + +using namespace std; + +struct OffscreenContext +{ + GLXContext openGLContext; + Display *xdisplay; + Window xwindow; + int width; + int height; + fbo_t *fbo; +}; + +void offscreen_context_init(OffscreenContext &ctx, int width, int height) +{ + ctx.width = width; + ctx.height = height; + ctx.openGLContext = NULL; + ctx.xdisplay = NULL; + ctx.xwindow = (Window)NULL; + 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" + << "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) +{ + cerr << "XCreateWindow failed: XID: " << event->resourceid + << " request: " << (int)event->request_code + << " minor: " << (int)event->minor_code << "\n"; + char description[1024]; + XGetErrorText( dpy, event->error_code, description, 1023 ); + cerr << " error message: " << description << "\n"; + XCreateWindow_failed = true; + return 0; +} + +bool create_glx_dummy_window(OffscreenContext &ctx) +{ + /* + create a dummy X window without showing it. (without 'mapping' it) + and save information to the ctx. + + This purposely does not use glxCreateWindow, to avoid crashes, + "failed to create drawable" errors, and Mesa "WARNING: Application calling + GLX 1.3 function when GLX 1.3 is not supported! This is an application bug!" + + This function will alter ctx.openGLContext and ctx.xwindow if successfull + */ + + int attributes[] = { + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 1, + None + }; + + Display *dpy = ctx.xdisplay; + + int num_returned = 0; + GLXFBConfig *fbconfigs = glXChooseFBConfig( dpy, DefaultScreen(dpy), attributes, &num_returned ); + if ( fbconfigs == NULL ) { + cerr << "glXChooseFBConfig failed\n"; + return false; + } + + XVisualInfo *visinfo = glXGetVisualFromFBConfig( dpy, fbconfigs[0] ); + if ( visinfo == NULL ) { + cerr << "glXGetVisualFromFBConfig failed\n"; + XFree( fbconfigs ); + return false; + } + + // can't depend on xWin==NULL at failure. use a custom Xlib error handler instead. + original_xlib_handler = XSetErrorHandler( XCreateWindow_error ); + + Window root = DefaultRootWindow( dpy ); + XSetWindowAttributes xwin_attr; + int width = ctx.width; + int height = ctx.height; + xwin_attr.background_pixel = 0; + xwin_attr.border_pixel = 0; + xwin_attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); + xwin_attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; + unsigned long int mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + Window xWin = XCreateWindow( dpy, root, 0, 0, width, height, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &xwin_attr ); + + // Window xWin = XCreateSimpleWindow( dpy, DefaultRootWindow(dpy), 0,0,42,42, 0,0,0 ); + + + XSync( dpy, false ); + if ( XCreateWindow_failed ) { + XFree( visinfo ); + XFree( fbconfigs ); + return false; + } + XSetErrorHandler( original_xlib_handler ); + + // Most programs would call XMapWindow here. But we don't, to keep the window hidden + XMapWindow( dpy, xWin ); + + GLXContext context = glXCreateNewContext( dpy, fbconfigs[0], GLX_RGBA_TYPE, NULL, True ); + if ( context == NULL ) { + cerr << "glXCreateNewContext failed\n"; + XDestroyWindow( dpy, xWin ); + XFree( visinfo ); + XFree( fbconfigs ); + return false; + } + + //GLXWindow glxWin = glXCreateWindow( dpy, fbconfigs[0], xWin, NULL ); + + if (!glXMakeContextCurrent( dpy, xWin, xWin, context )) { + //if (!glXMakeContextCurrent( dpy, glxWin, glxWin, context )) { + cerr << "glXMakeContextCurrent failed\n"; + glXDestroyContext( dpy, context ); + XDestroyWindow( dpy, xWin ); + XFree( visinfo ); + XFree( fbconfigs ); + return false; + } + + ctx.openGLContext = context; + ctx.xwindow = xWin; + + XFree( visinfo ); + XFree( fbconfigs ); + + return true; +} + + +Bool create_glx_dummy_context(OffscreenContext &ctx) +{ + // This will alter ctx.openGLContext and ctx.xdisplay and ctx.xwindow if successfull + int major; + int minor; + Bool result = False; + + ctx.xdisplay = XOpenDisplay( NULL ); + if ( ctx.xdisplay == NULL ) { + cerr << "Unable to open a connection to the X server\n"; + return False; + } + + // glxQueryVersion is not always reliable. Use it, but then + // also check to see if GLX 1.3 functions exist + + glXQueryVersion(ctx.xdisplay, &major, &minor); + + if ( major==1 && minor<=2 && glXGetVisualFromFBConfig==NULL ) { + cerr << "Error: GLX version 1.3 functions missing. " + << "Your GLX version: " << major << "." << minor << endl; + } else { + result = create_glx_dummy_window(ctx); + } + + if (!result) XCloseDisplay( ctx.xdisplay ); + return result; +} + +OffscreenContext *create_offscreen_context(int w, int h) +{ + OffscreenContext *ctx = new OffscreenContext; + offscreen_context_init( *ctx, w, h ); + + // before an FBO can be setup, a GLX context must be created + // this call alters ctx->xDisplay and ctx->openGLContext + // and ctx->xwindow if successfull + if (!create_glx_dummy_context( *ctx )) { + return NULL; + } + + // glewInit must come after Context creation and before FBO calls. + GLenum err = glewInit(); + if (GLEW_OK != err) { + cerr << "Unable to init GLEW: " << glewGetErrorString(err) << endl; + return NULL; + } + // cerr << glew_dump(0); + +/* ctx->fbo = fbo_new(); + if (!fbo_init(ctx->fbo, w, h)) { + cerr << "GL Framebuffer Object init failed; dumping GLEW info" << endl; + return NULL; + }*/ + + return ctx; +} + +bool teardown_offscreen_context(OffscreenContext *ctx) +{ + if (ctx) { + fbo_unbind(ctx->fbo); + fbo_delete(ctx->fbo); + XDestroyWindow( ctx->xdisplay, ctx->xwindow ); + glXDestroyContext( ctx->xdisplay, ctx->openGLContext ); + XCloseDisplay( ctx->xdisplay ); + return true; + } + return false; +} + +/*! + Capture framebuffer from OpenGL and write it to the given filename as PNG. +*/ +bool save_framebuffer(OffscreenContext *ctx, const char *filename) +{ + if (!ctx || !filename) return false; + int samplesPerPixel = 4; // R, G, B and A + GLubyte pixels[ctx->width * ctx->height * samplesPerPixel]; + glReadPixels(0, 0, ctx->width, ctx->height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Flip it vertically - images read from OpenGL buffers are upside-down + int rowBytes = samplesPerPixel * ctx->width; + unsigned char *flippedBuffer = (unsigned char *)malloc(rowBytes * ctx->height); + if (!flippedBuffer) { + cerr << "Unable to allocate flipped buffer for corrected image."; + return 1; + } + flip_image(pixels, flippedBuffer, samplesPerPixel, ctx->width, ctx->height); + + bool writeok = write_png(filename, flippedBuffer, ctx->width, ctx->height); + + free(flippedBuffer); + + return writeok; +} + +void bind_offscreen_context(OffscreenContext *ctx) +{ + if (ctx) fbo_bind(ctx->fbo); +} diff --git a/tests/OffscreenContextWGL.cc b/tests/OffscreenContextWGL.cc index 3756a82..4deaf2a 100644 --- a/tests/OffscreenContextWGL.cc +++ b/tests/OffscreenContextWGL.cc @@ -48,7 +48,7 @@ void offscreen_context_init(OffscreenContext &ctx, int width, int height) ctx.fbo = NULL; } -string get_windows_info() +string get_os_info() { OSVERSIONINFO osvi; @@ -81,8 +81,8 @@ string get_windows_info() string offscreen_context_getinfo(OffscreenContext *ctx) { stringstream out; - out << glew_dump(false); - out << get_windows_info(); + out << "GL context creator: WGL\n" + << get_windows_info(); return out.str(); } diff --git a/tests/OffscreenView.cc b/tests/OffscreenView.cc index 2a4a27e..9c8964c 100644 --- a/tests/OffscreenView.cc +++ b/tests/OffscreenView.cc @@ -1,11 +1,13 @@ #include #include "OffscreenView.h" +#include "system-gl.h" #include #include "renderer.h" #include #include #include #include +#include #define FAR_FAR_AWAY 100000.0 @@ -17,19 +19,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); } @@ -251,7 +240,22 @@ bool OffscreenView::save(const char *filename) std::string OffscreenView::getInfo() { - return offscreen_context_getinfo(this->ctx); + 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) diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc index 5866346..9511688 100644 --- a/tests/csgtestcore.cc +++ b/tests/csgtestcore.cc @@ -76,8 +76,8 @@ AbstractNode *find_root_tag(AbstractNode *n) string info_dump(OffscreenView *glview) { -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) + assert(glview); + #ifdef __GNUG__ #define compiler_info "GCC " << __VERSION__ #elif defined(_MSC_VER) @@ -85,18 +85,26 @@ string info_dump(OffscreenView *glview) #else #define compiler_info "unknown compiler" #endif - assert(glview); + std::stringstream out; out << "OpenSCAD info dump:" - << "\nOpenSCAD Year/Month/Day: " << int(OPENSCAD_YEAR) << "." - << int(OPENSCAD_MONTH) << "." + << "\nOpenSCAD Year/Month/Day: " << int(OPENSCAD_YEAR) << "." + << int(OPENSCAD_MONTH) << "." #ifdef OPENSCAD_DAY - << int(OPENSCAD_DAY) + << int(OPENSCAD_DAY); #endif - << "\nOpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION) - << "\nCompiled with: " << compiler_info - << "\nGL Context info: \n" << glview->getInfo() - << "\n"; +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + << "\nOpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION) + << "\nCompiled by: " << compiler_info + << "\nBoost version: " << BOOST_LIB_VERSION + << "\nEigen version: " << EIGEN_WORLD_VERSION << "." + << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION + // << "\nCGAL version: " << CGAL_VERSION ??? + // << "\nOpenCSG" << ??? + << "\n" << glview->getInfo() + << "\n"; + return out.str(); } diff --git a/tests/ctest_pretty_print.py b/tests/ctest_pretty_print.py deleted file mode 100755 index 430f106..0000000 --- a/tests/ctest_pretty_print.py +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/python -import string,platform,sys,re,os - -wiki_basepath = 'OpenSCAD' -logfilename = 'LastTest.log' -builddir = os.getcwd() -logpath = os.path.join(builddir,'Testing','Temporary',logfilename) -NO_END = False -if logfilename.endswith('.tmp'): NO_END = True - -def read_sysinfo(): - try: - f=open('sysinfo.txt') - except: - return '' - data=f.read() - machine_str, osplain_str, renderer_str = '','','' - machine = re.search('Machine:(.*?)\n',data) - osinfo = re.search('OS info:(.*?)\n',data) - renderer = re.search('GL Renderer:(.*?)\n',data) - if machine: machine_str = machine.group(1).strip().replace(' ','-').replace('/','-') - if osinfo: - osplain_str = osinfo.group(1).strip().split(' ')[0].strip().replace('/','-') - if 'windows' in osinfo.group(1).lower(): osplain_str = 'win' - if renderer: - tmp = renderer.group(1).strip().split(' ') - tmp = string.join(tmp[0:3],'-') - if '/' in tmp: tmp = tmp.split('/')[0] - renderer_str = tmp - platform = osplain_str + '_' + machine_str + '_' + renderer_str - platform = platform.lower() - return data, platform - -def readlog(): - try: - print 'reading',logpath - f = open(logpath) - except: - print 'couldnt open ',logpath - return None - - data = f.read() - return data - -class Test: - def __init__(self,fullname,time,passed,output,type,outputfile,expectedfile): - self.fullname,self.time,self.passed,self.output = \ - fullname, time, passed, output - self.type = type - self.outputfile = outputfile - self.expectedfile = expectedfile - - def __str__(self): - x = 'fullname: ' + self.fullname - x+= '\noutputfile: ' + self.outputfile - x+= '\nexpectedfile: ' + self.expectedfile - x+= '\ntesttime: ' + self.time - x+= '\ntesttype: ' + self.type - x+= '\npassfail: ' + self.passfail - x+= '\noutput: \n' + self.output - x+= '\n' - return x - -def gettest_strings(data): - chunks = data.split('----------------------------------------------------------') - print 'read',len(chunks), 'chunks' - if NO_END: - enddate = 'n/a (cancelled)' - chunks.pop() - else: - enddate = chunks.pop().replace('End testing: ','').strip() - chunks.reverse() - startdate = chunks.pop().replace('Start testing: ','').strip() - chunks.reverse() - tests=[] - chunksize = 3 - for i in range(0,len(chunks),chunksize): - testchunks = chunks[i:i+chunksize] - test = string.join(testchunks,'-----') - tests += [test] - #print '----------<<<<<<<<<<<<<<<<' - #print test - #print '----------<<<<<<<<<<<<<<<<' - test = '' - sysinfo, platform = read_sysinfo() - return startdate, tests, enddate, sysinfo, platform - -def parsetest(teststring): - s = teststring - def regex(pat,str): - x=re.search(pat,str,re.DOTALL|re.MULTILINE) - if x: - if len(x.groups())>0: - return x.group(1).strip() - return '' - testfullname = regex("Test:(.*?)\n",s) - testtime = regex("Test time =(.*?)\n",s).replace(' sec','') - passfail = regex("Test time.*?Test (Passed)",s) - command = regex("Command:(.*?)\n",s) - tmp = command.split(' "') - testtype = '' - try: - testtype = tmp[3].strip('"') - except: - print 'failed to parse log', teststring - goodimg = regex("expected image:(.*?)\n",s) - actualimg = regex("actual image:(.*?)\n",s) - if passfail=='Passed': passed = True - else: passed = False - output = regex("Output:(.*?)",s).replace('-----','') - test = Test(testfullname, testtime, passed, output, testtype, actualimg, goodimg ) - return test - -def parse(data): - startdate, test_strs, enddate, sysinfo, platform = gettest_strings(data) - print 'found', len(test_strs),'test results' - tests = [] - for i in range(len(test_strs)): - test = parsetest(test_strs[i]) - tests += [test] - return startdate, tests, enddate, sysinfo, platform - -def towiki(startdate, tests, enddate, sysinfo, platform): - def convert_path(fulltestname,platform,path): - # convert system path name (image file) to wiki path name - testprogram = fulltestname[0:fulltestname.rfind('_')] - testprogram = testprogram.replace('test','') - filename = os.path.basename(path) - filename = filename.replace('-tests-actual.png','.png') - filename = filename.replace('-tests-expected.png','.png') - try: - platform = platform[0].upper() + platform[1:] - except: - platform = 'error' - newpath = testprogram + '_' + filename - # must use _ not / b/c of wikinet.org weird name mangling - newpath = wiki_basepath + '_' + platform + '_' + newpath - return newpath - - x=''' -

OpenSCAD test run

- -platform: PLATFORM - -detailed system info: -
-SYSINFO
-
- -start time: STARTDATE -end time : ENDDATE - -Failed tests - -{|TABLESTYLE -! Testname !! expected output !! actual output -|- -| FTESTNAME || [[File:EXPECTEDIMG|thumb|250px]] || [[File:ACTUALIMG|thumb|250px]] -|} - -Passed tests - -{|TABLESTYLE -! Testname -|- -| PTESTNAME -|} - -''' - - repeat1=''' -|- -| FTESTNAME || [[File:EXPECTEDIMG|thumb|250px]] || [[File:ACTUALIMG|thumb|250px]] -''' - - repeat2=''' -|- -| PTESTNAME -''' - - x = x.replace('TABLESTYLE','border=1 cellspacing=0 cellpadding=1 align="center"') - x = x.replace('STARTDATE',startdate) - x = x.replace('ENDDATE',enddate) - x = x.replace('SYSINFO',sysinfo) - x = x.replace('PLATFORM',platform) - - for t in tests: - print t.type, t.fullname, t.expectedfile, t.outputfile - if t.passed: - tmp = str(repeat2) - tmp = tmp.replace('PTESTNAME',t.fullname) - x = x.replace(repeat2,tmp + repeat2) - elif not t.passed and t.type=='png': - tmp = str(repeat1) - tmp = tmp.replace('FTESTNAME',t.fullname) - - wiki_imgpath1 = convert_path(t.fullname,'expected',t.expectedfile) - if t.type!='png': wiki_imgpath1 = '' - if t.expectedfile=='': wiki_imgpath2 = '' - tmp = tmp.replace('EXPECTEDIMG',wiki_imgpath1) - - wiki_imgpath2 = convert_path(t.fullname,platform,t.outputfile) - if t.type!='png': wiki_imgpath2 = '' - if t.outputfile=='': wiki_imgpath2 = '' - tmp = tmp.replace('ACTUALIMG',wiki_imgpath2) - - x = x.replace(repeat1,tmp + repeat1) - - x = x.replace(repeat1,'') - x = x.replace(repeat2,'') - return x - -def wikitohtml(data): - # not pretty - data = data.replace('\n\n','\n

\n') - data = re.sub('\{\|.*?\n','\n',data) - data = re.sub('\n\! ','\n\n') - data = re.sub('\n\| ','\n
',data) - data = data.replace(' !! ','') - data = data.replace('|-','
',data) - data = data.replace(' || ','') - data = data.replace('|}','\n
') - data = re.sub('[[File:(.*?)|.*?]]','',data) - return data - -def testsort(tests): - passed = [] - failed = [] - for t in tests: - if t.passed: passed+=[t] - else: failed +=[t] - return failed+passed - -def save(data,filename): - try: - f=open(filename,'w') - except: - print 'couldnt open ',filename, 'for writing' - return None - print 'writing',len(data),'bytes to',filename - f.write(data) - f.close() - -def main(): - data = readlog() - startdate, tests, enddate, sysinfo, platform = parse(data) - tests = testsort(tests) - wikidata = towiki(startdate, tests, enddate, sysinfo, platform) - htmldata = wikitohtml(wikidata) - save(wikidata, platform+'.wiki') - save(htmldata, platform+'.html') - -main() - diff --git a/tests/test_cmdline_tool.py b/tests/test_cmdline_tool.py index 485a821..3e9f45a 100755 --- a/tests/test_cmdline_tool.py +++ b/tests/test_cmdline_tool.py @@ -64,17 +64,20 @@ 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): + print >> sys.stderr, 'Yee image compare:' + 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, 'Yee image compare: ' - print >> sys.stderr, ' expected image: ', expectedfilename print >> sys.stderr, ' actual image: ', resultfilename if execute_and_redirect("./yee_compare", [expectedfilename, resultfilename, "-downsample", "2", "-threshold", "300"], sys.stderr) != 0: return False diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py new file mode 100755 index 0000000..6bc3f54 --- /dev/null +++ b/tests/test_pretty_print.py @@ -0,0 +1,266 @@ +#!/usr/bin/python +# +# this program reads the ctest logfiles from builddir/Testing/Temporary +# and generates two 'pretty printed' outputs in that directory: +# +# 1. mediawiki format, for uploading to a wiki. +# automated uploading is available by following these steps: +# +# download mwclient +# python ctest_pretty_print.py --upload +# +# 2. html format, for easy local viewing +# +# sysinfo.txt: +# sysinfo.txt should have been created by ctest by the main test run. +# it is the output of opencsgtest --info + + +# todo +# 1. add sysinfo about ... git branch +# 2. consolidate image flip +# 3. uploading, can it be done in one file +# 4. consolidate pretty print + +import string,sys,re,os,hashlib,subprocess + +def tryread(filename): + data = None + try: + print 'reading', filename + f = open(filename) + data = f.read() + f.close() + except: + print 'couldn\'t open ',filename + return data + +def trysave(data,filename): + try: + f=open(filename,'w') + print 'writing',len(data),'bytes to',filename + 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 + + hasher = hashlib.md5() + hasher.update(data) + hexhash = hasher.hexdigest()[-4:].upper() + # make all letters for aesthetic reasons + hash = '' + for c in hexhash: hash += chr(ord(c)+97-48) + + sysid = osplain + '_' + machine + '_' + renderer + '_' + hash + sysid = sysid.lower() + + data += read_gitinfo() + + return data, sysid + +class Test: + def __init__(self,fullname,time,passed,output,type,actualfile,expectedfile,scadfile): + self.fullname,self.time,self.passed,self.output = \ + fullname, time, passed, output + self.type, self.actualfile, self.expectedfile, self.scadfile = \ + type, actualfile, expectedfile, scadfile + + 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+= '\n' + return x + +def parsetest(teststring): + patterns = ["Test:(.*?)\n", # fullname + "Test time =(.*?) sec\n", + "Test time.*?Test (Passed)", + "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]) + 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 ) + print 'found', len(tests),'test results' + return startdate, tests, enddate + +def wikify_filename(testname,filename,sysid): + # translate from local system to wiki style filename. + result = wiki_rootpath+'_'+testname+'_' + expected = ezsearch('(expected....$)',filename) + if expected!='': result += expected + actual = ezsearch(os.sep+'.*?-output.*?(actual.*)',filename) + if actual!='': + result += sysid+'_'+actual + return result.replace('/','_') + + +def towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, testlog): + wiki_template = ''' +

OpenSCAD test run

+ +sysid: SYSID + +detailed system info: +
+SYSINFO
+
+ +start time: STARTDATE +end time : ENDDATE + +Failed image tests + +{|border=1 cellspacing=0 cellpadding=1 align="center" +! Testname !! expected output !! actual output + +|- +| FTESTNAME || [[File:EXPECTEDFILE|thumb|250px]] || ACTUALFILE_WIKI + +|} + +Failed text tests (see test log, below, for diff output) + +{|border=1 cellspacing=0 cellpadding=1 align="center" + +|- +| FTESTNAME + +|} + +Passed tests + +{|border=1 cellspacing=0 cellpadding=1 align="center" +! Testname + +|- +| PTESTNAME + +|} + +LastTest.log + +
+LASTTESTLOG
+
+ +''' + manifest = {} + s = wiki_template + repeat1 = ezsearch('(.*?)',s) + repeat2 = ezsearch('(.*?)',s) + repeat3 = ezsearch('(.*?)',s) + dic = { 'STARTDATE': startdate, 'ENDDATE': enddate, + 'SYSINFO': sysinfo, 'SYSID':sysid, 'LASTTESTLOG':testlog } + for key in dic.keys(): + s = re.sub(key,dic[key],s) + for t in tests: + print t.passed, t.type, t.fullname, t.expectedfile, t.actualfile + manifest[t.actualfile] = wikify_filename(t.fullname,t.actualfile,sysid) + manifest[t.expectedfile] = wikify_filename(t.fullname,t.expectedfile,sysid) + if t.passed: + newchunk = re.sub('PTESTNAME',t.fullname,repeat3) + s = s.replace(repeat3, newchunk+repeat3) + elif not t.passed and t.type=='txt': + newchunk = re.sub('FTEST_OUTPUTFILE',t.fullname,repeat2) + newchunk = re.sub('FTESTNAME',t.fullname,repeat2) + s = s.replace(repeat2, newchunk+repeat2) + elif not t.passed and t.type=='png': + if t.actualfile: + actualfile_wiki = '[[File:'+manifest[t.actualfile]+'|thumb|250px]]' + else: + actualfile_wiki = 'No file generated. See test output for more info' + newchunk = re.sub('FTESTNAME',t.fullname,repeat1) + newchunk = newchunk.replace('ACTUALFILE_WIKI',actualfile_wiki) + newchunk = newchunk.replace('EXPECTEDFILE',manifest[t.expectedfile]) + s = s.replace(repeat1, newchunk+repeat1) + s = s.replace(repeat1,'') + s = s.replace(repeat2,'') + s = s.replace(repeat3,'') + s = re.sub('\n','',s) + s = re.sub('','',s) + return manifest, s + +def wikitohtml(data): + # not pretty + data = data.replace('\n\n','\n

\n') + data = re.sub('\{\|.*?\n','\n',data) + data = re.sub('\n\! ','\n\n') + data = re.sub('\n\| ','\n
',data) + data = data.replace(' !! ','') + data = data.replace('|-','
',data) + data = data.replace(' || ','') + data = data.replace('|}','\n
') + data = re.sub('[[File:(.*?)|.*?]]','',data) + return data + +wiki_rootpath = 'OpenSCAD' +builddir = os.getcwd() +logpath = os.path.join(builddir,'Testing','Temporary') +logfilename = os.path.join(logpath,'LastTest.log') + +def main(): + testlog = tryread(logfilename) + startdate, tests, enddate = parselog(testlog) + tests = sorted(tests, key = lambda t:t.passed) + sysinfo, sysid = read_sysinfo('sysinfo.txt') + manifest, wikidata = towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, testlog) + htmldata = wikitohtml(wikidata) + #save(wikidata, os.path.join(logpath,sysid+'.wiki')) + #save(htmldata, os.path.join(logpath,sysid+'.html')) + trysave(wikidata, sysid+'.wiki') + trysave(htmldata, sysid+'.html') + +main() + -- cgit v0.10.1