Mercurial > hg > aimc
changeset 227:73c6d61440ad
- First add of a lot of graphics code from the old version. Not working yet, not even compiling yet.
line wrap: on
line diff
--- a/SConstruct Wed Sep 29 00:24:03 2010 +0000 +++ b/SConstruct Fri Oct 15 05:40:53 2010 +0000 @@ -51,6 +51,16 @@ 'Modules/Output/FileOutputHTK.cc', 'Modules/Output/FileOutputAIMC.cc', 'Modules/Features/ModuleGaussians.cc'] + +graphics_sources = [ 'Modules/Output/Graphics/GraphAxisSpec.cc', + 'Modules/Output/Graphics/GraphicsView.cc', + 'Modules/Output/Graphics/GraphicsViewTime.cc', + 'Modules/Output/Graphics/Devices/GraphicsOutputDevice.cc', + 'Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.cc', + 'Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc', + 'Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.cc' ] +graphics_libraries = [ 'cairo', + '' ] # List of currently incative source files which we may want to add back in sources_disabled = ['Modules/SNR/ModuleNoise.cc',
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.cc Fri Oct 15 05:40:53 2010 +0000 @@ -18,10 +18,8 @@ #include "Support/Common.h" #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h" -namespace aimc { - -GraphicsOutputDevice::GraphicsOutputDevice(Parameters *parameters) { - parameters_ = parameters; +GraphicsOutputDevice::GraphicsOutputDevice(Parameters *pParam) { + m_pParam = pParam; } void GraphicsOutputDevice::gVertex3f(float x, @@ -30,8 +28,8 @@ float r, float g, float b) { - gColor3f(r, g, b); - gVertex3f(x, y, z); + gColor3f(r, g, b); + gVertex3f(x, y, z); } void GraphicsOutputDevice::gVertex2f(float x, @@ -39,18 +37,17 @@ float r, float g, float b) { - gColor3f(r, g, b); - gVertex3f(x, y, 0); + gColor3f(r, g, b); + gVertex3f(x, y, 0); } void GraphicsOutputDevice::gVertex2f(float x, float y) { - gVertex3f(x, y, 0); + gVertex3f(x, y, 0); } void GraphicsOutputDevice::gText2f(float x, float y, - const char *text_string, - bool rotated) { - gText3f(x, y, 0, text_string, rotated); + const char *sStr, + bool bRotated) { + gText3f(x, y, 0, sStr, bRotated); } -} // namespace aimc
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.h Fri Oct 15 05:40:53 2010 +0000 @@ -1,4 +1,4 @@ -// Copyright 2006-2010, Willem van Engen, Thomas Walters +// Copyright 2006, Willem van Engen // // AIM-C: A C++ implementation of the Auditory Image Model // http://www.acousticscale.org/AIMC @@ -20,8 +20,6 @@ #include "Support/Parameters.h" -namespace aimc { - /*! * \class GraphicsOutputDevice "Output/GraphicsOutputDevice.h" * \brief General output device class @@ -36,23 +34,23 @@ * ... * oOutput->Start(); * while ( bIsRunning ) { - * // Start a drawing operation - * oOutput->gGrab(); - * // Draw five horizontal lines - * for (int y=0; y<5; y++) { - * // Start a new line - * oOutput->gBegin(); - * // Give each line it's own colour - * oOutput->gColor3f( (a%255)/255, 0, 1-(a%255)/255 ); - * // Draw the line - * oOutput->gVertex2f(0, y); - * oOutput->gVertex2f(1, y); - * // End the line - * oOutput->gEnd(); - * } - * oOutput->gRelease(); - * Sleep(1); - * a++; + * // Start a drawing operation + * oOutput->gGrab(); + * // Draw five horizontal lines + * for (int y=0; y<5; y++) { + * // Start a new line + * oOutput->gBegin(); + * // Give each line it's own colour + * oOutput->gColor3f( (a%255)/255, 0, 1-(a%255)/255 ); + * // Draw the line + * oOutput->gVertex2f(0, y); + * oOutput->gVertex2f(1, y); + * // End the line + * oOutput->gEnd(); + * } + * oOutput->gRelease(); + * Sleep(1); + * a++; * } * oOutput->Stop(); * \endcode @@ -63,138 +61,131 @@ */ class GraphicsOutputDevice { public: - GraphicsOutputDevice(Parameters *pParam); - virtual ~GraphicsOutputDevice() { }; + GraphicsOutputDevice(AimParameters *pParam); + virtual ~GraphicsOutputDevice() { }; - /*! \brief Initialize the module, sets up everything to Start(). - * \return true on success, false on error - * - * Initialize() needs to be called before any other function. - * - * This method is called in it's form as displayed here by the GraphicsView, - * but you may want to setup your own Initialize(...) function with - * different arguments and call it yourself. - * - * Thus make sure you do all memory allocations here. They can be cleaned - * up by the destructor. Because Initialize() may fail, it's not put in - * the constructor, so it can return a value. - * - * \sa Module::Initialize() - */ + /*! \brief Initialize the module, sets up everything to Start(). + * \return true on success, false on error + * + * Initialize() needs to be called before any other function. + * + * This method is called in it's form as displayed here by the GraphicsView, + * but you may want to setup your own Initialize(...) function with + * different arguments and call it yourself. + * + * Thus make sure you do all memory allocations here. They can be cleaned + * up by the destructor. Because Initialize() may fail, it's not put in + * the constructor, so it can return a value. + * + * \sa Module::Initialize() + */ + virtual bool Initialize(unsigned int iVerticesMax) { return true; }; + /*! \overload + * This function reloads the parameters; make sure to have at least the + * function with maximum parameters called once. + */ + virtual bool Initialize() { return true; }; - /*! \overload - * This function reloads the parameters; make sure to have at least the - * function with maximum parameters called once. - */ - virtual bool Initialize(Parameters *global_parameters) { - global_parameters_ = global_parameters; - return true; - }; + /*! \brief Create a new drawing + * Run this before any other drawing command. + * \sa glRelease() + */ + virtual void gGrab() = 0; - /*! \brief Create a new drawing - * Run this before any other drawing command. - * \sa glRelease() - */ - virtual void gGrab() = 0; - - //! \brief Start a new vertex group for drawing a line strip + //! \brief Start a new vertex group for drawing a line strip virtual void gBeginLineStrip() = 0; //! \brief Start a new vertex group for drawing a quad strip virtual void gBeginQuadStrip() = 0; - /*! \brief Specify a vertex to draw - * \param[in] x X-coordinate of the vertex - * \param[in] y Y-coordinate of the vertex - * \param[in] z Z-coordinate of the vertex - * \param[in] r Red component of colour - * \param[in] g Green component of colour - * \param[in] b Blue component of colour - * - * Currently, only lines are implemented. - */ + /*! \brief Specify a vertex to draw + * \param[in] x X-coordinate of the vertex + * \param[in] y Y-coordinate of the vertex + * \param[in] z Z-coordinate of the vertex + * \param[in] r Red component of colour + * \param[in] g Green component of colour + * \param[in] b Blue component of colour + * + * Currently, only lines are implemented. + */ virtual void gVertex3f(float x, float y, float z, float r, float g, float b); - /*! \overload - * This will add a vertex with the last specified colour. - */ + /*! \overload + * This will add a vertex with the last specified colour. + */ - virtual void gVertex3f(float x, float y, float z) = 0; - /*! \overload - * This will add a vertex in the 2d-plane with z=0. - */ + virtual void gVertex3f(float x, float y, float z) = 0; + /*! \overload + * This will add a vertex in the 2d-plane with z=0. + */ - virtual void gVertex2f(float x, float y, float r, float g, float b); + virtual void gVertex2f(float x, float y, float r, float g, float b); - /*! \overload - * This will add a vertex in the 2d-plane with z=0 with the last + /*! \overload + * This will add a vertex in the 2d-plane with z=0 with the last * specified colour. - */ - virtual void gVertex2f(float x, float y); + */ + virtual void gVertex2f(float x, float y); - /*! \brief Sets the current colour - * \param[in] r Red component - * \param[in] g Green component - * \param[in] b Blue component - */ - virtual void gColor3f(float r, float g, float b) = 0; + /*! \brief Sets the current colour + * \param[in] r Red component + * \param[in] g Green component + * \param[in] b Blue component + */ + virtual void gColor3f(float r, float g, float b) = 0; - //! \brief End a vertex group + //! \brief End a vertex group virtual void gEnd() = 0; - /*! \brief Render a text string - * \param[in] x X-coordinate of the text's alignment point - * \param[in] y Y-coordinate of the text's alignment point - * \param[in] z Z-coordinate of the text's alignment point - * \param[in] sStr Text to render - * \param[in] bRotated \c true for vertically rotated text - * - * Current alignment is horizontal:left and vertical:bottom - * \todo Allow multiple alignment points - */ - virtual void gText3f(float x, + /*! \brief Render a text string + * \param[in] x X-coordinate of the text's alignment point + * \param[in] y Y-coordinate of the text's alignment point + * \param[in] z Z-coordinate of the text's alignment point + * \param[in] sStr Text to render + * \param[in] bRotated \c true for vertically rotated text + * + * Current alignment is horizontal:left and vertical:bottom + * \todo Allow multiple alignment points + */ + virtual void gText3f(float x, float y, float z, const char *sStr, bool bRotated = false) = 0; - /*! \overload - * This will render a text string in the 2d-plane with z=0. - */ - virtual void gText2f(float x, + /*! \overload + * This will render a text string in the 2d-plane with z=0. + */ + virtual void gText2f(float x, float y, const char *sStr, bool bRight = false); - /*! \brief Finish drawing - * Call this when a drawing is finished. It also makes sure that the - * rendering is actually done. - * \sa glGrab() - */ - virtual void gRelease() = 0; + /*! \brief Finish drawing + * Call this when a drawing is finished. It also makes sure that the + * rendering is actually done. + * \sa glGrab() + */ + virtual void gRelease() = 0; - /*! \brief Called when animation starts - * - * You may wonder what Start() and Stop() do here. Some implementations - * may want to behave differently with respect to updating, if an - * animation is running or not (e.g. updating). - */ - virtual void Start() { m_bRunning = true; } + /*! \brief Called when animation starts + * + * You may wonder what Start() and Stop() do here. Some implementations + * may want to behave differently with respect to updating, if an + * animation is running or not (e.g. updating). + */ + virtual void Start() { m_bRunning = true; } - //! \brief Called when animation stops - virtual void Stop() { m_bRunning = false; } - - virtual void Reset(Parameters* global_parameters) = 0; - + //! \brief Called when animation stops + virtual void Stop() { m_bRunning = false; } protected: - //! \brief True when animation is running - bool m_bRunning; - //! \brief Parameter store - Parameters *parameters_; - Parameters *global_parameters_; + //! \brief True when animation is running + bool m_bRunning; + //! \brief Parameter store + AimParameters *m_pParam; - //! \brief Pixel Formats - enum PixelFormat {AIM_PIX_FMT_RGB24_32, AIM_PIX_FMT_RGB24_24}; + //! \brief Pixel Formats + enum PixelFormat {AIM_PIX_FMT_RGB24_32, AIM_PIX_FMT_RGB24_24}; }; -} // namespace aimc + #endif /* __GRAPHICS_OUTPUT_DEVICE__ */
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.cc Fri Oct 15 05:40:53 2010 +0000 @@ -1,4 +1,4 @@ -// Copyright 2007-2010, Thomas Walters, Willem van Engen +// Copyright 2007, Thomas Walters // // AIM-C: A C++ implementation of the Auditory Image Model // http://www.acousticscale.org/AIMC @@ -31,98 +31,56 @@ #include <string.h> #include <stdio.h> #include <math.h> -#include <limits.h> -#ifdef _WINDOWS -# include <direct.h> // for _mkdir&_rmdir -#endif - -//#include "cairo-quartz.h" - -#include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h" - -namespace aimc { +#include "Support/util.h" +#include "Output/GraphicsOutputDeviceCairo.h" GraphicsOutputDeviceCairo::GraphicsOutputDeviceCairo(Parameters *pParam) - : GraphicsOutputDevice(pParam) { - m_bOutputFile = false; - m_iFileNumber = 0; - m_iVertexType = VertexTypeNone; - m_bUseMemoryBuffer=false; - parameters_->DefaultString("output.img.format", "png"); + : GraphicsOutputDevice(pParam) { + m_bOutputFile = false; + m_iFileNumber = 0; + m_iVertexType = VertexTypeNone; + m_bUseMemoryBuffer=false; } -void GraphicsOutputDeviceCairo::Reset(Parameters* global_parameters) { - Initialize(global_parameters); +bool GraphicsOutputDeviceCairo::Initialize(const char *sDir) { + Init(); + + //! \todo Output to file if sDir is a file, to directory with + //! multiple images if it's a directory. + strncpy(m_sDir, sDir, sizeof(m_sDir)/sizeof(m_sDir[0])); + + /* Try to open an image to see if everything is allright. We want to avoid + * errors in the main Process()ing loop. */ + if ( !OpenFile(0) ) { + //! \todo Better error message that is more specific about the cause. + AIM_ERROR(_T("Could not open output directory '%s' using graphics format '%s'."), + m_sDir, m_pParam->GetString("output.img.format") ); + return false; + } + CloseFile(); + + return true; } -bool GraphicsOutputDeviceCairo::Initialize(Parameters *global_parameters) { - global_parameters_ = global_parameters; -#ifdef _WINDOWS - string pathsep("\\"); -#else - string pathsep("/"); -#endif - directory_ = global_parameters->GetString("output_filename_base") + pathsep; - //! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt. -#ifdef _WINDOWS - _mkdir(directory_.c_str()); -#else - mkdir(directory_.c_str(), S_IRWXU); -#endif - InitialzeInternal(); - return true; -} - -bool GraphicsOutputDeviceCairo::Initialize(string directory) { - directory_ = directory; - InitialzeInternal(); - - /* Try to open an image to see if everything is allright. We want to avoid - * errors in the main Process()ing loop. */ - /*if (!OpenFile(0)) { - //! \todo Better error message that is more specific about the cause. - LOG_ERROR(_T("Could not open output directory '%s' using graphics format '%s'."), - directory_.c_str(), parameters_->DefaultString("output.img.format", "png")); - return false; - } - CloseFile();*/ - - return true; -} - -/*bool GraphicsOutputDeviceCairo::Initialize() { +bool GraphicsOutputDeviceCairo::Initialize() { Init(); m_bUseMemoryBuffer = true; return(true); -}*/ +} -void GraphicsOutputDeviceCairo::InitialzeInternal() { - AIM_ASSERT(parameters_); +void GraphicsOutputDeviceCairo::Init() { + AIM_ASSERT(m_pParam); + /* + * Set parameters + */ + m_pParam->GetString("output.img.color.background"); - parameters_->DefaultString("output.img.color.background", "black"); + m_bInvertColors = m_pParam->GetBool("output.img.color.invert"); - m_bInvertColors = parameters_->DefaultBool("output.img.color.invert", "false"); - - // Output size. - m_iWidth = parameters_->DefaultInt("output.img.width", 800); - m_iHeight = parameters_->DefaultInt("output.img.height", 600); - - // Cairo's RGB24 format has 32-bit pixels with the upper 8 bits unused. - // This is not the same as the plotutils PNG format. This information is transferred by the - // function GetPixelFormat. The pixel format is dealt with by the reciever. - m_cSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, - m_iWidth, - m_iHeight); - m_cCr = cairo_create(m_cSurface); - cairo_scale(m_cCr, (float)m_iWidth, (float)m_iHeight); - // Now setup things for this plotter. - cairo_select_font_face(m_cCr, - parameters_->DefaultString("output.img.fontname", - "HersheySans"), - CAIRO_FONT_SLANT_NORMAL, - CAIRO_FONT_WEIGHT_BOLD); - cairo_set_font_size (m_cCr, 0.02); + // Output size! + m_iWidth = m_pParam->GetUInt("output.img.width"); + m_iHeight = m_pParam->GetUInt("output.img.height"); } unsigned char* GraphicsOutputDeviceCairo::GetBuffer() { @@ -133,27 +91,25 @@ } bool GraphicsOutputDeviceCairo::OpenFile(unsigned int index) { - const char *strPlottype = parameters_->GetString("output.img.format"); + const char *strPlottype = m_pParam->GetString("output.img.format"); if (!m_bUseMemoryBuffer) { struct stat fileinfo; // Get filename without trailing slash - char filename[PATH_MAX]; - strncpy(filename, directory_.c_str(), sizeof(filename)/sizeof(filename[0])); + strncpy(m_sFilename, m_sDir, sizeof(m_sFilename)/sizeof(m_sFilename[0])); #ifdef _WINDOWS - if (filename[strlen(filename)-1]=='\\') { - filename[strlen(filename)-1]='\0'; + if (m_sFilename[strlen(m_sFilename)-1]=='\\') { + m_sFilename[strlen(m_sFilename)-1]='\0'; } #else - if (filename[strlen(filename)-1]=='/') { - filename[strlen(filename)-1]='\0'; + if (m_sFilename[strlen(m_sFilename)-1]=='/') { + m_sFilename[strlen(m_sFilename)-1]='\0'; } #endif // Enumerate files it m_sDir is a directory. - if (stat(filename, &fileinfo) == 0 && (fileinfo.st_mode & S_IFDIR)) { + if (stat(m_sFilename, &fileinfo) == 0 && (fileinfo.st_mode & S_IFDIR)) { // We have a directory: enumerate with index - snprintf(filename, sizeof(filename) / sizeof(filename[0]), - "%s%06d.%s", - directory_.c_str(), + snprintf(m_sFilename, sizeof(m_sFilename)/sizeof(m_sFilename[0]),"%s%06d.%s", + m_sDir, index, strPlottype); // If type is 'auto', fallback to 'png' @@ -161,49 +117,61 @@ strPlottype = "png"; } else { // We have a (probably non-existant) file. Auto-detect type by extension if requested - strncpy(filename, - directory_.c_str(), - sizeof(filename)/sizeof(filename[0])); - char *pDot = strrchr(filename, '.'); + strncpy(m_sFilename, m_sDir, sizeof(m_sFilename)/sizeof(m_sFilename[0])); + char *pDot = strrchr(m_sFilename, '.'); if (!pDot) { - LOG_ERROR(_T("Please supply extension on filename when using 'auto' format: '%s'"), - filename); + AIM_ERROR(_T("Please supply extension on filename when using 'auto' format: '%s'"), + m_sFilename); return false; } strPlottype = &pDot[1]; } - image_filename_ = filename; m_bOutputFile= true; //! \todo Should check that it's possible to write to the file } - - return true; + // Cairo's RGB24 format has 32-bit pixels with the upper 8 bits unused. + // This is not the same as the plotutils PNG format. This information is transferred by the + // function GetPixelFormat. The pixel format is dealt with by the reciever. + m_cSurface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + m_iWidth, + m_iHeight); + m_cCr = cairo_create (m_cSurface); + cairo_scale(m_cCr, (float)m_iWidth, (float)m_iHeight); + // Now setup things for this plotter. + cairo_select_font_face(m_cCr, + m_pParam->GetString("output.img.fontname"), + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size (m_cCr, 0.015); + return true; } void GraphicsOutputDeviceCairo::CloseFile() { - // And the output file - if (m_bOutputFile) { - cairo_surface_write_to_png(m_cSurface, image_filename_.c_str()); - m_bOutputFile = false; - } - cairo_set_source_rgb (m_cCr, 0.0, 0.0, 0.0); - cairo_paint (m_cCr); - //cairo_destroy(m_cCr); - //cairo_surface_destroy(m_cSurface); + // Plotting library + if (m_iPlotHandle>0) { + cairo_destroy(m_cCr); + m_iPlotHandle = 0; + } + // And the output file + if (m_bOutputFile) { + cairo_surface_write_to_png(m_cSurface, m_sFilename); + m_bOutputFile = false; + } + cairo_surface_destroy(m_cSurface); } GraphicsOutputDeviceCairo::~GraphicsOutputDeviceCairo() { - AIM_ASSERT(!m_iPlotHandle); - CloseFile(); + AIM_ASSERT(!m_iPlotHandle); + CloseFile(); } void GraphicsOutputDeviceCairo::gGrab() { // Open file. - if (!OpenFile(m_iFileNumber)) { - return; + if (!OpenFile(m_iFileNumber)) { + return; } - // Setup plotting area. - cairo_set_line_width (m_cCr, 0.001f); - gColor3f (0.0f, 0.0f, 0.0f); + // Setup plotting area. + cairo_set_line_width (m_cCr, 0.001f); + gColor3f (0.0f, 0.0f, 0.0f); cairo_paint (m_cCr); gColor3f(1.0f, 1.0f, 0.0f); } @@ -213,85 +181,80 @@ } void GraphicsOutputDeviceCairo::gBeginLineStrip() { - m_bIsFirstVertex = true; - m_iVertexType = VertexTypeLine; - //! \todo Make line width user-settable - cairo_set_line_width (m_cCr, 0.001f); + m_bIsFirstVertex = true; + m_iVertexType = VertexTypeLine; + //! \todo Make line width user-settable + cairo_set_line_width (m_cCr, 0.001f); } void GraphicsOutputDeviceCairo::gBeginQuadStrip() { - m_bIsFirstVertex = true; - m_iVertexType = VertexTypeQuad; - m_iPrevVertexCount = 0; + m_bIsFirstVertex = true; + m_iVertexType = VertexTypeQuad; + m_iPrevVertexCount = 0; cairo_set_line_width (m_cCr, 0.001f); } void GraphicsOutputDeviceCairo::gColor3f(float r, float g, float b) { if (m_bInvertColors) { - r = 1.0 - r; - g = 1.0 - g; - b = 1.0 - b; - } + r = 1-r; + g = 1-g; + b = 1-b; + } cairo_set_source_rgb (m_cCr, r, g, b); } void GraphicsOutputDeviceCairo::gVertex3f(float x, float y, float z) { - switch(m_iVertexType) { - case VertexTypeLine: - if (m_bIsFirstVertex) { - m_bIsFirstVertex = false; - //pl_fmove(x, y); - cairo_move_to(m_cCr, x, 1.0 - y); - } else { - //pl_fcont(x, y); - cairo_line_to(m_cCr, x, 1.0 - y); - } - break; - case VertexTypeQuad: - /* Store vertices until we have four in a row. - * The order of vertices when processing quads is: - * 1-----3-----5 - * | | | - * 0-----2-----4 - */ - if (m_iPrevVertexCount >= 3) { - // Plot this quad - //cairo_set_source_rgb(m_cCr, 0.2, 1 - m_aPrevY[0], m_aPrevX[0]); - cairo_rectangle (m_cCr, m_aPrevX[2], - 1 - m_aPrevY[2], m_aPrevX[2] - m_aPrevX[0], - y - m_aPrevY[2]); - cairo_fill (m_cCr); + switch(m_iVertexType) { + case VertexTypeLine: + if (m_bIsFirstVertex) { + m_bIsFirstVertex = false; + //pl_fmove(x, y); + cairo_move_to(m_cCr, x, 1-y); + } else { + //pl_fcont(x, y); + cairo_line_to(m_cCr, x, 1-y); + } + break; + case VertexTypeQuad: + /* Store vertices until we got four in a row. + * The order of vertices when processing quads is: + * 1-----3-----5 + * | | | + * 0-----2-----4 + */ + if (m_iPrevVertexCount >= 3) { + // Plot this quad + cairo_move_to(m_cCr, m_aPrevX[0], 1-m_aPrevY[0]); + cairo_line_to(m_cCr, m_aPrevX[1], 1-m_aPrevY[1]); + cairo_line_to(m_cCr, x, y); + cairo_line_to(m_cCr, m_aPrevX[2], 1-m_aPrevY[2]); + cairo_close_path (m_cCr); - /*cairo_move_to(m_cCr, , ); - cairo_line_to(m_cCr, , 1 - m_aPrevY[1]); - cairo_line_to(m_cCr, x, y); - cairo_line_to(m_cCr, m_aPrevX[2], 1 - m_aPrevY[2]);*/ - - // Last vertices of this quad are the first of the next - m_aPrevX[0] = m_aPrevX[2]; - m_aPrevY[0] = m_aPrevY[2]; - m_aPrevX[1] = x; - m_aPrevY[1] = y; - m_iPrevVertexCount = 2; - } else { - // Not at the fourth, keep storing - m_aPrevX[m_iPrevVertexCount] = x; - m_aPrevY[m_iPrevVertexCount] = y; - m_iPrevVertexCount++; - } - break; - default: - // Should not happen - AIM_ASSERT(0); - } + // Last vertices of this quad are the first of the next + m_aPrevX[0] = m_aPrevX[2]; + m_aPrevY[0] = m_aPrevY[2]; + m_aPrevX[1] = x; + m_aPrevY[1] = y; + m_iPrevVertexCount = 2; + } else { + // Not at the fourth, keep storing + m_aPrevX[m_iPrevVertexCount] = x; + m_aPrevY[m_iPrevVertexCount] = y; + m_iPrevVertexCount++; + } + break; + default: + // Should not happen + AIM_ASSERT(0); + } } void GraphicsOutputDeviceCairo::gEnd() { - if(m_iVertexType==VertexTypeLine) + if(m_iVertexType==VertexTypeLine) cairo_stroke (m_cCr); else cairo_fill (m_cCr); - m_iVertexType = VertexTypeNone; + m_iVertexType = VertexTypeNone; } void GraphicsOutputDeviceCairo::gText3f(float x, @@ -299,23 +262,22 @@ float z, const char *sStr, bool bRotated) { - //cairo_text_extents_t te; - if (bRotated) { - cairo_rotate(m_cCr, M_PI/2); - //cairo_move_to(m_cCr, x ,1-y); - cairo_show_text(m_cCr, sStr); - //cairo_identity_matrix(m_cCr); - cairo_rotate(m_cCr, -M_PI/2); - } else { - cairo_move_to(m_cCr, x ,1-y); - cairo_show_text(m_cCr, sStr); - } + cairo_text_extents_t te; + if (bRotated) { + cairo_rotate(m_cCr, M_PI/2); + cairo_move_to(m_cCr, x ,1-y); + cairo_show_text(m_cCr, sStr); + //cairo_identity_matrix(m_cCr); + cairo_rotate(m_cCr, -M_PI/2); + } else { + cairo_move_to(m_cCr, x ,1-y); + cairo_show_text(m_cCr, sStr); + } } void GraphicsOutputDeviceCairo::gRelease() { - AIM_ASSERT(m_iPlotHandle>0); - CloseFile(); - // Finished this one, up to the next! - m_iFileNumber++; + AIM_ASSERT(m_iPlotHandle>0); + CloseFile(); + // Finished this one, up to the next! + m_iFileNumber++; } -} // namespace aimc
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h Fri Oct 15 05:40:53 2010 +0000 @@ -27,8 +27,6 @@ #ifndef __GRAPHICS_OUTPUT_DEVICE_CAIRO_H__ #define __GRAPHICS_OUTPUT_DEVICE_CAIRO_H__ -#include <string> - #include <stdlib.h> #include <stdio.h> @@ -36,8 +34,6 @@ #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h" -namespace aimc { -using std::string; /*! * \class GraphicsOutputDeviceCairo "Output/GraphicsOutputDeviceCairo.h" * \brief Output class for output to a graphics file using Cairo @@ -45,92 +41,93 @@ * This class outputs a graphics operation to file. It only supports 2d though, * so the z-component is ignored. */ -class GraphicsOutputDeviceCairo : public GraphicsOutputDevice { +class GraphicsOutputDeviceCairo : public GraphicsOutputDevice +{ public: - GraphicsOutputDeviceCairo(Parameters *parameters); + GraphicsOutputDeviceCairo(AimParameters *pParam); virtual ~GraphicsOutputDeviceCairo(); - /*! \brief Initializes this output device, prepares plotting tools. - * \param sDir Directory or filename where to put images, max length is - * _MAX_PATH. Must end with slash. - * \return true on success, false on failure. - * - * sDir can be either a filename, in which case the output will be - * to that file, or a directory, in which case it will be filled - * with 6-digit numbered files. A new file is then created at every - * call to gGrab(). - * - * As usual, make sure to call this function before any other. If this - * Initialize() failed, you shouldn't try the other functions either. - */ - bool Initialize(string directory); -virtual bool Initialize(Parameters *global_parameters); - + /*! \brief Initializes this output device, prepares plotting tools. + * \param sDir Directory or filename where to put images, max length is + * _MAX_PATH. Must end with slash!!! + * \return true on success, false on failure. + * + * sDir can be either a filename, in which case the output will be + * to that file, or a directory, in which case it will be filled + * with 6-digit numbered files. A new file is then created at every + * call to gGrab(). + * + * As usual, make sure to call this function before any other. If this + * Initialize() failed, you shouldn't try the other functions either. + */ + bool Initialize(const char *sDir); + bool Initialize(); void gGrab(); void gBeginLineStrip(); void gBeginQuadStrip(); - using GraphicsOutputDevice::gVertex3f; // Because we overload it - void gVertex3f(float x, float y, float z); - void gColor3f(float r, float g, float b); + using GraphicsOutputDevice::gVertex3f; // Because we overload it + void gVertex3f(float x, float y, float z); + void gColor3f(float r, float g, float b); void gEnd(); - void gText3f(float x, float y, float z, const char *sStr, bool bRotated = false); - void gRelease(); - unsigned char* GetBuffer(); - int GetPixelFormat(); - virtual void Reset(Parameters* global_parameters); + void gText3f(float x, float y, float z, const char *sStr, bool bRotated = false); + void gRelease(); + unsigned char* GetBuffer(); + int GetPixelFormat(); protected: /*! \brief Internal initialisation * */ - void InitialzeInternal(); + void Init(); - /*! \brief Open the file with given index for output - * \param index File number to open - * \return true on success, false on error - * - * This opens a file for output and sets up the plotting library. - */ - bool OpenFile(unsigned int index); + /*! \brief Open the file with given index for output + * \param index File number to open + * \return true on success, false on error + * + * This opens a file for output and sets up the plotting library. + */ + bool OpenFile(unsigned int index); - //! \brief Closes a plot output file, if any is open. - void CloseFile(); + //! \brief Closes a plot output file, if any is open. + void CloseFile(); - //! \brief Set to true if the input file can be written to - bool m_bOutputFile; - //! \brief Output directory - string directory_; - //! \brief Current file number - unsigned int m_iFileNumber; - //! \brief true if this is the first vertex after gBegin() - bool m_bIsFirstVertex; + //! \brief Set to true if the input file can be written to + bool m_bOutputFile; + //! \brief The Cairo plotter + int m_iPlotHandle; + //! \brief Output directory + char m_sDir[PATH_MAX]; + //! \brief Current file number + unsigned int m_iFileNumber; + //! \brief true if this is the first vertex after gBegin() + bool m_bIsFirstVertex; - enum VertexType { - VertexTypeNone, + enum VertexType { + VertexTypeNone, VertexTypeLine, VertexTypeQuad - }; - //! \brief The current vertex type - VertexType m_iVertexType; - //! \brief Begin vertex of current quad - float m_aPrevX[3], m_aPrevY[3]; - //! \brief Current number of quad vertices stored - unsigned int m_iPrevVertexCount; + }; + //! \brief The current vertex type + VertexType m_iVertexType; + //! \brief Begin vertex of current quad + float m_aPrevX[3], m_aPrevY[3]; + //! \brief Current number of quad vertices stored + unsigned int m_iPrevVertexCount; - //! \brief Whether to invert the colors or not - bool m_bInvertColors; + //! \brief Whether to invert the colors or not + bool m_bInvertColors; //! \brief Cairo Drawing Surface cairo_surface_t *m_cSurface; //! \brief Cairo Context - cairo_t *m_cCr; + cairo_t *m_cCr; //! \brief Internal store for the input filename - string image_filename_; + char m_sFilename[PATH_MAX]; - unsigned int m_iWidth; - unsigned int m_iHeight; - bool m_bUseMemoryBuffer; + unsigned int m_iWidth; + unsigned int m_iHeight; + bool m_bUseMemoryBuffer; }; -} // namespace aimc + #endif /* __GRAPHICS_OUTPUT_DEVICE_CAIRO_H__ */
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc Fri Oct 15 05:40:53 2010 +0000 @@ -1,265 +1,256 @@ -// Copyright 2006, Willem van Engen -// -// AIM-C: A C++ implementation of the Auditory Image Model -// http://www.acousticscale.org/AIMC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/*! - * \file - * \brief Output device for output to a movie - * - * \author Willem van Engen <cnbh@willem.engen.nl> - * \date created 2006/10/16 - * \version \$Id: GraphicsOutputDeviceMovie.cpp 633 2008-09-11 04:20:16Z tom $ - */ - -/*! \todo - * A recent experiment showed that the video was about an audioframe - * (something like 30 ms) behind the audio in rdct.wav. It seems odd - * to me, since I already output a frame at the beginning to compensate - * for the missed buffer. - * A solution that would solve this and be a broader improvement, is to - * include the source's time when Fire()ing. The outputdevice can then - * do audio/video synchronization. In the case of the movie, the very - * first gGrab() looks at the time and emits as much empty output frames - * as needed until the correct signal time is reached. - */ -#include "Support/Common.h" - -#ifdef _WINDOWS -# include <direct.h> // for _mkdir&_rmdir -#else -# include <sys/types.h> -# include <dirent.h> // for opendir&friends -#endif -#include <stdio.h> -#include <string.h> - -#include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h" - -namespace aimc { - -GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *parameters) - : GraphicsOutputDeviceCairo(parameters) { - sound_filename_.clear(); - movie_filename_.clear(); -} - -bool GraphicsOutputDeviceMovie::Initialize(Parameters *global_parameters) { - global_parameters_ = global_parameters; - sound_filename_ = global_parameters->GetString("input_filename"); - string file_suffix = parameters_->DefaultString("filename_suffix", ".mov"); - movie_filename_ = global_parameters->GetString("output_filename_base") - + file_suffix; - - FILE *f; - - // Check sound file exists - if ((f = fopen(sound_filename_.c_str(), "r")) == NULL) { - LOG_ERROR(_T("Couldn't open sound file '%s' for movie creation."), - sound_filename_.c_str()); - sound_filename_.clear(); - return false; - } - fclose(f); - - // Check movie output file can be made - if ((f = fopen(movie_filename_.c_str(), "w")) == NULL) { - LOG_ERROR(_T("Couldn't open movie file '%s' to write to."), - movie_filename_.c_str()); - movie_filename_.clear(); - return false; - } - fclose(f); - - // Get a temporary image output directory - //! \warning Not really safe ... but windows has no mkdtemp() - //! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt. -#ifdef _WINDOWS - char *temp_dir = NULL; - if ((temp_dir = _tempnam(NULL, AIM_NAME)) - && _mkdir(temp_dir) >= 0) { - directory_ = temp_dir; - directory_ += "\\"; // Make sure to end with trailing slash - } else { - LOG_ERROR(_T("Couldn't create a temporary directory for movie output.")); - if (temp_dir) { - free(temp_dir); - } - return false; - } - if (temp_dir) { - free(temp_dir); - } -#else - char temp_dir[PATH_MAX]; - strcpy(temp_dir, "/tmp/"AIM_NAME"-movie.XXXXXX"); - if (mkdtemp(temp_dir)) { - directory_ = temp_dir; - directory_ += "/"; // Make sure to end with trailing slash - } else { - LOG_ERROR(_T("Couldn't create a temporary directory for movie output.")); - return false; - } -#endif - - // We want png for movie conversion - parameters_->SetString("output.img.format", "png"); - if ( !GraphicsOutputDeviceCairo::Initialize(directory_) ) { - return false; - } - return true; -} - -void GraphicsOutputDeviceMovie::Start() { - GraphicsOutputDeviceCairo::Start(); - // Output a couple of frames to get audio/video in sync, put params in there. - gGrab(); - PlotParameterScreen(); - gRelease(); - gGrab(); - PlotParameterScreen(); - gRelease(); -} - -void GraphicsOutputDeviceMovie::Reset(Parameters* global_parameters) { - Stop(); - Initialize(global_parameters); -} - -void GraphicsOutputDeviceMovie::Stop() { - GraphicsOutputDeviceCairo::Stop(); - CloseFile(); - m_iFileNumber = 0; - -#ifdef __WX__ - // GUI only: popup dialog -#else - printf("Generating movie ... \n"); -#endif - AIM_ASSERT(parameters_); - // Convert images and sound file to a movie. - //! \warning Movie files are overwritten without warning. - char sffmpegPath[1024]; - if (!parameters_->IsSet("output.ffmpeg_path")) { - strcpy(sffmpegPath,"ffmpeg"); - } else { - strcpy(sffmpegPath, parameters_->GetString("output.ffmpeg_path")); - } - char sCodecOptions[1024]; - if (!parameters_->IsSet("output.ffmpeg_codec_options")) { - strcpy(sCodecOptions,""); - } else { - strcpy(sCodecOptions, parameters_->GetString("output.ffmpeg_codec_options")); - } - float frame_rate = global_parameters_->DefaultFloat("frame_rate", -1.0); - char sCmdLine[1024]; //!\todo check that snprintf does not want a larger buffer - snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), - "%s -r %.2f -y -i \"%s\" -i \"%s%%06d.png\" " - "-sameq -r %.2f -ar 44100 -acodec pcm_s16le %s \"%s\"", - sffmpegPath, frame_rate, sound_filename_.c_str(), directory_.c_str(), - frame_rate, sCodecOptions, movie_filename_.c_str()); - printf(sCmdLine); - printf("\n"); - if (system(sCmdLine)) { - LOG_ERROR(_T("Couldn't create movie output.")); - } - -#ifdef __WX__ - // GUI only: close dialog again -#endif - // Remove files in temporary directory and the dir itself - //! \todo make portable function, possibly decided on by build system -#ifdef _WINDOWS - HANDLE hList; - WIN32_FIND_DATA FileData; - snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), "%s/*.*", directory_.c_str()); - if ((hList = FindFirstFile(sCmdLine, &FileData)) == INVALID_HANDLE_VALUE) { - LOG_ERROR(_T("Couldn't remove files from temporary directory.")); - return; - } - bool bRMfinished = false; - while (!bRMfinished) { - snprintf(sCmdLine, - sizeof(sCmdLine)/sizeof(sCmdLine[0]), - "%s%s", - directory_.c_str(), - FileData.cFileName); - remove(sCmdLine); - if (!FindNextFile(hList, &FileData) && GetLastError() == ERROR_NO_MORE_FILES) { - bRMfinished = true; - } - } - FindClose(hList); - _rmdir(directory_.c_str()); -#else - DIR *dir; - struct dirent *dirent; - if (!(dir = opendir(directory_.c_str()))) { - LOG_ERROR(_T("Couldn't remove files in temporary directory.")); - return; - } - while ((dirent = readdir(dir))) { - snprintf(sCmdLine, - sizeof(sCmdLine)/sizeof(sCmdLine[0]), - "%s%s", - directory_.c_str(), - dirent->d_name); - unlink(sCmdLine); - } - closedir(dir); - rmdir(directory_.c_str()); -#endif -} - -void GraphicsOutputDeviceMovie::PlotParameterScreen() { - AIM_ASSERT(parameters_); - char sStr[50]; - int lineno = 1; - - float fMarL = parameters_->GetFloat(_S("graph.margin.left")); - float fMarT = parameters_->GetFloat(_S("graph.margin.top")); - float fTextHeight = 1.0f / 50.0f * 1.2; // change this when fontsizing is there! - - gText2f(fMarL, 1-(fMarT+fTextHeight*lineno++), - _S("AIM-C")); - gText2f(fMarL, - 1-(fMarT+fTextHeight*lineno++), - _S("(c) 2006-2010, Thomas Walters, Willem van Engen")); - gText2f(fMarL, - 1-(fMarT+fTextHeight*lineno++), - _S("http://aimc.acousticscale.org/")); - lineno++; - - static const char *pPlotParams[] = { - _S("input.buffersize"), - _S("input.samplerate"), - _S("bmm.freqstart"), - _S("bmm.freqend"), - _S("bmm.numchannels"), - _S("preset.name"), - _S("preset.title"), - NULL - }; - for (int i = 0; pPlotParams[i]; i++) { - snprintf(sStr, - sizeof(sStr)/sizeof(sStr[0]), _S("%s=%s"), - pPlotParams[i], - parameters_->GetString(pPlotParams[i])); - gText2f(fMarL, - 1-(fMarT+fTextHeight*lineno++), - sStr); - } -} -} // namespace aimc +// Copyright 2006, Willem van Engen +// +// AIM-C: A C++ implementation of the Auditory Image Model +// http://www.acousticscale.org/AIMC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * \file + * \brief Output device for output to a movie + * + * \author Willem van Engen <cnbh@willem.engen.nl> + * \date created 2006/10/16 + * \version \$Id: GraphicsOutputDeviceMovie.cpp 633 2008-09-11 04:20:16Z tom $ + */ + +/*! \todo + * A recent experiment showed that the video was about an audioframe + * (something like 30 ms) behind the audio in rdct.wav. It seems odd + * to me, since I already output a frame at the beginning to compensate + * for the missed buffer. + * A solution that would solve this and be a broader improvement, is to + * include the source's time when Fire()ing. The outputdevice can then + * do audio/video synchronization. In the case of the movie, the very + * first gGrab() looks at the time and emits as much empty output frames + * as needed until the correct signal time is reached. + */ +#include "Support/Common.h" + +#ifdef _WINDOWS +# include <direct.h> // for _mkdir&_rmdir +#else +# include <sys/types.h> +# include <dirent.h> // for opendir&friends +#endif +#include <stdio.h> +#include <string.h> + + +#include "Output/GraphicsOutputDeviceMovie.h" + +GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *pParam) + : GraphicsOutputDeviceCairo(pParam) { // or GraphicsOutputDevicePlotutils + m_sMovieFile[0] = '\0'; + m_sSoundFile[0] = '\0'; +} + +bool GraphicsOutputDeviceMovie::Initialize(const char *sSoundFile, + const char *sMovieFile) { + FILE *f; + AIM_ASSERT(sSoundFile); + AIM_ASSERT(sMovieFile); + + // Check sound file exists + if ((f = fopen(sSoundFile, "r")) == NULL) { + AIM_ERROR(_T("Couldn't open sound file '%s' for movie creation."), + sSoundFile); + return false; + } + fclose(f); + strcpy(m_sSoundFile, sSoundFile); + + // Check movie output file can be made + if ( (f=fopen(sMovieFile, "w"))==NULL ) { + aimERROR(_T("Couldn't open movie file '%s' to write to."), + sMovieFile); + return false; + } + fclose(f); + strcpy(m_sMovieFile, sMovieFile); + + // Get a temporary image output directory + //! \warning Not really safe ... but windows has no mkdtemp() + //! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt. + char *sTmpDir = NULL; +#ifdef _WINDOWS + if ((sTmpDir = _tempnam(NULL, AIM_NAME)) + && _mkdir(sTmpDir) >= 0) { + strcpy(m_sDir, sTmpDir); + strcat(m_sDir, "\\"); // Make sure to end with trailing slash + } else +#else + strcpy(m_sDir, "/tmp/"AIM_NAME"-movie.XXXXXX"); + if (mkdtemp(m_sDir)) { + strcat(m_sDir, "/"); // Make sure to end with trailing slash + } else +#endif + { + AIM_ERROR(_T("Couldn't create a temporary directory for movie output.")); + if (sTmpDir) free(sTmpDir); + return false; + } + if (sTmpDir) { + free(sTmpDir); + } + + // We want png for movie conversion + //! \bug This may change the user preference in GUI, hmm what to do? See TODO.txt + m_pParam->SetString("output.img.format", "png"); + //if ( !GraphicsOutputDevicePlotutils::Initialize(m_sDir) ) { + if ( !GraphicsOutputDeviceCairo::Initialize(m_sDir) ) { + return false; + } + + return true; +} + +void GraphicsOutputDeviceMovie::Start() { + //GraphicsOutputDevicePlotutils::Start(); + GraphicsOutputDeviceCairo::Start(); + // Just output a single frame to get audio/video in sync, put params in there + gGrab(); + PlotParameterScreen(); + gRelease(); +} + +void GraphicsOutputDeviceMovie::Stop() { + // Make sure Plotutils is really done writing. + //GraphicsOutputDevicePlotutils::Stop(); + GraphicsOutputDeviceCairo::Stop(); + CloseFile(); + +#ifdef __WX__ + // GUI only: popup dialog +#else + printf("Generating movie ... \n"); +#endif + AIM_ASSERT(m_pParam); + // Convert images and sound file to a movie + //! \warning Movie files are overwritten without warning + //! \bug ffmpeg only works with colour images, not with bw. So make sure to not use bw only in drawing.. + // Always convert to audio stream of 44.1kHz or problems may occur in playing or conversio. + float fFps = 1000.0 / m_pParam->GetFloat("output.frameperiod"); + char sffmpegPath[1024]; + if (!m_pParam->IsSet("output.ffmpeg_path")) { + strcpy(sffmpegPath,"ffmpeg"); + } else { + strcpy(sffmpegPath, m_pParam->GetString("output.ffmpeg_path")); + } + char sCodecOptions[1024]; + if (!m_pParam->IsSet("output.ffmpeg_codec_options")) { + strcpy(sCodecOptions,""); + } else { + strcpy(sCodecOptions, m_pParam->GetString("output.ffmpeg_codec_options")); + } + + char sCmdLine[1024]; //!\todo check that snprintf does not want a larger buffer + snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), + "%s -r %.2f -y -i \"%s\" -i \"%s%%06d.png\" " + "-title \"%s\" -comment \"Generated by "AIM_NAME" "AIM_VERSION_STRING"\" " + "-sameq -r %.2f -ar 44100 -acodec pcm_s16le %s \"%s\"", + sffmpegPath, fFps, m_sSoundFile, m_sDir, + m_pParam->GetString("output.movie.title"), + fFps, sCodecOptions, m_sMovieFile); + printf(sCmdLine); + printf("\n"); + if (system(sCmdLine)) { + AIM_ERROR(_T("Couldn't create movie output.")); + } + +#ifdef __WX__ + // GUI only: close dialog again +#endif + // Remove files in temporary directory and the dir itself + //! \todo make portable function, possibly decided on by build system +#ifdef _WINDOWS + HANDLE hList; + WIN32_FIND_DATA FileData; + snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), "%s/*.*", m_sDir); + if ((hList = FindFirstFile(sCmdLine, &FileData)) == INVALID_HANDLE_VALUE) { + AIM_ERROR(_T("Couldn't remove files from temporary directory.")); + return; + } + bool bRMfinished = false; + while (!bRMfinished) { + snprintf(sCmdLine, + sizeof(sCmdLine)/sizeof(sCmdLine[0]), + "%s%s", + m_sDir, + FileData.cFileName); + remove(sCmdLine); + if (!FindNextFile(hList, &FileData) && GetLastError() == ERROR_NO_MORE_FILES) { + bRMfinished = true; + } + } + FindClose(hList); + _rmdir(m_sDir); +#else + DIR *dir; + struct dirent *dirent; + if (!(dir = opendir(m_sDir))) { + AIM_ERROR(_T("Couldn't remove files in temporary directory.")); + return; + } + while (dirent = readdir(dir)) { + snprintf(sCmdLine, + sizeof(sCmdLine)/sizeof(sCmdLine[0]), + "%s%s", + m_sDir, + dirent->d_name); + unlink(sCmdLine); + } + closedir(dir); + rmdir(m_sDir); +#endif +} + +void GraphicsOutputDeviceMovie::PlotParameterScreen() { + AIM_ASSERT(m_pParam); + char sStr[50]; + int lineno = 1; + + float fMarL = m_pParam->GetFloat(_S("graph.margin.left")); + float fMarT = m_pParam->GetFloat(_S("graph.margin.top")); + float fTextHeight = 1.0f / 50.0f * 1.2; // change this when fontsizing is there! + + gText2f(fMarL, 1-(fMarT+fTextHeight*lineno++), + _S("AIM-C")); + gText2f(fMarL, + 1-(fMarT+fTextHeight*lineno++), + _S("(c) 2006-2010, Thomas Walters, Willem van Engen")); + gText2f(fMarL, + 1-(fMarT+fTextHeight*lineno++), + _S("http://aimc.acousticscale.org/")); + lineno++; + + static const char *pPlotParams[] = { + _S("input.buffersize"), + _S("input.samplerate"), + _S("bmm.freqstart"), + _S("bmm.freqend"), + _S("bmm.numchannels"), + _S("preset.name"), + _S("preset.title"), + NULL + }; + for (int i = 0; pPlotParams[i]; i++) { + snprintf(sStr, + sizeof(sStr)/sizeof(sStr[0]), _S("%s=%s"), + pPlotParams[i], + m_pParam->GetString(pPlotParams[i])); + gText2f(fMarL, + 1-(fMarT+fTextHeight*lineno++), + sStr); + } +}
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h Fri Oct 15 05:40:53 2010 +0000 @@ -27,11 +27,10 @@ #ifndef __GRAPHICS_OUTPUT_DEVICE_MOVIE_H__ #define __GRAPHICS_OUTPUT_DEVICE_MOVIE_H__ -#include <string> +#include "Support/util.h" +//#include "Modules/Output/Graphics/Devices/GraphicsOutputDevicePlotutils.h" #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h" -namespace aimc { - /*! * \class GraphicsOutputDeviceMovie "Output/GraphicsOutputDeviceMovie.h" * \brief Output class for output to a movie @@ -39,41 +38,38 @@ // GraphicsOutputDevicePlotutils is also possible here class GraphicsOutputDeviceMovie : public GraphicsOutputDeviceCairo { public: - GraphicsOutputDeviceMovie(Parameters *parameters); - virtual ~GraphicsOutputDeviceMovie() { }; + GraphicsOutputDeviceMovie(AimParameters *pParam); + virtual ~GraphicsOutputDeviceMovie() { }; - /*! \brief Initializes this output device, prepares plotting tools. - * \param sSoundFile Sound file for the movie - * \param sMovieFile Movie filename to produce - * \return true on success, false on failure. - * - * As usual, make sure to call this function before any other. If this - * Initialize() failed, you shouldn't try the other functions either. - */ - bool Initialize(Parameters *global_parameters); + /*! \brief Initializes this output device, prepares plotting tools. + * \param sSoundFile Sound file for the movie + * \param sMovieFile Movie filename to produce + * \return true on success, false on failure. + * + * As usual, make sure to call this function before any other. If this + * Initialize() failed, you shouldn't try the other functions either. + */ + bool Initialize(const char *sSoundFile, const char *sMovieFile); - void Start(); - //! \brief This function now also generates the output movie. - void Stop(); - - void Reset(Parameters* global_parameters); - + void Start(); + //! \brief This function now also generates the output movie. + void Stop(); protected: - /*! \brief Plots a summary of relevant parameters on the output - * - * This is intended for use in a movie as the first frame, which has no - * interesting data anyway, since at least one buffer of data is needed - * to be able to show someting. - * - * The caller must do the gGrab() and gRelease(). - */ - void PlotParameterScreen(); + /*! \brief Plots a summary of relevant parameters on the output + * + * This is intended for use in a movie as the first frame, which has no + * interesting data anyway, since at least one buffer of data is needed + * to be able to show someting. + * + * The caller must do the gGrab() and gRelease(). + */ + void PlotParameterScreen(); - //! \brief Name of the sound file to be merged with the video - string sound_filename_; - //! \brief Name of the movie file to produce - string movie_filename_; + //! \brief Name of the sound file to be merged with the video + char m_sSoundFile[PATH_MAX]; + //! \brief Name of the movie file to produce + char m_sMovieFile[PATH_MAX]; }; -} // namespace aimc + #endif /* __GRAPHICS_OUTPUT_DEVICE_MOVIE_H__ */
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.cc Fri Oct 15 05:40:53 2010 +0000 @@ -31,42 +31,41 @@ #include <string.h> #include <math.h> -#include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.h" - -namespace aimc { +#include "Support/util.h" +#include "Output/GraphicsOutputDeviceMovieDirect.h" GraphicsOutputDeviceMovieDirect::GraphicsOutputDeviceMovieDirect(Parameters *params) - : GraphicsOutputDeviceMovie(params) { - m_sMovieFile[0] = '\0'; - m_sSoundFile[0] = '\0'; + : GraphicsOutputDeviceMovie(params) { + m_sMovieFile[0] = '\0'; + m_sSoundFile[0] = '\0'; } bool GraphicsOutputDeviceMovieDirect::Initialize(const char *sSoundFile, const char *sMovieFile) { - // We want pnm for direct movie conversion as the data format is nice and simple - //! \bug This may change the user preference in GUI, hmm what to do? See TODO.txt - //m_pParam->SetString("output.img.format", "pnm"); + // We want pnm for direct movie conversion as the data format is nice and simple + //! \bug This may change the user preference in GUI, hmm what to do? See TODO.txt + //m_pParam->SetString("output.img.format", "pnm"); - // Initialise GraphicsOutputDevicePlotutils for memory buffer use - if(!GraphicsOutputDeviceCairo::Initialize()) + // Initialise GraphicsOutputDevicePlotutils for memory buffer use + if(!GraphicsOutputDeviceCairo::Initialize()) return false; int width = m_pParam->GetUInt("output.img.width"); - int height = m_pParam->GetUInt("output.img.height"); - //float framerate = 1000.0f/m_pParam->GetFloat("output.frameperiod"); - float framerate=1000.0f/20.0f; + int height = m_pParam->GetUInt("output.img.height"); + //float framerate = 1000.0f/m_pParam->GetFloat("output.frameperiod"); + float framerate=1000.0f/20.0f; m_pOutputMovie = new LibavformatWriter; - m_pOutputMovie->Init(sMovieFile, width, height, framerate); + m_pOutputMovie->Init(sMovieFile, width, height, framerate); - return true; + return true; } void GraphicsOutputDeviceMovieDirect::Stop() { - // Make sure Plotutils is really done writing. - GraphicsOutputDeviceCairo::Stop(); - m_pOutputMovie->End(); - delete m_pOutputMovie; + // Make sure Plotutils is really done writing. + GraphicsOutputDeviceCairo::Stop(); + m_pOutputMovie->End(); + delete m_pOutputMovie; } @@ -393,6 +392,5 @@ unsigned char *pFrameBuffer, int width, int height) { - memcpy((void*)&(pict->data[0][0]), (void*)pFrameBuffer, width*height*4); + memcpy((void*)&(pict->data[0][0]), (void*)pFrameBuffer, width*height*4); } -} // namespace aimc
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.h Fri Oct 15 05:40:53 2010 +0000 @@ -34,8 +34,6 @@ #include <ffmpeg/swscale.h> } -namespace aimc { - /*! * \class LibavformatWriter "Output/GraphicsOutputDeviceMovieDirect.h" * \brief Helper class to use libavcodec to write a movie file @@ -43,10 +41,10 @@ class LibavformatWriter { public: LibavformatWriter(); - ~LibavformatWriter() { }; - bool Init(const char *sMovieFile, int width, int height, float framerate); - void WriteFrame(unsigned char *pFrameBuffer); - void End(); + ~LibavformatWriter() { }; + bool Init(const char *sMovieFile, int width, int height, float framerate); + void WriteFrame(unsigned char *pFrameBuffer); + void End(); private: AVFrame *picture, *tmp_picture; uint8_t *video_outbuf; @@ -72,20 +70,20 @@ class GraphicsOutputDeviceMovieDirect : public GraphicsOutputDeviceMovie { public: GraphicsOutputDeviceMovieDirect(AimParameters *pParam); - virtual ~GraphicsOutputDeviceMovieDirect() { }; - /*! \brief Initializes this output device, prepares plotting tools. - * \param sSoundFile Sound file for the movie - * \param sMovieFile Movie filename to produce - * \return true on success, false on failure. - * - * As usual, make sure to call this function before any other. If this - * Initialize() failed, you shouldn't try the other functions either. - */ - bool Initialize(const char *sSoundFile, const char *sMovieFile); - void Stop(); + virtual ~GraphicsOutputDeviceMovieDirect() { }; + /*! \brief Initializes this output device, prepares plotting tools. + * \param sSoundFile Sound file for the movie + * \param sMovieFile Movie filename to produce + * \return true on success, false on failure. + * + * As usual, make sure to call this function before any other. If this + * Initialize() failed, you shouldn't try the other functions either. + */ + bool Initialize(const char *sSoundFile, const char *sMovieFile); + void Stop(); void gRelease(); private: - LibavformatWriter* m_pOutputMovie; + LibavformatWriter* m_pOutputMovie; }; -} // namespace aimc + #endif /* __GRAPHICS_OUTPUT_DEVICE_MOVIE_DIRECT_H__ */
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicePlotutils.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicePlotutils.cc Fri Oct 15 05:40:53 2010 +0000 @@ -36,53 +36,53 @@ GraphicsOutputDevicePlotutils::GraphicsOutputDevicePlotutils(Parameters *pParam) : GraphicsOutputDevice(pParam) { - m_iPlotHandle = 0; - m_pOutputFile = NULL; - m_iFileNumber = 0; - m_iVertexType = VertexTypeNone; - m_bUseMemoryBuffer = false; - m_pMemoryBuffer = NULL; - m_uWidth=0; - m_uHeight=0; + m_iPlotHandle = 0; + m_pOutputFile = NULL; + m_iFileNumber = 0; + m_iVertexType = VertexTypeNone; + m_bUseMemoryBuffer = false; + m_pMemoryBuffer = NULL; + m_uWidth=0; + m_uHeight=0; } bool GraphicsOutputDevicePlotutils::Initialize(const char *sDir) { Init(); - //! \todo Output to file if sDir is a file, to directory with multiple + //! \todo Output to file if sDir is a file, to directory with multiple //! images if it's a directory. - strncpy(m_sDir, sDir, sizeof(m_sDir)/sizeof(m_sDir[0])); + strncpy(m_sDir, sDir, sizeof(m_sDir)/sizeof(m_sDir[0])); - /* Try to open an image to see if everything is allright. We want to avoid - * errors in the main Process()ing loop. */ - if (!OpenFile(0)) { - //! \todo Better error message that is more specific about the cause. - AIM_ERROR(_T("Could not open output directory '%s' using graphics format '%s'."), - m_sDir, m_pParam->GetString("output.img.format") ); - return false; - } - CloseFile(); - return true; + /* Try to open an image to see if everything is allright. We want to avoid + * errors in the main Process()ing loop. */ + if (!OpenFile(0)) { + //! \todo Better error message that is more specific about the cause. + AIM_ERROR(_T("Could not open output directory '%s' using graphics format '%s'."), + m_sDir, m_pParam->GetString("output.img.format") ); + return false; + } + CloseFile(); + return true; } void GraphicsOutputDevicePlotutils::Init() { AIM_ASSERT(m_pParam); - /* - * Set parameters - */ - pl_parampl("BG_COLOR", (void*)m_pParam->GetString("output.img.color.background")); - // Handle GIFs as other output formats, don't merge frames into single GIF. - pl_parampl("GIF_ANIMATION", (void*)"no"); - pl_parampl("INTERLACE", (void*)"no"); + /* + * Set parameters + */ + pl_parampl("BG_COLOR", (void*)m_pParam->GetString("output.img.color.background")); + // Handle GIFs as other output formats, don't merge frames into single GIF. + pl_parampl("GIF_ANIMATION", (void*)"no"); + pl_parampl("INTERLACE", (void*)"no"); - m_bInvertColors = m_pParam->GetBool("output.img.color.invert"); + m_bInvertColors = m_pParam->GetBool("output.img.color.invert"); - // Output size! - m_uWidth = m_pParam->GetUInt("output.img.width"); - m_uHeight = m_pParam->GetUInt("output.img.height"); - char strSize[100]; - snprintf(strSize, sizeof(strSize)/sizeof(strSize[0]), "%ux%u", m_uWidth, m_uHeight); - pl_parampl("BITMAPSIZE", (void*)strSize); + // Output size! + m_uWidth = m_pParam->GetUInt("output.img.width"); + m_uHeight = m_pParam->GetUInt("output.img.height"); + char strSize[100]; + snprintf(strSize, sizeof(strSize)/sizeof(strSize[0]), "%ux%u", m_uWidth, m_uHeight); + pl_parampl("BITMAPSIZE", (void*)strSize); } bool GraphicsOutputDevicePlotutils::Initialize() { @@ -136,30 +136,30 @@ strPlottype="pnm"; // Force pnm format or this doesn't work } - /* - * Create a plotter - * - * Plotutils knows the following types for file output: - * pnm gif ai ps gif pcl hpgl tek meta - */ - if ((m_iPlotHandle = pl_newpl(strPlottype, + /* + * Create a plotter + * + * Plotutils knows the following types for file output: + * pnm gif ai ps gif pcl hpgl tek meta + */ + if ((m_iPlotHandle = pl_newpl(strPlottype, NULL, m_pOutputFile, stderr)) < 0 ) { - return false; - } - pl_selectpl(m_iPlotHandle); + return false; + } + pl_selectpl(m_iPlotHandle); - if ( pl_openpl() < 0) { - return false; - } + if ( pl_openpl() < 0) { + return false; + } - // Now setup things for this plotter - pl_fontname(m_pParam->GetString("output.img.fontname")); - //! \todo Make fontsize work in Plotutils, currently disabled - //pl_ffontsize(m_pParam->GetUInt("output.fontsize")); + // Now setup things for this plotter + pl_fontname(m_pParam->GetString("output.img.fontname")); + //! \todo Make fontsize work in Plotutils, currently disabled + //pl_ffontsize(m_pParam->GetUInt("output.fontsize")); - return true; + return true; } char* GraphicsOutputDevicePlotutils::GetBuffer() { @@ -170,27 +170,27 @@ } void GraphicsOutputDevicePlotutils::CloseFile() { - // Plotting library - if (m_iPlotHandle>0) { - pl_closepl(); + // Plotting library + if (m_iPlotHandle>0) { + pl_closepl(); - pl_selectpl(0); - pl_deletepl(m_iPlotHandle); - m_iPlotHandle = 0; - } + pl_selectpl(0); + pl_deletepl(m_iPlotHandle); + m_iPlotHandle = 0; + } - // And the output file - if (m_pOutputFile) { - fclose(m_pOutputFile); - m_pOutputFile = NULL; - } + // And the output file + if (m_pOutputFile) { + fclose(m_pOutputFile); + m_pOutputFile = NULL; + } } GraphicsOutputDevicePlotutils::~GraphicsOutputDevicePlotutils() { - // Output file should be closed by gRelease() - AIM_ASSERT(!m_pOutputFile); - AIM_ASSERT(!m_iPlotHandle); - CloseFile(); + // Output file should be closed by gRelease() + AIM_ASSERT(!m_pOutputFile); + AIM_ASSERT(!m_iPlotHandle); + CloseFile(); } PixelFormat GraphicsOutputDevicePlotutils::GetPixelFormat() { @@ -198,91 +198,91 @@ } void GraphicsOutputDevicePlotutils::gGrab() { - // Open file - if (!OpenFile(m_iFileNumber)) { - return; + // Open file + if (!OpenFile(m_iFileNumber)) { + return; } - // Setup plotting area - pl_fspace(0.0, 0.0, 1.0, 1.0); - pl_flinewidth(0.0001); - pl_pencolorname("darkblue"); - pl_erase(); + // Setup plotting area + pl_fspace(0.0, 0.0, 1.0, 1.0); + pl_flinewidth(0.0001); + pl_pencolorname("darkblue"); + pl_erase(); } void GraphicsOutputDevicePlotutils::gBeginLineStrip() { - m_bIsFirstVertex = true; - m_iVertexType = VertexTypeLine; - pl_filltype(0); + m_bIsFirstVertex = true; + m_iVertexType = VertexTypeLine; + pl_filltype(0); } void GraphicsOutputDevicePlotutils::gBeginQuadStrip() { - m_bIsFirstVertex = true; - m_iVertexType = VertexTypeQuad; - m_iPrevVertexCount = 0; - pl_filltype(1); + m_bIsFirstVertex = true; + m_iVertexType = VertexTypeQuad; + m_iPrevVertexCount = 0; + pl_filltype(1); } void GraphicsOutputDevicePlotutils::gColor3f(float r, float g, float b) { - if (m_bInvertColors) { - r = 1-r; - g = 1-g; - b = 1-b; - } - int ir = (int)(r*0xffff); - int ig = (int)(g*0xffff); - int ib = (int)(b*0xffff); - ir = MIN(0xffff, MAX(0,ir)); - ig = MIN(0xffff, MAX(0,ig)); - ib = MIN(0xffff, MAX(0,ib)); - pl_color(ir, ig, ib); + if (m_bInvertColors) { + r = 1-r; + g = 1-g; + b = 1-b; + } + int ir = (int)(r*0xffff); + int ig = (int)(g*0xffff); + int ib = (int)(b*0xffff); + ir = MIN(0xffff, MAX(0,ir)); + ig = MIN(0xffff, MAX(0,ig)); + ib = MIN(0xffff, MAX(0,ib)); + pl_color(ir, ig, ib); } void GraphicsOutputDevicePlotutils::gVertex3f(float x, float y, float z) { - switch(m_iVertexType) { - case VertexTypeLine: - if (m_bIsFirstVertex) { - m_bIsFirstVertex = false; - pl_fmove(x, y); - } else { - pl_fcont(x, y); - } - break; - case VertexTypeQuad: - /* Store vertices until we got four in a row. - * The order of vertices when processing quads is: - * 1-----3-----5 - * | | | - * 0-----2-----4 - */ - if (m_iPrevVertexCount>=3) { - // Plot this quad - pl_fmove(m_aPrevX[0],m_aPrevY[0]); - pl_fcont(m_aPrevX[1],m_aPrevY[1]); - pl_fcont(x,y); - pl_fcont(m_aPrevX[2],m_aPrevY[2]); - pl_endpath(); - // Last vertices of this quad are the first of the next - m_aPrevX[0] = m_aPrevX[2]; - m_aPrevY[0] = m_aPrevY[2]; - m_aPrevX[1] = x; - m_aPrevY[1] = y; - m_iPrevVertexCount = 2; - } else { - // Not at the fourth, keep storing - m_aPrevX[m_iPrevVertexCount] = x; - m_aPrevY[m_iPrevVertexCount] = y; - m_iPrevVertexCount++; - } - break; - default: - // Should not happen - AIM_ASSERT(0); - } + switch(m_iVertexType) { + case VertexTypeLine: + if (m_bIsFirstVertex) { + m_bIsFirstVertex = false; + pl_fmove(x, y); + } else { + pl_fcont(x, y); + } + break; + case VertexTypeQuad: + /* Store vertices until we got four in a row. + * The order of vertices when processing quads is: + * 1-----3-----5 + * | | | + * 0-----2-----4 + */ + if (m_iPrevVertexCount>=3) { + // Plot this quad + pl_fmove(m_aPrevX[0],m_aPrevY[0]); + pl_fcont(m_aPrevX[1],m_aPrevY[1]); + pl_fcont(x,y); + pl_fcont(m_aPrevX[2],m_aPrevY[2]); + pl_endpath(); + // Last vertices of this quad are the first of the next + m_aPrevX[0] = m_aPrevX[2]; + m_aPrevY[0] = m_aPrevY[2]; + m_aPrevX[1] = x; + m_aPrevY[1] = y; + m_iPrevVertexCount = 2; + } else { + // Not at the fourth, keep storing + m_aPrevX[m_iPrevVertexCount] = x; + m_aPrevY[m_iPrevVertexCount] = y; + m_iPrevVertexCount++; + } + break; + default: + // Should not happen + AIM_ASSERT(0); + } } void GraphicsOutputDevicePlotutils::gEnd() { - pl_endpath(); - m_iVertexType = VertexTypeNone; + pl_endpath(); + m_iVertexType = VertexTypeNone; } void GraphicsOutputDevicePlotutils::gText3f(float x, @@ -290,20 +290,20 @@ float z, const char *sStr, bool bRotated) { - if (bRotated) { - pl_textangle(90); - pl_fmove(x, y); - pl_alabel('l', 't', sStr); - } else { - pl_textangle(0); - pl_fmove(x, y); - pl_alabel('l', 'b', sStr); - } + if (bRotated) { + pl_textangle(90); + pl_fmove(x, y); + pl_alabel('l', 't', sStr); + } else { + pl_textangle(0); + pl_fmove(x, y); + pl_alabel('l', 'b', sStr); + } } void GraphicsOutputDevicePlotutils::gRelease() { - AIM_ASSERT(m_pOutputFile); - AIM_ASSERT(m_iPlotHandle>0); - CloseFile(); - m_iFileNumber++; + AIM_ASSERT(m_pOutputFile); + AIM_ASSERT(m_iPlotHandle>0); + CloseFile(); + m_iFileNumber++; }
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicePlotutils.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicePlotutils.h Fri Oct 15 05:40:53 2010 +0000 @@ -47,87 +47,87 @@ GraphicsOutputDevicePlotutils(Parameters *pParam); virtual ~GraphicsOutputDevicePlotutils(); - /*! \brief Initializes this output device, prepares plotting tools. - * \param sDir Directory or filename where to put images, max length + /*! \brief Initializes this output device, prepares plotting tools. + * \param sDir Directory or filename where to put images, max length * is _MAX_PATH. Must end with slash!!! - * \return true on success, false on failure. - * - * sDir can be either a filename, in which case the output will be - * to that file, or a directory, in which case it will be filled - * with 6-digit numbered files. A new file is then created at every - * call to gGrab(). - * - * As usual, make sure to call this function before any other. If this - * Initialize() failed, you shouldn't try the other functions either. - */ - bool Initialize(const char *sDir); - bool Initialize(); + * \return true on success, false on failure. + * + * sDir can be either a filename, in which case the output will be + * to that file, or a directory, in which case it will be filled + * with 6-digit numbered files. A new file is then created at every + * call to gGrab(). + * + * As usual, make sure to call this function before any other. If this + * Initialize() failed, you shouldn't try the other functions either. + */ + bool Initialize(const char *sDir); + bool Initialize(); void gGrab(); void gBeginLineStrip(); void gBeginQuadStrip(); - using GraphicsOutputDevice::gVertex3f; // Because we overload it - void gVertex3f(float x, float y, float z); - void gColor3f(float r, float g, float b); + using GraphicsOutputDevice::gVertex3f; // Because we overload it + void gVertex3f(float x, float y, float z); + void gColor3f(float r, float g, float b); void gEnd(); - void gText3f(float x, float y, float z, const char *sStr, bool bRotated = false); - void gRelease(); - char* GetBuffer(); + void gText3f(float x, float y, float z, const char *sStr, bool bRotated = false); + void gRelease(); + char* GetBuffer(); protected: - /*! \brief Open the file with given index for output - * \param index File number to open - * \return true on success, false on error - * - * This opens a file for output and sets up the plotting library. - */ - bool OpenFile(unsigned int index); + /*! \brief Open the file with given index for output + * \param index File number to open + * \return true on success, false on error + * + * This opens a file for output and sets up the plotting library. + */ + bool OpenFile(unsigned int index); - //! \brief Closes a plot output file, if any is open. - void CloseFile(); + //! \brief Closes a plot output file, if any is open. + void CloseFile(); - //! \brief Internal initialisation function called by overloaded variants of Initialize() - void Init(); + //! \brief Internal initialisation function called by overloaded variants of Initialize() + void Init(); - //! \brief The current output file's handle - FILE *m_pOutputFile; - //! \brief The plotutils plotter - int m_iPlotHandle; - //! \brief Output directory - char m_sDir[PATH_MAX]; - //! \brief Current file number - unsigned int m_iFileNumber; - //! \brief true if this is the first vertex after gBegin() - bool m_bIsFirstVertex; + //! \brief The current output file's handle + FILE *m_pOutputFile; + //! \brief The plotutils plotter + int m_iPlotHandle; + //! \brief Output directory + char m_sDir[PATH_MAX]; + //! \brief Current file number + unsigned int m_iFileNumber; + //! \brief true if this is the first vertex after gBegin() + bool m_bIsFirstVertex; - enum VertexType { - VertexTypeNone, + enum VertexType { + VertexTypeNone, VertexTypeLine, VertexTypeQuad - }; - //! \brief The current vertex type - VertexType m_iVertexType; - //! \brief Begin vertex of current quad - float m_aPrevX[3], m_aPrevY[3]; - //! \brief Current number of quad vertices stored - unsigned int m_iPrevVertexCount; + }; + //! \brief The current vertex type + VertexType m_iVertexType; + //! \brief Begin vertex of current quad + float m_aPrevX[3], m_aPrevY[3]; + //! \brief Current number of quad vertices stored + unsigned int m_iPrevVertexCount; - //! \brief Whether to invert the colors or not - bool m_bInvertColors; + //! \brief Whether to invert the colors or not + bool m_bInvertColors; - //! \brief The size of the memory bitmap buffer as provided by open_memstream - size_t m_sMemoryBufferSize; + //! \brief The size of the memory bitmap buffer as provided by open_memstream + size_t m_sMemoryBufferSize; - //! \brief Are we using a memory buffer for writing to (as opposed to a file)? - bool m_bUseMemoryBuffer; + //! \brief Are we using a memory buffer for writing to (as opposed to a file)? + bool m_bUseMemoryBuffer; - //! \brief Pointer to the memory buffer in question - char *m_pMemoryBuffer; + //! \brief Pointer to the memory buffer in question + char *m_pMemoryBuffer; - //! \brief Width of the bitmap - unsigned int m_uWidth; + //! \brief Width of the bitmap + unsigned int m_uWidth; - //! \brief Height of the bitmap - unsigned int m_uHeight; + //! \brief Height of the bitmap + unsigned int m_uHeight; }; #endif /* __GRAPHICS_OUTPUT_DEVICE_PLOTUTILS_H__ */
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicewxGLCanvas.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicewxGLCanvas.cc Fri Oct 15 05:40:53 2010 +0000 @@ -72,144 +72,144 @@ typedef void (*(*glGetProcAddressPtr_t)(const char*))(); GraphicsOutputDevicewxGLCanvas::GraphicsOutputDevicewxGLCanvas(Parameters *pParam, - wxWindow *parent, + wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name) - : wxGLCanvas(parent, (wxGLCanvas*) NULL, id, pos, size, + : wxGLCanvas(parent, (wxGLCanvas*) NULL, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE, name, GLAttrlist), - GraphicsOutputDevice(pParam) { - m_init = false; - m_gllist = 0; - m_pWorkerContext = NULL; - m_bAntialiasing = true; - m_pFont = NULL; - m_sFontFile = NULL; - m_iFontsize = -1; + GraphicsOutputDevice(pParam) { + m_init = false; + m_gllist = 0; + m_pWorkerContext = NULL; + m_bAntialiasing = true; + m_pFont = NULL; + m_sFontFile = NULL; + m_iFontsize = -1; #if !defined(_MACOSX) - s_bWorkerNeedsInit = false; + s_bWorkerNeedsInit = false; #endif #ifdef WITH_GL_VERTEX_ARRAYS - m_iVertexType = 0xffff; // no gBegin() has happened yet - m_bStaticColor = false; - m_pVertices = NULL; - m_iVerticesMax = 0; - // Enable vertex arrays if possible + m_iVertexType = 0xffff; // no gBegin() has happened yet + m_bStaticColor = false; + m_pVertices = NULL; + m_iVerticesMax = 0; + // Enable vertex arrays if possible #ifdef _MACOSX - m_glLockArraysEXT = ::glLockArraysEXT; - m_glUnlockArraysEXT = ::glUnlockArraysEXT; - m_bVertexArrayLock = true; + m_glLockArraysEXT = ::glLockArraysEXT; + m_glUnlockArraysEXT = ::glUnlockArraysEXT; + m_bVertexArrayLock = true; #else - m_bVertexArrayLock = false; - // OpenGL command needed to fetch entry point, do it in InitGL() + m_bVertexArrayLock = false; + // OpenGL command needed to fetch entry point, do it in InitGL() #endif /* _MACOSX */ #endif /* WITH_GL_VERTEX_ARRAYS */ } GraphicsOutputDevicewxGLCanvas::~GraphicsOutputDevicewxGLCanvas() { - // Cleanup OpenGL display list - if (m_init) { - glDeleteLists(m_gllist, 1); - } - DELETE_IF_NONNULL(m_pWorkerContext); - DELETE_IF_NONNULL(m_pFont); + // Cleanup OpenGL display list + if (m_init) { + glDeleteLists(m_gllist, 1); + } + DELETE_IF_NONNULL(m_pWorkerContext); + DELETE_IF_NONNULL(m_pFont); #ifdef WITH_GL_VERTEX_ARRAYS - DELETE_ARRAY_IF_NONNULL(m_pVertices); + DELETE_ARRAY_IF_NONNULL(m_pVertices); #endif } void GraphicsOutputDevicewxGLCanvas::Start() { - // This seems to be needed to prevent a crash on windows, but why???? - SetCurrent(); - return GraphicsOutputDevice::Start(); + // This seems to be needed to prevent a crash on windows, but why???? + SetCurrent(); + return GraphicsOutputDevice::Start(); } bool GraphicsOutputDevicewxGLCanvas::Initialize(unsigned int iVerticesMax) { - AIM_ASSERT(m_pParam); - // Give a chance to update anti-aliasing settings - if (m_bAntialiasing != m_pParam->GetBool("output.antialias")) { - m_bAntialiasing = m_pParam->GetBool("output.antialias"); - if (SetCurrent()) { - InitGL(); + AIM_ASSERT(m_pParam); + // Give a chance to update anti-aliasing settings + if (m_bAntialiasing != m_pParam->GetBool("output.antialias")) { + m_bAntialiasing = m_pParam->GetBool("output.antialias"); + if (SetCurrent()) { + InitGL(); #if !defined(_MACOSX) - { - wxMutexLocker lock(s_mutexOpenGL); - s_bWorkerNeedsInit = true; - } + { + wxMutexLocker lock(s_mutexOpenGL); + s_bWorkerNeedsInit = true; + } #endif - } - } + } + } #ifdef WITH_GL_VERTEX_ARRAYS - // Re-allocate vertices - if (iVerticesMax > m_iVerticesMax) { - DELETE_IF_NONNULL(m_pVertices); - m_iVerticesMax = iVerticesMax; - // If color is static, we need not store the color - if (m_bStaticColor) - m_pVertices = new GLfloat[(iVerticesMax+1)*3]; - else - m_pVertices = new GLfloat[(iVerticesMax+1)*6]; - } + // Re-allocate vertices + if (iVerticesMax > m_iVerticesMax) { + DELETE_IF_NONNULL(m_pVertices); + m_iVerticesMax = iVerticesMax; + // If color is static, we need not store the color + if (m_bStaticColor) + m_pVertices = new GLfloat[(iVerticesMax+1)*3]; + else + m_pVertices = new GLfloat[(iVerticesMax+1)*6]; + } #endif // Change font if requested - const char *sFontFile = m_pParam->GetString("output.gl.fontfile"); - unsigned int iFontsize = m_pParam->GetUInt("output.fontsize"); - if (!m_sFontFile + const char *sFontFile = m_pParam->GetString("output.gl.fontfile"); + unsigned int iFontsize = m_pParam->GetUInt("output.fontsize"); + if (!m_sFontFile || !strcmp(m_sFontFile,sFontFile)==0 || m_iFontsize!=(int)iFontsize) { - wxMutexLocker lock(s_mutexOpenGL); - DELETE_IF_NONNULL(m_pFont); - wxString sWorkingFontFilename = wxString::FromAscii(sFontFile); - if (!wxFileExists(sWorkingFontFilename)) { - sWorkingFontFilename = wxString::FromAscii(aimDataDir()); - sWorkingFontFilename += _T("/"); - sWorkingFontFilename += wxString::FromAscii(sFontFile); - } - //if (!wxFileExists(sWorkingFontFilename)) - //sWorkingFontFilename.replace("Font:").append(sFontFile); - m_pFont = static_cast<FTFont*>(new FTGLBitmapFont(sWorkingFontFilename.fn_str())); - if (!m_pFont || m_pFont->Error()) { - aimERROR(_T("Couldn't load font '%s'"), sFontFile); - DELETE_IF_NONNULL(m_pFont); - } else { - // Display lists don't mix with our own usage :( - // May not be needed for a Bitmap font - //m_pFont->UseDisplayList(false); - if ( !m_pFont->FaceSize(iFontsize) ) { - AIM_ERROR(_T("Couldn't select font size %u on font '%s'"), iFontsize, sFontFile); - DELETE_IF_NONNULL(m_pFont); - } - } - m_sFontFile = sFontFile; - m_iFontsize = iFontsize; - } - return true; + wxMutexLocker lock(s_mutexOpenGL); + DELETE_IF_NONNULL(m_pFont); + wxString sWorkingFontFilename = wxString::FromAscii(sFontFile); + if (!wxFileExists(sWorkingFontFilename)) { + sWorkingFontFilename = wxString::FromAscii(aimDataDir()); + sWorkingFontFilename += _T("/"); + sWorkingFontFilename += wxString::FromAscii(sFontFile); + } + //if (!wxFileExists(sWorkingFontFilename)) + //sWorkingFontFilename.replace("Font:").append(sFontFile); + m_pFont = static_cast<FTFont*>(new FTGLBitmapFont(sWorkingFontFilename.fn_str())); + if (!m_pFont || m_pFont->Error()) { + aimERROR(_T("Couldn't load font '%s'"), sFontFile); + DELETE_IF_NONNULL(m_pFont); + } else { + // Display lists don't mix with our own usage :( + // May not be needed for a Bitmap font + //m_pFont->UseDisplayList(false); + if ( !m_pFont->FaceSize(iFontsize) ) { + AIM_ERROR(_T("Couldn't select font size %u on font '%s'"), iFontsize, sFontFile); + DELETE_IF_NONNULL(m_pFont); + } + } + m_sFontFile = sFontFile; + m_iFontsize = iFontsize; + } + return true; } bool GraphicsOutputDevicewxGLCanvas::Initialize() { - return Initialize(0); + return Initialize(0); } void GraphicsOutputDevicewxGLCanvas::Render() { - wxPaintDC dc(this); - // We want to initialize first from main thread. - if (!m_init) { - if (!SetCurrent()) return; - InitGL(); - } - // Render saved list only if not animating (redrawn anyway in that case) - if (!m_bRunning) { - if (!SetCurrent()) { + wxPaintDC dc(this); + // We want to initialize first from main thread. + if (!m_init) { + if (!SetCurrent()) return; + InitGL(); + } + // Render saved list only if not animating (redrawn anyway in that case) + if (!m_bRunning) { + if (!SetCurrent()) { return; } - glClear(GL_COLOR_BUFFER_BIT/*|GL_DEPTH_BUFFER_BIT*/); - glCallList(m_gllist); - SwapBuffers(); - } + glClear(GL_COLOR_BUFFER_BIT/*|GL_DEPTH_BUFFER_BIT*/); + glCallList(m_gllist); + SwapBuffers(); + } } void GraphicsOutputDevicewxGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { @@ -221,16 +221,16 @@ wxGLCanvas::OnSize(event); // set GL viewport - // (not called by wxGLCanvas::OnSize on all platforms...) + // (not called by wxGLCanvas::OnSize on all platforms...) if (SetCurrent()) { - DoResize(); - // It is only sensible to update the other thread when it's running - // Don't acquire the mutex when s_bWorkerNeedsInit already to avoid deadlock - if (/*m_bRunning &&*/ !s_bWorkerNeedsInit) { - wxMutexLocker lock(s_mutexOpenGL); - s_bWorkerNeedsInit = true; - } - } + DoResize(); + // It is only sensible to update the other thread when it's running + // Don't acquire the mutex when s_bWorkerNeedsInit already to avoid deadlock + if (/*m_bRunning &&*/ !s_bWorkerNeedsInit) { + wxMutexLocker lock(s_mutexOpenGL); + s_bWorkerNeedsInit = true; + } + } } void GraphicsOutputDevicewxGLCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { @@ -240,224 +240,224 @@ bool bRet=true; #ifndef __WXMOTIF__ - bRet = (GetContext()!=NULL); - if (bRet) + bRet = (GetContext()!=NULL); + if (bRet) #endif - { - wxGLCanvas::SetCurrent(); - } - return bRet; + { + wxGLCanvas::SetCurrent(); + } + return bRet; } void GraphicsOutputDevicewxGLCanvas::DoResize() { int w, h; - GetClientSize(&w, &h); - glViewport(0, 0, (GLint)w, (GLint)h); + GetClientSize(&w, &h); + glViewport(0, 0, (GLint)w, (GLint)h); } void GraphicsOutputDevicewxGLCanvas::InitGL() { /* No SetCurrent() here, because this can be called from different GL contexts. - * Convenient for multi-threaded operation. */ + * Convenient for multi-threaded operation. */ //aimERROR(_T("InitGL Called")); #if defined(WITH_GL_VERTEX_ARRAYS) && !defined(_MACOSX) - if (!m_init) { - /* This needs to be done here, because OpenGL commands may need SetCurrent() - * and an already shown window. */ - char *extensions = (char *)glGetString(GL_EXTENSIONS); - if (!extensions) { - AIM_INFO(_T("Could not query OpenGL extensions, vertex arrays disabled")); - } else if (strstr(extensions, "GL_EXT_compiled_vertex_array")) { - m_glLockArraysEXT = (LOCAL_PFNGLLOCKARRAYSEXTPROC)GL_GET_PROC_ADDRESS("glLockArraysEXT"); - m_glUnlockArraysEXT = (LOCAL_PFNGLUNLOCKARRAYSEXTPROC)GL_GET_PROC_ADDRESS("glUnlockArraysEXT"); - if (!m_glLockArraysEXT || !m_glUnlockArraysEXT) - AIM_ERROR(_T("OpenGL error on GL_EXT_compiled_vertex_array")); - else - m_bVertexArrayLock = true; - } - } + if (!m_init) { + /* This needs to be done here, because OpenGL commands may need SetCurrent() + * and an already shown window. */ + char *extensions = (char *)glGetString(GL_EXTENSIONS); + if (!extensions) { + AIM_INFO(_T("Could not query OpenGL extensions, vertex arrays disabled")); + } else if (strstr(extensions, "GL_EXT_compiled_vertex_array")) { + m_glLockArraysEXT = (LOCAL_PFNGLLOCKARRAYSEXTPROC)GL_GET_PROC_ADDRESS("glLockArraysEXT"); + m_glUnlockArraysEXT = (LOCAL_PFNGLUNLOCKARRAYSEXTPROC)GL_GET_PROC_ADDRESS("glUnlockArraysEXT"); + if(!m_glLockArraysEXT || !m_glUnlockArraysEXT) + AIM_ERROR(_T("OpenGL error on GL_EXT_compiled_vertex_array")); + else + m_bVertexArrayLock = true; + } + } #endif - DoResize(); - glClearColor(0, 0, 0, 1); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity( ); + DoResize(); + glClearColor(0, 0, 0, 1); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity( ); - glEnable(GL_VERTEX_ARRAY); + glEnable(GL_VERTEX_ARRAY); - // Window limits in OpenGL co-ordiantes - //! \todo Make this configurable, or change and document fixed values - glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0); - glTranslatef(0.0, 0.0, 0.0); + // Window limits in OpenGL co-ordiantes + //! \todo Make this configurable, or change and document fixed values + glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0); + glTranslatef(0.0, 0.0, 0.0); - if (m_bAntialiasing) { - glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_ONE, GL_ONE); - glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); - } else { - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); - } - glLineWidth(1.0); + if (m_bAntialiasing) { + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_ONE, GL_ONE); + glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); + } else { + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); + } + glLineWidth(1.0); - // Get a free display list only the first time - if (!m_init) { + // Get a free display list only the first time + if (!m_init) { #if !defined(_MACOSX) - // Windows and Linux need a separate worker context - aimASSERT(wxIsMainThread()); + // Windows and Linux need a separate worker context + aimASSERT(wxIsMainThread()); #if wxCHECK_VERSION(2,8,0) - m_pWorkerContext = new wxGLContext(this, m_glContext); + m_pWorkerContext = new wxGLContext(this, m_glContext); #else - m_pWorkerContext = new wxGLContext(true, + m_pWorkerContext = new wxGLContext(true, this, wxNullPalette, m_glContext); #endif - aimASSERT(m_pWorkerContext); - s_bWorkerNeedsInit = true; + aimASSERT(m_pWorkerContext); + s_bWorkerNeedsInit = true; #endif - m_gllist = glGenLists(1); - aimASSERT(m_gllist); - // Empty window at start - glNewList(m_gllist, GL_COMPILE_AND_EXECUTE); - glEndList(); - m_init = true; - } + m_gllist = glGenLists(1); + aimASSERT(m_gllist); + // Empty window at start + glNewList(m_gllist, GL_COMPILE_AND_EXECUTE); + glEndList(); + m_init = true; + } } // Call before any other render* functions void GraphicsOutputDevicewxGLCanvas::gGrab() { - AimwxGuiLocker __lock__; + AimwxGuiLocker __lock__; #if !defined(_MACOSX) - // Detect if we're the main thread or not. - if (!wxIsMainThread()) { - // We're called by a worker thread, make sure there's a right context - AIM_ASSERT(m_pWorkerContext); + // Detect if we're the main thread or not. + if (!wxIsMainThread()) { + // We're called by a worker thread, make sure there's a right context + AIM_ASSERT(m_pWorkerContext); #if wxCHECK_VERSION(2,8,0) - m_pWorkerContext->SetCurrent(*this); + m_pWorkerContext->SetCurrent(*this); #else - m_pWorkerContext->SetCurrent(); + m_pWorkerContext->SetCurrent(); #endif - // Update OpenGL settings if needed - wxMutexLocker lock(s_mutexOpenGL); - if (s_bWorkerNeedsInit) { - InitGL(); - s_bWorkerNeedsInit = false; - } - } else + // Update OpenGL settings if needed + wxMutexLocker lock(s_mutexOpenGL); + if (s_bWorkerNeedsInit) { + InitGL(); + s_bWorkerNeedsInit = false; + } + } else #endif - { - // Either called by main thread, or we need no special worker glContext - if (!SetCurrent()) { - return; - } - // Init OpenGL once, but after SetCurrent - if (!m_init) { - InitGL(); - } - } - glClear(GL_COLOR_BUFFER_BIT); + { + // Either called by main thread, or we need no special worker glContext + if (!SetCurrent()) { + return; + } + // Init OpenGL once, but after SetCurrent + if (!m_init) { + InitGL(); + } + } + glClear(GL_COLOR_BUFFER_BIT); - // Start and store in a display list for redrawing - glNewList(m_gllist, GL_COMPILE); + // Start and store in a display list for redrawing + glNewList(m_gllist, GL_COMPILE); } void GraphicsOutputDevicewxGLCanvas::gBeginLineStrip() { #ifdef WITH_GL_VERTEX_ARRAYS - aimASSERT(m_iVertexType == 0xffff); // Previous gBegin*() must be gEnd()ed - // New lines vertex array - m_iVertexCount = 0; - m_iVertexType = GL_LINE_STRIP; + aimASSERT(m_iVertexType == 0xffff); // Previous gBegin*() must be gEnd()ed + // New lines vertex array + m_iVertexCount = 0; + m_iVertexType = GL_LINE_STRIP; #else - AimwxGuiLocker __lock__; - glBegin(GL_LINE_STRIP); + AimwxGuiLocker __lock__; + glBegin(GL_LINE_STRIP); #endif } void GraphicsOutputDevicewxGLCanvas::gBeginQuadStrip() { #ifdef WITH_GL_VERTEX_ARRAYS - aimASSERT(m_iVertexType == 0xffff); // Previous gBegin*() must be gEnd()ed - // New quads vertex array - m_iVertexCount = 0; - m_iVertexType = GL_QUAD_STRIP; + aimASSERT(m_iVertexType == 0xffff); // Previous gBegin*() must be gEnd()ed + // New quads vertex array + m_iVertexCount = 0; + m_iVertexType = GL_QUAD_STRIP; #else - AimwxGuiLocker __lock__; - glBegin(GL_QUAD_STRIP); + AimwxGuiLocker __lock__; + glBegin(GL_QUAD_STRIP); #endif } void GraphicsOutputDevicewxGLCanvas::gVertex3f(float x, float y, float z) { #ifdef WITH_GL_VERTEX_ARRAYS - aimASSERT(m_iVertexType != 0xffff); // Must be inside gBegin*() - if (m_iVertexCount>=m_iVerticesMax) { - static bool errShown=false; - if (!errShown) { - aimERROR(_T("Error: max vertex count reached: %d"), m_iVertexCount); - errShown=true; - } - return; - } - if (m_bStaticColor) { - m_pVertices[m_iVertexCount*3+0] = x; - m_pVertices[m_iVertexCount*3+1] = y; - m_pVertices[m_iVertexCount*3+2] = z; - } else { - m_pVertices[m_iVertexCount*6+0] = m_fCurColorR; - m_pVertices[m_iVertexCount*6+1] = m_fCurColorG; - m_pVertices[m_iVertexCount*6+2] = m_fCurColorB; - m_pVertices[m_iVertexCount*6+3] = x; - m_pVertices[m_iVertexCount*6+4] = y; - m_pVertices[m_iVertexCount*6+5] = z; - } - m_iVertexCount++; + aimASSERT(m_iVertexType != 0xffff); // Must be inside gBegin*() + if (m_iVertexCount>=m_iVerticesMax) { + static bool errShown=false; + if (!errShown) { + aimERROR(_T("Error: max vertex count reached: %d"), m_iVertexCount); + errShown=true; + } + return; + } + if (m_bStaticColor) { + m_pVertices[m_iVertexCount*3+0] = x; + m_pVertices[m_iVertexCount*3+1] = y; + m_pVertices[m_iVertexCount*3+2] = z; + } else { + m_pVertices[m_iVertexCount*6+0] = m_fCurColorR; + m_pVertices[m_iVertexCount*6+1] = m_fCurColorG; + m_pVertices[m_iVertexCount*6+2] = m_fCurColorB; + m_pVertices[m_iVertexCount*6+3] = x; + m_pVertices[m_iVertexCount*6+4] = y; + m_pVertices[m_iVertexCount*6+5] = z; + } + m_iVertexCount++; #else - AimwxGuiLocker __lock__; - glVertex3f(x,y,z); + AimwxGuiLocker __lock__; + glVertex3f(x,y,z); #endif } void GraphicsOutputDevicewxGLCanvas::gColor3f(float r, float g, float b) { #ifdef WITH_GL_VERTEX_ARRAYS - if (m_iVertexType==0xffff || m_bStaticColor) { - // If not inside vertex array run, use the ordinary command - glColor3f(r, g, b); - } - if (!m_bStaticColor) { - // Set current color for vertex array usage - m_fCurColorR = r; - m_fCurColorG = g; - m_fCurColorB = b; - } + if (m_iVertexType==0xffff || m_bStaticColor) { + // If not inside vertex array run, use the ordinary command + glColor3f(r, g, b); + } + if (!m_bStaticColor) { + // Set current color for vertex array usage + m_fCurColorR = r; + m_fCurColorG = g; + m_fCurColorB = b; + } #else - AimwxGuiLocker __lock__; + AimwxGuiLocker __lock__; glColor3f(r, g, b); #endif } void GraphicsOutputDevicewxGLCanvas::gEnd() { #ifdef WITH_GL_VERTEX_ARRAYS - aimASSERT(m_iVertexType != 0xffff); // Must be inside gBegin*() - AimwxGuiLocker __lock__; + aimASSERT(m_iVertexType != 0xffff); // Must be inside gBegin*() + AimwxGuiLocker __lock__; - // Draw the vertex array - glEnableClientState(GL_VERTEX_ARRAY); + // Draw the vertex array + glEnableClientState(GL_VERTEX_ARRAY); - // Draw vertices - if (m_bStaticColor) - glVertexPointer(3, GL_FLOAT, 0, m_pVertices); - else - glInterleavedArrays(GL_C3F_V3F, 0, m_pVertices); - if (m_bVertexArrayLock) m_glLockArraysEXT(0, m_iVertexCount); - glDrawArrays(m_iVertexType, 0, m_iVertexCount); - if (m_bVertexArrayLock) m_glUnlockArraysEXT(); + // Draw vertices + if (m_bStaticColor) + glVertexPointer(3, GL_FLOAT, 0, m_pVertices); + else + glInterleavedArrays(GL_C3F_V3F, 0, m_pVertices); + if (m_bVertexArrayLock) m_glLockArraysEXT(0, m_iVertexCount); + glDrawArrays(m_iVertexType, 0, m_iVertexCount); + if (m_bVertexArrayLock) m_glUnlockArraysEXT(); - glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); - // Remember we're outside a gBegin()..gEnd() loop - m_iVertexType = 0xffff; + // Remember we're outside a gBegin()..gEnd() loop + m_iVertexType = 0xffff; #else - AimwxGuiLocker __lock__; - glEnd(); + AimwxGuiLocker __lock__; + glEnd(); #endif } @@ -467,40 +467,40 @@ const char *sStr, bool bRotated) { #ifdef WITH_GL_VERTEX_ARRAYS - aimASSERT(m_iVertexType == 0xffff); // Must be outside gBegin*() + aimASSERT(m_iVertexType == 0xffff); // Must be outside gBegin*() #endif - if (!m_pFont) - return; + if (!m_pFont) + return; - //! \todo make rotation work - if (bRotated) - return; + //! \todo make rotation work + if (bRotated) + return; - { - AimwxGuiLocker __lock__; - /* - if (bRotated) { - glPushMatrix(); - glTranslatef(x,y,z); - glRotatef(90.0f, 0, 0, 1.0f); - glRasterPos3f(0,0,0); - m_pFont->Render(sStr); - glPopMatrix(); - } else { - */ - glRasterPos3f(x, y, z); - m_pFont->Render(sStr); - } + { + AimwxGuiLocker __lock__; + /* + if (bRotated) { + glPushMatrix(); + glTranslatef(x,y,z); + glRotatef(90.0f, 0, 0, 1.0f); + glRasterPos3f(0,0,0); + m_pFont->Render(sStr); + glPopMatrix(); + } else { + */ + glRasterPos3f(x, y, z); + m_pFont->Render(sStr); + } } void GraphicsOutputDevicewxGLCanvas::gRelease() { #ifdef WITH_GL_VERTEX_ARRAYS - aimASSERT(m_iVertexType == 0xffff); // Must be gEnd()ed + aimASSERT(m_iVertexType == 0xffff); // Must be gEnd()ed #endif - AimwxGuiLocker __lock__; - glEndList(); - glCallList(m_gllist); - //glFlush(); - SwapBuffers(); // Doesn't matter in what context + AimwxGuiLocker __lock__; + glEndList(); + glCallList(m_gllist); + //glFlush(); + SwapBuffers(); // Doesn't matter in what context }
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicewxGLCanvas.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicewxGLCanvas.h Fri Oct 15 05:40:53 2010 +0000 @@ -32,31 +32,31 @@ // Make sure GLCANVAS is compiled into wxWidgets #if !wxUSE_GLCANVAS -# error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" +# error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" #endif #if defined (_MACOSX) -# include <OpenGL/gl.h> -# include <OpenGl/glext.h> +# include <OpenGL/gl.h> +# include <OpenGl/glext.h> #elif defined (_WINDOWS) -# include <GL/gl.h> -# define GL_GET_PROC_ADDRESS wglGetProcAddress +# include <GL/gl.h> +# define GL_GET_PROC_ADDRESS wglGetProcAddress #else -# include <GL/gl.h> -# define GL_GET_PROC_ADDRESS(x) glXGetProcAddress((const GLubyte*)x) +# include <GL/gl.h> +# define GL_GET_PROC_ADDRESS(x) glXGetProcAddress((const GLubyte*)x) #endif /* Define them just ourselves, easiest way to get it working cross-platform * and -Mesa/OpenGL-version. */ #ifndef APIENTRY -# define APIENTRY +# define APIENTRY #endif typedef void (APIENTRY * LOCAL_PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); typedef void (APIENTRY * LOCAL_PFNGLUNLOCKARRAYSEXTPROC) (void); #ifdef FTGL_SUBDIR -# include <FTGL/FTGLBitmapFont.h> +# include <FTGL/FTGLBitmapFont.h> #else -# include <FTGLBitmapFont.h> +# include <FTGLBitmapFont.h> #endif #include "Output/GraphicsOutputDevice.h" @@ -76,7 +76,7 @@ public GraphicsOutputDevice { public: GraphicsOutputDevicewxGLCanvas(Parameters *pParam, - wxWindow *parent, + wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, @@ -88,147 +88,147 @@ void OnSize(wxSizeEvent& event); void OnEraseBackground(wxEraseEvent& event); - /*! \param iVerticesMax Maximum number of vertices to be draw inside a gBegin()..gEnd() - * - * When iVerticesMax is zero, this variable will not be updated. Note that is _has_ - * to be set at least once before using this class. - */ - bool Initialize(unsigned int iVerticesMax); - bool Initialize(); + /*! \param iVerticesMax Maximum number of vertices to be draw inside a gBegin()..gEnd() + * + * When iVerticesMax is zero, this variable will not be updated. Note that is _has_ + * to be set at least once before using this class. + */ + bool Initialize(unsigned int iVerticesMax); + bool Initialize(); - void Start(); + void Start(); void gGrab(); void gBeginLineStrip(); void gBeginQuadStrip(); - using GraphicsOutputDevice::gVertex3f; // Because we overload it - void gVertex3f(float x, float y, float z); - void gColor3f(float r, float g, float b); + using GraphicsOutputDevice::gVertex3f; // Because we overload it + void gVertex3f(float x, float y, float z); + void gColor3f(float r, float g, float b); void gEnd(); - void gText3f(float x, float y, float z, const char *sStr, bool bRotated = false); - void gRelease(); + void gText3f(float x, float y, float z, const char *sStr, bool bRotated = false); + void gRelease(); protected: - /*! \brief Smarter SetCurrent() replacement - * \return true on success, false on error - * - * This function tries GetContext() first. If that fails, it returns false. - */ - bool SetCurrent(); - void Render(); + /*! \brief Smarter SetCurrent() replacement + * \return true on success, false on error + * + * This function tries GetContext() first. If that fails, it returns false. + */ + bool SetCurrent(); + void Render(); - /*! \brief Initialize the OpenGL environment. - * - * This must be called after the canvas is realized but before any other - * OpenGL operation is done. Make sure to run SetCurrent() beforehand. - * Usually only needed when m_init is false. - */ + /*! \brief Initialize the OpenGL environment. + * + * This must be called after the canvas is realized but before any other + * OpenGL operation is done. Make sure to run SetCurrent() beforehand. + * Usually only needed when m_init is false. + */ void InitGL(); - /*! \brief Handle a resize (notify OpenGL of the new area) - * - * This is a separate function, because in multi-threading environments - * multiple contexts have to call it. - */ - void DoResize(); + /*! \brief Handle a resize (notify OpenGL of the new area) + * + * This is a separate function, because in multi-threading environments + * multiple contexts have to call it. + */ + void DoResize(); - /*! \brief Only need to initialize OpenGL once. - * - * This is false at start and true when OpenGL has been initialized. - * No mutex needed, since it's set once at InitGL() and only read afterwards. - */ + /*! \brief Only need to initialize OpenGL once. + * + * This is false at start and true when OpenGL has been initialized. + * No mutex needed, since it's set once at InitGL() and only read afterwards. + */ bool m_init; - /*! \brief Vertex list for last drawing so it can be updated on repaint. - * - * No mutex needed, since it's set once at InitGL() and only read afterwards. - */ + /*! \brief Vertex list for last drawing so it can be updated on repaint. + * + * No mutex needed, since it's set once at InitGL() and only read afterwards. + */ GLuint m_gllist; - //! \brief OpenGL context for worker thread, use when wxIsMainThread() returns false. - wxGLContext *m_pWorkerContext; + //! \brief OpenGL context for worker thread, use when wxIsMainThread() returns false. + wxGLContext *m_pWorkerContext; - //! \brief Mutex for inter-thread communication - wxMutex s_mutexOpenGL; + //! \brief Mutex for inter-thread communication + wxMutex s_mutexOpenGL; - //! \brief When true, OpenGL needs to be reinitialized (in the worker thread) - bool s_bWorkerNeedsInit; + //! \brief When true, OpenGL needs to be reinitialized (in the worker thread) + bool s_bWorkerNeedsInit; - //! \brief OpenGL attributes used for initialization. + //! \brief OpenGL attributes used for initialization. static int GLAttrlist[]; - //! \brief Whether to use anti-aliasing or not - bool m_bAntialiasing; + //! \brief Whether to use anti-aliasing or not + bool m_bAntialiasing; - //! \brief FTGL Font class - FTFont *m_pFont; - //! \brief Current font filename - const char *m_sFontFile; - //! \brief Current font size - int m_iFontsize; + //! \brief FTGL Font class + FTFont *m_pFont; + //! \brief Current font filename + const char *m_sFontFile; + //! \brief Current font size + int m_iFontsize; #if defined(WITH_GL_VERTEX_ARRAYS) || defined(DOXYGEN) - //! \brief OpenGL vertex type of the current m_pVertices, or 0xffff is outside gBegin()..gEnd() - int m_iVertexType; - //! \brief Maximum number of vertices begin gBegin()..gEnd() - unsigned int m_iVerticesMax; - //! \brief Vertex array to draw at gEnd(), this becomes m_pVertices[m_iVerticesMax*3] - GLfloat *m_pVertices; - //! \brief The current number of vertices inside m_pVertices - unsigned int m_iVertexCount; + //! \brief OpenGL vertex type of the current m_pVertices, or 0xffff is outside gBegin()..gEnd() + int m_iVertexType; + //! \brief Maximum number of vertices begin gBegin()..gEnd() + unsigned int m_iVerticesMax; + //! \brief Vertex array to draw at gEnd(), this becomes m_pVertices[m_iVerticesMax*3] + GLfloat *m_pVertices; + //! \brief The current number of vertices inside m_pVertices + unsigned int m_iVertexCount; - /*! \brief Whether to use coloring in vertex lists - * - * This variable must not change after Initialize(), or the program may crash. - * When this variable is true, color information is stored in vertex lists. If - * it is false, only vertex data is stored. - * - * This variable exists for performance reasons, but is currently only set in - * the constructor of this object. - */ - bool m_bStaticColor; - //! \brief Current color for vertex list drawing - float m_fCurColorR, m_fCurColorG, m_fCurColorB; + /*! \brief Whether to use coloring in vertex lists + * + * This variable must not change after Initialize(), or the program may crash. + * When this variable is true, color information is stored in vertex lists. If + * it is false, only vertex data is stored. + * + * This variable exists for performance reasons, but is currently only set in + * the constructor of this object. + */ + bool m_bStaticColor; + //! \brief Current color for vertex list drawing + float m_fCurColorR, m_fCurColorG, m_fCurColorB; - //! \brief Whether to use vertex array locking or not - bool m_bVertexArrayLock; - //! \brief Pointer to vertex array locking function; can be NULL. - LOCAL_PFNGLLOCKARRAYSEXTPROC m_glLockArraysEXT; - //! \brief Pointer to vertex array unlocking function; can be NULL. - LOCAL_PFNGLUNLOCKARRAYSEXTPROC m_glUnlockArraysEXT; + //! \brief Whether to use vertex array locking or not + bool m_bVertexArrayLock; + //! \brief Pointer to vertex array locking function; can be NULL. + LOCAL_PFNGLLOCKARRAYSEXTPROC m_glLockArraysEXT; + //! \brief Pointer to vertex array unlocking function; can be NULL. + LOCAL_PFNGLUNLOCKARRAYSEXTPROC m_glUnlockArraysEXT; #endif - /*! \brief wxMutexGuiEnter() / wxMutexGuiLeave() wrapper - * - * This is a wxMutexLocker-alike for the main gui mutex. Any method that - * is public, can be called from within another thread and does OpenGL or - * other gui calls must use this. Example: - * \code - * void DoFoo() { - * AimwxGuiLocker __lock__; - * glAmazingMethod(); - * } - * \endcode - * - * It is mostly on X-Windows (Xorg/XFree86) that the gui mutex appears to - * be needed. Otherwise the error "Xlib: unexpected async reply" can occur. - * - * On windows, the ui may occasionally lock up for a short while with these - * mutexes. Since they aren't really needed on that platform, it's left out - * alltogether. - */ - class AimwxGuiLocker { - public: - inline AimwxGuiLocker() { + /*! \brief wxMutexGuiEnter() / wxMutexGuiLeave() wrapper + * + * This is a wxMutexLocker-alike for the main gui mutex. Any method that + * is public, can be called from within another thread and does OpenGL or + * other gui calls must use this. Example: + * \code + * void DoFoo() { + * AimwxGuiLocker __lock__; + * glAmazingMethod(); + * } + * \endcode + * + * It is mostly on X-Windows (Xorg/XFree86) that the gui mutex appears to + * be needed. Otherwise the error "Xlib: unexpected async reply" can occur. + * + * On windows, the ui may occasionally lock up for a short while with these + * mutexes. Since they aren't really needed on that platform, it's left out + * alltogether. + */ + class AimwxGuiLocker { + public: + inline AimwxGuiLocker() { #ifndef _WINDOWS - if (!wxIsMainThread()) wxMutexGuiEnter(); + if (!wxIsMainThread()) wxMutexGuiEnter(); #endif - } - inline ~AimwxGuiLocker() { + } + inline ~AimwxGuiLocker() { #ifndef _WINDOWS - if (!wxIsMainThread()) wxMutexGuiLeave(); + if (!wxIsMainThread()) wxMutexGuiLeave(); #endif - } - }; + } + }; DECLARE_EVENT_TABLE() }; #endif /* __GRAPHICS_OUTPUT_DEVICE_GL_CANVAS_H__ */
--- a/src/Modules/Output/Graphics/GraphAxisSpec.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/GraphAxisSpec.cc Fri Oct 15 05:40:53 2010 +0000 @@ -21,39 +21,37 @@ #include "Modules/Output/Graphics/GraphAxisSpec.h" -namespace aimc { - GraphAxisSpec::GraphAxisSpec(float fMin, float fMax, Scale::ScaleType iScale) { - m_pScale = NULL; - m_sLabel = NULL; - SetDisplayRange(fMin, fMax); - SetDisplayScale(iScale); + m_pScale = NULL; + m_sLabel = NULL; + SetDisplayRange(fMin, fMax); + SetDisplayScale(iScale); } GraphAxisSpec::GraphAxisSpec() { - m_pScale = NULL; - m_sLabel = NULL; - m_fMin = 0; - m_fMax = 0; + m_pScale = NULL; + m_sLabel = NULL; + m_fMin = 0; + m_fMax = 0; } GraphAxisSpec::~GraphAxisSpec() { - DELETE_IF_NONNULL(m_pScale); + DELETE_IF_NONNULL(m_pScale); } void GraphAxisSpec::SetDisplayRange(float fMin, float fMax) { - AIM_ASSERT(fMin <= fMax); - m_fMin = fMin; - m_fMax = fMax; - if (m_pScale) - m_pScale->FromLinearScaledExtrema(m_fMin, m_fMax); + AIM_ASSERT(fMin <= fMax); + m_fMin = fMin; + m_fMax = fMax; + if (m_pScale) + m_pScale->FromLinearScaledExtrema(m_fMin, m_fMax); } void GraphAxisSpec::SetDisplayScale(Scale::ScaleType iScale) { - DELETE_IF_NONNULL(m_pScale); - m_pScale = Scale::Create(iScale); - AIM_ASSERT(m_pScale); - m_pScale->FromLinearScaledExtrema(m_fMin, m_fMax); + DELETE_IF_NONNULL(m_pScale); + m_pScale = Scale::Create(iScale); + aimASSERT(m_pScale); + m_pScale->FromLinearScaledExtrema(m_fMin, m_fMax); } bool GraphAxisSpec::Initialize(Parameters *parameters, @@ -61,64 +59,68 @@ float fMin, float fMax, Scale::ScaleType iScale) { - AIM_ASSERT(parameters); - AIM_ASSERT(sPrefix && sPrefix[0]!='\0'); - char sParamName[Parameters::MaxParamNameLength]; + AIM_ASSERT(pParam); + AIM_ASSERT(sPrefix && sPrefix[0]!='\0'); + char sParamName[Parameters::MaxParamNameLength]; - //! The following parameters are recognized for each axis: - //! - \c "<prefix>.min", the minimum value; a float or \c 'auto' - snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]), + //! The following parameters are recognized for each axis: + //! - \c "<prefix>.min", the minimum value; a float or \c 'auto' + snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]), "%s.min", sPrefix); - if (strcmp(parameters->DefaultString(sParamName, "auto"), "auto") == 0) - m_fMin = fMin; - else - m_fMin = parameters->GetFloat(sParamName); - + if (pParam->IsSet(sParamName)) { + if (strcmp(parameters->GetString(sParamName), "auto") == 0) + m_fMin = fMin; + else + m_fMin = parameters->GetFloat(sParamName); + } - //! - \c "<prefix>.max", the maximum value; a float or \c 'auto' - snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]), + //! - \c "<prefix>.max", the maximum value; a float or \c 'auto' + snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]), "%s.max", sPrefix); - if (strcmp(parameters->DefaultString(sParamName, "auto"), "auto")==0) - m_fMax = fMax; - else - m_fMax = parameters->GetFloat(sParamName); + if (pParam->IsSet(sParamName)) { + if (strcmp(parameters->GetString(sParamName), "auto")==0) + m_fMax = fMax; + else + m_fMax = parameters->GetFloat(sParamName); + } - // Make sure ranges are updated properly - SetDisplayRange(m_fMin, m_fMax); + // Make sure ranges are updated properly + SetDisplayRange(m_fMin, m_fMax); - //! - \c "<prefix>.scale", the scale; one of \c 'auto', + //! - \c "<prefix>.scale", the scale; one of \c 'auto', //! \c 'linear', \c 'erb' or \c 'log' - snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]), + snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]), "%s.scale", sPrefix); - // Scale change, we updated min/max values already so no need to - Scale::ScaleType iThisScale; - const char *sVal = parameters->DefaultString(sParamName, "auto"); - if (strcmp(sVal, "auto")==0) - iThisScale = iScale; - else if (strcmp(sVal, "linear")==0) - iThisScale = Scale::SCALE_LINEAR; - else if (strcmp(sVal, "erb")==0) - iThisScale = Scale::SCALE_ERB; - else if (strcmp(sVal, "log")==0) - iThisScale = Scale::SCALE_LOG; - else { - LOG_ERROR(_T("Unrecognized scale type in parameter '%s': '%s'"), - sParamName, - sVal); - return false; - } - SetDisplayScale(iThisScale); + if (pParam->IsSet(sParamName)) { + // Scale change, we updated min/max values already so no need to + Scale::ScaleType iThisScale; + const char *sVal = parameters->GetString(sParamName); + if (strcmp(sVal, "auto")==0) + iThisScale = iScale; + else if (strcmp(sVal, "linear")==0) + iThisScale = Scale::SCALE_LINEAR; + else if (strcmp(sVal, "erb")==0) + iThisScale = Scale::SCALE_ERB; + else if (strcmp(sVal, "log")==0) + iThisScale = Scale::SCALE_LOG; + else { + AIM_ERROR(_T("Unrecognized scale type in parameter '%s': '%s'"), + sParamName, + sVal); + return false; + } + SetDisplayScale(iThisScale); + } - - //! - \c "<prefix>.label", the label; a string - snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]), + //! - \c "<prefix>.label", the label; a string + snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]), "%s.label", sPrefix); - m_sLabel = parameters->DefaultString(sParamName, ""); // Assumes strings remains valid + if (parameters->IsSet(sParamName)) + m_sLabel = parameters->GetString(sParamName); // Assumes strings remains valid - return true; + return true; } -} // namespace aimc
--- a/src/Modules/Output/Graphics/GraphAxisSpec.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/GraphAxisSpec.h Fri Oct 15 05:40:53 2010 +0000 @@ -21,72 +21,68 @@ #include "Support/Parameters.h" #include "Modules/Output/Graphics/Scale/Scale.h" -namespace aimc { - /*! \class GraphAxisSpec "Output/GraphAxisSpec.h" * \brief Axis specification for a GraphicsView */ class GraphAxisSpec { public: - /*! \brief Create a new GraphAxisSpec - * \param fMin Minimum value on the axis to show - * \param fMax Maximum value on the axis to show - * \param iScale Scale to use - * - * Please see SetScale() and SetRange() for more details. - */ - GraphAxisSpec(float fMin, float fMax, Scale::ScaleType iScale); - //! \brief Create a new GraphAxisSpec from defaults - GraphAxisSpec(); + /*! \brief Create a new GraphAxisSpec + * \param fMin Minimum value on the axis to show + * \param fMax Maximum value on the axis to show + * \param iScale Scale to use + * + * Please see SetScale() and SetRange() for more details. + */ + GraphAxisSpec(float fMin, float fMax, Scale::ScaleType iScale); + //! \brief Create a new GraphAxisSpec from defaults + GraphAxisSpec(); - ~GraphAxisSpec(); + ~GraphAxisSpec(); - /*! \brief Set the scale to use - * \param iScale Scale to use - */ - void SetDisplayScale(Scale::ScaleType iScale); - /*! \brief Set the minumum and maximum values to show on the axis - * \param fMin Minimum value on the axis to show - * \param fMax Maximum value on the axis to show - * - * Either fMin _must_ be smaller than fMax, or fMin==fMax but then - * this function must be called later to fulfil the former condition - * before it is used to scale data. - */ - void SetDisplayRange(float fMin, float fMax); - /*! \brief Set the label of this axis - * \param sLabel New label, or NULL to remove label - */ - void SetLabel(const char *sLabel); + /*! \brief Set the scale to use + * \param iScale Scale to use + */ + void SetDisplayScale(Scale::ScaleType iScale); + /*! \brief Set the minumum and maximum values to show on the axis + * \param fMin Minimum value on the axis to show + * \param fMax Maximum value on the axis to show + * + * Either fMin _must_ be smaller than fMax, or fMin==fMax but then + * this function must be called later to fulfil the former condition + * before it is used to scale data. + */ + void SetDisplayRange(float fMin, float fMax); + /*! \brief Set the label of this axis + * \param sLabel New label, or NULL to remove label + */ + void SetLabel(const char *sLabel); - /*! \brief Read axis specification from parameter store - * \param pParam Parameter store to read from - * \param sPrefix Prefix to use, e.g. "view.x" - * \param fMin Default minumum value for 'auto' - * \param fMax Default maximum value for 'auto' - * \param iScale Default scale for 'auto' - * \return true if no error occured in reading - */ - bool Initialize(Parameters *pParam, + /*! \brief Read axis specification from parameter store + * \param pParam Parameter store to read from + * \param sPrefix Prefix to use, e.g. "view.x" + * \param fMin Default minumum value for 'auto' + * \param fMax Default maximum value for 'auto' + * \param iScale Default scale for 'auto' + * \return true if no error occured in reading + */ + bool Initialize(Parameters *pParam, const char *sPrefix, float fMin, float fMax, Scale::ScaleType iScale); protected: - //! \brief Minimum value on the axis to display - float m_fMin; - //! \brief Maximum value on the axis to display - float m_fMax; - //! \brief Scale to use - Scale *m_pScale; - //! \brief Axis label, NULL for no label - const char *m_sLabel; + //! \brief Minimum value on the axis to display + float m_fMin; + //! \brief Maximum value on the axis to display + float m_fMax; + //! \brief Scale to use + Scale *m_pScale; + //! \brief Axis label, NULL for no label + const char *m_sLabel; - friend class GraphicsView; - friend class GraphicsViewTime; + friend class GraphicsView; + friend class GraphicsViewTime; }; -} // namespace aimc - #endif /* __GRAPH_AXIS_SPEC_H__ */
--- a/src/Modules/Output/Graphics/GraphicsView.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/GraphicsView.cc Fri Oct 15 05:40:53 2010 +0000 @@ -15,180 +15,154 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include <algorithm> - #include "Support/Common.h" -#include "Modules/Output/Graphics/GraphicsView.h" -#include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h" -#include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h" - -namespace aimc { +#include "Output/GraphicsView.h" +#include "Output/GraphicsOutputDevice.h" GraphicsView::GraphicsView(Parameters *parameters) : Module(parameters) { - module_description_ = "Graphics output."; + module_description_ = ""; module_identifier_ = "graphics"; module_type_ = "output"; module_version_ = "$Id: $"; + + m_pDev = NULL; + m_bPlotLabels = false; + m_pAxisX = new GraphAxisSpec(); + AIM_ASSERT(m_pAxisX); + m_pAxisY = new GraphAxisSpec(); + AIM_ASSERT(m_pAxisY); + m_pAxisFreq = new GraphAxisSpec(); + AIM_ASSERT(m_pAxisFreq); - if (parameters_->DefaultBool("output.images", false)) { - m_pDev = new GraphicsOutputDeviceCairo(parameters_); - } else { - m_pDev = new GraphicsOutputDeviceMovie(parameters_); - } - m_bPlotLabels = false; - m_pAxisX = new GraphAxisSpec(); - AIM_ASSERT(m_pAxisX); - m_pAxisY = new GraphAxisSpec(); - AIM_ASSERT(m_pAxisY); - m_pAxisFreq = new GraphAxisSpec(); - AIM_ASSERT(m_pAxisFreq); - initialized_ = true; + m_pAxisY->Initialize(m_pParam, + _S("graph.y"), + -1, + 1, + Scale::SCALE_LINEAR); + m_fMarginLeft = m_pParam->GetFloat(_S("graph.margin.left")); + m_fMarginRight = m_pParam->GetFloat(_S("graph.margin.right")); + m_fMarginTop = m_pParam->GetFloat(_S("graph.margin.top")); + m_fMarginBottom = m_pParam->GetFloat(_S("graph.margin.bottom")); + m_bPlotLabels = m_pParam->GetBool(_S("graph.plotlabels")); - if (!m_pAxisY->Initialize(parameters_, - _S("graph.y"), - -1, - 1, - Scale::SCALE_LINEAR)) { - LOG_ERROR("Axis initialization failed"); - initialized_ = false; - } - m_fMarginLeft = parameters_->DefaultFloat(_S("graph.margin.left"), 0.05); - m_fMarginRight = parameters_->DefaultFloat(_S("graph.margin.right"), 0.005); - m_fMarginTop = parameters_->DefaultFloat(_S("graph.margin.top"), 0.005); - m_fMarginBottom = parameters_->DefaultFloat(_S("graph.margin.bottom"), 0.05); - m_bPlotLabels = parameters_->DefaultBool(_S("graph.plotlabels"), true); + const char *sGraphType = m_pParam->GetString(_S("graph.type")); + if (strcmp(sGraphType, _S("line"))==0) + m_iGraphType = GraphTypeLine; + else if (strcmp(sGraphType, _S("colormap"))==0) + m_iGraphType = GraphTypeColormap; + else if (strcmp(sGraphType, _S("none"))==0) + m_iGraphType = GraphTypeNone; + else { + ret = false; + AIM_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType); + } - const char *sGraphType = parameters_->DefaultString(_S("graph.type"), "line"); - if (strcmp(sGraphType, _S("line"))==0) - m_iGraphType = GraphTypeLine; - else if (strcmp(sGraphType, _S("colormap"))==0) - m_iGraphType = GraphTypeColormap; - else if (strcmp(sGraphType, _S("none"))==0) - m_iGraphType = GraphTypeNone; - else { - LOG_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType); - initialized_ = false; - } + if (strcmp(m_pParam->GetString(_S("graph.mindistance")),"auto") == 0) + // -1 means detect later, based on type and Fire() argument + m_fMinPlotDistance = -1; + else + m_fMinPlotDistance = m_pParam->GetFloat(_S("graph.mindistance")); - if (strcmp(parameters_->DefaultString(_S("graph.mindistance"), "auto"),"auto") == 0) - // -1 means detect later, based on type and Fire() argument - m_fMinPlotDistance = -1; - else - m_fMinPlotDistance = parameters_->GetFloat(_S("graph.mindistance")); } GraphicsView::~GraphicsView() { - DELETE_IF_NONNULL(m_pAxisX); - DELETE_IF_NONNULL(m_pAxisY); - DELETE_IF_NONNULL(m_pAxisFreq); + DELETE_IF_NONNULL(m_pAxisX); + DELETE_IF_NONNULL(m_pAxisY); + DELETE_IF_NONNULL(m_pAxisFreq); } -void GraphicsView::ResetInternal() { - if (m_pDev != NULL) { - m_pDev->Reset(global_parameters_); - } -} +bool bool GraphicsView::InitializeInternal(const SignalBank &bank) { - if (!m_pDev) { - LOG_ERROR("Output device not connected"); - return false; - } + if (!m_pDev) { + LOG_ERROR("Output device not connected"); + return false; + } float y_min = bank.centre_frequency(0); float y_max = bank.centre_frequency(bank.channel_count() - 1); - if (!m_pAxisFreq->Initialize(parameters_, + if (!m_pAxisFreq->Initialize(m_pParam, "graph.freq", - y_min, - y_max, - Scale::SCALE_ERB)) { - LOG_ERROR("Frequency axis init failed."); + y_min, + y_max, + Scale::SCALE_ERB)) { + LOG_ERROR(""); return false; } float x_min = 0.0; float x_max = 1000.0 * bank.buffer_length() / bank.sample_rate(); - if (!m_pAxisX->Initialize(parameters_, + if (!m_pAxisX->Initialize(m_pParam, "graph.x", - x_min, + x_min, x_max, - Scale::SCALE_LINEAR)) { - LOG_ERROR("Time axis init failed."); + Scale::SCALE_LINEAR)) { + LOG_ERROR(""); return false; } - /* Inform graphics output of maximum number of vertices between - * gBegin*() and gEnd(), for any type of plot. Colormap needs most. - */ - LOG_INFO("Initializing graphics output device."); - - if (!m_pDev->Initialize(global_parameters_)) { - LOG_ERROR("Graphics output device init failed."); + /* Inform graphics output of maximum number of vertices between + * gBegin*() and gEnd(), for any type of plot. Colormap needs most. + */ + if (!m_pDev->Initialize(MAX(10, bank.buffer_length() * 2 + 2))) { + LOG_ERROR(""); return false; } - m_pDev->Start(); - previous_start_time_ = 0; - return true; } void GraphicsView::Process(const SignalBank &bank) { - float height = 1.0 / bank.channel_count(); - float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop); - float xScaling = 1.0f; + float height = 1.0 / bank.channel_count(); + float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop); + float xScaling = 1.0f; - m_pDev->gGrab(); - PlotAxes(bank); - m_pDev->gColor3f(1.0f, 1.0f, 0.8f); - for (int i = 0; i < bank.channel_count(); i++) { - float yOffs = bank.centre_frequency(i); - yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f; - /* Don't plot below zero and stop when above 1, since yOffs is + m_pDev->gGrab(); + PlotAxes(bank); + m_pDev->gColor3f(1.0f, 1.0f, 0.8f); + for (int i = 0; i < bank.channel_count(); i++) { + float yOffs = bank.centre_frequency(i); + yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f; + /* Don't plot below zero and stop when above 1, since yOffs is * monotonically increasing. Because of rounding errors, we need * to check for yOffs < -1e-6 instead of yOffs < 0. */ - if (yOffs < -1e-6) + if (yOffs < -1e-6) continue; - if (yOffs > 1) + if (yOffs > 1) break; // Scale to single channel graphing. - yOffs = yOffs * (1.0f - height) + height / 2.0; - yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom; - PlotData(bank[i], bank.sample_rate(), yOffs, heightMinMargin, xScaling); - } - m_pDev->gRelease(); - - frame_rate_ = bank.sample_rate() - / (bank.start_time() - previous_start_time_); - previous_start_time_ = bank.start_time(); - global_parameters_->SetFloat("frame_rate", frame_rate_); + yOffs = yOffs * (1.0f - height) + height / 2.0; + yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom; + PlotData(bank[i], yOffs, heightMinMargin, xScaling); + } + m_pDev->gRelease(); } void GraphicsView::SetAxisScale(Scale::ScaleType iHori, Scale::ScaleType iVert, Scale::ScaleType iFreq) { - AIM_ASSERT(m_pAxisX); - AIM_ASSERT(m_pAxisY); - AIM_ASSERT(m_pAxisFreq); - m_pAxisX->SetDisplayScale(iHori); - m_pAxisY->SetDisplayScale(iVert); - m_pAxisFreq->SetDisplayScale(iFreq); + AIM_ASSERT(m_pAxisX); + AIM_ASSERT(m_pAxisY); + AIM_ASSERT(m_pAxisFreq); + m_pAxisX->SetDisplayScale(iHori); + m_pAxisY->SetDisplayScale(iVert); + m_pAxisFreq->SetDisplayScale(iFreq); } void GraphicsView::BeginDataStrip() { - m_iPrevValEqual=0; - m_bFirstPoint=true; - switch(m_iGraphType) { - case GraphTypeLine: - m_pDev->gBeginLineStrip(); - break; - case GraphTypeColormap: - m_pDev->gBeginQuadStrip(); - break; - case GraphTypeNone: - // Nothing: just for testing computation overhead of graphing - break; - } + m_iPrevValEqual=0; + m_bFirstPoint=true; + switch(m_iGraphType) { + case GraphTypeLine: + m_pDev->gBeginLineStrip(); + break; + case GraphTypeColormap: + m_pDev->gBeginQuadStrip(); + break; + case GraphTypeNone: + // Nothing: just for testing computation overhead of graphing + break; + } } void GraphicsView::PlotDataPoint(float x, @@ -196,66 +170,65 @@ float val, float height, bool isLast) { - AIM_ASSERT(m_pDev); + AIM_ASSERT(m_pDev); - /* Reduce the number of points plotted by eliminating duplicate values: - * - * oooo o--o - * o / o - * oooo ooo => o--o o--o - * oooo ooo o--o o-o - * - * with 'o' points that are plotted, and '-' by the graphics output - * device interpolated points. We could be smarter and include - * first-order interpolation, but we leave that as an exercise for - * the reader. Please send your patches :) - * - * So, we don't draw points that are too close to the previous value. - * But if the value changes (or it's the last point), we must draw the - * previous point too. - */ - if (!m_bFirstPoint + /* Reduce the number of points plotted by eliminating duplicate values: + * + * oooo o--o + * o / o + * oooo ooo => o--o o--o + * oooo ooo o--o o-o + * + * with 'o' points that are plotted, and '-' by the graphics output + * device interpolated points. We could be smarter and include + * first-order interpolation, but we leave that as an exercise for + * the reader. Please send your patches :) + * + * So, we don't draw points that are too close to the previous value. + * But if the value changes (or it's the last point), we must draw the + * previous point too. + */ + if (!m_bFirstPoint && !isLast - && abs(m_fPrevVal-val) < m_fMinPlotDistance) { - m_iPrevValEqual++; - // Don't set m_fPrevVal to avoid not catching slow changes - m_fPrevX = x; - m_fPrevY = y; - m_fPrevHeight = height; - return; - } else { - if (m_iPrevValEqual > 0) { - // Draw previous point - PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight); - } - m_iPrevValEqual = 0; - m_fPrevVal = val; - m_bFirstPoint = false; - } - PlotDataPointDirect(x, y, val, height); + && fabs(m_fPrevVal-val) < m_fMinPlotDistance) { + m_iPrevValEqual++; + // Don't set m_fPrevVal to avoid not catching slow changes + m_fPrevX = x; + m_fPrevY = y; + m_fPrevHeight = height; + return; + } else { + if (m_iPrevValEqual > 0) { + // Draw previous point + PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight); + } + m_iPrevValEqual = 0; + m_fPrevVal = val; + m_bFirstPoint = false; + } + PlotDataPointDirect(x, y, val, height); } void GraphicsView::PlotDataPointDirect(float x, float y, float val, float height) { - // Draw it in the right way - switch(m_iGraphType) { - case GraphTypeLine: - m_pDev->gVertex2f(x, y + val * height); - break; - case GraphTypeColormap: - //! \todo make it a real colormap instead of grayscale - m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5); - m_pDev->gVertex2f(x, y - height / 2); - m_pDev->gVertex2f(x, y + height / 2); - break; - case GraphTypeNone: - // Nothing: just for testing computation overhead of graphing - break; - default: - // Shouldn't happen - AIM_ASSERT(0); - } + // Draw it in the right way + switch(m_iGraphType) { + case GraphTypeLine: + m_pDev->gVertex2f(x, y + val * height); + break; + case GraphTypeColormap: + //! \todo make it a real colormap instead of grayscale + m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5); + m_pDev->gVertex2f(x, y - height / 2); + m_pDev->gVertex2f(x, y + height / 2); + break; + case GraphTypeNone: + // Nothing: just for testing computation overhead of graphing + break; + default: + // Shouldn't happen + AIM_ASSERT(0); + } } -} // namespace aimc
--- a/src/Modules/Output/Graphics/GraphicsView.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/GraphicsView.h Fri Oct 15 05:40:53 2010 +0000 @@ -27,15 +27,12 @@ #ifndef __GRAPHICS_VIEW_H__ #define __GRAPHICS_VIEW_H__ -#include "Support/Module.h" #include "Support/Parameters.h" #include "Support/SignalBank.h" #include "Modules/Output/Graphics/Scale/Scale.h" #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h" #include "Modules/Output/Graphics/GraphAxisSpec.h" -namespace aimc { - /*! * \class GraphicsView "Modules/Output/Graphics/GraphicsView.h" * \brief General graphics view module @@ -45,128 +42,141 @@ */ class GraphicsView : public Module { public: - /*! \brief Create a new view - * \param params A parameter store - * - */ - GraphicsView(Parameters *params); - virtual ~GraphicsView(); + /*! \brief Create a new view + * \param params A parameter store + * + */ + GraphicsView(Parameters *params); + virtual ~GraphicsView(); - /*! \brief Create a copy of this GraphicsView - * \param pDev Output device to bind to - * \return Newly created GraphicsView, to be freed by the caller. - * \deprecated Possibly, use Initialize() - */ - virtual GraphicsView *Clone(GraphicsOutputDevice *pDev) = 0; + /*! \brief Create a copy of this GraphicsView + * \param pDev Output device to bind to + * \return Newly created GraphicsView, to be freed by the caller. + * \deprecated Possibly, use Initialize() + */ + virtual GraphicsView *Clone(GraphicsOutputDevice *pDev) = 0; - /*! \brief (Re-)initialize this graphics view and it's device - * \param pParam Main parameter store to bind to - * \param pDev Graphics output device to draw to - * \return true on success, false on error - * - * It is possible to call Initialize() multiple times for binding - * to another graphics device or updating the parameters. This method - * does read all parameters than can be changed at run-time. - * - * One of the Initialize() functions _must_ be called before actually - * using it for plotting. - */ - virtual bool InitializeInternal(const SignalBank &bank); - virtual void ResetInternal(); - /*! \brief Set the axes' scale - * \param iXScale Scale type of the horizontal axis - * \param iYScale Scale type of the vertical axis for signal data - * \param iFreqScale Scale type of the vertical axis - * \deprecated Possibly, use AimParameters and Initialize - * \todo const arguments - */ - virtual void SetAxisScale(Scale::ScaleType iXScale, + /*! \brief (Re-)initialize this graphics view and it's device + * \param pParam Main parameter store to bind to + * \param pDev Graphics output device to draw to + * \return true on success, false on error + * + * It is possible to call Initialize() multiple times for binding + * to another graphics device or updating the parameters. This method + * does read all parameters than can be changed at run-time. + * + * One of the Initialize() functions _must_ be called before actually + * using it for plotting. + */ + virtual bool InitializeInternal(const SignalBank &bank); + + /*! \brief Set the axes' scale + * \param iXScale Scale type of the horizontal axis + * \param iYScale Scale type of the vertical axis for signal data + * \param iFreqScale Scale type of the vertical axis + * \deprecated Possibly, use AimParameters and Initialize + * \todo const arguments + */ + virtual void SetAxisScale(Scale::ScaleType iXScale, Scale::ScaleType iYScale, Scale::ScaleType iFreqScale); - virtual void Process(const SignalBank &bank); + virtual void Process(const SignalBank &bank); protected: - /*! \brief Plot the data of a signal - * \param pSig Signal to plot - * \param yOffset Vertical offset (between 0 and 1), where to plot 0 signal value. - * \param height Height of the signal to plot (between 0 and 1) - * \param xScale Scaling in x-direction. 1.0 makes it cover the whole length. 0.5 only the left half. - */ - virtual void PlotData(const vector<float> &signal, - float sample_rate, + /*! \brief Plot the data of a signal + * \param pSig Signal to plot + * \param yOffset Vertical offset (between 0 and 1), where to plot 0 signal value. + * \param height Height of the signal to plot (between 0 and 1) + * \param xScale Scaling in x-direction. 1.0 makes it cover the whole length. 0.5 only the left half. + */ + virtual void PlotData(const vector<float> &signal, float yOffset, float height, float xScale) = 0; - /*! \brief Plot the axes for a signal bank - * \param pSig Signal to plot the axes for - */ - virtual void PlotAxes(const SignalBank &bank) = 0; + /*! \brief Plot the axes for a signal bank + * \param pSig Signal to plot the axes for + */ + virtual void PlotAxes(const SignalBank &bank) = 0; - //! \brief Calls the correct m_pDev->gBegin*() for the current PlotType - virtual void BeginDataStrip(); - /*! \brief Plot a data point (with smart reduction) - * \param x X-coordinate of point (in OpenGL space) - * \param y y-coordinate of point (in OpenGL space) - * \param val Value to plot (from -0.5..0.5) - * \param height Height to use for plotting (in OpenGL space) - * \param isLast True if this is the last point of this batch to draw - * - * This method tries to reduce the number of actual graphics output - * operations using it's interpolation methods (e.g., a line). - */ - virtual void PlotDataPoint(float x, + //! \brief Calls the correct m_pDev->gBegin*() for the current PlotType + virtual void BeginDataStrip(); + /*! \brief Plot a data point (with smart reduction) + * \param x X-coordinate of point (in OpenGL space) + * \param y y-coordinate of point (in OpenGL space) + * \param val Value to plot (from -0.5..0.5) + * \param height Height to use for plotting (in OpenGL space) + * \param isLast True if this is the last point of this batch to draw + * + * This method tries to reduce the number of actual graphics output + * operations using it's interpolation methods (e.g., a line). + */ + virtual void PlotDataPoint(float x, float y, float val, float height, bool isLast); - /*! \brief Plot a data point (directly) - * \param x X-coordinate of point (in OpenGL space) - * \param y y-coordinate of point (in OpenGL space) - * \param val Value to plot (from -0.5..0.5) - * \param height Height to use for plotting (in OpenGL space) - */ - virtual void PlotDataPointDirect(float x, float y, float val, float height); + /*! \brief Plot a data point (directly) + * \param x X-coordinate of point (in OpenGL space) + * \param y y-coordinate of point (in OpenGL space) + * \param val Value to plot (from -0.5..0.5) + * \param height Height to use for plotting (in OpenGL space) + */ + virtual void PlotDataPointDirect(float x, float y, float val, float height); - //! \brief Where to plot to - GraphicsOutputDevice *m_pDev; + /*! \brief Plot a strobe point + * \param x X-coordinate of centre (in OpenGL space) + * \param y Y-coordinate of centre (in OpenGL space) + * \param size Size of the block drawn + * \param colour_r Red colour intensity + * \param colour_g Green colour intensity + * \param colour_b Blue colour intensity + */ + virtual void PlotStrobePoint(float x, + float y, + float size, + float color_r, + float color_g, + float color_b); - //! \brief Axes specifications - GraphAxisSpec *m_pAxisX, *m_pAxisY, *m_pAxisFreq; + //! \brief Where to plot to + GraphicsOutputDevice *m_pDev; - //! \brief Graph margins - float m_fMarginLeft, m_fMarginRight, m_fMarginTop, m_fMarginBottom; + //! \brief Main parameter store + Parameters *m_pParam; - //! \brief Whether labels are plotted or not - bool m_bPlotLabels; + //! \brief Axes specifications + GraphAxisSpec *m_pAxisX, *m_pAxisY, *m_pAxisFreq; - //! \brief Graphics device type - enum GraphType { - GraphTypeNone, + //! \brief Graph margins + float m_fMarginLeft, m_fMarginRight, m_fMarginTop, m_fMarginBottom; + + //! \brief Whether labels are plotted or not + bool m_bPlotLabels; + + //! \brief Graphics device type + enum GraphType { + GraphTypeNone, GraphTypeLine, GraphTypeColormap - }; - GraphType m_iGraphType; + }; + GraphType m_iGraphType; - /*! \brief Minimum distance between subsequent values for plotting a point - * - * This value is set in Initialize() from parameter graph.mindistance. - */ - float m_fMinPlotDistance; + /*! \brief Minimum distance between subsequent values for plotting a point + * + * This value is set in Initialize() from parameter graph.mindistance. + */ + float m_fMinPlotDistance; - //! \brief true if this next point is the first of the strip - bool m_bFirstPoint; - //! \brief Value of previously plotted point - float m_fPrevVal, m_fPrevX, m_fPrevY, m_fPrevHeight; - //! \brief Number of times m_fValPrev was within range m_fMinPlotDistance - int m_iPrevValEqual; - float frame_rate_; - int previous_start_time_; + //! \brief true if this next point is the first of the strip + bool m_bFirstPoint; + //! \brief Value of previously plotted point + float m_fPrevVal, m_fPrevX, m_fPrevY, m_fPrevHeight; + //! \brief Number of times m_fValPrev was within range m_fMinPlotDistance + int m_iPrevValEqual; +}; - bool initialized_; -}; -} // namespace aimc #endif /* __GRAPHICS_VIEW_H__ */
--- a/src/Modules/Output/Graphics/GraphicsViewTime.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/GraphicsViewTime.cc Fri Oct 15 05:40:53 2010 +0000 @@ -32,65 +32,65 @@ #include "Modules/Output/Graphics/GraphicsView.h" #include "Modules/Output/Graphics/GraphicsViewTime.h" -namespace aimc { - GraphicsViewTime::GraphicsViewTime(Parameters *pParam) - : GraphicsView(pParam) { - module_description_ = "Graphics output."; - module_identifier_ = "graphics_time"; - module_type_ = "output"; - module_version_ = "$Id: $"; + : GraphicsView(pParam) { } GraphicsViewTime *GraphicsViewTime::Clone(GraphicsOutputDevice *pDev) { - GraphicsViewTime *pView = new GraphicsViewTime(parameters_); - // Copy everything - pView->m_pAxisX->SetDisplayRange(m_pAxisX->m_fMax, m_pAxisX->m_fMin); - pView->m_pAxisX->SetDisplayScale(m_pAxisX->m_pScale->getType()); - pView->m_pAxisY->SetDisplayRange(m_pAxisY->m_fMax, m_pAxisY->m_fMin); - pView->m_pAxisY->SetDisplayScale(m_pAxisY->m_pScale->getType()); - pView->m_pAxisFreq->SetDisplayRange(m_pAxisFreq->m_fMax, m_pAxisFreq->m_fMin); - pView->m_pAxisFreq->SetDisplayScale(m_pAxisFreq->m_pScale->getType()); - return pView; + GraphicsViewTime *pView = new GraphicsViewTime(m_pParam); + // Copy everything + pView->m_pAxisX->SetDisplayRange(m_pAxisX->m_fMax, m_pAxisX->m_fMin); + pView->m_pAxisX->SetDisplayScale(m_pAxisX->m_pScale->getType()); + pView->m_pAxisY->SetDisplayRange(m_pAxisY->m_fMax, m_pAxisY->m_fMin); + pView->m_pAxisY->SetDisplayScale(m_pAxisY->m_pScale->getType()); + pView->m_pAxisFreq->SetDisplayRange(m_pAxisFreq->m_fMax, m_pAxisFreq->m_fMin); + pView->m_pAxisFreq->SetDisplayScale(m_pAxisFreq->m_pScale->getType()); + return pView; } void GraphicsViewTime::PlotAxes(const SignalBank &bank) { - m_pDev->gColor3f(0.0f, 0.7f, 0.7f); - // Vertical axis - m_pDev->gBeginLineStrip(); - m_pDev->gVertex2f(m_fMarginLeft, m_fMarginBottom); - m_pDev->gVertex2f(m_fMarginLeft, 1.0f - m_fMarginTop); - m_pDev->gEnd(); - // Horizontal axis - m_pDev->gBeginLineStrip(); - m_pDev->gVertex2f(m_fMarginLeft, m_fMarginBottom); - m_pDev->gVertex2f(1.0f-m_fMarginRight, m_fMarginBottom); - m_pDev->gEnd(); + m_pDev->gColor3f(0.0f, 0.7f, 0.7f); + // Vertical axis + m_pDev->gBeginLineStrip(); + m_pDev->gVertex2f(m_fMarginLeft, m_fMarginBottom); + m_pDev->gVertex2f(m_fMarginLeft, 1.0f - m_fMarginTop); + m_pDev->gEnd(); + // Horizontal axis + m_pDev->gBeginLineStrip(); + m_pDev->gVertex2f(m_fMarginLeft, m_fMarginBottom); + m_pDev->gVertex2f(1.0f-m_fMarginRight, m_fMarginBottom); + m_pDev->gEnd(); - //if (!m_bPlotLabels) - // return; + if (!m_bPlotLabels) + return; - // Labels - char sTxt[80]; - snprintf(sTxt, sizeof(sTxt) / sizeof(sTxt[0]), + // Labels + char sTxt[80]; + snprintf(sTxt, sizeof(sTxt) / sizeof(sTxt[0]), _S("%s [%.0f..%.0f Hz, %s scale]"), - m_pAxisFreq->m_sLabel ? m_pAxisFreq->m_sLabel : "", - m_pAxisFreq->m_fMin, m_pAxisFreq->m_fMax, - m_pAxisFreq->m_pScale->getName()); - m_pDev->gText2f(0.0025f, 0.35f, sTxt, true); - snprintf(sTxt, sizeof(sTxt) / sizeof(sTxt[0]), - _S("%s [%.2f..%.2f ms, %s scale]"), - m_pAxisX->m_sLabel ? m_pAxisX->m_sLabel : "", - m_pAxisX->m_fMin, - m_pAxisX->m_fMax, - m_pAxisX->m_pScale->getName()); + m_pAxisFreq->m_sLabel ? m_pAxisFreq->m_sLabel : "", + m_pAxisFreq->m_fMin, m_pAxisFreq->m_fMax, + m_pAxisFreq->m_pScale->getName()); + m_pDev->gText2f(0.0025f, 0.35f, sTxt, true); + if (m_bPlotScaled) { + snprintf(sTxt, sizeof(sTxt) / sizeof(sTxt[0]), + _S("%s [cycles, %s scale]"), + m_pAxisX->m_sLabel ? m_pAxisX->m_sLabel : "", + m_pAxisX->m_pScale->getName()); + } else { + snprintf(sTxt, sizeof(sTxt) / sizeof(sTxt[0]), + _S("%s [%.2f..%.2f ms, %s scale]"), + m_pAxisX->m_sLabel ? m_pAxisX->m_sLabel : "", + m_pAxisX->m_fMin, + m_pAxisX->m_fMax, + m_pAxisX->m_pScale->getName()); + } + m_pDev->gText2f(m_fMarginLeft, 0.0025f, sTxt, false); - m_pDev->gText2f(m_fMarginLeft, 0.0025f, sTxt, false); - - // Frame time - snprintf(sTxt, sizeof(sTxt)/sizeof(sTxt[0]), _S("t=%.0f ms"), - 1000.0 * bank.start_time() / bank.sample_rate()); - m_pDev->gText2f(0.8f, 0.0025f, sTxt, false); + // Frame time + snprintf(sTxt, sizeof(sTxt)/sizeof(sTxt[0]), _S("t=%.0f ms"), + pBank->getSampleTime(0)); + m_pDev->gText2f(0.8f, 0.0025f, sTxt, false); } void GraphicsViewTime::PlotData(const vector<float> &signal, @@ -98,42 +98,42 @@ float yOffset, float height, float xScale) { - AIM_ASSERT(xScale >= 0 && xScale <= 1); - AIM_ASSERT(height > 0 && height <= 1); - AIM_ASSERT(yOffset >= 0 && yOffset <= 1); - AIM_ASSERT(m_pAxisX && m_pAxisX->m_pScale); - AIM_ASSERT(m_pAxisY && m_pAxisY->m_pScale); + AIM_ASSERT(pSig); + AIM_ASSERT(xScale >= 0 && xScale <= 1); + AIM_ASSERT(height > 0 && height <= 1); + AIM_ASSERT(yOffset >= 0 && yOffset <= 1); + AIM_ASSERT(m_pAxisX && m_pAxisX->m_pScale); + AIM_ASSERT(m_pAxisY && m_pAxisY->m_pScale); - // Make sure we get time is ms as x value - xScale *= 1000.0 / sample_rate; - m_pDev->gColor3f(1.0f, 1.0f, 0.8f); - BeginDataStrip(); + // Make sure we get time is ms as x value + xScale *= 1000.0 / sample_rate; + m_pDev->gColor3f(1.0f, 1.0f, 0.8f); + BeginDataStrip(); - // Draw the signal. - float x = 0; - float y = 0; - for (unsigned int i = 0; i < signal.size(); i++) { - // Find out where to draw and do so - x = xScale * i; - y = signal[i]; - x = m_pAxisX->m_pScale->FromLinearScaled(x) + 0.5f; - y = m_pAxisY->m_pScale->FromLinearScaled(y); + // Draw the signal. + float x = 0; + float y = 0; + for (int i = 0; i < signal.size(); i++) { + // Find out where to draw and do so + x = xScale * i; + y = signal[i]; + x = m_pAxisX->m_pScale->FromLinearScaled(x) + 0.5f; + y = m_pAxisY->m_pScale->FromLinearScaled(y); - if (x < 0.0) + if (x < 0.0) continue; - // Now fit it into the drawing area - x = x * (1.0f - m_fMarginLeft - m_fMarginRight) + m_fMarginLeft; // fit inside x-axis area - PlotDataPoint(x, yOffset, y, height, false); - /* There's no point in drawing anything when x>1.0, outside of view. - * x is continuously increasing, so we can just stop completely. We need to - * plot this point however, to finish the final line. */ - if (x > 1.0) - break; - } - // Redraw the last point in case it's needed - PlotDataPoint(x, yOffset, y, height, true); + // Now fit it into the drawing area + x = x * (1.0f - m_fMarginLeft - m_fMarginRight) + m_fMarginLeft; // fit inside x-axis area + PlotDataPoint(x, yOffset, y, height, false); + /* There's no point in drawing anything when x>1.0, outside of view. + * x is continuously increasing, so we can just stop completely. We need to + * plot this point however, to finish the final line. */ + if (x > 1.0) + break; + } + // Redraw the last point in case it's needed + PlotDataPoint(x, yOffset, y, height, true); - m_pDev->gEnd(); + m_pDev->gEnd(); } -} // namespace aimc
--- a/src/Modules/Output/Graphics/GraphicsViewTime.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/GraphicsViewTime.h Fri Oct 15 05:40:53 2010 +0000 @@ -12,11 +12,11 @@ #ifndef __GRAPHICS_VIEW_TIME_H__ #define __GRAPHICS_VIEW_TIME_H__ +#include "Support/Signal.h" #include "Support/SignalBank.h" -#include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h" -#include "Modules/Output/Graphics/GraphicsView.h" +#include "Output/GraphicsOutputDevice.h" +#include "Output/GraphicsView.h" -namespace aimc { /*! * \class GraphicsViewTime "Output/GraphicsViewTime.h" * \brief Time-definition graphics view class @@ -25,22 +25,19 @@ */ class GraphicsViewTime : public GraphicsView { public: - /*! \brief Create a new view - * \param pParam Main parameter store - */ - GraphicsViewTime(Parameters *pParam); - virtual ~GraphicsViewTime() { }; + /*! \brief Create a new view + * \param pParam Main parameter store + */ + GraphicsViewTime(AimParameters *pParam); + virtual ~GraphicsViewTime() { }; - virtual GraphicsViewTime *Clone(GraphicsOutputDevice *pDev); + virtual GraphicsViewTime *Clone(GraphicsOutputDevice *pDev); private: - void PlotData(const vector<float> &signal, - float sample_rate, - float yOffset, - float height, - float xScale = 1.0); - void PlotAxes(const vector<float> &signal); - void PlotAxes(const SignalBank &pBank); + void PlotData(Signal* pSig, float yOffset, float height, float xScale = 1.0); + void PlotAxes(Signal* pSig); + void PlotAxes(SignalBank* pBank); + }; -} // namesapce aimc + #endif /* __GRAPHICS_VIEW_TIME_H__ */
--- a/src/Modules/Output/Graphics/Scale/Scale.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Scale/Scale.cc Fri Oct 15 05:40:53 2010 +0000 @@ -9,68 +9,98 @@ /* (c) 2006, University of Cambridge, Medical Research Council * http://www.pdn.cam.ac.uk/groups/cnbh/aimmanual */ -#include "Support/Common.h" -#include "Modules/Output/Graphics/Scale/Scale.h" -#include "Modules/Output/Graphics/Scale/ScaleLinear.h" -#include "Modules/Output/Graphics/Scale/ScaleERB.h" -#include "Modules/Output/Graphics/Scale/ScaleLog.h" -#include "Modules/Output/Graphics/Scale/ScaleLogScaled.h" +#include "Support/common.h" +#include "Support/util.h" +#include "Modules/Scale/Scale.h" +#include "Modules/Scale/ScaleLinear.h" +#include "Modules/Scale/ScaleERB.h" +#include "Modules/Scale/ScaleLog.h" +#include "Modules/Scale/ScaleLogScaled.h" -namespace aimc { - -Scale *Scale::Create(ScaleType iType, - unsigned int min, - unsigned int max, - float density) { - switch(iType) { - case SCALE_LINEAR: - return static_cast<Scale*>(new ScaleLinear(min, max, density)); - case SCALE_ERB: - return static_cast<Scale*>(new ScaleERB(min, max, density)); - case SCALE_LOG: - return static_cast<Scale*>(new ScaleLog(min, max, density)); - case SCALE_LOGSCALED: - return static_cast<Scale*>(new ScaleLogScaled(min, max, density)); - default: - AIM_ASSERT(0); - break; - } - // Unreachable code - AIM_ASSERT(0); - return NULL; +Scale *Scale::Create(ScaleType iType, unsigned int min, unsigned int max, float density) +{ + switch(iType) { + case SCALE_LINEAR: + return static_cast<Scale*>(new ScaleLinear(min, max, density)); + case SCALE_ERB: + return static_cast<Scale*>(new ScaleERB(min, max, density)); + case SCALE_LOG: + return static_cast<Scale*>(new ScaleLog(min, max, density)); + case SCALE_LOGSCALED: + return static_cast<Scale*>(new ScaleLogScaled(min, max, density)); + default: + aimASSERT(0); + break; + } + // Unreachable code + aimASSERT(0); + return NULL; } -Scale *Scale::Create(ScaleType iType) { - return Create(iType, 0, 0, 0); +Scale *Scale::Create(ScaleType iType) +{ + return Create(iType, 0, 0, 0); } -Scale *Scale::Clone() { - Scale *pScale = Create(m_iType, m_iMin, m_iMax, m_fDensity); - AIM_ASSERT(pScale); - pScale->m_fScaledCurHalfSum = m_fScaledCurHalfSum; - pScale->m_fScaledCurDiff = m_fScaledCurDiff; - return pScale; +Scale *Scale::Clone() +{ + Scale *pScale = Create(m_iType, m_iMin, m_iMax, m_fDensity); + aimASSERT(pScale); + pScale->m_fScaledCurHalfSum = m_fScaledCurHalfSum; + pScale->m_fScaledCurDiff = m_fScaledCurDiff; + return pScale; } -float Scale::FromLinearScaled(float fVal) { - /*! This function returns - * ( FromLinear(fVal) - (fMinScaled+fMaxScaled)/2 ) / (fMaxScaled-fMinScaled) - */ - float fValScaled = FromLinear(fVal); - return (fValScaled - m_fScaledCurHalfSum) / m_fScaledCurDiff; +float Scale::FromLinearScaled(float fVal) +{ + /*! This function returns + * ( FromLinear(fVal) - (fMinScaled+fMaxScaled)/2 ) / (fMaxScaled-fMinScaled) + */ + float fValScaled = FromLinear(fVal); + return (fValScaled - m_fScaledCurHalfSum) / m_fScaledCurDiff; +} +void Scale::FromLinearScaledExtrema(float fMin, float fMax) +{ + float fMinScaled = FromLinear(fMin); + float fMaxScaled = FromLinear(fMax); + m_fScaledCurHalfSum = (fMinScaled+fMaxScaled)/2; + m_fScaledCurDiff = fMaxScaled-fMinScaled; + m_fMin = fMin; + m_fMax = fMax; +} +void Scale::FromLinearScaledExtrema(Scale *pScale) +{ + aimASSERT(pScale); + FromLinearScaledExtrema(pScale->m_fMin, pScale->m_fMax); } -void Scale::FromLinearScaledExtrema(float fMin, float fMax) { - float fMinScaled = FromLinear(fMin); - float fMaxScaled = FromLinear(fMax); - m_fScaledCurHalfSum = (fMinScaled+fMaxScaled)/2; - m_fScaledCurDiff = fMaxScaled-fMinScaled; - m_fMin = fMin; - m_fMax = fMax; +SignalBank* Scale::CreateSignalBank(unsigned int iChannels, unsigned int iBufferlength, unsigned int iSamplerate) +{ + SignalBank *pBank; + double intpart, fracpart; + fracpart = modf((m_iMax-m_iMin)*m_fDensity, &intpart); + unsigned int nBankChan = (unsigned int) intpart; + if (fracpart >= 0.5f) + nBankChan++; + + pBank = new SignalBank(iChannels, iBufferlength, iSamplerate, nBankChan); + aimASSERT(pBank); + + float scaleDelta = ( FromLinear(m_iMax) - FromLinear(m_iMin) ) / (nBankChan-1); + float scaleCur = FromLinear(m_iMin); + + for (unsigned int i=0; i<nBankChan; i++) { + pBank->setCentreFrequency(i, ToLinear(scaleCur)); + scaleCur+=scaleDelta; + } + + return pBank; } -void Scale::FromLinearScaledExtrema(Scale *pScale) { - AIM_ASSERT(pScale); - FromLinearScaledExtrema(pScale->m_fMin, pScale->m_fMax); + + +SignalBank* Scale::CreateSignalBank(Signal* pSig) { + aimASSERT(pSig); + return CreateSignalBank(pSig->getAudioChannels(), pSig->getBufferlength(), pSig->getSamplerate()); } -} // namespace aimc +
--- a/src/Modules/Output/Graphics/Scale/Scale.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Scale/Scale.h Fri Oct 15 05:40:53 2010 +0000 @@ -12,7 +12,7 @@ #ifndef __MODULE_SCALE_H__ #define __MODULE_SCALE_H__ -namespace aimc { +#include "Support/SignalBank.h" /*! * \class Scale "Modules/Scale/Scale.h" @@ -28,114 +28,132 @@ class Scale; class Scale { public: - //! \brief A list of possible scales - enum ScaleType { - SCALE_LINEAR, SCALE_ERB, SCALE_LOG, SCALE_LOGSCALED - }; - /*! \brief Create a new scale based on type - * \param iType Scale type to create - * \param min Bottom frequency - * \param max Top frequency - * \param density Density of distribution on the scale (scale-dependent) - * \return Newly created scale, to be freed by the caller. - * - * This is on purpose no virtual function, always use it Scale::Create(). - * \todo Split into scaling and filterbank creation parts. - * Maybe even a separate ScaleMaker that implements Create(). - */ - static Scale *Create(ScaleType iType, unsigned int min, unsigned int max, float density); + //! \brief A list of possible scales + enum ScaleType { + SCALE_LINEAR, SCALE_ERB, SCALE_LOG, SCALE_LOGSCALED + }; + /*! \brief Create a new scale based on type + * \param iType Scale type to create + * \param min Bottom frequency + * \param max Top frequency + * \param density Density of distribution on the scale (scale-dependent) + * \return Newly created scale, to be freed by the caller. + * + * This is on purpose no virtual function, always use it Scale::Create(). + * \todo Split into scaling and filterbank creation parts. + * Maybe even a separate ScaleMaker that implements Create(). + */ + static Scale *Create(ScaleType iType, unsigned int min, unsigned int max, float density); - /*! \overload - * This function is for scaling-only Scales, you must not create a SignalBank + /*! \overload + * This function is for scaling-only Scales, you must not create a SignalBank * with the returned Scale. - */ - static Scale *Create(ScaleType iType); + */ + static Scale *Create(ScaleType iType); - /*! \brief Create a new Scale - * \param min Bottom frequency - * \param max Top frequency - * \param density Density of distribution on the scale (scale-dependent) - */ - Scale(unsigned int min, unsigned int max, float density) { - m_iMin = min; - m_iMax = max; - m_fDensity = density; - m_sName = NULL; - }; + /*! \brief Create a new Scale + * \param min Bottom frequency + * \param max Top frequency + * \param density Density of distribution on the scale (scale-dependent) + */ + Scale(unsigned int min, unsigned int max, float density) { + m_iMin = min; + m_iMax = max; + m_fDensity = density; + m_sName = NULL; + }; - virtual ~Scale() { }; + virtual ~Scale() { }; - /*! \brief Create an exact copy of this Scale - * \return A newly created Scale, to be freed by the caller. - */ - virtual Scale *Clone(); + /*! \brief Create an exact copy of this Scale + * \return A newly created Scale, to be freed by the caller. + */ + virtual Scale *Clone(); - //! \return this Signal's ScaleType - ScaleType getType() { return m_iType; }; - //! \return this Signal's name - const char *getName() { return m_sName; }; + //! \return this Signal's ScaleType + ScaleType getType() { return m_iType; }; + //! \return this Signal's name + const char *getName() { return m_sName; }; - /*! \brief Scale a frequency from linear to this scale - * \param fFreq Frequency to scale - * \return Scaled frequency - */ - virtual float FromLinear(float fFreq) = 0; + /*! \brief Scale a frequency from linear to this scale + * \param fFreq Frequency to scale + * \return Scaled frequency + */ + virtual float FromLinear(float fFreq) = 0; - /*! \brief Scale a frequency from this scale to linear - * \param fFreq Scaled frequency to scale back - * \return Linear frequency - */ - virtual float ToLinear(float fFreq) = 0; + /*! \brief Scale a frequency from this scale to linear + * \param fFreq Scaled frequency to scale back + * \return Linear frequency + */ + virtual float ToLinear(float fFreq) = 0; - /*! \brief Scale from [fMin..fMax] to [-0.5..0.5] - * \param fVal Value to scale, must be within [fMin..fMax] - * \return Float in [-0.5..0.5] according to this scale - * \sa FromLinearScaledExtrema - * - * This is mainly for displaying any value on a scale and to make sure - * that it fits in on screen. Don't use this for any real maths! - * - * The default implementation assumes that the scale is monotonic, so the - * FromLinear(fMin) and FromLinear(fMax) are scale's output boundaries. - * - * fMin and fMax are set by FromLinearScaledExtrema. Do not use this before - * calling that. - */ - float FromLinearScaled(float fVal); - /*! \brief Update the FromLinearScaled min/max values - * \param fMin Minimum value to be input - * \param fMax Maxmimum value to be input - * \sa FromLinearScaled - */ - void FromLinearScaledExtrema(float fMin, float fMax); - /*! \overload - * \brief Copy min/max values from another Scale - * \param pScale Scale from which to copy min/max values, must not be NULL - */ - void FromLinearScaledExtrema(Scale *pScale); + /*! \brief Scale from [fMin..fMax] to [-0.5..0.5] + * \param fVal Value to scale, must be within [fMin..fMax] + * \return Float in [-0.5..0.5] according to this scale + * \sa FromLinearScaledExtrema + * + * This is mainly for displaying any value on a scale and to make sure + * that it fits in on screen. Don't use this for any real maths! + * + * The default implementation assumes that the scale is monotonic, so the + * FromLinear(fMin) and FromLinear(fMax) are scale's output boundaries. + * + * fMin and fMax are set by FromLinearScaledExtrema. Do not use this before + * calling that. + */ + float FromLinearScaled(float fVal); + /*! \brief Update the FromLinearScaled min/max values + * \param fMin Minimum value to be input + * \param fMax Maxmimum value to be input + * \sa FromLinearScaled + */ + void FromLinearScaledExtrema(float fMin, float fMax); + /*! \overload + * \brief Copy min/max values from another Scale + * \param pScale Scale from which to copy min/max values, must not be NULL + */ + void FromLinearScaledExtrema(Scale *pScale); + + /*! \brief Create a new signal bank + * \param iChannels Number of audio channels + * \param iBufferlength Length of the buffer in frames + * \param iSamplerate Samplerate in Hz + * Note that the caller must free the signal bank again. + */ + virtual SignalBank* CreateSignalBank(unsigned int iChannels, unsigned int iBufferlength, unsigned int iSamplerate); + + /*! \overload + * \brief Create a signal bank based on a Signal's parameters + * \param pSig Signal to get parameters from + * pSig is only used to look at parameters like samplerate, nothing is done + * with its contents. + * Note that the caller must free the signal bank again. + */ + virtual SignalBank* CreateSignalBank(/*! \todo const*/ Signal* pSig); + protected: - //! \brief Bottom frequency - unsigned int m_iMin; - //! \brief Top frequency - unsigned int m_iMax; - //! \brief Density of distribution on the scale (scale-dependent) - float m_fDensity; - //! \brief The type of this scale, used by Clone(); set this in children. - ScaleType m_iType; - //! \brief The name of this scale; set this in children. - const char *m_sName; + //! \brief Bottom frequency + unsigned int m_iMin; + //! \brief Top frequency + unsigned int m_iMax; + //! \brief Density of distribution on the scale (scale-dependent) + float m_fDensity; + //! \brief The type of this scale, used by Clone(); set this in children. + ScaleType m_iType; + //! \brief The name of this scale; set this in children. + const char *m_sName; - /*! \brief Minimum value for scaling as input - * \sa FromLinearScaled(), FromLinearScaledExtrema() */ - float m_fMin; - /*! \brief Maximum value for scaling as input - * \sa FromLinearScaled(), FromLinearScaledExtrema() */ - float m_fMax; - //! \brief Value used in FromLinearScaled - float m_fScaledCurHalfSum; - //! \brief Value used in FromLinearScaled - float m_fScaledCurDiff; + /*! \brief Minimum value for scaling as input + * \sa FromLinearScaled(), FromLinearScaledExtrema() */ + float m_fMin; + /*! \brief Maximum value for scaling as input + * \sa FromLinearScaled(), FromLinearScaledExtrema() */ + float m_fMax; + //! \brief Value used in FromLinearScaled + float m_fScaledCurHalfSum; + //! \brief Value used in FromLinearScaled + float m_fScaledCurDiff; }; -} // namespace aimc + #endif /* __MODULE_SCALE_H__ */
--- a/src/Modules/Output/Graphics/Scale/ScaleERB.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Scale/ScaleERB.h Fri Oct 15 05:40:53 2010 +0000 @@ -14,9 +14,7 @@ #include <math.h> -#include "Modules/Output/Graphics/Scale/Scale.h" - -namespace aimc { +#include "Modules/Scale/Scale.h" /*! * \class ScaleERB "Modules/Scale/ScaleERB.h" @@ -30,16 +28,16 @@ */ class ScaleERB : public Scale { public: - ScaleERB(unsigned int min, unsigned int max, float density) - : Scale(min, max, density) { m_iType = SCALE_ERB; m_sName = "erb"; }; + ScaleERB(unsigned int min, unsigned int max, float density) + : Scale(min, max, density) { m_iType = SCALE_ERB; m_sName = "erb"; }; - float FromLinear(float fFreq) { - return 21.4f*log10(0.00437f*fFreq + 1.0f); - }; + float FromLinear(float fFreq) { + return 21.4f*log10(0.00437f*fFreq + 1.0f); + }; - float ToLinear(float fFreq) { - return (pow(10, fFreq/21.4f) - 1.0f)/0.00437f; - }; + float ToLinear(float fFreq) { + return (pow(10, fFreq/21.4f) - 1.0f)/0.00437f; + }; }; -} // namespace aimc + #endif /* __MODULE_SCALE_ERB_H__ */
--- a/src/Modules/Output/Graphics/Scale/ScaleLinear.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Scale/ScaleLinear.h Fri Oct 15 05:40:53 2010 +0000 @@ -12,9 +12,7 @@ #ifndef __MODULE_SCALE_LINEAR_H__ #define __MODULE_SCALE_LINEAR_H__ -#include "Modules/Output/Graphics/Scale/Scale.h" - -namespace aimc { +#include "Modules/Scale/Scale.h" /*! * \class ScaleLinear "Modules/Scale/ScaleLinear.h" @@ -26,16 +24,16 @@ */ class ScaleLinear : public Scale { public: - ScaleLinear(unsigned int min, unsigned int max, float density) - : Scale(min, max, density) { m_iType = SCALE_LINEAR; m_sName = "linear"; }; + ScaleLinear(unsigned int min, unsigned int max, float density) + : Scale(min, max, density) { m_iType = SCALE_LINEAR; m_sName = "linear"; }; - float FromLinear(float fFreq) { - return fFreq; - }; + float FromLinear(float fFreq) { + return fFreq; + }; - float ToLinear(float fFreq) { - return fFreq; - }; + float ToLinear(float fFreq) { + return fFreq; + }; }; -} // namepspace aimc + #endif /* __MODULE_SCALE_LINEAR_H__ */
--- a/src/Modules/Output/Graphics/Scale/ScaleLog.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Scale/ScaleLog.h Fri Oct 15 05:40:53 2010 +0000 @@ -14,9 +14,7 @@ #include <math.h> -#include "Modules/Output/Graphics/Scale/Scale.h" - -namespace aimc { +#include "Modules/Scale/Scale.h" /*! * \class ScaleLog "Modules/Scale/ScaleLog.h" @@ -26,19 +24,19 @@ */ class ScaleLog : public Scale { public: - ScaleLog(unsigned int min, unsigned int max, float density) - : Scale(min, max, density) { m_iType = SCALE_LOG; m_sName="log"; }; + ScaleLog(unsigned int min, unsigned int max, float density) + : Scale(min, max, density) { m_iType = SCALE_LOG; m_sName="log"; }; - /*! The log scale has a problem, because log(0)=inf, so all values below - * 1e-5 are truncated to 1e-5. */ - float FromLinear(float fFreq) { - if (fFreq<1e-5f) fFreq=1e-5f; - return log(fFreq); - }; + /*! The log scale has a problem, because log(0)=inf, so all values below + * 1e-5 are truncated to 1e-5. */ + float FromLinear(float fFreq) { + if (fFreq<1e-5f) fFreq=1e-5f; + return log(fFreq); + }; - float ToLinear(float fFreq) { - return exp(fFreq); - }; + float ToLinear(float fFreq) { + return exp(fFreq); + }; }; -} // namespace aimc + #endif /* __MODULE_SCALE_LOG_H__ */
--- a/src/Modules/Output/Graphics/Scale/ScaleLogScaled.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/Output/Graphics/Scale/ScaleLogScaled.h Fri Oct 15 05:40:53 2010 +0000 @@ -14,9 +14,7 @@ #include <math.h> -#include "Modules/Output/Graphics/Scale/Scale.h" - -namespace aimc { +#include "Modules/Scale/Scale.h" /*! * \class ScaleERB "Modules/Scale/ScaleERB.h" @@ -30,16 +28,16 @@ */ class ScaleLogScaled : public Scale { public: - ScaleLogScaled(unsigned int min, unsigned int max, float density) - : Scale(min, max, density) { m_iType = SCALE_ERB; m_sName = "logscaled"; }; + ScaleLogScaled(unsigned int min, unsigned int max, float density) + : Scale(min, max, density) { m_iType = SCALE_ERB; m_sName = "logscaled"; }; - float FromLinear(float fFreq) { - return 21.4f*log10(0.00437f*fFreq); - }; + float FromLinear(float fFreq) { + return 21.4f*log10(0.00437f*fFreq); + }; - float ToLinear(float fFreq) { - return (pow(10, fFreq/21.4f))/0.00437f; - }; + float ToLinear(float fFreq) { + return (pow(10, fFreq/21.4f))/0.00437f; + }; }; -} // namespace aimc + #endif /* __MODULE_SCALE_ERB_H__ */
--- a/src/Modules/SSI/ModuleSSI.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/SSI/ModuleSSI.cc Fri Oct 15 05:40:53 2010 +0000 @@ -69,6 +69,13 @@ // The centre frequency of the channel which will just fill the complete // width of the SSI buffer pivot_cf_ = parameters_->DefaultFloat("ssi.pivot_cf", 1000.0f); + + // Whether or not to do smooth offset when the pitch cutoff is active. + do_smooth_offset_ = parameters_->DefaultBool("ssi.do_smooth_offset", false); + + // The number of cycles, centered on the pitch line, over which the SSI is taken + // to zero when doing the pitch cutoff. + smooth_offset_cycles_ = parameters_->DefaultFloat("ssi.smooth_offset_cycles", 3.0f); } ModuleSSI::~ModuleSSI() { @@ -146,16 +153,45 @@ if (do_pitch_cutoff_) { pitch_index = ExtractPitchIndex(input); } + + float gamma_min = -1.0f; + float gamma_max = log2(ssi_width_cycles_); for (int ch = 0; ch < channel_count_; ++ch) { float centre_frequency = input.centre_frequency(ch); + + float channel_weight = 1.0f; + int cutoff_index = buffer_length_ - 1; + if (do_pitch_cutoff_) { + if (pitch_index < cutoff_index) { + if (weight_by_cutoff_) { + channel_weight = static_cast<float>(buffer_length_) + / static_cast<float>(pitch_index); + } + cutoff_index = pitch_index; + } + } + + // tanh(3) is about 0.995. Seems reasonable. + float smooth_pitch_constant = smooth_offset_cycles_ * 3.0f; + float pitch_h = 0.0f; + if (do_smooth_offset_) { + if (log_cycles_axis_) { + float gamma = gamma_min + (gamma_max - gamma_min) + * static_cast<float>(pitch_index) + / static_cast<float>(ssi_width_samples_); + pitch_h = pow(2.0f, gamma); + } else { + pitch_h = static_cast<float>(pitch_index) * ssi_width_cycles_ + / static_cast<float>(ssi_width_samples_); + } + } + // Copy the buffer from input to output, addressing by h-value for (int i = 0; i < ssi_width_samples_; ++i) { float h; float cycle_samples = sample_rate_ / centre_frequency; if (log_cycles_axis_) { - float gamma_min = -1.0f; - float gamma_max = log2(ssi_width_cycles_); float gamma = gamma_min + (gamma_max - gamma_min) * static_cast<float>(i) / static_cast<float>(ssi_width_samples_); @@ -173,17 +209,11 @@ float frac_part = modf(h * cycle_samples, &whole_part); int sample = floor(whole_part); - float weight = 1.0f; - - int cutoff_index = buffer_length_ - 1; - if (do_pitch_cutoff_) { - if (pitch_index < cutoff_index) { - if (weight_by_cutoff_) { - weight *= static_cast<float>(buffer_length_) - / static_cast<float>(pitch_index); - } - cutoff_index = pitch_index; - } + float weight = channel_weight; + + if (do_smooth_offset_ && do_pitch_cutoff_) { + // Smoothing around the pitch cutoff line. + weight *= (1.0f + tanh(smooth_pitch_constant * (pitch_h - h))) / 2.0f; } if (weight_by_scaling_) { @@ -193,7 +223,7 @@ } float val; - if (sample < cutoff_index) { + if (sample < cutoff_index || do_smooth_offset_) { float curr_sample = input.sample(ch, sample); float next_sample = input.sample(ch, sample + 1); val = weight * (curr_sample
--- a/src/Modules/SSI/ModuleSSI.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Modules/SSI/ModuleSSI.h Fri Oct 15 05:40:53 2010 +0000 @@ -24,7 +24,6 @@ #ifndef AIMC_MODULES_SSI_SSI_H_ #define AIMC_MODULES_SSI_SSI_H_ -#include <vector> #include "Support/Module.h" namespace aimc { @@ -57,7 +56,6 @@ int ssi_width_samples_; float ssi_width_cycles_; float pivot_cf_; - vector<float> h_; bool do_pitch_cutoff_; bool weight_by_cutoff_;
--- a/src/Support/Module.cc Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Support/Module.cc Fri Oct 15 05:40:53 2010 +0000 @@ -87,7 +87,6 @@ if (!initialized_) return; - // LOG_INFO("Resetting module %s", module_identifier_.c_str()); ResetInternal(); // Iterate through all the targets of this module, resetting
--- a/src/Support/SignalBank.h Wed Sep 29 00:24:03 2010 +0000 +++ b/src/Support/SignalBank.h Fri Oct 15 05:40:53 2010 +0000 @@ -54,14 +54,27 @@ bool Initialize(const SignalBank &input); bool Validate() const; + // Return a const reference to an individual signal. Allows for + // signal[channel][sample] referencing of SignalBanks. inline const vector<float> &operator[](int channel) const { return signals_[channel]; }; + // Return a const reference to an individual signal. inline const vector<float> &get_signal(int channel) const { return signals_[channel]; }; + // Return a reference to the signal vector. The reference is not + // const, so the vector is directly modifiable. In order to maintain + // consistency of the data within the filterbank, the size of this + // vector should not be changed. Changes to the vector size can be picked + // up with a call to Validate(), which will return false if the sizes of + // channle vectors are not consistent. + inline vector<float> &get_mutable_signal(int channel) { + return signals_[channel]; + }; + inline void set_signal(int channel, vector<float> input) { signals_[channel] = input; }